第十九节 — 演化与版本管理
这一节回答:FinBayes 各类资产(接口契约 / 数据 schema / Prompt / Provider / 工具)如何演化?如何保证升级时不打破现有用户的状态与体验?
五类需要版本化的资产
| 资产类型 | 演化频率 | 版本化策略 |
|---|---|---|
| 接口契约 | 中(每次外部 API 调整) | semver(major.minor.patch)+ contract_version 字段 |
| 数据 schema(State Store) | 低(破坏性变更稀有) | schema_version + migration 脚本 |
| Prompt(System / 任务模板) | 高(持续迭代) | 见 ADR-009(待定) |
| Provider 池(LLM / 数据 Provider) | 中 | 配置文件版本 + Provider Adapter 内部适配 |
| 工具池(Capability Registry) | 中 | tool_version + 工具退役流程 |
各类资产的演化策略不同 —— 接口契约要严格 semver、数据 schema 要带 migration、Prompt 要支持快速迭代但留可回溯能力、Provider 与工具池要支持热插拔。
接口契约的版本化
哪些是"接口契约"
| 接口 | 契约位置 |
|---|---|
| 入口 HTTP / WebSocket API | OpenAPI schema |
| MCP Server 暴露的工具 | MCP tool schema |
| Channel Adapter 接收的事件 | 各 Channel 的 webhook schema |
| 内部子系统间(CHAP-09 各接口) | Python 函数签名 + Pydantic 数据对象 |
| Provider Adapter 内部 | 统一 OpenAI-compatible schema |
Semver 语义
| 版本变更 | 含义 |
|---|---|
| major ↑ | 破坏性变更:删除字段 / 改字段语义 / 改方法签名 / 改错误码语义 |
| minor ↑ | 向后兼容增加:新增 optional 字段 / 新增方法 / 新增错误码 |
| patch ↑ | 修 bug、不动接口形态 |
字段级演化规则
关键约束:
- 不向已发布的接口悄悄改字段语义(即使字段名 / 类型不变)
- 删字段前必须先 deprecated 一个 minor 版本,给用户 / 实施 Agent 升级窗口
- 每次 major 升级附升级指南(自动转换工具 + 手动迁移说明)
Contract Version 在协议消息中
每条 API 消息含 contract_version 字段:
| 行为 | 触发 |
|---|---|
| 同 major 不同 minor | 服务端兼容处理(缺失字段用默认值) |
| 不同 major | 服务端拒绝,返回 INVALID_CONTRACT_VERSION + 当前服务端支持的版本范围 |
| 缺失 contract_version | 服务端按"最低支持版本"处理或拒绝 |
数据 Schema 的版本化(State Store)
Schema Migration 流程
关键约束:
- migration 脚本单向(只有 up,没有自动 down —— 降级靠从 bak 恢复,避免双向 migration 的复杂性)
- migration 必须幂等(重复运行不损坏数据)—— 实现机制:
- DDL 层幂等:所有
CREATE TABLE/CREATE INDEX用IF NOT EXISTS;所有ALTER TABLE ADD COLUMN先查PRAGMA table_info跳过已存在列 - 运行时层幂等:migration runner 启动时读
schema_metadata.migration_history(JSON 数组),跳过已记录的 migration 文件名 - 事务层:每个 migration 脚本在单一事务内执行,失败 ROLLBACK + 不写入 history;成功 COMMIT + 追加到 history
- DDL 层幂等:所有
- migration 失败时全量回滚到 bak,不留中间状态
- 用户能看到 migration 进度(不是黑盒等待)
Schema 元表
State Store 含一张元表 schema_metadata:
| 字段 | 含义 |
|---|---|
| schema_version | 当前 DB schema 版本 |
| finbayes_version | 上次写入此 DB 的 FinBayes 程序版本 |
| migrated_at | 上次 migration 时间戳 |
| migration_history | 历次 migration 记录(from / to / timestamp / 备份位置) |
Prompt 版本化(ADR-009 决策位置)
Prompt 既是"代码"(程序行为的关键决定因素)又是"数据"(频繁迭代 + 与提示词工程并行进化)。
两个候选策略
| 策略 | 优点 | 缺点 |
|---|---|---|
| A. Prompt as Code:Prompt 进 Git,与代码同 release 周期 | 版本可追溯 / Review gate 覆盖 / CI 跑得过 | 迭代慢 / Prompt 工程师等不及 release / 大文件 diff 噪音 |
| B. Prompt as Data:Prompt 存独立资源(YAML / DB),运行时加载 | 迭代快 / Prompt 工程师独立工作 | 难追溯 / Review 难 / 版本错位风险 |
初步倾向(待 ADR-009 确认):混合
- 关键 Prompt(System Prompt / 任务路由模板 / 输出契约 schema)走策略 A(进代码仓 + Review gate)
- 实验性 Prompt(个性化模板 / A/B 候选 prompt)走策略 B(YAML + 版本字段 + 审计追踪)
- 切换在每条 Prompt 自描述的
delivery_mode: code | data
Prompt 演化的可观测要求(无论哪种策略)
每次 Prompt 变更必须可追溯:
| 字段 | 含义 |
|---|---|
| prompt_id | 全局唯一标识 |
| prompt_version | semver |
| activated_at | 启用时间 |
| author | 作者 / Git commit 引用 |
| eval_score | 上线前评估分数(详见 CHAP-21 评估闭环) |
| rollback_target | 如需回滚指向的上一版本 |
prompt_id 命名约定
prompt_id 采用三段式:<subsystem>.<purpose>.<variant>
| 段 | 含义 | 取值示例 |
|---|---|---|
| subsystem | 所属子系统 | orchestration / cognition / evidence / clarify |
| purpose | 用途类型 | system / task_template / output_schema / judge |
| variant | 变体标识 | main / compact / verbose / experimental_a |
示例:
cognition.system.main— 综合层主 System Promptorchestration.task_template.synthesis— Task Orchestration 用的综合任务模板clarify.system.main— clarify 工具 System Promptcognition.judge.counter_evidence_v1— 评估 judge prompt(反方证据维度,详见 CHAP-21)
命名约定避免:
- 同名跨子系统冲突(subsystem 前缀强制)
- 实验 prompt 与生产 prompt 混淆(variant 后缀显式
experimental_*) - A/B 测试时 prompt_id 混淆(variant 用
_a/_b/ 而非数字)
详细 ADR-009 待写。
Provider 池演化
新增 Provider
约束:
- 新增 Provider 不动 runtime 业务代码(仅在 Provider Adapter Pool 层)
- 新增 Provider 不影响现有 contract_version
- 用户既有的 Provider 偏好顺序保留 / 升级时仅追加可用 Provider 不强制重排
Provider 退役
| 步骤 | 内容 |
|---|---|
| 1. 标 deprecated | 用户配置中显示警告:"Provider X 将于版本 Y 移除" |
| 2. 引导迁移 | 提供"自动迁移到等效 Provider"建议(如 Provider X → Y) |
| 3. 一个 major 版本后移除 | 仍配置该 Provider 的用户启动时明示 + 引导重配 |
Provider API 变化(Provider 端)
LLM Provider(如 OpenAI)调整 API 时:
- Provider Adapter 内部适配(patch / minor 版本)
- runtime 业务代码不变
- 用户感知:通常无感(除非 Provider 端废弃旧接口强制迁移)
工具池演化
新增工具
工具通过 Capability Registry 注册(详见 CHAP-09)。新增工具流程:
| 步骤 | 内容 |
|---|---|
| 1. 工具实现 | 实现 schema + 调用逻辑 |
| 2. 标 category | 严格枚举(read_only / analysis / synthesis / clarify / 等),无 execution 选项 |
| 3. Review gate | 人工审查工具用途 + schema 校验(自动 grep 执行类参数名) |
| 4. 注册到 Registry | runtime 启动时通过 Registry 装载 |
| 5. Self-consistency 测试 | LLM Function Calling 能否正确选择该工具(避免新工具拉低意图识别准确度) |
工具退役
| 步骤 | 内容 |
|---|---|
| 1. 标 deprecated | LLM 工具池 schema 中加 deprecated: true + 替代工具指向 |
| 2. 兼容期 | 现有 task 仍可调用,但 LLM 优先选替代工具 |
| 3. 移除 | 一个 minor 版本后移除(任何引用旧工具的状态对象 / Judgment 仍可读,只是不能再调用) |
工具 schema 变更
新增 optional 参数:minor;改 required 参数 / 改返回 schema:major。
Concept 退役流程
战略层已禁入概念不允许进入主分支(CHAP-02 + CHAP-17)。但未来若某战略概念被明确退役(如"任务类型清单"扩展),工程层需要支持。
退役流程
| 步骤 | 内容 |
|---|---|
| 1. 战略层 ADR | 在 governance 层写战略级 ADR 明示退役 + 替代 |
| 2. 加入 verify-kb 禁词表 | 自动 grep 拦截 |
| 3. 状态对象兼容 | 已有的引用旧概念的状态对象不破坏(只读 + 在 UI 中标"历史概念") |
| 4. 文档归档 | 旧概念相关文档移到 _archive/,frontmatter 标 legacy |
| 5. 用户感知 | 给一个 release 的过渡期 + 明示提醒 |
升级流程的工程承接
详见 CHAP-14 升级流程。这里强调演化角度:
| 升级路径 | 接口契约 | 数据 schema | Prompt | Provider | 工具 |
|---|---|---|---|---|---|
| patch(bug 修复) | 不变 | 不变 | 可能变 | 不变 | 不变 |
| minor(兼容增强) | 兼容新增 | 兼容新增 | 频繁变 | 可能新增 | 可能新增 / deprecated |
| major(破坏性变更) | 可破坏 + 升级指南 | migration 必备 | 可能重写 | 可能新增 / 退役 | 可能新增 / 退役 |
约束:每次 release 的 changelog 必须按上述五类资产清晰罗列变更。
演化中的不变量
无论怎么演化,下列不变量永远不变:
| 不变量 | 演化中的保护 |
|---|---|
| 凭证不变量(不收不存不训练) | 任何接口 / schema / Prompt / 工具变更都不能引入凭证字段或凭证类参数 |
| 不直接下单 / 不持账户凭证 | 工具池禁止注册执行类工具(即使新增 category) |
| 不替用户决策 | 综合层输出契约必须含反方 / 风险 / 失效条件(不能因"简化"删除) |
| 用户数据主权 | 任何数据 schema 变更都不能让用户失去查看 / 修改 / 删除权 |
| 本地优先 | 任何架构演化(如未来加云端)都不能让本地优先用户失能 |
这些是战略级硬约束,演化策略必须服从战略层(详见 CHAP-02 上位继承与不变量)。
版本管理的可观测
每次资产变更都进入审计 trail / 元数据表:
| 资产 | 追溯位置 |
|---|---|
| 接口契约 | OpenAPI / Pydantic schema 在 Git 历史 + contract_version 在消息中 |
| 数据 schema | schema_metadata 表 + Git 历史 |
| Prompt | Prompt 自描述字段 + 审计 trail "prompt_version_changed" 事件 |
| Provider | providers.yaml 在 Git 历史 + 用户配置文件版本 |
| 工具 | Capability Registry 的工具元数据 + 审计 trail "tool_registered/deprecated" 事件 |
与其他章节的关系
- 战略级不变量演化中的保护 → CHAP-02 上位继承与不变量
- 升级流程的部署形态承接 → CHAP-14 部署形态
- Schema migration 的存储承接 → CHAP-15 数据存储划分
- 接口契约消息体 contract_version → CHAP-16 通信协议
- Review gate 的工程承接 → CHAP-17 边界与安全
- 变更的审计可见性 → CHAP-18 可观测性
- 评估如何驱动 Prompt 演化 → CHAP-21 评估闭环
- ADR-009 Prompt 是代码还是数据 → 待写