03 三方配置合并去重


文档摘要

03 三方配置合并去重 本节摘要:上一节讲 OpenWork 用「服务端管理的配置文件」注入,但现实里用户可能也有自己的引擎配置,甚至可能有 legacy(老格式)配置。三方配置凑在一起,怎么合并?OpenCode 的解法是三方配置合并去重:legacy 配置、用户配置、服务端管理配置按规则叠加,冲突时按优先级解决,重复项去重。本节讲清这套合并:三方分别是什么、合并优先级、为什么必须去重。

03 三方配置合并去重

本节摘要:上一节讲 OpenWork 用「服务端管理的配置文件」注入,但现实里用户可能也有自己的引擎配置,甚至可能有 legacy(老格式)配置。三方配置凑在一起,怎么合并?OpenCode 的解法是三方配置合并去重:legacy 配置、用户配置、服务端管理配置按规则叠加,冲突时按优先级解决,重复项去重。本节讲清这套合并:三方分别是什么、合并优先级、为什么必须去重。

一、为什么会有「三方」配置

先理清这三方配置分别是什么、从哪来:

配置方 来源 例子
legacy 配置 老格式的历史配置 早期 OpenWork 用的格式,现在兼容
用户配置 用户自己的引擎配置 用户直接用引擎时写的配置
服务端管理配置 OpenWork 注入的(第 02 节) OpenWork 想让引擎用的 Agent/插件/MCP/Provider

这三方都可能存在,引擎要把它们合并成一份最终生效的配置。这就是「三方合并」的来源。

💡 为什么有 legacy:软件演进过程中,配置格式会变。老用户可能有老格式的配置,OpenWork 不能强迫他们立刻迁移,所以要兼容(读 legacy 格式)。这是软件演进的常态代价。

二、合并优先级:谁覆盖谁

三方合并的核心问题是优先级——冲突时谁胜出。OpenWork 的合并大致遵循这样的优先级(具体以本地实现为准):

服务端管理配置(最高优先级) │ 冲突时覆盖 用户配置 │ 冲突时覆盖 legacy 配置(最低优先级)

也就是说:

  • 服务端管理配置优先级最高——OpenWork 注入的东西,用户配置不能轻易覆盖(否则 OpenWork 接管不了引擎)。
  • 用户配置居中——用户的自定义覆盖 legacy,但被服务端管理配置覆盖。
  • legacy 配置优先级最低——只是兼容性兜底。

这个优先级设计反映了一个权衡:OpenWork 要能接管引擎(服务端配置最高),但又尊重用户的合理自定义(用户配置覆盖 legacy)

⚠️ 注意:这个优先级不是「OpenWork 蛮横地覆盖一切」。服务端管理配置主要管「OpenWork 注入的能力」(Agent/插件/MCP/Provider),不会无端覆盖用户的其他配置。冲突主要发生在「同一项被多方定义」时。

三、合并的细节:按项合并

合并不是「整体替换」,而是按项合并。配置里有很多项(Agent 列表、插件列表、MCP 列表、Provider 设置......),每一项单独合并:

Agent 列表: legacy: [A] 用户: [B] 服务端: [C, D] ──► 合并后:[A, B, C, D](各自加进来) 某 Provider 设置: legacy: { url: X } 用户: { url: Y } 服务端: { url: Z } ──► 合并后:{ url: Z }(按优先级取最高的)

列表类(如 Agent 列表)通常是「合集」(都加进来),标量类(如某个 Provider 的 url)是「按优先级取一」。这种「按项、按类型」的合并,让三方能共存而不全盘互斥。

四、为什么必须去重

合并里有一个关键步骤——去重。为什么必须去重?考虑这个场景:

用户配置:[插件甲] 服务端管理配置:[插件甲(同一个,但 OpenWork 也注入了)] │ ▼ 不去重直接合并 [插件甲, 插件甲] ← 重复了! │ ▼ 引擎看到两个「插件甲」 报错或行为异常(引擎不允许同名重复)

所以合并必须去重——识别出「同一个东西被多方定义」,只保留一份(按优先级留最高那方)。去重的依据通常是名字或唯一标识:

合并后:[插件甲, 插件甲] │ ▼ 按名字去重(同名只留优先级最高的) [插件甲(服务端版,因为服务端优先级最高)]

💡 去重避免引擎报错:很多引擎不允许同名配置重复,不去重会直接启动失败。去重看似细节,实则是合并能成功的关键。

五、合并的复杂性来源

诚实地说,三方合并是第 5 章里最容易出 bug 的部分。复杂性来自:

  • 格式差异:legacy、用户、服务端三方可能格式不同,要先归一化再合并。
  • 合并规则多样:列表合、标量取、嵌套对象深合并......不同项规则不同。
  • 去重判断:什么算「同一个」(名字?ID?路径?),边界情况多。
  • 优先级交互:某项在多方都有,要精确判断谁覆盖谁。

这就是为什么 OpenWork 有专门的「运行时配置存储」模块来管这件事(下一节讲它的同步)。合并不是「拼一拼」那么简单,它是一个需要仔细设计的子系统。

六、合并的产物

合并的最终产物,是一份引擎实际生效的配置——它包含了三方的合力:legacy 的兼容兜底 + 用户的自定义 + OpenWork 的注入。引擎读到这份合并配置,就同时满足了「兼容老用户、尊重用户自定义、被 OpenWork 接管」三个目标。

legacy 配置 ─┐ 用户配置 ─┼─► 三方合并去重 ──► 引擎生效配置 服务端配置 ─┘

本节要点回顾

  1. 三方配置:legacy(老格式兼容)、用户(用户自定义)、服务端管理(OpenWork 注入)。
  2. 优先级:服务端 > 用户 > legacy,反映「能接管又尊重用户自定义」的权衡。
  3. 按项合并:列表类合集、标量类按优先级取——不是整体替换。
  4. 必须去重:按名字/ID 识别同一项,只留优先级最高的,避免引擎因同名重复报错。
  5. 合并易出 bug:格式差异、规则多样、去重边界——是第 5 章最复杂的部分。
  6. 产物:一份满足「兼容 + 自定义 + 接管」三目标的引擎生效配置。

合并产出了配置,但配置改了怎么让引擎知道?这就是下一节的「配置新鲜度同步」。


发布者: 作者: 灏天文库 转发
评论区 (0)
U