主从式的上下文与通信:消除上下文割裂
作者:程序员马丁
Ragent AI —— 从 0 到 1 纯手工打造企业级 Agentic RAG,拒绝 Demo 玩具!AI 时代,助你拿个offer。
上一篇我们手写了主从式多智能体:编排者(Orchestrator)负责拆任务和选人,商品、售后、IoT 子 Agent 各自带着独立的人设与工具箱执行任务。
这套架构已经能跑,但还留下了一个关键问题:子 Agent 的上下文是隔离的,它们怎么知道前面的 Agent 做了什么?
假设用户对比特严选提出这样一个请求:
订单 88231 的扫地机老掉线,帮我查保修并给出处理建议;如果要换新,预算 2000 元以内,希望能和家里的比特 SoundBox Mini 智能音箱联动。
这个请求至少涉及三个领域:
- 售后 Agent 查询订单商品和保修状态;
- 商品 Agent 根据预算筛选换新候选;
- IoT Agent 核对候选商品与现有音箱的联动能力。
商品 Agent 需要知道售后 Agent 查到的商品型号,IoT Agent 又需要知道商品 Agent 给出的候选。如果每个 Agent 都从用户原话重新推理,容易重复查询;如果把所有聊天记录全部塞给每个 Agent,上下文又会迅速膨胀。
咱们只解决一个基础问题:
在保持子 Agent 上下文隔离的前提下,怎样把必要信息准确地交给下一个 Agent?
多智能体通信,本质上是上下文工程
上下文工程(Context Engineering)指的是:为一次模型调用选择、组织并注入真正需要的信息。
单 Agent 只有一份上下文。拆成多个 Agent 后,每个 Agent 都有自己的局部上下文,于是系统必须额外回答三个问题:
- 哪些信息需要在整个请求内长期保存?
- 哪些信息只是一次性的任务通知?
- 当前 Agent 应该看到哪些前序结果?
这三类信息不应该混在一个不断增长的聊天记录里。更清晰的划分是:
| 信息类型 | 示例 | 负责组件 |
|---|---|---|
| 请求级状态 | 用户原话、订单号、预算、已有设备 | AgenticScope |
| 一次性事件 | 给某个 Agent 的任务、结果就绪或失败通知 | MessageHub |
| 子任务结果 | 执行状态、自然语言答复、可共享事实 | AgentResult |
| 事实的来源 | 从工具返回里确定性抽取的字段 | ToolFactExtractor |
| 依赖关系 | 商品 Agent 依赖售后结果 | HandoffRunner |
| 最终输出 | 按完成顺序汇总各领域结果 | Aggregator |
道理很简单:
状态归状态,消息归消息;事实由工具产生,前序结果只按显式依赖交给下游。
这六个组件各自站在什么位置、谁和谁说话,画出来比表格更好理解。

注意,这张图没有让三个 Agent 共享同一份 ReAct 对话。它们共享的是经过选择的请求级状态,而不是彼此的完整思考过程。
本项目中具体代码已上传 GitHub TinyAgent,大家 Clone 项目后,将代码分支切换到 1.16.x,默认主分支是最新代码。运行前复制
.env.example为.env,把自己的 API Key 填进去,默认阿里云百炼平台;.env已加入.gitignore,切分支时不会丢。
先定义结果契约:AgentResult
如果 Agent 之间只传一个 String,调用方无法区分这次执行是否完成,也无法区分写给用户看的答复和后续任务真正需要的字段。
所以第一步不是造黑板,而是先定义最小结果契约:
public record AgentResult(
String agentName,
Status status,
String summary,
Map<String, String> facts) {
public enum Status {
COMPLETED,
FAILED
}
// 省略空值归一化、不可变 Map 复制,以及 completed / failed 两个静态工厂
}
四个字段各有明确职责:
| 字段 | 含义 | 是否适合交给后续 Agent |
|---|---|---|
agentName | 结果由谁产生 | 是 |
status | 这次调用是否正常完成 | 是 |
summary | 这位专家写给用户看的自然语言答复,后面统一叫答复 | 只能当背景,不能当事实证据 |
facts | 显式交接字段 | 是,且必须来自工具或业务系统 |
这里必须守住一个边界:
COMPLETED只表示 Agent 正常返回了结果,不表示结果中的每一句自然语言都已经被证明正确。
通信层负责把结果送到正确位置,不负责完成业务事实审计。
到这里为止,一切听起来都很顺。但真正的坑在下一节:这个 facts 到底由谁填?