为了折腾自己的贾维斯,周末看了下 DeepSeek 新开源的 dsh-superagent 的设计。

如果用一句话来定位它,这是一个真正奔着「主动干活」去研发的 coding agent 原型系统,宗旨是「尽量少占人的注意力,尽量多产出价值」。

为了把这句话兑现成可运行的工程,它没有搞那些花哨的提示词魔法,而是把经典分布式系统和操作系统里被验证过几十年的架构手段,老老实实搬到了 agent 工程里。我归纳了其中 5 个最实用的设计,并用餐厅后厨的比喻来逐个解释下。


推荐的 5 个实用设计

设计 1:Router-Worker 前后台分离 + 活人感注意力纪律

许多 agent 一旦接了个大任务(比如重构一个模块),它的会话就被完全占死了。你发新消息它不理,想中途调整方向只能强行掐断进程。

dsh-superagent 把交互和干活彻底拆成两拨会话:一个 Router(主会话)专门负责跟人对接,常驻在前面,维持用户的全局记忆、偏好和对话上下文;背后则挂着多个 Worker(执行会话),按需启动,并行去跑具体的代码修改、测试或者文档排查。

这种结构带来了天然的 sessionless 体验:用户无论什么时候在群里说话,Router 永远在场,随时都能搭理你,绝不会因为系统正在改代码就假死。

更绝的是它配套的一套近乎苛刻的「注意力纪律」:

  1. 绝对不在干活期间给用户发垃圾进度,只在「必须由人来拍板决断」或者「产出了可用阶段性成果」这两个节点开口;
  2. 每次需要人介入,严格限制只能问一个结构化问题,把选项列清,绝不抛大而化之的开放式反问;
  3. 过程保持极度安静;
  4. 汇报绝对诚实,草稿就是草稿、必须打上未完成标记,失败了就老老实实报失败原因,绝不掩饰。

这就像一家体面餐厅里的「前厅领班」与「后厨厨师」。

Router 就是那位穿戴笔挺、站在台前的值班领班。他脑子里记着你的口味偏好、忌口清单和上次来坐的哪张桌子。后厨的厨师们(Worker)则只管埋头颠勺切菜,根本不用直接跟食客废话。食客要是中途想加杯水或者问句菜品,领班立刻就能笑着回应,绝不会出现服务员全部缩进厨房、大堂空无一人的尴尬场面。

更关键的是这位领班极有教养:厨师在里面切葱姜蒜、热油锅的时候,领班绝不会每隔二十秒跑来桌边跟你念叨「先生,我们现在开始切葱了」「我们刚把锅烧热了」。他只有在两种情况下才会走近餐桌:要么菜端上来了请你品尝;要么后厨发现最后一份海鲈鱼卖空了,拿着菜单问你一句结构化的问题:「后厨的鲈鱼售罄了,我们为您换成石斑鱼还是红鲷鱼?」


设计 2:事件驱动 + 按来源分 Thread 串行处理(agent 界的 epoll)

传统的 agent 要么是一个单向循环(经典的 ReAct,即模型思考一步、调用一次工具、再观察结果的循环),一旦这个循环跑起来,外部来了个 GitHub issue 或者一条即时通讯消息,它根本插不进去;要么就是简单粗暴地为每个新消息起一个新 agent,结果多个 agent 读着不同时间点的截断上下文,各做各的决策,提交代码时互相踩脚、疯狂打架。

dsh-superagent 的解法是:做一套事件驱动架构。

任何外部输入(新提交的代码、issue、群聊消息)进入系统时,都被封装成一个 Trigger(不可变事件,指已经发生、不可篡改的事实记录)。系统会根据数据源把这些事件织进不同的 Thread(处理线程)里。

核心规则非常严密:同一个 Thread 在同一时刻只允许跑一个 Eval(评估任务);如果当前 Eval 正在执行,新来的事件绝不丢弃,也不强行中断当前任务,而是暂存在队列中,等当前评估结束后合并进下一批批量处理;而不同 Thread 之间完全并行。

这就巧妙达成了「并行度」与「一致性」的平衡。更妙的是,在这些事件被送进昂贵的 LLM(大语言模型)之前,会先经过一层轻量规则与小型模型的粗筛,把闲聊、机器自动生成的通知和无意义噪声直接过滤掉,不让核心流程为垃圾输入买单。

你可以把这看作后厨挂点菜单的流水铁夹。

每张餐桌都对应厨房墙上的一叠点菜单。同桌客人追加的菜品,新单子一律老老实实夹在这一桌单子的最末尾,厨师做完手里这一道,伸手揭下一张接着做,一张餐桌上的菜严格按照先来后到出餐,绝不会出现两位厨师同时抢做同一张桌子的菜、结果端出两盘一模一样的酸辣土豆丝。

与此同时,1 号桌和 2 号桌是两条完全独立的单子,两位厨师可以在两个灶头上同时起锅、各做各的。而在服务员把点菜单送进厨房之前,还有个传菜小哥负责把关:客人写错了的废单、小孩子画在纸巾上的涂鸦,在前厅直接就被扔进垃圾桶,根本进不了后厨的视线。


设计 3:异步 ReAct Loop(5 秒规则 + 唤醒机制 + Watchdog)

让大模型写代码,最怕它敲下一行编译或者跑全套单元测试的 shell 命令,然后整个会话就傻傻地卡在那儿干等。

dsh-superagent 定了一条硬性指标:前台 shell 命令只要执行超过 5 秒,系统立刻自动将它沉淀为后台任务。命令转入后台后,Worker 马上恢复自由身,在下一步循环里就能继续接收新消息、阅读其他代码或者规划下一步。后台任务或者子任务一旦跑完,会通过一套唤醒机制把对应的 Worker 唤醒,告诉它输出拿到了,接着往下推导。

为了防止程序死循环或者跑飞,所有后台任务挂着 30 分钟的硬性超时上限,时间一到直接杀掉,并在报告里如实写明「因超时终止」。

在这个体系里,还有一个不可或缺的兜底角色:Watchdog = 旁边盯着火候的监工(模型限流、agent 卡死、任务超时由它收拾)。

大模型 API 遇到 429 限流、网络抖动、速率限制甚至 Worker 崩溃是家常便饭。普通 agent 碰上这些报错直接就崩了,人如果正巧在睡觉,整个晚上就白白浪费;而 Watchdog 就像操作系统里的守护进程,捕捉这些故障后负责退避重试、拉起重启或者妥善兜底。

这就像在后厨里,炉灶的火力是有限的。

大厨把食材下锅,如果是一道猛火爆炒的小炒肉,5 秒内就能见分晓,大厨就在灶前直接出锅;但如果大厨下了整只老母鸡,需要慢火熬高汤,他绝不会站在锅前傻等两个小时。这道菜在 5 秒内就会被直接挪到旁边的文火小炉子上,定上一个响铃计时器,大厨转身去砧板前切别的凉菜。

等到炖汤的时间一到,计时器「叮」地一响,大厨再被叫回小炉子前开盖收汁。要是慢炖时间超过了半小时还没动静,厨房规矩是直接关火倒掉,绝不占着地方。厨房里还有一个专门背着手巡视的看灶师傅(Watchdog):他不管今天做淮扬菜还是川菜,就专盯着煤气阀门和火苗。高汤溢锅浇灭了火苗、或者天然气管网突然水压不稳,大厨不用操心,看灶师傅第一时间上去关阀、重新点火、调稳火候,让整个后厨不至于因为一口锅扑了而彻底瘫痪。


设计 4:版本化 Policy + Mandate 授权单 + 影子模式

给 agent 赋予自主权是一件极度危险的事。稍不留神,它可能顺手把生产数据库给删了,或者在公开仓库里提了一堆荒谬的 PR。很多系统试图在提示词里用自然语言叮嘱「请小心谨慎」,但在大模型面前,这种叮嘱就像耳边风。

dsh-superagent 拿出了一套工程化极其严肃的三道防线:

第一道是版本化的 Policy(策略规则库),系统接单的准入条件是用机器可读的配置写死的,每一版都有独立版本号,不能模棱两可;

第二道是 Mandate = 授权单(写明这单活能做什么、依据哪版规矩,事后可查)。一旦评估通过接下这单活,系统会签发一张完全不可变的授权单,上面清清楚楚地印着执行范围、权限强度以及依据的是哪一版 Policy,整个干活链路全凭这张授权单行事,事后随时可以审计和追责;

第三道是设计文档里规划的 record-only 影子模式:对于团队心里还没底的主动行为,系统先运行在影子模式下。按照设计蓝图,这时候 agent 只被允许记录「如果让我做,我本来打算执行这三行命令、修改这个文件」,但实际上完全不执行。经过数天甚至数周的日志审查,确认它的判断稳定靠谱之后,才把开关推上去真正放权。

它的底线原则非常克制:永远先窄后宽,从最短的权限白名单起步。

这就像后厨对待一个刚入职的试用期厨师。

店里有一本明明白白的员工守则,印着第 3 版店规(Policy)。新厨师每天打卡上班,领班会根据他今天的工种给他脖子上挂一张授权牌(Mandate):上面盖着钢印,写得清清楚楚:今天你只能碰 3 号切菜墩、只能加工胡萝卜和土豆、绝对不准碰放着鲍鱼干贝的名贵食材柜。万一今天菜品出了问题,翻出挂牌就能查清是谁批的条子、依据的哪条规矩。

对于店里打算推的新菜品,主厨会让他先上「影子班」:他在案板旁边拿着笔和纸观摩,心里琢磨每一步该怎么放盐、怎么颠勺,但他只准在纸上把做菜步骤写下来,绝对不准碰锅铲。晚上下班后,主厨翻开他的笔记本,一页页核验他的配比。连看一个礼拜,发现这个新人体会极为到位、从来不出格,这才准许他第一次真正开火炒菜。


设计 5:Stored Work 先记账后动手 + 全链路恢复

做分布式系统的人都知道,世界上最脆弱的事情就是把状态存在内存里。网络随时可能中断,服务器随时可能重启,LLM 的 API 随时可能返回一段格式错误的坏数据。

dsh-superagent 的核心设计叫 Stored work = 先记账后动手(动作先写进数据库再执行)。系统产生的每一个关键动作——不论是给 Worker 派活、投递一条通知,还是回复人类一句话——必须先在持久化数据库里落库记账,然后才执行实际的网络调用。

比如它的 Outbox(发件箱)机制,所有发往外部的消息先排队落盘,由独立机制保证严格按照对话序列发出,失败了自带指数退避重试,绝不会因为网络抽风导致同一条消息发了三遍,也不会把消息弄丢。

更震撼的是它的异常恢复能力:哪怕机器在半夜被强行重启,未完成的派工在重启拉起后,会随身带上一张「恢复便签」。便签用大白话提醒苏醒过来的 Worker:「你刚经历了一次系统重启,不要盲目从头再来一遍。请先去检查工作目录、查看本地 Git 提交历史,确认哪些步骤其实已经做完了,再决定要不要重复调用外部动作。」不仅如此,连一条消息究竟「读没读过」,系统都坚持在调用 LLM 之前完成状态落库。绝不重复发一条消息,也绝不丢一条状态。

这就是后厨出菜口那本厚重泛黄的「传菜记录本」。

厨师炒好一盘红烧肉,绝不是端起来就往大堂跑。他必须先走到出菜台,用笔在记录本上工工整整写下一行:「18:05,3 号桌红烧肉已出锅,传菜生小李接盘」,写完盖上章,传菜生才能把盘子端走。要是小李在路上脚底打滑把菜打翻了,没人需要靠脑子去回忆刚才发生了什么,前台翻开账本,按退避流程重新安排补做。

更绝的是应对突发状况:要是后厨突然遭遇全楼跳闸断电,半小时后来电,整个厨房不至于陷入无头苍蝇般的混乱。领班从出菜台拿起那本账本,打着手电筒核对:哪道菜已经送达客人桌上、哪道菜客人已经动了筷子、哪道菜其实刚下锅还没盛盘,账目一清二楚。厨师绝不会因为断了次电,迷迷糊糊又给 3 号桌重新炒一盘他们早已吃得干干净净的红烧肉。


回头看我自己搭的个人系统:五处刺痛与启发

读完 dsh-superagent 的这份设计文档,我顺手打开了我自己捣鼓了快两年的个人自动化工程。

坦白讲,在没有仔细推敲专业 agent 架构之前,我一直觉得自己的系统跑得挺溜。但一旦拿着它这 5 个设计当镜子照过来,我系统里那些掩盖在「能跑就行」之下的工程硬伤,几乎无处遁形。

1. 闹钟驱动 vs 事件驱动:统一分拣层的缺失

我的系统本质上是一个「闹钟驱动的 Loop 工程」。它完全依赖一批定时任务轮流在固定时间醒来干活:早上八点醒来抓一次待办,中午醒来扫一遍未读邮件,晚上醒来整理今日笔记。

这种模式最大的毛病在于缺乏弹性:很多时候明明几个小时内什么都没发生,定时任务还在傻傻地空转轮询;而一旦外部突发了好几个任务,它们又挤在同一个时间点扎堆触发,抢占资源。更要命的是,我为每个入口都手写了一套定制的触发逻辑:抓邮件写一套,看即时消息写一套,接收外部链接又写一套,逻辑分散凌乱。

dsh 给我的直接启发是:我需要拆掉那些各自为政的定时闹钟,把所有外部入口归拢成一个真正的排队分拣层。 无论是收到一条微信长文链接,还是邮箱进了一封新邮件,它们都应该作为标准的数据源事件,先落进同一个队列,按来源拆进不同的线程里串行评估。空闲时完全休眠,事件来时有序分拣,而不是天天靠闹钟催醒。

2. 体检报告 vs 看灶监工:从被动报警到主动自救

在稳定性方面,我原本颇为自得于自己写的一套「每日体检」机制。这套机制能够定期巡检:某个该跑的数据同步进程挂了没有、依赖的底层容器是不是还活着。

但我忽视了一个根本性的差异:我有「体检」,却没有「监工」。 我的巡检程序就算发现「该跑的进程死掉了」,它能做的全部事情,也只是往我的手机上推一条刺眼的报警通知:「注意,同步进程已于两小时前异常退出」。如果这条通知发出来时我正在睡梦中,或者正在外面开会,这条报警就没有任何意义,整个系统依然处于瘫痪状态。

dsh 那个 Watchdog 的设计提醒了我。真正的工程系统不需要一个只会朝主人哭喊的巡检员,而是需要一个能在旁边盯着火候、具备兜底能力的现场监工。模型限流了,监工应该自己去计算指数退避,等两分钟重试;子任务假死了,监工应该果断把超时进程掐断,清理掉临时文件并记录原因。人在睡觉时,系统必须学会在边界内自救,而不是把每一个小感冒都变成主人的半夜惊魂。

3. 散文式人读文档 vs 机器可读授权:影子模式的救赎

翻看我自己系统的规则配置,我忍不住苦笑。我写了洋洋洒洒好几千字的规约文档,里面充斥着诸如「遇到重要文件修改时务必谨慎」「不要频繁向外部接口提交请求」「整理笔记时保持原有格式」这类充满主观色彩的散文段落。

我一直幻想大语言模型在执行时能体会我的苦心。但现实是,散文式的规矩只能寄希望于模型的自觉性,稍微换个大版本模型,它就经常「会错意」或者干脆放飞自我。

dsh 的 Policy 与 Mandate 机制告诉我:规矩绝不能写成给人类读者陶冶情操的散文,而必须收敛成机器可读、可精确校验的配置清单。 某一个自动化任务动手前,到底能不能写磁盘、能不能访问外网、每次最多修改几个文件,必须由程序根据版本化策略签发不可篡改的凭证,动手前先验票。

更重要的是它的影子模式,这正是我之前极度欠缺的过渡手段。以前我写了个新的自动化想法,要么不敢放开让它跑,要么一放开就直接捅娄子。我完全可以给新任务加上一个为期一周的影子模式:让它每天如常触发,但只准把「我本打算删除哪几条数据、把哪篇笔记归档」写进观察日志。我看了一周觉得可以了,再正式推到生产环境。

4. 崩溃整轮重来 vs 先记账后动手的断点续跑

我的个人系统里为了防止任务重复执行,大量使用了简单的「标记文件」或者布尔值标志位。任务开始时建个临时标记,结束时删掉。

这种土办法最怕中途断电或者网络抖动。一旦一个耗时十几分钟的多步骤任务在第十四分钟因为网络闪退挂掉,那个标记位通常还残留在磁盘上。下次定时任务醒来,看到标记文件以为还在跑,直接跳过;或者我手动把标记删掉,整个任务又必须从第一分钟的第一步从头再洗一遍,导致前半截已经执行完的操作被重复执行,甚至在外部系统里产生两份重复的记录。

dsh-superagent 的 Stored Work 才是正规军的打法:不要迷信内存和易失性标志位,动手之前先写账本。 每一个步骤、每一条待投递的消息,先落到轻量数据库里,附带明确的状态机。哪怕机器中途重启,新进程读着数据库里的账本,带着恢复便签,就能清楚地知道第 1 到第 4 步已经做完且在本地留下了文件,直接从第 5 步接着往下推。这种断点续跑的底气,正是来自于「动作未动,账本先行」。

5. 各自开火的通知轰炸 vs 统一出海口的领班过滤

最后一点,也是我日常被骚扰得最痛苦的一点:我的个人系统缺乏一个统一的「注意力出口」。

我的知识库同步任务写完了会给我发条推送,代码抓取任务报错了会给我发封邮件,定时整理系统跑完了又在聊天工具里敲我一下。每个子系统都以为自己的事情最紧急,每天手机屏幕上密密麻麻全是系统自己跟自己聊天的流水账。久而久之,我干脆把所有通知都设成了免打扰——这直接导致真正重要的系统故障报警,也被我一并忽略了。

dsh-superagent 的注意力纪律是一剂清醒剂:所有对外输出的消息,必须经由前台领班这一层统一收敛和把关。干活过程中的一切碎碎念,全部按在日志里;日常自动化运行得顺风顺水时,根本不需要向我表忠心。只有当系统确实产出了立即可用的阶段性成果,或者碰到了预设规则之外、必须由人类亲自做抉择的分水岭时,才允许敲开我的大门,并且一次只准给出一个结构清晰、选项分明的单选单。


结语

拆解完 dsh-superagent 的整套设计,你会发现一件很有趣的事:无论是前后台分离、事件驱动、异步非阻塞任务,还是发件箱模式、版本化授权单以及守护进程,这里面没有任何一个技术点属于前无古人的「新理论」。它们几乎全都是计算机工程过去几十年里,在操作系统、网络通信和分布式架构中被反复咀嚼过的常识。

但在 agent 这个被狂热情绪裹挟、充斥着各种华丽名词与概念包装的新领域里,能把这些质朴的工程常识不打折扣地一次性做全、做扎实,本身就是极罕见的事情。

这份原型的真正价值,不在于它讲了多么玄妙的智能故事,而在于有人真的耐下性子,用最冷峻严密的工程骨架,把一个原本晃晃悠悠的实验品,焊成了一台规整运转的机器。

最难得的是,他们把这张设计蓝图开源了出来(仓库名 dsh-superagent-prototype),清清楚楚摆在所有人面前——当然也要说句公道话:开源的是研究用原型,与内部版本有差异,其中一部分设计(比如影子模式)还停留在蓝图阶段。但这丝毫不减这份文档的参考价值,恰恰相反,能把「哪些是已被验证的常识、哪些是下一步的方向」坦荡写出来,本身就是工程诚实的体现。


小广告:我打算做一个《AI 写作工程学》的课程。课程浓缩了我用 AI 产线写完并出版《前线部署工程师》(首印售罄加印)的整套真实流水线:选题、素材基建、合成起草、去 AI 味、出版三通道,8 个模块配 8 件可直接抄走的实操模板。感兴趣的朋友,可以早鸟预购 。