6.1 Agent 数据模型

模型: claude-opus-4-6 (anthropic/claude-opus-4-6) 生成日期: 2026-02-17


在上一章我们深入剖析了 Tool 系统——Agent 与外部世界交互的"手"。而本章,我们将聚焦于 Agent 本身——它是 OpenCode 赋予 LLM "性格"和"能力边界"的核心抽象。

如果说 Tool 定义了"Agent 能做什么",那么 Agent 就定义了"Agent 是谁"——它使用什么模型、拥有什么权限、遵循什么行为准则、最多执行多少步。理解 Agent 数据模型,是理解 OpenCode 整个多 Agent 编排体系的基础。

6.1.1 Agent.Info 的 Zod Schema 定义

Agent 的数据模型定义在 packages/opencode/src/agent/agent.ts 中,使用 Zod Schema 声明:

// agent/agent.ts
export namespace Agent {
  export const Info = z
    .object({
      name: z.string(),
      description: z.string().optional(),
      mode: z.enum(["subagent", "primary", "all"]),
      native: z.boolean().optional(),
      hidden: z.boolean().optional(),
      topP: z.number().optional(),
      temperature: z.number().optional(),
      color: z.string().optional(),
      permission: PermissionNext.Ruleset,
      model: z
        .object({
          modelID: z.string(),
          providerID: z.string(),
        })
        .optional(),
      variant: z.string().optional(),
      prompt: z.string().optional(),
      options: z.record(z.string(), z.any()),
      steps: z.number().int().positive().optional(),
    })
    .meta({ ref: "Agent" })
  export type Info = z.infer<typeof Info>
}

这段代码展示了 OpenCode 一贯的"Zod-first"设计风格——先定义数据 Schema,再从中推导出 TypeScript 类型。让我们逐一解析每个字段的含义和设计意图。

核心标识字段

字段
类型
必填
说明

name

string

Agent 的唯一标识符,如 "build""explore"

description

string

Agent 的用途描述,用于 UI 展示和 LLM 选择参考

native

boolean

是否为 OpenCode 内置 Agent(区别于用户自定义 Agent)

hidden

boolean

是否在 UI 中隐藏(辅助型 Agent 如 titlesummary 通常为 true

name 是 Agent 在整个系统中的索引键。当用户通过 @agent-name 语法或 Task 工具委托子任务时,都是通过 name 来引用特定的 Agent。

运行模式:mode

mode 字段决定了 Agent 可以在什么场景下被使用:

  • primary:主 Agent,只能作为会话的顶层 Agent 使用。用户直接与其交互。例如 build Agent 和 plan Agent。

  • subagent:子 Agent,只能被其他 Agent 通过 Task 工具调用。不能直接作为会话的主 Agent。例如 explore Agent 和 general Agent。

  • all:两种模式皆可。适用于用户自定义的 Agent——它们既可以作为主 Agent 使用,也可以被其他 Agent 委托。

这种分类体现了一个重要的架构约束:不是所有 Agent 都应该被用户直接操控。辅助型 Agent(如 compactiontitlesummary)被标记为 hidden 且其权限被严格限制,它们只为系统内部服务,不暴露给用户。

模型绑定

Agent 可以指定它使用的模型。如果未指定(optional),则使用系统的默认模型。model 字段由 providerID(如 "anthropic""openai")和 modelID(如 "claude-sonnet-4-20250514")两部分组成。

这种设计允许不同 Agent 使用不同的模型。例如在 oh-my-opencode 这样的插件中,主 Agent(Sisyphus)可能使用 Claude Opus 这样的高端模型进行复杂推理,而探索型 Agent(Explore)可能使用较便宜的模型来降低成本。

生成参数

衍生解释:Temperature 和 Top-P

这两个参数控制 LLM 生成文本时的"随机性":

  • Temperature(温度):值越高(如 1.0),生成的文本越多样、越有创造性;值越低(如 0.1),生成的文本越确定、越保守。在 Agent 场景中,代码生成通常使用较低的 temperature 以确保输出的确定性。

  • Top-P(核采样):从概率最高的 token 中选取,使得累积概率不超过 P 值。Top-P = 0.9 意味着只从概率总和达到 90% 的候选 token 中采样。

这两个参数通常二选一使用。OpenCode 的 title Agent 将 temperature 设为 0.5,在确定性和多样性之间取得平衡——既不总生成一模一样的标题,也不生成过于离谱的标题。

variant 字段是模型变体的概念。某些模型提供不同的变体(如思考深度、响应风格等),variant 允许 Agent 指定其偏好的变体。

权限规则集

这是 Agent 最关键的字段之一。每个 Agent 都携带一组权限规则(Ruleset),定义它可以使用哪些工具、可以访问哪些文件路径。权限系统的详细设计将在第 9 章展开,这里只需理解:Agent 的权限规则直接决定了它的行为边界

专属 Prompt

Agent 可以拥有自己专属的 System Prompt。当设置了 prompt 字段时,该 Prompt 将替代默认的 Provider Prompt(如 anthropic.txt),而非追加。这一设计让 Agent 可以拥有完全不同的"人格"。

例如,explore Agent 的 Prompt 是 prompt/explore.txt,将其定义为"文件搜索专家",与默认的 build Agent("全能编码助手")有着截然不同的行为特征。

步数限制

steps 限制了 Agent 在一次交互中可以执行的最大迭代步数。在 Agentic Loop 中,每一次"工具调用 → 执行 → 返回结果 → 继续对话"算一步。当达到步数限制时,系统会注入一段强制性提示(max-steps.txt),要求 Agent 停止使用工具并以纯文本总结当前进展。

这是一种防护机制——防止 Agent 陷入无限循环或消耗过多资源。与 Doom Loop 检测(重复失败检测)不同,steps 是绝对上限,无论 Agent 是否在"有意义地"工作。

Provider 特定选项

options 是一个开放式的键值对,用于传递 Provider 特定的选项。例如,某些 Provider 可能支持特殊的推理模式或安全设置,这些设置无法通过标准字段表达,就通过 options 传递。在 LLM 调用时,这些 options 会被层层合并:

视觉属性

color 字段用于 TUI 中的视觉区分。当用户切换不同 Agent 时,界面会使用对应的颜色标识当前活跃的 Agent。支持 HEX 颜色码(如 #FF5733)或主题颜色名(如 "primary""accent")。

6.1.2 Instance.state() 模式下的 Agent 初始化

Agent 的实例化使用了我们在第 3 章介绍过的 Instance.state() 模式:

这段代码的关键特征是:

  1. 延迟初始化Instance.state() 接受一个异步工厂函数,只在第一次调用 state() 时执行。

  2. 项目隔离:每个项目实例拥有独立的 Agent 注册表,不同项目可以有不同的 Agent 配置。

  3. 缓存语义:初始化结果被缓存,后续调用直接返回缓存值,避免重复计算。

6.1.3 Agent 的公共 API

Agent 模块对外暴露三个核心函数:

defaultAgent() 的实现揭示了几个重要的约束:

  • 默认 Agent 不能是 subagent 模式的 Agent。

  • 默认 Agent 不能是 hidden 的 Agent。

  • 如果用户没有指定 default_agent,系统会选择第一个非 subagent、非 hidden 的 Agent(通常是 build)。

这些约束确保了用户在启动 OpenCode 时,总有一个合适的主 Agent 可用。

6.1.4 Agent 与 Session 的关系

理解 Agent 数据模型,还需要理解它与 Session(会话)的关系。在 OpenCode 中:

  • 一个 Session 只能绑定一个 Agent——在创建 Session 时指定。

  • 子会话继承父会话的 Agent 配置——当 Task 工具创建子会话时,可以指定不同的 Agent。

  • Agent 决定了 Session 的行为特征——包括使用什么 System Prompt、拥有什么权限、使用什么模型。

这种"Agent-Session 绑定"的设计,使得多 Agent 协作成为可能:主 Session 使用 build Agent,而通过 Task 工具派生的子 Session 可以使用 exploregeneral 等子 Agent,每个子 Agent 都有自己独立的行为边界和能力范围。


本节建立了对 Agent 数据模型的全面理解。下一节,我们将聚焦于 OpenCode 最重要的内置 Agent——build,深入分析它的权限配置和行为设计。

Last updated