DeepSeek Harness Superagent架构03:授权模型
DeepSeek Harness Superagent 授权模型:一条消息如何变成一张工单
系列第 3 篇。本文解释谁可以发起工作、工作在什么范围内被授权,以及已结束的 Ticket 如何恢复。它建立在上一篇领域模型之上。
一、授权系统在防什么
授权要回答两个问题:
- 谁可以开始一项工作?
- 这项工作可以包含什么?
在 dsh-superagent 中,host 强制执行允许名单、规则和 Mandate。消息、评论、引用文档只是决策的输入,它们不能改变这些权限。这个边界很重要:模型可以在允许范围内判断,但不能通过一段外部文字提升自己的权限。
二、一条 Trigger 的两条路径
Eval:决定是否开始工作
Source 会记录消息是否对着 Agent:mention 表示提到 bot 或 agent 账号,direct 表示私聊。Gate 检查发送者和 Source 的 Policy:
- 允许名单中的人明确对 Agent 说话,构成 explicit request。
- 人在带 Ticket 的 Thread 上跟进,按下面的规则处理。
- 其他人的消息使用对应接收范围的 admission table。
- 在 Source bot 名单中的 bot 可以产生 inferred candidate,但永远不能产生 explicit request。其他 bot 不进入。
Subscription:继续已有工作
订阅 Thread 上的每条消息都会作为上下文到达订阅它的 Ticket,包括 bot 和 CI 的消息。这条投递绕过 Gate,也不授予新权限。每个 Ticket 始终受它的 Mandate 限制。
人在 Ticket 自己 Thread 上的消息由该 Ticket 的 Executor 决定。主 Session 把消息 attach 到 Ticket 时也一样。只要 Executor 拥有这条消息,它就不经过 Eval、也不产生 Decision。Executor 要么在 Ticket 范围内处理,要么交回,让系统路由到别处。
只要 Ticket 还是 live 的,即使人移除了 Subscription,这个 ownership 仍然存在。它同样覆盖已经 ended、但并非被人 stop、并且有消息等待恢复它的 Ticket。
主 Session 收到 follow-up notice。Executor 拥有该消息时,主 Session 只能在人的请求下停止工作;accept、attach、ignore、requeue 都会被拒绝。stop 仍通过 Gate,使用 follow-up 强度。
交回与释放 follow-up
Executor 在以下情况交回消息一次:
- 请求超出 Ticket 范围;
- 请求属于另一个 Ticket。
Ticket 保留 Subscription。如果 attach 的 Thread 不相关,Executor 交回它在那里拥有的消息。
只有当没有 Ticket 再拥有该消息时,它才进入新的 Eval。候选会带上 Executor 的原因。Gate 把它当作 Thread 上的普通消息判断;主 Session 可以 accept、attach 到别处或 ignore。
Ticket 结束时,会释放 Executor 没有读或没有接管的 follow-up。这些消息包括从未投递到 Executor 的,以及在最后 Report 或 turn end 之后投递但未确认、回答、交回的。释放的消息在没有其他 Ticket 拥有时进入 Eval。stop 只结束被 stop 的 Ticket 的工作。
被 stop 的 Ticket 不会再把 stop 消息送入 Eval,除非另一个 Ticket 交回了它。执行 stop 的主 Session 可以把消息的其余部分作为新工作接受。
人可以在面板把 owned follow-up 送入 Eval。如果主 Session 又把它 attach 回 live Ticket,Executor 会再次收到。没有有效裁决覆盖该消息时,面板还提供重新评估。
只看上下文的 Subscription
Executor 可以跟随相关 Thread(例如另一个 Issue 或 PR)获取上下文。那里的消息到达 Ticket,但不授予权限或 follow-up strength。人类消息不会恢复 ended Ticket,除非主 Session attach 了该 Thread 的消息。主 Session 关于其他工作的 note 也只是上下文。
到达不了任何 Ticket 的人类消息,包括被人 stop 的 Ticket 的 Thread,走 Eval 路径。bot 消息独立于投递给订阅 Ticket,也走 Eval 路径。
三、Strength:授权有多强
| Strength | 场景 |
|---|---|
| explicit | 名单中的人对 Agent 说话;或人在已有 Ticket 的 Thread 上跟进;或 admission table 的某格被设为 explicit request |
| inferred | 不在名单的人在带 Ticket 的 Thread 上跟进,除非该格为 explicit;或 admission table 某格设为 inferred candidate;或 bot 名单中的 bot 对 Agent 说话,或发到 Source 接收所有消息的位置 |
| not admitted | 其他 bot 的消息;admission table ignore 的一切;以及 accept mode 为 off 时的所有 inferred 情况 |
对不在名单的人,explicit admission cell 优先,即使 Thread 上已经有 Ticket,并且在所有 accept mode 下都有效。否则他们的 follow-up 是 inferred,在 off 模式下不进入。只用于上下文而跟随的 Thread 上的消息,使用 admission table 而不是 follow-up strength。
四、Admission table:把“接收范围”配置成权限
每个 Source 的 Policy 都有一张 admission table,行是接收范围:
- Feishu: 每个配置的 chat、bot 收到 mention 的其他 chat、私聊。其他 chat 只有在 Feishu 卡片上把“其他群”设置为“仅 @”时才会接收。
- GitHub: 新 Issue、新 Pull Request、comments、默认分支 CI。
一行最多有三个格,每个格决定一条消息成为 explicit request、inferred candidate 还是 nothing:
| Cell | Choices | Default |
|---|---|---|
| 在名单中,未对 Agent 说话 | inferred, ignore | inferred |
| 不在名单中,对 Agent 说话 | explicit, inferred, ignore | ignore |
| 不在名单中,未对 Agent 说话 | inferred, ignore | ignore |
未对 Agent 说话的消息单元格只在 Source 接收所有消息的地方可用,例如设置为“全部消息”的 Feishu chat,或开启 receive-all 的 GitHub scope。CI 结果没有 sender,所以它的行只提供最后一个 cell。bot 消息使用 bot list,不使用这些 cells。
把 unlisted-addressed 设为 explicit,相当于允许该范围内的任何人通过 @ Agent 请求工作,适合专门的 support chat。Inferred candidate 仍然受 accept mode 影响。follow-up 通常绕过 admission table,但 explicit cell 仍会赋予 explicit strength。
Admission table 是 Policy version 的一部分。放宽一个 cell 不会立刻停止已经按它接受的 open Ticket;它们只在恢复前重新验证时可能被吊销 Mandate。
Bots 与 automated reviewers
Host 把 GitHub Apps、以 [bot] 结尾的登录名、Feishu bots 识别为 bot。Source 可以列 dependabot[bot] 这样的 bot,其消息可以成为 inferred candidate。它们必须对 Agent 说话,或发到接收所有消息的 scope。它们不能产生 explicit request,也不能 stop Ticket。
使用普通账号的 automated reviewer 对 host 来说算人。其评论会到达订阅 Ticket,并产生 follow-up notice。团队 prompt 文本必须把这些账号标为 automated reviewer。
五、主 Session 如何路由候选
主 Session 用 orchestrator_route 路由 explicit candidate。一次调用可以包含多个 accept、attach、stop 或 ignore decision。每一项独立处理:一个被拒绝的项或缺失字段不会阻止其他项运行。
Inferred candidate 通常需要完整 assessment。一个捷径是:如果卡片明显不触及任何启用规则,例如普通聊天或不相关讨论,主 Session 可以直接 ignore。Decision 记录 ignoredFromCard 以区别于规则 assessment。主 Session 读取 Policy prompt section 中的启用规则。
接受 inferred candidate 始终需要 assessment。直接 accept 会拒绝 Gate 未把其作为 explicit 接纳的 Trigger。
六、Accept mode 与 rules
| Mode | 效果 |
|---|---|
off | 任何 inferred 都不成为 candidate,例如未对 Agent 说话的消息、bot 消息、不在名单的人的 follow-up |
observe(默认) | Inferred candidate 被 assessment;正向 assessment 被记录为 ignore,标记 “would accept”,不实际接受 |
auto | Inferred candidate 的正向 assessment 接受它 |
Explicit request 在所有模式下都有效。建议从 observe 开始,在检查记录的 Decision 后再切到 auto。每个 assessment 对每条启用规则恰好判断一次,无论是否匹配。Proactive accept 至少需要一条匹配规则。
每条规则描述一种 proactive work。Ticket 的 Mandate 记录匹配规则,Executor 收到规则名称和指令。对某个 Ticket,规则的 process 和 communication requirements 会覆盖默认值。silence rule 可以抑制确认;review rule 可以指定 reviewer 和 merge 前 approval。适用于所有 Ticket 的要求放进 team prompt sections。
七、Policy version:为什么规则版本必须进入 Mandate
Rules、accept mode 和每个 Source 的 Policy 共同组成 Policy version。每个 Mandate 记录它是在哪个版本下接受的。
版本变更会丢弃运行中的 Eval,并把它们的 Trigger 重新排队。它还会向每个受影响的 live Ticket 发送 policy-changed Input,说明:
- 匹配规则是否变化,包括新文本,或不再适用;
- 请求者是否不再可以发起工作;
- proactive work 是否不再接受,例如模式从
auto变掉。
未受影响的 Ticket 不收到通知。变更不会立即撤销 live Ticket 的 Mandate。
Source 配置与 Policy 分离。它控制什么进入系统:读取哪些 chat,scope 是接收所有消息还是只接收 mention。Mandate 记录它的 Source 和接收 scope。恢复需要 Source 仍然监听原 Thread,但不要求它仍接收所有消息。
Source 关闭时,回复会等待。如果 Source 不再监听目的地,回复会被 dropped。
“Executor 可以怎样处理自己的结果”,例如什么时候能 merge,不决定谁可以授权工作。它属于 Agent 指令,不属于 Policy。
八、Resume 与 stop:结束的 Ticket 何时能回来
Ended Ticket 保留 Mandate。人在它自己的 Thread 上发消息,可以无需新 Eval 或 Decision 恢复同一工作,无论发送者是谁。bot 和 CI 不会唤醒 ended Ticket。Executor 判断请求是否符合 scope,不符合就结束这一轮。
只有三个操作会改变 Mandate:
- accept 创建它;
- 人的 stop 撤销它;
- 失败的 revalidation 吊销它。
被人 stop 的 Ticket 保持 ended,不再接收任何内容。那里需要新工作,必须重新 accept。
Resume 前的 revalidation
Source 必须仍监听原 Thread。其余检查取决于 Mandate basis:
- explicit follow-up Mandate 通过。
- inferred Mandate 需要
auto模式和匹配规则仍启用。 - 通过 admission table cell 进入的 Mandate,必须在今天的 table 和 sender membership 下仍至少获得原强度。把 sender 从名单移除,可能吊销通过 listed-sender cell 接受的 Mandate。
- bot 的 Mandate 要求 bot 仍在 Source bot 名单中。inferred table 和 bot Mandate 也需要
auto模式和启用规则。 - 其他 Mandate 要求 sender 仍在 Source 允许名单中。
Revalidation 失败时,Ticket 保持 ended,不接收任何等待消息。每条消息被当作没有 Ticket 接收;如果没有其他 Ticket 拥有它,就进入 Eval。主 Session 不会被告知它到达过 worker。处理暂停后同样适用。attach 被拒绝,继续工作需要新 accept。
需要记住:
- 人在 Thread 中说 “stop” 是普通 Trigger,由 Eval 决定 stop;Executor 不能声明某人让它停止。
- 面板中的 stop 是命令,直接作用于 Ticket,并记录为 manual stop。
- 等待条件属于 Source。例如“N 小时没有 assignee”应当是 Source 自己等待并再次检查;Eval 永远不等待。
九、Eval 没完成怎么办
时间限制从 candidate 到达主 Session 开始。等待投递的时间不计入;未投递的 candidate 永远不过期。
过期的 Eval 会重新排队 Trigger 再试一次。连续两次重试后,第三次过期记录 unavailable。Assessment failure 也记录 unavailable;后来的 Trigger 可以启动新 Eval。Policy change 或基于过期 Policy 做出的 Decision 记录 unavailable,并立即按当前版本重新排队。
evals health entry 报告过去一小时内未解决的 unavailable Decisions。scripts/dsh-superagent status 会包含这个 error。
面板只在以下条件同时满足时才要求人注意:
- unavailable Decision 小于 24 小时;
- 它仍是 Thread 上最新 Decision;
- 未被 dismiss;
- Thread 既未排队也未评估。
人可以重新评估 Trigger,或 dismiss 问题。
更多推荐

所有评论(0)