把 Session 还给系统:拆解 DeepSeek Harness 的 Super-agent
让用户不再管理 session,代价是系统得把这件事管好。DeepSeek Harness 搬来的计算机系统老办法,连老问题也一起搬了过来。
如果你同时开过五个 coding agent 的窗口,大概有过这种时刻:盯着第三个窗口想,刚才说的那个接口改动,是跟这个说的,还是跟第五个说的?
模型越来越不需要人一步步盯着,可人还得在窗口之间来回切,记住哪个 session 知道哪件事。DeepSeek Harness(下文简称 DH)团队在 11 月 1 日的长文《Exploring Super-agent Design》里给了一个数字:一个人通常只能同时跟进 3 到 5 个活跃 session。单个任务的上限是模型,多个任务的上限是人的注意力。
他们的结论写在文章中间,我认为是全文最重要的一句:
Session 应该是系统的实现细节,而不是用户的心智负担。
为了做到这一点,原文给出了五个模块:两层架构、事件驱动的 Trigger、全双工多渠道交互、计算/状态/环境分离、Watchdog。原文是按模块讲的,这篇不按模块拆,而是抽出贯穿其中的四个判断:
- Router 不是大脑,是一个分类器;
- 整套系统是一层套一层的快慢路径;
- 上下文窗口是一块缓存;
- 执行环境是一只换不掉的宠物。
每个判断都会讲原文怎么做、我推测它具体怎么实现,以及它没讲透的地方。最后再聊原文留下的开放问题。
先说明两点。原文自己声明讲的是架构设想,配套的 dsh-superagent-prototype 只是验证思路的原型,不是正式产品。文中所有标了「推测」的代码和数据结构都是我的推演,不代表 DH 的实际实现。
先看全貌
环境事件(IM / GitHub / 邮件 / CI / 日历)
│
▼ Trigger
过滤:代码规则 → LLM 判断
│
├─ 已订阅的 Thread ──▶ Worker Session(每任务一个,隔离,干活)
│ │ ▲
│ 汇报 │ │ 派活
│ ▼ │
└─ 未订阅的新事件 ──▶ Router(常驻,不干活)◀──▶ 人
Worker ──命令 / 结果──▶ 端侧 daemon(用户的机器 / 云主机 / 按需沙箱)
Watchdog:主系统之外,定时巡检所有组件
底座:Agent Loop 跑在无状态云容器里,session 状态存在数据库
一句话:前台接需求,后台做任务,事件驱动整个系统,计算放在云上,环境留在原地,旁边再放一个看门狗。
一、Router 不是大脑,是分类器
两层架构拆的是什么
把所有事件都交给一个 session,上下文最连续,但 ReAct 一次只走一步,任务排着队做,不同任务的中间过程还会搅在一起。给每个事件开一个新 session,吞吐上去了,可 session 之间互相不知道对方在干什么,几个 session 分头回复用户,场面会很乱。
DH 的解法是拆成两层:常驻的 Router 负责所有和人的交互、所有派活;上下文隔离的 Worker 一个任务一个,工具齐全,只管干活,不直接对人说话,干完向 Router 汇报,由 Router 统一回复。
我的理解是,这本质上是把「接需求」和「完成需求」拆成了两步。接需求这一步要解决的是和人交互、搜集信息;完成需求那一步才需要最强的模型和完整的工具。
所以 Router 被刻意设计成不干活的,原文说它连 Bash 工具都可以不给。这不是为了省事。只要 Router 能动手,它就会在某些时候觉得「这个小,我自己来」,然后被一个长任务卡住,所有新消息都在后面排队。不干活这条约束是写在架构里的,不是写在提示词里的。
Router 回答的三个问题
原文给 Router 定了三个身份:全局序点、协调点、记忆。序点指所有跨任务的信息都在这里汇聚、统一排定先后,类似并发里的串行化点。
把这三个身份翻译成 Router 每次收到一条事件时要回答的问题:
- 记忆:处理这条事件,需要调出哪些历史?
- 序点:它在全局时间线上排在哪里,之前发生过什么相关的事?
- 协调:交给哪个 Worker?已有的,还是新开一个?
这三个问题的答案绝大多数是「从一个有限的集合里挑一个」。这是分类问题,不是推理问题。原文也承认 Router 的活比预想的简单,轻一点的模型就能兼顾速度和质量。
顺着这个思路还能再走一步:如果进到 Router 的信息是半结构化的,Router 的第一层可以不用 LLM,而用 decision model。比如 TypeSafe 的 Jev,它不生成文字,只从预先定义的答案里选一个,并给出每个选项的概率,延迟和成本都比 LLM 低一两个数量级。高置信度的分类直接放行,拿不准的再交给 LLM。
但 decision model 只能当第一层,不能替代 Router。它的选项得事先给定,可 Router 面对的 Worker 列表一直在变;给人写回复、顺着引用链去找老任务的上下文,也都离不开 LLM。
一个 Router 扛得住吗
所有交互都压在一个常驻 session 上,直觉上它会成为瓶颈。原文的回答是:它自带批处理。
Router 推理的时候,新到的 Trigger 会排队,下一轮合并进同一次 LLM 调用。事件来得稀疏时,每次只有一条,响应很快;事件扎堆时,一批自然变大。Router 的请求是典型的「长输入、短输出」,合并进来的 Trigger 在 Prefill 阶段并行计算,单次请求的耗时增长远比批大小慢。原文的压测里,需要决策的 Trigger 从每分钟约 1 个涨到约 40 个,平均批大小从 1.0 涨到 2.8,单次请求耗时只从 2.5 秒涨到 3.9 秒,平均每个决策的耗时反而从 6.4 秒降到了 1.6 秒。
这里没有「平时逐条处理、拥挤时切换成批处理」这种模式切换。逐条进来,就是批大小为 1 的批处理。
原文没给批处理的输入格式。我推测每个 Trigger 会被包装成一个待决策的问题,带上自己的定位信息,Router 一次答完一组:
[
{
"question": "用户 A 提到需要修复页面卡顿,请判断它和哪些 session 相关",
"context": {
"channel": "群聊 A",
"time": "...",
"last_decision": [],
"recent_session_ids": [],
"nearby_messages_summary": []
}
},
{
"question": "用户 B 提到 CPU 负载上升",
"context": { "channel": "群聊 B", "time": "...", "...": "..." }
}
]
这个结构说明了一个约束:批处理要成立,每个 Trigger 都得自带足够的上下文,否则 Router 在一轮里分不清谁是谁。这个约束会在第三节变成一套完整的机制。
二、整套系统是一层套一层的快慢路径
把原文的几个模块放在一起看,会发现它们用的是同一招:确定、高频、稳定的判断交给代码,便宜、快;模糊、低频、需要理解语义的判断交给模型,贵、慢、灵活。 原文借的是计算机系统里 Fast Path / Slow Path 的说法。这一招至少用了三次。
第一次:过滤
接进真实的群聊和代码平台后,事件流噪声极大。同一个群里,不同的人可能在聊完全不相干的事,绝大多数消息根本不需要 agent 出手。
- 快路径:代码按事件来源、所在的群、用户或机器人白名单做准入。每个来源可以配成三档:只响应明确请求、作为候选、忽略。被 @ 本身就是一种事件,在「只响应明确请求」的来源里,被 @ 的直接处理,其余直接丢掉。
- 慢路径:通过准入的候选事件交给 LLM,结合上下文和写在提示词里的策略,判断要不要出手。
慢路径同时是一个自然语言的扩展点:加一条策略、关掉一条策略,改提示词就行,不用发版。
推测配置大概是这样:
sources:
- match: { type: im, group: "oncall-告警" }
policy: candidate
- match: { type: github, event: [pr_review_comment, check_run] }
policy: candidate
- match: { type: im, group: "*" }
policy: explicit_only # 只响应 @
- match: { type: im, sender_is_bot: true, not_in: allowlist }
policy: ignore
第二次:路由
过滤之后,Router 仍然要承受两股并发:人发来的新需求,以及已经派出去的任务源源不断的后续事件。后一股往往更大。
DH 引入了 Thread:同一个 PR、同一个 IM 话题、同一串邮件上的连续事件,构成一个事件流。Router 为某个 Thread 的第一条事件创建 Worker 之后,这个 Worker 就直接订阅这个 Thread。
- 快路径:已订阅 Thread 的后续事件,由代码直接推给订阅它的 Worker,不经过 Router 的推理。Worker 发现某条事件跟自己无关,可以退订,或者交还 Router 重新分派。
- 慢路径:没有订阅者的新事件,才交给 Router 决策。Router 依然能看到所有事件,用来维护全局状态,但只对这部分出手。
于是 Router 只负责两件事:新任务的冷启动,以及跨任务的协调。原文的消融实验里,关掉直通后任务完成时间差不多,但 Router 的决策次数多了约 30%,cache-read token 多了约 37%。
订阅是多对多的,这一点很关键。两个 Worker 在同一个 PR 上撞车时,它们都订阅了这个 PR 的 Thread,同一条事件会同时推给两边,它们就有机会看到对方在做什么,自己化解冲突。注意这里只是「有机会」,后面会再回来讨论。
推测实现就是一张订阅表加一个分发函数:
type Subscriptions = Map<ThreadId, Set<WorkerId>> // 多对多
function dispatch(t: Trigger) {
router.observe(t) // 只追加进 Router 的上下文,不触发推理
const subs = subscriptions.get(t.threadId)
if (subs?.size) subs.forEach(w => workers.get(w).enqueue(t)) // 快路径
else router.enqueueForDecision(t) // 慢路径:冷启动
}
observe 和 enqueueForDecision 的区别,就是「Router 能看到」和「Router 要出手」的区别。
第三次:Router 自己
如果按第一节的思路,用 decision model 做 Router 的第一层,那 Router 内部也是一条快慢路径。三次用的是同一个结构:代码和便宜的模型挡在前面,昂贵的推理留在最后。
这个视角的好处是,它给出了扩展这套系统时的方向:哪里成了瓶颈,就在哪里前面再加一级快路径。
三、上下文窗口是一块缓存
Inline 和 Spill
事件送进 session 之后,下一个问题是给模型看多少。给多了,窗口塞满,注意力被稀释;给少了,模型就得一次次调工具去读,执行步骤变多。原文的说法是:浪费上下文窗口,就是浪费模型的智力。
DH 把上下文窗口当成缓存,借用编译器里的两个词:
- Inline:可能马上用到的信息直接放进窗口,省掉工具调用的往返;
- Spill:超出预算、或者不常用的完整信息放在窗口外,窗口里只留摘要和引用,用到时再读。
放什么进来,靠的是局部性原理:先只给当前对象的 ID 和摘要,再按时间和空间上的邻近关系逐步 Inline,比如紧密相关对象的 ID、内容的前 50 个字、被回复的那条消息、同一个评审讨论里相邻的评论。太长的内容截断,留一个「后面还有,去这里读」的指针。
推测一条注入后的 Trigger 长这样:
[trigger tr_8f2a] github.pr_review_comment
thread: th_pr_1287 "fix: 页面滚动卡顿" subscribers: ws_31
author: alice at: 2026-11-01T10:12
body: "这里改成 requestAnimationFrame 会不会更好?#1203 里讨论过…" [+412 chars → read(tr_8f2a)]
reply_to: cm_5521 "先用 throttle 顶一下"
related: th_im_88 (群聊「前端周会」, 3 条相关), ws_27 (已结束, 处理过 #1203)
每一行都是 Inline 进来的局部信息,每一个 ID 都是一次可选的 Spill 召回入口。第一节说「批处理要求每个 Trigger 自带定位信息」,指的就是这个。
Chain of Recall:给 Router 的寻路机制
这套规则统一用在所有对象上:Trigger、Thread、Worker Session 都有唯一 ID,注入时都附带相关对象的 ID,这些 ID 就连成了一张引用图。召回某个对象时,返回结果同样遵循 Inline & Spill,带着下一跳的摘要和 ID。模型从当前事件出发,顺着引用一跳一跳往回找,需要多远就找多远。原文把这叫 Chain of Recall。
它主要是给 Router 用的。大量后续事件直通 Worker,长期运行下来历史任务越积越多,Router 不可能把每个任务的完整历史都留在窗口里。但用户在另一个渠道提起一个老任务时,Router 还得把它接上。比如从当前消息所在的 Thread 出发,找到关联的 Worker Session,再找到这个 Worker 碰过的另一个代码评审 Thread。
缓存还有第三个问题
到这里,DH 回答了缓存的两个问题:放什么进来(Inline),放不下怎么办(Spill)。
缓存还有第三个问题:什么时候失效。 原文没有讲。
在一个只有 agent 自己读写的系统里,这个问题不明显。可 Super-agent 接的是真实世界:用户会在群里改口,会在 PR 里推翻上一条评论,最要命的是,会在自己的电脑上改文件。agent 上下文里那份一小时前读到的文件,此刻可能已经是脏数据了,而它会基于这份过期的认知继续干活。
这个问题在下一节会变得更尖锐,因为 DH 选了一条让它无法回避的路。
四、执行环境是一只换不掉的宠物
三个问题
计算、状态、环境分离这一节,本质上是在回答每个云端 harness 都要面对的三个问题:
- Agent Loop 的计算,应该有状态还是无状态?
- 会话状态,持久化到哪一层?
- 执行环境,放在云端沙箱,还是留在本地?
计算应该无状态。 云端的 Agent Loop 大部分时间都在等:等模型、等工具、等人。这和云上的 CPU 很像,大多数时候不是在算,而是在等 IO。为一个大部分时间在等的东西长期占着资源维持状态,在高并发下是浪费。只有无状态的计算,才能扩容、重启、替换,让 agent 摆脱单台机器的生命周期。原文的出发点偏向可用性:本地设备睡眠或掉线,agent 不能跟着停。成本和可用性,两个理由指向同一个答案。
状态落库。 计算无状态之后,session 状态自然持久化到数据库,用到时再拉出来。这一步没什么争议。
环境是真正的分歧所在。
DH 和 Anthropic 分道扬镳的地方
模型用到的大量上下文,来自对执行环境的工具调用:代码仓库、本地文件、依赖的服务。所以广义上说,执行环境本身也是上下文。
常见的做法有两种:在云上起沙箱,拉代码,尽量重建和同步环境;或者让用户干脆把工作搬到云上。原文认为两种都很贵。真实环境里有未提交的改动、私有凭证、对内网服务的依赖、特定的硬件和工具链,同步起来又贵又容易漏;整体搬迁对很多人来说门槛太高。
DH 的选择是:既然最难复制的恰恰是环境本身,那就不复制。Agent Loop 留在云上,环境留在原地,每台机器只装一个轻量 daemon。daemon 不保存任何状态,只负责执行命令、返回结果。原文把这叫 BYOM(Bring Your Own Machine):直接接入用户自己的开发机。用户的设备重新上线时,云端会自动开始并完成需要在这台设备上跑的任务。
原文自己引了 Anthropic 的「Decoupling the brain from the hands」,说两者方向一致:harness 无状态,session 日志放在外面,执行环境按需接入。但两者的落点不一样。Anthropic 讲的是托管服务,环境是按需创建的沙箱或客户 VPC 里的资源;DH 首先要接的是人们每天在用的个人电脑。
运维圈有个老比喻,pets vs cattle,正好能说清这个区别:
- Anthropic 的沙箱是 cattle。 可以从 session 状态按需重建,坏了换一台,没人心疼。
- DH 接入的机器是 pet。 就是你那台独一无二的电脑,上面有只存在于它身上的东西,换不掉,也复制不了。
推测一下 daemon 的形态:个人电脑大多在 NAT 后面,云端连不进来,所以多半是 daemon 主动向云端建立长连接,云端通过这条连接下发命令。设备离线时,需要它的任务在云端排队,连接恢复后再继续。
养宠物的代价
选 pet 的好处很直接:不用同步,真实环境里有什么就是什么。但有几笔账,原文没算:
- 离线就得等。 机器一合盖,和它有关的任务只能挂起。投机执行也没法在你的机器上提前跑。
- 工作区会被争抢。 同一台机器上的几个 Worker 共用一份仓库,一个切分支,另一个就踩空了。原文没讲怎么隔离,git worktree 是一种可能。
- 安全风险最终落在个人设备上。 这一点原文自己在开放问题里提了,这里不展开。
还有一笔账更根本,就是上一节留下的缓存失效问题。
如果环境是 cattle,它只有 agent 在改,agent 记住的就是真实的状态。如果环境是 pet,人和 agent 在同时改同一台机器。「我读过的文件被别人改了」,在云沙箱里是边角情况,在 BYOM 里是常态。
DH 的设计里,环境本身没有副本,agent 每次都通过 daemon 实时读取,所以不存在「副本和真实环境对不上」的问题。但不一致并没有消失,而是转移到了 agent 的上下文里:上下文里的那些观察,就是环境的副本。
我能想到两种补法:
- 给观察打版本。 Inline 进上下文的环境信息带上 mtime、hash 或 git HEAD,基于它行动之前先比对一次。
- 把「环境变了」也变成 Trigger。 daemon 通过文件系统 watch 或 git hook 主动推送变更事件,交给前面那套过滤和订阅机制处理。
第二种和 DH 事件驱动的整体风格更一致。环境变更本来就是一种环境事件,没有理由不走同一条通道。
五、不等人,也不让人等
前面四节讲的是结构,这一节讲的是体验。原文有三个设计,目标都是让人少等。
异步 ReAct。 传统 ReAct 里调用同步的 run(),循环会阻塞到工具返回,这期间用户说什么都没人理。DH 把耗时操作换成 start() 和 stop():start() 立刻返回「已启动」,工具在后台跑完后,结果作为一条新事件推回 session;跑太久了,模型可以调 stop() 终止。原文说这个机制 DH 已经实现,只是默认没开。
start({ cmd: "pnpm test --filter web" }) // → { taskId: "bg_42", status: "started" }
// ……几轮对话之后,系统注入:
// [trigger tr_9c01] bg_task.finished bg_42 exit=1 "3 failed, 128 passed" [+6.2KB → read(bg_42)]
从这段推测的代码能看出,工具完成也只是一种 Trigger。异步 ReAct 并不是额外的机制,而是事件驱动自然延伸到工具调用上的结果。
投机执行。 根据环境信号,在还不确定结果用不用得上时,就先在后台开干。有用就交付,没用就扔掉,用后台算力换人少等一会。原文的例子是他们内部群里的「静默复现并修复」策略:有人报问题,agent 先在后台复现、找修法,确认问题存在、而且修法简单才出声,否则全程沉默。很容易想到的另一个场景是线上告警:报错一出来,人还没赶到,agent 已经定位、写好修复、跑完测试了。这是 tokenmaxxing 的思路,用 token 换时间。
按渠道说话。 Worker 啰嗦的推理和工具调用都关在自己的 session 里,对外只有 Router 一个出口。Router 再按渠道调整说话的方式:IM 里像个靠谱的同事,只在需要决策时出声,只给结论,他们验证过一条硬规则,每条回复不超过 100 字;GitHub、邮件、文档里则写得完整、结构化,PR 描述里背景、改动、验证结果一样不少。
六、Watchdog:主系统之外的 controller
长期在线的系统,不能只靠自己的内部逻辑保证可靠,它需要一个站在外面的控制回路。
agent 系统还多一层麻烦:很多故障不是崩溃。进程活得好好的,模型却在原地打转,或者早就偏离了目标。进程存活探针看不出这种问题。
DH 的 Watchdog 是主系统之外一个独立的 agent session,由定时消息驱动。它处理 API 报错、状态恢复失败这类基础设施故障,也用模型判断每个 Worker 是否在实质推进、有没有跑偏。发现问题就修,遇到外部的临时故障就反复复查,直到恢复。
最贴切的类比是 k8s 的 controller:不在数据通路上,周期性地比对期望状态和实际状态,有偏差就纠正。不同之处有两点:
- Watchdog 判断「实际状态」时用的是模型,所以能识别「一切正常但事情没进展」这种 controller 看不出来的情况;
- 它本身就是一个工具齐全的 agent,维护者可以直接问它「为什么挂了」,也可以让它在系统运行时改提示词、调触发规则。运维多了一个能对话的入口。
七、原文没回答的问题
原文最后列了四类开放问题:两层架构怎么扩展、没有 session 之后怎么交互、上下文边界和 A2A、安全和隐私。安全不在本文讨论范围内,下面说说另外三个,给出我的答案。
Router 怎么长大
原文的态度很务实:一个常驻 Router、加上订阅直通、Worker 之间不直接通信,已经够他们现在的团队规模用;为了吞吐过早拆分 Router,会牺牲全局上下文的连续性,不值得。但规模再往上走,答案是空着的。
我认为要分两件事来看。
第一件,治理 Router 的状态。 常驻意味着上下文一定会膨胀。可以沿用缓存的分级思路:
| 级别 | 对象 | 在窗口里的形态 | 怎么用 |
|---|---|---|---|
| 热 | 进行中的任务 | Inline 完整信息 | 直接用 |
| 温 | 最近结束的任务 | 压缩成摘要 + ID | 通过 Chain of Recall 召回 |
| 冷 | 很久以前的任务 | 只在归档里 | 只能显式检索 |
关键是:过时的东西可以降级,不能删除,也不能标成「不可召回」。用户随时可能在另一个渠道提起一个老任务,Chain of Recall 存在的意义就是接住这种时刻,这是「连续性」的承诺。分级只是让近的召回更便宜,不是放弃远的。冷数据怎么检索,就是原文说的长期记忆瓶颈。
第二件,Router 本身的结构。 最直觉的做法是分治:按职能拆成几个 Router,一个对人,一个处理事件,一个处理 Worker 的回调。
但简单分治有一个致命的代价:序点没了。 几个 Router 各看各的,谁来保证跨任务信息的先后顺序?用户在群里说「改成 B 吧」,事件 Router 和对人 Router 各看到一半,可能做出互相矛盾的决定。
所以分治最后会变成分层:
- 事件层:只回答「要不要调度 Worker」。这一层大量使用代码规则和 decision model,量最大,逻辑最简单。
- 调度/协作层:回答「多个 Worker 之间怎么配合,谁该订阅谁的 Thread」。这一层仍然是唯一的序点,但大部分负载已经被事件层挡掉了。
这是用增加结构的方式提高单个节点的承载力,而不是把节点横向切开。也就是第二节那句话的又一次应用:哪里成了瓶颈,就在哪里前面加一级快路径。
Worker 之间要不要直接说话
讨论要不要通信之前,先问通信是为了什么。
两个 Worker 需要频繁对话,说明它们之间有协作依赖。这种依赖靠它们自己往往解决不了:两个对等的 Worker 意见相左时,谁说了算?给它们拉一条直连通道,只是多了一个互相等待、互相覆盖的地方。原文的订阅机制让它们「有机会」看到对方,但看到不等于能决定。
我认为合理的路有两条,都由 Router 来拍板,因为它本来就是协调点:
- 派一个临时的 mediator Worker。 专门负责协调这两个 Worker,它们结束,它也跟着结束。这有点像分布式系统里的选举,只不过协调者是临时生成的新节点,而不是从现有节点中选出来的。
- 合并成一个 Worker。 两个任务耦合到需要专人协调的程度,通常说明 Router 当初就不该把它们拆开。合并后的 Worker 内部可以是一个 Agent Team,原来的跨任务问题就变成了任务内部的问题,而任务内部的问题本来就是 Worker 擅长的。
Session 消失之后
原文说,两层架构把 session 藏起来之后,界面该长什么样就成了新问题;用户看到的一个对话,不必对应底层的一个 session。
我认为 session 并没有消失,而是变大了。它不再以任务为单位,而是以意图为单位。微观层面的那些切入点,比如这一步调了哪个工具、那一步改了哪行代码,没那么重要了。重要的是意图有没有实现。
这是一种鸭子测试:叫起来像鸭子、走起来像鸭子、长得像鸭子,那它就是鸭子。交互应该围绕结果组织,结果的形态由任务决定。代码任务的结果是代码跑起来符合预期,交付物是 PR;调研任务的交付物可能是一份 PPT、一张图表,或者就是一段对话。
可原文在同一节也提醒,现阶段很多任务还需要人在中途插手。结果导向会不会把过程藏得太深,让人无从下手?
我认为结果导向是目的,中途介入是额外开的一个口子。要不要介入,是一笔经济账:一边是沿着错误方向一路跑下去、再返工的 token 成本,一边是人看一眼的成本。人的时间越贵,介入就越少;介入的门槛一高,这个口子就形同虚设。
所以要做的不是增加介入的次数,而是降低介入的门槛。一个办法是在流程里打 checkpoint:任务在关键节点留下状态,人可以从任意一个 checkpoint 开始,分叉出一条自己主导的路,不用打断正在跑的那条,也不用从头再来。
这在 DH 的架构里一半是现成的:session 状态本来就存在数据库里,给对话打 checkpoint 很便宜。另一半又绕回了第四节:执行环境是 pet,不会跟着对话回滚,除非借助 git 这类机制。对话可以分叉,机器只有一台。 第三节留下的缓存失效问题,在这里会以最尖锐的形式重新出现。
上下文的边界画在哪里
原文最后说,用的人从个人、小团队扩大到更大的组织时,决定怎么部署 Super-agent,实际上就是决定哪些上下文共享、哪些隔离。需要共享的部门共用一个实例,需要隔离的各用各的,实例之间再通过 A2A 协作。
这不只是技术问题,更是信息如何流通的问题。它首先是组织的命题,然后才是工程的命题,每个组织会有自己的答案。
康威定律说,系统的结构会复刻组织的沟通结构。过去,这体现在代码模块的边界最终会长成部门的边界。到了 Super-agent,它会更加直接:你让哪些人共用一个实例,就是在规定谁能看到谁的上下文。Agent 的部署拓扑,就是组织的信息拓扑。 工程能做的,是让这条边界可以调整、让跨边界的通信安全可控;至于边界画在哪里,工程决定不了。
结语
把这篇文章拆到最后,剩下的是一个朴素的判断:多任务并行时,人是瓶颈,所以这首先是一个系统设计问题,而不是提示词问题。Router 不干活、Worker 不对人、事件绕过 Router 直通、计算不留状态,每一条约束都是在系统层面替人省注意力。
DH 没有发明新理论,它搬来的是快慢路径、批处理、缓存和局部性、投机执行、存算分离、外部控制回路。这些办法都成熟,它们的老问题也同样成熟:缓存要回答什么时候失效,宠物要回答离线、争抢、被人改动时怎么办,序点要回答扛不住时怎么长大。原文给了一部分答案,剩下的还空着。
但方向我是认同的。session 是从底层 LLM API 继承下来的概念,它是给机器用的。让人去管理它,本来就是一个历史遗留问题。
原文:Exploring Super-agent Design,DeepSeek Harness 团队,2026-11-01。文中标注「推测」的代码与数据结构为笔者推演,不代表 DH 的实际实现。