7.3 模型元数据系统

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


每个 LLM 模型都有自己独特的能力特征——不同的上下文窗口大小、不同的输入输出能力(是否支持图片、音频)、不同的价格和不同的推理能力。OpenCode 通过 Provider.Model 数据模型统一管理这些元数据,为上层系统(如 Compaction、权限控制、UI 展示)提供决策依据。

7.3.1 Provider.Model 类型定义

export const Model = z.object({
  id: z.string(),                    // 模型 ID(如 "claude-sonnet-4-20250514")
  providerID: z.string(),            // 所属 Provider
  api: z.object({
    id: z.string(),                  // API 调用时使用的模型 ID
    url: z.string(),                 // API 端点 URL
    npm: z.string(),                 // SDK npm 包名
  }),
  name: z.string(),                  // 模型显示名称
  family: z.string().optional(),     // 模型系列(如 "claude-3")
  capabilities: z.object({
    temperature: z.boolean(),        // 是否支持 temperature 参数
    reasoning: z.boolean(),          // 是否具有推理能力
    attachment: z.boolean(),         // 是否支持文件附件
    toolcall: z.boolean(),           // 是否支持工具调用
    input: z.object({                // 输入模态支持
      text: z.boolean(),
      audio: z.boolean(),
      image: z.boolean(),
      video: z.boolean(),
      pdf: z.boolean(),
    }),
    output: z.object({               // 输出模态支持
      text: z.boolean(),
      audio: z.boolean(),
      image: z.boolean(),
      video: z.boolean(),
      pdf: z.boolean(),
    }),
    interleaved: z.union([           // 交错思考链支持
      z.boolean(),
      z.object({ field: z.enum(["reasoning_content", "reasoning_details"]) }),
    ]),
  }),
  cost: z.object({                   // 定价信息(每百万 token)
    input: z.number(),
    output: z.number(),
    cache: z.object({
      read: z.number(),
      write: z.number(),
    }),
    experimentalOver200K: z.object({ /* 超过 200K 上下文的定价 */ }).optional(),
  }),
  limit: z.object({                  // 限制
    context: z.number(),             // 上下文窗口大小
    input: z.number().optional(),    // 最大输入 token 数
    output: z.number(),              // 最大输出 token 数
  }),
  status: z.enum(["alpha", "beta", "deprecated", "active"]),
  options: z.record(z.string(), z.any()),
  headers: z.record(z.string(), z.string()),
  release_date: z.string(),
  variants: z.record(z.string(), z.record(z.string(), z.any())).optional(),
})

能力系统的设计

capabilities 字段构成了模型的能力矩阵。这些布尔标志在系统的多个层面被使用:

能力
使用场景

temperature

LLM 调用时是否传递 temperature 参数

reasoning

是否显示思考链 UI、是否启用变体选择

toolcall

是否可以作为 Agent 使用(不支持工具调用的模型无法执行 Agentic Loop)

input.image

是否允许用户发送图片附件

input.pdf

是否允许用户发送 PDF 文件

interleaved

处理交错思考链的方式

interleaved 字段值得特别注意。它有三种可能的值:

  • true:模型原生支持交错思考链(思考内容和文本内容交替出现)。

  • false:不支持交错思考链。

  • { field: "reasoning_content" }:模型通过特殊字段返回思考内容,需要在消息处理中进行格式转换。

价格信息的用途

cost 字段不仅用于 UI 展示,还影响系统行为:

7.3.2 models.dev 集成

OpenCode 的模型数据库来自 models.devarrow-up-right——一个集中化的 LLM 模型信息服务:

衍生解释:lazy() 模式

lazy() 是一种延迟计算模式——函数体只在第一次调用时执行,结果被缓存供后续使用。这与 Instance.state() 类似,但不依赖项目实例上下文。这种模式特别适合"加载一次、全局共享"的数据。

models.dev 的数据从 ModelsDev.Model 格式转换为 Provider.Model 格式:

模型搜索

OpenCode 使用 fuzzysort 库进行模型的模糊搜索:

当用户输入的模型名有拼写错误时,系统会提供最接近的模型建议,提升用户体验。

7.3.3 Small Model 选择

许多辅助操作(如标题生成、摘要生成)不需要使用昂贵的大模型。OpenCode 通过 getSmallModel() 自动选择同一 Provider 下的小型模型:

小型模型的选择策略体现了几个考虑:

  1. 同 Provider 优先:优先使用与主模型相同的 Provider,避免额外的 API Key 配置。

  2. 成本意识:GitHub Copilot 用户优先使用免费模型(gpt-5-mini)。

  3. 兜底策略:如果找不到合适的小模型,使用 OpenCode 免费提供的 gpt-5-nano

7.3.4 模型变体(Variants)

衍生解释:什么是模型变体?

许多现代 LLM 支持"推理模式"——模型可以在回答前进行更深入的思考。不同 Provider 用不同的方式控制这个功能:OpenAI 使用 reasoningEffort,Anthropic 使用 thinking.budgetTokens,Google 使用 thinkingConfig

OpenCode 将这些差异统一抽象为"变体"(Variants)——同一个模型的不同运行配置。例如 Claude Sonnet 的 high 变体会启用 16000 token 的思考预算,max 变体则使用最大思考预算。

变体的生成由 ProviderTransform.variants() 函数自动完成:

变体系统使得用户可以通过简单的名称(如 "high")来控制复杂的 Provider 特定参数,而无需了解每个 Provider 的 API 细节。在 Agent 配置中,可以通过 variant 字段指定默认使用的变体。


下一节将分析 ProviderTransform 模块——OpenCode 如何处理不同 Provider 之间的消息格式差异、输出 token 限制和 Schema 适配。

Last updated