Files
dsh-superagent/docs/001-领域模型.md
T

12 KiB
Raw Blame History

001 领域模型

本文命名 dsh-superagent 的各个概念,以及每个概念守住的规则。代码、agent 调用的工具、面板和其他文档都使用这些术语,不用别的。依照 000 理念,模型只保留工作需要的概念,一个业务需求会变成其中某个概念的属性。

流程

工作从 Trigger 到 Eval 再到执行。Source 产出 Triggers。一个 Trigger 作为上下文扇出给订阅了其 Threads 的各个 Tickets。以这种方式到达某个 Ticket 的人的消息就留在那个 Ticket 上;其余每个 Trigger 都进入 Eval,由它决定是否发起新的工作。Eval 接单时,创建一个带 Mandate 的 Ticket。Assignment 把 Ticket 交给一个 Executor,结果通过 Channel 回到 Source。

flowchart LR
  S[Source] -->|Trigger| T[Thread]
  T -->|batch| E[Eval]
  T -->|Subscription fan-out| K[Ticket]
  E -->|accept with Mandate / stop| K
  E -->|ignore / unavailable| X[recorded]
  P[Policy change] -->|notice| K
  K -->|Assignment| W[Executor]
  K -->|Channel| S

概念

Source、Thread、Eval、Mandate 与 Subscription 构成核心领域;其余概念支撑它们。

概念 定义 它守住的规则 为什么存在
Source 一条事件流。Source kind 是一个可复用的实现;Source instance 是某个 kind 的一份配置:是否运行、监听什么 保存自己的读取位置与自己的 bot 身份。定义什么算事件,包括只在时间上成立的条件。在进入领域之前,丢弃 bot 自己的消息和监听范围之外的 Triggers。把每个 Trigger 翻译成它所属的 Threads 与用于答复的 Channel 地址 重启不得重放事件
Trigger 一条不可变事件,带有 Source 自己的元数据,例如它的 actor 属于一个或多个 Threads。同一个 Trigger 被接单两次只创建一个 Ticket 审计与幂等的单位
Thread 按时间排列的 Triggers;由 Source 定义哪些 Triggers 构成一个 Thread 同一时刻至多运行一个 Eval。它可以有多个 Tickets。它保存自己的 Subscriptions、正在运行的 Eval 和 Decision 历史 给 Eval 一个一致的视图和它的上下文
Correlation 同一个 Trigger 所属 Threads 之间的关系 只增加上下文;从不路由 让 Eval 能追踪相关证据
Channel Thread 的写入侧;地址由 Source 定义 一个 Thread 可以有多个 Channels;一个 Ticket 持有其中一个集合 认领回执、答复、pull requests 和 resolved reviews 都是写入
Policy 带版本的评估规则,加上每个 Source 自己的部分:谁可以通过该 Source 发起工作、用的是该 Source 自己的身份、名单如何同步、以及哪些 bots 可以产生候选 Policy 版本覆盖规则、accept mode 和各 Source 部分。一个与某个活着的 Ticket 相关的变化——比如它接单所依据的规则变了——会投递给它的 Assignment;但不吊销 Mandates。不同 Source 上的身份彼此绝不映射 规则变了,正在运行的 Eval 必须作废
Eval 对一个 Trigger 批次的判断,分两层:gate 与 assessment 输入:Trigger 批次、一个 Thread 快照、该 Thread 上的所有 Tickets(含 ended 的)、以及当前的 Policy。输出:一个 Decision。不持有状态 决定新的工作是开始、继续还是停止
Mandate 一次接单所授予的东西:Policy 版本、scope、强度、命中的规则、发送者在该 Source 上的身份、以及 Source 收到该 Trigger 的方式 不可变;更宽的 scope 意味着新的 Ticket。Ticket 的结束不等于它的结束:只有人的 stop 才撤回它,一个不再成立的 Policy 会吊销它。ended Ticket 恢复之前会按当前 Policy 重新校验 说明工作为什么可以做、能做到什么程度
Ticket 一份授权工作的单位 只能由 Eval 创建。引用它的 Mandate;持有它的 Channels 与 Inputs。走 open → ended,当有人在它某个 Thread 上发的消息让它复活时会回到 open,除非它是被人停掉的。它定义自己的状态,不跟随 Executor 的 拥有执行及其报告
Assignment 一个 Ticket 与某一个 Executor 实例的绑定 一个 Ticket 随时间会有多个。独立于 Ticket 走 pending → running → ended。在 Executor 一侧,只有它的最终报告能结束 Ticket Executor 在领域之外,但"由谁执行"必须在领域之内
Subscription Ticket 与 Threads 之间的多对多关系,由 Thread 持有 命中的 Trigger 会扇出给每个订阅着的活 Ticket,不检查发送者是谁;以这种方式到达某个 Ticket 的人的消息不经过 Eval。Executor 为上下文关注的 Thread 同样会抵达它的 Ticket,但不给它带来任何授权、也不使它复活。ended Ticket 保留它的 Subscriptions,包括一个已关闭或已合并的 pull request 的订阅:人的消息会在同一个 Mandate 下让它复活,不经过 Eval 也不产生 Decision;来自 bots 和 CI 的消息到不了它,因为它的 Executor 恢复时会重新读取它的 Threads。被人停掉的 Ticket 什么都收不到。只有当一条消息明确指向某个既有 Ticket 时,main Session 才把 Thread attach 到它。人可以移除某个 Thread 上的所有 Subscriptions;Executor 只能移除自己的 Ticket 对一个它判定为无关的 Thread 的订阅,除了它的 Ticket 由此开始的那个 Thread、以及被 Source 要求关注的那个 Thread(例如它的 pull request) 让后续讨论不需要任何人再次点名 agent,就能到达 Executor

人不是领域概念。Trigger 带着 Source 给出的 actor 标识符。允许名单是 Source 在 Policy 里的那部分,用的是该 Source 的身份体系。同一个人拥有几个 Source 上的账号——这是 agent 需要时才会读的提示词文本。

Executor 连同它的 Sessions 和目录在领域之外,通过 Assignments 连接。

聚合:Source 持有它的读取位置。Thread 持有它的 Subscriptions、正在运行的 Eval——Eval 串行运行,期间到达的 Triggers 并入下一批——以及它的 Decision 历史。Ticket 持有它的 Assignments、Channels 与 Inputs,并按 id 引用 Decisions。

被拒绝的概念

被拒绝的 理由
Principal 或 Membership 作为实体、或跨 Sources 映射身份 人是 Trigger 的元数据;允许名单是 Source 在 Policy 里的部分;跨 Source 的映射是提示词文本
Eval 自己调度延迟的 Triggers 一个需要等待的条件就是一个普通的 Source,这样 Eval 永远不反过来依赖 Sources
waiting 或 revoked 的 Eval 状态 等待属于 Sources;超时的 Eval 把它的 Triggers 重新排队,或以 unavailable 结束
每个 Thread 至多一个活 Ticket 一个 Thread 可以承载多件相互独立的工作;评估靠 Ticket 列表来避免重复
"append to Ticket" 这个 Decision 追加是 Subscription 扇出,不需要 Eval
对 Subscriptions 做准入检查 Subscription 覆盖整个 Thread;Mandate 负责区分授权与上下文
会路由的 Correlation 路由归 Subscriptions;Correlation 只增加上下文
Ticket 状态跟随 DSH Session Ticket 可以被移交、复活、或由多个 Executors 执行,所以它定义自己的状态
由 Executor 声称有人要求它停止 只有 Eval 决定结束的强度
Policy 变更时取消正在运行的 Tickets 被取消的改动会留下做了一半的工作;正确的做法是记录并投递这个变更
Executor Session 失败或受阻时锁掉它的全部工具 那会连累直接在 Session 里工作的人、以及恢复之后的报告;暂停自动输入就够了
从报告的自由文本推断"在等人" 分类需要结构化事实;Executor 用结构化字段来问

哪些是可复用的

上面的概念及其规则是可复用的。Source 实现、Policy 内容、Executor 与 Channel 实现属于具体的部署。每个 Source 在内部保留自己的说法,例如 message、chat 或 notification,并把它们翻译成 Triggers。

部分 在本仓库中
Source Feishu:实时事件、历史恢复、对订阅话题的轮询。GitHub:notifications、被订阅的 Issues 与 pull requests、CI 变化、pull requests 的合并或关闭,以及(开启时)仓库中每一个新的 Issue、pull request、评论和默认分支的 CI
Policy 评估规则,以及每个 Source 的允许名单、它的同步、bot 名单与准入表
Executor 每个 Ticket 一个 DSH Executor Session 和一个目录,运行在一个由 Executor 与各 Sources 注册变量的执行环境里
Channel Feishu 话题回复、GitHub 评论与 review thread 回复

术语表

本及后续文档所用术语的对照表,附中文名;上面没有引入的术语由后续文档解释。面板一次只显示一种语言;它的 (?) 按钮打开这份双语术语表。agent 在 GitHub 与 Feishu 上发给人的消息使用平实的语言,不用这些术语。

术语 中文 含义
Agent 智能体 dsh-superagent 运行的自动化团队成员,通过 GitHub 账号、Feishu bot 这样的身份在 Sources 上行动
Main Session 主 Session 评估 Triggers、接单并派发 Tickets、以及答复的那个 DSH Session;代码与提示词里叫 orchestrator
Executor Session 执行器 Session Executor 为一个 Ticket 运行的 DSH Session;代码与提示词里叫 worker
Source 来源 一条事件流:由插件提供的一个 kind,加上一份实例配置
Trigger 触发 来自 Source 的一条不可变事件
Thread 线程 按时间排列的 Triggers;Eval 在其上逐个运行的单位
Correlation 关联 共享一个 Trigger 的 Threads 之间的关系;只增加上下文
Channel 渠道 Thread 的写入侧
Policy 策略 用于接受工作的带版本规则,以及每个 Source 在其中的部分,例如谁可以在那里请求工作
Policy version 策略版本 规则、Source 部分与 accept mode 的一种组合的标识;每个 Mandate 都记录它
Eval 评估 把一个 Trigger 批次变成一个 Decision 的过程
Gate 准入 Eval 确定性的第一层:谁可以发起工作、以什么强度
Assessment 研判 Eval 期间模型做出的判断
Decision 决定 Eval 的结果
Mandate 授权 一次接单所授予的东西:强度、scope 和它所依据的 Policy 版本
Ticket 工单 一份授权工作的单位
Assignment 派工 一个 Ticket 与某一个 Executor 实例的绑定
Subscription 订阅 一个 Ticket 与一个 Thread 之间的关系
Fan-out 扇出 把被订阅 Thread 的 Triggers 作为上下文交付给一个 Ticket
Executor 执行器 运行 Assignments 的端口:每个 Ticket 一个 Executor Session 和一个目录
Execution environment 执行环境 Executor Sessions 与 prepare command 运行的地方:由 Executor 与各 Sources 注册的变量,每个都有 key、取值和说明
Report 报告 一个 Assignment 向它的 Ticket 报告的状态
Attention 待人工决定 Ticket 上等待人答复的一个问题
Disposition 去向 一个 Trigger 被过滤、被评估或被扇出的记录
Input 输入 投递给一个 Ticket 的上下文:扇出的 Triggers、Policy 变更、resume 与文本
Scope 范围 一个 Mandate 所允许的工作
Strength 强度 一个 Mandate 或 Eval 的依据有多强
分组 取值
Decision accept 接单 · stop 停止 · ignore 忽略 · unavailable 未完成
Strength explicit 明确 · inferred 推断
Assignment pending 待启动 · running 执行中 · ended 已结束
Report progress 进展 · waiting 等待 · ready 就绪 · blocked 受阻 · failed 失败 · dropped 无需处理