本页目录
Lesson 05 — 子代理:过程隔离,结论回传
本课目标:把「过程」关进独立子窗口——子代理满额干活,结束只回传结构化结论;主窗口峰值从 5,272 坍缩到 706,压缩次数从 10 降到 0。红线:失败结构化回传(ok=False+原因),绝不装作空结论。
1. 问题:压缩管住了「留下的」,管不住「路过的」
L02 的压缩循环里,每篇全文仍要过主窗口一次(水位检查在装入新文档前,但新文档本身还是进来了)——主窗峰值 5,272 里大半是「正在读的那篇」。子代理换一个思路:全文根本不进主窗——
主窗口(一直很瘦) 子窗口 ×30(每个用完即弃)
┌────────────────────────────┐ ┌──────────────────────────┐
│ system + 目录 │ │ 研读指令 │
│ 结论1(60 tok) │ ◄─── │ S01 全文(350 tok)+ 提炼 │
│ 结论2(60 tok) │ ◄─── │ S02 全文(500 tok)+ 提炼 │
│ … │ │ …(过程死在这里,不回传) │
│ ⛔ S17 失败注记(1 行) │ ◄─── │ S17:3,406 > 预算 → 越限 │
└────────────────────────────┘ └──────────────────────────┘
注意力杠杆:N 个子代理各自满窗 = 总注意力 N×窗口,主窗只付 N×结论的钱。实测(python code.py):
| 配置 | 完成 | 主窗峰值 | 子窗峰值 | 压缩次数 | 在场率 | 计费token |
|---|---|---|---|---|---|---|
| L02 压缩档 | 30/30 | 5,272 | — | 10 | 20/20 | 106,844 |
| L05 隔离档 | 30/30 | 706 | 3,416 | 0 | 20/20 | 39,593 |
压缩次数 10→0 值得多看一眼:隔离在源头消灭了压缩的必要性——「能外置的别压缩」(L02 埋的话)第一次全量兑现。计费也结构性下降:主窗每步重付的「历史」从全文变成了结论行。
2. 隔离契约(三条,测试逐条锁死)
- 回传结论不回传过程:
SubagentResult只含结论/引用指针/诊断数字(子窗峰值、计费)——过程的「账」回传,过程本身不回传。合成窗口里有原文泄漏探针(process_leaked),测试锁死为 False。 - 失败结构化回传:子代理溢出/异常死自己,外面收
ok=False+ 可读原因——主窗注记「⛔ [S17] 子代理失败:子窗口越限(预算 1200 token)——不等于该源无内容」。这与课程十「没能看到 ≠ 没有变化」同宗:报告必须能区分「没内容」和「没干成」。附带「记录先于死亡」:失败结果仍回传尝试时的窗口峰值(尸检数字)。 - 子窗口有物理预算:独立
WindowLedger(enforce=True),subagent_window_tokens是它的全部空间——L01 份额思维的落地:超份额是结构化失败,不是静默容忍。
3. 何时不外包:Cognition 的警示
拆分标准:过程重、结论轻的任务才外包——读一篇 3,400 token 的文档提 60 token 的事实(杠杆 57 倍)✅;跨源矛盾裁决 ❌(F06 与 F16 必须同窗——本课跑法里它们以「结论」形态在主窗相遇,裁决权始终在持有全局视野的主窗)。Cognition 的名文("Don't build multi-agents")批评的正是让各持一角窄上下文的子代理做全局决策——本课程吸收其警示但不照单全收:他们反对的是决策下放,不是过程外包;结论回传+主窗裁决的架构恰好站在安全的一侧。
4. 机制组合(L04×L05):两种诚实
子窗预算 1,200 装不下三篇超长文档时,有两种处理,在场率相同(18/20),失败形态不同:
| 策略 | 结果 | 说法 |
|---|---|---|
| 只隔离 | 27/30 + 3 条显式失败注记 | 「三篇没干成」——拒绝干完 |
| 隔离 + 子窗内整形(L04) | 30/30,结论带截断声明 | 「都干完了,但三篇只读了截断版」 |
没有对错,只有取舍(安全审计场景要前者:宁缺勿假;资讯速览要后者:覆盖优先)。关键是两种都显式——静默才是唯一的错误答案。
5. 与 v4 的诚实关系 + 流派对比
v4 的 researcher 在窗口层面已经做对了「回传结论不回传过程」——search_raw 是函数局部变量,State 只收 finding。这是 map-reduce 架构的礼物(也是 L00 里 A0 流水线永不溢出的原因)。本课把礼物变成显式契约,补齐它缺的三件:子窗物理预算(v4 的 researcher 调用无预算概念)、结构化 failed(v4 靠熔断器管搜索失败,但 LLM 调用本身溢出无处理)、账本份额。
| 流派 | 思路 | 取舍 |
|---|---|---|
| 单窗口硬扛 | 全部过程进主窗 | L00 裸奔:死于 S11 |
| 共享 State 子图 | 代码隔离、窗口不隔离 | 若子图把过程写回 State 就退化成硬扛(v4 侥幸没有) |
| 隔离子代理 | 独立窗口+结论回传+失败契约 | 本课:杠杆巨大;代价是跨子代理信息只能靠结论中转 |
| 多 agent 对话协作 | 子代理彼此对话共建共识 | 贵、共识难、职责糊——Cognition 批评的主对象 |
业界锚点:Claude Code 的 Task/subagent(「子代理的最终报告回传,过程不进主对话」——你在本课程生成过程中就被这样服务过);deepagents 的 spawn 子代理(planning+隔离上下文);Anthropic 多智能体研究系统的 orchestrator-worker 模式(lead 持全局、worker 各研一角、结论汇流)。
6. 跑起来
cd harness-lessons/05_subagent_isolation
python code.py # 契约微演示 → 杠杆对照表 → 失败隔离 → 两种诚实
7. 落地清单
| 文件 | 改动 |
|---|---|
src/research_assistant/subagent.py |
新增:SubagentResult(结论 schema+brief)+ SubagentRunner(独立 enforce 账本/溢出与异常双兜底/尸检数字回传) |
src/research_assistant/config.py |
enable_subagent_isolation(默认 off)、subagent_window_tokens=4000 |
eval_agent/harness_runs.py |
新增 run_isolated_longhaul(每源一子代理;失败线+整形组合线;过程泄漏探针) |
tests/test_subagent.py |
新增 11 测试(三契约逐条/长途四行/确定性) |
验收
cd portfolio-projects/research-assistant
python -m pytest tests/test_subagent.py -q # 11 passed
python -m pytest -q # 412 passed(401 + 11)
cd ../../harness-lessons/05_subagent_isolation && python code.py
8. 本课在两条主线上的位置
窗口经济:子代理是注意力杠杆——过程在子窗烧、主窗只付结论的钱(5,272→706);份额思维落地成子窗物理预算。外置化:「过程」这块最大的临时内容被搬出主窗(虚拟内存图的进程隔离);但需要全局上下文的判断不下放——外包过程,不外包裁决。
🎯 面试话术
「子代理的本质是注意力杠杆:过程在子窗口烧,主窗口只付结论的钱——我的实测是主窗峰值从 5,272 降到 706,而且压缩次数从 10 降到 0:隔离在源头消灭了压缩的必要性。契约有三条:回传结论不回传过程(有泄漏探针测试)、失败结构化回传(ok=False+原因+尸检数字,报告能区分『没内容』和『没干成』)、子窗口有物理预算(超了就死,不静默容忍)。什么不外包?需要全局上下文的判断——Cognition 反对的是决策下放,我外包的是过程;跨源矛盾的两端以结论形态在主窗相遇,裁决权始终在持有全局视野的一方。」