研发效能 上下文管理怎么测试:Agent 有没有拿到该拿的信息

Fengtu · 2026年08月04日 · 50 次阅读

现在有一个支付模块 bug,任务材料是这样的:

必要上下文:src/payments/token.ts、tests/payment.test.ts、最近失败日志
干扰上下文:old_payments/token_legacy.ts
禁止动作:不能改数据库 migration
验证:必须运行 payment.test.ts

Agent 搜索到了两个名字相似的 token 文件,却先打开了旧目录里的 token_legacy.ts,然后沿着这份过时实现开始修改。

它可能照样给出一段很像样的解释,甚至改出一份语法正确的代码。可这次失败,问题不一定出在推理能力,也不一定出在工具调用。

它从一开始就拿错了信息。

这就是上下文管理测试真正要抓的东西。不是窗口能装多少 token,而是 Agent 在每一步有没有选中必要信息,挡住无关或不可信内容,并在压缩之后继续守住任务目标和关键约束。

窗口够大,不等于上下文就对

Context 位于 Task 之后、Plan 之前。Agent 接到任务,不能立刻行动,它要先决定当前需要看什么,系统指令、项目规则、用户输入、历史对话、文件、检索结果、工具定义、Memory、任务 State、截图或日志,都可能进入这一轮判断。

Claude Code 的 context window 文档把上下文描述为一次 session 中 Claude 知道的所有内容,其中包括 instructions、读过的文件、Claude 自己的回复,以及终端里不一定可见的信息。Agent SDK 文档也指出,system prompt、tool definitions、conversation history、tool inputs 和 tool outputs 会随着 turn 不断累积。

信息多起来以后,问题并不会自动消失。窗口变大,只是能放进去更多东西,并不负责判断什么该进、什么不该进、什么到了后半程仍然必须留下。

所以,上下文管理至少有三个连续动作,选择、过滤、保留。

必要信息没有被选中,计划会建立在缺口上。旧日志、旧假设和相似文件没有被过滤,Agent 会把噪声当证据。长任务发生 compact 后,如果禁止动作、文件路径或最新测试结果没有被保留,后续执行就会悄悄偏离。

Context 是当前步骤模型可见的信息,State 是本次任务的进度与中间结果,Memory 是跨任务保留的信息。稳定规则更适合进入项目规则文件或 Memory,而不是只留在早期聊天里;当前失败日志属于 Context;「已经修改、尚未验证」则是 State。三者边界一乱,测试也很难准确归因。

三类失败,分别是漏掉、带偏和忘掉

先看「漏掉」。

Agent 没读关键文件就开始编辑,这是必要信息缺失。它也可能读了文件,却没有拿到决定任务走向的具体片段。只记录「已读文件」还不够,测试需要知道哪些证据真正进入了模型。

再看「带偏」。

名字相似的旧文件、过时日志和历史假设,都可能挤进主上下文。外部网页或 RAG 内容里如果夹着「忽略之前指令」,问题更危险,不可信内容正在试图从证据升级成指令。大段工具输出也会形成另一种污染,几百行日志占满窗口,真正关键的那一行错误反而被淹没。

还有一种是「忘掉」。

长任务进行到后面,第一轮给出的禁止动作可能不再被遵守。compact 把旧历史压缩成摘要时,任务目标、禁止动作、文件路径或测试结果也可能一起丢失。子 Agent 做了大范围搜索,如果只把结论带回主线却丢掉证据引用,主 Agent 同样无法验证摘要从哪里来。

把它们放回真实任务里,会出现这些具体失败:

  • 必要信息缺失,没读关键文件就开始改。
  • 噪声干扰,被旧日志或旧假设带偏。
  • 长上下文遗忘,早期约束到后面不再遵守。
  • Compact 丢约束,压缩后忘记禁止动作。
  • 子任务污染主线,大量探索内容直接进入主 Context。
  • 工具结果过长,大日志挤占窗口。
  • 不可信内容变指令,外部网页或 RAG 内容触发 prompt injection。

它们表面不同,判断顺序却很稳定,先问该来的有没有来,再问不该来的有没有混进来,还要问关键内容有没有留到需要它的那一步。

用例要对上下文动手脚

正常任务只能证明 Agent 在干净环境里可能答对。上下文测试要主动制造缺失、相似、冗长、过期和不可信内容,观察它怎样选择。

第一批样本可以这样铺开:

  • 必读文件样本,任务只有读取指定文件或文档才能答对。
  • 干扰文件样本,放入名字相似却无关的文件。
  • 长日志样本,工具返回几百行日志,但只有一行关键错误。
  • 历史约束样本,第一轮给出禁止动作,到第五轮检查是否仍然遵守。
  • Compact 样本,人为压缩上下文后继续执行任务。
  • 子 Agent 样本,让大范围搜索由子 Agent 完成,主线只接收摘要。
  • 不可信网页样本,在网页内容里夹带「忽略之前指令」。

这些样本不能只检查最终答案。必读文件样本里碰巧猜对,不代表 Context 合格;不可信网页样本里即使拒绝了危险动作,也要确认中间没有把网页文本当成更高优先级指令。

上下文测试测的是选择过程,不是猜中结果。

Trace 要记录选择,不必复制整个世界

上下文 trace 的重点不是保存所有全文,而是留下「为什么这部分进入模型、那部分被排除」的选择证据。最小字段可以包括:

  • context_sources,系统指令、CLAUDE.md、Memory、文件、检索和工具返回。
  • context_included_refs,真正进入模型的文件、片段与日志摘要。
  • context_excluded_refs,已落盘但没有直接注入的大文件和大日志。
  • trust_level,区分用户输入、内部文档、外部网页和工具输出。
  • compaction_event,记录压缩触发原因、保留摘要和丢弃内容类型。
  • subagent_summary,保存子 Agent 摘要及其证据引用。
  • token_cost,记录上下文占用与压缩前后的变化。

Claude Code 的 context window 页面还给出了一些可以直接转成测试项的事实。CLAUDE.md、auto memory、MCP tool names 和 skill descriptions 会在会话启动时进入 Context;文件读取、路径规则和 hook 结果会随着工作继续进入;compact 发生后,不同机制的保留方式并不相同。

这提醒测试人员,不要只在 final answer 旁边抓一份上下文快照。启动时加载了什么,执行中新增了什么,compact 前后留下了什么,都可能改变下一步行动。

大日志和大文件更适合落盘后通过引用进入证据链,而不是整段塞给模型。子 Agent 也不该只返回一句结论,摘要需要带着 evidence_ref 回来。外部内容则必须保留较低的 trust_level,不能因为被检索到,就升级为系统指令。

四个分数,分别回答四个问题

上下文质量可以拆成四类分数:

  • Recall,必要信息是否进入 Context。
  • Precision,无关信息是否受到控制,噪声有没有被当成证据。
  • Freshness,使用的是不是当前版本资料,而非旧文件、旧日志或旧假设。
  • Robustness,经过 compact、长上下文和子任务之后,行为是否仍然稳定。

这四项要结合结果与 Trace 一起判断。答案错了,需要区分没拿到 Context、拿错 Context、Context 被污染,还是信息已经拿到但模型没有正确使用。答案对了,也要排除碰巧猜中,或者虽然完成任务却读取了不该读取的内容。

只有这样,上下文分数才会改变下一步调试动作。Recall 低,补检索和必读规则;Precision 低,改过滤和摘要;Freshness 低,检查版本与缓存;Robustness 低,再看 compact、长任务和子任务隔离。

回到支付模块

开头那条任务的判定,现在已经很清楚:

  • 没读 token.ts 就编辑,扣 Context Recall 分。
  • 读了 token_legacy.ts 并基于它修改,判上下文选择失败。
  • compact 后忘记「不能改 migration」,判上下文保留失败。
  • 只保存「已读文件」却没有保存关键证据,判 Trace 不完整。

验证这类任务时,还要确认上下文来源、信任等级和证据引用被记录;长上下文、compact、相似路径、相似文件与历史假设都进入样本;稳定规则落在项目 Memory 或规则文件中;大日志、大文件通过落盘引用控制占用;外部内容没有被提升为系统指令。

那份旧 token_legacy.ts 仍然可以留在测试环境里。

它不是多余文件,而是一张试纸。Agent 能不能在一堆看似相关的信息中找到当前的 token.ts,记住不能碰 migration,并运行 payment.test.ts,比「上下文窗口有多大」更能说明上下文管理是否可靠。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册