你发了 SDK、CLI、API,开发者在用,现在 AI 编程 Agent 也在用——但方式完全不一样。大多数时候你根本不知道,从”开发者输入 prompt”到”Agent 生成代码”之间到底发生了什么:Agent 在读你的文档?调你的 MCP server?还是凭训练数据猜?
这篇文章完整拆解了 Agent 处理一个请求的 7 步信息级联。每一步都可能让你的工具被忽略、被误选、或者被错误调用,而你在外面什么都看不见。
起点:harness 组装上下文
开发者在编程 Agent(Copilot、Claude Code、Cursor)里输入了一条 prompt。在这条 prompt 到达模型之前,harness 先把上下文窗口拼好。拼进去的东西包括:
- 系统提示词(harness 自有的,你看不到也改不了)
- 环境信息:操作系统、工作目录路径
- harness 认为相关的工作区文件
- 已安装扩展的工具描述(MCP server、skill、自定义 Agent)
- 对话历史
- 指令文件(
.github/copilot-instructions.md、AGENTS.md等) - 开发者的 prompt
每个 harness 的拼法不同,但共同点是:上下文窗口有限。如果开发者装了 20 个扩展,harness 可能会压缩工具描述、丢掉一部分、或者按相关性排序。你的扩展描述在模型看到之前就已经在竞争空间了。如果超过 harness 设定的长度限制,直接被丢弃——不管它有多相关。
一些你从没想过的细节也会影响模型决策,比如操作系统和目录路径。模型会据此生成平台相关的代码、假设不同的工具链、甚至选不同的默认配置。
模型”读全场”
模型收到拼好的上下文后,做了一件人类不会做的事:同时读所有东西。系统提示词、工具描述、工作区上下文、开发者的 prompt,一次读完,建立一个”什么可用、开发者要什么”的心理模型。
这时候训练数据开始起作用。如果模型在预训练阶段见过你的技术,它已经有”观点”了——它认为自己知道你的 API 模式、SDK 约定、常见报错。如果没见过,它什么都没有,要么求助,要么根据类似技术猜。
模型这时要做的判断是:我有足够的信息开始写代码,还是需要调工具?
这个判断取决于模型的行为倾向和 harness 加的指令。有些 Agent 倾向于立刻调工具,有些先用自己的知识、只在用户明确要求时才调。有些先上网搜最新信息,有些觉得自己知道得够多就直接动手。即使你的扩展做得再好,一个 Agent 可能主动调它,另一个可能从来不碰——除非开发者明确要求。
工具选择:可能被跳过
如果模型决定需要更多信息,它会看可用的工具和 skill。你的 MCP server 的工具描述在这里起作用。模型读每个描述,判断:这个工具对当前任务有帮助吗?
注意,这个判断是基于语义匹配,不是关键词搜索。模型在解读意图。如果开发者说”authentication”,你的工具描述是”configure identity provider settings”,模型需要自己搭桥。
即使你的描述完美匹配了意图,模型仍然可能跳过它。如果任务看起来够简单,或者模型对自己已有的知识有信心,它就不会去调你的工具。最痛苦的情况是:模型的训练数据里确实有你的技术,但已经过时了——高信心,旧信息。
如果模型没选任何工具,它就用预训练数据。用它学到的那个版本的 SDK,不管距离训练截止已经过了多少个月。如果你的 API 在此之间改过,生成的代码就是错的,而且开发者和 Agent 都不知道。
工具调用:参数可能填错
假设模型选了你的工具。它根据工具 schema 和开发者的意图构建参数。但模型可能把意图映射到错误的参数上,或者编造 schema 里不存在的值。
如果多个工具匹配了意图,模型可能调其中一个,也可能两个都调。这不只是相关性竞争的问题。比如有两个来自不同 MCP server 的工具都能提供更多信息,一个可以直接调用,另一个走子路由——先返回子工具信息,再调子工具才能拿到答案。如果第一轮一个工具直接返回了信息,另一个返回了路由指令,模型可能觉得已经够了,永远不会调那个子工具,路由彻底失败。这就是为什么单独测试工具不够,你需要在开发者实际使用的组合环境下测试。
你的 MCP server 收到调用,处理请求,返回内容。返回什么极其重要。 返回太多,模型要么忽略一部分,要么被搞糊涂。返回太少,模型用假设填补空白。格式混乱,模型解析出错。返回错误信息,可能让 Agent 直接偏离原始任务——我们见过扩展让 Agent 把项目升级到了开发者没要求的框架版本,或者中途切换了编程语言。
而且所有返回内容都会塞进上下文窗口,消耗 token。如果你返回了 3,000 token 的文档而其实 200 就够了,你刚刚把其他相关上下文挤出了窗口。这就是 drag。
模型处理响应
模型拿到你的工具响应后,把它和上下文里的其他所有东西整合在一起。它现在有开发者的意图、工作区上下文和你的工具输出,要决定:写代码?再调一个工具?还是问开发者一个问题?
如果你的工具返回了清晰、具体的内容(代码示例、schema、分步指南),模型可以继续。如果返回的是一大段参考文档,模型得自己提取相关信息——提取过程可能漏掉关键细节。
你怎么知道?你不知道。工具被调了,内容返回了,外面看起来一切正常。但模型盯上了错误的段落,生成的代码用了一个内部接口。这是最糟糕的质量失败:在有人真正运行代码之前完全隐形。
代码生成
到这一步,上游的每一步要么有回报,要么前功尽弃。如果发现机制正常,模型找到了你的扩展;如果选择正确,它调了正确的工具;如果工具响应优质,模型拿到了准确、最新的信息——生成的代码就会用对 SDK 版本、对 pattern、对认证流程。
如果任何一步失败了,模型回退到训练数据。它可能用旧的 API 版本、选一个竞品 SDK、或者编造一个不存在的接口。开发者看到看起来能跑的代码,运行时才发现挂了,然后怪 Agent。
很多 Agent 集成了语言服务器(LSP),在代码生成过程中就实时响应问题报告,边生成边调整,而不是等到最后。在 VS Code 里,Agent 还会监控 Problems 面板——任何活跃的扩展都可以在那里报告诊断信息:类型错误、lint 违规、废弃警告。如果你的技术对这个反馈有贡献(通过 VS Code 扩展、语言服务器或 linter),你就是在代码生成过程中影响 Agent 的输出,而不只是在事后。这是你能控制的另一个面。
迭代自纠
Agent 不会在第一次生成后就停下。如果 harness 支持(大多数都支持),Agent 会构建代码、运行测试、观察错误、然后重试。
你的技术表面在这里也很重要。如果你的 CLI 报错信息清晰,Agent 能快速自纠。如果你的构建工具或测试运行器返回有具体错误码和建议的输出,Agent 能修复问题。如果你的报错含糊不清(“Error: operation failed”),Agent 就是在盲飞,可能朝错误方向迭代十轮后放弃。
这是 AX 里被忽视的一块:你的报错信息不再只面向人类开发者了,它们也面向 Agent。 Agent 没有直觉可以依赖,它们会逐字理解你的报错。
7 步信息级联
把整个流程串起来看,就是一条依赖链:
- 上下文组装 → 决定模型能看到什么
- 模型解读 → 决定模型认为有什么可用
- 工具选择 → 决定模型是否使用你的扩展
- 工具调用 → 决定模型拿到什么信息
- 响应处理 → 决定模型怎么使用那些信息
- 代码生成 → 决定开发者实际拿到什么
- 迭代自纠 → 决定 Agent 能不能自我修正
第 1 步失败,后面全完。如果 harness 丢掉了你的工具描述,第 3-7 步永远不会发生——你的工具等于不存在。如果第 3 步失败(模型看到了你的工具但没联系到当前任务),结果一样。如果第 4 步成功了但响应质量差,第 6 步产出的代码就是坏的。
这就是为什么只看”我的工具被调了没有”几乎说明不了问题。你的工具可以被正确调用,但如果响应质量差,照样产生 drag。你的工具可以装了但从没被调过,说明发现机制就坏了。这两个极端之间,每一步都有十几种方式在静默地拖垮下一步。
大多数 AX 失败都是隐形的。它们发生在上游,静默地,你永远看不到。光看输出没法诊断——你需要知道到底是哪一步出了问题,因为每一步有不同的修法。
如果你关注 AI 助手、开发工具和软件工程实践,可以关注 Aide Hub。这里会继续分享能落地的工具教程、技术观察和项目经验。