乐于分享
好东西不私藏

自举时代,让OpenCode的插件学会配置自己

自举时代,让OpenCode的插件学会配置自己

opencode-models-discovery 最初解决的是一个很具体的问题:OpenCode 接入 LM Studio、Ollama、LiteLLM、OpenRouter 或各种 OpenAI-compatible provider 时,模型列表变化太快,手写 `models` 配置很容易过期。

所以插件做了一件简单但高频的事:启动 OpenCode 时,从 provider 的模型接口读取模型列表,再把发现到的模型注入到 OpenCode 的 provider 配置里。

但走到 v0.12,这个插件遇到的问题已经不只是“如何发现模型”。真正摆在面前的是:当插件自己的配置机制变复杂后,它能不能帮助用户理解和维护这些配置?

这就是 v0.12 的转折点。

v0.12 原本只是兼容提醒版本

v0.12 的原始定位并不激进。

它原本只是 v1.0 之前的兼容提醒版本。

一路走来,插件增加了很多能力:provider-level 控制、正则过滤、自定义 endpoint、LiteLLM 元数据、models.dev 补全、/connect 凭据支持。

能力变多之后,配置模型也不可避免地积累了一些历史包袱。

其中最典型的,就是 plugin-level 全局 discovery 配置。

早期全局配置是合理的。那时插件还更像一个统一的“发现开关”:启用 discovery、过滤 provider、过滤模型。用一个全局配置控制所有 Provider,简单直接。

但当 Provider 数量变多之后,这个边界开始变得不自然。

不同 Provider 可能有不同的 models endpoint,不同的模型过滤规则,不同的 metadata 来源,不同的认证方式。此时 discovery 规则更应该贴近 Provider 自身,而不是散落在插件全局配置里。

所以 v1.0 会淘汰 plugin-level 全局配置,把配置边界收敛到:

provider.<name>.options.modelsDiscovery

对应地,v0.12 需要承担两个职责:

- 提醒用户旧配置即将废弃。

- 帮助用户把旧配置迁移到新的 provider-level 配置模型。

原计划:写一个程序自动迁移

一开始,我设想的是写一个单纯的程序来完成配置迁移。

它大概会这样工作:

  • 检测旧的 plugin-level 配置。

  • 找到 `opencode.json`。

  • 生成 JSON patch。

  • 把 对应的配置 等字段移动到Provider 的 option 配置。

这看起来很直接。

但开发越深入,这个方案的问题越明显。

OpenCode 配置并不总是只有一个文件。它可能来自:

  • 项目根目录的 opencode.json 或 opencode.jsonc

  • 也可能来自 .opencode/opencode.json

  • 用户全局配置

  • OPENCODE_CONFIG环境变量

  • 甚至还有 managed 或 organization-controlled config。

更复杂的是,迁移不只是字段搬运,还涉及语义判断:

  • 旧的 providers.include 应该如何等价迁移?

  • 已有 provider-level option 能不能覆盖?

  • 用户的注释和 JSONC 格式要不要保留?

  • 某些配置文件是不是根本不应该动?

  • 如果 Provider 不在当前可编辑配置里,应该猜测还是停止?

如果把这些情况全部硬编码进插件,迁移工具会越来越像一个脆弱的配置编辑器。

这并不是一个好方向。

后来我意识到:这是一个非常适合自举的场景

随着对 LLM 应用理解得更深入,我发现配置迁移其实并不一定要由插件自己硬编码完成。

插件可以自描述

它可以告诉 OpenCode 和 LLM:

  • 我的旧配置字段有哪些。

  • 我的新配置边界是什么。

  • 哪些配置文件应该检查。

  • 哪些 managed config 不应该直接修改。

  • 迁移时哪些字段可以移动,哪些已有字段不能覆盖。

  • 如果不能安全迁移,应该向用户解释阻塞点,而不是强行修改。

然后,由 OpenCode 中的 LLM assistant 在真实项目上下文里完成配置迁移。

换句话说,插件不再只是运行一段固定逻辑,而是把“如何配置自己”描述给 LLM,让 OpenCode 与 LLM 相互驱动来完成本插件的配置。

这就是“LLM 的自举配置”。

v0.12 做了什么

v0.12 最终没有内置一个强行改文件的迁移器,而是引入了两个 helper commands:

/models-discovery:config

/models-discovery:migrate

/models-discovery:config 会在插件加载时注入,用于日常配置。

当用户想设置 provider-level discovery、开启 metadata enrichment、为某个 provider 禁用 discovery,或者检查当前配置是否合理时,可以使用这个命令。

它会引导LLM assistant 使用 OpenCode 的 customize-opencode skill,检查项目配置、用户全局配置和 OPENCODE_CONFIG环境变量,再根据用户意图修改配置。

/models-discovery:migrate 只在检测到存在plugin-level 全局配置选项时注入。

它的目标是迁移旧配置,而不是简单字符串替换。它会引导 assistant 理解当前 OpenCode 的配置上下文,理解 opencode-models-discovery 插件的配置规则,如果还有plugin-level 的配置,则与用户交互,确认用户的意图,执行相关迁移。

同时,v0.12 仍然保持兼容:旧的 plugin-level 全局配置 在 0.12.x 中继续工作,只是会收到 warning、toast 和迁移入口。

这很重要。过渡版本不应该突然破坏用户配置。

这不是简单的“加两个命令”

表面看,v0.12 只是多了两个 command。

但背后的理念变化更大。

过去插件的能力是:我帮你发现模型。

现在插件开始具备另一种能力:

  1. 你需要配置插件,那我来帮你;

  2. 我发现你正在使用即将废弃的配置方式,我会告诉你风险,并给你一个由 assistant 执行的迁移入口。

这和传统 CLI 工具的 migration command 不一样。

传统 migration command 往往假设配置文件格式固定、位置固定、语义固定,一经上线,逻辑固定。

我们现在放弃这种形式,让 opencode 背后的 LLM 协助最终用户,按用户的意愿以及插件的运行规则,来实现配置。

所以 v0.12. 的选择是:

  • 插件负责检测 deprecated config。

  • 插件负责发出 warning 和 toast。

  • 插件负责注入 migration/config helper command。

  • LLM assistant 负责在用户授权和上下文中完成实际编辑。

这是一个更符合 OpenCode 这种 LLM 生态工具的迁移方式。

自举不只用于迁移

迁移只是第一个场景。

一旦插件可以用自描述的方式告诉 LLM “我应该如何被配置”,日常配置也可以进入同一个流程。

比如:

  • 给 LM Studio 开启 discovery。

  • 给 DeepSeek 指定非标准 `/models` endpoint。

  • 给 LiteLLM 配置 modelInfoEndpoint和modelInfoFormat。

  • 给 CLI Proxy 开启 modelInfoFormat: "models.dev"。

  • 给某个 provider 禁用 models 发现。

  • 检查旧配置是否还存在。

  • 解释为什么配置改完后需要重启 OpenCode。

这意味着配置不再只是用户读文档、手动复制 JSON。

插件可以把自己的配置知识带进 OpenCode,让 LLM 在上下文中协助用户完成配置。

写给 v1.0 之前

v0.12 是过渡版本,不是终点。

在 0.12.x 中,旧的 plugin-level discovery config 仍然继续工作。

但 v1.0 会确立新的配置边界:

  • plugin-level global discovery config 将被移除。

  • discovery 默认仍然保持启用,除非某个 provider 显式禁用。

  • 单个 provider 使用modelsDiscovery.enabled = false 禁用 discovery。

  • 后续计划支持用环境变量配置,让未显式配置的 provider 默认不启用 discovery。

v1.0 的目标不是让配置更复杂,而是让配置边界更自然。

OpenCode Provider 决定 provider 是什么,modelsDiscovery 决定这个 provider 如何发现模型。

而我们通过 v0.12实现配置自举的意义在于,它没有把迁移压力全部丢给用户,也没有让插件变成一个脆弱的配置重写器。

它选择了第三条路:让配置从“用户独自读文档”,变成“插件、OpenCode 和 LLM 一起协作”。

这也是我认为 v0.12 是走向 v1.0 前最重要版本的原因。它把下一阶段的方向提前暴露出来:

未来的软件,不只是运行代码,也会帮助用户理解和维护自己、改进自己。

AI LLM 时代的软件,理应具备自我表达能力。

点击“阅读原文”, 查看Release Note