☰
从 Cursor 的「Dynamic Context Discovery」谈起:AI Agent 真正的护城河,是上下文工程而不是 Prompt
2026/10/2 13:49:25 网站建设 项目流程

1. 为什么你的 Agent 总是“答非所问”:从 Cursor 动态上下文发现说起

很多人第一次用 Cursor 写代码时,都会经历一个错觉:明明模型很强,为什么它改出来的代码还是跑不通?我试过把一个 3000 行的老项目直接丢给 AI,结果它给我补了一个根本不存在的函数名。问题不在模型,而在于我一次性塞给它的上下文里,真正有用的信息被淹没了。

Cursor 在 2025 年发布的技术博客《Dynamic Context Discovery》里,把这件事讲透了。它的核心思想一句话就能概括:不要急着把所有信息塞给模型,而是让模型在需要的时候,自己去找。这听起来像是一句正确的废话,但落到工程上,它意味着一次根本性的设计转变——从“人类预判上下文”变成“模型自主发现上下文”。

传统做法是静态 prompt:你把 README、接口文档、历史对话、工具说明全部拼在一起,一次性注入。模型能力弱的时候,这招确实能提高成功率,因为模型自己不会找。但模型变强之后,问题就反过来了:冗余信息会干扰判断,注意力被迫分散,真正关键的那几行代码反而被淹没。这就像你给一个资深工程师派活,却把公司十年的制度文档全堆在他桌上——不是帮助,是干扰。

Dynamic Context Discovery 要解决的,就是“模型什么时候需要什么信息”这个问题。它把长输出变成文件、把聊天历史变成摘要加原始记录、把 Agent Skills 按需加载、把 MCP 工具描述瘦身、把终端会话也同步成文件。五个场景,一个共同点:上下文不再承载数据本体,只承载访问入口。

这篇文章我会带你拆解这套机制,给出可复制的上下文分层配置模板和检索触发条件,并演示在 TaoToken 统一 Key/API 通道下切换模型,验证上下文命中率与任务完成度的具体步骤。适合正在做 AI Agent、Coding Agent,或者被“上下文爆炸”折磨过的开发者。

2. TaoToken 前置准备:统一 Key 与 API 通道,让上下文实验可复现

在讲配置之前,得先把实验环境搭好。上下文工程最怕的一件事是:你换了模型,结果任务完成度变了,你分不清是上下文策略的功劳还是模型本身的差异。所以我们需要一个能统一管理 Key、随时切换模型的通道。TaoToken 就是干这个的。

TaoToken 是一个面向开发者的模型 API 聚合通道,官网是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。它的价值在于:你只需要一个 Key,就能在 Claude、GPT、Gemini 等模型之间切换,而不用为每个模型单独申请账号、单独配环境。对于上下文工程的验证来说,这一点很关键——你可以固定上下文策略,只换模型,看命中率怎么变。

先拿 Key。打开 https://taotoken.net/api-keys ,登录后创建一个 API Key,复制出来。注意这个 Key 只显示一次,丢了就得重建。拿到之后,建议先放到环境变量里,别硬编码进代码:

export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

如果你用的是 Claude Code 这类工具,它需要的是 Anthropic 兼容的 Base URL。TaoToken 的接入文档在 https://taotoken.net/doc ,里面有各客户端的详细配置。这里先给一个通用的 OpenAI 兼容配置,后面第三节会展开。

为什么要强调“统一通道”?因为上下文工程的核心变量是“信息组织方式”,不是“模型供应商”。如果你每次换模型都要重新配一遍环境,实验根本没法做。TaoToken 把这一层抹平了,你才能专注在上下文分层和检索触发条件上。

另外,如果你打算长期跑 Coding Agent,可以了解一下 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。它针对编码场景做了额度优化,适合需要反复验证上下文策略的开发者。不过这一节先把基础通道打通,别急着上套餐。

3. 可复制的上下文分层配置模板与检索触发条件

这一节是全文的核心。我会给出一个可以直接抄的上下文分层配置模板,包含 JSON 和 TOML 两种格式,并说明每一层的检索触发条件。你可以把它理解成“给 Agent 的信息索引系统”。

先讲分层思路。参考 Cursor 的五个场景,我把上下文分成四层:

第一层是常驻层(Always-on)。这一层放的是每次请求都必须带上的信息,比如系统角色、当前任务目标、输出格式约束。它的特点是体积小、变化少、命中率 100%。常驻层不能放代码本体,只能放“指针”。

第二层是索引层(Index)。这一层放的是文件目录、工具名列表、技能目录。它告诉模型“有什么可用”,但不告诉模型“具体内容是什么”。模型看到索引后,自己决定要不要深入。

第三层是按需层(On-demand)。这一层是真正的内容本体:完整代码文件、MCP 工具描述、聊天历史原文、终端日志。它们平时不进入上下文,只有当模型触发检索条件时才被拉取。

第四层是归档层(Archive)。这一层是持久化存储,通常是文件系统或对象存储。它容量近乎无限,模型通过 read、grep、diff 这些操作访问。

下面是一个 JSON 格式的分层配置模板,你可以直接放到项目根目录的.agent/context.json:

{ "layers": { "always_on": { "system_role": "你是一个严谨的编码 Agent,只修改用户明确要求的文件。", "task_goal": "{{current_task}}", "output_format": "diff", "max_tokens": 800 }, "index": { "file_tree": ".agent/index/file_tree.json", "tool_names": ".agent/index/tools.json", "skill_catalog": ".agent/index/skills.json", "max_tokens": 1200 }, "on_demand": { "source_root": "./src", "history_file": ".agent/archive/chat_history.jsonl", "terminal_log": ".agent/archive/terminal.log", "mcp_descriptions": ".agent/archive/mcp/*.md", "max_tokens_per_fetch": 4000 }, "archive": { "root": ".agent/archive", "retention_days": 30 } }, "retrieval_triggers": { "read_file": ["修改", "重构", "修复", "实现", "添加函数"], "grep_log": ["报错", "异常", "失败", "timeout", "undefined"], "load_skill": ["部署", "测试", "迁移", "性能优化"], "fetch_mcp": ["调用外部服务", "查询数据库", "发送请求"], "recall_history": ["之前说过", "上次", "继续", "回退"] } }

如果你更喜欢 TOML,等价配置如下,放到.agent/context.toml:

[layers.always_on] system_role = "你是一个严谨的编码 Agent,只修改用户明确要求的文件。" task_goal = "{{current_task}}" output_format = "diff" max_tokens = 800 [layers.index] file_tree = ".agent/index/file_tree.json" tool_names = ".agent/index/tools.json" skill_catalog = ".agent/index/skills.json" max_tokens = 1200 [layers.on_demand] source_root = "./src" history_file = ".agent/archive/chat_history.jsonl" terminal_log = ".agent/archive/terminal.log" mcp_descriptions = ".agent/archive/mcp/*.md" max_tokens_per_fetch = 4000 [layers.archive] root = ".agent/archive" retention_days = 30 [retrieval_triggers] read_file = ["修改", "重构", "修复", "实现", "添加函数"] grep_log = ["报错", "异常", "失败", "timeout", "undefined"] load_skill = ["部署", "测试", "迁移", "性能优化"] fetch_mcp = ["调用外部服务", "查询数据库", "发送请求"] recall_history = ["之前说过", "上次", "继续", "回退"]

这份模板的关键在于retrieval_triggers。它定义了“什么词触发什么检索”。比如用户说“修复登录报错”,Agent 会同时触发read_file和grep_log,先去读登录相关文件,再去终端日志里 grep 错误堆栈。而不是一上来就把整个 src 目录塞进上下文。

这里有个坑要注意:触发词不能太宽泛。如果你把“代码”设成触发词,那几乎每句话都会触发全量读取,分层就失效了。建议触发词控制在 5 到 8 个,且尽量是动词或明确的名词。

另外,索引层的file_tree.json建议用脚本生成,只保留路径和文件大小,不要放内容。工具名列表同理,只放名字和一行描述。这样索引层的 token 消耗能压到 1200 以内,给按需层留出足够空间。

4. 验证请求与成功结果:在 TaoToken 通道下测上下文命中率

配置写好了,怎么验证它真的有效?这一节给你一套可执行的验证流程,包括一个 Python 脚本和预期结果。

先装依赖:

pip install openai

然后写一个验证脚本verify_context.py。它的逻辑是:构造一个带触发词的任务,让 Agent 按分层配置去检索,最后统计“实际拉取的文件数”和“任务完成度”。

import os import json from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"] ) with open(".agent/context.json", "r", encoding="utf-8") as f: ctx = json.load(f) task = "修复 src/auth/login.py 里的登录报错,并检查终端日志" # 模拟触发词匹配 triggers = ctx["retrieval_triggers"] hit = {} for action, words in triggers.items(): if any(w in task for w in words): hit[action] = words print("触发检索动作:", list(hit.keys())) # 构造分层上下文 always_on = ctx["layers"]["always_on"] index_layer = ctx["layers"]["index"] messages = [ {"role": "system", "content": always_on["system_role"]}, {"role": "user", "content": f"任务: {task}\n可用索引: {index_layer}"} ] resp = client.chat.completions.create( model="claude-3-5-sonnet", messages=messages, temperature=0 ) print("模型首轮响应:") print(resp.choices[0].message.content)

跑之前,确保你的.agent/index/file_tree.json和.agent/archive/terminal.log存在。运行:

python verify_context.py

预期结果分两部分。第一部分是触发动作,应该输出['read_file', 'grep_log'],因为任务里同时出现了“修复”和“报错”。第二部分是模型首轮响应,它不应该直接给出修复代码,而应该先请求读取src/auth/login.py和 grep 日志。如果模型直接开始编代码,说明你的常驻层里“输出格式”约束不够强,或者索引层没有正确传递。

成功的结果是:模型首轮只返回一个“检索计划”,比如“我需要读取 login.py 并搜索日志中的 Traceback”。然后你把这个计划喂回模型,它才会拉取具体内容。这就是动态上下文发现——模型自己决定什么时候要什么。

为了对比,你可以把always_on里的max_tokens调到 8000,把整个 src 目录内容塞进去,再跑一次。你会发现模型首轮就开始改代码,但改出来的函数名经常对不上。这就是静态上下文的典型症状:信息过载导致注意力分散。

如果你想换模型验证,只需要改model参数。TaoToken 支持在同一个 Key 下切换,比如换成gpt-4o或gemini-1.5-pro。建议固定任务和配置,只换模型,记录三次结果。实测下来,不同模型对触发词的敏感度不一样,Claude 系列更倾向于先检索再动手,GPT 系列有时会跳过检索直接生成。这个差异本身就是上下文工程要关注的。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

这一节整理你在接入和验证过程中最可能撞上的四个报错,每个都给出真实报错文本和排查路径。

第一个是 401 Unauthorized。报错通常长这样:

{"error": {"message": "Invalid API key", "type": "invalid_request_error"}}

原因基本是 Key 没配对。检查三件事:环境变量TAOTOKEN_API_KEY是否真的导出成功(用echo $TAOTOKEN_API_KEY看前几位);Key 是否带了多余空格;Base URL 是否写成了https://taotoken.net/api而不是带路径的地址。注意 Base URL 不要加 UTM 参数,那是给网页用的。

第二个是 local proxy failed。这个报错一般出现在你本地起了代理工具,或者环境变量里残留了HTTP_PROXY。报错文本类似:

APIConnectionError: Connection error. local proxy failed to connect

排查方法是先清掉代理环境变量:

unset HTTP_PROXY unset HTTPS_PROXY unset ALL_PROXY

然后确认你的网络能直接访问https://taotoken.net/api。如果你在公司内网,可能需要找网管开白名单,而不是自己挂代理。

第三个是 reading choices 相关报错。典型文本:

KeyError: 'choices'

或者

TypeError: 'NoneType' object is not subscriptable

这通常是因为响应体不是标准的 OpenAI 格式,或者请求被拦截返回了 HTML。先打印完整响应看看:

print(resp.model_dump_json(indent=2))

如果返回的是 HTML 登录页,说明你的 Key 没生效,请求被重定向了。检查base_url是否漏了/api,或者 Key 是否过期。

第四个是 OAuth 相关报错。如果你用的是 Claude Code 或 Cline 这类工具,可能会看到:

OAuth token expired, please re-authenticate

注意,TaoToken 走的是 API Key 通道,不是 OAuth。如果你在工具里选了 OAuth 登录模式,就会撞上这个。正确做法是在工具的模型配置里选“API Key”模式,填入 TaoToken 的 Key,Base URL 填https://taotoken.net/api,Model ID 填你要用的模型名,比如claude-3-5-sonnet。这三件套缺一不可。

如果你用的是 CC Switch 或 Cline MCP,配置里同样要写全 Base URL、Key、Model ID。Cline 的 MCP 配置一般在cline_mcp_settings.json,Codex 的 auth.json 则在~/.codex/auth.json。不管哪个文件,核心字段都是这三个。少一个就会报 401 或 reading choices。

排障的时候,建议先用 curl 做最小验证:

curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"claude-3-5-sonnet","messages":[{"role":"user","content":"hi"}]}'

如果 curl 通了,说明通道没问题,问题在客户端配置。如果 curl 也不通,先检查 Key 和网络。

6. 从 Prompt 到 Context:把上下文工程变成你的默认工作流

聊到这里,你应该能感觉到:Prompt 工程和上下文工程不是替代关系,而是层次关系。Prompt 解决的是“怎么问”,上下文工程解决的是“问之前给什么、问之后补什么”。当模型足够聪明时,少给一点上下文,让它自己去找,反而比硬塞一堆信息效果更好。

我自己的做法是把第三节那份配置模板固化到项目里,每次开新任务先跑一遍verify_context.py,确认触发词命中正常。然后根据任务类型微调retrieval_triggers,比如做前端任务时加上“组件”“样式”触发词,做后端时加上“接口”“数据库”。这样 Agent 的行为是可预测的,而不是每次靠运气。

如果你还没开始做上下文分层,建议先从最小闭环开始:只做常驻层和索引层,按需层先用文件路径代替内容。跑通之后,再逐步把 MCP 描述、终端日志、聊天历史接进来。TaoToken 的模型对话入口在 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,你可以用它快速对比不同模型在同一份上下文配置下的表现。接入文档在 https://taotoken.net/doc ,API Keys 在 https://taotoken.net/api-keys ,需要哪个直接取。

最后留一个实用技巧:把retrieval_triggers的命中日志打到.agent/archive/trigger.log,每周看一次。你会发现有些触发词从来没被命中过,有些则频繁误触发。删掉没用的,收紧太宽的,你的 Agent 会越来越准。上下文工程不是一次配置,而是一个持续调优的过程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询