DeepSeek 开源的 super-agent,是怎么把一条 @提到 变成一次 PR 的?

0 阅读4分钟

📌 原文由 Lyncore 团队撰写并发布于官网:lyncore.top/tech/deepse… 本文为 Lyncore 团队授权转载,仅作分发用途。

DeepSeek 开源的 super-agent,是怎么把一条 @提到 变成一次 PR 的?

你在 GitHub 上 @ 一个编码 Agent 一句「帮我修下这个 bug」,过一会儿它真开了一个 PR 回来——中间到底发生了什么?

很多介绍 Agent 的文章停在「LLM 加一堆工具、循环调用」这种抽象描述,但真到工程里,难点从来不是模型有多聪明,而是「一条请求进来,怎么被鉴权、怎么被派活、怎么保证不重复、怎么回到原会话」。DeepSeek 开源的 dsh-superagent 把这套链路拆得很干净,值得顺着一条评论走一遍。

一条 @提到 的五段旅程:dsh-superagent 的领域模型与源码依据

一条 @提到 的旅行

dsh-superagent 的领域模型(见它的 docs/001-domain.md)可以浓缩成这一条数据流:

Source → Trigger → Thread → Eval(gate + assessment) → Decision
       → Ticket(Mandate) → Assignment → Executor → Channel

1. Source:事件从哪来。 GitHub 和飞书是两种 Source 实现。Source 自己维护"读到哪了"的位置,过滤掉机器人自己的消息,把原始事件翻译成统一的 Trigger。关键是:重启不能重放事件——所以读位置必须持久化。

2. Trigger:不可变的最小事件。 一条 Trigger 带着发送者身份等元数据,是审计和幂等的单位。"同一条 Trigger 被 accept 两次 = 同一个 Ticket",这句话保证了不会重复开活。

3. Thread:按时间排序的触发序列。 一个 Thread 同一时刻只跑一个 Eval。一个 Thread 可以挂多个 Ticket——比如一个 Issue 下既有"修 bug"又有"补文档"两件独立工作。

4. Eval:两层的判定。 第一层 Gate 是确定性的:谁、以什么强度,能发起工作(查白名单)。第二层 Assessment 交给模型研判:这条请求到底要不要接、接的话范围多大。Eval 本身无状态,输入是 Trigger 批次 + Thread 快照 + 当前 Policy,输出一个 Decision。

5. Mandate:接单授予的"授权书"。 这是整个设计里很妙的一点。accept 之后会发一张 Mandate,记下:Policy 版本、scope(能跑到哪)、strength(明确还是推断)、命中的规则、发送者身份。它不可变——后面 Policy 改了,也不会偷偷撤销已经发出的授权,只会把变更投递给在跑的任务。

6. Ticket:已授权的工作单元。 只有 Eval 能创建 Ticket。它在 open 和 ended 之间来回:人在它的 Thread 上发一句消息,就能把它从 ended 唤醒继续干。

7. Assignment + Executor:真正动手。 一个 Ticket 会被绑定到一个 Executor(一个 DSH Session + 一个以 Ticket 短名命名的目录)。每个 Ticket 一个 worker-<id> 会话,跑命令不用每次审批。干完通过 Channel 回到原会话——比如发一条评论,或者开一个 PR。

这套设计和 Lyncore 的哪块对得上

把镜头拉回我们自己的产品,Lyncore 在架构直觉上和它是同构的:

  • dsh 的 Main Session(router,负责判定与调度) + Executor Session(worker,负责执行每个 Ticket),就是 Lyncore 里"大脑与手分离"的那条主线——spawn_worker 在顶层收口 lite/pro 两档执行器加并行 expert,重的拆解(task_decompose)归 Pro 那一档。区别只在 Lyncore 把这条线做成了自有后端 + 桌面壳的产品,而 dsh 是吃 Harness 底座的 bundle。
  • dsh 把 "等人"做成 Ticket 的一等公民状态(person/answer、person/review、person/blocked…),和 Lyncore 任务生命周期里的 waiting_approval 挂起态是同一个思路——都拒绝把"等人类"当成错误,而是当成可恢复、可原位续走的状态。
  • dsh 用 Effects 事务外发队列(先落库后执行、失败退避重试)保证"决定即落地、重启不丢活",对应 Lyncore 用 NATS 事件总线 + 持久任务记录(dag_run_events)做同一件事。

延伸阅读:把"大脑与手"分开这件事,《主会话 + 工作会话:Agent 编排里"大脑与手"为什么要分开》 里展开讲;《把"等人"做成一等公民状态》 讲人环设计;《先决定、后动手》 讲可靠执行。

几个值得抄的作业

读完它的文档(docs/007-architecture.md 连类图和模块表都给了),有三个工程取舍很值得记:

  1. 领域模型极其克制。 docs/001 甚至列了一张"被否决的概念"清单——不把人做成实体、不让 Eval 反向依赖 Source、Ticket 状态不跟随 DSH Session……这种反向记录比正向设计更难得。
  2. 授权显式建模。 与其到处写 if 白名单,不如把 Policy 版本 + 授权范围 + 强度做成一个不可变的 Mandate,挂在每个 Ticket 上。
  3. 副作用走事务外发。 所有对外动作(发消息、启动执行、投递输入)都先存进 Effects 队列再执行,崩溃后按序重试——把"决策的原子性"和"动作的副作用"彻底分开。

本文由 Lyncore 撰写,源自官网:lyncore.top/tech/deepse…