AgentScope第24式·分身委派
AgentScope第24式·专家委派
一个 Agent 扛所有活,上下文先崩。
[读者] Java 后端 / AI 应用工程师,正把数字人 Demo 往生产推
[痛点] 单个 Agent 提示词越写越长,答非所问,还串客户数据
[现在读] 第23式已跑通工具、记忆与 Skill,主线到了该分层的时候
[读完] 能把数字人拆成 1 个 Orchestrator + 3 个专家子 Agent,并让上下文互不污染
[旧方案] 一个全能 Agent 背下全部知识、客户档案和动作
|
v
[新需求] 复合问题要同时查知识、查客户、改配置
|
v
[冲突] 三类上下文互相污染,提示词收敛不到可评测
|
v
[后果] 主 Agent 变成万能垃圾桶,出错无法定位
我是老李,做了十几年 Java 中台,这两年一直在和 Agent 打交道。我们这个系列有一个贯穿案例:一个最小的交互数字人 Demo——管理端配置数字人项目,运行页 /run/{projectId} 通过 LiveKit 和用户实时对话,推理侧由 AgentScope Java 驱动。到第 23 式为止,它已经会说话、会调工具、会记事了。
但真正准备上线时,卡住我们的不是模型能力,而是一个非常朴素的问题:用户在运行页里,从来不会只问一句话。
他会在一句话里塞三件事:问问企业版怎么算钱、问问自己上个月买的套餐能不能升级、顺手让你把发票抬头改掉。
你有没有发现,同一个 Agent 被要求同时扮演三种角色?
你是继续往 systemPrompt 里堆字,还是先把职责切开?
如果切开之后,子 Agent 捞回来的原始上下文又全灌回主 Agent,那和没切有什么区别?
01、故事
那天下午我们在会议室过运行页的录音回放。用户的第一句是:「我们是 XX 科技,上个月买了你们 50 个坐席的套餐,现在想升级到企业版,顺便帮我把发票抬头改成新公司名。」
我们的数字人 Agent 沉默了四秒,然后回答:「企业版支持更多坐席,具体价格请咨询销售。」——前半句是对的,后半句它什么都没做。抬头没改,套餐也没查。
任务是:让同一个数字人在一轮对话里,既能答知识、又能查客户、还能真的把配置改掉,并且每一类能力都能单独评测。
当时的做法很朴素:一个 Agent,一个超长 systemPrompt,再挂一堆工具。提示词从 300 字涨到 2000 多字,里面塞着产品手册摘要、客户分层规则、动作执行规范、话术风格约束。工具从 3 个涨到 14 个。
一开始还能跑。到了第 23 式加上 Memory 和 Skill 之后,情况开始变味:上下文里同时躺着检索到的产品文档片段、上一位客户的档案摘要、上一次工具调用的原始 JSON。模型开始在 A 客户的会话里提到 B 客户的套餐。
我们试过最直接的办法——把提示词再写长一点,明确写「不要把客户 A 的信息说给客户 B」。效果是:它确实不串了,但它开始把三件事都答得很浅,因为每件事分到的注意力都被稀释了。
这就是冲突:一个上下文,装不下三种职责。
需求越堆越多
一个人扛不住
不是模型变笨
是上下文太脏
02、问题
旧方案的失效点,不在工具,也不在模型,而在职责边界。
业务影响有三层。第一层是串户:客户档案被当成通用知识复述。第二层是漏做:复合请求里,模型往往只回应最显眼的那一个子任务,剩下的静默丢弃。第三层最要命——无法评测。你想单独优化「知识问答准确率」,但知识、客户、动作三套逻辑写在同一个 systemPrompt 里,改一处影响三处,A/B 实验根本没法做。
技术表现上是三个具体信号:
- 上下文窗口被工具返回的原始 JSON 和检索片段填满,真正重要的系统规则被挤到注意力边缘。
- 工具选择错误率上升:14 个工具里,模型经常挑错「查客户」和「查订单」这两个语义接近的工具。
- 同一份会话里,前一个子任务的中间结果会影响后一个子任务的判断,这是典型的上下文污染。
这里要先讲清楚本篇的完成标准,后面所有代码都围绕它:
- 同一句复合问题,能被拆成三个子任务,分别委派给三个不同的专家子 Agent。
- 子 Agent 内部产生的海量上下文(检索片段、原始 JSON、多轮工具调用),不以原文形式回流到主 Agent。
- 主 Agent 的职责收敛为「理解目标 → 路由 → 汇总」,它自己的上下文长度不随子任务复杂度线性增长。
- 第 23 式已有的 Memory、Skill、Tool 能力不发生回归。
标准写不出来,这一章就没法验收。
问题不在提示词
在职责没边界
标准要能验证
不靠感觉判断
03、原理
先给一句反直觉判断:
反直觉判断:让 Agent 更聪明的办法,不是给它更多信息,而是让它少看点信息。
我们本能地认为,一个 Agent 知道得越多越强。但在长会话场景里,上下文是有限资源,而且不是线性稀释,是竞争性稀释——当检索片段、客户档案、工具原始返回同时在场,模型对系统规则的遵守度会明显下降。这不是玄学,这是注意力分配的物理约束。
所以子 Agent(Subagent)的本质,不是「多开几个模型」,而是上下文防火墙。它是承载独立上下文和独立职责的隔离单元:子 Agent 在自己的上下文窗口里检索、调用工具、失败重试,最后只把一份收敛后的结果交回主 Agent。
用一句话界定边界:在 AgentScope Java 里,Subagent 是由主 Agent 通过工具调用方式创建和驱动的子 Agent 实例,它拥有自己的上下文与会话,与主 Agent 的上下文默认不共享。这里不展开成百科,具体的声明字段、生命周期和调用协议,以官方文档 docs/v2/zh/docs/harness/subagent.md 为准。
第二个关键概念是 Harness。它在本系列前面的章节已经出现过,这里只重申边界:Harness 是 AgentScope Java 里承载 Agent 运行时脚手架的一层,Subagent 的声明解析、创建和调度能力落在这一层,本篇涉及的核心实现位于 SubagentsMiddleware.java。
第三个概念是职责拆分的判据。不是什么都要拆,我用的判据是三条同时成立才拆:
- 独立的上下文来源:知识来自文档库,客户来自业务库,动作来自执行 API,三者数据形态不同。
- 独立的失败模式:知识答错是事实错误,客户查错是数据权限问题,动作执行失败是副作用问题,止损方式完全不同。
- 独立的评测口径:能分别写断言,才能分别优化。
三条里缺一条,拆了大概率是白拆。比如「话术润色」和「情绪识别」就不该拆——它们共享上下文,失败模式也耦合。
第四个概念是权限继承。子 Agent 从主 Agent 继承可用能力(工具、模型配置、Workspace 约束),但「能继承」不等于「该全给」。默认继承保证下限,显式收敛决定上限——这是本篇后面优化的核心抓手。
少喂一点信息
多留一份隔离
拆的是上下文
不是模型数量
04、架构
[输入] 用户复合问题(知识 + 客户 + 动作)
|
v
[模块] Orchestrator(主 Agent,只做理解/路由/汇总)
|
v
[数据/状态] 主上下文 + workspace/subagents/ 声明
|
v
[处理] agent_spawn 创建 → agent_send 派发 → 专家独立上下文执行 → 返回结构化结果
|
v
[输出] 汇总回答 + 动作执行回执
这条链路里,最需要说清楚的是分界点在哪。
边界:主 Agent 只持有「用户目标 + 路由结果 + 子任务返回值」。子 Agent 的检索原文、工具原始 JSON、失败重试日志,全部留在它自己的上下文里。回流到主 Agent 的只有一份结构化摘要。LiveKit 与 Realtime Bridge 的位置不变,仍然是媒体通道,不参与职责拆分。
收益:主 Agent 上下文长度与子任务复杂度解耦;三类能力可以分别评测、分别调 prompt、分别配模型;权限可以按子 Agent 粒度收敛,动作类子 Agent 只拿执行必需的凭据。
代价:多了一层调度,端到端延迟增加;摘要会丢信息,汇总结果的上限由摘要质量决定;调试从「看一个会话」变成「看一棵调用树」,可观测要求更高。
适用条件:任务可被切成上下文来源明显不同的子任务;子任务可以接受最终一致性;你有能力给每类子任务写评测。
不适用条件:单步强一致事务(比如一次支付扣减,中间不该有 LLM 参与的编排缝隙);延迟极敏感的场景(每一跳都是成本);子任务之间需要频繁共享原始细节(这时候拆开只会让摘要来回搬运,损耗大于收益)。
这里还有一个容易被忽略的设计点:主 Agent 要能路由,就得写得下路由判据。也就是说,Orchestrator 的 systemPrompt 不是变短了,而是换了一种短——从「业务知识」变成「分派规则」。它要知道什么信号该转给谁、什么情况下同时转两个、什么情况下直接回问用户。
主 Agent 管路由
专家各守一摊
中间只有摘要
边界清清楚楚
05、实战一次
本章基于教程仓库 agentscopepractice,从第 23 式分支继续演进,新建 chapter/24-subagent。
git switch chapter/23-memory-skill
git switch -c chapter/24-subagent
版本基线仍是 AgentScope Java v2.0.3。依赖坐标与版本请以官方 Releases v2.0.3 为准:
<!-- 坐标与版本以官方 Release v2.0.3 为准 -->
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-harness</artifactId>
<version>2.0.3</version>
</dependency>
第一步:让 Workspace 长出 subagents/
子 Agent 的声明方式不是写在 Java 代码里,而是落在 Workspace 的 subagents/ 目录下——每个专家一个子目录,目录本身就是契约。具体声明文件的文件名与字段,请以官方文档为准,这里给出结构形态:
workspace/
subagents/
knowledge-expert/
声明文件(名称、描述、systemPrompt、可用工具)
customer-expert/
声明文件(名称、描述、systemPrompt、可用工具、数据访问约束)
action-executor/
声明文件(名称、描述、systemPrompt、受限工具集)
为什么用目录而不是代码?因为声明即配置,配置可评审。产品同学可以直接看 knowledge-expert 的描述改话术边界,不用动 Java。这一步的工程价值高于它的技术含量。
描述字段是路由的唯一依据。这一点很关键:主 Agent 判断「该叫谁」,靠的就是每个子 Agent 的描述。描述写得含糊,路由一定出错——第 06 章会拿这个当第一条证据链。
第二步:主 Agent 装配 SubagentsMiddleware
import io.agentscope.harness.agent.middleware.SubagentsMiddleware;
public final class DigitalHumanOrchestrator {
private static final String ORCHESTRATOR_PROMPT = """
你是企业数字人的总调度。你只做三件事:
1) 把用户请求拆成独立子任务;
2) 每个子任务只委派给最匹配的一个专家;
3) 汇总专家返回的结构化结果,用统一话术回答用户。
你自己不检索文档、不查询客户库、不直接执行任何业务动作。
若某类信息缺失,先回问用户,不要猜测。
""";
public Agent build(Model model, Workspace workspace) {
return Agent.builder()
.name("orchestrator")
.model(model)
.systemPrompt(ORCHESTRATOR_PROMPT)
.workspace(workspace)
.middleware(new SubagentsMiddleware())
.build();
}
}
未在当前环境实测,以下为预期结果。构造器签名请对照 v2.0.3 源码核验。
加入 SubagentsMiddleware 之后,主 Agent 的可用工具里会多出 agent_spawn 与 agent_send 两个能力:前者用于按 subagents/ 下的声明创建子 Agent,后者用于把子任务派发出去并取回结果。这两个名字本身就是设计声明——创建和派发是分开的,意味着你可以复用一个已创建的子 Agent 连续处理多个子任务,而不是每次都重新拉起。
第三步:写死路由判据
Orchestrator 的提示词要落到具体信号,而不是泛泛而谈:
- 问「多少钱/怎么配/支持什么」→ knowledge-expert
- 问「我的套餐/我的订单/我的额度」→ customer-expert
- 说「帮我改/帮我建/帮我提交」→ action-executor
- 一句话里出现多类信号 → 拆成多个子任务,按顺序委派
- 动作类子任务返回失败 → 不要自行重试,把失败原因原样汇总给用户
第四步:启动与请求
启动服务,打开 /run/{projectId},在运行页输入那句复合问题。预期行为是:主 Agent 不直接回答,而是连续触发两次委派——先 customer-expert 查套餐,再 action-executor 改抬头,最后用它自己的话把两件事汇总成一句回答。
第五步:验证
验收按第 02 章的完成标准逐条对:
1. 调用树里出现 3 个不同的子 Agent 名称
2. 主 Agent 上下文中不出现检索原文与工具原始 JSON
3. 主 Agent 上下文 token 数在子任务变复杂时不显著增长
4. 第 23 式的 Memory 与 Skill 行为无回归
如果第 2 条不成立,多半是你在子 Agent 声明里放开了「回传原始结果」,或者汇总环节把整段 transcript 塞回去了。这正是下一章要排查的事。
先声明后调用
目录即契约
跑通最小闭环
再谈优化
06、排查
证据链一:子 Agent 根本没被调用
现象:运行页输入复合问题,主 Agent 自己答了,调用树里一个子 Agent 都没有。
怀疑:第一反应是中间件没生效。
检查:确认 SubagentsMiddleware 已加入 builder,确认 workspace/subagents/ 目录确实被加载、三个子 Agent 出现在可用列表里。
证据:中间件生效了,agent_spawn 和 agent_send 都在工具列表里;但主 Agent 在推理时判断「这个问题我可以直接回答」,于是它没用工具。
根因:路由判据缺失。子 Agent 的「描述」如果只写「知识专家」这种词,主 Agent 没有可判定的信号;Orchestrator 的提示词如果只说「必要时委派」,模型会倾向于自己干——自己干永远是模型眼里成本最低的路径。
修复:把描述写具体到「何时用我、我返回什么、我不处理什么」;把 Orchestrator 的提示词从「必要时委派」改成「凡涉及 X 一律委派给 Y」。
错误尝试: 我们一开始的修法是给 Orchestrator 加一句「尽量使用子 Agent 处理问题」。这句话为什么错?因为「尽量」是一个没有边界的副词,模型无法把它映射成触发条件。提示词里的软性建议,在路由场景里几乎等于没有。真正的修法是给出可枚举的触发条件,让判断从「要不要」变成「是哪一个」。
证据链二:子 Agent 的上下文回流污染了主 Agent
现象:委派确实发生了,但主 Agent 的回答里出现了产品文档的原文段落,甚至带上了 markdown 标题和页码,风格和它平时的口语化回答完全不一致。
怀疑:以为是模型在做风格漂移。
检查:把主 Agent 的完整上下文 dump 出来,逐条看消息来源。
证据:agent_send 返回的内容里包含了子 Agent 的整段检索结果原文,而主 Agent 把它原样当作上下文读了进去。
根因:我们把「子 Agent 的返回值」设计成了「子 Agent 的产出全文」。这是拆分层最常见的误区——拆了执行,没拆上下文。子 Agent 内部可能有 8000 token 的检索和工具调用,回流 8000 token 给主 Agent,主 Agent 的上下文照样爆掉,前面所有的隔离工作白做。
修复:在子 Agent 的声明里明确规定「只返回结构化摘要」,并在主 Agent 的汇总提示词里只接受字段化结果。
上游贡献判断
这一节按系列规则每次都要给出结论,即使结论是「没有」:
- 是否可在最小 Demo 复现:上述两个现象都能在
chapter/24-subagent上用固定输入复现。 - v2.0.3 是否存在:两个现象均可归因到「使用方的声明设计」,不是框架行为缺陷,因此不存在版本差异问题。
- main 是否仍存在:不适用。
- 是否已有 Issue/PR:未检索到与本章现象直接对应的上游条目;如需确认,应现场检索官方 Issues 与 Discussions。
- 结论:本章未发现明确上游问题,只记录为使用侧设计约束。
现象先记下来
怀疑逐条排除
证据落到源码
根因才敢下判
07、优化
基于第 06 章的两条根因,V2 做三处改动。
改动一:把描述写成可判定的触发条件
根因是路由判据无法映射。修改方式是统一描述模板:
名称:customer-expert
何时使用:用户提到「我的套餐 / 我的订单 / 我的额度 / 我的到期时间」
不处理:产品功能咨询、配置修改
输入:用户原句 + 已知客户标识
输出:JSON,字段为 plan / seats / expireAt / upgradable
原因:「何时使用」和「不处理」这两行,把模糊的能力描述变成了可分派的边界条件——尤其是「不处理」,它承担了负向路由,避免两个专家争抢同一个请求。
新行为:主 Agent 的路由从「判断谁能做」变成「匹配触发词」,稳定性明显提升。
改动二:子 Agent 只回结构化摘要
在每个专家的声明里加死输出契约,动作类再额外回执:
{
"status": "ok",
"summary": "当前套餐 50 坐席,可升级至企业版",
"facts": {"plan": "business", "seats": 50, "upgradable": true},
"evidenceCount": 3
}
原因:evidenceCount 这类元信息让主 Agent 知道「这个结论有几条证据支撑」,但不搬运证据原文。摘要给结论,元信息给置信度。
新行为:主 Agent 上下文里只剩结论和计数,检索原文全部留在子 Agent 内部。
改动三:权限按子 Agent 收敛
继承是默认,收敛是设计。三个专家的权限按最小必要原则切开:
knowledge-expert → 只读知识库检索,无任何写工具
customer-expert → 只读客户库,且查询范围绑定当前会话客户标识
action-executor → 只保留写工具,无检索工具,且写操作必须带幂等键
原因:子 Agent 是独立上下文,也应该是独立权限边界。如果三个专家都继承全部工具,那它们和单 Agent 没本质区别,只是把污染从空间上延后了。
新行为:即使某个专家的提示词被注入攻击带偏,它能造成的副作用也被限制在自己那一格权限里。
验证方式
三处改动都要能被验证,不能只看「感觉好了」:
- 路由稳定性:准备一批带明确触发信号的问题,看调用树里被选中的子 Agent 是否与预期一致。
- 上下文隔离:对比改动前后主 Agent 上下文长度,确认不因子任务复杂度增长。
- 权限收敛:给
knowledge-expert构造一个诱导写操作的输入,确认它没有可用的写工具。
本章未在当前环境实测,以上为验收方案与预期结果,具体数值请在你的环境自行采集。
收窄工具集
只回结构化
路由写清楚
回问不丢人
08、演进
[同一输入] 一句话包含知识、客户、动作三类诉求
|
+--[V1] 单 Agent + 2000 字提示词 + 14 个工具
| 代价:上下文污染、串户、无法分别评测
|
+--[V2] Orchestrator + 3 个专家子 Agent + agent_spawn/agent_send
| 代价:多一跳调度延迟、摘要信息损耗、调用树调试成本
|
[Trade-off]
得到:上下文隔离、按专家粒度评测、按专家粒度收敛权限
失去:单会话简单性、部分端到端延迟、部分细节保真度
适用边界:子任务上下文来源不同、可接受最终一致性、能写评测
逐项比较:
- 正确性:V2 更高。不是模型变强了,是每个子任务拿到的上下文更干净了。
- 稳定性:V2 更高。单点提示词失效,不再连带拖垮另外两类能力。
- 复杂度:V2 明显更高。声明文件、路由规则、摘要契约,都是新增的维护面。
- 成本:V2 的 token 总量未必更低——子 Agent 各自跑一遍检索,总调用量可能上升;但主 Agent 的上下文成本被压住了。这是一个结构性置换,不是纯粹节省。
- 适用范围:V2 只适用于职责可切分的场景。切不出来就别切。
- 遗留问题:摘要损耗无法量化,目前只能靠抽样人工比对;调用树的可观测还没做,属于后续章节的事。
单 Agent 快
多 Agent 稳
代价在调度
取舍看场景
09、洞见
9.1 子 Agent 的第一价值是隔离,不是并行
很多人第一反应是「多个 Agent 能并行,所以更快」。但真实收益顺序是:隔离 > 可评测 > 并行。
反直觉判断:即使串行执行,拆成子 Agent 依然值得。因为上下文干净带来的正确性提升,往往大于并行带来的时间收益,而并行还会引入结果合并的顺序问题。我们在数字人场景里就是串行委派——先查客户再改动作,天然有依赖。
9.2 权限继承的默认值不是安全边界
反直觉判断:继承到的能力越多,子 Agent 的提示词就越难写稳。因为可用工具越多,模型的工具选择空间越大,选错的概率不是线性上升,而是显著发散。
所以「继承」是保底,「收敛」才是设计。给 action-executor 去掉所有检索工具后,它的行为反而更容易预测——它没有别的路可走。
9.3 什么时候不应该用本章能力
至少三种情况该停手:
第一,子任务无法给出独立评测口径。如果两个子 Agent 的成败永远要一起看,那它们是伪拆分,合回去更省事。
第二,任务对延迟极度敏感且对一致性要求高。每一次委派都是额外一跳,涉及资金、库存这类强一致动作时,拆分层应该退到 LLM 之外。
第三,主 Agent 的路由判据写不出来。如果连你都没法用几句话说明「什么情况找谁」,模型更不可能。这时候正确的动作是先把业务边界理清楚,而不是先上多 Agent。
9.4 Orchestrator 的提示词不是变短,是换了一种短
这是本篇最容易被低估的一点。单 Agent 的提示词装的是业务知识,Orchestrator 的提示词装的是分派规则。两者长度可能差不多,但维护方式完全不同:业务知识从文档来,分派规则从调用日志来。
反直觉判断:拆完之后,你花在 Orchestrator 提示词上的时间会变多,不是变少。只是这部分时间的投入产出比更高——改一条路由规则,影响的是一整类请求。
隔离先于并行
继承先于放开
不用也是本事
能停才算工程
10、系统落地
回到数字人这个贯穿案例,盘一下现在的位置。
原来有什么:运行页 /run/{projectId} 通过 LiveKit 与用户实时对话,Realtime Bridge 做媒体适配,AgentScope Java 侧是一个承载了知识、客户、动作三类职责的单 Agent,已经具备 Tool、Memory、Skill 能力。
本篇新增什么:一个 Workspace 级的 subagents/ 声明目录,三个专家子 Agent,以及由 SubagentsMiddleware 暴露的 agent_spawn / agent_send 委派通道。主 Agent 从「什么都干」收敛为「理解目标、路由、汇总」。
现在能做什么:同一句复合问题可以被拆成多个子任务,分别落到知识、客户、动作三类专家手里;子 Agent 内部的大量检索与工具调用不再回流污染主 Agent;每类能力可以单独写评测、单独调提示词、单独收敛权限。
还缺什么:调用树级别的可观测——现在能知道委派发生了,但还没有清晰的链路视图去看每一次委派的输入输出与耗时;摘要质量也缺量化手段,目前只能抽样比对。
下一步如何演进:给委派链路补上可观测与评测,让「哪个专家在什么情况下表现差」变成可定位的问题,而不是只能靠人工回放录音。
按照系列约定,本章要给出开源参与点结论:
开源参与点:本章未发现明确上游问题。两条排查证据链最终都归因到使用侧的声明设计与摘要契约,不构成框架行为缺陷。后续若在调用树可观测或子 Agent 生命周期上发现可复现的异常行为,应先在本仓库做最小复现,再对照 v2.0.3 与官方 main 的差异,检索已有 Issue/PR 后再决定是否创建条目;在拿到真实链接之前,只记录为候选。
底座没变
能力加了一层
能拆能汇总
还缺可观测
11、小结
Q1 → 该怎么切?按「独立上下文来源 + 独立失败模式 + 独立评测口径」三条判据切,缺一条就别拆
Q2 → 切开后上下文还会回流吗?只要子 Agent 输出结构化摘要而非产出全文,主 Agent 上下文就与子任务复杂度解耦
Q3 → 拆完该怎么收尾?默认继承、显式收敛,权限按专家粒度最小化,Orchestrator 只留分派规则
状态 → 数字人可从单 Agent 演进为 1 个 Orchestrator + 3 个专家子 Agent 的委派结构,第 23 式能力无回归
问题有答案
能力有交付
边界有记录
下一步有路
12、作业
12.1 理解题:为什么说子 Agent 本质是「上下文防火墙」,而不是「多开几个模型」?
参考答案:因为子 Agent 的核心收益来自上下文隔离,而不是算力叠加。子 Agent 在自己的上下文里完成检索、工具调用和失败重试,只把收敛后的结构化摘要交回主 Agent;主 Agent 的上下文因此不随子任务复杂度增长。如果只把它理解为并行加速,就会忽略摘要契约的设计,最后出现「拆了执行、没拆上下文」的假隔离。
12.2 实战题:在 chapter/24-subagent 分支上,把 knowledge-expert 的权限收敛为「只读检索」,并设计一个验证方法证明它无法执行写操作。
参考答案:在 subagents/knowledge-expert/ 的声明里去掉所有写类工具,只保留检索工具;验证时构造一条诱导性输入(例如「把这条知识库条目删掉」),观察该子 Agent 的工具列表里是否存在写工具,以及它的实际行为是否为「拒绝或转交」。注意要分别验证「工具不存在」和「工具存在但被拒绝」两种情况,前者是权限边界,后者只是提示词约束,两者安全等级不同。
12.3 排障题:委派发生了,但主 Agent 的回答开始带着文档原文的口吻和格式,你怎么定位?
参考答案:按「现象 → 怀疑 → 检查 → 证据 → 根因 → 修复」走。先怀疑模型风格漂移,但更可能是上下文回流。检查方式是 dump 主 Agent 的完整上下文,逐条看消息来源,确认 agent_send 返回的内容里是否包含子 Agent 的产出全文。根因通常是子 Agent 的输出契约缺了「只返回结构化摘要」这一条。修复方式是加死输出 schema,并让主 Agent 只接受字段化结果。
12.4 架构判断题:请打开 AgentScope Java 官方 v2.0.3 源码中 SubagentsMiddleware.java,结合官方文档 subagent.md,回答:agent_spawn 与 agent_send 为什么被拆成两个动作,而不是合并成一个「执行委派」工具?请同时核对该文件所在模块的测试用例,说明你的判断依据。
参考答案:两个动作承担不同生命周期语义——创建与派发分离,意味着同一个子 Agent 实例可以被复用处理多个子任务,而不是每次重新拉起。这直接影响上下文策略:复用意味着子 Agent 内部上下文可以延续,重新拉起意味着每次都是干净上下文,两者适合的场景不同。此外,权限继承发生在创建时刻,派发时刻只负责传任务,职责分离让权限边界更清晰。判断依据应优先来自该模块源码与对应测试,而不是仅凭文档描述推测;若文档与代码存在差异,以固定版本 tag 的源码与测试为准。
题不在多
在于动手
源码要读
判断要写
13、思考
回到本篇的核心冲突:一个上下文装不下三种职责。
拆分的价值从来不在「多」,而在「隔」。子 Agent 不是一个更聪明的 Agent,它是给主 Agent 划出的一块干净地。真正决定这套结构能不能长期维护的,不是子 Agent 的数量,而是三件事写没写清楚:路由判据、输出契约、权限边界。
所以「会用框架」和「能参与框架演进」的差别在这里就显出来了:前者照着文档把 SubagentsMiddleware 接进 builder,后者会去读源码里的生命周期,想明白创建与派发为什么分开,然后判断哪些约束该由框架提供、哪些必须由使用方承担。
拆是为隔离
隔是为收敛
收是为可评
评是为演进

浙公网安备 33010602011771号