docs(agent-specs): 配置控制面阶段二 yudao配置中心 设计成稿(创始人已拍 B)——双评审已回(Codex 2B+5M/Opus 0B+2M+4m),先落基线版便于修订对照

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
lili 2026-07-02 20:52:42 -07:00
parent 0daa5e5011
commit d4471b02fc

View File

@ -0,0 +1,259 @@
---
date: 2026-07-02
topic: 配置控制面-阶段二
status: 草稿 · 创始人已拍方向 B(维持 yudao⊕Nacos;prompt 移出 Nacos→MySQL 版本行,2026-07-02)· 待 Codex+Opus 双评审 → 创始人评审
sot-impact: 修订 生成引擎运行时(SoT §5.2 管理面配置管理 / §5.8 配置三类"受治理发版" / ADR-4 配置热取 / A13 配置注册表:把 GitOps/Langfuse 式口径收敛为 yudao 配置中心版本化(版本账本落 MySQL 版本行)+ 双路激活,与上级设计 §6 pending 同一收口面,收口时回写;对上级设计两处口径的回调挂账见本档 §7)
上级: docs/agent-specs/2026-06-30-配置控制面一次性按序实现-设计.md
关联:
- 阶段前置(已落地):阶段〇 生产基建(Nacos 2.4.3 / RocketMQ 5.3.1 / Sentinel 自托管 mini-infra + game-cloud 接入,`docs/plans/2026-07-01-配置控制面-spike与阶段〇生产基建-plan.md`)· 阶段一① 护城河 middleware(`07100eef`)· 阶段一② cheap-worker 归并 Service `/chat`(`526e9b3d`)
- tier2/gen-worker/worker/genconfig.py(进程内配置门面 `get(area,key,default)`,现读本地 `tier2/config/generation.yaml`;本阶段把其读取后端提升到 Nacos)
- tier2/gen-worker/worker/nacos_hotconfig.py(阶段〇 D2 已建、未接线;本阶段接进 genconfig 作热源)
- tier2/gen-worker/worker/middleware.py:173(CircuitBreakerMiddleware 软预算,预算/阈值经 genconfig 读)· worker/gate_judge.py(门判 GateJudgment)
- tier2/gen-worker/worker/store.py(MySQL manifest + MinIO 源文件的成品归档 —— MinIO 在本项目的既有角色参照,§3.1 prompt 存储选型佐证)· cheap-worker/cheap_roles.py ≈30KB / tier2 worker/roles.py ≈24KB(prompt 尺寸画像依据)
- cheap-worker/cheap_service_app.py:213(`_cheap_middlewares_factory` 每回合工厂)· :300(`build_cheap_app`)
- tier2/gen-worker/service/app.py(AgentScope Service `/chat` + `/agent` + `/session`)
- agentscope==2.0.2:app/_router/_agent.py:138(`update_agent` PATCH)· app/_router/_session.py:291(`update_session` PATCH,部分字段更新语义)
- game-cloud huijing-module-bpm(审批,放量后)· huijing-module-system(操作日志 + 权限,yudao 原生)· game-module-aigc(生成配置治理落点)· huijing-module-infra(Nacos SCA 通路 + infra_config KV 参照)
- game-admin/src/views/wanxiang(配置编辑面,阶段三消费)
- commit hash:待收口填
图清单: [图0 一图看懂, 图1 分工边界与四方职责, 图2 配置生命周期与双路激活, 图3 失败模式与兜底]
---
# 配置控制面 · 阶段二:yudao 配置中心 · 功能设计
## 0 一图看懂
(图0 概览 SVG 待补)
- **核心思想**:阶段一已经让生成配置能热改——prompt/模型/参数经 `/agent`+`/session` 由 AgentScope 每 POST 现装配、下一次生成即生效,预算/门阈值经 genconfig 从本地 YAML 热取。但热改缺一层治理:改动没有版本历史、没有归因、不能一键回滚、没有激活闸。阶段二在这层热配之上补一个**版本化治理层**:创始人在 game-cloud 的 yudao 侧编辑一组生成配置,走"改 → 定版 → 审核挂点 → 激活",激活时**双路下发**——prompt/模型/参数这一路 PATCH 进 AgentScope Service(写它的 Redis,下一次 POST 现装配即生效),预算/门阈值这一路 publish 进 Nacos、由 worker 的 genconfig 经 Nacos 热读投影。版本历史、回滚、diff 落 yudao 侧的 MySQL 版本行(prompt 正文随行存 `MEDIUMTEXT`、**不进 Nacos**——Nacos 单配置默认上限 100KB,扛不住会长大的 prompt,创始人已拍);Nacos 收窄为预算/门阈值那一路的生效下发通道;鉴权、creator 归属、审计、审批全部复用 yudao 原生。
- **边界**:管**业务生成配置**的版本化治理(prompt/context/max_iters/模型/参数/预算/门阈值);**基建配置**(game-cloud 的 Spring 配置、Sentinel 流控规则、RocketMQ 参数)不进本治理层——那条是阶段〇已接的 Nacos SCA 原生通路,运维改、即时热生效。BPM 审批**放量后启用**(架构预留挂点,MVP 由创始人本人直接激活);配置编辑 UI 属阶段三;观测属阶段四;机制级激活原子性留放量后(MVP 取静默期语义)。
- **成功**:本会话手改过的每个旋钮(模型 M3↔glm-5.2、预算 ¥10↔¥49、max_tokens、prompt)都能在配置中心改一版、激活、下一次生成即生效、一键回滚,并可查谁在何时改了什么、diff 是什么;一组协同旋钮作一个配置集一次激活;激活失败、Service 不可达、配置漂移都有明确兜底。
## 1 意图与目标
### 1.1 意图
配置控制面这条线的痛点在上级设计里已经讲透:本会话调一款便宜档游戏,四个旋钮里三个要改代码重启,而且是在 live worktree 上 SSH 手敲。阶段〇到阶段一②把"能不能热改"这半解决了——生产基建三件套自托管进 mini-infra,护城河续修/软预算/门判做成 AgentScope 洋葱里的 middleware,cheap 与 tier2 两档都归并到同一套 Service `/chat`,prompt/模型/参数经 `/agent`+`/session` 每 POST 现装配、预算/门阈值经 genconfig 从 `generation.yaml` 热取。
剩下的是"改动能不能管"这半。今天改一个旋钮,要么直接 PATCH Service、要么 scp 一份新的 `generation.yaml` 上去,两条路都没有版本账本:改错了没有上一版可回滚,改过了查不出是谁在什么时候改的、和上一版差在哪,更没有一个"激活"的闸把"编辑中"和"已生效"分开。放量后这些配置要过审批才能上生产,现在连挂审批的地方都没有。阶段二就是把这层治理补上,让配置从"能热改的散落旋钮"变成"可版本、可回滚、可归因、可审批的受治理资产"。
还有一个阶段〇留下的 follow-up 一直悬着:`nacos_hotconfig.py` 在阶段〇 D2 已经写好并单测绿了,但没有接进任何 middleware——预算/门阈值现在还是 genconfig 从本地文件读。这条线不接上,配置中心对预算/阈值那一路的"激活"就落不了地。阶段二把它接上,让这些参数真正从 Nacos 热读,从"本地文件热取"升级为"配置中心版本化 + 集中热推"。
### 1.2 目标
- **配置即数据、版本可管**:每一组生成配置进配置中心,能改一版、激活、回滚、看 diff,逐项覆盖本会话手改过的全部硬编码点。
- **改动可审计、归因到人**:编辑者即 yudao 登录用户、落进 `creator`,写操作受权限门约束,每次改动与激活随版本可查,审计复用 yudao 原生操作日志。
- **双路激活、以激活版为权威**:prompt/模型/参数经 PATCH、预算/门阈值经 Nacos 热读,两路由同一个激活编排统一驱动;配置中心记"当前激活版"为权威,Service 与 worker 是它的生效投影。
- **NacosHotConfig 接线落地**:genconfig 的读取后端从本地 `generation.yaml` 提升到 Nacos(NacosHotConfig 作热源、本地 YAML 与内置默认作回落),middleware 的调用面一行不改。
- **分工边界清晰**:基建配置走 Nacos SCA 原生通路、不经本治理层;业务生成配置以 yudao 为治理与版本账本、只以 Nacos 作路 B 生效下发;两者在 Nacos 上以命名空间/分组隔离。
- **失败模式有兜底**:激活是一批非原子写,须幂等、失败即整批判未生效可重试;Service 不可达时保留上一激活版;配置漂移可检测并一键重推。
## 2 边界
(图1 分工边界 SVG 待补)
进控制面的判据沿用 SoT §5.8 的配置三类;本阶段只碰其中"热配置策略类"里属于**生成业务**的那部分,并给它加治理。
| | 进阶段二 | 不进 |
|---|---|---|
| **业务生成配置**(受治理版本化) | prompt / system_prompt、压缩比例、tool_result 截断、max_iters、模型、协议 type、credential 引用、max_tokens、thinking、reasoning_effort、temperature、软预算目标、门阈值档 | — |
| **基建配置** | — | game-cloud Spring 配置、Sentinel 流控规则、RocketMQ 参数、服务发现——阶段〇已接 Nacos SCA 原生通路,运维改、即时热生效 |
| **硬代码机制类** | — | 门断言逻辑、熔断机制本体、续修机制、基线硬门强制、那几条铁律 |
几条明确的划界:
- **BPM 审批放量后启用**。上级设计已定:放量前创作页置灰、配置改动者是创始人本人、属非关键即时改。所以阶段二把审核落成状态机里的一个挂点(见 §3.2),放量前创始人角色从"草稿"直接到"激活"、审批自动通过;放量后打开 `huijing-module-bpm` 审批流,同一状态机不改。**不在本阶段验证真实审批流**。
- **配置编辑 UI 属阶段三**。阶段二只交付后端治理层、版本化、激活编排与 NacosHotConfig 接线;编辑表单由阶段三在 game-admin 落地,消费 AgentScope 的 `/agent/schema`。
- **观测属阶段四**(Studio + genMonitor)。
- **机制级激活原子性留放量后**。一个配置集的多次 PATCH/publish 机制上非原子,MVP 取静默期语义规避(单操作者 + 创作页置灰,blast radius 小);真机制级原子(epoch 戳)留放量后。这条沿用上级 §3.3,不在本阶段重推。
## 3 方案
### 3.1 配置中心的两半:yudao 治理与版本账本 ⊕ Nacos 生效下发
配置中心把职责劈成两半,各用现货、不自建机器。**yudao 管治理与版本账本**:编辑的鉴权、`creator` 归因、放量后的 BPM 审批、激活状态机、操作审计,连同每次定版落下的版本行——权限、审计、CRUD 全是 yudao 作为成熟后台框架的原生件,game-cloud 是它的 fork,拿来即用。**Nacos 管生效下发**:长轮询推送、客户端磁盘快照兜底、命名空间隔离——这些是 Nacos 打磨多年的下发机器,阶段〇已自托管进 mini-infra,预算/门阈值那一路的热推全靠它(路 B,见 §3.3)。
版本账本落 MySQL 而不落 Nacos,被三个事实定死,第一个就是创始人拍 B 时点名要解的:
- **prompt 正文放不进 Nacos**。Nacos 单配置内容默认上限 100KB(容量保护 `defaultMaxSize`),而本仓一个角色的 prompt 源就有几十 KB(`cheap_roles.py` ≈30KB、tier2 `roles.py` ≈24KB),配置集版本再带 few-shot 与参数,内容会向上限爬。把最大、改得最勤的旋钮放在一条 100KB 的钢丝上,不如一开始就换地方。
- **定版要原子**。版本行(元数据 + 全量内容)同库同事务一次落;内容若在库外,定版就成了跨系统写,要补超时/重试/补偿——治理层最高频的动作不该是分布式事务。而 prompt 一旦出 Nacos,版本若劈成"prompt 在 MySQL、小参在 Nacos"两处,一次定版跨两系统、必漂移,所以账本整体落 MySQL。
- **diff 与检索要就地**。版本 diff、按内容查历史都是版本行上的本地操作;内容在外部系统则每次 diff 都要来回取对象。
**prompt 内容列定 MySQL `MEDIUMTEXT`,不选 MinIO**——在此定死、不留开放项。MinIO 在本项目的既有角色是成品源工程归档(`store.py`:MySQL manifest + MinIO 源文件、内容哈希、id+version 寻址),那是"多文件源树"的形状;prompt 是"一段文本字段"的形状,几 KB 到几十 KB,MinIO 的价值(大对象、二进制、流式)一样都用不上,却把定版原子性与就地 diff 全破掉,还把备份从"一份 MySQL dump = 治理+内容一致快照"劈成两个系统。列型取 `MEDIUMTEXT`(16MB)而非 `TEXT`(64KB):30KB 级 prompt 加 few-shot 有越过 64KB 的现实可能,MEDIUMTEXT 给足余量且无额外成本。
对上级设计"自建版本表 = 重造 Nacos"的判定要诚实交代:那条针对的是**版本化下发机器**(推送/快照/回滚/灰度),这部分仍然全买——路 B 热推是 Nacos、基建配置通路是 Nacos SCA;挪回 MySQL 的只是**版本行**这张普通 yudao 业务表,借的全是 yudao CRUD/分页/审计原生能力,没有一行自建机器。此口径回调上级 §3.3 等处,挂账见 §7。
于是四方各就各位:
- **yudao(game-cloud)**:配置集元数据 + 版本行(全量内容含 prompt,`MEDIUMTEXT`)+ 当前激活版指针 + creator + 状态机 + 审批挂点 + 操作审计 + 激活编排。治理与账本权威。
- **Nacos**:路 B 生效下发通道——激活时 publish 预算/门阈值到生效 dataId,worker 长轮询热读;**不再承版本账本**(生效 dataId 上的配置历史只是运维排障的顺带留痕,不是权威)。
- **AgentScope Service 的 Redis**:路 A(prompt/模型/参数)生效投影(激活时 PATCH 写入,每 POST 现装配读出;Service 只认自己的 Redis、不认 Nacos,所以路 A 生效只能靠 PATCH)。
- **worker 进程内 genconfig**:路 B 生效投影(经 NacosHotConfig 从 Nacos 热读)。
账本单点(MySQL 版本行)、投影两处(Redis / Nacos 生效 dataId)、消费两路(Service per-POST / middleware 构造)——权威与投影的关系一眼可查,§3.6 的漂移对账就建在这上面。
### 3.2 配置对象与生命周期:改 → 版本 → 审核 → 激活 → 回滚
治理的单元是**配置集**,不是单个旋钮。一款档位的生成行为由一组协同旋钮共同决定——便宜档配置集 = 便宜档 agent 的 system_prompt + M3 模型 + 参数(max_tokens/thinking)+ 软预算目标 + 门阈值;tier2 富游戏配置集 = tier2 agent 的 prompt + glm-5.2 + 参数 + 预算 + 门阈值。以配置集为激活单元,才能让一组本该一起变的旋钮一次激活、不出现"新 prompt 配旧模型"的半拉子状态。
一个配置集走这样一条生命周期:
```mermaid
stateDiagram-v2
[*] --> 草稿: 创始人在 yudao 编辑一组旋钮
草稿 --> 待审: 定版(版本行落库,creator/时间随行)
待审 --> 已激活: 审核通过(MVP 创始人角色直接激活 · 放量后走 BPM 审批)
已激活 --> 待审: 编辑出新版本
已激活 --> 已激活: 回滚(取历史版本行,重放激活)
已激活 --> 已归档: 被更新版本取代
待审 --> 草稿: 驳回
```
几个关键点。**激活之前 Nacos 完全不被触碰**:草稿与版本行都是 yudao 库内数据,配置内容到"激活"才第一次离开治理库——这天然堵死了"草稿提前生效"的口子(Nacos 的配置是 publish 即被监听者读到的,预算/阈值若提前进 Nacos 就绕过了激活闸)。**激活是独立的闸**:它把选定版本的内容双路下发(见 §3.3),并把"当前激活版指针"指过去。**回滚就是重放激活**:取历史版本行的内容,走一遍激活动作,幂等。**归因与审计随生命周期自然沉淀**:定版记 creator 与时间,激活/回滚是一条 yudao 操作日志,diff 是两条版本行的就地比对——全是 yudao 原生能力,不新造。
### 3.3 双路激活:PATCH 路 ⊕ Nacos 热读路
(图2 配置生命周期与双路激活 SVG 待补)
激活一个配置集,编排层从选定的版本行取内容,按旋钮性质分两路下发:
```mermaid
flowchart LR
ACT["yudao 激活编排<br/>(取选定版内容)"]
ACT -- "路A:prompt/context/max_iters" --> PA["PATCH /agent"]
ACT -- "路A:模型/参数/thinking/temp" --> PS["PATCH /session"]
PA & PS --> REDIS[("AgentScope Redis<br/>当前配置")]
REDIS -- "每 POST 现装配(热)" --> GEN["/chat 生成回合"]
ACT -- "路B:软预算目标/门阈值" --> PUB["publish Nacos 生效 dataId"]
PUB --> HC["worker NacosHotConfig<br/>长轮询推送热读"]
HC --> GENC["genconfig 门面"]
GENC -- "middleware 构造时读" --> GEN
ACT -- "记当前激活版 + 操作日志" --> YU[("yudao 治理表")]
```
- **路 A(prompt/模型/参数)**:激活编排把内容 PATCH 进 AgentScope Service 的 `/agent`(system_prompt / 压缩比例 / tool_result 截断 / max_iters)与 `/session`(模型 / 协议 type / credential / max_tokens / thinking / reasoning_effort / temperature)。`/session` 的 PATCH 是部分字段更新语义,只改本次带上的字段。写进 Service 的 Redis 后,下一个 POST `/chat` 现装配即生效。
- **路 B(软预算目标 / 门阈值)**:这些参数不在 `/agent`+`/session` 里,它们是 worker 的 middleware 在构造时从 genconfig 读的。激活编排把内容 publish 进 worker 监听的 Nacos 生效 dataId,NacosHotConfig 经长轮询推送热读进进程内,genconfig 从它取到新值,下一次 middleware 构造时读到。
**为什么静默期语义在这个模型下几乎是自然的**:两路生效都发生在"下一次生成"的边界上——路 A 的 Redis 在 `/chat` 进 session 锁之前读、路 B 的 genconfig 在 middleware 构造时读,正在跑的那一局早已经读过配置了,新配置只影响此后新起的 POST。所以真正的撕裂窗口只剩一个:一个配置集的多次 PATCH/publish 之间非原子,理论上并发一局能读到"路 A 新、路 B 旧"的组合。MVP 单操作者 + 创作页置灰把这个窗口的影响面压到零,取静默期语义即可;真机制级原子留放量后(上级 §3.3)。激活编排对此的硬要求是:一批下发须**幂等**、**失败即整批判未生效可重试**、不留半生效态(见 §3.6 失败模式)。
### 3.4 NacosHotConfig 接进 genconfig(阶段〇 follow-up 落地)
预算/门阈值那一路的热读,是把 `nacos_hotconfig.py` 接进既有的 genconfig 门面,而不是改 middleware。现状链条是 `middleware → genconfig.get("budget", "rmb_hard_limit") → generation.yaml`;genconfig 已经是一个带缓存、带 best-effort 兜底、带内置默认的成熟门面,middleware 到处在调它。阶段二只换 genconfig 的**读取后端**:让它优先读 NacosHotConfig(配置中心激活投影),读不到回落本地 `generation.yaml`,再回落内置默认。
这样接线有三处好处。其一,**middleware 一行不改**:`genconfig.get(...)` 的调用面完全不动,CircuitBreakerMiddleware 的软预算目标、门判的阈值都自动吃上 Nacos 热读。其二,**回落链天然是 fail-safe**:Nacos 不可达时 NacosHotConfig 自带本地磁盘快照兜底,再不行 genconfig 回落本地 YAML 与内置默认,生成主链不被配置中心连累。其三,**尊重既有 working code**:genconfig 是雏形阶段就在的进程内配置层(SoT §5.2 提到的那个雏形),阶段二是把它的源从本地文件提升到集中版本化,不是推翻重造。
命名空间上有一个已知的坑必须钉死:**Nacos 默认公共空间的 namespaceId 是空串,不是字面量 "public"**(阶段〇 follow-up 明确)。业务生成配置的 dataId 要么显式放进一个专门的命名空间(用真实 namespaceId、不是 "public" 三个字母),要么明确用空串走默认空间;写侧(yudao publish)与读侧(worker NacosHotConfig 订阅、game-cloud SCA)必须对齐同一个真实 namespaceId,否则激活写进一个空间、worker 在另一个空间读、配置永远推不到。
### 3.5 分工边界:基建配置 vs 业务生成配置
配置控制面用了 Nacos,阶段〇的基建也用了 Nacos,两者必须划清,否则治理层会误伸手去管运维配置、或运维改配置时绕过了该有的审计。判据是一句话:**谁改、改了要不要治理**。
| | 基建配置 | 业务生成配置 |
|---|---|---|
| 例子 | game-cloud Spring 配置、Sentinel 流控规则、RocketMQ 参数、服务发现 | prompt / 模型 / 参数 / 软预算 / 门阈值 |
| 谁改 | 运维 / 开发 | 创始人 / 运营 |
| 要不要治理 | 不要——即时热生效即可 | 要——版本 / 审计 / 审批 / 可回滚 |
| 通路 | Nacos SCA 原生(`spring-cloud-starter-alibaba-nacos-config`,dataId 按应用名,@RefreshScope 或重启) | yudao 治理层(MySQL 版本行为账本)→ 激活时 PATCH Service + publish 生效 dataId |
| 消费方 | game-cloud 各 Java 服务 | AgentScope Service(PATCH)+ Python worker(NacosHotConfig) |
两者共用 Nacos 这套下发基础设施,但治理路径分开、命名空间或分组隔离。基建配置那条阶段〇已经接好、跑在生产,阶段二不碰它;阶段二只在 Nacos 上开一块属于业务生成配置的地(路 B 生效 dataId),由 yudao 激活编排独占写入。
### 3.6 失败模式与兜底
(图3 失败模式与兜底 SVG 待补)
激活是一批跨系统的非原子写(PATCH Service + publish Nacos + 更新 yudao 指针),这里的失败模式要正面处理,不能让配置中心把生成链路带崩。
- **激活失败可重试、不留半生效态**。一批下发里任一步失败(某个 PATCH 返错、Nacos publish 超时),整批判**未激活**:yudao 的当前激活版指针**不前移**,保留上一激活版为权威,并把这次激活标为失败可重试。下发动作须幂等(同一版本重放不产生副作用),重试就是把整批重放一遍。绝不出现"指针已前移、但 Service 只 PATCH 了一半"的状态。
- **Service 不可达**。路 A 依赖 Service 在线才能 PATCH。Service 不可达时,激活判失败(同上),保留上一激活版;此时 Service 上跑的还是它 Redis 里的旧配置,生成不中断,只是新配置没生效。Service 恢复后重放激活即可。
- **配置漂移检测**。Service 的 Redis 投影可能与"当前激活版"漂移——Service 重启若 Redis 未持久化会丢配置回落缺省、或有人绕过治理直接改了 Redis/Nacos、或某次激活 PATCH 部分失败没被发现。配置中心提供一个对账:激活后与定期,拉 Service 的 `/agent`+`/session` 当前配置、比对当前激活版的路 A 内容;拉 worker 的生效投影、比对路 B 内容;对不上即告警,并支持一键重推(重放激活把投影拉回激活版)。这道对账是"配置中心为权威、Service 与 worker 为投影"这个定位的兜底闸。
- **命名空间错配**。见 §3.4:写读两侧的 namespaceId 必须是同一个真实值,默认空间是空串非 "public"。这条在接线时一次性核对钉死,避免配置静默推不到。
## 4 步骤计划
(阶段序 SVG 待补)
阶段二自身按依赖分五步串行;阶段三(UI)、阶段四(观测)作为后续阶段划界在后,各自后续出 plan。
```mermaid
flowchart LR
S1[步骤1<br/>配置集建模<br/>+ yudao 治理骨架] --> S2[步骤2<br/>版本行与历史 MySQL<br/>回滚/diff]
S2 --> S3[步骤3<br/>双路激活编排]
S1 --> S4[步骤4<br/>NacosHotConfig<br/>接进 genconfig]
S3 --> S5[步骤5<br/>失败兜底<br/>+ 漂移对账]
S4 --> S5
S5 --> N3[阶段三 UI<br/>后续出 plan]
N3 --> N4[阶段四 观测<br/>后续出 plan]
```
**步骤 1 · 配置集建模 + yudao 治理骨架**
- 交付:在 game-module-aigc 落一个生成配置治理子域(复用 yudao 的鉴权/creator/审计框架,不塞进 infra_config 的 KV 表——生成配置是结构化配置集、不是键值对)。定义配置集的数据模型(一个配置集含哪些旋钮、映射到哪些 `/agent`+`/session` 字段与哪些 Nacos 生效 key)、版本与当前激活版指针、生命周期状态机、creator 与操作审计。
- 验证:能建/改/定版一个配置集,creator 与时间随版本落库;权限门挡住无权写;状态机流转符合 §3.2。
- 依赖:yudao(game-cloud 已在)。
- 风险:配置集与 AgentScope agent/session 的字段映射要对齐 `/agent`+`/session` 的真实 schema(消费 `/agent/schema`),映射错则激活 PATCH 无效。
**步骤 2 · 版本行与历史(MySQL)**
- 交付:定版落版本行——配置集全量内容(prompt 存 `MEDIUMTEXT` + 模型/参数/预算/阈值)与元数据同库同事务一次写成一行;历史列表、任一历史版取回、两版 diff;当前激活版指针只由激活动作前移(定版不动它)。
- 验证:定多版后能列历史、取任一版、diff 两版;定版是单库事务、无跨系统写;30KB 级 prompt 正文完整存取无截断。
- 依赖:步骤 1。
- 风险:版本行只增不删,量级 = 人工定版频次(每天几次),多年不清理也只是几千行——留一个归档策略位即可,不做提前优化。
**步骤 3 · 双路激活编排**
- 交付:激活动作把选定版双路下发——路 A PATCH `/agent`+`/session`,路 B publish 进 worker 监听的生效 dataId;更新当前激活版指针 + 记操作日志;成组下发幂等、失败整批判未生效可重试(见 §3.6);静默期语义(只对下一批新生成生效)。
- 验证:改任一旋钮 → 定版 → 激活 → 下一次生成生效;并发两局不读到路 A 新/路 B 旧的撕裂组合(静默期);回滚旧版即恢复;一批下发中途失败时指针不前移、可重试。
- 依赖:步骤 1、2;阶段一②(两档已归并 Service,PATCH 有落点)。
- 风险:激活一致性是本阶段最重的风险(§3.6);Service PATCH 与 Nacos publish 跨系统,须幂等 + 判未生效可重试。
**步骤 4 · NacosHotConfig 接进 genconfig**
- 交付:genconfig 的读取后端提升到 Nacos——优先 NacosHotConfig、回落本地 `generation.yaml`、回落内置默认;NacosHotConfig 作进程级单例接进 worker 启动。middleware 调用面不改。落地阶段〇 D2 建好未接线的 `nacos_hotconfig.py`。
- 验证:改 Nacos 生效 dataId → worker 数秒内经 genconfig 读到新预算/阈值(不重启);Nacos 不可达时回落本地 YAML 与默认、生成不受影响;cheap 与 tier2 两档的软预算目标、门阈值都吃上热读。
- 依赖:阶段〇 Nacos + NacosHotConfig(已建);阶段一①(middleware 经 genconfig 读预算/阈值)。
- 风险:genconfig 现有缓存与 NacosHotConfig 的推送时序要理顺(别让本地 YAML 缓存盖住 Nacos 热值);回落链的优先级要测到位。
**步骤 5 · 失败兜底 + 漂移对账**
- 交付:激活失败整批判未生效 + 保留上一激活版 + 可重试;Service 不可达兜底;配置漂移对账(拉 Service/worker 投影比对当前激活版)+ 一键重推。
- 验证:模拟 PATCH 中途失败/Service 不可达 → 指针不前移、生成用旧配置不中断、重放激活恢复;篡改 Redis/生效 dataId 后对账能检出漂移并重推拉回。
- 依赖:步骤 3、4。
- 风险:漂移对账要区分"真漂移"与"正在激活的中间态",避免误报。
**后续阶段(划界,各自出 plan)**:阶段三 = game-admin 配置编辑面(浏览/改/定版/激活/回滚/历史/diff,表单消费 `/agent/schema`),依赖阶段二;阶段四 = 观测(Studio + genMonitor,trace 回放/成本对账/在跑监控),依赖 trace 事件流。两者不在本设计展开。
## 5 验证方式
1. **配置即数据、版本可管**:改 model/budget/max_tokens/thinking/prompt 任一 → 定版 → 激活 → 下一次生成生效;回滚即恢复;逐项覆盖本会话手改过的硬编码点。
2. **归因与审计**:每次定版记 creator/时间,激活/回滚有 yudao 操作日志,任意两版可 diff。
3. **双路激活、静默期无撕裂**:路 A PATCH、路 B Nacos 热读都生效;一组旋钮作一个配置集激活;并发两局不读到跨路撕裂组合。
4. **NacosHotConfig 接线**:改 Nacos 生效 dataId,cheap 与 tier2 的软预算/门阈值经 genconfig 数秒内热读到新值、不重启;Nacos 不可达回落本地 YAML 与默认、生成不受影响。
5. **分工边界**:基建配置仍走 SCA 原生通路、不经治理层;业务生成配置的写入只由 yudao 治理层独占。
6. **失败兜底**:激活中途失败/Service 不可达时指针不前移、生成用旧配置不中断、重放可恢复;漂移可检出并重推。
## 6 风险与回滚
- **激活一致性(本阶段最重)**:一批 PATCH+publish 跨系统非原子。缓解 = 幂等 + 失败即整批判未生效可重试 + 当前激活版指针只在整批成功后前移 + 保留上一激活版为权威;并发撕裂 MVP 由静默期规避,机制级原子(epoch 戳)留放量后。回滚 = 配置中心永远能重放上一激活版。
- **Service 不可达 / Redis 未持久化丢配置**:激活判失败保留旧版;Service 恢复后由漂移对账检出并一键重推。Service Redis 的持久化策略需与运维确认(丢配置是否需 Service 启动即从配置中心拉激活版自愈,可作后续增强)。
- **NacosHotConfig 接线破坏 middleware 读参**:回落链(Nacos → 本地 YAML → 内置默认)是保命绳,先在两档单测里锁死三级回落再上;真接线灰度——先只把一个低风险旋钮(如门阈值)切到 Nacos 热读、验稳再推预算目标。回退 = genconfig 后端切回纯本地 YAML(改一处开关)。
- **命名空间错配**:默认空间是空串非 "public";写读两侧 namespaceId 一次性核对钉死,否则配置静默推不到(阶段〇同款坑)。
- **配置集字段映射漂移**:配置集到 `/agent`+`/session` 字段的映射依赖 AgentScope schema,框架升版可能变;映射以 `/agent/schema` 为准、加一致性校验,别硬编码字段名。
- **SoT 收口**:本阶段落地后,须把 SoT 里 GitOps/Langfuse 式的旧口径收敛为 yudao 配置中心版本化(账本落 MySQL 版本行)——§5.2 管理面配置管理、§5.8 配置三类的"受治理发版"、ADR-4 配置热取、A13 配置注册表四处,与上级设计 §6 pending 是同一收口面,收口时一并回写,避免两份自称权威触 canonical 门;对上级设计本身的口径回调逐条挂账在 §7,由编排层另单收口、本档不动上级档。
## 7 收口涟漪清单(挂账,由编排层另单收口)
版本账本从 Nacos 挪进 yudao MySQL 版本行(§3.1)回调了上级设计已评审的几处口径。按创始人指令,本档**不改上级档**,在此逐条挂账;收口时随上级 §6 已挂的 SoT 收口单一并执行、不双开。
| # | 位置 | 现口径 | 应回调为 |
|---|---|---|---|
| 1 | 上级设计 §0 / §3.3 / §3.7"互补"行 | "Nacos 管版本化存储与下发(版本历史/回滚/diff/灰度/推送),取代自建 Flyway 版本表 + 薄读接口" | 版本账本落 yudao MySQL 版本行(prompt 100KB 上限 + 定版原子性所迫,§3.1);Nacos 收窄为路 B 生效下发;"消灭薄读接口"结论不变(NacosHotConfig 仍替它);"灰度发布"收窄为路 B 生效 dataId 层能力、MVP 不启用 |
| 2 | 上级设计 §4 阶段二节(交付/验证/风险) | "激活时把 active 版写进 Nacos 并 PATCH""Nacos 承版本/回滚/灰度/推送(取代自建 Flyway 版本表 + 薄读接口)" | 交付 = yudao 治理子域(版本行 + 状态机 + 激活编排)+ 双路激活 + NacosHotConfig 接 genconfig;验证/风险按本档 §4/§6 |
| 3 | 上级设计 §3.6 mermaid(UI→yudao→NACOS 写版本→激活 PATCH) | 版本写进 Nacos、激活自 Nacos 侧发出 | yudao(MySQL 账本)→ 激活编排双路下发(PATCH `/agent`+`/session` · publish 生效 dataId);图随文改 |
| 4 | SoT 回写口径(架构图说 §5.2 / §5.8 / ADR-4 / A13;上级 §6 已挂"GitOps 口径"收口项) | GitOps / Langfuse 式热取叙述 | "配置中心版本化"的落点 = yudao MySQL 版本行 + 双路激活(本档 frontmatter sot-impact 申报);与上级挂的收口单合并执行 |
## 附 图清单与状态
| 图 | 角色 | 状态 |
|---|---|---|
| 图0 一图看懂 | §0 门面 SVG | 待 opus 子代理出图 |
| 图1 分工边界与四方职责 | §2/§3.5 SVG | 待出图 |
| 图2 配置生命周期与双路激活 | §3.2/§3.3 SVG(内联 Mermaid 事实源已在文) | 待出图 |
| 图3 失败模式与兜底 | §3.6 SVG(内联 Mermaid 事实源已在文) | 待出图 |
文字 + Mermaid 为事实源,SVG 为派生视觉。