本文档为 dsh-superagent 的概念命名,并给出每个概念遵守的规则。代码、agent 调用的工具、面板与其余文档只使用这些术语,不使用别的。遵循 000 设计哲学,模型只保留工作需要的概念;一项业务需求会成为其中某个概念的属性。
流程
工作从 Trigger(触发)流向 Eval(评估),再流向执行。Source(来源)产出 Trigger。一个 Trigger 作为上下文,扇出到订阅了其所属 Thread(线程)的各个 Ticket(工单)。以这种方式到达某个 Ticket 的人的消息,留在该 Ticket 内;其余每个 Trigger 都会进入 Eval,由 Eval 决定是否发起新工作。Eval 接受时,会创建一个带 Mandate(授权)的 Ticket。Assignment(派工)把 Ticket 交给 Executor(执行器),结果经 Channel(渠道)回到 Source。
概念
Source、Thread、Eval、Mandate 与 Subscription(订阅)构成核心领域;其余概念为它们提供支撑。
| 概念 | 定义 | 遵守的规则 | 存在理由 |
|---|---|---|---|
| Source | 一条事件流。Source 种类(kind)是可复用的实现;Source 实例(instance)是某种类的一份配置:是否运行、监听什么 | 持有自己的读取位置和自己的 bot 身份。定义什么算一个事件,包括只在时间上成立的条件。在事件进入领域之前,就丢弃 bot 自己的消息与监听范围之外的 Trigger。把每个 Trigger 翻译成它所属的各个 Thread,以及用于回复的 Channel 地址 | 重启不得重放事件 |
| Trigger | 一个不可变事件,携带 Source 自己的元数据,例如其 actor | 属于一个或多个 Thread。两次接受同一 Trigger 只会创建一个 Ticket | 审计与幂等性的单位 |
| Thread | 按时间排序的 Trigger 集合;由 Source 定义哪些 Trigger 构成一个 Thread | 同一时刻至多一个 Eval 在其上运行。它可以有多个 Ticket。它持有其 Subscription、运行中的 Eval 及其 Decision 历史 | 给 Eval 一致的视图与上下文 |
| Correlation(关联) | 一个 Trigger 同时所属的多个 Thread 之间的关系 | 只添加上下文,从不路由 | 让 Eval 能跟随相关证据 |
| Channel | Thread 的写入侧;由 Source 定义其地址 | 一个 Thread 可以有多个 Channel;一个 Ticket 持有一组 Channel | 确认、回复、pull request 与已解决的 review 都是写入 |
| Policy(策略) | 带版本的研判规则,以及每个 Source 的部分:谁可以经由该 Source、以该 Source 自己的身份发起工作,名单如何同步,以及哪些 bot 可以制造候选 | Policy 版本覆盖规则、accept 模式与各 Source 部分。对进行中 Ticket 有影响的变更(例如修改了它被接受时所依据的规则)会送达其 Assignment;它不撤销 Mandate。不同 Source 上的身份从不互相映射 | 规则变更时,运行中的 Eval 必须丢弃 |
| Eval | 对一批 Trigger 的研判,分两层:gate(准入)与 assessment(研判) | 输入:Trigger 批次、Thread 快照、该 Thread 上的每一个 Ticket(含已结束的)与当前 Policy。输出:一个 Decision(决定)。不持有状态 | 决定新工作是否开始、继续或停止 |
| Mandate | accept(接受)所授予的内容:Policy 版本、scope(范围)、strength(强度)、匹配的规则、发送者在该 Source 上的身份,以及 Source 收到该 Trigger 的方式 | 不可变;更宽的范围意味着新的 Ticket。Ticket 的结束并不结束它:只有人的 stop(停止)会撤回它,不再容纳它的 Policy 会撤销它。已结束的 Ticket 恢复之前,会对照当前 Policy 重新校验 | 说明这项工作为什么可以做、可以做到哪一步 |
| Ticket | 一个被授权的工作单元 | 只有 Eval 能创建 Ticket。Ticket 引用其 Mandate;持有其 Channel 与 Input(输入)。经历 open(打开)→ ended(结束),当人在其某个 Thread 上的消息恢复它时回到 open,除非人已 stop 它。它定义自己的状态,而不是跟随 Executor 的状态 | 拥有执行及其报告 |
| Assignment | Ticket 与一个 Executor 实例的绑定 | 一个 Ticket 随时间可以有多个 Assignment。Assignment 独立于 Ticket 经历 pending(待启动)→ running(执行中)→ ended(已结束)。只有其最终报告能在 Executor 一侧结束 Ticket | Executor 在领域之外,但「由谁执行」必须在领域之内 |
| Subscription | Ticket 与 Thread 之间、由 Thread 持有的多对多关系 | 匹配的 Trigger 扇出到每个订阅中的活跃 Ticket,不检查发送者是谁;以这种方式到达 Ticket 的人的消息不走 Eval。Executor 为获取上下文而跟随的 Thread,以同样方式到达其 Ticket,但不授予它权力,也不恢复它。已结束的 Ticket 保留其 Subscription,包括已关闭或已合并的 pull request 的那个:人的消息在同一 Mandate 下恢复它,无需 Eval 或 Decision;bot 与 CI 的消息不会到达它,因为其 Executor 恢复时会重新读取它的 Thread。被人 stop 的 Ticket 不再接收任何内容。主 Session 只有在消息明确指向某个 Ticket 时,才把 Thread 附到既有 Ticket 上。人可以丢弃一个 Thread 上的全部 Subscription;Executor 只能丢弃自己 Ticket 对某个它认定无关的 Thread 的 Subscription,但其 Ticket 起始的 Thread、以及 Source 让它跟随的 Thread(例如其 pull request 的 Thread)除外 | 后续讨论无需任何人再次提及 agent,就能到达 Executor |
人不是领域概念。Trigger 携带其 actor 的标识符,由 Source 给出。允许列表是 Policy 中属于某个 Source 的部分,用该 Source 的身份表示。「同一个人在多个 Source 上有账号」是 prompt 文本,agent 需要时会去读。
Executor 及其 Session 与目录在领域之外,经 Assignment 接入。
聚合:Source 持有读取位置。Thread 持有其 Subscription、其运行中的 Eval(串行运行,并把期间到达的 Trigger 合并进下一批)及其 Decision 历史。Ticket 持有其 Assignment、Channel 与 Input,并按 id 引用 Decision。
被拒绝的概念
| 被拒绝 | 原因 |
|---|---|
| 把 Principal 或 Membership 做成实体,或跨 Source 映射身份 | 人是 Trigger 元数据;允许列表是 Policy 的 Source 部分;跨 Source 映射是 prompt 文本 |
| Eval 自行调度延迟的 Trigger | 需要等待的条件就是一个普通的 Source,因此 Eval 从不反向依赖 Source |
| Eval 的等待或已撤销状态 | 等待属于 Source;耗尽时间的 Eval 把它的 Trigger 重新排队,或以 unavailable 结束 |
| 每个 Thread 至多一个活跃 Ticket | 一个 Thread 可以承载多件独立的工作;研判借助 Ticket 列表避免重复 |
| 「追加到 Ticket」的 Decision | 追加就是 Subscription 扇出,不需要 Eval |
| 对 Subscription 做准入检查 | Subscription 覆盖整个 Thread;Mandate 把授权与上下文分开 |
| 会路由的 Correlation | 路由由 Subscription 完成;Correlation 只添加上下文 |
| 跟随 DSH Session 的 Ticket 状态 | Ticket 可以被移交、恢复或由多个 Executor 运行,因此它定义自己的状态 |
| 由 Executor 声明「有人要求它停止」 | 只有 Eval 决定一次结束的强度 |
| Policy 变更时取消运行中的 Ticket | 被取消的变更会留下半成品;改为记录变更并送达 |
| Executor Session 失败或受阻时锁死其全部工具 | 这会拒绝直接在 Session 里工作的人,以及恢复之后的报告;暂停自动输入就足够了 |
| 从报告的自由文本推断「正在等人」 | 分类需要结构化事实;Executor 通过结构化字段提问 |
什么可复用
上述概念及其规则是可复用的。Source 实现、Policy 内容、Executor 与 Channel 的实现属于一次具体部署。每个 Source 在内部保留自己的词汇(例如 message、chat、notification),并把它们翻译成 Trigger。
| 部分 | 本仓库中的实现 |
|---|---|
| Source | 飞书:实时事件、历史恢复、订阅话题的轮询。GitHub:通知、订阅的 Issue 与 pull request、CI 变更、pull request 被合并或关闭,以及(在开启时)仓库内每一个新 Issue、新 pull request、新评论与默认分支的 CI |
| Policy | 研判规则,以及每个 Source 的允许列表、其同步方式、bot 列表与准入表 |
| Executor | 一个 DSH Executor Session 与每个 Ticket 一个目录,运行在由 Executor 与各 Source 注册了变量的执行环境中 |
| Channel | 飞书话题回复、GitHub 评论与 review 线程回复 |
词汇表
本文档及后续文档所用术语的参考清单,附各自的中文名称;后续文档会解释上文尚未引入的术语。面板一次显示一种语言;其 (?) 按钮会打开本词汇表的双语对照。agent 在 GitHub 和飞书上发给人的消息使用平实的语言,不使用这些术语。
| 术语 | 中文 | 含义 |
|---|---|---|
| Agent | 智能体 | dsh-superagent 运行的自动化团队成员,通过 GitHub 账号、飞书 bot 等身份在 Source 上行动 |
| Main Session | 主 Session | 负责研判 Trigger、接受与派发 Ticket 并进行回复的 DSH Session;代码与 prompt 中为 orchestrator |
| Executor Session | 执行器 Session | Executor 为一个 Ticket 运行的 DSH Session;代码与 prompt 中为 worker |
| Source | 来源 | 一条事件流:由插件提供的种类,加上一份实例配置 |
| Trigger | 触发 | 来自 Source 的一个不可变事件 |
| Thread | 线程 | 按时间排序的 Trigger;Eval 在其中一次一个地运行 |
| Correlation | 关联 | 共享同一 Trigger 的 Thread 之间的关系;只添加上下文 |
| Channel | 渠道 | Thread 的写入侧 |
| Policy | 策略 | 带版本的接单规则,以及每个 Source 的部分,例如谁可以在那里发起工作 |
| Policy version | 策略版本 | 规则、Source 部分与 accept 模式的一种组合的标识符;每个 Mandate 都记录它 |
| Eval | 评估 | 把一批 Trigger 变成一个 Decision 的过程 |
| Gate | 准入 | Eval 的确定性第一层:谁可以发起工作、以什么强度 |
| Assessment | 研判 | Eval 中模型做出的判断 |
| Decision | 决定 | Eval 的结果 |
| Mandate | 授权 | accept 授予的内容:强度、范围与所依据的 Policy 版本 |
| Ticket | 工单 | 一个被授权的工作单元 |
| Assignment | 派工 | Ticket 与一个 Executor 实例的绑定 |
| Subscription | 订阅 | Ticket 与 Thread 之间的关系 |
| Fan-out | 扇出 | 把已订阅 Thread 的 Trigger 作为上下文送达 Ticket |
| Executor | 执行器 | 运行 Assignment 的端口:每个 Ticket 一个 Executor Session 与一个目录 |
| Execution environment | 执行环境 | Executor Session 与 prepare 命令运行之处:由 Executor 与各 Source 注册的变量,各有键、值与描述 |
| Report | 报告 | Assignment 向其 Ticket 报告的状态 |
| Attention | 待人工决定 | Ticket 上等待人回答的问题 |
| Disposition | 去向 | 一个 Trigger 被过滤、被研判或被扇出的记录 |
| Input | 输入 | 送达 Ticket 的上下文:扇出的 Trigger、Policy 变更、恢复与文本 |
| Scope | 范围 | Mandate 允许的工作 |
| Strength | 强度 | Mandate 或 Eval 的依据有多强 |
| 分组 | 取值 |
|---|---|
| Decision | accept 接单 · stop 停止 · ignore 忽略 · unavailable 未完成 |
| Strength | explicit 明确 · inferred 推断 |
| Assignment | pending 待启动 · running 执行中 · ended 已结束 |
| Report | progress 进展 · waiting 等待 · ready 就绪 · blocked 受阻 · failed 失败 · dropped 无需处理 |