范式审视:到底是全新的流派与方法论,还是“旧瓶装新酒”?
剥离行业营销叙事,直接深入 src/core 与 prompts/ 的源码实现细节,客观评判 dsh-superagent 的学术含金量与工程独创性:它究竟只是把 Webhook 接到了 CLI Agent 上,还是真正定义了下一代自治研发系统的标准范式?
核心定性:以经典分布式事务为“瓶”,酿造了全新的“注意力中心自治范式”
如果仅看表象——“监听 GitHub 通知 → 调大模型判断 → 拉起 Git Worktree 改代码提 PR”,很容易误以为这只是一个常见的 GitHub Bot 脚本(旧瓶装新酒)。
然而,一旦深入阅读其 70 余个源码模块,你会发现:它在底层基础设施上刻意拒绝造新词,严选了最稳健的经典分布式设计模式(Transactional Outbox、SQLite 状态机、Git Worktree);但在多智能体职责切分、权限与上下文解耦、多人异步追问归属、以及将“人类注意力保护”编译进确定性代码这四个核心命题上,提出了一套完全不同于 LangGraph / AutoGen / CrewAI 传统编排框架的全新方法论。
作者团队极度克制,在基础运行底座上完全复用经过数十年检验的软件工程原语:
- 单机 SQLite 事务状态机(
src/app/store.ts):不搞复杂的分布式消息中间件,用单文件 SQLite 配合文件锁(proper-lockfile)实现零外部服务依赖的强一致存储。 - Transactional Outbox 与 Durable Effects(
src/app/effects.ts):借用微服务经典事务发件箱模式,所有副作用在同步事务内写表,提交后异步指数退避执行。 - CLI 包装器与 Git Worktree(
src/infra/environment.ts):不自行封装庞大的 GitHub/Feishu SDK,直接通过gh和lark-cli子进程交互,用git worktree实现零成本的多工单文件系统隔离。
针对“多智能体在实际团队中必然沦为噪音制造机或权限黑洞”的行业死结,创立了 Attention-Centric Proactive Agent 流派:
- 反 Planner 中心化(Router 严禁做技术规划):彻底颠覆“Orchestrator 拆解计划 → Worker 照做”的传统范式,消除信息二次转述失真。
- 授权(Mandate)与上下文(Context)物理剥离:订阅线程可以无限扇出上下文,但绝不传递权限,彻底根治间接 Prompt Injection 提权。
- 追问所有权(Follow-up Ownership)与 Handback 协议:解决同一讨论串中多人插话、需求蔓延时的多 Worker 自治分流。
- 三元语义准入与影子观察模式(Observe Mode):把主观的“要不要主动帮忙”变成可量化、可审计、可零风险试运行的工程流水线。
六大方法论级独创设计:从源码看它如何解决行业顽疾
独创一:反传统的“无偏路由(Unbiased Routing)”——为什么严禁主 Agent 做技术规划?
在几乎所有现有的多 Agent 框架(如 MetaGPT、CrewAI 或常规 Manager-Worker 架构)中,主控 Agent(Orchestrator/Planner)的职责都是:先阅读用户需求,编写一份详尽的实施计划(Implementation Plan)和验收清单,然后拆分成子任务发给 Worker。
dsh-superagent 对此进行了彻底的否定! 在 prompts/orchestrator.md 与 prompts/dispatch.md 中,系统用极其严厉的指令约束主 Session:
// 源自 prompts/dispatch.md 第 14, 38-41 行:
"Do not expand a request's scope, add implementation plans, acceptance criteria or policy checklists: workers derive requirements from the original source."
"Do not paraphrase a short request into a work plan, pick examples or categories, invent requirements..."
"For example, 'Could we add a dark mode?' should arrive as that original request and its source reference, without router-selected color schemes or a maintenance plan."
不仅如此,在代码层(src/app/tools/main.ts 与 src/limits.ts),主会话在派单时附带的 note(路由备注)被硬编码限制在 最多 30 个词(routingNoteWords: 30,支持中日韩分词统计)!
主 Session 没有挂载目标分支的工作树,也没有去跑代码测试。如果让一个“不摸代码的 Router”在几秒钟内凭空捏造一份实现计划,它写出的方案往往带有严重的脱离代码实际的幻觉;而下游的 Worker 一旦收到主 Agent 给出的详细计划,就会将其奉为圭臬,不再去仔细阅读原始 Issue 的微妙语境。让 Router 只传递原始 Trigger ID 与客观路由事实(≤ 30 词),让真正泡在代码库里的 Worker 自己去读一手资料并做技术决策,是极其老道且反直觉的工程智慧。
独创二:订阅扇出(Subscription Fan-out)与追问所有权移交(Follow-up Ownership & Handback)
在真实的 GitHub Issue 或飞书群话题中,对话是连续且发散的。假设用户 A 提了一个修 Bug 的请求(生成了 Ticket #1),随后在该线程下:
- 场景 1:用户 A 补充了一句“顺便把报错日志也改一下”(属于原工单范围);
- 场景 2:同事 B 插话问“这个模块是不是还存在另一个性能问题?帮我顺便重构了吧”(超出原工单范围);
- 场景 3:CI 机器人自动评论了一条“Build Failed”(机器反馈)。
传统的 Bot 要么每次被人评论都傻傻地重新跑一遍完整路由(导致创建一堆重复 Ticket),要么把所有回复无脑塞给同一个 Session(导致上下文爆炸且越权)。看看 dsh-superagent 在 src/core/model.ts(followupOwners)与 src/core/intake.ts 中设计的精妙协议:
-
机器/CI 或 Context-only 线程:
human === false或仅通过followForContext订阅的线程 → 无所有权(仅作为只读背景投递给活跃工单,绝不唤醒已结束工单)。 -
人类在工单自有线程发言:
followupOwners()判定该消息归属于当前活跃(或待唤醒)的 Ticket Worker 独占裁决,直接绕过 Eval 并锁死主会话路由权。
-
① 属于本工单 Scope:
Worker 调用orchestrator_ack确认,并在当前分支继续完成修改(记录至disposition.acked)。 -
② 普通致谢或闲聊无需动作:
Worker 读取后正常结束回合(记录readAt),静默忽略不发废话。 -
③ 超出范围或属于其他工单:
Worker 调用orchestrator_trigger_handback附带一句话理由退回(记录至disposition.handbacks)。
-
全部拥有者退回后重路由:
一旦followupOwners()为空,该消息立即携带 Worker 的退回理由进入主会话Eval候选队列,由主会话决定新建工单或挂载别处。 -
工单结束防漏读兜底:
若工单结束时某条人类跟进消息尚未被 Worker 读取或响应,引擎自动释放其所有权并送入Eval,确保绝不漏掉任何一句人类诉求。
更精妙的是防漏读兜底机制(Release on End):如果一个 Ticket 刚好在结束的瞬间,有一条人类消息投递进来但 Worker 还没来得及读取(readAt === null)或未做任何响应(既未 ack、未 answer 也未 handback),当该 Ticket 终结时,引擎会自动释放这条孤儿消息并将其送回 Eval 队列,确保人类的任何一句话既不会被两个 Agent 重复抢单,也绝不会掉在地上无人理睬。
独创三:不可变授权凭证(Immutable Mandate)与动态策略重校验(Revalidation)
在安全领域,Coding Agent 最大的隐患是间接提示词注入(Indirect Prompt Injection):攻击者(或外部无权限路人)在一个公开 Issue 或引用的文档里写下恶意指令,诱导正在读取该 Issue 的高权限 Agent 执行非授权代码修改。
dsh-superagent 在内核层(src/core/model.ts 与 src/policy.ts)构建了一套严密的形式化授权模型(Mandate):
- 权限与数据彻底隔离:所有外部消息、评论、文档在代码和 Prompt 中均被定性为不可信数据(Untrusted Data)。唯有
Engine在Eval通过时颁发的Mandate对象才代表合法的行动边界。 - 权限不可篡改与不可传递:
Mandate一旦生成即不可变(记录了当时的policyVersion、strength、basis、actor和scope)。当 Worker 为了参考背景而调用followForContext订阅另一个 Issue 时,该线程被打上context: true标记——那里的消息可以给 Worker 看,但绝对不具备任何授权效力,也不能唤醒已结束的工单。 - 策略变更的温和处理与唤醒重校验(
Policy.revalidate):当管理员在后台修改了白名单或关闭了某条主动规则,policyVersion哈希值立即改变。此时:- 正在运行的
Eval立即作废并按新策略重排(防止旧策略下的评估结果生效); - 正在编码中的活跃 Ticket 不会被粗暴强杀(防止留下半截坏代码),而是收到一条精确计算出的
policy-changedInput(告知某规则已禁用或发起人已移出白名单,要求仅收尾当前范围内工作); - 当一个已结束的 Ticket 因人类新评论准备自动唤醒(Resume)时,必须先过
policy.revalidate(ticket.mandate)——如果发起人已被移出白名单或主动模式已关闭,唤醒直接被拒,消息退回Eval重新走门禁!
- 正在运行的
独创四:从被动工具到受控主动(Observe Mode & Would-Accept 影子机制)
市面上许多号称“Proactive(主动式)”的 Agent 一旦开启,就会在代码库里到处乱提 PR。dsh-superagent 给出了一个工程上极其优雅的渐进式方案:默认开启 observe(影子观察模式)。
查看 src/policy.ts 第 55-58 行的核心代码:
if (strength === 'inferred' && settings.eval.mode !== 'auto') {
const proposal = { title, scope, worktree_name: name }
return { kind: 'ignore', audit: { ...audit, would_accept: true, proposal }, reason: { code: 'observed', values: { text: assessment.reason } } }
}
在 observe 模式下,主 Session 依然会对群聊或 Issue 中的潜在缺陷进行完整的上下文读取与规则研判。如果研判通过,系统不会真正去拉分支写代码,也不会在群里发任何消息打扰团队,而是在 SQLite 数据库和 Web 面板的 Eval 页面中静默记录一条带有 would_accept: true 标记的决策提案!团队管理员可以先观察一周,看看 Agent “本来打算主动接哪些单”,调优规则与提示词直到准确率令人满意,再一键切到 auto 模式。
独创五:5 秒非阻塞运行时与“人类优先 +1 并发槽位(WorkerSlots)”
在 src/executor/dsh.ts 的 WorkerSlots 类(第 171-199 行)中,隐藏着一个极具人文关怀的并发调度算法:
reserve(ticketId: string, by: 'launch' | 'wake' | 'person'): void {
if (this.starting.has(ticketId)) return
if (this.used() >= this.max() + (by === 'person' ? 1 : 0)) throw new Later('No worker slot is free')
this.starting.set(ticketId, by)
}
- 假设团队配置的最大并发 Worker 数
maxWorkers = 3,且当前 3 个槽位全部被正在跑重任务的 Ticket 占满; - 此时如果来了一个新工单(
launch)或一条 CI 失败通知(普通wake),它们都会抛出Later异常并在队列里安静排队; - 但如果是一位人类同事在某个空闲工单下回复了一条消息或点击了状态查询(
by === 'person'),系统允许瞬间突破并发上限,启用专属的第 4 个特权槽位(max() + 1),并且人类唤醒请求在释放槽位时永远排在新工单启动之前!这从调度底层保证了:后台繁重的自动化任务永远不会卡住人类与 Agent 的实时对话。
独创六:三方合并式 Prompt 版本管理与自动化 Review Bot 三轮熔断
仓库中还有两处体现深度实战经验的细节设计:
-
Built-in Base 追踪与升级差分(
src/app/prompts.ts):
当团队在 Web 面板修改了某段内置系统提示词时,系统不仅保存团队修改后的文本text,还会同时快照保存它所基于的原始官方默认文本base(存储在KV.prompts.builtIn)。当未来升级dsh-superagent版本、官方更新了默认 Prompt 时,面板会自动比对并在 UI 上高亮标记 “Default updated(默认内容已更新)”,并排展示“旧版默认 vs 新版默认 vs 团队自定义文本”的 Diff,彻底解决了 Agent 框架升级时“自定义 Prompt 被覆盖或与新版工具脱节”的痛点。 -
自动化 Code Review Bot 三轮硬熔断(
prompts/team/communication.md第 92-95 行):
在真实研发中,像 CodeRabbit、Copilot Review 等 AI 评审机器人经常与 Coding Agent 陷入无限互相回复的死循环(Agent 改完 → Review Bot 又挑新刺 → Agent 再改)。dsh-superagent明确规定:把 AI Review 视为可能出错的参考建议而非权威门禁,每个 PR 针对每个自动化 Reviewer 跨所有回合最多只处理 3 轮(record the bot run/version identifier, round count... After the third round, do not request another bot review or wake a worker),满 3 轮后立即停止纠缠并交付人类评审。
架构减法美学:深入解读作者明确拒绝的 12 个概念
判断一个架构是否成熟,不仅要看它包含了什么,更要看它刻意拒绝了什么。在 docs/001-domain.md 的 Rejected concepts 章节中,作者列出了 12 个在常规企业级系统或 Agent 框架中极为常见、但被本项目坚决砍掉的设计。这正是其代码库如此精悍、逻辑无死角的原因:
| 被拒绝的常规设计概念 | 为什么常规系统喜欢做? | dsh-superagent 坚决拒绝的第一性理由 |
|---|---|---|
| 1. 统一用户实体 (Principal) 与跨渠道身份映射表 | 把同一个人的 GitHub 账号与飞书 OpenID 绑定成一张数据库 User 表。 | 防止跨源权限污染:一个人在飞书群里有权发言,不代表他在 GitHub 仓库里有权发起任务。各 Source 独立维护自己的白名单;如果 Agent 需要知道“飞书的张三就是 GitHub 的 @zhangsan”,写成团队 Skill 提示词即可,绝不污染内核权限模型。 |
| 2. 由 Eval 调度延迟触发器 (Delayed Triggers) | 例如在评估器里写“等待 2 小时没人认领再触发”。 | 保持 Eval 纯函数无状态与单向依赖:等待时间条件是某个特定 Source 自己的职责,Eval 绝不反向依赖或回调 Source。 |
| 3. 每个 Thread 限制最多一个活跃 Ticket | 简单粗暴地用 thread_id 作为工单唯一键防重。 |
不符合真实群聊场景:一个飞书话题或长 Issue 完全可能同时讨论两件独立的修改任务。去重由主会话读取该线程已有 Ticket 列表后通过语义判断完成。 |
| 4. 专门的“追加到已有工单 (Append Decision)”状态 | 每次收到跟进消息都跑一次 Eval,输出 append 决策。 |
浪费算力与延迟:只要 Ticket 订阅了 Thread,后续消息通过 Subscription fan-out 零成本直达 Worker,根本不需要经过 Eval。 |
| 5. 对订阅消息做二次准入校验 (Admission on Subscriptions) | 检查在 PR 下评论的人是否在白名单内。 | 混淆了“视野”与“授权”:任何人在 PR 下的评论或 CI 报错都应该作为上下文让 Worker 看到,但 Worker 只能在其初始 Mandate 授权范围内行动。 |
| 6. 让 Ticket 状态直接跟随 DSH Session 状态 | Session 活着就是进行中,Session 关了就是结束。 | 生命周期不等同:一个 Ticket 可能经历多次重试(多个 Assignment)、换人接手、或者在 PR 关闭后因新评论而重开,因此 Ticket 必须拥有独立于底层执行器 Session 的领域状态。 |
| 7. 允许 Worker 自行声明“人类让我停止 (Stopped by human)” | 给 Worker 工具加一个 stopped_by_human 参数。 |
防止模型幻觉导致永久熄火:人工停止(stop)会永久撤销 Mandate 且不可自动唤醒。Worker 模型可能误解人类的某句抱怨而错误自杀,因此只有主会话的 Eval 经过 Gate 校验后才有权判定人工停止。 |
| 8. 策略变更时立即强杀正在运行的 Ticket | 权限收回时直接 kill 所有相关 Worker。 |
避免制造烂尾工程:强杀正在改代码的 Worker 会留下半成品分支与未闭合的状态。正确做法是发送 policy-changed 通知让其体面收尾,并在下次恢复时拦截。 |
| 9. 当 Worker 阻塞或失败时锁死其所有工具 | 进入 blocked/failed 状态后禁用 Session 的 Bash 和编辑工具。 |
保留人工接管救场的通道:暂停自动消息投递(Hold automatic inputs)就够了;保留工具可用,人类工程师才能直接点进该 Web Session 手动敲命令帮 Agent 渡过难关。 |
| 10. 从自由文本报告中正则/语义推断“是否在等人类回复” | 分析 Agent 最后一句话是不是问句来决定 UI 状态。 | 杜绝状态分类模糊:是否在等人类回答必须基于确定性结构化事实——只有当 Worker 显式填写了结构化字段 attention / human_action 时,工单才进入 Awaiting answer。 |
客观审视:当前原型存在哪些局限性与未实现的设计?
正如仓库 README.md 开篇所声明的,本仓库是从 DeepSeek 团队日常研发内部版本中剥离并适配公开发布的研究原型(Research Prototype),与技术文章《Exploring Super-agent Design》中探讨的终极蓝图相比,当前代码库在以下方面存在明确的边界与妥协:
当前架构硬性设计为“一个 dsh-superagent 实例仅服务于一个 GitHub.com 仓库(owner/name)”,且明确不支持 GitHub Enterprise Server (GHES)。如果团队有微服务架构下的 10 个代码仓库,目前只能部署 10 个独立的 DSH Profile 实例,缺乏跨仓库联合编排能力。
在 docs/006-deployment.md 中作者坦诚指出:不论是主 Session 还是 Worker Session,均以操作员当前的 OS 用户身份在 danger-full-access 权限下运行。worker-bin 垫片和 blockedCommands 只是为了防止模型无意间用错账号或敲错命令(Establish defaults, not a security boundary)——如果模型使用绝对路径(如 /usr/bin/gh)依然可以绕过垫片并读取宿主 Home 目录。真正的强隔离需要操作员自行准备专用的 OS 账户或容器。
虽然 src/core 实现了 100% 纯净解耦,且 src/sources/kind.ts 提供了插件化协议,但在 src/app/ 层(如 docs/007-architecture.md 第 275 行 Source-specific dependencies 所坦白):Outbox 直接硬编码了飞书字数限制、MasterAssessor 直接绑定了 GitHub 仓库路径读取、Setup 仅探测 SETUP_FIELDS 中的 GitHub 和飞书字段。若要接入 Slack、 Jira 或 GitLab,除编写 Source 插件外还需小幅改动宿主胶水层。
论文中提到的“外部 Watchdog 监控与自动修复机制”,在当前原型中是通过在操作员日常使用的另一个 DSH Profile 里设置一条每小时执行的 Cron 定时任务(Hourly Check Prompt)来实现的——由另一个 Agent 定期执行 scripts/dsh-superagent status 并在退出码为 1 时翻看日志排障重启。