用 Agent 做复杂任务的时候,经常遇到过这种情况:一开始回答得挺好,跑了几轮工具调用之后,开始"忘事",渐渐答非所问,甚至重复之前做过的事情?
这种情况就是网上讨论的非常频繁的问题——上下文污染(Context Pollution)。
这主要是因为 LLM 的上下文越长,注意力越分散。在长上下文中,后面的 token 会逐渐"盖过"前面的内容,模型对早期信息的检索能力明显下降。
具体到 Agent 场景:
调了一次文件搜索,返回 200 行代码
跑了一次测试,输出 50 行日志
中间还试错了几次,debug 信息堆了一摞
这些全塞在上下文里。等到第 10 轮推理的时候,prompt 里 80% 的内容是已经用过的中间结果,真正关键的任务目标反而被挤到角落去了。
debug 轨迹的累积正是长任务性能下降的元凶。如果子任务 A 的错误日志还在上下文里,子任务 B 就被干扰了。
别人怎么解决的
最早的做法是压缩上下文——把旧的工具结果落盘,只留个摘要;或者对整个对话历史做一次 summarization。LangChain 的 Deep Agents SDK 就是这么干的:超过 2 万 token 的工具结果自动落盘,上下文到 85% 的时候触发全量压缩。
但压缩是有代价的,摘要可能丢细节,模型之后需要那个细节的时候找不回来。Anthropic 的上下文工程文章专门提到了"goal drift"——压缩之后模型忘了最初要干什么,开始瞎转悠。
更彻底的方案是子 Agent 委派:给每个子任务开一个全新的上下文窗口,干完活只把结果返回给主 Agent。主 Agent 的上下文始终干净。
这个思路现在已经是业界共识。大部分框架都已经支持了子 Agent 模式。核心思想一样:
主 Agent 负责决策和编排
子 Agent 在隔离的上下文里执行具体任务
只把最终结果(不是中间过程)返回主 Agent
AgentScope 的子 Agent 有什么特别的
概念不新鲜,但实现质量差别很大。AgentScope Java 2.0 在子 Agent 这块有几个设计我觉得值得拿出来讲讲。
零配置就能用
大多数框架要你写一堆代码注册子 Agent。AgentScope 最简单的方式是在工作区放一个 Markdown 文件:
---description: 代码审查专家。当用户需要 review PR、检查代码规范时使用。---你是一个专注代码评审的子 Agent。
文件名就是 agent_id,主 Agent 在推理时自动识别并调用。不需要注册,不需要改 Java 代码。
这个设计看起来简单,但实际用起来差别很大——子 Agent 的定义能跟代码一起提交到 Git,review 的时候大家都能看懂,改起来也方便。
后台任务不用轮询
主 Agent 调 agent_spawn 时可以选同步等结果还是后台跑。后台模式下,子 Agent 跑完不需要轮询——下一次推理开始前,框架自动把结果注入对话:
<system-reminder>后台任务已交付:- task_id=xxx,agent=researcher,status=COMPLETED结果摘要:...</system-reminder>
主 Agent 看到这条提醒自然接着处理。
而其他框架大多需要你手动调 task_output 或者 list_background_agents 去查状态。
用户可以直接跟子 Agent 对话
这个是 AgentScope 独有的能力,配置 expose_to_user=true,子 Agent 就变成一个用户可直接交互的入口,完全绕过父 Agent:
agent_spawn agent_id="researcher" task="调研 AI 趋势" expose_to_user=true适合"分支对话"场景——主 Agent 派一个专家出去,用户独立地跟那个专家继续聊,不用每次都经过主 Agent 转发。
安全边界不会破
子 Agent 会自动继承父 Agent 的权限限制。父被禁用的工具,子也用不了。userId 自动透传,多租户隔离链不会断。
这个在 demo 里感觉不到重要性,但在生产环境里是底线,委派的子任务同样必须安全控。
流式事件实时转发
同步子 Agent 的中间事件会实时流回父 Agent 的 streamEvents() 流中,每个事件带 source 字段标识来源(比如 "main/researcher")。前端可以区分渲染父子 Agent 的输出,用户能看到子 Agent 的实时进度。
什么时候该用子 Agent
几个典型场景:
任务涉及多种专业能力(代码审查 + 文档生成 + 测试),拆成多个专家
特定步骤的上下文特别重(分析大量文件),隔离出去防止污染主 Agent
多个独立任务需要并行跑,可以通过后台创建几个子 Agent 同时处理
不同模型处理不同任务:比如便宜的模型来做数据清洗,贵的模型做最终总结分析
如果你的 Agent 就是简单的一问一答加几个工具调用,就完全没必要用子 Agent了,徒增复杂度。
最后
上下文污染是个隐蔽的问题——它不报错,只是让 Agent 慢慢变傻。子 Agent 委派是目前最有效的解决方案之一:给每个子任务一个干净的上下文,主 Agent 始终保持清醒。
AgentScope 2.0 在这个模式上做得比较完整:从声明式配置到后台任务自动通知,到用户直接交互,到权限继承和流式转发。尤其是零配置的 spec 文件方式和 expose_to_user 这两个设计,在实际项目里省了不少事。