Files
deepseek-harness/docs/rfc/implemented/architecture/2026-07-08-agent-scope-contexts.zh.md
T
Ziya 2565133af3 docs(i18n): RFC tree batch — 146 bilingual pairs via the committed pipeline
implemented(除 4 篇超长文档随后补)、proposed、rejected 全树配对;
同一流水线 + 二遍校验(paraphrase-back + 仓库上下文一致性)产出。
docs/rfc/implemented/AGENTS.md 与其 CLAUDE.md 符号链接列入排除
(agent 指令文件,与根 AGENTS.md 同策略)。
2026-07-15 23:25:06 -07:00

10 KiB
Raw Blame History

RFC:agent 即注册作用域

Status: implemented

English | 中文

问题

一个应用需要在多个 agent(智能体)之间共享基础设施,同时让每个 agent 拥有自己的工具、prompt 贡献、策略和监听器。共享的适配器、持久化和用户界面属于部署层面;而一个人设、工具变体或监听器往往只属于某一个 agent。

为每个 agent 建立独立的服务图会重复共享基础设施。一个全局注册图则有相反的问题:某个 agent 的专属贡献可能泄漏到无关的 agent 中。贡献者需要一种普通的注册机制,既能决定谁能看到一项贡献,又能决定何时清理它。

该机制还需要一个发布边界。agent 在其本地世界完整之前不得变为可见,而拆除过程必须保留该世界直到最终工作停止。

决策

每个存活的 agent 拥有一个扁平的注册层,通过 agent.ctx 暴露。代码通过拥有该贡献的上下文进行注册;感知作用域的服务将部署全局注册与恰好一个匹配的 agent 层组合;操作从其真实 agent 选择该层;该层在 agent 完整的已发布生命周期内存在。

Cordis 是 SDK 底层的插件框架。Cordis 上下文(context) 是插件用来访问服务和注册效果的对象,效果的清理跟随该上下文。Cordis 入门对框架有更详细的说明。

对大多数贡献者而言,完整的契约是四条规则:

问题 规则
在哪里为某个 agent 注册行为? 通过 agent.ctx 调用普通的注册 API
某个 agent 的操作能看到什么? 部署全局加上该 agent 的层,使用所属服务的合并规则
哪些作用域监听器会运行? 无作用域监听器加上为该操作的 agent 注册的监听器
该层存在多久? setup 在发布前完成;dispose 保留该层直到工作达到静止

作用域是扁平的。解析永远不会遍历父级或兄弟作用域,生命周期所有权也不意味着注册继承。

flowchart LR
  plain["Plain plugin context<br/>cleanup follows the plugin"] -->|"registers into"| globalLayer["Deployment-global layer"]
  agentAContext["agentA.ctx<br/>cleanup follows Agent A"] -->|"registers into"| agentALayer["Agent A layer"]
  agentBContext["agentB.ctx<br/>cleanup follows Agent B"] -->|"registers into"| agentBLayer["Agent B layer"]

  operationA["Operation for Agent A"] -->|"selects"| agentAView["Agent A view<br/>globals plus A local"]
  globalLayer --> agentAView
  agentALayer --> agentAView
  operationB["Operation for Agent B"] -->|"selects"| agentBView["Agent B view<br/>globals plus B local"]
  globalLayer --> agentBView
  agentBLayer --> agentBView

缺失的交叉边就是隔离规则:Agent A 的本地注册不会进入 Agent B 的视图,父级的注册也不会仅因为父级拥有子级的生命周期就进入子级。

配套的运行时设计 RFC 解释了实现与正确性推理。subagent 组合控制 RFC 拥有独立的 persona、toolFilter 和 maxDepth 功能。

注册来源决定可见性与清理

通过普通插件上下文进行的注册是部署全局的,随该插件 dispose。同一方法通过 agent.ctx 调用则贡献给一个 agent,随该 agent 的作用域 dispose。

注册来源 默认可见性 随谁 dispose
普通插件上下文 每个符合条件的 agent 视图 注册插件
agent.ctx 仅该 agent 的视图 agent 作用域

工具、prompt 段落与变量、工具限制、守卫和作用域事件监听器都采用此契约。同名的本地值通常对该 agent 遮蔽同名的全局值;每个所属服务自行记录例外与合并行为。

普通贡献者的模式是在 agent setup 期间注册完整的本地世界:

const handle = await ctx.agents.create({
  agentId: AgentId('reviewer'),
  sessionId: SessionId('reviewer-session'),
  agentOptions: { model: 'model-name' },
  setup(agentCtx) {
    agentCtx.systemPrompt.section({
      name: 'deployment:persona',
      order: 0,
      text: 'Review code, but do not modify files.',
    })
    agentCtx.tools.register({
      name: 'review_summary',
      description: 'Return the review summary.',
      parameters: { type: 'object', properties: {} },
      async execute() {
        return [{ type: 'text', text: 'review complete' }]
      },
    })
  },
})

ctx.tools.get('review_summary')                // undefined: not global
ctx.tools.get('review_summary', handle.agent)  // the reviewer-local tool

await handle.dispose()
ctx.tools.get('review_summary', handle.agent)  // undefined: scope is gone

setup 接收一个完整的受信 Cordis 上下文,因此可以组合普通的插件和服务。其契约仅限组合:通过强制转换或内部注册表调用来驱动或发布正在构建的 agent 是不受支持的。

操作选择视图

注册来源与操作主体是两个独立的事实。通过 agent.ctx 调用服务决定的是新注册归属何处,并不将后续读取绑定到该 agent。

工具查找与执行接收其服务的 agent。prompt 组装接收正在构建请求的 agent 的组装上下文。事件分发接收其领域主体。这使共享服务实例可在多个 agent 间复用,同时让每个操作的视图保持显式。

只有采纳了作用域契约的服务才会解析 agent 层。agent.ctx 不会自动改变任意 Cordis 服务调用的行为。

作用域事件将路由与事件数据分离

关于 Agent A 的事件通常到达无作用域监听器和 A 作用域监听器,而不到达 B 作用域监听器。没有 agent 主体的事件只到达无作用域监听器。

在 Cordis 层面,Scoped<T> 是一个不透明的路由接收器。它携带用于选择监听器的过滤器,但本身不是领域对象。因此事件签名将真实的 Agent、工具执行、审批请求或其他主体作为显式参数保留,供监听器检查。

以 { global: true } 注册的监听器有意绕过上下文受众过滤,但其清理仍跟随注册上下文。注册表成员变更通知保持不过滤,因为它们描述的是共享注册表状态而非某个 agent 的操作。生成的事件目录是详尽的事件参考。

创建最后发布,dispose 最后撤销

ctx.agents.create() 和 resume() 构建未发布的会话、作用域、agent 和驱动器。它们等待 setup,准入最终的会话和 agent 条目,按序公告,启动循环,然后才返回 handle。

可选的创建信号仅在 create 或 resume 挂起期间取消工作。promise resolve 后,返回的 AgentHandle 拥有显式的 dispose 权。

如果加载、setup、准入或发布失败,私有事务回滚其准备的一切。使用同一调用方提供的存活 ID 的并发操作可能都到达 setup,但最终注册表条目只准入一个;所有失败者拒绝并清理其私有资源。在等待 dispose 完成后的顺序复用仍然有效。

AgentHandle.dispose() 反转边界。它停用创建或驱动,等待同步发布解除,停止并排空驱动器和最终会话刷新,分离 agent 和会话,最后 dispose 作用域。重复或竞争的 dispose 请求合并为一个完成 promise。

调用方的 Cordis 上下文和具体的 AgentLoop 工厂是结构性共同所有者。卸载任一方都会 dispose 事务或存活 agent。

flowchart TB
  request["Create or resume"] --> privateWorld["Build private session, scope, agent, and driver"]
  privateWorld --> setup["Await composition through agent.ctx"]
  setup --> admission["Admit final session and agent entries"]
  admission --> publish["Announce lifecycle and start the driver"]
  publish --> live["Return AgentHandle"]

  privateWorld -->|"failure, cancellation, or owner loss"| rollback["Rollback private work"]
  setup -->|"failure, cancellation, or owner loss"| rollback
  admission -->|"duplicate or owner loss"| rollback
  publish -->|"listener failure or owner loss"| rollback
  live -->|"handle or owner disposal"| quiesce["Stop and drain work"]
  rollback --> quiesce
  quiesce --> detach["Detach agent, then session"]
  detach --> revoke["Dispose the agent scope"]

安全与权限是非目标

agent 作用域组合的是受信的同进程注册。它不沙箱化插件,不定义父到子的权限格,不在创建时冻结授权,也不保证子级不能做超出父级的事。

父级可以拥有一个可见工具比自身更宽的子级,因为生命周期所有权不捐赠也不封顶注册。持有 Cordis 上下文的插件同样运行在同一进程中,可以直接调用可用服务。

需要非升级保证的部署需要独立的权限表示、传播规则和执行检查。父集合授权、创建时授权快照、显式的未来授权 API、以及通用的能力/输出/终止标签均不在本决策范围内。

曾考虑的替代方案

被否决的设计要么将可见性与清理分离,要么只覆盖一个注册族,要么重复共享基础设施,要么将生命周期所有权与继承混为一谈。

向每次注册传递 agent 选项

类似 tools.register(definition, { agent }) 的 API 在每个注册表中重复作用域管道,并允许可见性所有权与清理所有权漂移。通过 agent.ctx 注册使两个事实跟随同一个 Cordis 效果所有者。

过滤事件但保持注册表全局

监听器过滤能阻止错误的钩子运行,但无法限定工具 schema、可执行查找、prompt 段落、变量或其他已注册数据的作用域。agent 本地组合仍需临时的全局变更。

为每个 agent 创建一个服务图

所需的视图是共享部署服务加上一个本地注册层。每 agent 一个图会重复适配器,并使共享持久化、提供方注册表和应用启动复杂化。

继承父级注册作用域

父子关系描述的是生命周期和对话谱系,而非通用合并策略。层级查找会让无关服务意外继承,且在没有独立权限模型的情况下无法定义安全性。

后果

贡献者使用一种熟悉的模式:通过插件上下文注册共享行为,通过 agent.ctx 注册本地行为,在操作上选择真实 agent,dispose 返回的 handle。从观察者角度看 setup 是原子的,teardown 保留本地行为直到工作停止。

代价是显式的主体选择、异步的编程式创建,以及服务需要逐个采纳作用域。扁平注册作用域有意不等于权限,subagent 组合控制作为独立功能存在,而非隐藏在作用域语义中。