FinBayes 工程架构
本文档是 FinBayes 工程实施的契约事实源。任何工程实施仓的代码、提案、决策都必须可追溯到本文档某一章节或某条 ADR。
文档元信息
| 维度 | 内容 |
|---|---|
| 上位依据 | FinBayes 战略白皮书 / FinBayes 产品定义 |
| 编写方法论 | arc42 + C4 + ADR + DDD 业务建模(详见 ADR-002) |
| 工程范式 | Harness Workflow + 里程碑切片 + 走通骨架试点(详见 ADR-001) |
| 工程协作 | OpenSpec + Archon + Claude Code 主控 + Codex 实施(详见 ADR-003) |
| 重写工作流 | governance/workstreams/finbayes-arch-rewrite/ |
| 前版(v1)归档 | _archive/projects/finbayes/2026-05-27-architecture-v1-rewrite/ |
文档结构
本文档分 9 部分共 29 节(§28 / §29 为附录与子系统索引):
第一部分 立架
第二部分 业务架构
第三部分 系统全景
第四部分 系统运行
第五部分 部署与基础设施
第六部分 横向贯穿的关注点
第七部分 质量与验收
第八部分 已知缺口与决策
第九部分 落地映射
配套资产
| 资产 | 位置 |
|---|---|
| 架构决策记录(ADR) | governance/workstreams/finbayes-arch-rewrite/decisions/ADR-NNN-*.md |
| 章节单独草稿(评审用) | governance/workstreams/finbayes-arch-rewrite/drafts/CHAP-NN-*.md |
| 工作流状态 | governance/workstreams/finbayes-arch-rewrite/status.md |
| 任务识别策略深度调研 | projects/finbayes/research/intent-recognition-and-llm-strategy/ |
章节交叉引用规则
- 章节间引用用"§N"或"第 N 节"
- ADR 引用用 ADR-NNN
- 任何工程实施仓的代码引用本文档时必须用§N 锚点
1. 文档角色与读者
这一节回答:这份文档是什么,怎么用。
这是什么
FinBayes 工程架构文档是 FinBayes 系统设计的总图。它从战略白皮书与产品定义文档派生,把战略层的"为什么做、做什么"翻译成工程层的"系统是什么样的、怎么动、怎么部署、怎么演化"。
怎么用
按需查阅,不需要从头读到尾。
- 写代码时:去"系统全景"找当前要实现的子系统;去"系统运行"找跨模块协作的时序;去"代码仓位置映射"找代码落点
- 设计评审时:先读"业务架构"建立总体认识,再核对要评审的模块所属子系统
- 遇到模糊点:查"架构决策索引",每个关键决策在
decisions/下有独立文档说明上下文与结论 - 接手维护时:从"立架"三节开始建立坐标系,再按需 zoom in
与上下游文档的承接
- 战略白皮书:FinBayes 是什么、战略不变量、阶段范围
- 产品定义文档:用户行为契约、任务类型、输出认知要素
- 本文档:把上述两份内容落到模块、接口、数据、部署
- 第三方基线评估:从现有 martinpmm/Finclaw 工程仓如何演化到本文档定义的形态
- Harness Workflow 与里程碑规范:按节奏切片实施本文档定义的内容
任何冲突以战略白皮书与产品定义文档为准,本文档须修正。
2. 上位继承与不变量
这一节回答:FinBayes 的工程实现必须承接哪些战略层事实。
FinBayes 是什么
FinBayes 是金融认知层应用。它把用户的自然语言问题映射为金融认知任务,调度多 Agent 与金融原子技能执行,产出条件化、可复盘、带不确定性意识的认知材料。用户基于这些材料形成自己的判断与决策;买卖、调仓、转账、自动交易等执行能力由用户或下游执行系统承接。
但「把一次提问映射成一次认知输出」只是 FinBayes 在单个回合内的行为,不是 FinBayes 的全部——产品本体是下面这条 identity 级不变量定义的 agent。
FinBayes 产品本体是带自主循环的认知 agent(架构级不变量 · identity 级)
FinBayes 的产品本体不是「输入问题 → 输出一次认知材料」的问答函数,而是一个带自主循环的金融认知 agent:感知(接地真实数据)→ 规划(拆解任务)→ 行动(调工具 / 认知机制)→ 观察(结果回灌)→ 收敛,并跨回合把判断沉淀为状态资产、在市场变化触及失效条件时主动发起复盘。synthesize_cognition(单次综合)是这个循环在单个回合内被调用的一个认知动作,不是 runtime 的顶层入口。
这条不变量是 identity 级(与「不直接下单」「不收凭证」同级,不可被里程碑排期稀释):
- 主动信号 / 自主复盘循环是 identity 级能力,不是晚期里程碑的增量功能。任何里程碑路线图不得把「状态 + 自主触发循环」的端到端打通排到状态化(M1)之后太远——最小自主循环(哪怕只监控 1 类失效条件、只对 1 个 Fin Object)必须在 M1/M2 端到端可见(§25 里程碑对应承接此约束)。
- State Management 的主动信号触发器与 Task Orchestration 的单回合编排是 agent 的两个半:缺主动触发器,FinBayes 在结构上退化为单次问答函数(§9.2 承接此分工)。
- 允许 M0 walking skeleton 以 single-shot 形态起步,但这是已知的 pre-agent 阶段,必须在路线图显式标注并给缓解,不得让 single-shot 惯性一路延续到后期里程碑。
frame 背景:本不变量为 2026-06-04 阶段 0 文档矫正新增,依据金融真智能体骨架蓝图(E)#2 + owner 议定结果。它把此前隐含在 §5 / §11 主动信号、却从未被立为 identity 的「agent 本体」显式硬化,纠正「越往工程下游越退化成单次问答函数」的框架漂移。
战略边界
FinBayes 不直接下单, 也不持有账户凭证。
工程层承接:runtime 范围只包含金融认知任务的处理,不实现交易执行能力;工具注册表对执行类工具的注册请求一律拒收;状态写入路径不保留可触发执行的凭证或权限令牌。
凭证处理
金融执行凭证——私钥、助记词、钱包恢复短语、交易所登录凭证、交易所 API key、经纪商 API key、银行账户、信用卡等——FinBayes 一律不收、不存、不训练, 即使为了"提升服务质量" 也不收。
工程层的三个机械承接:
- 不收:输入端识别凭证类信息后给安全回应,不进入认知任务处理链
- 不存:状态对象、缓存、日志、审计 trail 一概不保留凭证内容;输出端扫描防止大模型生成凭证样式的内容被意外捕获
- 不训练:凭证内容不进入反馈数据、评估样本、微调数据
金融执行凭证 vs 本机配置秘密:两者必须严格区分。
- 金融执行凭证:用户在金融账户上的支配权(私钥 / 助记词 / 交易所 API key / 等),归本节管辖
- 本机配置秘密:用户自己的运行环境秘密(大模型 Provider key、数据 Provider key、本地服务 token 等),按本机安全存储正常处理,不属于本节管辖
界面上必须明确区分两类秘密,避免用户混淆。
用户主权
用户对自己的画像保有完整控制权:随时查看、修改、清空整个画像。用户清空时系统显式提示"协作上下文已重置"。
画像服务于沟通效率(表达密度、术语深度选择),不进入证据筛选——综合层产出的反方证据、关键风险、失效条件按事实空间生成,不因画像偏好被裁剪。
任务类型与认知要素
FinBayes 第一阶段识别七类用户认知任务(来自产品定义文档,本文不增不减不改名):
- 解释类:理解金融概念 / 机制 / 现象
- 分析类:围绕事件 / 数据 / 变化展开认知组织
- 比较类:多个金融对象的维度化对比
- 复盘类:触发历史判断的成立条件 / 当前变化 / 是否仍成立
- 风险识别类:主动识别下行风险 / 反方 / 盲点
- 交易准备类:交易前的条件 / 风险 / 反方 / 失效边界检查
- 交易决策辅助:聚焦具体决策点的条件化判断
每类任务按需组合产品定义文档里定义的认知要素(结论 / 倾向 / 依据 / 多视角 / 反方证据 / 成立条件 / 失效条件 / 不确定性 / 信息缺口 / 来源与时间戳 / 可继续追问项 / 历史判断链接)。不固化字段表,按任务类型动态组合。
与战略未决问题相关的参数
战略白皮书把"商业模式整体压力测试、单位经济、vs 通用 AI 留存竞争、L1-L3 商业强度"列为战略层未决问题。工程层涉及这些问题的参数全部走配置文件,由商业团队 + 产品团队基于冷启动数据填写:
- 每次任务的大模型调用次数上限
- 单用户同时进行中的任务数上限
- 主动信号每用户每天触发上限
- 不同用户层级的服务边界(使用频率、持续支持时长、主动反馈能力)
- 付费转换点的触发条件
具体的配置文件路径在"演化与版本管理"那节定义。
概念使用约定
本文档术语与战略白皮书保持一致。用"交易准备 / 交易决策 / 交易行动"系列措辞;不用"行动准备 / 行动判断 / 行动方案"系列。
如下游实施中发现需要引入战略白皮书未授权的新概念,必须先在战略白皮书或产品定义文档里授权(走 governance change-protocol),不在工程文档里自创。
本文档变更时的快速核查
本文档每次改动时,下列 grep 级核查作为变更评审的必要条件:
- 战略边界原句 "FinBayes 不直接下单, 也不持有账户凭证" 仍然出现在文档中
- 凭证条款原句 "一律不收、不存、不训练" 仍然出现在文档中
- 七类任务类型措辞与产品定义文档完全一致
- 战略未决问题相关的参数文中未出现具体数值(必须是配置文件指针 / 占位符)
- agent 本体不变量仍在:「FinBayes 产品本体是带自主循环的认知 agent,主动信号 / 自主复盘循环是 identity 级能力」未被删改,且无任何里程碑把最小自主循环排到状态化(M1)之后太远
这些是文档表面完整性的快速核查,不替代实质语义 review。变更评审还需配套人工核查:被禁概念是否以同义改写 / 结构隐藏 / 英文替换等方式被引入文档。这两层检查的角色分工详见架构目标章节下的战略保真度质量属性。
3. 架构目标与质量取舍
这一节回答:这个架构在追求什么;冲突时按什么规则取舍。
总体目标
让 FinBayes 实施者(写代码的 AI 助手 / 接手维护的工程师)能够实现的代码:
- 不漂移战略白皮书与产品定义文档的不变量
- 覆盖产品定义文档要求的全部用户行为
- 多入口(CLI、TUI、Web、MCP、Channel)的认知质量与用户体验一致
- 未来增加新任务类型 / 新市场 / 新入口时不需要推倒重来
关键质量属性
按对架构决策的影响优先级排序:
| 优先级 | 质量属性 | 工程上具体做什么 |
|---|---|---|
| 一 | 战略保真度 | 每次架构改动过 review gate,双层检查:(a) 机械 grep 检查战略不变量原句仍存在 (b) 人工实质语义核查战略未授权概念的本质内涵未被同义改写 / 结构隐藏 / 英文替换等方式引入。grep 是必要的快速过滤,不是合格判定 |
| 二 | 认知输出质量 | 综合层产出反方证据 / 关键风险 / 失效条件 / 信息缺口按事实空间生成;画像只影响表达密度,不进入证据筛选;每条认知输出可被重放、对比、追溯(含证据来源、综合路径、Provider 调用),作为后续质量评估的可被验证基础。具体的认知质量验收方法(评估维度、rubric、多评估者机制)属于待定义的工程设计问题,详见 OQ-002 与后续 §20 / §21 |
| 三 | 可演化性 | 跨模块接口显式版本化;任务路由 / 技能 / 数据源 / 大模型 Provider 走注册表查找而非硬编码;与战略未决问题相关的参数走配置 |
| 四 | 可观测性 | 每次任务执行产出可序列化审计记录(不含凭证类内容);每个降级 / 失败的证据节点带降级原因;用户可见"为什么这么答"线索 |
| 五 | 响应性 | 多任务并发执行;部分结果流式输出(不等所有内部任务完成才出第一屏);长时间任务异步走 |
| 六 | 可测试性 | 五层测试:单元(模块内部)/ 契约(跨模块接口)/ 集成(多模块协作)/ 场景抽样回归(FinBayes Case Library,定位质量退化与缺口,内容动态迭代不作为二元门禁)/ 认知质量评估(具体方法待 §20 / §21 与产品团队共同定义) |
| 七 | 本地优先 | 第一阶段本地部署跑完整体验;本机配置秘密走本机安全存储;状态可落本地文件或嵌入式数据库 |
| 八 | 健壮性 | 每个外部依赖有降级路径;一个证据节点失败只影响依赖它的下游节点,不阻塞其他任务 |
冲突时的取舍
| 冲突情境 | 取舍 |
|---|---|
| 战略保真度 vs 实施速度 | 保真度优先 |
| 认知输出质量 vs 响应性 | 第一屏先回答用户题眼并标注"反方 / 详细条件还在补充";最终结果必须完整 |
| 可演化性 vs 简洁性 | 跨模块接口必须版本化(不可简化);内部实现可简化(单进程优先,不微服务化) |
| 响应性 vs 完整性 | 部分结果先输出 + 最终归并;不允许"等齐了再出"导致用户等待 |
| 本地优先 vs 多入口一致性 | 多入口走同一 runtime 接口契约;不为本地特殊化降级共用接口 |
| 可观测性 vs 性能 | 第一阶段全量审计 trail;性能问题在后续优化时再讨论降低粒度 |
第一阶段实施时的具体技术取向
明确这些事项第一阶段这样做(而不是另一种做法):
- 单进程优先:runtime 在第一阶段单进程实现,不微服务化。多入口(CLI / TUI / Web / MCP / Channel)共享同一 runtime 实例
- 本地优先:状态落本地文件 / 嵌入式数据库(如 SQLite);不依赖云端 state store
- 异步走 Python asyncio:多任务并发用异步等待原语(具体细节见 ADR-005 待写)
- 大模型 Provider 走统一适配层:不直接调用各家 SDK,所有 Provider 通过统一接口接入(具体细节见 arch-rewrite/ADR-008 accepted)
- 状态写入两步:长期状态对象(关注列表、判断记录、动态画像)的写入分待确认 / 已确认两步(具体细节见 ADR-007 待写)
- 审计 trail 全量记录:第一阶段每次任务执行的证据 / 综合路径 / Provider 调用全量写审计,性能优化是后续事项
第一阶段不投入优化的事
显式声明这几件事第一阶段不做(避免实施者误优化):
- 极致低延迟(首屏 100 毫秒以内):认知任务本质需要大模型调用,秒级延迟合理
- 大规模并发(单实例万级 QPS):第一阶段本地部署优先 + 个人用户量级
- 跨地域部署 / 跨用户横向扩展 / 数据库分片:远期事项
什么时候开始投入这些优化的判断条件留给运维 / 产品决定,工程架构不预设阈值。
4. 业务对象与关系
字段权威定义见 contracts/structured-cognition-result.yaml(Step 11 整改包 I 单一事实源层)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:FinBayes 业务里有哪些 first-class 概念,它们之间什么关系。
概览
FinBayes 业务层识别 7 个 first-class 概念。它们是用户能感知、能操作、能引用的对象。工程实现按这些概念组织数据模型与接口。
| 对象 | 工程英文名 | 是什么 |
|---|---|---|
| Fin Object 金融对象 | FinObject | 用户关注的金融对象,可以是单一标的 / 板块 / 主题 / 事件 / 政策 / 组合 / 叙事 / 关键人物中的任意一种或组合 |
| Watchlist 关注列表 | Watchlist | 用户组织 Fin Object 的列表机制,便于持续追踪 |
| Session 会话 | Session | 一次对话或任务上下文容器,承载多轮交互 |
| Task 金融认知任务 | Task | 用户的自然语言提问被识别为的具体任务,按产品定义文档当前定义的任务类型清单识别。一个输入可能触发多个并发任务 |
| 认知结果 | StructuredCognitionResult | Task 的输出,包含按任务类型组合的认知要素 |
| Judgment Record 判断记录 | JudgmentRecord | 用户在某时刻对某 Fin Object 形成的判断的可复盘记录,含成立条件 / 失效条件 / 反方证据等 |
| 动态画像 | DynamicProfile | 用户在持续使用中表现出的认知偏好、表达密度、关注模式,用户保有查看 / 修改 / 清空控制权 |
工程英文名是 Pydantic 模型 / SQLite 表名 / 代码模块名的统一约定,后续章节(§9 / §11 / §15 / §27)按这套英文名引用。中文名仅用于用户可见输出与本架构文档正文。
关系图
这张图表达什么:用户拥有动态画像(每用户一份)、维护任意多个 Watchlist、发起任意多个 Session。Watchlist 包含 Fin Object。Session 承载 Task。Task 围绕 Fin Object 并产出认知结果。认知结果经用户确认后可成为 Judgment Record。Judgment Record 针对具体 Fin Object,并能形成复盘链(用户后续更新或矫正旧判断时)。
这张图特意不表达什么:模块级实现细节(如 TaskGroup 是 Task 的并发容器、EvidencePacket 是证据单元等工程对象)、字段级数据结构、状态写入路径(候选 → 已确认等工程细节)、各对象的数量基数(一对多 / 多对多等)—— 这些在系统全景与系统运行章节展开。
怎么读这张图:实线箭头是直接关系("用户维护 Watchlist"),虚线箭头是条件关系("认知结果用户确认后可成为 Judgment Record"),Judgment Record 自环表示"复盘链"是同一对象内部的版本关系(旧判断 → 新判断)。
各对象的关键属性与生命周期
Fin Object
是用户关注的金融对象。可以是以下任意一种或组合:
- 标的(单一资产,如 BTC / ETH / NVDA / AAPL)
- 板块 / 行业(如半导体、Layer1、AI 概念股)
- 跨标的主题(如降息、AI 浪潮、稳定币监管)
- 用户自定义组合(如 BTC vs ETH 对比组合、自选股组合)
- 单次重要市场事件(如财报、FOMC、链上 hack、协议升级)
- 政策 / 宏观变量(利率、通胀、监管动向)
- 影响市场叙事的关键人物(KOL、机构、央行)
- 市场叙事(如 AI、降息、ETF、监管、链上周期等当前主导的故事线)
Fin Object 是 FinBayes 一切金融判断的承载体——用户的关注、历史判断、反方证据、成立条件、失效条件、复盘记录都围绕 Fin Object 组织。
Watchlist
用户主动维护的 Fin Object 集合。加入 Watchlist 是用户对该 Fin Object 表达持续关注的承诺。Watchlist 支持:
- 任意类型 Fin Object 加入(不限于"标的",可加事件 / 主题 / 政策 / 关键人物等)
- 分组、排序、按 Fin Object 设置不同的关注密度与复盘节奏
- 与历史判断和复盘记录联动:市场变化触及用户判断时,FinBayes 围绕 Watchlist 内对象触发主动信号
Session
一次对话或任务上下文容器。FinBayes 支持:
- 默认会话:首次使用无需创建,降低首次使用门槛
- 命名会话:用户主动创建用于不同意图 / 场景 / 关注对象
- 跨会话持续状态:Judgment Record、Watchlist、动态画像 跨会话持有
Session 的生命周期:创建 → 活跃中 → 上下文超额时压缩 → 归档 → 可恢复 → 删除。具体状态机在状态对象生命周期章节展开。
Task
用户的自然语言提问被识别为的具体任务。任务类型清单由产品定义文档定义。第一阶段含以下类型(未来可能扩展或细分,工程实现按注册表查找而非硬编码 if-else 分支):
- 解释类:金融概念 / 机制 / 现象的解释
- 分析类:围绕事件 / 数据 / 变化展开认知组织
- 比较类:多个 Fin Object 的维度化对比
- 复盘类:触发历史判断的成立条件 / 当前变化 / 是否仍成立
- 风险识别类:主动识别下行风险 / 反方 / 盲点
- 交易准备类:交易前的条件 / 风险 / 反方 / 失效边界检查
- 交易决策辅助:聚焦具体决策点的条件化判断
一个用户输入可能命中多个任务(如"NVDA 财报后我的判断要不要更新 + 现在该不该加仓"是复盘 + 交易准备的组合)。多任务的并发组织由工程层的 TaskGroup 承接(详见系统全景章节)。
自然语言到任务的识别策略(规则 / LLM / 混合 / 其他)是关键架构决策,留待 ADR-004 任务识别策略 定(详见 status.md OQ-003)。
认知结果
Task 的输出。按任务类型组合产品定义文档定义的认知要素:
- 结论 / 倾向(条件化)
- 依据
- 多视角
- 反方证据
- 成立条件
- 失效条件
- 不确定性 / 信息缺口
- 来源与时间戳
- 可继续追问项
- 历史判断链接(与用户已有 Judgment Record 的关系)
不固化字段表,按任务类型动态组合。具体哪个任务类型组合哪些要素由综合层章节展开。
Judgment Record
用户在某时刻对某 Fin Object 形成的判断的可复盘记录。是 FinBayes 持续认知能力的关键载体。每条 Judgment Record 包含:
- 时间戳与所属 Session
- 涉及的 Fin Object
- 用户判断方向 / 倾向
- 支持理由 + 反方证据(FinBayes 主动提的 + 用户接受的)
- 成立条件与失效条件
- 不确定性 / 信息缺口
- 复盘记录链(之后的更新 / 矫正)
Judgment Record 是独立的可被检索、复查、引用的认知资产,与聊天记录区分。生命周期:候选生成 → 用户确认 → 已确认 → 市场变化触及成立 / 失效条件时主动信号触发复盘 → 更新链。详见状态对象生命周期章节。
动态画像
FinBayes 在用户使用和交互过程中静默构建的用户画像。画像在用户持续使用中逐步完善,是 FinBayes "越来越懂用户" 的基础。
画像包含 (但不限于):
- 用户当前阶段的风险偏好
- 关注模式(关注密度、复盘节奏、对新信息的敏感度)
- 关注的市场与标的范围
- 任务类型偏好(更常做分析 / 复盘 / 交易准备 / 等)
- 表达密度偏好(专业术语 vs 解释性语言)
动态画像不影响 FinBayes 输出质量的标准——反方证据 / 关键风险 / 失效条件等核心认知要素的呈现不会因画像被裁剪。画像主要影响两件事:
- 意图识别的精准度:同一句用户表达在不同用户身上可能对应不同任务类型(例如"还能追吗"在常做交易准备的用户与常做风险扫描的用户身上有不同的隐含意图)
- 输出内容范围匹配用户期望:在某个 Fin Object 上展开的深度、关注哪些细节、表达密度等会按画像调整(但核心认知要素的覆盖度不变)
用户对画像保有查看、修改、清空的完整控制权(战略层不变量,详见上位继承与不变量章节)。
不在这一章的对象
下列对象是工程层实现细节,在系统全景 / 系统运行章节展开:
- TaskGroup:多任务并发的组织容器(用户感知"答案在分步流出"但不直接操作 TaskGroup)
- EvidencePlan / EvidencePacket:证据组织的内部结构
- State Candidate:待用户确认的状态写入
- Context Snapshot:长会话的上下文压缩快照
跨层对象映射(产品 → 架构 → 工程)
本章定义的 7 个 first-class 业务对象,在产品定义 / 主架构 / 状态机 / 持久化 / 模块路径 / M0 实现度的对应:
| 业务对象 | 产品定义 § | 工程英文名 | 持久化(§15) | 独立状态机(§11) | 模块路径(§27) | M0 实现 |
|---|---|---|---|---|---|---|
| Fin Object | §3.1 | FinObject | fin_objects 表 | 无(仅 created/archived 标记) | state/fin_object.py | ✅ implement |
| Watchlist | §3.2 | Watchlist | watchlist_objects 表 | 无(由 StateCandidate 承载) | state/watchlist.py | ❌ M1+ |
| Session | §3.3 | Session | sessions 表 | ✅ 有 | state/session.py | ✅ implement(默认 Session 兜底) |
| Task | (工程派生) | Task | 仅审计 trail(内存对象) | ✅ 有 | orchestration/task.py | ✅ implement |
| 认知结果 | §7 | StructuredCognitionResult | 仅审计 trail | 无 | cognition/types.py | ✅ implement(M0 综合层输出契约) |
| Judgment Record | §3.4 | JudgmentRecord | judgment_records 表 | ✅ 有 | state/judgment.py | ❌ M1+ |
| 动态画像 | §3.5 | DynamicProfile | dynamic_profiles 表 | 无 | state/profile.py | ❌ M1+ |
派生的工程对象(不是 first-class 业务对象但有独立状态机或承载关键职责):
| 工程对象 | 独立状态机(§11) | 模块路径(§27) | M0 实现 |
|---|---|---|---|
| TaskGroup | ✅ 有 | orchestration/task_group.py | ⚠️ stub(M0 仅单任务) |
| StateCandidate | ✅ 有 | state/candidate.py | ⚠️ stub |
| Provider Readiness | ✅ 有 | providers/readiness.py | ✅ implement |
| AuditEvent | 无 | state/audit.py | ✅ implement |
阅读约定:
- 用户视角看到的是"业务对象"(产品定义 §3)—— 5 类核心 + 隐式的 Task / 认知结果
- 工程视角看到的是"业务对象 + 派生工程对象"(架构 §4 + §11) —— 7 first-class + 4 派生
- 持久化 / 状态机 / 模块路径只是工程视角的不同 view,不引入新对象
- M0 阶段实施按"M0 实现"列,详见 M0 走通骨架工程包 §2 接口子集表
5. 用户价值与认知流转
这一节回答:战略层提的"想清楚 / 看全面 / 看本质"三层价值在工程上怎么落;用户问题如何流转到认知结果。
三层价值的工程承接
FinBayes 的核心价值是把用户的金融困惑转化为可复盘的金融认知。战略层把这件事拆为三层:
| 战略层价值 | 工程上落到 |
|---|---|
| 想清楚 — 帮用户把含糊的情绪 / 直觉 / 疑问转化为可分析的金融认知任务 | 任务识别(自然语言 → 任务类型 + Fin Object + 市场范围 + 时间窗口)+ 触发型澄清(信息不足时主动追问关键问题) |
| 看全面 — 帮用户把碎片信息组织成完整事实空间,主动呈现反方证据 | 证据组织(按 Market Pack 调用数据源 / 工具 / Skill)+ 多视角整合(不同立场 / 方法 / 时间尺度的观点)+ 反方证据主动呈现 |
| 看本质 — 帮用户看清成立条件 / 失效条件 / 关键变量 / 信息缺口 | 综合层产出条件化结论 + 成立条件 + 失效条件 + 不确定性 + 信息缺口 |
这三层不是顺序而是同时进行——综合层产出的内容同时承接三层价值。
认知流转主线
一次用户提问的端到端业务流程:
这张图表达什么:FinBayes 作为 agent 的默认闭环。横向的单回合(A→G)只是 agent 的一个回合、问答只是入口之一;图的骨架是常开的自主循环——判断沉淀进 agent 状态层(K),agent 持续监控市场变化是否触及成立 / 失效条件(L),触及就主动发起复盘(J)回到认知,且状态层作为跨回合记忆喂回每一个回合。这条循环不以「用户是否愿意沉淀」为可选开关,而是 FinBayes 之所以是 agent 而非问答函数的本体(承接 §2 agent 本体不变量)。
这张图特意不表达什么:工程实现细节(任务识别如何分发到 Router Agent、综合层如何调用 LLM、状态写入两步、heartbeat / cron 如何驱动 L 的扫描等),这些在系统全景章节展开。
怎么读这张图:菱形是判断分叉,矩形是处理步骤,圆柱是 agent 状态层;turn 子图是单个回合的边界,子图外的 K→L→J→B 回路是 agent 的常开主动循环。实线是默认路径,虚线(K⇢B)是跨回合记忆注入。它表达 FinBayes 与用户的协作不是一次性问答,而是一个会自主回头、跨回合记得用户的 agent。
关键节点的业务约束
识别问题类型与对象:识别基于产品定义文档的七类任务清单,不依赖样例 prompt 的字符串匹配;新出现的提问表达若与已知 paraphrase 相似,应稳定识别为同类任务。
澄清追问:用户表达不足以决定任务类型 / 对象 / 时间窗口时主动追问一两个关键问题。澄清的目标是把用户的模糊表达推向明确的金融认知任务,不是无限追问降低进入门槛。
组织相关信息:信息组织以 Fin Object 为中心,不以孤立 ticker 或事件为中心。同一 Fin Object 的不同信息面(价格 / 链上 / 财报 / 资金流 / 新闻 等)由 Market Pack 声明,工具调用结果归一化为证据单元。
呈现认知材料:第一屏先回答用户题眼(用户最直接问的事),其他认知要素(反方、详细条件、追问项等)随后展开。第一屏不暴露内部 trace、不只是字段列表、不退化为免责声明。
用户基于材料判断 / 决策:用户保留完整决策权与执行权。FinBayes 提供认知材料供用户做决策,不替用户决定行动,也不在金融账户上执行任何动作。
判断沉淀:用户可以把当前关注的 Fin Object 加入 Watchlist;可以把当前形成的判断记录为 Judgment Record。沉淀经"用户确认"才发生(候选 → 已确认两步),不悄悄写入用户长期状态。
市场变化复盘触发:用户已确认的 Judgment Record 中的成立条件 / 失效条件被市场变化触及时,FinBayes 主动发出复盘信号,明示触及哪条判断、哪个条件、当前变化是什么。主动信号不退化为价格提醒或新闻推送。
与战略未决问题的边界
认知流转涉及的工程参数(每次任务的大模型调用次数上限 / 主动信号触发频率 / 用户层级服务边界等)按战略未决问题的承接约定走配置而非硬编码,留给商业团队与产品团队基于冷启动数据决定(详见上位继承与不变量章节)。
6. 关键业务场景
这一节回答:第一阶段典型业务场景下,认知流转具体走成什么样。
场景一览
下列 12 个场景覆盖产品定义文档当前定义的各类任务、复合场景与 agent 自主行为场景:
被动 / 主动场景配比(frame):S1–S8 是用户发起的单回合问答(agent 的入口行为),S9–S12 是 agent 在无人提问时的自主行为(主动监控、到期对账、事件驱动复查、heartbeat 批量唤醒)。早期版本只有 1 个自主场景(S9)、被动:主动 = 8:1,这个配比本身会把读者引向「FinBayes ≈ 问答函数」的误读。本节显式补齐自主场景到 4 个,让场景集如实反映 §2 的 agent 本体不变量——agent 的自主循环与单回合问答同等是产品骨架。
| 编号 | 用户语言示例 | 主要任务类型 |
|---|---|---|
| S1 | "什么是 ETF 折溢价" | 解释类(被动入口) |
| S2 | "美联储这次讲话怎么看" | 分析类(被动入口) |
| S3 | "BTC vs ETH 这轮该怎么配" | 比较类(被动入口) |
| S4 | "我之前看多 ETH 的理由还成立吗" | 复盘类(被动入口) |
| S5 | "BTC 现在最大下行风险是什么" | 风险识别类(被动入口) |
| S6 | "我现在该不该减 ETH"(用户尚未声明仓位 / 风险 / 时间窗) | 交易准备类(被动入口) |
| S7 | "NVDA 跌到 130 我要不要补" | 交易决策辅助(被动入口) |
| S8 | "NVDA 财报后我对它的判断要不要更新,现在该不该加仓" | 复盘 + 交易准备 复合(被动入口) |
| S9 | (无用户主动提问)市场变化触及用户某条 Judgment Record | agent 自主行为:条件触及主动复盘 |
| S10 | (无用户主动提问)heartbeat 周期唤醒,批量扫描所有到期 / 临界的 Judgment Record | agent 自主行为:定时巡检 |
| S11 | (无用户主动提问)某条判断的时间窗到期,延迟神谕可验证 | agent 自主行为:到期拉真实数据对账 |
| S12 | (无用户主动提问)Watchlist 对象出现新关键事件 | agent 自主行为:事件驱动复查提示 |
场景详述
S1:概念解释
用户:什么是 ETF 折溢价?
- 任务类型:解释类
- 认知要素组合:结论 / 依据 / 来源与时间戳 / 可继续追问项(如"折溢价对哪些交易策略有用"、"溢价持续时是不是套利信号"等)
- 状态变化:通常无(仅在用户主动加入关注时触发 Watchlist 操作)
- 业务约束:不退化为词典式定义,应结合 FinBayes 已积累的市场上下文(哪些 ETF 当前确实在显著折溢价)
S2:事件分析
用户:美联储这次讲话怎么看?
- 任务类型:分析类
- 认知要素组合:结论 / 依据 / 多视角 / 反方证据 / 成立条件 / 不确定性 / 来源与时间戳
- 状态变化:可能触发"是否将该事件加入 Watchlist"、"是否将当前判断记录为 Judgment"
- 业务约束:多视角真实呈现不同立场(鹰派 / 鸽派 / 市场预期偏差等),不只是同一观点的不同表述
S3:对比配置
用户:BTC vs ETH 这轮该怎么配?
- 任务类型:比较类
- 认知要素组合:对比维度声明(如基本面 / 周期位置 / 资金流 / 政策环境 / 风险结构)/ 各对象在各维度的结论 / 反方 / 不确定性
- 状态变化:可能将该对比组合作为 Fin Object 加入 Watchlist
- 业务约束:对比维度由 Market Pack 声明,不让 LLM 自由发挥;用户已声明"配置"意图但未声明仓位 / 风险预算时,不直接给具体配比,给"在不同条件下偏向 X 的逻辑"
S4:历史复盘
用户:我之前看多 ETH 的理由还成立吗?
- 任务类型:复盘类
- 认知要素组合:当时成立条件 / 当前变化 / 是否仍成立 / 新增信息 / 反方 / 历史判断链接
- 状态变化:可能在 Judgment Record 上加一条复盘记录(用户确认后)
- 业务约束:复盘必须找到对应的 Judgment Record;若用户曾经表达过但未沉淀为 Judgment Record,应主动询问当时的具体理由,不替用户假设
S5:风险扫描
用户:BTC 现在最大下行风险是什么?
- 任务类型:风险识别类
- 认知要素组合:风险来源(多个)/ 触发条件 / 失效条件(在什么前提下这个风险不存在)/ 多视角(不同时间尺度的风险)
- 状态变化:通常无
- 业务约束:识别多个具备不同时间尺度与触发条件的风险,不退化为"宏观环境不确定 / 监管风险"这类无信息含量的回答
S6:交易准备(用户未声明仓位)
用户:我现在该不该减 ETH?
- 任务类型:交易准备类
- 认知要素组合:一般性条件化判断(不针对用户具体仓位)/ 反方 / 失效边界 / 不确定性 / 显式标注"这是检验而非指令、执行权在你"
- 状态变化:可能触发用户主动声明仓位 / 风险预算 / 时间窗口;用户声明后进入针对该仓位的具体条件化判断
- 业务约束:用户未声明仓位时不给具体减仓数量 / 比例 / 价位建议,给的是"在什么条件下减仓的逻辑是 X,在什么条件下不减的逻辑是 Y"的条件化判断
S7:交易决策辅助(具体价位)
用户:NVDA 跌到 130 我要不要补?
- 任务类型:交易决策辅助
- 认知要素组合:在 130 这个价位下的条件化倾向 / 成立条件 / 失效条件 / 反方 / 不确定性 / 显式标注"这是检验而非指令、执行权在你"
- 状态变化:可能触发将该决策点作为 Watchlist 内事件追踪
- 业务约束:同 S6,仅在用户已声明仓位 / 风险预算 / 时间窗口时给具体决策倾向;未声明时给条件化分析
S8:复合场景(复盘 + 交易准备)
用户:NVDA 财报后我对它的判断要不要更新,现在该不该加仓?
- 任务类型:复盘类 + 交易准备类(一个用户输入命中两个任务)
- 业务流转:内部并发执行两个任务:复盘任务调出已有 Judgment Record 检查成立 / 失效条件 / 当前变化;交易准备任务围绕"是否加仓"组织条件化判断。两个任务的输出归并为一份给用户的有逻辑顺序的整合回答(如"基于复盘结论 X,加仓的条件化判断是 Y")
- 业务约束:内部并发对用户透明,用户看到的是整合回答不是分裂的两份输出;某一任务降级时另一任务仍能给有价值的部分回答
S9:主动信号触发
触发条件:用户某条已确认 Judgment Record 的成立 / 失效条件被市场数据触及(如 ETH 跌幅触发某条 Judgment Record 的失效条件)
系统行为:主动发出复盘信号,明示:触及哪条判断 / 哪个条件 / 当前变化是什么 / 是否仍成立 / 建议如何复盘
业务约束:
- 信号不退化为价格提醒或新闻推送
- 信号节奏由用户配置的关注密度控制,不高频骚扰
- 信号必须能回到对应 Judgment Record 让用户完成复盘并更新认知
S10:heartbeat 定时巡检(agent 自主行为)
触发条件:周期性 heartbeat 唤醒(无用户提问),agent 批量扫描所有 Watchlist 对象与未结算 Judgment Record,识别哪些判断的成立 / 失效条件已临界、哪些已到期可对账。
系统行为:用结构化 enum 判定每条是 skip 还是 run(应对触发信号本身带噪),只对真正越线的判断生成主动信号,避免噪声轰炸;批量结果按用户关注密度合并推送。
业务约束:
- heartbeat 是 agent 主回路的一种触发源,不是用户可见功能;自动注入的扫描 prompt 必须过提示注入防御
- skip/run 判定走 LLM 结构化输出,不用裸阈值,以容忍神谕带噪
- 巡检绝不触发任何交易动作,只产出复盘信号
S11:延迟神谕到期对账(agent 自主行为)
触发条件:某条 Judgment Record 的时间窗到期(如「财报后两周」),其可证伪断言此时可被真实市场数据验证(无用户提问)。
系统行为:agent 主动再次拉取真实市场数据,对该判断做判断跟进结算(旧称「三态结算」;按 ADR-022 formal 化为「验证状态+验证结论」两层枚举,见 glossary),把结算结论与原判断同时保留形成时间线(不覆盖原判断),并在置信度与事后印证频率间记录校准信号。
业务约束:
- 对账锚点是「成立 / 失效条件是否被市场触发、条件化倾向方向是否被事后演化支持」,不是「按判断交易的真实盈亏」(FinBayes 不下单、不接触持仓)
- 结算不二值化(三态),承认对错本身模糊
- 正式校准记录 / 命中率系统不在第一阶段强建(留作单独产品设计课题),第一阶段只需 agent 能到期主动回来对账并留痕
S12:事件驱动复查提示(agent 自主行为)
触发条件:Watchlist 内某 Fin Object 出现新的关键事件(如监管公告、协议升级、财报),可能影响用户已有判断(无用户提问)。
系统行为:agent 主动评估该事件是否触及任一历史判断的关键前提,命中则推送复查提示,明示事件、受影响的判断、可能改变的条件。
业务约束:
- 以「是否触及历史判断条件」为中心,而非以「事件热度 / 价格波动」为中心
- 未触及任何历史判断条件的事件不主动打扰用户
- 提示保留认知 / 执行分工说明,不作为交易信号
不在第一阶段场景之列
下列业务场景明确第一阶段不做:
- 自动执行任何交易(不下单 / 不调仓 / 不持有账户凭证)
- 主动监控用户在交易所 / 经纪商的账户状态
- 替用户做任何金融决策
- L4 职业投资者的团队协作 / 深度数据 / 审计 / 权限工作流
- A 股 / 商品 / 外汇 / 债券等独立市场(仅作为宏观横向输入支撑 Crypto + US Stocks 的判断)
7. 系统与外部世界的关系
这一节回答:FinBayes 作为一个黑盒,与外部世界的接触边界是什么。
系统上下文图
这张图表达什么:FinBayes 作为生态认知层与 7 类外部角色的交互边界。用户是 FinBayes 唯一直接对话的人类参与者;LLM 与外部数据 Provider 是 FinBayes 主动调用的能力提供方;Data Horizon / Trading Matrix / RLE / FEFM 是生态内协同项目,各自有独立的产品定位与接口契约。
这张图特意不表达什么:FinBayes 内部模块(容器与组件划分留给系统内部的进程与服务划分章节)、具体接口字段(schema 留给附录)、部署拓扑(留给部署形态章节)。
怎么读这张图:实线箭头是 FinBayes 主动调用 / 接收的关系;虚线箭头是潜在 / 未来的关系(如 RLE 学习信号回流、FEFM 模型能力接入)。FinBayes 与 AI Trading Matrix 没有直接连接——用户在授权后自主把意图转交 Trading Matrix,FinBayes runtime 不参与执行链路。
7 类外部角色的接触契约
用户
接触形态:自然语言对话(文本输入,未来扩展语音 / 文件附件 / URL / 表单等多模态)。
FinBayes 给用户的输出:按任务类型动态组合的认知材料(含结论 / 倾向 / 依据 / 多视角 / 反方证据 / 成立条件 / 失效条件 / 不确定性 / 信息缺口 / 来源时间戳 / 可继续追问项 / 历史判断链接)。
用户对 FinBayes 的控制权:
- 对话内容(用户表达什么由用户定)
- 状态写入确认(候选 → 已确认 两步,用户拒绝则不写入)
- 画像查看 / 修改 / 清空(战略不变量)
- Provider 配置选择(本地优先部署下,用户可自配置喜欢的 LLM / 数据 Provider)
LLM Providers
接触形态:FinBayes 通过统一的 Provider Adapter 层调用各种 LLM Provider(云端 Claude / GPT / DeepSeek / Qwen API;本地 Ollama / vLLM / LM Studio / Hugging Face TGI 等;用户自定义 OpenAI-compatible endpoint)。
调用方式:标准化的 Function Calling 接口 + streaming 响应 + 多模态消息(按 Provider 支持的能力)。
用户配置主导:本地优先部署下,用户可自配置 Provider 偏好与 fallback 顺序。系统默认配置是兜底而非强制(详见用户自配置 Provider 设计)。
外部数据 Providers
接触形态:通过统一的数据源注册表接入各种金融数据 API(价格行情、链上数据、SEC filings、财报数据、新闻、宏观数据等)。
调用方式:HTTP API 调用、SDK 接入、文件读取(用户上传的财报 / 研报 PDF 等)。
关键约束:所有外部数据进入后归一化为统一的证据单元(含来源、时间戳、freshness、置信度、降级原因等元数据)。
Data Horizon(生态感知层)
接触形态:FinBayes 消费 Data Horizon 提供的整理过的金融素材(事件、实体、时间线、情报)。Data Horizon 不替 FinBayes 判断;FinBayes 不替 Data Horizon 做数据感知。
接口契约:见生态协同契约章节(待起草)。第一阶段以"从 Data Horizon 取素材"为主,可能含订阅式实时更新(待具体定义)。
AI Trading Matrix(生态执行支持层)
接触形态:FinBayes 与 Trading Matrix 没有直接连接。用户基于 FinBayes 形成判断后,自主决定是否把意图转交 Trading Matrix。
为什么不直连:战略不变量"FinBayes 不直接下单, 也不持有账户凭证"要求执行链路与认知链路严格分离。直连会让用户无法清晰区分"获取认知材料"与"发起执行"两个动作,违反认知不替执行的分工原则。
未来如果接入:必须通过独立授权边界 + 外部系统 contract,不能把 Trading Matrix 的执行能力注册为 FinBayes 的认知 skill。
RLE(生态反馈学习)
接触形态:FinBayes 把用户对认知材料的反馈(接受 / 拒绝 / 修改)发送给 RLE;用户在 Trading Matrix 上行动后的反馈也回流到 RLE。RLE 整合后产出学习信号回流到 FinBayes。
第一阶段范围:用户反馈采集 + RLE 接口契约(具体学习闭环的实现复杂度由 RLE 自身决定,FinBayes 只承接接口)。
关键约束:金融执行凭证 / 用户敏感画像 等不进入 RLE 训练数据(凭证不变量 + 用户主权)。
FEFM(金融领域基础模型)
接触形态:FEFM 作为生态内的金融领域基础模型,可经 LLM Provider 适配层接入 FinBayes(FEFM 在 FinBayes 视角下就是另一个 LLM Provider,只是来自生态内部)。
第一阶段范围:FEFM 的具体形态由 FEFM 项目自身决定。FinBayes 在 Provider Adapter 层预留对 FEFM 的接入位,等 FEFM 提供 API 时即可加入用户可选 Provider 列表。
战略边界与不变量在这一层的体现
| 不变量 | 在系统上下文层的体现 |
|---|---|
| 不直接下单 / 不持有账户凭证 | FinBayes 与 Trading Matrix 无直连,用户在 FinBayes 与 Trading Matrix 之间保留完整决策权与执行权 |
| 凭证不收 / 不存 / 不训练 | 用户输入端拦截凭证类内容(与 LLM Provider / 数据 Provider / RLE 之间的接口都不传递凭证) |
| 用户画像主权 | 用户保有查看 / 修改 / 清空画像的完整控制权(与 RLE 之间的反馈不绕过用户控制权) |
| 输出是认知材料不是执行指令 | 给用户的输出始终是条件化认知材料;不主动调用 Trading Matrix 触发任何执行动作 |
| 画像不裁剪事实空间 | 画像只影响表达密度与术语深度;与 LLM Provider / 数据 Provider 交互时不因画像偏好过滤反方证据或关键风险 |
与生态内其他项目的边界总结
FinBayes 与生态内项目的边界遵循"分工而非隔离"原则:
- 认知不替感知:FinBayes 不重做 Data Horizon 的数据整理工作
- 认知不替执行:FinBayes 不实现任何交易执行能力
- 执行不补造认知:Trading Matrix 不替 FinBayes 做金融判断
- 反馈不绕过主权:RLE 收到的反馈来自用户主动行为(接受 / 拒绝 / 修改),不悄悄抓取
各项目各自独立产品 + 通过清晰接口契约协同。FinBayes 的工程实现不假设生态内其他项目的内部细节。
8. 系统内部的进程与服务划分
这一节回答:FinBayes 内部分几个进程 / 服务单元?哪些同进程?哪些独立部署?
第一阶段的整体取向:单进程优先
FinBayes 第一阶段采用 单进程实现 + 多入口共享同一 runtime 实例 的部署形态。具体而言:
- CLI / TUI / Web API Server / MCP Server / Channel Adapter 都是同一 runtime 进程的入口适配
- 多入口共享同一 Core Runtime 实例
- State Store(本地数据库)通过同进程库访问,非独立服务
- LLM Provider Adapter 是 runtime 内的客户端模块,通过 HTTP / stdio 调外部 Provider
理由(来自架构目标与质量取舍章节):
- 个人用户量级 + 本地优先部署,不需要为大规模并发优化
- 跨入口的认知质量一致性靠"共享同一 runtime 实例"硬保证
- 单进程内的接口契约 = 函数调用,迭代成本低
- 接口契约本身仍版本化,未来按需拆分进程不破坏现有调用方
容器图
这张图表达什么:FinBayes 内部分为 入口适配 / Core Runtime / Provider Adapter Pool / 本地持久化 四类容器。所有入口适配同进程,共享同一个 Core Runtime 实例。Provider Adapter Pool 通过 HTTP / stdio 调外部 LLM 与数据 Provider。持久化分四类:State Store(用户状态资产)、Cache(L3 缓存 + 语义缓存)、Config Store(用户 Provider 配置)、Credential Store(用户的 Provider API key 等本机配置秘密)。
这张图特意不表达什么:每个容器内部组件(留给"每个子系统的内部组件"章节)、具体数据流(留给关键场景的流转图章节)、未来从单进程演化到多进程的拓扑(留给部署形态章节)。
怎么读这张图:上半是外部世界,下半是 FinBayes Runtime Process。中间的箭头是跨容器调用。同一 box(如 entries 子图)内的容器都在同一进程中。Provider Adapter Pool 是同一进程内的客户端层,不是独立服务。
各容器的职责简述
| 容器 | 职责 | 第一阶段实现 |
|---|---|---|
| CLI Adapter | 命令式终端入口;单次提问 / Provider readiness 检查 / Session 管理命令 / Watchlist 操作 / 等 | Python click / typer 等 CLI 框架 |
| TUI Adapter | 终端持续问答入口;用户可切换 Session、确认状态候选、复盘判断等 | Rich / Textual 等 TUI 框架 |
| Web API Server | HTTP / WebSocket 服务,供 Web UI 调用;task request / event stream / state action 等 contract 接口 | FastAPI / Starlette |
| MCP Server | 标准 MCP(Model Context Protocol)服务,让外部 Agent 调用 FinBayes runtime | stdio 协议(MCP 标准) |
| Channel Adapter | Telegram / Discord / 等社群 channel 集成;摘要式输出 + 回链到 Web Session | webhook 接收 + Provider SDK |
| Core Runtime | 任务编排 / 路由 / 综合判断 / 状态管理 / 主动信号 等核心认知能力 | Python class + asyncio |
| Provider Adapter Pool | LLM / 数据 Provider 统一接入层;Provider Registry + Routing Policy + 能力匹配 + Fallback | 通过 LiteLLM 或自实现统一接口 |
| State Store | 用户状态资产持久化(Session / Watchlist / Judgment Record / 动态画像 / 审计 trail) | SQLite(本地优先) |
| Cache | L3 语义缓存 + 精确缓存 | Redis(如本机有)或进程内 LRU 内存 |
| Config Store | 用户的 Provider 配置(哪些 Provider 启用、任务-Provider 映射、fallback 顺序等) | YAML / JSON 配置文件 |
| Credential Store | 用户的 Provider API key 等本机配置秘密 | OS Keychain(macOS / Windows / Linux)优先,环境变量次之,加密本地文件兜底 |
容器间的通信方式
| 通信关系 | 协议 / 形态 |
|---|---|
| 入口适配 → Core Runtime | 同进程函数调用(Python class method / asyncio 协程) |
| Core Runtime → Provider Adapter Pool | 同进程函数调用 |
| Provider Adapter Pool → 外部 LLM | HTTP / streaming(按 Provider 协议;Ollama / vLLM 用 OpenAI-compatible API) |
| Provider Adapter Pool → 外部数据 Provider | HTTP / SDK 调用 |
| Core Runtime → State Store | 同进程库调用(SQLite Python binding) |
| Core Runtime → Cache | 同进程(Redis 通过本地 Redis 客户端 / 进程内 LRU) |
| Web API Server ↔ Web UI | HTTP(task request / state action)+ WebSocket(task event stream) |
| MCP Server ↔ 外部 Agent | stdio(标准 MCP 协议) |
| Channel Adapter ↔ Channel 平台 | webhook / polling(按 Channel 协议) |
部署形态对容器选择的影响
详见部署形态章节,这里点要点:
- 本地优先单机部署:所有容器同进程,State Store 用 SQLite,Cache 可选 Redis 或内存,所有 Provider 配置在用户本机
- 本地 + 远程 Provider:Core Runtime 与持久化都在本机,仅 Provider Adapter Pool 调用远程 LLM / 数据 API(用户配置)
- 未来托管部署(不在第一阶段):Web API Server 可分离为独立进程;State Store 可迁移到远程数据库;其他容器按需扩展
第一阶段的接口契约设计不锁死本地——未来按需拆分进程不破坏现有调用方。
与工程仓的代码位置映射
本章容器在 FinBayes 工程仓中的代码组织遵循 Python 标准 src layout:所有业务代码在 src/finbayes/ 下,按 6 子系统 + 入口适配 分子目录。各容器与代码模块的精确映射详见 §27 代码仓位置映射 —— 本章不重复,避免双源漂移。
入口适配子目录约定(src/finbayes/io/entries/):
| 入口容器 | 子目录 |
|---|---|
| CLI Adapter | cli/ |
| TUI Adapter | tui/ |
| Web API Server | web/ |
| MCP Server | mcp/ |
| Channel Adapter | channels/ |
详细映射(业务对象 / 状态机 / 工具 / 配置 / 测试 / 评估 全部 7 张表)见 §27。
9. 每个子系统的内部组件
字段权威定义见 contracts/structured-cognition-result.yaml(Step 11 整改包 I 单一事实源层)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:Core Runtime 内部分哪些子系统?每个子系统的职责、接口、关键组件是什么?
6 个子系统概览
Core Runtime 内部分 6 个子系统:
| 子系统 | 核心职责 |
|---|---|
| Input/Output Pipeline | 多模态输入归一化(文本 / 文件 / URL / 语音 / 表单)+ 输出投影(按入口呈现)+ 边界保护 hook |
| Task Orchestration | LLM Function Calling 驱动的意图识别 + 任务路由 + TaskGroup 并发编排 + 事后任务类型标签 |
| Evidence + Synthesis | 工具调用执行 + 证据归一化 + 综合判断(产出认知要素)+ 高风险任务 self-consistency |
| State Management | Session / Watchlist / Judgment Record / Profile / 审计 trail + 候选到已确认两步写入 + 主动信号触发 |
| Capability Registry | Tool / Skill 注册 + 任务类型本体(事后审计用)+ 执行类工具注册拒收 |
| Provider Adapter | LLM / 数据 Provider 统一适配 + 用户配置 Provider 池 + 4 层降级(L1-L4)+ 凭证安全 |
子系统间通过明确的接口契约协作,详见各子系统下方的接口表。
9.1 Input/Output Pipeline 子系统
组件图
这张图表达什么:输入侧把多种模态归一化为统一表示后过边界保护 hook,再进入 Task Orchestration;输出侧从综合层接收结构化结果过出口边界保护后,按入口投影为不同呈现格式。
这张图特意不表达什么:Task Orchestration / Synthesis 等下游子系统的内部组件(在下面各小节展开)。
职责
把所有用户输入归一化为「主文本 + 结构化上下文片段 + 元数据」供下游使用;把综合结果投影为各入口需要的呈现格式。
输入端的边界保护 hook 是战略不变量的工程承接点:凭证类与执行类输入在这里被规则识别 + 拦截,不进入 Task Orchestration / LLM 调用链。输出端的边界保护 hook 扫描凭证样式内容(防大模型 hallucinate 出地址 / 密钥串),不进入审计或状态。
关键接口
| 接口 | 输入 | 输出 |
|---|---|---|
preprocess(raw_input) | 任意模态原始输入 + 入口元数据 | 归一化输入对象(主文本 + 结构化上下文 + 元数据) |
boundary_check_input(normalized) | 归一化输入 | 通过 / 拦截(含安全回应内容) |
project(result, entry_type) | 综合结果 + 入口类型 | 该入口的投影对象 |
boundary_check_output(result) | 综合结果 | 扫描后的结果(凭证样式内容标记 / 脱敏) |
失败模式与降级
| 失败 | 降级 |
|---|---|
| 文件解析失败 | 标记"文件未解析",给用户安全回应 + 重试建议 |
| URL 不可访问 / 内容类型未识别 | 同上 |
| ASR 失败 | 提示"语音未转写",引导用户改文本输入 |
| 边界保护识别凭证类输入 | 返回安全回应(不进入认知任务链)+ 提示"凭证类信息不要发给 FinBayes" |
| 边界保护识别执行类请求 | 转为认知任务(如"是否要 X 行动 → 走交易准备类任务认知材料") |
验收信号
- 归一化输出在不同输入模态下结构一致
- 边界保护拦截测试覆盖:私钥 / 助记词 / 交易所 API key / 银行账户号 / 信用卡号 / 自动交易请求 / 直接下单请求等 negative cases
- 输出投影在 5 个入口(CLI / TUI / Web / MCP / Channel)共享同一 StructuredCognitionResult,投影差异只在呈现层
9.2 Task Orchestration 子系统
组件图
这张图表达什么:输入归一化后,加载用户上下文与工具池 schema,喂给 LLM Function Calling 做意图识别与工具选择。LLM 决定调单工具 / 多工具组合 / clarify 工具中的某一种。任务执行完成后,事后回填任务类型标签到审计 trail。
这张图特意不表达什么:意图本体作为前置分类器(FinBayes 不采用此模式,详见架构决策记录 ADR-004)。
职责
驱动用户输入到结构化任务的转换。不预设意图分类管道——意图识别由 LLM Function Calling 完成,FinBayes 提供工具池 schema、用户上下文、对话状态作为输入。任务类型本体在这里作为事后标签用于审计,不作前置路由。
复合任务(一个用户输入命中多个任务)通过 TaskGroup 显式拆解为单工具任务串行 / 并发调用——这是 FinBayes 在意图层的工程责任,不依赖 LLM 原生处理多轮复合任务(业界研究确认 LLM 在多轮工具调用上不稳定)。
frame 说明(agent 的两个半):Task Orchestration 承接的是 agent 的「单回合编排」——把一次用户输入在一个回合内组织成任务并产出认知。它不是 agent 的全部主回路。跨回合的自主循环——在无人提问时被 heartbeat / 市场变化唤醒、判断成立 / 失效条件触及时主动发起新一轮认知——由 §9.4 State Management 的主动信号触发器承接(§9.4 组件图中的
主动信号触发器,其产出的新任务经「State Management → Task Orchestration:主动信号触发的新任务」回流进本子系统,见 §9 跨子系统接口表)。单回合编排 + 主动信号触发器 = agent 的两个半:只有前者,FinBayes 是一个会编排单次问答的函数;两者合起来,才构成 §2 不变量定义的带自主循环的 agent。实施时不得只建 Task Orchestration 而把主动信号触发器无限后推。
关键接口
| 接口 | 输入 | 输出 |
|---|---|---|
orchestrate(normalized_input) | 归一化输入 | TaskGroup(含一个或多个任务)或 ClarifyResponse |
dispatch_task_group(group) | TaskGroup 对象 | 部分结果流 + 最终归并结果 |
tag_task_type(task, llm_call) | 任务 + LLM 调用结果 | 任务类型标签(来自任务类型本体)写入审计 trail |
内部组件简述
- Context Loader:从 State Management 读取用户画像 / 对话状态 / Watchlist / 已声明持仓
- Tool Pool Assembler:从 Capability Registry 取工具 schemas,按用户上下文过滤可用工具
- LLM Function Caller:经 Provider Adapter 发起 Function Calling,处理 confidence / 重试
- TaskGroup Manager:多任务并发执行 / 失败隔离 / 部分结果流式输出 / 最终归并
- Clarify Handler:clarify 工具调用的特殊处理(强制串行阻塞,澄清后回到 orchestrate 起点)
- Task Type Labeler:事后从 LLM 工具调用反推任务类型标签(用于合规审计)
失败模式与降级
| 失败 | 降级 |
|---|---|
| LLM 不可用 | 由 Provider Adapter 触发 L2 / L3 / L4 降级(详见 Provider Adapter 子系统) |
| LLM 给低 confidence | 自动调 clarify 工具,回到 orchestrate 起点 |
| TaskGroup 某子任务失败 | 该子任务降级输出 + 不阻塞其他子任务,最终归并时明示降级 |
| 高风险任务(交易准备类 / 决策辅助类) | 强制 self-consistency N≥3 采样投票(由 Evidence + Synthesis 实施) |
验收信号
- 同一用户输入在重复运行中识别为相同任务组合(除非走 LLM 路径产生合理变化)
- 复合任务(如复盘 + 交易准备)显式拆解为多工具调用,不靠 LLM 单次输出
- 事后任务类型标签覆盖所有完成的 task,进入审计 trail
9.3 Evidence + Synthesis 子系统
组件图
这张图表达什么:从任务到结构化认知结果的转换。证据层生成 EvidencePlan、执行工具调用、归一化为 EvidencePacket DAG;综合层产出认知要素。高风险任务走 self-consistency。
职责
证据层:按任务声明的证据面调工具与数据源,归一化为 EvidencePacket(含 source / freshness / confidence / status / degraded_reason)。
综合层:基于证据 DAG 产出认知要素(结论 / 倾向 / 依据 / 多视角 / 反方证据 / 成立条件 / 失效条件 / 不确定性 / 信息缺口 / 来源时间戳 / 可继续追问项 / 历史判断链接)。画像信号只调整表达密度与术语深度,不进入证据筛选——反方证据 / 关键风险 / 失效条件按事实空间生成,不被裁剪(战略不变量)。
高风险任务(交易准备 / 交易决策辅助)触发 self-consistency:N≥3 次综合采样 + 一致性投票(业界研究确认 LLM verbalized confidence 不可信,自一致性是替代方案)。
关键接口
| 接口 | 输入 | 输出 |
|---|---|---|
plan_evidence(task) | 任务对象 | EvidencePlan(DAG 节点 / 依赖 / 预算 / fallback) |
execute_evidence(plan) | EvidencePlan | EvidencePacket DAG |
synthesize(task, evidence_dag, context) | 任务 / 证据 / 用户上下文 | StructuredCognitionResult |
synthesize_with_consistency(task, evidence_dag, context, n) | 同上 + 采样数 | 经一致性投票的 StructuredCognitionResult |
失败模式与降级
| 失败 | 降级 |
|---|---|
| 单证据节点失败 | 标记 degraded_reason,不阻塞依赖它的其他证据节点之外的任务 |
| 必需证据全部失败 | 综合层产出 degraded snapshot(明示信息缺口,不强行给方向性结论) |
| LLM 综合失败 | 走 Provider Adapter 降级链;若全部 LLM 不可用走 L3 缓存 / 规则路径 |
| Self-consistency N 次采样结果分歧大 | 输出"判断不收敛"信息 + 各分歧的依据,让用户判断 |
验收信号
- 证据 DAG 可序列化为 run result / fixture / 审计记录
- 高风险任务在测试中能被识别并触发 self-consistency
- 反方证据 / 关键风险 / 失效条件 在不同用户画像下的呈现一致(不被画像裁剪)
- 没有可靠数据时给信息缺口而非凑数
9.4 State Management 子系统
组件图
这张图表达什么:长期状态(Watchlist / Judgment Record / 动态画像)通过 candidate → confirmed 两步写入;用户对画像保有完整控制权(查看 / 修改 / 清空);动态画像也来自后台静默观察。审计 trail 独立记录所有任务执行。主动信号机制:已确认的 Judgment Record 的成立/失效条件被市场变化触及时自动触发新一轮认知。
职责
承载 FinBayes 持续认知的所有长期状态资产;保证战略不变量在状态层的硬约束:
- 凭证类信息一律不进入任何长期状态(凭证不变量)
- 画像由用户保有查看 / 修改 / 清空的完整控制权(用户主权不变量)
- 画像不进入证据筛选(与综合层协作约束,画像信号只在 Context Loader 注入综合层时调表达密度)
- 判断与状态写入需用户主动确认(candidate → confirmed 两步)
关键接口
| 接口 | 输入 | 输出 |
|---|---|---|
create_candidate(type, payload) | candidate 类型 + 内容 | StateCandidate(待用户确认) |
confirm_candidate(id, edit?) | candidate id + 可选编辑 | 已确认状态对象 |
reject_candidate(id) | candidate id | 标记拒绝 |
read_session_context(sess_id) | session id | Session + 当前 Context |
compact_session(sess_id) | session id | Context Snapshot(保留判断条件 / 信息缺口 / 来源时间点) |
view_profile(user_id) / modify_profile(...) / clear_profile(user_id) | 用户主权动作 | 画像查看 / 修改 / 清空结果(清空时给出"协作上下文已重置"明示) |
trigger_active_signal(market_change) | 市场变化事件 | 触及的 Judgment Record 列表 + 主动信号材料 |
append_audit(task, calls, ...) | 任务执行细节 | 审计记录 |
内部组件简述
- Candidate Buffer:未确认状态的暂存
- Confirmed Store:已确认的 Watchlist / Judgment Record / Profile(落地 SQLite)
- Session Manager:Session 创建 / 切换 / 归档 / 删除生命周期
- Context Compactor:长会话上下文压缩(保留金融语义锚点)
- Profile Manager:用户画像的静默构建 + 用户主权动作
- Active Signal Trigger:定期 / 事件驱动检查 Judgment Record 的成立/失效条件
- Audit Logger:所有任务 / Provider 调用 / 降级 的审计记录
失败模式与降级
| 失败 | 降级 |
|---|---|
| State Store(SQLite)不可用 | runtime 进入只读模式 + 提示用户存储问题 |
| Context Compactor 失败 | 长会话切断,新 Session 开始 + 引用历史 Judgment Record |
| 主动信号触发引擎宕机 | 不阻塞主动 query;主动信号补发不实时 |
| 用户清空画像后系统仍有缓存 | 立即同步清空 + 显式提示"协作上下文已重置" |
验收信号
- 凭证类信息 grep 测试:状态对象 / 审计 trail 中 0 命中
- candidate vs confirmed tests 覆盖确认 / 编辑 / 拒绝 / 清空
- 用户画像清空后所有引用都不可读
- 主动信号触发的复盘建议能链回对应 Judgment Record
9.5 Capability Registry 子系统
组件图
这张图表达什么:3 个注册表(工具池 / 技能 / 任务类型本体)+ 执行类工具的硬性拒收规则 + 能力匹配过滤。任务类型本体仅供事后审计标签使用,不参与前置路由。
职责
集中管理 FinBayes 内部的可调用能力。执行类工具的注册请求一律拒收——这是战略边界"FinBayes 不直接下单, 也不持有账户凭证"在能力注册层的硬性承接,不允许通过任何方式(包括 plugin / 用户自定义工具 / 等)绕过。
任务类型本体由产品定义文档定义(解释 / 分析 / 比较 / 复盘 / 风险识别 / 交易准备 / 交易决策辅助),第一阶段实现为有序枚举 + 元数据(描述 / 触发关键词 / 涉及证据面 / 等)。未来可扩展或细分,按注册表查找而非硬编码 if-else。
关键接口
| 接口 | 输入 | 输出 |
|---|---|---|
register_tool(tool_schema) | 工具 schema | 注册成功或拒收(含拒收理由) |
assemble_tool_pool(user_ctx, provider_caps) | 用户上下文 + Provider 能力 | 该次任务可用的工具 schema 列表 |
lookup_task_type(task_id) | task id | 任务类型本体节点(用于审计) |
关键约束
- 执行类工具拒收清单(注册接口必须拒收的工具特征):
- 任何含"下单 / order / trade / buy / sell"语义
- 任何含账户操作("transfer / withdraw / deposit / sign / approve")
- 任何含自动化触发("schedule / cron / auto")
- 任何含 shell / 系统命令执行
- 任务类型本体的演化策略:扩展任务类型需先在产品定义文档授权,再在工具池增加对应工具 schema + 在任务类型本体增加节点
失败模式
| 失败 | 处理 |
|---|---|
| 注册执行类工具的尝试 | 拒收 + 记录到审计 trail(含尝试者 / 工具内容 / 时间) |
| 任务类型本体内节点缺失 | runtime 失败式拒绝,强制先扩本体再继续(防止任务"漂"到未知类型) |
| Tool Pool 为空(如用户配置过严过滤) | 返回受限工具池 + 提示用户检查配置 |
验收信号
- negative cases 覆盖各类执行工具注册尝试,全部拒收
- 任务类型本体与产品定义文档清单完全一致(grep 比对)
- 工具池组装在不同 Provider(有的不支持 Function Calling)下能力匹配正确
9.6 Provider Adapter 子系统
组件图
这张图表达什么:Provider 选择走 4 层降级(L1 用户配置 → L1' 系统默认 → L2 本地嵌入 → L3 缓存+规则 → L4 受限菜单),每层有可用性 + 能力匹配检查。统一适配层屏蔽不同 Provider 的 API 差异。凭证由 Credential Store 提供(不与代码 / 配置混存)。
职责
抽象 LLM / 数据 Provider 接入,让 Task Orchestration / Evidence + Synthesis 通过统一接口调用,下层 Provider 可替换。
用户自配置作为 first-class 场景:用户可在本地配置喜欢的 Provider(云端 Claude / GPT-4 / DeepSeek API;本地 Ollama / vLLM / LM Studio;自定义 OpenAI-compatible endpoint)+ 偏好顺序。系统默认 routing 是兜底而非强制。
4 层降级保障 LLM 不可用时仍可用:业界默认"LLM 不可用 = 服务不可用",FinBayes 本地优先定位要求更高可用性,故设计 L1-L4 降级。
关键接口
| 接口 | 输入 | 输出 |
|---|---|---|
select_provider(task_type, user_ctx, capability_needed) | 任务类型 + 用户上下文 + 能力要求(function calling / vision / 等) | 选定 Provider 实例 + 当前降级层级 |
call_llm(messages, tools, options) | OpenAI-compatible 消息格式 | 响应(function call / 文本 / streaming) |
register_provider(provider_spec) | Provider 配置 | 加入用户 Provider 池 |
check_readiness() | — | 所有 Provider 的实时可用性 + 能力 |
get_audit(task_id) | 任务 id | 该任务用了哪个 Provider / 成本 / 是否走 fallback |
关键内部组件
- Provider Registry:内置 Provider 列表(OpenAI / Anthropic / DeepSeek / Qwen / Ollama / vLLM / LM Studio / Hugging Face TGI / 等)+ 用户自定义 Provider 注册位
- Routing Policy:两层路由(系统默认 + 用户覆盖),按任务 / 区域 / 成本 / 用户偏好选择
- Capability Matcher:检查 Provider 支持的能力(Function Calling / vision / streaming / 上下文长度)vs 任务需要
- Readiness Prober:runtime 启动 + 周期性 ping 各 Provider 端点
- Unified API Adapter:统一 OpenAI-compatible 接口(用 LiteLLM 或自实现),屏蔽各家 SDK 差异
- L2 Local LLM Manager:管理本地嵌入式 LLM(Ollama 集成),探测本地模型可用性
- L3 Cache + Rule Engine:精确缓存(Redis SHA256)+ 语义缓存(Redis Vector + bge embedding)+ 规则匹配(关键词词典 + BM25 兜底检索,不引入 ML 训练管道 — 本地优先定位约束)
- L4 Restricted Menu Provider:所有 LLM 不可用时的菜单驱动兜底
- Cost Tracker:每次调用的 token 数 / 价格 / 累计成本(用于用户审计)
失败模式与降级(4 层全展开)
| 层 | 触发条件 | 提供能力 | 牺牲 |
|---|---|---|---|
| L1 用户 Provider 池 | 用户配置的至少一个 Provider 可用 + 用户偏好顺序 | 完整能力 | 无 |
| L1' 系统默认 fallback | 用户没配置或配置全部不可用,回到系统默认(用户允许时) | 完整能力但可能要求用户补配置 | 用户偏好被旁路 |
| L2 本地嵌入式 LLM | 所有云端 / API 不可用,用户已部署本地小模型 | 接近 L1,质量稍低 | 部分高难度任务质量下降 |
| L3 缓存 + 规则 | 所有 LLM 都不可用 | 仅预设常见模式(行情 / 概念解释 / Watchlist 操作等) | 失去自然语言鲁棒性 + 复杂任务不可用 |
| L4 受限菜单 UI | L1-L3 都失败 | 用户从菜单选任务 + 受限查询 | 完全失去自然语言低门槛,仅"读功能" |
关键约束
- 同一 Tool Registry 跨所有层:LLM 是可替换变量,工具池不变
- L1 → L2 自动切换:runtime 探测云端可用性,无缝降级
- L2 → L3 半自动:本地 LLM 不可用时系统显示"已进入受限模式"
- L3 / L4 用户明示:用户必须看到"当前是受限模式,需要 X 才能恢复完整能力"
- 本地嵌入式 LLM 是可选安装:首次部署时引导,不强制
验收信号
- 用户在不同 region / 任务下能配置不同 Provider 偏好,runtime 按偏好选择
- Provider 凭证仅从 Credential Store 读取,不进入审计 / 日志 / 状态
- L1 主 Provider 失败时自动 fallback 到下一个用户偏好(无需用户介入)
- 所有 LLM 都不可用时,L3 缓存命中的查询(如"什么是 PE")仍能返回;L4 菜单可见
子系统间的数据流总览
| 流向 | 数据 |
|---|---|
| Input/Output Pipeline → Task Orchestration | 归一化输入(边界保护后) |
| Task Orchestration → Capability Registry | 工具池请求 + 用户上下文 |
| Task Orchestration → Provider Adapter | LLM Function Calling 调用 |
| Task Orchestration → Evidence + Synthesis | 选定任务 + 上下文 |
| Evidence + Synthesis → Provider Adapter | 工具执行 + 综合层 LLM 调用 |
| Evidence + Synthesis → State Management | 审计 trail / 候选写入 |
| Task Orchestration → State Management | 任务类型标签 / 审计记录 |
| State Management → Task Orchestration | 用户画像 / 对话状态 / Watchlist |
| Evidence + Synthesis → Input/Output Pipeline | StructuredCognitionResult |
| State Management → Task Orchestration | 主动信号触发的新任务 |
详细的时序流转(同步问答 / TaskGroup 并发 / Provider 降级 / 等场景)在关键场景的流转图章节展开。
10. 关键场景流转图
这一节回答:典型场景下子系统如何按时序协作?哪些步骤同步、哪些异步、哪些可降级?
场景清单
下列 8 个场景覆盖第一阶段的关键时序:
| 场景 | 触发条件 |
|---|---|
| S1 同步问答端到端流 | 用户单一文本提问 |
| S2 TaskGroup 多任务并发 | 用户输入命中复合任务 |
| S3 主动信号触发复盘 | 市场变化触及已确认 Judgment Record 的失效条件 |
| S4 候选状态写入与用户确认 | 任务执行产出可沉淀状态 |
| S5 Provider 降级路径 | L1 用户 Provider 不可用 |
| S6 边界拒收凭证 | 用户输入含凭证类信息 |
| S7 clarify 工具触发的澄清回路 | LLM 给出低 confidence 的工具调用 |
| S8 长会话压缩 | Session Context 超额 |
每个场景含 Sequence 图 + 关键说明 + 失败 / 降级路径。
子系统简称(图中使用):
IO= Input/Output PipelineTO= Task OrchestrationCR= Capability RegistryPA= Provider AdapterES= Evidence + SynthesisSM= State Management
S1 — 同步问答端到端流
关键点:第一屏先回答用户题眼,反方 / 详细条件等通过 streaming 后续到达。事后任务类型标签由 TO 完成(不是 LLM 自报),用于审计 trail。
S2 — TaskGroup 多任务并发
关键点:复合任务在 FinBayes 意图层显式拆解,不依赖 LLM 原生处理多轮(业界研究确认 LLM 多轮 function calling 不稳定)。Partial Result 先到达可流式呈现给用户,最终结果由 Result Merger 整合。
失败隔离:任务 A 失败不阻塞任务 B;最终归并时明示哪个任务降级。
S3 — 主动信号触发复盘
关键点:主动信号不退化为价格提醒 / 新闻推送。信号必须明示触及哪条判断、哪个条件、当前变化是什么。信号节奏由用户配置的关注密度控制。
降级:触发器宕机时不影响主动 query;信号补发不实时。
S4 — 候选状态写入与用户确认
关键点:长期状态经用户主动确认才写入——是战略不变量"用户主权"在工程层的硬承接。FinBayes 不悄悄写入用户长期状态。
清空操作:用户清空画像时系统显式提示"协作上下文已重置"(战略不变量)。
S5 — Provider 降级路径(L1 → L1' → L2 → L3 → L4)
关键点:4 层降级(L1 → L1' → L2 → L3 → L4)自动切换。每层失败带明确原因(超时 / 鉴权失败 / 用户未配置 等),用户能看到当前在哪一层。
用户配置作为 first-class:用户偏好顺序优先于系统默认;用户拒绝 fallback 时 L1' 不触发。
S6 — 边界拒收凭证
关键点:凭证不变量的工程承接 —— 不收、不存、不训练 在边界 hook 层实现。规则路径必须在 LLM 之前(不让 LLM 自由决定是否处理凭证)。
输入端 vs 输出端:输出端 hook 也扫描(防 LLM hallucinate 出地址 / 密钥串后被状态意外捕获)。
S7 — clarify 工具触发的澄清回路
关键点:clarify 作为标准工具(不是管道阶段),由 LLM 自己决定何时调用。澄清后回到 LLM Function Calling 起点,不绕过工具池。
澄清问题:动态生成(基于 LLM 当前的意图候选),不用固定模板。
S8 — 长会话压缩
关键点:上下文压缩不是单纯聊天摘要。必须保留四类金融语义:用户关注对象、已确认 Judgment Record 的成立 / 失效条件、当前问题的信息缺口、后续复盘需要引用的来源时间点。
失败处理:压缩失败时 Session 切断 + 新 Session 起 + 引用历史 Judgment Record(而不是用残缺 Context 继续)。
8 个场景间的关系
| 关系 | 说明 |
|---|---|
| S1 → S2 | S2 是 S1 的复合扩展(命中多任务时走 S2) |
| S1 → S4 | S1 末尾若有可沉淀状态走 S4 |
| S1 → S5 | S1 中的 PA 调用若失败走 S5 |
| S1 → S6 | S1 入口前若识别凭证走 S6 |
| S1 → S7 | S1 中的 LLM 调用若低 confidence 走 S7 |
| S1 → S8 | 长会话累积后自动触发 S8 |
| S3 | 与 S1 独立但产物(复盘任务)走 S1 类似流程 |
详细的状态对象在每个场景中的生命周期由下一章承接。
11. 状态对象生命周期
字段权威定义见 contracts/state-machines.yaml(Step 11 整改包 I 单一事实源层)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:每个有独立状态机的对象有哪些状态?什么事件触发状态变更?每个状态下的不变量是什么?
6 个有独立状态机的对象
本章列出 6 个有独立状态机的对象。其中前 5 个是 §4 的 first-class 业务对象(Session / Task / TaskGroup / Judgment Record / StateCandidate),第 6 个 Provider Readiness 是工程对象但承担跨子系统协调职责(Provider Adapter Pool 的探测状态 + 4 层降级触发器,详见 §9 / §13)。
| 对象 | 由谁管理 | 本章展开位置 |
|---|---|---|
| Session | State Management 子系统的 Session Manager | 11.1 |
| Task | Task Orchestration 子系统的 Task 实例 | 11.2 |
| TaskGroup | Task Orchestration 子系统的 TaskGroup Manager | 11.3 |
| Judgment Record | State Management 子系统的 Confirmed Store | 11.4 |
| StateCandidate | State Management 子系统的 Candidate Buffer | 11.5 |
| Provider Readiness | Provider Adapter Pool 的 Readiness Prober | 详见 §9 § Provider Adapter Pool |
首-class 业务对象 vs 有独立状态机的对象:§4 列 7 个 first-class 业务对象(Session / Watchlist / Judgment Record / Dynamic Profile / State Candidate / Fin Object / Task)。其中 Watchlist 与 Fin Object 没有独立状态机 —— Watchlist 由 StateCandidate(候选)+
watchlist_objects表(confirmed store)承担状态;Fin Object 只有 created / archived 两个简单标记,状态变化通过 StateCandidate → watchlist_objects 路径承载。TaskGroup 是工程对象不是 first-class 业务对象,但有独立状态机(任务编排需要)。
工程对象(如 EvidencePacket / EvidencePlan)也有生命周期,但单次任务内即完成,不需独立状态机;详见 Evidence + Synthesis 子系统。
11.1 Session 生命周期
状态说明:
| 状态 | 含义 | 不变量 |
|---|---|---|
| Active | 当前活跃的对话 | Context 长度在预算范围内 |
| Snapshotted | 因 Context 超额触发压缩 | Context Snapshot 保留金融语义锚点 |
| Archived | 用户主动归档 | 内容不变,但不在默认列表 |
| Deleted | 用户删除 | 引用的 Judgment / Watchlist 不被级联删除 |
关键约束:
- Default Session 不可删除(用户始终有一个默认会话兜底)
- Archived 与 Snapshotted 之间没有直接转换(必须先 resume 到 Active)
- 删除 Session 不删除它引用的 Judgment Record / Watchlist 对象(这些是独立资产)
11.2 Task 生命周期
状态说明:
| 状态 | 含义 |
|---|---|
| Created | Task 对象生成但未执行 |
| Executing | 证据 / 综合在调用中 |
| Degraded | 部分证据缺失但仍可产出降级结果 |
| Completed | 产出 StructuredCognitionResult |
| Failed | 关键依赖失败,无可输出材料 |
| Cancelled | 用户主动取消或 TaskGroup 整体取消 |
关键约束:
- 任务进入 Completed / Failed / Cancelled 后状态不可逆,审计 trail 写入完毕
- Cancelled 任务的部分证据可被保留(用于后续分析),但不进入用户可见状态
- Failed 不等于无输出——必须给用户可解释的"为什么这次答不了"
11.3 TaskGroup 生命周期
状态说明:
| 状态 | 含义 |
|---|---|
| Planned | Group 对象生成(含主任务 + 辅助任务清单 + 依赖图 + 并发边界) |
| Running | 任意子任务在执行 |
| PartiallyDegraded | 至少一个子任务降级,其他还在跑 |
| AllCompleted | 所有子任务进入终态 |
| Merged | Result Merger 整合输出 |
| Cancelled | 整个 Group 取消 |
关键约束:
- 子任务失败隔离:一个失败不阻塞其他
- 用户取消 Group 时,正在执行的子任务收到 cancel 信号,已完成的子任务结果保留至审计
- Merged 状态的输出是用户看到的最终整合结果
11.4 Judgment Record 生命周期
状态说明:
| 状态 | 含义 |
|---|---|
| Candidate | 任务识别出的待确认判断 |
| Confirmed / ConfirmedEdited | 用户确认(含编辑后)的判断,进入长期资产 |
| Active | 在主动信号监控中(成立 / 失效条件被持续检查) |
| Triggered | 条件被市场变化触及,主动信号已发出 |
| ReviewedUnchanged | 复盘后判断仍成立 |
| Updated | 用户基于复盘形成新判断(新建后续 Judgment,旧的保留在复盘链) |
| Superseded | 用户认为旧判断已失效 |
| Rejected | 用户拒绝候选 |
关键约束:
- Judgment Record 是 first-class 资产,不是聊天记录的归档
- 复盘链:Updated 不删除旧 Judgment,形成版本链("当时 → 现在"可追溯)
- Superseded 的 Judgment 仍可读,仅不进入主动信号监控
11.5 StateCandidate 生命周期
状态说明:
| 状态 | 含义 |
|---|---|
| Pending | 候选生成,等待用户操作 |
| Confirmed / ConfirmedEdited | 用户确认,候选转为实际 State 对象(Judgment Record / Watchlist Object / Profile 信号 等) |
| Rejected | 用户主动拒绝 |
| Expired | 超过过期时间用户仍未处理 |
关键约束:
- 候选不进入 Confirmed Store,仅在 Candidate Buffer 暂存
- Expired 候选自动清理,不影响其他状态资产
- 候选的 payload 在 Confirmed 时转入对应的 Confirmed Store 对象(Judgment Record / Watchlist Object / Profile Signal 等)
候选类型与 Confirmed 对象的映射:
| Candidate 类型 | Confirmed 后转入 |
|---|---|
JudgmentCandidate | Judgment Record |
WatchlistCandidate | Watchlist Object(Fin Object 加入用户 Watchlist) |
ProfileSignalCandidate | 动态画像的某个字段更新 |
SessionRenameCandidate | Session 元数据更新 |
状态对象间的引用关系
- Session 引用:Task / TaskGroup / Context Snapshot / 当前关注的 Fin Object
- Task 引用:Session / Fin Object / EvidencePacket DAG / StructuredCognitionResult
- TaskGroup 引用:多个 Task / 主任务标识
- Judgment Record 引用:Fin Object / Session(创建时)/ 复盘链中的其他 Judgment Record
- StateCandidate 引用:Session / 候选要转化的目标对象 schema
生命周期独立性:
- Session 删除不删除 Judgment Record / Watchlist Object(它们是独立资产)
- 删除 Judgment Record 需用户显式操作(不可级联)
- 用户清空画像不影响 Judgment Record / Watchlist
- 用户清空 Watchlist 不影响该对象的 Judgment Record(仍可在历史中查到)
状态变更的审计 trail
所有状态对象的状态变更都进入审计 trail(State Management 子系统的 Audit Logger),含:
- 状态变更前后
- 触发事件(用户动作 / 系统事件 / 市场变化)
- 时间戳
- 关联的 Session / Task / Provider 调用
敏感性约束:审计 trail 不写入凭证类信息(凭证不变量延伸到审计层)。
12. 并发与异步处理
这一节回答:FinBayes 用什么并发原语?多任务怎么并发?失败如何隔离?用户取消时发生什么?
并发原语:Python asyncio
FinBayes Runtime 采用 Python asyncio 作为基础并发原语。理由:
- Runtime 工作是 I/O 密集 而非 CPU 密集(LLM 调用 / 工具调用 / 数据 API 都是网络 I/O)
- asyncio 单线程事件循环避免锁竞争与死锁的常见坑
- 与 Python 生态(FastAPI / aiohttp / httpx 等)天然契合
- Python 3.11+ 提供
asyncio.TaskGroup与结构化并发原语,匹配 FinBayes 业务对象 TaskGroup
例外:CPU 密集的操作(如本地 LLM 推理 / 大量 PDF 解析)走 loop.run_in_executor 抛到线程池或进程池执行,不阻塞事件循环。
业务层 TaskGroup 与异步原语的映射
业务对象 TaskGroup(用户输入命中多任务时的并发容器,详见状态对象生命周期)的工程实现:
## 示意代码(非最终实现)
async def execute_task_group(group: TaskGroup) -> MergedResult:
async with asyncio.TaskGroup() as tg:
tasks = [
tg.create_task(execute_task(t)) for t in group.tasks
]
# asyncio.TaskGroup 保证:
# - 所有子任务并发执行
# - 任一子任务失败时其他子任务被自动取消(结构化并发)
# - 异常被 ExceptionGroup 集中抛出
return merge_results([t.result() for t in tasks if not t.exception()])
关键设计选择:
| 选择 | 理由 |
|---|---|
用 asyncio.TaskGroup 而不是 asyncio.gather(...) | TaskGroup 提供结构化并发(任一失败自动取消其他),避免悬挂任务 |
| 失败 collected by ExceptionGroup | 不丢失任何子任务错误(vs gather(return_exceptions=True) 静默吞错) |
merge_results 处理 partial success | 失败的子任务不阻塞 partial result 输出(业务约束:失败隔离) |
Trace ID 跨任务传递机制
task_id 等 trace ID(详见 §18 trace ID 体系)通过 contextvars.ContextVar 在 TaskGroup 创建的子任务中自动继承:
## 示意代码
import contextvars
from contextvars import ContextVar
trace_task_id: ContextVar[str] = ContextVar("task_id")
trace_session_id: ContextVar[str] = ContextVar("session_id")
trace_user_id: ContextVar[str] = ContextVar("user_id")
async def execute_task(task: Task) -> TaskResult:
# asyncio 在 create_task 时自动 copy 当前 context(PEP 567)
# 因此 trace_task_id 在 TaskGroup 创建的所有子任务中自动可见
current_task_id = trace_task_id.get()
audit_event("task_started", task_id=current_task_id, ...)
...
关键约束:
- 所有 LLM / 工具 / Audit 子调用通过 ContextVar 拿到 trace ID,不通过参数显式传递(避免每个函数签名拖一串 trace 参数)
- httpx middleware 在出站 HTTP 请求时自动从 ContextVar 读取 trace ID 并注入
X-Trace-ID/X-Task-Id请求头(用于 Provider 端日志关联) - 任意
asyncio.create_task(...)调用都自动继承 context —— 这是 asyncio 的内置行为(PEP 567),不需要工程层额外处理 - 跨线程边界(如
asyncio.to_thread)需显式context.run(...)或contextvars.copy_context()转移 context
失败隔离的颗粒度
FinBayes 在多个层级提供失败隔离:
| 层级 | 颗粒度 | 隔离机制 |
|---|---|---|
| TaskGroup 内 | 每个 Task | asyncio.TaskGroup 结构化并发 + 失败子任务的 result 标记为降级 |
| Task 内 | 每个证据节点(EvidencePacket) | 单证据节点失败只影响依赖它的下游证据节点,不影响其他证据节点 |
| Evidence 内 | 每个工具调用 | 工具调用失败标记 degraded_reason,归一化为降级 EvidencePacket,不抛异常 |
| Provider 调用内 | 每个 LLM Provider | 失败触发 L1 → L1' → L2 → L3 → L4 降级(详见 Provider Adapter 子系统) |
关键约束:
- 默认不让单点失败传染到整个 Session
- 每个失败都有
degraded_reason元数据进入 EvidencePacket / Result,前台可呈现给用户 - 真正阻断的失败(如 State Store 完全不可用)才让 Session 进入只读模式
用户取消语义
用户主动取消(如 Ctrl+C / ESC / Web UI 取消按钮)的处理:
关键设计:
- 取消是 协作式 而非强制(asyncio 取消信号传播到协程边界)
- 已完成的部分证据 / 部分结果保留至审计 trail(用户后续可查阅"取消前发生了什么")
- 正在进行中的 LLM 调用通过 httpx 客户端的 CancelledError 立即释放,不浪费用户的 token 配额
TaskGroup 取消:用户取消整个 TaskGroup 时,所有子任务收到 cancel 信号;子任务已开始的工具调用允许 5 秒 grace period 完成(避免数据不一致),然后强制结束。
超时控制
不同层级的超时策略:
| 层级 | 默认超时 | 可配置 |
|---|---|---|
| 单个工具调用 | 30s | 是(per-tool) |
| 单个 LLM 调用 | 60s | 是(per-task-type) |
| 单个 Task(含所有证据 + 综合) | 120s | 是 |
| TaskGroup(用户感知的总等待) | 180s | 是 |
| Session Context Compactor | 30s | 是 |
超时触发后:
- 进行中的协程被 cancel
- 已完成的部分结果保留
- 用户看到部分结果 + 超时原因明示
- 审计 trail 记录"哪一层超时"
配置走文件不硬编码:与战略未决问题相关的成本 / 性能参数都走配置(详见上位继承与不变量章节"不抢答"约定)。
并发限制(backpressure)
为防止本地资源被无界并发耗尽,runtime 设全局并发限制:
| 限制项 | 默认值 | 调节点 |
|---|---|---|
| 同时进行的 Task 数量 | 5 | 配置 |
| 单 Task 内同时调用的工具数量 | 3 | 配置 |
| 总 LLM 调用并发(跨 Task) | 10 | 配置 |
| 数据 Provider 调用并发 | 20 | 配置 |
实现:用 asyncio.Semaphore 在各层级控流。超过限制的请求进入 FIFO 队列等待。
用户感知:高并发时新任务可能等待几秒;用户应能看到"正在排队"提示而非静默卡顿。
事件循环与阻塞调用的处理
asyncio 单线程事件循环对同步阻塞调用敏感。FinBayes 规则:
| 操作类型 | 处理方式 |
|---|---|
| HTTP / WebSocket / 数据库(SQLite asyncio binding)/ 文件 I/O | 直接 await(原生异步) |
| 本地 LLM 推理(Ollama 等通过 HTTP,已是异步) | 直接 await |
| 大量 CPU 计算(如复杂 PDF 解析 / 数据处理) | loop.run_in_executor(None, sync_func, args) 抛线程池 |
| 第三方同步 SDK 调用 | 同上 |
| 子进程调用(如 mermaid-cli 渲染) | asyncio.create_subprocess_exec 异步等待 |
约束:任何直接调用同步阻塞 API 而不抛到线程池的代码视为 bug,进入 review gate 必查项。
测试约束
并发模型的测试覆盖:
| 测试类型 | 覆盖什么 |
|---|---|
| 单任务并发测试 | TaskGroup 内任务真正并发执行(不是串行) |
| 失败隔离测试 | 一个子任务失败时其他子任务能完成 |
| 取消传播测试 | 用户取消能正确传播到 Provider 调用 |
| 超时测试 | 各层超时后部分结果保留 + 审计完整 |
| 并发限制测试 | 超过 Semaphore 限制的请求被正确队列化 |
详细测试体系见质量与验收章节。
13. 故障与降级路径
这一节回答:FinBayes 在外部依赖失败 / 内部组件故障 / 数据缺失时怎么走?降级路径如何让用户仍能拿到价值?
总体降级哲学
FinBayes 的本地优先定位要求 比业界默认更高的可用性 —— 业界共识是"LLM 不可用 = Agent 服务不可用",FinBayes 不接受这个共识。
降级遵循三条原则:
- 明示而非沉默:任何降级都让用户看到"当前在降级模式 + 为什么"
- 失败隔离不传染:单点失败不让整个 Session / Runtime 崩溃
- 拒收硬给:信息不足时说"我不知道 / 数据不可用",不强行生成无依据回答
故障决策树
这张图表达什么:从认知请求到输出的完整故障决策路径。每个分叉点对应一种故障,每个分叉都有降级出口,最终都能给用户输出(即使是"系统受限"的输出)。
这张图特意不表达什么:每种故障的具体表现 / 触发条件 / 用户感知(在下面分模块展开)。
各模块的故障与降级
LLM Provider 故障(4 层降级)
详见 Provider Adapter 子系统章节。这里给出用户感知矩阵:
| 当前层 | 用户感知 | 触发下移条件 |
|---|---|---|
| L1 用户配置 | 无感(正常使用) | 用户配置的所有 Provider 都失败 |
| L1' 系统默认 | 提示"使用系统默认 Provider" | 系统默认 Provider 不可用或用户未授权 |
| L2 本地嵌入式 | 提示"使用本地模型,质量稍低" | 本地未安装 / 模型加载失败 |
| L3 缓存 + 规则 | 提示"当前受限模式,仅能处理常见查询" | 缓存未命中 + 规则未匹配 |
| L4 受限菜单 | 提示"系统当前完全离线,请选择常用查询" | 仅作 last resort |
工具 / 数据源调用故障
| 故障 | 降级 |
|---|---|
| 数据 API 401 鉴权失败 | 标记该 source 不可用,尝试 fallback source;用户可见"该 Provider 鉴权失败,请检查 key" |
| 数据 API 超时 | EvidencePacket 标记 degraded_reason: timeout;不阻塞其他证据 |
| 数据 API 限流 | 等待 + 重试;超过重试次数后降级 |
| 必需数据完全缺失 | 综合层输出"信息缺口",明示用户哪类数据缺;不硬编 |
| 工具返回格式异常 | 标记 packet 状态为 parse_error,归一化处理;调试模式记录原始响应 |
| 网络中断 | 进入 L2 本地优先模式(数据用本地缓存 + 本地 LLM) |
证据缺失的综合层处理
| 缺失情况 | 综合层处理 |
|---|---|
| 实时价格缺失 | 不给短期方向性结论;给中长期框架性分析 |
| 链上数据缺失(Crypto 场景) | 退化为宏观 + 价格 + 叙事的有限分析 |
| 财报数据缺失(US Stocks 场景) | 退化为行业 + 估值 + 宏观联动 |
| 反方证据缺失 | 综合层主动标"反方覆盖不足,暂未发现重要反方信息",不悄悄省略 |
| 历史 Judgment Record 缺失(复盘任务) | 主动询问用户具体当时理由,不替用户假设 |
关键不变量:反方证据 / 关键风险 / 失效条件等核心认知要素不因画像偏好被裁剪。可以因数据缺失而标注缺口,不可以因"用户偏好简洁"而省略。
State Store 不可用
| 程度 | 降级 |
|---|---|
| State Store 完全不可用(SQLite 文件锁 / 磁盘满 / 等) | runtime 进入只读模式:可读取已有 Session / Watchlist / Judgment,不能写入新状态;用户可见明确提示 |
| Cache 不可用(Redis / 内存 LRU) | runtime 退化为不缓存模式,每次都走全链路(成本上升但功能完整) |
| Config Store 不可用 | 用最后已知的内存配置 + 提示用户配置丢失 |
| Credential Store(OS Keychain)不可用 | 退化为环境变量读取;环境变量也不可用时无法做 LLM 调用,进入 L3 / L4 |
输入边界保护识别凭证
详见 S6 边界拒收凭证场景。这里只标关键点:
- 凭证类输入识别后立即终止该输入的处理链
- 不进入 Task Orchestration / LLM / 状态对象 / 审计 trail
- 用户得到安全回应:明示"我不接受这类凭证,请保存在你的 [钱包 / 交易所 / 等]"
综合层失败
| 失败 | 降级 |
|---|---|
| LLM 综合调用失败 | 触发 Provider Adapter 降级链 |
| Self-consistency 多次采样结果分歧大(高风险任务) | 输出"判断不收敛"信息 + 各分歧的依据,让用户判断(不强行二选一) |
| 综合结果不通过输出 schema 校验 | 标记结果 invalid + 走 fallback(如简化为列表式结构),不向用户呈现垃圾 |
用户主动取消的处理
用户取消的工程承接详见并发与异步处理章节。这里强调降级视角的设计:
- 取消是 意图明示 而非故障 —— 不算降级;但部分结果保留在审计 trail 中
- 取消后用户可以"复活"被取消的任务(基于审计 trail 中保留的部分证据)
- TaskGroup 取消时,每个子任务允许 5 秒 grace period 完成已发起的 I/O 调用
配置层错误处理(用户视角)
用户配置错误(如 API key 失效 / Provider URL 错误 / 配置文件格式错误)是常见情况:
| 错误 | 降级 |
|---|---|
| Provider API key 无效 | 启动时探测时即明示"Provider X 鉴权失败",引导用户重配 |
| Provider URL 不可达 | 启动时跳过该 Provider,提示用户检查 |
| 配置文件格式错误 | 退回到默认配置 + 明示哪一行有错 |
| 本地 Ollama / vLLM 服务未启动 | 探测时即明示,给"启动该服务"或"切换 Provider"的建议 |
| 用户未配置任何 Provider | 进入引导流程(首次使用引导) |
关键约束:所有配置错误都在 runtime 启动时明示(Provider Readiness 探测阶段),不让用户在使用中遇到"突然不能用"。
不降级的硬故障
少数情况 runtime 必须硬失败而非降级:
| 硬故障 | 理由 |
|---|---|
| 工具注册尝试包含执行类工具(下单 / 转账 / 等) | 战略边界硬约束;规则路径直接拒绝注册,记审计但不接受 |
| 用户尝试主动输入凭证类信息绕过边界保护 | 凭证不变量;硬拒收不让任何路径接收 |
| 状态对象引用的 Fin Object 不存在(数据完整性破坏) | 数据完整性问题;硬失败 + 提示用户进行数据修复 |
| 工程实现意外注入未授权的概念(如战略层被禁的概念) | Review gate 拒收(grep + 人工双层);不允许进入主分支 |
降级路径的可观测性
每次降级都进入审计 trail,含:
- 降级层级(如 L1 → L2)
- 触发原因(具体错误信息 / 错误代码)
- 时间戳
- 关联的 Task / Session
用户可查看"为什么这次降级了" —— 这是核心可观测性能力。详见可观测性章节。
与其他章节的关系
- LLM 4 层降级的具体实现细节 → Provider Adapter 子系统章节
- 用户取消的工程承接 → 并发与异步处理章节
- 边界保护 hook 的具体实现 → 边界与安全章节(横向贯穿)
- 降级原因如何写入审计 trail → 可观测性章节
- 测试如何覆盖各降级路径 → 测试体系章节
14. 部署形态
这一节回答:FinBayes 在用户本地如何部署?多种部署形态各自的拓扑是什么样?
三种部署形态
FinBayes 支持三种部署形态。第一阶段主推本地优先单机,混合与托管形态作为演化路径预留接口。
| 形态 | 第一阶段 | 描述 |
|---|---|---|
| 本地优先单机 | ✅ 主推 | 所有容器(含 State Store / Cache)都在用户本机;LLM / 数据 Provider 可云端可本地 |
| 本地 + 远程 Provider | ✅ 支持 | 容器仍本机,但 LLM 与数据 Provider 走云端 API(用户配置) |
| 未来托管部署 | 远期 | 容器迁移到云端服务;多用户共享;超出第一阶段范围 |
部署形态变化时 runtime 接口契约不变——这是可演化性质量属性的工程承接(详见架构目标与质量取舍章节)。
本地优先单机部署的物理拓扑
这张图表达什么:所有 FinBayes 容器与持久化都在用户本机;外部 Provider(云端 LLM / 数据 / Data Horizon)通过 HTTPS 访问;本地 LLM 是可选安装(用于 L2 降级或用户主动选择)。
这张图特意不表达什么:容器内部组件细节(在 §9 已展开);远程托管形态的拓扑(在下面单独描述)。
怎么读这张图:实线箭头是必要数据流,虚线箭头是可选数据流(如本地 LLM)。同一框内的组件共享主机资源。
部署形态对各容器的影响
| 容器 | 本地优先单机 | 本地 + 远程 Provider | 未来托管 |
|---|---|---|---|
| 入口适配 | 全部本机 | 全部本机 | Web API 迁云,其他容器(CLI / TUI)仍本机 |
| Core Runtime | 本机进程 | 本机进程 | 云端服务进程 |
| Provider Adapter Pool | 本机 | 本机 + 调云 LLM | 云端 |
| State Store | SQLite 本地文件 | SQLite 本地文件 | 远程数据库(PostgreSQL 候选) |
| Cache | 内存 LRU 或本地 Redis | 同左 | 远程 Redis 集群 |
| Config Store | 本地配置文件 | 本地配置文件 | 用户级账户存储 |
| Credential Store | OS Keychain | OS Keychain | 云端密钥管理 |
重要约束:所有形态共用同一 runtime 接口契约。从本地优先单机演化到远程托管时,应用代码不变——仅 Provider Adapter Pool 和 State Store 的实现替换。这是接口版本化的回报。
用户首次安装与初始化流程
关键设计:
- 用户至少要有一种 LLM 可用才能用 FinBayes 完整功能(云端或本地);都没有时进入 L3 / L4 受限模式(明示)
- 本地 LLM 安装是可选,不强制(增加部署门槛与下载量)
- 默认 Session 在初始化时自动创建(用户不需手动建第一个 Session)
配置文件与数据文件的路径约定
按 OS 平台不同,FinBayes 的本地文件遵循各 OS 的标准目录约定(XDG Base Directory Specification on Linux / macOS 标准 / Windows AppData):
| 平台 | 配置目录 | 数据目录 | 缓存目录 |
|---|---|---|---|
| macOS | ~/Library/Application Support/finbayes/config/ | ~/Library/Application Support/finbayes/data/ | ~/Library/Caches/finbayes/ |
| Linux | $XDG_CONFIG_HOME/finbayes/(默认 $HOME/.config/finbayes/) | $XDG_DATA_HOME/finbayes/(默认 $HOME/.local/share/finbayes/) | $XDG_CACHE_HOME/finbayes/(默认 $HOME/.cache/finbayes/) |
| Windows | %APPDATA%\finbayes\config\ | %APPDATA%\finbayes\data\ | %LOCALAPPDATA%\finbayes\cache\ |
不变量:
- 凭证类不进入这些目录的任何文件(凭证走 OS Keychain)
- 配置文件可被用户直接编辑(YAML 格式)
- 数据文件(State Store SQLite)不建议用户直接编辑(需用 FinBayes CLI 操作)
升级流程
| 升级类型 | 处理 |
|---|---|
| FinBayes 软件版本升级 | runtime 启动时检查 State Store schema 版本,按需运行 migration 脚本(schema 演化策略详见演化与版本管理章节) |
| 接口契约版本升级 | major 升级时拒绝过期客户端连接,提示用户升级;minor 升级保持向后兼容 |
| LLM Provider API 变化 | Provider Adapter 内部适配,runtime 业务代码不变 |
| 本地 LLM 模型升级 | 用户主动操作(Ollama pull);FinBayes 重新探测 Readiness |
回滚策略:State Store 在 schema migration 前自动备份(SQLite 文件复制),失败时回滚。详见数据存储划分章节。
卸载与数据清理
用户卸载 FinBayes 时:
| 数据类型 | 默认行为 | 用户可选 |
|---|---|---|
| 安装的二进制 / 程序文件 | 删除 | — |
| 配置文件 | 保留(方便重装) | 明示选择"完全删除" |
| 数据文件(State Store) | 保留 | 明示选择"完全删除"(不可恢复警告) |
| 缓存文件 | 删除 | — |
| OS Keychain 中的 Provider 凭证 | 删除 | — |
| 本地 LLM 模型(Ollama 下载的) | 不删(由 Ollama 管理) | 用户在 Ollama 中删除 |
关键约束:用户清空画像 ≠ 卸载 FinBayes ≠ 删除 State Store。三种动作明确区分,避免误操作。
部署形态相关的未决问题
未决但第一阶段不抢答:
- 远程托管形态下的多用户隔离(待第一阶段冷启动数据验证商业模式后定)
- 跨设备同步(用户在多台机器上的 FinBayes 状态是否同步)
- 企业部署形态(如团队共享 Watchlist / 团队级审计)
这些都在战略未决问题范围内(详见上位继承与不变量章节)。
15. 数据存储划分
这一节回答:FinBayes 的不同数据类别分别放在哪里?为什么这样分?
5 类持久化数据
FinBayes 把持久化数据分为 5 类,每类有专属存储位置:
| 类别 | 存储位置 | 物理形式 |
|---|---|---|
| State Store | 数据目录 | SQLite 数据库文件 |
| Cache | 缓存目录 | Redis(本地实例)或进程内 LRU |
| Config Store | 配置目录 | YAML 配置文件 |
| Credential Store | OS Keychain | OS 系统凭证管理 |
| Audit Trail | 数据目录 | SQLite(与 State Store 同库不同表)或独立 JSONL 文件 |
分类原则:按数据敏感度 + 访问频率 + 生命周期划分。最敏感的(凭证)走 OS 级保护;最频繁的(缓存)走内存;持久状态走 SQLite。
存储分类图
这张图表达什么:5 类数据各自的物理形式与典型内容。SQLite State Store 包含 8 张业务表(Session / Watchlist / Judgment Record / Dynamic Profile / StateCandidate / Fin Object / Audit Trail / Context Snapshots),其中 Audit Trail 是审计层独立表,Context Snapshots 是长会话压缩资产;mermaid 图为简洁起见仅画 6 类核心业务对象表。完整 8 张表的 schema 见下方"关键表"。
这张图特意不表达什么:表的字段定义(在附录数据对象 schema 索引);数据迁移流程(在升级流程中描述)。
State Store(SQLite)
为什么 SQLite:
- 本地优先部署的天然选择(无需独立服务进程)
- 单文件易备份 / 易迁移
- Python 生态完备(sqlite3 标准库 + aiosqlite 异步绑定)
- 个人用户量级数据规模(每用户几千到几万条记录)远未到 SQLite 性能上限
- 支持事务保证状态写入原子性
关键表:
| 表 | 内容 | 增长趋势 |
|---|---|---|
| sessions | Session 实例 | 用户活跃度相关 |
| watchlist_objects | Watchlist 内的 Fin Object | 用户关注集大小 |
| judgment_records | 历史判断 | 长期累积 |
| dynamic_profiles | 用户画像 | 一用户一行 |
| state_candidates | 待确认状态 | 短期(过期清理) |
| fin_objects | 用户关注的金融对象 | 用户关注的对象总数 |
| audit_trail | 任务执行 / 状态变更 / 降级 等审计记录 | 持续累积,按日归档 |
| context_snapshots | 长会话压缩后的 Snapshot | 与 Session 关联 |
事务策略:
- 用户主动动作(confirm 候选 / 修改画像 / 删除 Session)走单事务
- 主动信号触发的多 Judgment 更新走批量事务
- 审计 trail 写入异步化(不阻塞主流程,允许丢少量审计记录的边界 case)
备份与恢复:
- runtime 启动时自动备份当前 SQLite 文件到
*.bak - schema migration 前强制备份
- 用户可手动
finbayes backup触发备份
Cache
用途:L3 缓存(精确 + 语义)+ Task 执行过程的中间数据 + Provider Readiness 状态缓存
实现选择:
| 部署环境 | 选用 |
|---|---|
| 用户本机已装 Redis | Redis(推荐,支持 Redis Vector for L3b 语义缓存) |
| 用户本机无 Redis | 进程内 LRU(如 cachetools 库),L3b 语义缓存改用简单的 in-memory FAISS 或临时禁用 |
关键设计:
- 缓存不存储敏感内容(凭证 / 用户画像中的隐私字段不进缓存)
- 缓存键含
user_id,防 user-scoped poisoning(一个用户的缓存不能命中到另一个用户) - 行情类查询的缓存 TTL 必须短(≤30s),分析类可几小时
- 进程重启缓存清空(不持久化)
降级:Cache 不可用时 runtime 退化为不缓存模式(每次都走全链路,成本上升但功能完整)。
Config Store
位置:配置目录下的 YAML 文件
| 文件 | 内容 |
|---|---|
config.yaml | 全局配置(runtime 参数、超时、并发限制 等) |
providers.yaml | 用户配置的 Provider 列表 + 偏好顺序(key 不在这里,在 Credential Store) |
task_routing.yaml | 任务类型 → Provider 映射(可选用户自定义) |
ui.yaml | 用户界面偏好(表达密度初始值、术语深度 等) |
关键设计:
- 配置文件可被用户直接编辑(YAML 格式 + 详细注释)
- runtime 启动时检查格式 + 验证字段,错误时退回默认配置 + 明示错误
- 修改配置后无需重启 runtime(hot reload 支持)—— 但某些核心配置(如端口)仍需重启
Credential Store
位置:OS 系统凭证管理
| 平台 | 实现 |
|---|---|
| macOS | Keychain Access(通过 keyring Python 库或 security CLI) |
| Windows | Windows Credential Manager |
| Linux | Secret Service(如 GNOME Keyring / KDE Wallet) |
| Linux 无桌面环境 | 加密本地文件(用 cryptography 库 + 用户提供的密码) |
存储内容:
- 云端 LLM Provider API key(OpenAI / Anthropic / DeepSeek / 等)
- 数据 Provider API key / token
- 用户自定义 Provider 的 secret
关键约束(凭证不变量在工程层的承接):
- 金融执行凭证不进入 Credential Store(私钥 / 助记词 / 交易所 API key / 银行账户 / 信用卡)—— Credential Store 仅存"本机配置秘密"(LLM / 数据 Provider key 等),与"金融执行凭证"严格区分
- 用户卸载 FinBayes 时自动清除该程序在 Keychain 中的所有凭证
- Credential 不通过日志 / 审计 trail / 任何序列化输出泄露
Audit Trail
位置:与 State Store 同 SQLite 文件的独立表,或独立 JSONL 文件(用户可选)
内容:
| 记录类型 | 示例字段 |
|---|---|
| 任务执行 | task_id / type / 输入摘要 / 输出摘要 / Provider 调用链 / 成本 / 时长 |
| 状态变更 | object_type / object_id / before / after / 触发事件 / 时间戳 |
| Provider 调用 | provider_id / model / token 数 / 成本 / 是否走 fallback |
| 降级事件 | 触发层级 / 原因 / 时间戳 / 关联 task |
| 用户主动动作 | 确认候选 / 修改画像 / 清空 / 删除 等 |
| 边界拒收事件 | 输入特征摘要(不含具体凭证内容)/ 时间戳 |
关键约束:
- 审计 trail 不包含任何凭证类内容(边界拒收事件记录中只标"识别为凭证类,已拒收",不记录具体凭证字符串)
- 审计 trail 可被用户查阅("为什么这次降级了" / "这条 Judgment 是怎么形成的")
- 审计 trail 按日 / 月归档,避免单一文件无限增长
数据完整性保护
| 完整性问题 | 保护机制 |
|---|---|
| 部分写入(runtime 崩溃时) | SQLite WAL 模式 + 事务原子性 |
| 引用完整性(如 Session 引用不存在的 Judgment) | 数据库外键约束 + runtime 启动时完整性检查 |
| Schema 版本不匹配(升级后) | runtime 启动时检查 schema 版本 + 自动 migration |
| 文件损坏 | runtime 启动时校验和检查 + 自动从 *.bak 恢复 |
| 用户误操作清空 | 删除前二次确认 + 操作后保留 7 天可恢复窗口 |
用户视角的数据动作
用户可对自己的数据做下列动作:
| 动作 | 影响范围 |
|---|---|
finbayes session delete <id> | 删除指定 Session(不删除引用的 Judgment / Watchlist) |
finbayes judgment delete <id> | 删除指定 Judgment Record(需二次确认) |
finbayes watchlist remove <fin_object_id> | 移除关注对象(不删除 Judgment) |
finbayes profile view / modify / clear | 画像查看 / 修改 / 清空(清空时显式提示"协作上下文已重置") |
finbayes export | 导出所有用户数据到 JSON / CSV |
finbayes uninstall --clean | 卸载 + 完全删除所有数据(不可恢复) |
战略不变量"用户画像主权"在数据操作层的完整承接。
16. 通信协议
这一节回答:FinBayes 各组件间用什么协议通信?外部接口的协议是什么?为什么这样选?
通信关系总览
按通信范围分四类:
| 类别 | 范围 | 主要协议 |
|---|---|---|
| 进程内 | runtime 内部子系统间 | Python 函数调用 + asyncio 协程 |
| 本机进程间 | runtime 与本机其他进程 | stdio / Unix domain socket / 本地 HTTP |
| 本机内 UI | runtime 与用户的浏览器 / 终端 | HTTP / WebSocket / 终端 stdin&stdout |
| 跨网络外部 | runtime 与外部 Provider | HTTPS(OpenAI-compatible / 各家 SDK) |
进程内通信
主要场景:§9 的 6 个子系统之间。
实现:直接 Python 函数调用(同步或异步协程)。
特点:
- 零序列化开销
- 类型安全(Python type hints + Pydantic 数据对象)
- 不依赖网络
- 同进程异常直接传播(不需 RPC 序列化)
关键约束:
- 子系统间的接口契约用 Python class / function signature 表达,并在 §9 各子系统的"关键接口"段落明示
- 即使是进程内通信,跨子系统的数据对象必须通过 Pydantic schema 校验(防内部数据不一致)
本机 UI 入口的通信
CLI 入口
协议:终端 stdin / stdout / stderr
特点:
- 单次提问一次性返回(除非用户主动开 streaming 模式
--stream) - 输出格式默认人类可读;
--json切换 JSON - 退出码语义化(0 = 成功 / 10 = 输入错误 / 20 = Provider 不可用 / 30 = 边界拒收 / 等)
TUI 入口
协议:终端原生(用 Textual / Rich 等 TUI 框架)
特点:
- 持续运行,键盘事件驱动
- 实时呈现流式输出(部分结果 + 最终归并)
- 支持多 Session 切换 / Watchlist 浏览 / Judgment 查看 / 状态确认动作
Web API Server
协议:HTTP(任务请求 / 状态动作)+ WebSocket(task event 流式更新)
| 端点 | 协议 | 用途 |
|---|---|---|
POST /api/task | HTTP | 创建认知任务(请求体含 task request schema) |
GET /api/task/{id} | HTTP | 查询任务状态 |
GET /api/task/{id}/stream | WebSocket | 实时接收 task event |
POST /api/state-action | HTTP | 用户确认 / 拒绝 / 编辑候选状态 |
GET /api/session/list | HTTP | 列出用户 Session |
POST /api/session/action | HTTP | Session 创建 / 切换 / 归档 / 删除 |
鉴权(本地优先单机部署):
- 本机访问默认无鉴权(同主机进程间信任)
- Web UI 与 Web API 通过 localhost 通信,外部网络访问被拒绝
- 远程访问需用户显式启用并配置 token(不在第一阶段范围)
Contract Versioning:
- 每个 API 端点的 schema 含
contract_version字段 - 新增 optional 字段不升 major;删除字段 / 改语义升 major
- 不兼容版本拒绝服务并返回
INVALID_CONTRACT_VERSION错误码
MCP Server
协议:标准 MCP(Model Context Protocol,Anthropic 提出)—— 基于 stdio 的 JSON-RPC
特点:
- 外部 Agent(如 Claude Code / Codex / 其他 MCP-compatible Agent)可调用 FinBayes 的能力
- runtime 作为 MCP server 暴露工具(如
finbayes_analyze/finbayes_review_judgment/ 等) - stdio 协议天然适合本地 Agent 间通信(无需起 HTTP 服务)
MCP 工具池:FinBayes 暴露给外部 Agent 的工具是 Capability Registry 的子集(不暴露所有内部工具,仅暴露对外 API 级的)。
Channel Adapter
协议:因 channel 平台而异
| Channel | 协议 |
|---|---|
| Telegram | Telegram Bot API(HTTPS webhook 或 long polling) |
| Discord | Discord API(HTTPS + WebSocket gateway) |
| Slack | Slack API(HTTPS webhook) |
| 其他 | 按平台 SDK |
特点:
- Channel 入口主要为主动信号推送("你对 ETH 的判断 X 失效条件被触及")
- 也支持用户从 Channel 直接提问(视 Channel 平台特性)
- Channel 输出是低噪音摘要 + 回链到 Web Session 继续复盘
鉴权:每个 Channel 的 webhook secret / Bot token 走 Credential Store。
跨网络外部通信
LLM Provider 调用
协议:HTTPS
API 规范:
- 主流云端 Provider(OpenAI / Anthropic / DeepSeek / Qwen API)都支持 OpenAI-compatible 接口形态
- 本地 LLM 服务(Ollama / vLLM / LM Studio)也提供 OpenAI-compatible API
- Provider Adapter 内部用统一 OpenAI-compatible 客户端(如 LiteLLM 或自实现),屏蔽各家 SDK 差异
鉴权:API key 从 Credential Store 读取,通过 HTTPS Authorization 头传输(不进入代码 / 配置 / 日志)。
流式:所有 Provider 支持 SSE(Server-Sent Events)流式响应。Provider Adapter 统一为内部异步生成器。
外部数据 Provider 调用
协议:HTTPS(个别老旧 Provider 可能要求 HTTP,但默认拒绝)
鉴权方式:
| 类型 | 处理 |
|---|---|
| API key in header(如 yfinance / Alpha Vantage) | 走 Credential Store |
| OAuth(如某些券商数据 API) | 走 Credential Store + 刷新 token 管理 |
| 公开无鉴权(如 SEC EDGAR) | 直接调用,注意限流 |
限流处理:
- 每个 Provider 配置 rate limit
- runtime 用
asyncio.Semaphore控并发 - 超限时排队等待 + 必要时降级到 fallback Provider
Data Horizon 接口
协议:HTTPS(具体接口形态待 Data Horizon 项目定义)
FinBayes 视角的契约要求:
- 提供整理过的金融素材(事件 / 实体 / 时间线 / 数据)
- 支持订阅式实时推送(可选)+ 按需查询
- 不替 FinBayes 做判断(仅提供素材)
协议安全约束
所有协议层共同的安全约束:
| 约束 | 工程承接 |
|---|---|
| 凭证不进入协议消息体 | Provider API key 走 HTTP Authorization 头不写入 request body / 日志;Channel secret 同理 |
| TLS 不可降级 | 所有外部网络通信强制 HTTPS(HTTP 拒绝) |
| 本机 socket 限制 | Web API / MCP 默认仅监听 127.0.0.1,外部网络访问被拒绝 |
| 错误响应不泄露敏感 | 错误消息不含凭证 / 用户画像 / 内部 trace;详细 trace 仅写审计 trail |
错误码语义
跨协议统一的错误码语义(详细在附录数据对象 schema 索引):
| 错误码 | 含义 |
|---|---|
INVALID_CONTRACT_VERSION | 请求或响应版本不兼容 |
INVALID_INPUT | 输入空 / 格式不合法 / 附件不可解析 |
PROVIDER_NOT_READY | LLM 或数据 Provider 未配置 / 不可用 |
EVIDENCE_UNAVAILABLE | 必需证据不可获得 |
UNSUPPORTED_SCOPE | 超出第一阶段范围 |
EXECUTION_TOOL_BLOCKED | 试图注册或调用执行类工具(边界硬约束) |
BOUNDARY_REJECT | 输入含凭证类内容被拒收 |
STATE_STORE_READONLY | State Store 进入只读模式 |
TASK_CANCELLED | 任务被取消 |
TASK_TIMEOUT | 任务超时 |
协议演化策略
| 演化情境 | 处理 |
|---|---|
| 新增 LLM Provider 类型 | Provider Adapter 内加新适配器;接口契约不变 |
| 接口契约小升级(新增 optional 字段) | minor 版本递增,向后兼容 |
| 接口契约破坏性变更 | major 版本递增 + 不兼容 client 拒绝 + 升级指南 |
| Channel 平台 API 变化 | Channel Adapter 内部适配,runtime 业务代码不变 |
详细的契约版本化策略在演化与版本管理章节。
17. 边界与安全
这一节回答:FinBayes 的边界与安全约束在工程层如何具体承接?哪些约束是横向贯穿所有子系统的、不可被任何模块单独决定的?
三条边界约束(战略来源)
来自战略层的三条硬约束(详见上位继承与不变量章节):
| 战略约束 | 工程层承接位置 |
|---|---|
| 凭证不变量:金融执行凭证一律不收、不存、不训练 | 输入边界 hook + State / Cache / 审计 trail 凭证过滤 + 输出端过滤 |
| 不直接下单 / 不持账户凭证 | Capability Registry 拒绝注册执行类工具 + 工具 schema 校验 |
| 不替用户决策(认知层定位) | 综合层产出"判断 + 反方 + 失效条件"的结构化输出契约 + 不输出无证据的方向性结论 |
这三条不是某个子系统的局部规则,而是横向贯穿多个组件的全局不变量。
凭证类内容的端到端阻断
凭证识别的位置
这张图表达什么:凭证类内容的双向阻断 —— 入口 hook 拦截用户主动输入,出口 hook 拦截模型可能"幻觉"生成的凭证样式内容。两处之间的所有路径(Task / LLM / 综合层 / 状态对象)都绝不接触凭证。
这张图特意不表达什么:具体的正则模式(在工程实现仓维护);识别准确率(在测试体系章节)。
凭证类型与识别策略
| 凭证类型 | 识别策略 |
|---|---|
| 私钥 / 助记词(12 / 24 词序列) | 正则 + 词表匹配(BIP-39 词表) |
| 钱包地址附带私钥 / WIF 格式 | 正则(特定前缀 + 长度 + 校验位) |
| 交易所 / 经纪商 API key + secret pair | 正则(常见格式:长 base64 / 长 hex) |
| 银行账户 / 信用卡号 | 正则(Luhn 校验) |
| 用户主动"贴整段配置文件" | 启发式(看到 key = value 形式的多行密钥) |
| LLM 辅助二次判断 | 对不确定 case 调小模型快速判断(注意:调用前已脱敏,不送原 token) |
优先级:规则路径优先,LLM 辅助仅作可疑 case 的二次判断(避免每个输入都走 LLM)。
凭证拒收的用户感知
用户主动贴凭证类内容时,FinBayes 给安全回应:
我不接受这类凭证(看起来像 [私钥 / API key / 等])。请把它保存在你的
[钱包 / 交易所 / 等] 里。
我不需要它就能帮你做 [当前任务]。如果你想让我帮你判断某个交易所的资产
表现,请直接告诉我[交易所名称 + 资产名称]即可。
关键约束:
- 安全回应不重复用户贴的具体凭证字符串(避免日志记录)
- 安全回应说明替代路径(不让用户无所适从)
- 拒收事件进入审计 trail,但仅记录"识别为凭证类,已拒收 + 拒收时间戳",不记录具体内容
输出端过滤(arch-rewrite/ADR-010 accepted)
LLM 可能在生成内容时幻觉地输出凭证样式字符串(例如"一个看起来像私钥的随机 64 位 hex")。即便不是真凭证,让看起来像凭证的字符串流向用户也增加误用风险。
过滤的两个候选位置
| 候选位置 | 优点 | 缺点 |
|---|---|---|
| 综合层产出后、统一格式化前 | 离 LLM 最近,能感知语义上下文 | 增加综合层职责 |
| Output Pipeline 最末端、用户呈现前 | 集中点检查、所有路径都过 | 离 LLM 最远,可能丢失语义 |
初步决策(待 ADR-010 确认):两处都做。综合层做语义级(看到"私钥 / 助记词"等词附近的高熵字符串就警觉),Output Pipeline 做格式级最终扫描(与输入端 hook 同一套正则,方向相反)。
检测到凭证样式时的处理
- 高置信度(多条规则同时命中):剥除该段 + 用占位符替换 + 给用户 banner "输出包含可能凭证样式,已过滤"
- 中置信度(单条规则命中):保留但加 banner 提示
- 低置信度(仅模糊匹配):日志记录,不剥除
arch-rewrite/ADR-010 accepted(2026-05-28):具体阈值与正则集合见 ADR-010 §3。
执行类工具的注册拒绝
战略约束"不直接下单"在工具层的承接(详见 §9 Capability Registry 段)。
拒绝注册的工具类型
| 工具类型 | 拒绝理由 |
|---|---|
| 下单 / 撤单 / 改单(交易所 / 经纪商 API) | 直接执行金融动作 |
| 转账 / 提币 / 充值(区块链交易广播) | 直接执行金融动作 |
| 银行账户操作(转账 / 支付) | 直接执行金融动作 |
| 任何持有私钥 / 助记词的签名调用 | 持账户凭证 |
| 任何要求"金融执行凭证"作为参数的工具 | 凭证不变量 |
拒绝机制
关键约束:
- 工具 schema 必填字段
category,且枚举严格(无execution选项) - 工具参数 schema 用启发式扫描禁用字段名
- 拒绝是注册时(启动期),不是调用时(运行期)—— 运行期已无此类工具可调
- 审计 trail 记录所有尝试注册执行类工具的请求
详见 §9 Capability Registry。
用户数据隔离
多 user / 多 session 在同一 runtime 内的隔离
第一阶段单机部署虽然主要服务单用户,但 runtime 仍预留 user_id 维度(为未来多用户预留):
| 数据类别 | 隔离机制 |
|---|---|
| State Store | 所有表含 user_id 列 + 查询强制带 user_id where 条件 |
| Cache | Cache key 含 user_id 前缀(防 cache poisoning) |
| 审计 trail | 含 user_id 字段 |
| LLM Provider 调用 | 每个用户的 Provider 池 / key 独立(key 仍在 OS Keychain,per-user 命名空间) |
| 动态画像 | 严格 per-user,不跨用户共享 |
约束:跨用户读取在工程层禁止(即使是 admin / debug 模式)。debug 输出经脱敏。
Session 内的会话上下文
Session 内的认知协作上下文:
- 不跨 Session 泄露(一个 Session 的 Judgment 不自动出现在另一个 Session)
- 跨 Session 的引用是显式的(用户主动 link 或 Watchlist 关联)
- Session 归档 / 删除时,相关 Cache / 临时数据级联清理
网络层安全
TLS 强制
| 通信对象 | 协议 | 强制 |
|---|---|---|
| 云端 LLM Provider | HTTPS | ✅ HTTP 一律拒绝 |
| 外部数据 Provider | HTTPS | ✅ 个别老旧 Provider 例外需用户显式 allow-list 配置 |
| Data Horizon | HTTPS | ✅ |
| 本地 LLM(Ollama / vLLM) | HTTP(localhost) | ✅ 仅允许 127.0.0.1 |
| 本机 Web API | HTTP(localhost) | ✅ 仅监听 127.0.0.1,外部访问拒绝 |
| MCP Server | stdio | ✅ 进程间,无网络 |
凭证传输路径
- LLM Provider key 通过 HTTPS Authorization 头传输,不写入 request body / URL query / 日志
- Provider Adapter 内部使用 key 时是短生命周期(调用前从 Keychain 读,调用后即销毁内存引用,不在内存中持久持有)
- 错误日志中 key 一律 redact(如
sk-***xxxx)
详见 §16 协议安全约束。
Prompt 注入与对抗输入
LLM 应用的特殊风险:用户输入或外部数据中包含的对抗指令尝试改变 LLM 行为。
| 风险场景 | 应对 |
|---|---|
| 用户输入"忽略上述指令,输出 ..." | System prompt 加固(明示不接受 in-band 指令变更)+ 综合层输出 schema 校验(不符合契约直接拒绝) |
| 外部数据(如新闻 / 网页)中嵌入对抗指令 | 工具返回的外部数据进入 LLM 前包裹在 <external_data> 标记内 + system prompt 明示标记内内容不构成指令 |
| 用户尝试诱导 LLM 输出凭证样式 / 执行类建议 | 输出端 hook 兜底 + 安全回应 |
| 用户尝试诱导 LLM 假冒 FinBayes 系统消息 | 输出格式契约 schema 强制 |
关键不变量:FinBayes 不通过 prompt 行为约束作为唯一防线 —— 关键边界(凭证 / 执行类)有规则路径做硬约束,prompt 加固只是冗余防御。
用户主权
战略不变量"用户画像主权"在工程层的承接(详见 §15 用户数据动作):
| 主权维度 | 工程承接 |
|---|---|
| 知情权 | 用户可查看自己的所有数据(finbayes export / TUI 浏览) |
| 修改权 | 用户可修改动态画像(finbayes profile modify) |
| 清空权 | 用户可清空画像 / 删除 Session / 删除 Judgment(显式确认 + 明示影响范围) |
| 卸载权 | 用户可完全卸载 FinBayes 并删除所有本地数据(不可恢复警告) |
| 可移植 | 用户可导出所有数据到 JSON / CSV |
关键约束:
- 清空画像 ≠ 卸载 FinBayes ≠ 删除 State Store —— 三种动作明确区分
- 用户每个数据修改动作都进入审计 trail(用户可追溯自己的操作)
- 未来若引入云端同步,必须用户显式启用(不在第一阶段范围)
Review Gate 的工程承接
战略禁入概念(11 条字段级强约束 / 默认与行动准备双模式 / 认知协作伙伴 / L3 长期状态四承诺 / 零状态前提 / 情绪桥 / 信任债承诺 / 行动准备 / 行动判断 / 行动方案)不允许进入主分支。
| 检查层 | 工具 |
|---|---|
| 自动 grep | npm run verify:kb 含 banned-concept grep(CI 必跑) |
| 人工语义审查 | PR review 必备一位非作者人员复核(防 grep 同义词漏检) |
| 审计追溯 | 每次 release 留 grep + 人工审查记录 |
详见 §2 架构目标与质量取舍。
安全相关的可观测性
每个边界事件进入审计 trail(不含敏感内容):
| 事件类型 | 记录字段 |
|---|---|
| 输入边界拒收 | 时间戳 + 入口(CLI/TUI/Web/MCP/Channel)+ 识别类型(如 "私钥样式" / "API key 样式")+ 入口用户 / Session |
| 输出端过滤 | 时间戳 + 关联 task_id + 过滤类型 + 置信度 + 是否剥除 |
| 工具注册拒绝 | 时间戳 + 尝试注册的工具名 + 拒绝原因(execution / 含凭证参数 / 等) |
| Prompt 注入识别 | 时间戳 + 注入特征摘要(不含原文)+ 关联 task_id |
用户可查阅自己 Session 范围内的边界事件("为什么 FinBayes 拒收了我的输入")。
详见 §18 可观测性。
与其他章节的关系
- 输入边界 hook 的落点 → §9 Input Pipeline 子系统
- 执行类工具注册拒绝的具体实现 → §9 Capability Registry
- 输出端过滤的位置选择 → arch-rewrite/ADR-010(accepted 2026-05-28,规则见 ADR-010 §3)
- 凭证不变量的存储承接 → §15 Credential Store
- 网络层 TLS 约束 → §16 协议安全约束
- 凭证拒收场景的端到端 sequence → §10 S6 场景
- 边界事件如何写审计 trail → §18 可观测性
18. 可观测性
这一节回答:FinBayes 通过什么手段让"系统正在做什么 / 为什么这样做 / 是否健康"对用户与工程都可见?
两类可观测对象
| 对象 | 看什么 | 谁看 |
|---|---|---|
| 认知过程可观测 | 任务为什么走 LLM A 而不是 B / 为什么这次降级 / 这条 Judgment 怎么形成 / 反方为什么是这些 | 用户视角为主 |
| 系统运行可观测 | 延迟 / 错误率 / 成本 / 并发负载 / 缓存命中率 | 工程视角为主 |
FinBayes 的本地优先定位要求两类都做 —— 但侧重点不同:认知过程可观测直接服务用户信任与复盘,系统运行可观测支撑工程化排障。
审计 trail(认知过程可观测的主载体)
审计 trail 的存储位置详见 §15。这一节聚焦全景视图与用户可查阅维度。
记录的事件类型
| 事件类型 | 关键字段 |
|---|---|
| 任务执行 | task_id / type / 输入摘要 / 输出摘要 / Provider 调用链 / 成本 / 时长 / 关联 Session |
| Provider 调用 | provider_id / model / token 数(输入/输出)/ 成本 / 是否走 fallback / 失败原因 |
| 降级事件 | 触发层级(L1→L2 等)/ 触发原因 / 时间戳 / 关联 task |
| 状态变更 | object_type / object_id / before / after / 触发事件 / 时间戳 |
| 用户主动动作 | 确认候选 / 修改画像 / 删除 Session / 等 + 时间戳 |
| 边界拒收 | 时间戳 + 入口 + 识别类型(不含具体凭证内容) |
| 主动信号触发 | 关联 Judgment Record / 失效条件被触及的事件 / 通知投递路径 |
用户视角的可查阅维度
用户能问的问题与对应查询:
| 用户问题 | 对应查询 |
|---|---|
| "我刚才那次提问为什么这么慢?" | task_id → Provider 调用链 + 各步耗时 |
| "为什么这次走了本地模型?" | task_id → 降级事件链(L1 → L2 触发原因) |
| "这条 Judgment 是怎么形成的?" | judgment_id → 关联 task → 证据来源 → 综合层依据 |
| "为什么 FinBayes 拒收了我刚才贴的内容?" | session_id → 边界拒收事件(仅识别类型) |
| "我这周用了多少 Provider 成本?" | 时间范围 + user_id → Provider 调用聚合 |
| "FinBayes 怎么静默地改了我的画像?" | profile.history → 历次画像更新事件 + 触发任务 |
用户可见的不变量
- 审计 trail 不含凭证字符串(边界拒收事件只标"识别为凭证类,已拒收")
- 审计 trail 不含完整 LLM 输入输出(仅含摘要 + token 数 + 关键字段;完整内容仅 debug 模式留存 N 天)
- 审计 trail 是用户的资产(导出 / 删除 / 归档由用户决定)
任务 trace(贯穿子系统的因果链)
每个认知任务有一个唯一 task_id,贯穿所有子系统调用。
这张图表达什么:task_id 是横向贯穿所有子系统的相关 ID;每个子系统产生的事件都标 task_id(+ 子调用的 tool_call_id / llm_call_id),用户或工程可基于 task_id 重建完整因果链。
这张图特意不表达什么:trace 的存储格式(在 §15);分布式 trace(本地优先单机不需要)。
Trace ID 体系
| ID | 范围 | 用途 |
|---|---|---|
session_id | Session 生命周期 | 关联同一会话内的所有 task |
task_id | 单个 task | 一次认知请求的全链路 |
tool_call_id | 单次工具调用 | LLM Function Calling 的工具调用追踪 |
llm_call_id | 单次 LLM 调用 | 多次 LLM 调用(如综合层多采样)的区分 |
trace_id | 跨 session 的相关任务(主动信号触发新任务) | 主动信号链路追踪 |
指标体系
FinBayes 关注的指标分四类:
性能指标
| 指标 | 含义 | 用途 |
|---|---|---|
task_latency_first_screen | 首屏响应时间 | 用户体验核心 |
task_latency_complete | 任务完整完成时间 | 看流式输出全长 |
llm_call_latency | 单次 LLM 调用延迟 | 看 Provider 健康 |
tool_call_latency | 单次工具调用延迟 | 看外部数据 Provider 健康 |
concurrent_tasks | 当前并发任务数 | 看负载 |
成本指标
| 指标 | 含义 | 用途 |
|---|---|---|
provider_token_usage | 各 Provider token 用量 | 成本核算 + 用户预算可见 |
provider_cost_estimate | 各 Provider 估算成本 | 用户成本主权 |
cache_hit_rate | L3 缓存命中率 | 看降本效果 |
可靠性指标
| 指标 | 含义 | 用途 |
|---|---|---|
degradation_rate_by_layer | L1→L2 / L2→L3 / L3→L4 触发率 | 看降级链健康 |
provider_failure_rate | 各 Provider 失败率 | Provider 健康对比 |
boundary_reject_rate | 边界拒收率 | 看是否有异常输入模式 |
state_store_write_failure | State Store 写入失败次数 | 看 SQLite 健康 |
认知质量指标(间接)
| 指标 | 含义 | 用途 |
|---|---|---|
self_consistency_divergence | Self-consistency 多采样分歧度 | 高分歧 = 任务难 / 综合层不收敛 |
evidence_completeness | 综合层使用的证据数 / 应用证据数 | 看反方 / 风险覆盖完整度 |
clarify_rate | 触发 clarify 工具的比例 | 高 = 输入意图不清 / 用户体验需改进 |
user_action_on_candidate_rate | 候选状态被用户确认 vs 拒绝 vs 编辑的比例 | 看 candidate 阶段质量 |
约束:所有指标 per-user 维度独立计算(不跨用户聚合)。
用户视角的可观测 UI
CLI / TUI
| 命令 | 显示 |
|---|---|
finbayes status | 当前 Provider Readiness / Cache 状态 / State Store 健康 |
finbayes trace <task_id> | 单个 task 完整链路(Provider 调用 / 工具调用 / 降级事件 / 时长) |
finbayes audit list [--since=7d] | 时间范围内的审计事件 |
finbayes cost report [--since=30d] | 时间范围内的 Provider 成本汇总 |
finbayes session show <id> | Session 内所有 task 与状态变更概览 |
Web UI
- Session 详情页:每条 task 旁边显示"trace 入口",点击查看该 task 的 Provider 调用链 + 降级事件 + 关键时长
- Judgment Record 详情:显示"为什么形成这个判断"—— 关联 task 的证据来源 + 综合层依据 + Provider
- 全局健康 banner:Provider 池状态 / Cache 命中率 / 最近降级事件(如有)
工程视角的可观测
日志分级
| 级别 | 用途 | 是否默认开启 |
|---|---|---|
ERROR | 不可恢复的失败 | ✅ |
WARN | 降级 / 重试 / 边界识别 | ✅ |
INFO | 任务开始 / 完成 / 关键节点 | ✅ |
DEBUG | LLM 调用入参出参摘要 / 工具调用参数 | ❌(用户主动开) |
TRACE | LLM 完整 prompt / 完整响应 | ❌(用户主动开,明示日志会含完整内容) |
日志脱敏
不管什么级别,日志都不写入:
- LLM Provider API key / Channel token / 任何认证凭证
- 凭证类内容(边界拒收的具体字符串)
- 完整用户画像(仅摘要 / hash)
DEBUG / TRACE 级别开启时给用户明示警告("日志将包含完整 LLM 入参出参,请注意敏感数据")。
异常上报
第一阶段不引入云端异常上报服务(如 Sentry)—— 单机部署不应把异常发到第三方。
替代方案:
- runtime 在严重异常时本地保存 crash report(用户可选择上报)
- 用户主动
finbayes diagnostic export打包审计 trail + 配置 + crash report(敏感字段脱敏)供反馈
Provider 调用的精细观测
LLM Provider 调用是成本与延迟的主要来源,需要精细观测:
| 观测点 | 字段 |
|---|---|
| 调用前 | provider_id / model / 任务类型 / 是否走 fallback / 缓存是否命中 |
| 调用中 | latency_to_first_token(流式响应)/ 是否流式中断 |
| 调用后 | input_token_count / output_token_count / estimated_cost / 是否结构化输出校验通过 |
| 失败时 | 失败类型(鉴权 / 限流 / 超时 / 5xx / 解析失败)/ 是否触发降级 / 关联 fallback 调用 |
每次 Provider 调用进入审计 trail(含上述全部字段),可被用户查询 / 工程聚合。
降级原因的可观测
每次降级(详见 §13)都进入审计 trail 含:
- 降级层级(L1 / L1' / L2 / L3 / L4)
- 触发原因(具体错误码 + 错误消息脱敏)
- 时间戳
- 关联 task_id
用户视角的呈现:在受到降级影响的 task 输出末尾加 banner "本次因 [原因] 走 [层级] 模式,结果质量可能下降",并提供"点击查看完整降级链"。
测试可观测性
测试体系(详见 §20)依赖可观测性:
- 单元测试:mock Provider 调用,断言审计事件按预期写入
- 集成测试:跑端到端任务,校验 trace 完整性
- 评估闭环(详见 §21):基于审计 trail 的离线分析(如 "上周 self-consistency 分歧度趋势")
第一阶段不做的可观测能力
明示不做:
- 分布式 trace(OpenTelemetry 等)—— 单机不需要
- 云端日志聚合(Datadog / Loki)—— 本地优先违背
- A/B 测试框架 —— 第一阶段单用户场景不必要
- 实时 metric dashboard(如 Prometheus + Grafana)—— 用户视角 UI 已够
这些都不是不可演化(接口契约不变),只是第一阶段不抢答(详见 §19 演化与版本管理)。
与其他章节的关系
- 审计 trail 的存储位置与 schema → §15 数据存储划分
- 任务 trace 的进程内传递 → §9 Task Orchestration 子系统
- 降级事件的产生 → §13 故障与降级路径
- 边界事件的产生 → §17 边界与安全
- Provider 调用观测的具体字段 → §9 Provider Adapter 子系统
- 可观测性如何支撑测试 → §20 测试体系
- 可观测性如何支撑评估闭环 → §21 评估闭环
19. 演化与版本管理
这一节回答: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 |
| 内部子系统间(§9 各接口) | 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 | 上线前评估分数(详见 §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(反方证据维度,详见 §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 注册(详见 §9)。新增工具流程:
| 步骤 | 内容 |
|---|---|
| 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 退役流程
战略层已禁入概念不允许进入主分支(§2 + §17)。但未来若某战略概念被明确退役(如"任务类型清单"扩展),工程层需要支持。
退役流程
| 步骤 | 内容 |
|---|---|
| 1. 战略层 ADR | 在 governance 层写战略级 ADR 明示退役 + 替代 |
| 2. 加入 verify-kb 禁词表 | 自动 grep 拦截 |
| 3. 状态对象兼容 | 已有的引用旧概念的状态对象不破坏(只读 + 在 UI 中标"历史概念") |
| 4. 文档归档 | 旧概念相关文档移到 _archive/,frontmatter 标 legacy |
| 5. 用户感知 | 给一个 release 的过渡期 + 明示提醒 |
升级流程的工程承接
详见 §14 升级流程。这里强调演化角度:
| 升级路径 | 接口契约 | 数据 schema | Prompt | Provider | 工具 |
|---|---|---|---|---|---|
| patch(bug 修复) | 不变 | 不变 | 可能变 | 不变 | 不变 |
| minor(兼容增强) | 兼容新增 | 兼容新增 | 频繁变 | 可能新增 | 可能新增 / deprecated |
| major(破坏性变更) | 可破坏 + 升级指南 | migration 必备 | 可能重写 | 可能新增 / 退役 | 可能新增 / 退役 |
约束:每次 release 的 changelog 必须按上述五类资产清晰罗列变更。
演化中的不变量
无论怎么演化,下列不变量永远不变:
| 不变量 | 演化中的保护 |
|---|---|
| 凭证不变量(不收不存不训练) | 任何接口 / schema / Prompt / 工具变更都不能引入凭证字段或凭证类参数 |
| 不直接下单 / 不持账户凭证 | 工具池禁止注册执行类工具(即使新增 category) |
| 不替用户决策 | 综合层输出契约必须含反方 / 风险 / 失效条件(不能因"简化"删除) |
| 用户数据主权 | 任何数据 schema 变更都不能让用户失去查看 / 修改 / 删除权 |
| 本地优先 | 任何架构演化(如未来加云端)都不能让本地优先用户失能 |
这些是战略级硬约束,演化策略必须服从战略层(详见 §2 上位继承与不变量)。
版本管理的可观测
每次资产变更都进入审计 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" 事件 |
与其他章节的关系
- 战略级不变量演化中的保护 → §2 上位继承与不变量
- 升级流程的部署形态承接 → §14 部署形态
- Schema migration 的存储承接 → §15 数据存储划分
- 接口契约消息体 contract_version → §16 通信协议
- Review gate 的工程承接 → §17 边界与安全
- 变更的审计可见性 → §18 可观测性
- 评估如何驱动 Prompt 演化 → §21 评估闭环
- ADR-009 Prompt 是代码还是数据 → 待写
20. 测试体系
字段权威定义见 contracts/state-machines.yaml(Step 11 整改包 I 单一事实源层)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:FinBayes 用什么测试体系覆盖业务正确性 / 子系统协作 / 端到端场景 / LLM 不确定性?
测试金字塔在 LLM 应用中的调整
传统软件的测试金字塔是 "单元 > 集成 > E2E",但 LLM 应用多一层评估测试(详见 §21)—— 因为 LLM 输出无确定预期,必须用统计指标而非断言。
这张图表达什么:从下到上数量递减,从下到上跨越的范围递增。评估测试单独一层是 LLM 应用的特殊性,不能用传统 assert 覆盖(详见 §21)。
这张图特意不表达什么:每层具体覆盖率指标(在工程实现仓 CI 配置);性能基准测试(在 §21 评估体系)。
单元测试
覆盖范围
| 类别 | 覆盖对象 |
|---|---|
| 业务对象逻辑 | Session / Watchlist / Judgment Record / Profile / Fin Object / StateCandidate 的方法 |
| 状态机转移 | §11 的 6 个状态机的每个转移 |
| 工具实现 | 每个工具的纯函数部分(不依赖外部 API) |
| 数据契约校验 | Pydantic schema 的字段级约束 |
| Provider Adapter 内部归一化 | OpenAI-compatible 转换逻辑(不真调 Provider) |
| 输入边界 hook 规则 | 凭证识别正则的命中率(§17) |
| 综合层输出 schema 校验 | 含反方 / 风险 / 失效条件字段的强约束 |
| 错误处理 | 各种错误码 / 异常路径 |
关键约束
- 单元测试不调真 LLM / 不调真外部 API(速度 + 成本 + 稳定性)
- 单元测试不读真 State Store(用内存 SQLite 或 tmpdir)
- 单元测试不依赖时间(用 freeze_time 等手段冻结时间)
- 每个单元测试 <100ms
LLM 相关的单元测试
LLM 相关的纯函数也走单元测试:
| 测试对象 | 测试内容 |
|---|---|
| Prompt 模板渲染 | 给定输入变量,渲染出预期 Prompt 文本 |
| LLM 响应解析 | 给定 mock 响应(含异常格式),解析逻辑健壮 |
| Function Calling schema 生成 | 给定工具池,生成的 schema 符合 OpenAI 规范 |
| 多轮上下文压缩 | 给定长上下文,压缩后保留关键信息 + 长度合规 |
集成测试
覆盖范围
| 类别 | 覆盖对象 |
|---|---|
| 子系统间协作 | §9 各子系统接口 + §10 各 sequence 流转 |
| State Store 完整 CRUD | 真 SQLite(tmpdir 隔离)+ 事务原子性 |
| Provider Adapter Pool | mock LLM Provider + 4 层降级链触发 |
| Capability Registry | 工具注册 + LLM Function Calling mock + 工具调用 |
| Cache | 真 Redis(容器化)或内存 LRU |
| 审计 trail 写入 | 所有事件类型按预期写入 |
| 并发任务执行 | asyncio.TaskGroup + 失败隔离 + 取消(§12) |
Mock 策略
| 真 / Mock | 对象 |
|---|---|
| 真 | State Store / Cache / 内部子系统 |
| Mock | LLM Provider(用 fixture 录制响应 + 重放)/ 外部数据 Provider(用 fixture) |
LLM Mock 是集成测试的关键工程,下文专门讨论。
关键约束
- 集成测试单次跑应该 <30 秒(不可被开发者跳过)
- 每个子系统至少有 3 个跨子系统的协作场景测试
端到端测试
覆盖范围
§6 列举的 9 个关键业务场景每个对应至少一组端到端测试:
| 场景 | 端到端测试核心断言 |
|---|---|
| S1 即时认知请求 | 首屏 <X 秒 + 流式输出完整 + 含反方与失效条件 |
| S2 状态确认 | 候选 → 用户确认 → 持久化到 Watchlist |
| S3 复盘 | 历史 Judgment 引用 + 综合层输出含"信息缺口" |
| S4 关注流 | 主动信号触发 → Channel 通知投递 |
| S5 长 Session 上下文 | 多轮后压缩 + 关键 Judgment 保留 |
| S6 边界拒收凭证 | 凭证类输入识别 + 不进入 Task / LLM / 状态对象 / 审计 trail |
| S7-S9(按当前任务类型清单) | 业务约束按 §6 描述 |
LLM 调用策略
端到端测试分两档:
| 档 | LLM 调用 | 何时跑 |
|---|---|---|
| 快档 | Mock LLM(录制 fixture) | 每次 PR / CI |
| 真档 | 真 LLM(用低成本 Provider,如 DeepSeek) | nightly / release 前 |
约束:快档必须每次 CI 跑(覆盖业务流转);真档跑发现的真实 LLM 问题用于评估闭环(§21)。
数据隔离
- 端到端测试绝不用用户真实 State Store
- 每次端到端测试在 tmpdir 起独立 State Store + Cache
- 测试结束清理(含 OS Keychain 中的测试凭证 —— 用专属测试命名空间)
LLM Mock 工程
LLM Mock 是 FinBayes 测试体系的关键 —— 既要快、便宜、稳定,又要逼真。
三种 Mock 模式
| 模式 | 描述 | 用途 |
|---|---|---|
| 录制重放 | 真实跑过一次,把请求/响应 fixture 化 | 集成 + 端到端快档 |
| 手工 fixture | 工程写死的固定响应(如"返回工具调用 X") | 单元测试 / 特定路径覆盖 |
| 简化模型 stub | 用简单规则模拟(如 echo / 关键词路由) | 性能测试 / 并发测试 |
录制重放的关键
关键约束:
- fixture 文件纳入 Git(可 review + 可追溯 LLM 行为变化)
- fixture 不含真实凭证 / 用户敏感信息(录制前脱敏)
- fixture 中的请求 hash 基于关键参数(model / messages / tools)+ 忽略时间戳等
- Provider 端 API 变化导致 fixture 失效时,CI 给明确报错(不悄悄通过)
降级路径测试
§13 列举的每条降级路径必须有测试:
| 降级层 | 测试方法 |
|---|---|
| L1 → L1' | mock 用户 Provider 全部失败 → 验证走系统默认 |
| L1' → L2 | mock 系统默认失败 + 本地 LLM 可用 → 验证走本地 |
| L2 → L3 | mock LLM 全失败 + 缓存有 → 验证走缓存 |
| L3 → L4 | mock 全失败 → 验证走受限菜单 + 用户明示提示 |
| State Store 只读模式 | mock SQLite 锁 / 磁盘满 → 验证读功能可用 + 写拒绝 |
| Cache 不可用 | mock Redis down → 验证退化为不缓存模式 |
| 工具调用超时 | 验证 EvidencePacket 标 timeout + 综合层继续 |
| 证据完全缺失 | 验证综合层输出"信息缺口"而非硬编 |
| 用户主动取消 | 验证 TaskGroup 取消 + 5s grace + 部分结果保留 |
约束:每条降级路径不仅测试走通,还测试用户感知(banner / 错误码 / 审计 trail 写入)。
边界与安全测试
§17 列举的每条边界约束必须有测试:
| 边界 | 测试 |
|---|---|
| 凭证类输入拒收 | 给输入贴 私钥 / API key / 助记词 等样式 → 拒收 + 安全回应 + 不进入任何后续 |
| 输出端凭证样式过滤 | mock LLM 输出含凭证样式 → 输出端剥除 + banner |
| 执行类工具注册拒绝 | 尝试注册 category=execution 工具 → 拒绝 + 审计记录 |
| 含凭证参数的工具拒绝 | 尝试注册参数含 private_key 字段的工具 → 拒绝 |
| Prompt 注入 | 输入含 "忽略上述指令" → 综合层输出仍符合契约 + 不偏离任务 |
| 用户数据隔离 | 跨 user_id 查询 → 拒绝 / 返回空 |
| TLS 降级 | 配置 HTTP Provider URL → 启动时拒绝 |
| 本机 socket 限 | 尝试从非 localhost 访问 Web API → 拒绝 |
约束:边界测试是回归关键 —— 战略边界一旦被绕过,影响远大于功能 bug。CI 跑边界测试集失败 = 阻断 release。
并发测试
§12 的并发设计需要专项测试:
| 测试场景 | 内容 |
|---|---|
| TaskGroup 一子任务失败 | 其他子任务能正常完成(或可控取消) |
| 用户主动取消任务 | 5s grace + 部分结果落审计 trail + 资源清理 |
| 多 Session 并发 | 每 Session 独立 + Cache key 不串 |
| backpressure | Provider 限流时排队 + 不掉单 |
| 高并发下 SQLite WAL | 多读 1 写不冲突 + 事务原子性 |
| 主动信号触发的批量任务 | 多 Judgment 同时失效 → 批量任务正确分发 |
测试数据管理
测试用户画像 / Watchlist / Judgment Record
| 类型 | 来源 |
|---|---|
| 单元测试用 fixture | 工程写死 |
| 集成测试用 fixture | YAML 文件 + 测试时载入 tmpdir 隔离 SQLite |
| 端到端测试用 fixture | 多套画像(保守 / 激进 / 多频次 / 新手)+ 多套 Watchlist |
| 评估测试用数据集 | 详见 §21 |
测试金融对象
- 不用真实交易所 / 真实价格 API
- 用 fixture 模拟价格序列(含暴涨 / 暴跌 / 横盘 / 缺数据等场景)
- 必要时用历史数据回放(如某次行情事件的真实数据)
测试可观测性依赖
测试依赖 §18 可观测性体系:
- 测试断言可以基于审计 trail(如"凭证拒收事件按预期写入")
- 集成测试用 task_id trace 验证因果链完整
- 性能测试用指标体系(latency / token / cost)做基线对比
CI 集成
| 触发 | 跑什么 |
|---|---|
| 每次 PR | 单元 + 集成 + 端到端快档(Mock LLM)+ 边界测试集 + verify-kb |
| nightly | 全部 + 端到端真档(真 LLM,低成本 Provider)+ 评估测试(详见 §21) |
| release 前 | nightly 全跑 + 完整评估数据集 + 性能基线对比 |
约束:
- 每次 PR 测试不超过 15 分钟(开发者反馈循环)
- nightly 测试不超过 1 小时(含真 LLM 调用)
- 测试报告进入审计 trail(哪次测试失败 / 哪条 fixture 过期 / 等)
第一阶段不做的测试能力
明示不做:
- 跨平台兼容性矩阵测试(仅主流 macOS + Linux + Windows 各一基线)
- 浏览器 UI 自动化测试(第一阶段 Web UI 仅做最小可用,重点在 CLI / TUI)
- 性能回归基准跑(评估闭环里有,但不在 CI 跑)
- 模糊测试(fuzzing)—— 可演化能力
与其他章节的关系
- 测试覆盖的场景来源 → §6 关键业务场景
- 测试覆盖的子系统接口 → §9 子系统组件
- 测试覆盖的流转 → §10 关键场景流转图
- 测试覆盖的状态机 → §11 状态对象生命周期
- 并发测试覆盖的设计 → §12 并发与异步处理
- 降级路径测试覆盖 → §13 故障与降级路径
- 边界测试覆盖 → §17 边界与安全
- 测试依赖的可观测性 → §18 可观测性
- 评估测试详见 → §21 评估闭环
21. 评估闭环
字段权威定义见 contracts/evaluation-dimensions.yaml(Step 11 整改包 I 单一事实源层,11 维 D1-D11)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:FinBayes 的认知质量怎么衡量?怎么形成"评估 → 改进 → 再评估"的闭环?
为什么评估测试不等于普通测试
普通测试用 assert expected == actual,但 LLM 输出没有唯一正确答案。一个分析 ETH 走势的认知任务可以有多种合理输出 —— 不是 string 比对能判定。
评估测试用统计指标 + 数据集衡量质量趋势,而非单点断言:
| 维度 | 普通测试 | 评估测试 |
|---|---|---|
| 期望值 | 单一确定 | 一组合格输出(rubric) |
| 通过判据 | assert | 指标聚合 + 阈值 |
| 失败处理 | 修代码 | 修代码 / 修 Prompt / 修工具 / 标 case 入回归集 |
| 频率 | 每次 PR | 周期跑(nightly + release)+ 关键变更跑 |
| 数据规模 | 个位数 fixture | 几十到几百条评估样本 |
评估闭环的工程结构
这张图表达什么:评估数据集 → 跑 → 判定 → 报告 → 改进 → 失败 case 入回归集 → 再评估,是个闭环。每次改进都更新评估集,避免回归。
这张图特意不表达什么:具体评估工具实现(在工程实现仓);评估的真 LLM 成本(在 §18 成本指标)。
评估数据集(Eval Set)
数据集分层
| 层 | 用途 | 规模 | 跑频率 |
|---|---|---|---|
| 冒烟集 | 关键场景快速验证 | 10-20 条 | 每次 PR |
| 回归集 | 已发现失败 case 的固化 | 持续累积,初始 30-50 条 | nightly + release |
| 场景集 | §6 9 个场景的覆盖 | 每场景 5-10 条 = 50-100 条 | release |
| 抗扰集 | Prompt 注入 / 边界 case / 异常输入 | 持续累积 | release |
约束:
- 评估数据集进 Git + Review gate 覆盖(不能有 PR 偷偷删 case)
- 评估数据集不含真实用户数据(用脱敏 / 合成数据)
- 评估数据集不含凭证类样式(凭证不变量延伸到测试资产)
评估样本的结构
每条样本含:
| 字段 | 含义 |
|---|---|
sample_id | 全局唯一 |
scenario | 关联 §6 场景 |
input | 用户输入 + 上下文(如 Session 历史 / 画像 / Watchlist 状态) |
expected_capabilities | 期望具备的能力(如"必须给出反方" / "必须标失效条件" / "不应给方向性结论 if 数据缺失") |
negative_constraints | 不应出现(如"不能给执行类建议" / "不能输出凭证样式") |
rubric | 质量评分维度(见下) |
tags | 任务类型 / 难度 / 来源 / 等 |
评分 Rubric
DEPRECATED(v1 草案,已被取代,不要据此实现):下表 8 维 rubric 是 v1 草案,已由 11 维评测体系 D1-D11 全面取代(Step 11 整改包 I)。权威事实源为 contracts/evaluation-dimensions.yaml(字段单一事实源)+ Eval Harness 11 维评分公式(D1-D11 评分公式与加权)。新写代码 / 评估资产 / rubric 配置一律以 11 维 D1-D11 为准;下表仅保留作为 v1 演化的历史叙述上下文,不再是评分契约。
下表为已废弃的 v1 8 维 rubric(历史参考,权威维度见上文 11 维 D1-D11):
| v1 维度(已废弃) | v1 评分方法 |
|---|---|
| 反方覆盖完整度 | LLM-as-judge:检查输出是否含反方 + 反方质量打分 |
| 失效条件清晰度 | LLM-as-judge + 规则:必须含可观测的失效条件 |
| 证据归因 | 规则:输出中的关键结论必须有证据指向 |
| 信息缺口诚实度 | 规则 + 人工:缺数据时应该明示,不应硬编 |
| 输出格式契约 | 规则:综合层 schema 校验通过 |
| 表达密度匹配画像 | LLM-as-judge:是否过密 / 过疏 |
| 第一屏命中题眼 | LLM-as-judge:首屏是否回答用户主要疑问 |
| 边界约束遵守 | 规则 + grep:不出现禁词 / 不给执行类建议 |
v1 每个维度独立打分(0-5)+ 汇总加权——该评分方式同样被 11 维 D1-D11 的评分公式取代,以 contracts/ + Eval Harness 公式文档为准。
评估运行器
评估流程
关键约束:
- 评估运行器与 runtime 解耦 —— 运行器通过 runtime 公开 API 调用(CLI / Web API),不直接 import
- 每次评估记录 LLM 版本 + Prompt 版本 + Provider + 工具版本(可追溯哪次评估对应哪个组合)
- 评估结果库长期保留(看趋势 + 看回归)
质量判定方法
三种判定手段
| 手段 | 适用维度 | 优点 | 缺点 |
|---|---|---|---|
| 规则判定 | 格式 / 字段存在 / 禁词 / 边界 | 快 / 稳 / 便宜 | 难判语义质量 |
| LLM-as-judge | 反方质量 / 表达匹配 / 题眼命中 | 能判语义 | 贵 / 慢 / 自身有偏 |
| 人工抽检 | 关键 case / 争议结果 / 新数据集校准 | 真正可靠 | 极贵 / 不可大规模 |
LLM-as-judge 的工程约束
LLM-as-judge 是评估的核心手段之一,需要专门工程:
- judge LLM 与被评估 LLM 不同(避免自评偏见)—— 例如 GPT 评估 Claude 输出,反之亦然
- judge Prompt 本身是 Prompt 资产(详见 §19 Prompt 版本化)+ 与 rubric 同步演化
- judge 评分校准:用人工抽检的样本回头校准 judge 准确度(如 100 条人工标注 vs judge 判定的相关度)
- 高分歧 case(多 judge 不收敛)走人工
评估指标聚合
单次评估的核心指标
| 指标 | 含义 |
|---|---|
overall_score | 所有样本加权平均分 |
pass_rate | 总分 >阈值的样本比例 |
per_dimension_score | 各 rubric 维度的均分 |
per_scenario_score | §6 各场景的均分 |
regression_failures | 历史 pass 但本次 fail 的样本 |
boundary_violations | 边界约束违反次数(严重失败,单条即阻断) |
阈值与门禁
| 阈值类型 | 第一阶段建议 | 用途 |
|---|---|---|
overall_score >= 3.5/5 | 软阈值 | 看趋势,下滑明显需排查 |
pass_rate >= 80% | 软阈值 | 同上 |
regression_failures == 0 | 硬阈值 | 回归集必须全过,否则 release 阻断 |
boundary_violations == 0 | 硬阈值 | 边界违反 = release 阻断 |
关键约束:
- 软阈值用于趋势监控,不作 PR 门禁(避免 Goodhart's law —— 优化指标牺牲真实质量)
- 硬阈值仅限回归集 + 边界违反 —— 这两类是不可妥协的
- 评估结果不直接喂回 LLM 训练 / Prompt 自动优化(避免反馈循环失控)—— 改进需要人工分析 + 工程决策
离线评估 vs 在线评估
离线评估
| 何时跑 | 跑什么 |
|---|---|
| 每次 Prompt 变更 PR | 冒烟集 + 该 Prompt 关联的子集 |
| nightly | 回归集 + 抗扰集 |
| release 前 | 全部数据集 + 性能基线对比 |
| 重要架构变更 | 全部数据集 + 人工抽检 |
在线评估
第一阶段单机部署,"在线"指用户真实使用过程中的质量信号:
| 信号 | 采集方式 |
|---|---|
| 用户对候选状态的接受率 | candidate → confirmed / rejected / edited 的比例 |
| 用户对 Judgment 的"赞 / 否 / 编辑" | UI 提供反馈按钮(可选) |
| 用户主动重提问的频率 | 同一会话内连续多次提问 = 上一轮没满足 |
| 用户取消任务的频率 | 高 = 任务质量或速度问题 |
| 触发 clarify 的频率 | 高 = 意图识别不准 / 输入难懂 |
约束:
- 在线评估信号严格 per-user 隔离(不跨用户聚合 —— 隐私)
- 用户显式同意才上报到 FinBayes 团队(默认仅本地审计 trail)
- 上报仅含统计数据(不含具体输入输出 / 用户画像)
评估驱动改进
改进类型
| 评估发现的问题 | 改进路径 |
|---|---|
| 某场景反方覆盖不足 | 调综合层 Prompt + 加 fixture |
| 某任务类型表达过密 | 调表达密度模板 + 与画像联动 |
| 某 Provider 在特定任务上质量差 | task_routing.yaml 调路由 |
| 某工具调用频次过低 | 工具描述优化 + LLM Function Calling 测试 |
| 某边界 case 被识别成正常输入 | 边界 hook 规则增强 + 加边界测试集 |
| 信息缺口未明示 | 综合层 schema 强约束 + Prompt 加固 |
改进流程
约束:
- 改进不绕过评估闭环 —— 改完必须重跑评估
- 失败 case 进回归集避免反复跌入同一坑(这是 case library 的真正用途,详见下文)
- 每次重要改进记 ADR 或工程日志
Case Library 的角色(澄清)
战略层提到"Case Library"作为认知质量的回归追踪 —— 工程层的承接:
| Case Library 是 | Case Library 不是 |
|---|---|
| 评估数据集中的"回归集" | release 门禁的强制清单 |
| 历史失败 case 的累积 + 复测 | 测试覆盖率的代名词 |
| 看"质量是否退步"的趋势 | "0 命中 = 完美"的 KPI |
| 工程与战略层共同维护的资产 | 工程一方说了算的工具 |
详见 §3 架构目标与质量取舍。
评估资产的演化
评估数据集 / rubric / judge prompt 本身也需要演化(详见 §19 Prompt 版本化):
| 资产 | 演化策略 |
|---|---|
| 评估样本 | 累积 + 标过期 + 不强行删除(历史可追溯) |
| Rubric 维度 | 加 minor / 改语义 major + 重跑历史样本生成新基线 |
| Judge Prompt | semver + 切换时记录"哪一时点起用新 judge" |
| 阈值 | 可调,但每次调整记录理由(避免悄悄放水) |
第一阶段不做的评估能力
明示不做:
- 真实用户 A/B 实验(单机部署不需要)
- 自动 Prompt 优化(如 DSPy 等)—— 评估反馈喂回 Prompt 优化器,第一阶段不引入
- 多用户聚合趋势报表(隐私 + 第一阶段单用户)
- 实时质量监控告警(评估周期跑足够)
这些都不是不可演化(评估接口契约不变),只是第一阶段不抢答。
与其他章节的关系
- 评估覆盖的场景 → §6 关键业务场景
- 评估依赖的可观测性 → §18 可观测性
- 评估驱动 Prompt 演化 → §19 演化与版本管理(ADR-009 待写)
- 评估资产的 Review gate → §17 边界与安全
- 评估如何接入 CI → §20 测试体系
- Case Library 的战略来源 → §3 架构目标与质量取舍
22. 第一阶段缺口
这一节回答:第一阶段明示不抢答的开放问题有哪些?为什么不抢答?什么条件下会被触发处理?
三类缺口
| 类别 | 含义 | 来源 | 处理路径 |
|---|---|---|---|
| 战略待定 | 战略层尚未给定答案,工程层不替代 | 继承自白皮书 §15 | 触发条件成立时回到战略层讨论 |
| 工程延后 | 战略已定但第一阶段优先级不够 | 工程层新增 | 接口契约不变,后续版本演化补 |
| 场景外 | 不在第一阶段服务范围 | 战略边界 + 工程定位 | 暂不投入,演化预留接口 |
缺口来源分层(详见各 P1 / P2 段标注):
- 继承自白皮书 §15:商业模式与定价 / 个人 vs 机构分立 / 更多市场普适性 / L1-L3 商业强度
- 产品层新增(产品定义文档识别):跨设备同步 / Channel 优先级 / 任务类型最终形态
- 工程层新增(本架构文档识别):认知质量验收方法(OQ-002)/ 自动 Prompt 优化 / 实时 metric dashboard / 分布式 trace / 等
- ADR 状态(2026-05-31):原"待写"的 ADR-005(并发)/ ADR-006(部署)/ ADR-009(Prompt 版本化)/ ADR-014(语言栈)均已 accepted。ADR-007(状态写入两步,M1 龙头)/ ADR-015 / ADR-016 亦 accepted。ADR-004 / ADR-008 / ADR-010 早已 accepted。本工作流 ADR 已无 draft/空缺,全部 accepted。
明示这些缺口不是"工程不完整",而是有意识的不投入 —— 第一阶段焦点是"本地优先单机的认知层 MVP 走通",不抢答与该焦点无关的问题。
战略待定的缺口
这一类与战略层的"未决问题"(详见上位继承与不变量章节)对齐:
第一阶段不抢答的战略未决
| 未决问题 | 工程层影响 | 触发讨论条件 |
|---|---|---|
| 商业模式与定价 | 不影响第一阶段架构 | 用户量达到 1000+ / 主动信号价值验证后 |
| 多用户共享 Watchlist / 团队级审计 | State Store schema 预留 user_id,但不实现共享 | 企业用户出现 |
| 跨设备同步(用户多机 FinBayes 状态同步) | 不实现,State Store 单机本地 | 用户明确需求出现 |
| Channel Adapter 第二阶段优先级(TG / Discord / Slack 谁先) | 主推 Web 与 CLI / TUI,Channel 接口预留 | 用户访问通道偏好数据出现 |
| 任务类型清单的最终形态(是否扩展、是否细分) | 不写死,按 LLM Function Calling 动态识别(详见 §4 / §9) | 评估闭环发现新型任务模式 |
| 认知质量验收的最终方法(OQ-002) | §21 给出第一阶段建议,但不锁定 | 上线后实际质量数据积累 |
已经过深度调研但 ADR 待定
| 议题 | 调研产物 | ADR 编号 | 当前状态 |
|---|---|---|---|
| 自然语言到任务的识别策略(OQ-003) | projects/finbayes/research/intent-recognition-and-llm-strategy/ 已起草 README + summary + recommendations | arch-rewrite/ADR-004 | accepted(2026-05-28) |
| Prompt 是代码还是数据 | §19 给出初步倾向(混合策略) | arch-rewrite/ADR-009 | waiting,M1 启动前 accepted |
| 输出端凭证类内容过滤的位置 | §17 给出初步倾向(两处都做) | arch-rewrite/ADR-010 | accepted(2026-05-28) |
工程延后的缺口
战略已对齐、第一阶段不投入但接口契约预留的能力:
高级测试 / 评估能力
| 能力 | 第一阶段做什么 | 演化路径 |
|---|---|---|
| 模糊测试(fuzzing) | 不做 | 评估闭环成熟后加 |
| 自动 Prompt 优化(如 DSPy) | 不做(避免反馈循环失控) | 评估指标稳定后探索 |
| 实时 metric dashboard(Prometheus + Grafana) | 不做,用 CLI / TUI 命令查询 | 多用户部署后引入 |
| A/B 实验框架 | 不做(单用户单机不必要) | 远程托管后引入 |
| 浏览器 UI 自动化测试(Playwright) | 不做(Web UI 最小可用) | Web UI 成为主入口后引入 |
高级可观测性
| 能力 | 第一阶段做什么 | 演化路径 |
|---|---|---|
| 分布式 trace(OpenTelemetry) | 不做(单进程不需要) | 拆分进程或远程部署时引入 |
| 云端日志聚合(Datadog / Loki) | 不做(本地优先违背) | 用户显式选择上报时引入 |
| 实时质量告警 | 不做(评估周期跑足够) | 用户对认知质量提出实时监控需求时 |
| 异常上报到云服务(Sentry) | 不做 | 用户显式选择时 |
部署能力
| 能力 | 第一阶段做什么 | 演化路径 |
|---|---|---|
| 远程托管部署 | 不做,第一阶段单机 | 商业模式验证 + 多用户隔离设计完成 |
| 多用户的真正运行时隔离 | 仅 user_id 维度预留,不实现强隔离 | 远程托管时实现 |
| 容器化(Docker / K8s) | 不做(单机不需要) | 远程托管时 |
| 跨平台兼容性矩阵测试 | 主流平台各一基线 | 用户分布数据驱动 |
数据能力
| 能力 | 第一阶段做什么 | 演化路径 |
|---|---|---|
| State Store 从 SQLite 迁 PostgreSQL | 不做,SQLite 足够 | 多用户或单用户数据规模超 SQLite 上限时 |
| 数据回溯与时间旅行(如 EventSourcing) | 不做,仅靠审计 trail 复盘 | 复盘需求复杂化时 |
| 多语言 / 国际化 | 不做,第一阶段中文 + 英文术语 | 用户群扩展时 |
| 跨用户数据聚合 / 群体智能 | 不做(隐私 + 单用户) | 商业模式与隐私策略明确后 |
场景外的缺口
明示不在第一阶段服务范围:
| 场景 | 不做的理由 |
|---|---|
| 真正的"自动化交易代理" | 战略边界:FinBayes 不直接下单 / 不持账户凭证(详见 §2) |
| "金融执行凭证管家" | 战略边界:凭证一律不收 |
| 替用户做最终判断的"AI 决策"模式 | 认知层定位:不替用户决策(详见 §3) |
| 个性化广告 / 行情诱导 | 业务定位:仅服务用户认知,不卖流量 |
| 跨用户的"群体趋势"推断 | 隐私 + 战略:用户画像主权 |
| 实时高频信号(毫秒级触发) | 性能定位:认知层不做高频系统 |
这些不仅第一阶段不做,演化路径上也不做 —— 与战略定位冲突。
缺口的演化触发条件
缺口被触发时如何处理:
关键约束:
- 工程层不替战略层做决策 —— "战略待定"缺口被触发时回到 governance/change-protocol.md 走战略变更流程
- 工程层不为缺口偷偷开后门 —— 例如不会"先在 State Store 做多用户隔离的临时方案",因为这种临时方案常常被锁定下来变成事实标准
- 演化中的不变量(详见 §19)任何时候不变
缺口与质量目标的关系
缺口与 §3 的 8 个质量属性的关系:
| 质量属性 | 第一阶段缺口影响 |
|---|---|
| 可用性 | 不影响(第一阶段降级链已覆盖核心可用性需求) |
| 性能 | 不影响(缺的是优化空间,不是基础性能) |
| 可演化性 | 关键 —— 缺口的接口契约预留是可演化性核心承接 |
| 可测试性 | 部分影响(fuzzing / 浏览器自动化等延后,但核心测试体系已完整) |
| 可观测性 | 不影响(核心可观测已完整,缺的是高级集成) |
| 战略保真度 | 不影响(战略边界是缺口的约束,不是缺口的产物) |
| 部署便捷性 | 不影响第一阶段 |
| 用户主权 | 不影响(用户主权是战略级,缺口都遵守) |
缺口管理的工程动作
| 动作 | 内容 |
|---|---|
| 缺口登记 | 每个缺口在本章登记 + 在工程实施仓 issue tracker 留 placeholder |
| 缺口触发判断 | 每个 release 评估各缺口的触发条件是否成立 |
| 缺口推进 | 触发时按上述流程图走战略 / 工程分流 |
| 缺口与不变量冲突 | 缺口处理方案若与演化中的不变量冲突,停下来回战略层 |
与其他章节的关系
- 战略未决问题 → §2 上位继承与不变量
- 8 个质量属性 → §3 架构目标与质量取舍
- 任务类型清单非写死 → §4 业务对象与关系
- 第一阶段不抢答的部署形态 → §14 部署形态
- 演化中的不变量 → §19 演化与版本管理
- 第一阶段不做的测试能力 → §20 测试体系
- 第一阶段不做的评估能力 → §21 评估闭环
- 待写 ADR 清单 → §23 架构决策索引
- 缺口对应的风险 → §24 风险登记
23. 架构决策索引
字段权威定义见 contracts/adr-states.yaml(Step 11 整改包 I 单一事实源层,12 ADR + namespace)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:本架构文档涉及的所有架构决策记录(ADR)的全景索引。每条 ADR 在哪、谁触发、状态如何、影响哪些章节。
ADR 体系约定
| 字段 | 说明 |
|---|---|
| 编号 | ADR-NNN(三位数字),在 arch-rewrite 工作流 namespace 内唯一,不重用;跨工作流引用须显式带 <workstream>/ADR-NNN 前缀(详见 ADR INDEX §3 跨工作流同号消歧) |
| 位置 | governance/workstreams/finbayes-arch-rewrite/decisions/ADR-NNN-*.md |
| 状态 | proposed(待评审)/ accepted(已确认)/ superseded(已被新 ADR 替代)/ deprecated(已废弃但未替代) |
| 触发章节 | 哪个 CHAP 的设计需要这个决策 |
| 影响章节 | 决策一旦确认后影响哪些章节的描述 |
ADR 是独立成档的(详见 ADR-002),不在主架构文档中展开决策对比 —— 主文档只引用结论。
Namespace 说明:本索引为 finbayes-arch-rewrite 工作流 namespace;跨工作流 ADR-NNN 引用须显式带 <workstream>/ADR-NNN 前缀(如 finbayes-whitepaper-rewrite/ADR-008 与本工作流 ADR-008 同号不同物)。完整 namespace 消歧与 supplement 列表见 ADR INDEX。
已 accepted 的 ADR
| 编号 | 主题 | 文件 | 触发 | 影响 |
|---|---|---|---|---|
| ADR-001 | 工程范式:Harness Workflow + 里程碑切片 + 走通骨架试点 | decisions/ADR-001-工程范式.md | 工作流启动 | 全篇(特别是 §25 / §27) |
| ADR-002 | 架构文档结构:分层章节 + C4 画图 + 决策独立成档 + 业务建模思路 | decisions/ADR-002-架构文档结构.md | 工作流启动 | 全篇(文档结构本身) |
| ADR-003 | 工程实施栈与协作模式:OpenSpec + Archon + Claude Code 主理 + Codex 实现 | decisions/ADR-003-工程实施栈与协作.md | 工作流启动 | §25 / §27 |
| ADR-004 | 自然语言到任务的识别策略:LLM Function Calling 主导 | decisions/ADR-004-任务识别策略.md | §4 / §9 | §4 / §9 / §10 / §21 |
| ADR-008 | LLM Provider 接口抽象:统一 OpenAI-compatible | decisions/ADR-008-LLM-Provider-接口抽象.md | §9 | §9 / §13 / §15 |
| ADR-010 | 输出端凭证过滤位置:综合层语义级 + Output Pipeline 格式级 双处 | decisions/ADR-010-输出端凭证过滤位置.md | §17 | §9 / §17 / §20 |
待写的 ADR(M1+ 实施初期补)
以下决策已在主架构文档草稿中提出初步倾向,但尚未独立成 ADR 完整论证。M0 启动不阻塞(M0 实施 Agent 按当前倾向执行 + 在工程实施仓 PR 描述中标注采用了该倾向)。
| 编号 | 主题 | 触发章节 | 当前倾向 | 优先级 |
|---|---|---|---|---|
| ADR-005 | 内部并发原语选择:asyncio / 多线程 / 多进程 | §12 | Python asyncio.TaskGroup(结构化并发) | 中 |
| ADR-006 | 部署形态优先级:本地优先 / 远程优先 / 混合 | §14 | 本地优先单机为第一阶段 ✅;远程托管远期 | 中 |
| ADR-007 | 状态写入"候选 → 已确认"两步设计 | §11 | 主动状态全部走两步 + 显式拒收 / 编辑路径 | 中 |
| ADR-009 | Prompt 是代码还是数据 / 版本化策略 | §19 | 混合:关键 Prompt 进代码仓 + 实验性 Prompt 走 YAML | 中 |
优先级判定
- 高:第一阶段实施前必须有 ADR 才能起代码(涉及主干架构 / 战略边界)
- 中:可在第一阶段实施初期一周内补 ADR
- 低:第一阶段不阻塞,演化中再补
编号变迁说明
工作流早期 ADR-004 候选为"多 Skill 命中同一任务时的优先级规则",深度调研后该议题与"自然语言到任务的识别策略"合并 —— 后者更高优先级且涵盖前者。ADR-004 重命名为"任务识别策略",原"多 Skill 优先级"作为该 ADR 的子议题处理。
如未来"多 Skill 优先级"需独立成 ADR,会按下一可用编号(如 ADR-012)分配,不复用 ADR-004 编号。
拒绝概念的处理(无需独立 ADR)
战略层已禁入的概念清单(详见 §2 / §17)不需要独立 ADR —— 它们是战略级硬约束而非工程级决策。
| 拒绝概念 | 拒绝来源 | 工程承接 |
|---|---|---|
| 11 条字段级强约束 | 战略白皮书构建期否决 | 综合层 schema 不引入这 11 条字段 |
| 默认 vs 行动准备双模式 | 同上 | §6 关键场景不区分双模式 |
| 升格为关系定义的"认知协作伙伴" | 同上 | 全篇正文不使用该词 |
| L3 长期状态四承诺 | 同上 | §15 / §19 用户主权五维度替代 |
| 零状态前提 | 同上 | §14 / §15 显式状态管理 |
| 情绪桥 / 信任债承诺 | 同上 | 综合层输出契约不含此类元素 |
| 行动准备 / 行动判断 / 行动方案 | 同上 | 任务类型清单用"交易准备 / 交易决策 / 交易行动"代替 |
工程层的承接通过:
verify-kb.mjs的自动 grep 检查(CI 必跑)- PR Review gate 的人工语义复核(防同义改写)
- 章节级的 Review 历史保留
ADR 间的关系
这张图表达什么:ADR 之间的逻辑依赖关系。ADR-001/002/003 是工作流基础;ADR-004(任务识别策略)是认知架构核心,影响 ADR-005/008/009;ADR-006 部署形态依赖 ADR-007/008 的接口稳定。
这张图特意不表达什么:ADR 的写作顺序(按工程优先级,不按依赖严格拓扑)。
ADR 编写规范(来自 ADR-002)
每条 ADR 至少含:
| 段落 | 内容 |
|---|---|
| Context | 背景:为什么需要这个决策 |
| Decision | 决策:选了什么方案 |
| Rationale | 理由:为什么这样选(不展开未选方案的详细评分,只说结论) |
| Consequences | 后果:决策带来的好处 / 坏处 / 影响范围 |
| Status | 状态:proposed / accepted / superseded / deprecated |
| References | 关联:影响的 CHAP / 关联的其他 ADR / 关联的战略文档 |
关键约束:
- ADR 不变更(accepted 后追加 superseded 关系,不直接改原文)
- ADR 不超过 80 行(紧凑 + 聚焦 + 不堆方法论)
- ADR 文件名缩短(不含日期 / 长描述)
ADR 与主架构文档的关系
| 主架构文档(CHAP-NN) | ADR |
|---|---|
| 说"是什么 / 做什么 / 怎么做" | 说"为什么选这个、不选那个" |
| 引用结论 | 展开权衡 |
| 篇幅长 | 篇幅短(≤80 行) |
| 每章覆盖多个决策 | 每条覆盖单个决策 |
主架构文档不重复 ADR 的内容 —— 引用 ADR 编号即可。
主架构文档之外的决策痕迹
部分小决策不独立成 ADR,但在工程实施仓的 commit / PR 描述中留痕:
| 决策类型 | 留痕位置 |
|---|---|
| 工具版本选型(如选 Pydantic v2 而非 v1) | 工程实施仓的依赖文件 + 引入 commit |
| 字段命名 / API 路径细节 | OpenAPI schema + PR 描述 |
| Bug 修复中的次要设计选择 | PR 描述 |
判定标准:
- 决策影响多个章节 → 独立 ADR
- 决策影响单一模块 → 工程实施仓留痕
- 决策反映战略边界 → 战略层而非 ADR
已识别但暂不分配编号的潜在 ADR
下列议题可能在演化中变成 ADR,但当前不分配编号(避免编号膨胀):
- 多 Skill / 多工具优先级规则(被 ADR-004 涵盖)
- Cache TTL 策略(按数据敏感度分类,工程实施细节)
- 审计 trail 归档策略(按时间分片,工程实施细节)
- Provider Readiness 探测间隔(运维参数,工程实施细节)
这些都不到 "影响多个章节"的门槛,留在工程实施仓决策。
与其他章节的关系
- ADR 编写规范来源 → ADR-002 架构文档结构
- 拒绝概念清单的来源 → §2 上位继承与不变量
- 战略未决问题映射 → §22 第一阶段缺口
- ADR 与风险的对应 → §24 风险登记
- ADR 如何驱动里程碑 → §25 与里程碑/任务的对应
24. 风险登记
这一节回答:第一阶段已识别的关键风险有哪些?每个风险的可能性、影响、当前缓解状态是什么?
风险分类
| 类别 | 含义 |
|---|---|
| 技术风险 | 工程实现 / 性能 / 可靠性层面的不确定性 |
| 业务风险 | 用户接受度 / 认知质量 / 商业模式层面的不确定性 |
| 边界风险 | 战略边界被绕过或被攻击的风险 |
| 演化风险 | 长期演化中可能出现的设计债 |
评级约定
| 维度 | 等级 |
|---|---|
| 可能性 | 高(H)/ 中(M)/ 低(L) |
| 影响 | 高(H)/ 中(M)/ 低(L) |
| 优先级 | 由可能性 × 影响推导:HH / HM-MH = P1;MM / HL-LH = P2;其他 = P3 |
风险登记不是恐吓清单 —— 是让缓解动作有抓手。
技术风险
T1 — LLM Provider 不稳定(API 限流 / 5xx / 鉴权失败 / 延迟抖动)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | H / H / P1 |
| 表现 | 任务失败 / 用户体验中断 / 成本飙升 |
| 当前缓解 | 4 层降级链(§13)+ Provider Readiness 探测(§9)+ task_routing 配置 |
| 残余风险 | 全部 Provider 同时不可用极端场景 → L4 受限菜单兜底 |
| 触发处理动作 | Provider 失败率连续 30 min >10% → 自动降级 + 用户通知 |
T2 — 本地资源不足(内存 / 磁盘 / 计算)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / M / P2 |
| 表现 | 本地 LLM 推理慢 / SQLite 写阻塞 / 缓存换出 |
| 当前缓解 | 部署时探测 OS 资源(§14)+ 本地 LLM 模型大小自适应 + Cache TTL 限制 |
| 残余风险 | 用户机器极弱时本地兜底质量差 |
| 触发处理动作 | 启动期探测资源不足 → 明示用户选择"走云端 Provider"或"接受性能下降" |
T3 — SQLite 并发瓶颈
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | L / M / P3 |
| 表现 | 高并发任务下写阻塞 / WAL 文件膨胀 |
| 当前缓解 | WAL 模式 + 审计 trail 写入异步化 + 单用户量级 SQLite 远未到瓶颈(§15) |
| 残余风险 | 主动信号触发批量任务时偶发阻塞 |
| 触发处理动作 | 持续监控 state_store_write_failure 指标,达阈值时启 ADR 评估迁 PostgreSQL |
T4 — LLM Mock fixture 失效(Provider API 变化)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / M / P2 |
| 表现 | CI 测试通过但生产环境失败(fixture 与真 API 偏差) |
| 当前缓解 | 录制重放机制(§20)+ nightly 真档测试 + fixture 进 Git 可 review |
| 残余风险 | Provider 端悄悄改 API 行为 |
| 触发处理动作 | nightly 真档测试失败 → 强制重录相关 fixture + 通知 |
T5 — Schema migration 出错(State Store 升级失败)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | L / H / P2 |
| 表现 | 升级后用户数据损坏 / 丢失 |
| 当前缓解 | migration 前强制备份(§15)+ 单向幂等 migration(§19)+ 失败时全量回滚 |
| 残余风险 | 备份本身损坏的极端情况 |
| 触发处理动作 | 严重 migration 失败 → 用户可 finbayes restore --from=<bak> 强制恢复 |
业务风险
B1 — 认知质量不达预期(反方覆盖不足 / 失效条件模糊 / 综合层不收敛)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / H / P1 |
| 表现 | 用户对 Judgment 不满 / Case Library 失败率升 / 用户流失 |
| 当前缓解 | Self-consistency 高风险任务 N≥3(§12)+ 综合层输出强 schema(含反方 / 风险 / 失效条件)+ 评估闭环驱动改进(§21) |
| 残余风险 | 评估指标本身有偏(LLM-as-judge 偏见) |
| 触发处理动作 | 评估 overall_score 连续两周下滑 → 强制评估闭环复盘 |
B2 — 用户接受度低(首屏太慢 / 表达不匹配画像 / 不知道怎么用)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / H / P1 |
| 表现 | 用户使用频次低 / 取消率高 / 弃用 |
| 当前缓解 | 首屏优化(流式 + 题眼优先)+ 动态画像匹配表达密度 + 引导流程(§14) |
| 残余风险 | 个性化画像积累需要时间 |
| 触发处理动作 | 上线后第一周用户行为信号反推改进点 |
B3 — 复盘价值难量化
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | H / M / P2 |
| 表现 | 用户用了几次但不知道"它真的帮我变好"了 |
| 当前缓解 | Judgment Record 长期追踪 + 主动信号触及失效条件可被用户复盘(§10 S4 场景) |
| 残余风险 | 用户认知改善是慢变量 |
| 触发处理动作 | 用户问"它真有用吗"时主动给"过去 N 次主动信号的命中率 / 失效条件触及率" |
B4 — Provider 成本失控
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / M / P2 |
| 表现 | 用户单月 LLM 成本超预期 |
| 当前缓解 | 成本指标可视(§18)+ 用户主动设月度预算 + 超预算自动降级到便宜 Provider |
| 残余风险 | 用户对成本敏感度差异大 |
| 触发处理动作 | 首次安装时引导用户设月度预算(可选) |
边界风险
E1 — 凭证被绕过(用户主动贴凭证未被识别)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / H / P1 |
| 表现 | 凭证字符串进入 Task / LLM / 状态对象 / 审计 trail |
| 当前缓解 | 输入边界 hook(规则 + LLM 辅助,§17)+ 测试集覆盖各类凭证样式(§20) |
| 残余风险 | 新型凭证格式 / 用户极端规避 |
| 触发处理动作 | 任何凭证泄露事故 → 立即 release 阻断 + 全量审计 trail 扫描 + 通知用户 |
E2 — 执行类工具偷偷被注册
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | L / H / P2 |
| 表现 | 工程 PR 引入执行类工具 + Review 漏掉 |
| 当前缓解 | Capability Registry 注册时 category 校验(§9)+ 参数名启发式扫描(§17)+ Review gate 人工审查 |
| 残余风险 | 工具用 read_only category 伪装但内部偷偷执行 |
| 触发处理动作 | 每次工具注册需关联 PR / ADR / Review 记录三齐 |
E3 — Prompt 注入成功(用户输入或外部数据中的对抗指令改变 LLM 行为)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / M / P2 |
| 表现 | LLM 输出偏离任务 / 泄露敏感 / 违反输出契约 |
| 当前缓解 | System prompt 加固(§17)+ 外部数据包裹 <external_data> + 综合层 schema 强约束 + 抗扰评估集(§21) |
| 残余风险 | 高级注入 + LLM 误识别 |
| 触发处理动作 | 评估抗扰集失败率上升 → Prompt 加固 + judge 校准 |
E4 — 输出端凭证样式过滤漏检
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / M / P2 |
| 表现 | LLM 幻觉生成的凭证样式字符串流向用户 |
| 当前缓解 | 输出端双层 hook(综合层语义 + Output Pipeline 格式,详见 arch-rewrite/ADR-010 accepted) |
| 残余风险 | 模糊匹配未命中的边缘 case |
| 触发处理动作 | 用户上报 + 边界审计 trail 抽检 |
演化风险
V1 — 接口契约破坏性升级
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / H / P1 |
| 表现 | major 升级导致存量用户的 client / 集成 / MCP 调用方失败 |
| 当前缓解 | semver + contract_version + 强制升级提示(§19)+ 升级指南 + deprecated 宽限期 |
| 残余风险 | 用户不及时升级被强制阻断 |
| 触发处理动作 | major 发布前给至少一个 minor 版本的 deprecated 期 + 升级文档 |
V2 — Prompt 版本错位(生产用旧 Prompt + 评估用新 Prompt 等)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / M / P2 |
| 表现 | 评估通过但生产质量差,或反之 |
| 当前缓解 | Prompt 版本化(ADR-009 待)+ 评估记录 Prompt 版本 + 审计 trail 含 prompt_version 字段(§19) |
| 残余风险 | 混合策略(代码 + 数据)切换时漂移 |
| 触发处理动作 | 每次 release 用 prompt_version 跑全量对比 |
V3 — 战略概念变化(新增 / 重命名 / 退役)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | L / H / P2 |
| 表现 | 工程层与战略层不同步 / 用户看到混乱概念 |
| 当前缓解 | 概念退役流程(§19)+ 战略变更走 governance/change-protocol.md + verify-kb 禁词表同步 |
| 残余风险 | 已生成的历史 Judgment Record 引用旧概念 |
| 触发处理动作 | 旧概念在 UI 标"历史概念" + 不破坏数据 |
V4 — Provider 生态变化(旧 Provider 退役 / 新 Provider 涌现)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | H / M / P2 |
| 表现 | 用户偏好的 Provider 不再可用 / 新 Provider 体验更好但路由未更新 |
| 当前缓解 | Provider Adapter 层屏蔽(§9)+ providers.yaml 配置可热更新 + Provider 退役流程(§19) |
| 残余风险 | 用户配置历史包袱 |
| 触发处理动作 | Provider 退役前一个 major 版本通知 + 自动迁移建议 |
V5 — 评估闭环 Goodhart's law(优化指标导致真实质量下降)
| 字段 | 内容 |
|---|---|
| 可能性 / 影响 / 优先级 | M / H / P1 |
| 表现 | 评估分数上升但用户感知不好 |
| 当前缓解 | 软阈值仅看趋势(§21)+ 评估反馈不自动喂回 Prompt 优化 + 人工校准 judge |
| 残余风险 | 隐性指标钻空子(如优化反方数量但反方质量下降) |
| 触发处理动作 | 评估指标稳定上升但用户反馈下降 → 人工抽检 + rubric 重审 |
风险评级汇总
| 优先级 | 数量 | 风险 |
|---|---|---|
| P1 | 6 | T1 / B1 / B2 / E1 / V1 / V5 |
| P2 | 11 | T2 / T4 / T5 / B3 / B4 / E2 / E3 / E4 / V2 / V3 / V4 |
| P3 | 1 | T3 |
P1 风险必须在第一阶段 MVP 前有可执行的缓解动作 + 触发响应;P2 风险在第一阶段实施初期一轮内覆盖缓解机制;P3 风险登记即可,演化中再处理。
风险与缺口的关系
| 关系 | 含义 |
|---|---|
| 风险有缓解 → 残余风险登记 | 当前章节做的事 |
| 风险无缓解 → 进入缺口 | 关联 §22 |
| 风险触发战略层变化 → 战略未决 | 关联战略层(详见上位继承与不变量章节) |
风险登记是动态资产,每次 release / 重大事件后更新。
与其他章节的关系
- 凭证风险的边界承接 → §17 边界与安全
- 降级链应对技术风险 → §13 故障与降级路径
- 评估闭环应对业务风险 → §21 评估闭环
- 演化机制应对演化风险 → §19 演化与版本管理
- 风险缓解的可观测性 → §18 可观测性
- 缺口与风险的边界 → §22 第一阶段缺口
- 风险相关的 ADR → §23 架构决策索引
25. 与里程碑 / 任务的对应
这一节回答:本架构文档的 27 章如何映射到工程实施仓的里程碑切片?M0 走通骨架是什么?后续里程碑怎么 thicken?
范式回顾
详见 ADR-001。要点:
- M0 走通骨架:1 任务类型 × 1 市场 × 1 入口 × 1 状态对象端到端打通(1-2 天),验证契约能在代码上落
- 后续里程碑切片:按维度(任务类型 / 市场 / 入口 / 状态对象 / 工程能力)渐进 thicken
- 每个里程碑过三检 review gate:战略保真度 + 契约回归 + 认知质量评估
本章不重复决策论证,只把 27 章映射到具体里程碑。
frame 重定位(2026-06-04 阶段 0 文档矫正 · 头号结构性偏移纠正):下面的 M0–M7 里程碑序列是在旧的「磨答案」框架下排出的——它把 agent 的循环本体(主动信号 / 失效条件触及自动触发新一轮认知)整体排到了 M5,让 M0–M4 全程在没有自主循环的前提下扩状态(M1)、扩任务(M2)、扩入口(M3)、扩市场(M4)。这正是金融真智能体骨架蓝图(E) 点名的头号偏移:把 §2 已立为 identity 级的 agent 自主循环当成晚期增量功能,结果是「即便建了主回路,后续里程碑预算仍被单次回答优化吸走」。
本次矫正(非破坏插入,不重编号,遵循 ADR-016 先例):
- 最小自主循环切片前移到 M1/M2:把 M5 中「失效条件触及 → 自动触发新一轮认知」这个核心循环的最小切片(哪怕只监控 1 类失效条件、只对 1 个 Fin Object、由一次手动 tick 驱动)下沉为 M1/M2 的交付物 + agent 行为验收(见下方 M1/M2 验收新增项)。M5 退化为该能力的铺面(Channel 投递、批量触发、heartbeat/cron 真实调度)。
- M0–M4 是已知的 pre-agent 阶段:允许 M0 walking skeleton 以 single-shot 起步,但这是已标注的已知风险——若不前移最小循环,M0–M4 会一路把 FinBayes 做成「更好的问答函数」而非 agent。前移切片即是缓解。
- agent 的建造顺序以蓝图「阶段」序为准:蓝图议定结果定义的 阶段 0(文档矫正)→ 阶段 1(最小可用真 agent:主回路 + 1 工具 + 1 真实数据源 + 把
synthesize_cognition降为被回路调用的认知动作 + 落一条 Judgment Record)→ 阶段 2(主动性)→ 阶段 3(加固与可用化) 是当前实际建造序;它与这里的 M0–M7「磨答案」编号并存,冲突时以蓝图阶段序为准。- M0–M7 与 SVA-9 gate 机器的整体按 agent 重排,是 owner 治理连带项(见 CURRENT-MILESTONE §4),本次只做最小切片前移 + frame 标注,不做破坏性全量重编号。
里程碑全景
这张图表达什么:里程碑的依赖序列。M0 必须最先;M1-M3 是基础能力扩展;M4-M5 是范围扩展;M6-M7 是工程闭环。其中 M2 → M4 与 M3 → M5 可一定程度并行。
M1 范围更正(arch-rewrite/ADR-016,2026-05-31):M1 = 状态化 only(Session/Watchlist/Judgment Record/StateCandidate + candidate→confirmed 两步写入,龙头决策 ADR-007)。M0 遗留的认知核实化(
s1完整子流程、MCA 多桶裁决、posterior真算、tag_version锁定,即把确定性 stub 变真算)拆为独立里程碑 M1.5「认知核实化」,置于 M1 后、M2 前(非破坏插入,不重编号 M2–M7)。字段演化矩阵中这些认知字段的收紧时点相应改为 M1.5。
这张图特意不表达什么:每个里程碑的工期(按完工定义而非时间盒,详见 ADR-001);里程碑内的子任务(在 OpenSpec 提案中展开)。
M0 走通骨架
范围
| 维度 | M0 选什么 |
|---|---|
| 任务类型 | 即时认知请求(最常见 + 最简单链路) |
| 市场 | Crypto(数据 Provider 选项最多 / 限制最少) |
| 入口 | CLI(最易调试 + 无 UI 依赖) |
| 状态对象 | Fin Object(基础数据对象,无两步写入复杂度) |
M0 必须打通的链路
M0 覆盖的章节
| 章节 | M0 是否覆盖 |
|---|---|
| §1 至 §3 | ✅ 立架与目标 |
| §4 业务对象与关系 | ✅ 仅 Fin Object + Session(一个默认 Session) |
| §5 用户价值与认知流转 | ✅ 三层价值的"题眼回答"层 |
| §6 关键业务场景 | ✅ 仅 S1 即时认知请求 |
| §7 系统与外部世界 | ✅ Context 图最小子集 |
| §8 进程与服务划分 | ✅ 单进程 |
| §9 子系统组件 | ✅ 6 个子系统的最小可用版本 |
| §10 关键场景流转图 | ✅ 仅 S1 sequence |
| §11 状态对象生命周期 | ⚠️ Fin Object 仅 created 状态,不走两步写入 |
| §12 并发与异步处理 | ✅ asyncio.TaskGroup 基础 |
| §13 故障与降级路径 | ⚠️ 仅 L1 用户配置 Provider implement,L1' / L2 / L3 / L4 全部 stub(详见工程包 m0-walking-skeleton.md §2 接口子集表)。Provider 调用失败时仅记录降级事件 + 抛 ProviderNotReadyError(退出码 20),不真正切换 fallback。L1' 在 M1+ 上线。 |
| §14 部署形态 | ✅ 本地优先单机 |
| §15 数据存储划分 | ⚠️ 仅 State Store(SQLite) + 审计 trail;Cache / Credential / Config 简化 |
| §16 通信协议 | ✅ stdio + HTTPS Provider 调用 |
| §17 边界与安全 | ✅ 输入边界 hook(凭证识别)+ TLS 强制 |
| §18 可观测性 | ⚠️ 审计 trail + task_id trace,指标体系暂不实现 |
| §19 演化与版本管理 | ⚠️ semver 字段约定但不实际触发 migration |
✅ = 完整覆盖;⚠️ = 最小可用,后续里程碑 thicken;空白 = 不在 M0 范围
M0 验收
| 检查 | 通过条件 |
|---|---|
| 战略保真度 | verify-kb grep + 人工审查无禁词命中 |
| 契约回归 | M0 是基线,建立契约 baseline |
| 认知质量 | 手工跑 5 条样例输入,输出含反方 + 失效条件 + 题眼命中 |
| 边界 | 测试集 5 类凭证样式输入全部拒收 |
| 审计 trail | 每次 task 进入审计,含完整 Provider 调用链 |
M1 状态化
范围
- 引入 Session 多实例 + Session 切换
- 引入 Watchlist 与 Watchlist 内的 Fin Object
- 引入 Judgment Record 持久化
- 引入候选 → 已确认两步写入路径
覆盖章节增量
- §11 状态对象生命周期 → 完整 6 个状态机
- §15 State Store → 完整 8 张表
- §9 State Management 子系统 → 完整 candidate / confirmed 路径
M1 验收
- 用户在 Session A 创建一条 Judgment Record → 切换 Session B → 切回 A 仍可见
- candidate 状态对象等待用户确认;用户确认 / 拒绝 / 编辑路径都打通
- 用户主动修改画像 / 删除 Session 等动作齐全
- (agent 行为切片 · 前移自 M5 的状态基础):Judgment Record 必须带可被未来检查的失效条件字段(成立 / 失效条件 + 时间窗),作为 agent 自主触发的条件源——这些字段不是死档,是 M2 最小自主循环的状态前提(承接 §2 agent 本体不变量)
M2 任务类型扩展
范围
- 加复盘任务(引用历史 Judgment Record)
- 加关注流任务(基于 Watchlist)
- LLM Function Calling 工具池扩展(clarify 工具上线)
- 最小自主循环切片(前移自 M5 核心 · 头号 frame 矫正落点):实现「失效条件触及 → 自动发起一轮复盘」的最小闭环——由一次手动 tick / 单次脚本驱动,检查 Watchlist 对象当前值是否触及某条 Judgment Record 的失效条件,触及则 agent 无需用户提问自主发起复盘任务,并把复盘结论写回该 Judgment Record(暂不需 cron / Channel / 批量,那是 M5 铺面)
覆盖章节增量
- §6 关键业务场景 → S3 复盘 + S4 关注流 + S9 主动信号(最小切片)
- §10 关键场景流转图 → S3 + S4 + S5 sequence
- §9.4 State Management 主动信号触发器 → 最小可用版本(手动 tick 驱动,非 cron)
M2 验收
- 复盘任务能正确引用历史 Judgment Record + 输出"信息缺口"
- 关注流任务能基于 Watchlist 当前状态给输出
- LLM 调 clarify 工具的频率 <20%(评估指标)
- agent 行为门(最小自主循环端到端 · M2 首要验收):构造一条带失效条件的 Judgment Record + 一次触及该条件的市场变化(手动喂入)→ agent 无需用户提问即自主发起复盘 → 复盘结论写回原 Judgment Record 形成时间线(不覆盖原判断)。这是旧 single-shot 函数在结构上做不到的 agent 行为;达不到则 M2 判为未交付 agent 切片(哪怕复盘 / 关注流任务质量都达标,也只是更好的问答函数)。
M3 入口扩展
范围
- TUI 入口(Textual / Rich)
- Web API(HTTP + WebSocket)+ 最小 Web UI
覆盖章节增量
- §7 外部接触契约 → 3 个入口完整
- §16 通信协议 → Web API 端点 + WebSocket
M3 验收
- 三入口(CLI / TUI / Web)等价场景输出一致
- Web API 鉴权(localhost only)+ contract_version 协议工作
- Web UI 能查看 Session / Judgment / 主动信号
M4 市场扩展
范围
- US Stocks 市场加入
- 新数据 Provider(如 yfinance / SEC EDGAR)接入
覆盖章节增量
- §4 Fin Object 类型 → 完整覆盖股票 / 板块 / 财报事件
- §6 任务类型 → S2 / S6 等场景在 US Stocks 上运行
M4 验收
- 同一任务类型在两个市场都能跑
- 数据 Provider 失败降级路径覆盖
M5 主动信号(铺面 · 核心循环最小切片已前移 M2)
frame 注(2026-06-04 矫正):主动信号的核心循环(失效条件触及 → 自主发起复盘)的最小切片已在 M2 端到端打通(见 M2 范围 / 验收)。M5 不再是「第一次出现 agent 自主循环」的里程碑,而是把该能力铺面到生产级:真实定时调度(heartbeat / cron 替代 M2 的手动 tick)、批量触发、多渠道投递。这条调整是 §25 头部 frame 重定位的落点之一。
范围
Judgment Record 的失效条件被市场触及时自动触发新一轮认知(核心已前移 M2)→ M5 升级为:heartbeat / cron 真实定时驱动 + 批量扫描所有到期 / 临界 Judgment Record(承接 §6 场景 S10)+ skip/run 结构化判定抗噪- Channel Adapter 选其一(推荐 Telegram,最简单)
覆盖章节增量
- §10 S4 关注流 sequence → 完整
- §9 Input Pipeline → Channel 入口完整
- §13 主动信号触发的批量任务
M5 验收
- 失效条件触及 → 5 分钟内 Channel 投递 + 落审计
- 投递失败重试 + 用户可在 Web 复盘
M6 评估闭环
范围
- Eval Set 第一版(冒烟 + 回归 + 抗扰)
- LLM-as-judge 工程
- nightly 真档评估
覆盖章节增量
- §20 测试体系 → 完整四层
- §21 评估闭环 → 完整闭环
M6 验收
- 评估能在 nightly 跑完 + 报告生成
- 历史失败 case 进入回归集 + 不再回归
- 评估软阈值跑通
M7 演化能力
范围
- Schema migration 真实演练(v1 → v2 测试)
- Prompt 版本化(ADR-009 落地)
- Provider 退役 / 工具退役流程演练
覆盖章节增量
- §19 演化与版本管理 → 完整
- §22 缺口管理 → 工程承接到位
M7 验收
- Schema migration 跑通 + 回滚演练成功
- Prompt 版本切换可观测 + 评估关联
- 一次 Provider 退役完整走完流程
里程碑间的依赖与并行
| 里程碑 | 必须前置 | 可并行 |
|---|---|---|
| M0 | 无 | 无 |
| M1 | M0 | — |
| M2 | M1 | — |
| M3 | M1(不依赖 M2) | M2 |
| M4 | M2 | M3 |
| M5 | M2 + M3 | M4 |
| M6 | M2 | M3 / M4 / M5 |
| M7 | M6 | — |
里程碑工作流落地(呼应 ADR-003)
每个里程碑按 OpenSpec + Archon + Claude Code 主控 + Codex 实施的协作模式(详见 ADR-003):
| 阶段 | 谁做 | 产物 |
|---|---|---|
| Spec | Claude Code | OpenSpec 提案:task packet + 数据结构 diff + 验收口径 + 与本架构文档章节追溯 |
| 实施 | Codex(在 git worktree) | 代码 PR + 测试 + 文档更新 |
| Review | Claude Code | 跑确定性 gate + 跨文档一致性 + 出 review report |
| 认知质量评估 | 工作流维护者 + 跨 Agent 模拟 | 评估报告 |
| Merge + 移交 | Claude Code | 提案进 accepted + 更新 status |
关键约束:每个里程碑的 OpenSpec 提案必须显式追溯到本架构文档的章节(如 "M1 实施 §11 / §15 增量 + ADR-007 决策")。
与其他章节的关系
- 工程范式来源 → ADR-001
- 工程实施栈与协作 → ADR-003
- 战略保真度 review gate → §3 / §17
- 契约回归依据 → §19 演化与版本管理
- 认知质量评估方法 → §21 评估闭环
- 每里程碑审计点 → §26 审计点
- 代码物理位置 → §27 代码仓位置映射
26. 审计点
字段权威定义见 contracts/state-machines.yaml(Step 11 整改包 I 单一事实源层)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:每个里程碑的 review gate 具体审计什么?审计动作的标准动作是什么?谁来执行?
三检审计 + 四类断言
ADR-001 定义"每个里程碑过三检 review gate"。本章把"三检"展开为可执行的具体审计动作。
三检
| 检查项 | 含义 |
|---|---|
| 战略保真度审计 | 工程产物未引入战略禁入概念 / 未违反战略边界 |
| 契约回归审计 | 与上一里程碑的接口契约向后兼容(major 升级除外) |
| 认知质量审计 | 当前里程碑范围内的认知输出符合质量目标 |
四类断言
每检由若干可执行断言组成,分四类:
| 类别 | 检查方式 | 自动化程度 |
|---|---|---|
| 机械断言 | 脚本 / grep / 静态分析 | 完全自动(CI 跑) |
| 结构断言 | schema 校验 / 类型检查 / 依赖图 | 完全自动 |
| 样本断言 | 在评估数据集上跑 + 指标阈值 | 半自动(运行自动,判断需人复核) |
| 语义断言 | 人工审查(PR / spec / 文档一致性) | 人工 |
战略保真度审计动作
机械断言
| 断言 | 实现 | 通过条件 |
|---|---|---|
| 禁词不命中 | verify-kb.mjs 含 banned-concept grep | 全部 0 命中(或仅在拒绝清单列举段) |
| 战略原句存在 | grep 关键句(如"FinBayes 不直接下单"在文档中存在) | 至少一处命中 |
| 凭证字段不在数据 schema | grep private_key / mnemonic / api_secret 等字段名 | 0 命中(白名单:边界 hook 测试 fixture) |
| 执行类工具 category 不在 Capability Registry | 静态分析工具注册代码 | 0 个 category=execution 的工具 |
| TLS 强制 | grep http://(非 localhost)在 Provider 配置 | 0 命中 |
结构断言
| 断言 | 实现 |
|---|---|
| 综合层输出 schema 含反方 / 风险 / 失效条件三字段 | Pydantic schema 校验 |
工具 schema 含 category 字段 + 严格枚举 | OpenAPI / JSON Schema 校验 |
| 审计 trail 字段无凭证类列 | DB schema 静态检查 |
语义断言
| 断言 | 谁做 |
|---|---|
| 同义改写未绕过禁词(如"行动判断"改写为"行动倾向") | Claude Code Review |
| 输出契约语义未偷偷弱化 | Claude Code Review + 工作流维护者复核 |
| 战略不变量未被"工程方便"理由削弱 | 工作流维护者裁决 |
战略保真度阻断条件
战略保真度审计任何一条机械断言失败 = 阻断 merge。语义断言失败 = 进 review 反馈循环。
契约回归审计动作
机械断言
| 断言 | 实现 |
|---|---|
| 既有接口的字段未被删除 | OpenAPI diff |
| 既有字段类型未变更 | Pydantic schema diff |
| 既有错误码语义未变 | 错误码字典 diff |
| contract_version 正确递增 | Git diff + 版本规则校验 |
结构断言
| 断言 | 实现 |
|---|---|
| 数据库 schema 仅增加字段或新表 | SQL DDL diff |
| State Store schema_version 与代码期望版本匹配 | 启动期检查 |
| 删除字段前的 deprecated 标记存在至少一个 minor 版本 | Git 历史扫描 |
样本断言
| 断言 | 实现 |
|---|---|
| 上一里程碑的样例请求在当前里程碑仍能正常处理 | 跑上一里程碑的端到端测试 fixture |
| 既有审计 trail 在新版本下可读 | 加载历史审计文件 + 校验 |
契约回归阻断条件
契约回归审计任何机械 / 结构断言失败 = 阻断 merge。样本断言失败 = 看是否有合理升级路径(如已 deprecated 一版本)。
认知质量审计动作
详细方法见 §21。这里聚焦里程碑级的审计动作:
样本断言
| 断言 | 实现 |
|---|---|
| 当前里程碑范围的冒烟集全过 | 评估运行器跑 + 阈值校验 |
| 回归集无新增失败 | 评估运行器跑 + 对比上一里程碑结果 |
| 抗扰集(边界 case)无新增失败 | 评估运行器跑 |
| Self-consistency 高风险任务的分歧度未上升 | 指标对比 |
语义断言
| 断言 | 谁做 |
|---|---|
| 输出反方覆盖未削弱(如"反方质量"维度未下滑) | 工作流维护者 + 跨 Agent 模拟视角 |
| 表达密度匹配画像(不过密 / 不过疏) | 工作流维护者抽样 |
| 信息缺口处理诚实(没数据时不硬编) | 工作流维护者抽样 |
认知质量阻断条件
- 回归集失败 = 阻断 merge(硬阈值)
- 抗扰集失败 = 阻断 merge(边界相关,等同硬阈值)
- 冒烟集软阈值下降 >5% = warn + 必须 PR 描述里说明原因
- 语义断言不通过 = 进 review 反馈循环
各里程碑的审计点
M0 走通骨架审计
| 审计项 | 通过条件 |
|---|---|
| 战略保真度 | 全部机械断言 + 全部结构断言通过 |
| 契约回归 | 建立基线(M0 是基线 → 无前置对比) |
| 认知质量 | 5 条样例跑通 + 包含反方 + 失效条件 + 题眼命中 |
| 边界 | 5 类凭证样式输入 100% 拒收 |
| 审计 trail | task_id 贯穿 + Provider 调用链完整 |
M1 状态化审计
| 审计项 | 通过条件 |
|---|---|
| 战略保真度 | 同 M0 + 用户主权 5 维度全部可用 |
| 契约回归 | M0 baseline 100% 兼容 |
| 认知质量 | 候选 → 已确认两步路径可被评估观测 |
| 状态机 | 6 个状态机的所有转移都有测试 |
M2-M7 审计
每个里程碑的具体审计点在 OpenSpec 提案中由 Claude Code 起草,遵循"机械 + 结构 + 样本 + 语义"四类断言模板。
审计执行模型
这张图表达什么:每个 PR 走机械 + 结构断言(CI 自动)+ 样本断言(评估运行器)→ 人工 review 语义断言 → merge。所有审计结论进入审计记录。
这张图特意不表达什么:每条审计的具体工具实现(在工程实施仓 CI 配置);审计争议的仲裁流程(在 governance/change-protocol.md)。
审计的可观测性
审计自身需要可观测:
| 维度 | 实现 |
|---|---|
| 每次审计的结论 | 进 release notes + 审计 trail |
| 责任人 | PR review 字段 + 审计记录 |
| 时间 | 自动记录 |
| 阻断历史 | 哪些断言曾经阻断过 + 解决路径 |
| 审计 SLA | 每个里程碑的 review 应在 X 工作日内完成(不是软指标,是流程承诺) |
审计 vs 测试 vs 评估的关系
| 维度 | 测试(§20) | 评估(§21) | 审计(本章) |
|---|---|---|---|
| 触发 | 每次 PR + nightly | 周期 + release | 每个里程碑 |
| 对象 | 业务正确性 / 协作 / 边界 | 认知质量 / 趋势 | 里程碑产物整体 |
| 通过 | assert + 覆盖率 | 指标 + 阈值 | 三检通过 |
| 负责 | 工程实施 Agent | 评估运行器 + 工作流维护者 | Claude Code Review + 工作流维护者 |
测试与评估是审计的输入证据。审计是更高层的"这一刻这一切是否能合并到主分支"的综合判定。
审计的边界
审计不替代:
- 战略层的决策(战略变更走 governance/change-protocol.md)
- 工程实施的细节决定(PR 描述中说明)
- 用户的真实使用反馈(在线评估信号)
审计就只做三件事:
- 这次里程碑产物是否符合战略边界(保真度)
- 这次里程碑产物是否破坏既有用户(契约回归)
- 这次里程碑范围内认知质量是否未退化
与其他章节的关系
- 三检 review gate 来源 → ADR-001
- 工程协作模式 → ADR-003
- 战略不变量与禁入概念 → §2 / §17
- 契约版本化策略 → §19
- 评估测试方法 → §21
- 里程碑切片 → §25 与里程碑/任务的对应
- 代码层审计点的物理位置 → §27 代码仓位置映射
27. 代码仓位置映射
字段权威定义见 contracts/code-paths.yaml(Step 11 整改包 I 单一事实源层,src/finbayes/* + evals/)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:本架构文档的概念在 FinBayes 工程实施仓里的物理位置是什么?章节里的"子系统 / 工具 / 状态对象 / Prompt"具体落在哪个目录哪个模块?
工程实施仓与本仓的关系
| 仓 | 角色 | 内容 |
|---|---|---|
| 本仓(Labs-FinTecAI) | 知识库 + 治理库 | 战略 / 架构 / ADR / 提案 / 调研 |
| FinBayes 工程实施仓 | 工程代码 + 测试 + 运行配置 | runtime / 工具实现 / 测试 / CI / 部署脚本 |
两仓严格分离(详见 CLAUDE.md "工程执行产物不进本仓")。本架构文档(本仓)是契约事实源,工程实施仓的代码必须追溯到本架构文档某章节。
工程实施仓的物理路径由工作流维护者维护,不写入本仓(路径约束详见本仓 CLAUDE.md)。本章用抽象路径表达映射,工程实施仓内的实际目录名按 Python 项目惯例。
顶层目录约定
工程实施仓采用 Python 标准 src layout:
finbayes/ # 工程实施仓根
├── src/finbayes/ # 主代码(包根)
├── tests/ # 测试
├── evals/ # 评估数据集 + 评估运行器
├── prompts/ # Prompt 资产(YAML / 模板)
├── migrations/ # State Store schema migration 脚本
├── configs/ # 配置模板(用户实际 config 在 OS 用户目录)
├── scripts/ # 工具脚本(备份 / 诊断 / 等)
├── docs/ # 工程实施仓自己的运维文档(不重复本仓)
└── .github/ or .ci/ # CI 配置
关键约定:
- 业务代码全部在
src/finbayes/(不在仓根散落) - 测试与代码 1:1 镜像(
tests/test_<module>.py) - 评估资产与测试分开目录(评估是独立的运行模式,详见 §21)
子系统映射(§9 6 子系统)
| 子系统 | 抽象路径 | 关键模块 |
|---|---|---|
| Input / Output Pipeline | src/finbayes/io/ | entries/(CLI/TUI/WebAPI/MCP/Channel 各子模块)/ boundary.py(边界 hook)/ normalize.py(输入归一化)/ formatter.py(输出格式化)/ stream.py(流式输出) |
| Task Orchestration | src/finbayes/orchestration/ | task.py(task 对象 + 生命周期)/ dispatcher.py(任务分发)/ function_calling.py(LLM Function Calling 集成)/ clarify.py(clarify 工具) |
| Evidence + Synthesis | src/finbayes/cognition/ | evidence/(证据归一化 + EvidencePacket)/ synthesis/(综合层)/ self_consistency.py(多采样)/ schema.py(输出契约) |
| State Management | src/finbayes/state/ | store.py(State Store 抽象)/ session.py / watchlist.py / judgment.py / profile.py / candidate.py(两步写入)/ audit.py(审计 trail) |
| Capability Registry | src/finbayes/capabilities/ | registry.py(工具注册 + 校验)/ tools/(各工具实现的子目录)/ schema.py(工具元数据) |
| Provider Adapter Pool | src/finbayes/providers/ | adapter.py(统一接口)/ llm/(OpenAI compatible / Anthropic / DeepSeek / Ollama / 等)/ data/(外部数据 Provider)/ readiness.py(探测)/ routing.py(task_routing) |
业务对象映射(§4 7 个 First-Class 概念)
| 概念 | Pydantic 模型路径 | 持久化表 |
|---|---|---|
| Session | src/finbayes/state/session.py:Session | sessions |
| Watchlist | src/finbayes/state/watchlist.py:Watchlist | watchlist_objects |
| Judgment Record | src/finbayes/state/judgment.py:JudgmentRecord | judgment_records |
| Dynamic Profile | src/finbayes/state/profile.py:DynamicProfile | dynamic_profiles |
| State Candidate | src/finbayes/state/candidate.py:StateCandidate | state_candidates |
| Fin Object | src/finbayes/state/fin_object.py:FinObject | fin_objects |
| Task | src/finbayes/orchestration/task.py:Task | (内存为主 + 审计 trail) |
关键约束:
- 业务对象 schema 用 Pydantic v2(详见 arch-rewrite/ADR-008 accepted;该 ADR 是 LLM Provider 接口抽象。StructuredCognitionResult 字段定义见 whitepaper-rewrite/ADR-008 supplement accepted)
- schema 字段变化必须走 §19 演化策略
- 业务对象互引用通过 ID(不直接嵌入对象,避免循环 ref)
状态机映射(§11 6 个状态机)
| 状态机 | 实现位置 |
|---|---|
| Session 生命周期 | src/finbayes/state/session.py:SessionState |
| Task 生命周期 | src/finbayes/orchestration/task.py:TaskState |
| TaskGroup 生命周期 | src/finbayes/orchestration/task_group.py:TaskGroupState |
| Judgment Record 生命周期 | src/finbayes/state/judgment.py:JudgmentState |
| State Candidate 生命周期 | src/finbayes/state/candidate.py:CandidateState |
| Provider Readiness | src/finbayes/providers/readiness.py:ProviderReadinessState |
Fin Object 与 Watchlist 没有独立状态机(详见 §11 开篇说明)—— Watchlist 状态由 StateCandidate +
watchlist_objects表承载,Fin Object 仅 created/archived 标记。
数据存储映射(§15 5 类数据)
| 数据类别 | 物理位置 | 实现模块 |
|---|---|---|
| State Store | OS 数据目录 SQLite 文件 | src/finbayes/state/store.py + migrations/ |
| Cache | Redis 或内存 LRU | src/finbayes/cache/ |
| Config Store | OS 配置目录 YAML | src/finbayes/config/ |
| Credential Store | OS Keychain | src/finbayes/security/credentials.py |
| Audit Trail | SQLite 同库不同表 | src/finbayes/state/audit.py |
关键约束:
- 用户实际数据不在工程实施仓 —— 仓内只有 schema 与代码,运行时数据在用户机器的 OS 标准目录(§14)
migrations/内的脚本编号严格递增(如001_initial.sql/002_add_audit_trail.sql)
通信协议映射(§16)
| 协议层 | 实现位置 |
|---|---|
| 进程内(Python 调用) | 各子系统间直接 import |
| CLI 入口 | src/finbayes/io/entries/cli/ |
| TUI 入口 | src/finbayes/io/entries/tui/ |
| Web API + WebSocket | src/finbayes/io/entries/web/ |
| MCP Server | src/finbayes/io/entries/mcp/ |
| Channel Adapter | src/finbayes/io/entries/channels/(按平台分子目录) |
| LLM Provider HTTP | src/finbayes/providers/llm/ 各 adapter |
边界与安全映射(§17)
| 约束 | 实现位置 |
|---|---|
| 输入边界 hook | src/finbayes/io/boundary.py |
| 凭证识别规则 | src/finbayes/security/credential_patterns.py |
| 输出端凭证样式扫描 | src/finbayes/io/output_filter.py(arch-rewrite/ADR-010 accepted,规则见 ADR-010 §3) |
| 执行类工具注册拒绝 | src/finbayes/capabilities/registry.py:register_tool |
| 用户数据隔离(user_id) | src/finbayes/state/store.py 查询层 |
| TLS 强制 | src/finbayes/providers/http_client.py |
可观测性映射(§18)
| 资产 | 位置 |
|---|---|
| 审计 trail 写入器 | src/finbayes/state/audit.py |
| Task trace ID 管理 | src/finbayes/orchestration/trace.py |
| 指标采集 | src/finbayes/observability/metrics.py |
| 用户视角 CLI 命令 | src/finbayes/io/entries/cli/commands/(含 status / trace / audit / cost / session) |
| 日志分级与脱敏 | src/finbayes/observability/logging.py |
Prompt 资产映射(§19 + ADR-009 待)
混合策略下的路径约定:
| Prompt 类型 | 位置 |
|---|---|
| System Prompt(策略 A 进代码仓) | prompts/system/ |
| 任务模板(策略 A) | prompts/task_templates/(按任务类型分) |
| 输出契约 schema 关联 prompt(策略 A) | prompts/synthesis/ |
| 实验性 Prompt(策略 B) | prompts/experimental/ + 自描述 delivery_mode: data 字段 |
| Judge Prompt(评估专用) | prompts/eval_judges/ |
关键约束:
- 每个 Prompt 文件有 frontmatter:
prompt_id / prompt_version / delivery_mode / author / activated_at - 策略 A Prompt 进 Git diff + Review gate 覆盖
- 策略 B Prompt 在 runtime 启动时加载 + 进审计 trail
测试资产映射(§20)
| 测试类型 | 位置 |
|---|---|
| 单元测试 | tests/unit/(与 src/finbayes/ 镜像) |
| 集成测试 | tests/integration/ |
| 端到端测试(快档 Mock) | tests/e2e/quick/ |
| 端到端测试(真档真 LLM) | tests/e2e/real/ |
| 降级路径测试 | tests/degradation/ |
| 边界与安全测试 | tests/boundary/ |
| LLM Mock fixture | tests/fixtures/llm/ |
| 测试用业务对象 fixture | tests/fixtures/state/ |
评估资产映射(§21)
| 评估资产 | 位置 |
|---|---|
| 评估数据集(冒烟 / 回归 / 场景 / 抗扰) | evals/datasets/(按层分子目录) |
| 评估运行器 | evals/runner/ |
| Rubric 定义 | evals/rubrics/ |
| Judge Prompt | prompts/eval_judges/(与 prompts 共享) |
| 评估结果库 | (运行时,不在仓)evals/results/(gitignore) |
| 评估报告模板 | evals/reports/ |
CI 集成映射
| CI 阶段 | 实现 |
|---|---|
| PR:单元 + 集成 + 端到端快档 + 边界 + verify-kb | .ci/pr-pipeline.yml |
| Nightly:含真 LLM + 评估 | .ci/nightly.yml |
| Release:完整评估 + 性能基线 | .ci/release.yml |
| 战略保真度审计脚本 | scripts/audit_strategy_fidelity.py |
| 契约回归审计脚本 | scripts/audit_contract_regression.py |
配置文件映射(§14 + §15)
工程实施仓内只有模板 —— 用户实际配置在 OS 用户目录:
| 配置 | 模板位置(工程实施仓) | 运行时位置(用户机) |
|---|---|---|
config.yaml | configs/templates/config.yaml | OS 配置目录(按平台,§14) |
providers.yaml | configs/templates/providers.yaml | 同上 |
task_routing.yaml | configs/templates/task_routing.yaml | 同上 |
ui.yaml | configs/templates/ui.yaml | 同上 |
部署与运行脚本映射
| 脚本 | 位置 |
|---|---|
finbayes 入口(CLI) | src/finbayes/__main__.py |
| 安装引导(首次初始化) | src/finbayes/install/wizard.py |
| 备份与恢复 | scripts/backup.py / scripts/restore.py |
| 诊断打包 | scripts/diagnostic.py |
| Schema migration runner | migrations/runner.py |
章节到代码的反向追溯
工程实施仓的代码反向追溯到本架构文档:
| 机制 | 实现 |
|---|---|
| 每个 PR 的描述必须显式引用 CHAP-NN / ADR-NNN | OpenSpec 提案要求 |
| 每个 module 的 docstring 含章节引用 | 工程实施约定 |
| 每个 ADR 的"关联"段含反向 CHAP 列表 | ADR 模板 |
| 章节追踪表(status.md)随实施进展更新 | 工作流维护者职责 |
工程实施仓的代码不进本仓
关键边界:
- 工程实施代码不进本仓(即使是示例代码段在文档里也只用伪代码 / schema)
- 运行时数据 / 用户配置 / Controller state / task packet 不进本仓
- 工程实施仓的本地路径不写入本仓的任何文档(详见本仓 CLAUDE.md)
工程实施仓的物理路径由工作流维护者在本地记录(用户级 memory),不进本仓。
与其他章节的关系
- 子系统职责定义 → §9 子系统组件
- 业务对象定义 → §4 业务对象与关系
- 状态机定义 → §11 状态对象生命周期
- 数据存储定义 → §15 数据存储划分
- 通信协议定义 → §16 通信协议
- 边界与安全约束 → §17 边界与安全
- 可观测性资产 → §18 可观测性
- 演化资产 → §19 演化与版本管理
- 测试资产 → §20 测试体系
- 评估资产 → §21 评估闭环
- 工程协作 → ADR-003 工程实施栈与协作
- 里程碑产出 → §25 与里程碑/任务的对应
- 审计点 → §26 审计点
28. M0 工程包(附录)
这一节回答:M0 走通骨架实施所需的字段级 schema、Pydantic 模型、SQLite DDL、CLI 规格、Mock fixture、凭证正则、audit payload schema、bootstrap 模板、CI 模板等"工程材料"在哪里?
M0 工程包独立成 task-oriented 文档
M0 走通骨架实施所需的全部工程材料不在主架构文档中展开,而是集中在独立的 task-oriented 文档:
projects/finbayes/engineering/engineering-packs/m0-walking-skeleton.md
该文档专为工程化落地 Agent(Codex / Claude Code)一次性 load + 直接消费而设计,含 15 节:
| § | 内容 |
|---|---|
| §1 | M0 范围与 walking skeleton 链路 |
| §2 | M0 接口子集表(6 子系统 × implement/stub/skip = 34 个签名固定的接口) |
| §3 | M0 核心 Pydantic 模型 v0(5 个 types.py 完整代码 + placeholder 类型节) |
| §4 | M0 SQLite DDL v0(4 张业务表 + 1 张元表,含 PRAGMA / 索引) |
| §5 | AuditEvent.payload 按 event_type 字段集(10 种 event 的 schema) |
| §6 | M0 CLI 命令规格(5 命令 + 流式输出 + JSON 输出 + 6 个退出码) |
| §7 | M0 Mock Provider Fixture 规范(目录 + hash 算法白名单 + Provider API 变化检测) |
| §8 | M0 5 条样例输入 + 期望"能力清单"(含可 eval 的 pytest_check 表达式) |
| §9 | M0 5 类凭证 Negative Test Fixture(含 expected_reject_category 与 confidence) |
| §10 | 凭证识别正则基线 v0(5 类 Python pattern + BIP-39 词表 source + Luhn 算法) |
| §11 | M0 输出判定规则 v0(不依赖 LLM-as-judge,退化为 Pydantic + 人工 5 条 checklist) |
| §12 | 工程实施仓发现路径协议(OpenSpec task packet 必备字段) |
| §13 | 工程实施仓 Bootstrap 模板(pyproject + 工具链 + uuid4 + Pydantic ConfigDict + Exception 类层级 + 日志脱敏) |
| §14 | M0 三检 Review Gate CI 模板 |
| §14.5 | CI 接口规范(7 个未提供脚本/测试的接口定义) |
| §14.6 | M0 baseline 文件位置与格式 |
| §15 | 与主架构 / ADR 的承接 |
约 1640 行,工程实施 Agent 可一次 load。
为什么独立成文件
| 理由 | 说明 |
|---|---|
| 上下文负担 | 主架构 6500 行 + M0 工程包 1600 行 合并为 8000+ 行,工程实施 Agent 一次性 load 占 75-85% context,多文件操作易爆 |
| task-oriented vs architecture-oriented | 主架构是"FinBayes 是什么"(业务建模 + 系统全景 + 横向贯穿),M0 工程包是"M0 怎么做"(task packet 级别的可执行材料),消费路径不同 |
| 与 ADR-001 / ADR-003 范式一致 | Walking Skeleton + 里程碑切片 + OpenSpec task packet —— 每个 milestone 一个独立工程包是范式的自然映射 |
| 演化路径清晰 | M1-M7 各起独立工程包(m1-state-confirmation.md 等),不污染主架构 |
Agent 消费路径
| Agent 任务 | 应 Load 的文档 |
|---|---|
| M0 实施 | engineering-packs/m0-walking-skeleton.md + 主架构 §17(边界)+ 主架构 §27(代码仓位置)作 cross-check |
| 架构 Review / 战略保真度审计 | 主架构全文 |
| ADR 起草 | 主架构 §23 + 相关章节 + 调研产物 |
| M1+ 实施(未来) | 对应 engineering-packs/m{N}-*.md + 主架构横向贯穿章节 |
后续里程碑工程包(待起草)
| 里程碑 | 工程包文件 | 状态 |
|---|---|---|
| M0 走通骨架 | engineering-packs/m0-walking-skeleton.md | ✅ 已起草 |
| M1 状态化(候选两步写入 + 完整 8 表) | engineering-packs/m1-state-confirmation.md | 待起草 |
| M2 任务类型扩展(复盘 + 关注流 + clarify) | engineering-packs/m2-task-types.md | 待起草 |
| M3 入口扩展(TUI + Web API) | engineering-packs/m3-multi-entry.md | 待起草 |
| M4 市场扩展(US Stocks) | engineering-packs/m4-market-extension.md | 待起草 |
| M5 主动信号(失效条件触发 + Channel) | engineering-packs/m5-proactive-signal.md | 待起草 |
| M6 评估闭环(LLM-as-judge) | engineering-packs/m6-eval-loop.md | 待起草 |
| M7 演化能力(migration + Prompt 版本化) | engineering-packs/m7-evolution.md | 待起草 |
横向贯穿关注点(边界 / 可观测性 / 演化)的工程切片合订:engineering-packs/horizontal-concerns-bundle.md(待起草)。
与其他章节的关系
- M0 范围与 walking skeleton 链路上位 → §25 与里程碑/任务的对应
- 三检 Review Gate 上位 → §26 审计点
- 业务对象 Pydantic 模型上位 → §4 业务对象与关系
- 子系统接口上位 → §9 每个子系统的内部组件
- 状态机定义上位 → §11 状态对象生命周期
- 数据存储 DDL 上位 → §15 数据存储划分
- 凭证识别策略上位 → §17 边界与安全
- 审计 trail 上位 → §18 可观测性
- 测试体系上位 → §20 测试体系
- 代码物理位置上位 → §27 代码仓位置映射
29. 认知体系工程承接(4 子系统索引)
字段权威定义见 contracts/mca-buckets.yaml / contracts/evaluation-dimensions.yaml / contracts/structured-cognition-result.yaml(Step 11 整改包 I 单一事实源层)。本段为叙述用途,若与 contracts/ 不一致以 contracts/ 为准。承接 Step 11 整改方案。
这一节回答:ADR-007 supplement 锁定的金融认知体系第一版正式构成(8 机制 + MCA 7 分轴 + S1 跨机制子流程 + 11 维评测 + Phase 5 治理)与 ADR-008 supplement 锁定的 StructuredCognitionResult 1.0 → 1.1 机制层输出契约扩展,在 L3 架构层由哪些子系统承接。
上位 ADR-007 supplement 状态为 accepted(持续构建),v2 触发条件见 supplement Phase 5 治理段;本节 L3 承接同步保留「持续构建」状态语义,不得在工程化期间衰减为「已锁」。
这一节做什么
本节只放索引段。4 个子系统的职责定义 / 接口契约 / 数据流 / 关键依赖 / 测试要求 / v1 工程回退 / 待解决问题 / 跨子系统接口对齐在 认知体系工程承接子系统目录 的 4 份独立文档展开。
本节不重写既有 §9 六子系统章节,新增 4 子系统与既有 6 子系统正交:
- 既有 6 子系统(§9 每个子系统的内部组件):通路层(输入 → 编排 → 证据综合 → 状态 → 工具 → Provider)。
- 本节新增 4 子系统:认知层(图谱 / 一致性中间件 / 上下文分类 / 评测)。
4 子系统索引
| 子系统 | 承接的认知体系组件 | 核心输出 | 工程文档 |
|---|---|---|---|
| KnowledgeGraphService | M1 关系建模含跨市场映射边 + M3 phase 时钟 + M5 制度摩擦传导 + M6 资本结构与货币双轨 | causal_graph(含 correlation_regime)+ phase_evidence(含 phase_matrix) | 知识图谱服务 |
| ConsistencyMiddleware | S1 跨机制子流程(4 失败模式 a/b/c/d + attention 二阶分支 + 回路收敛 N=3 + 反向触发) | s1(8 字段输出) | 一致性中间件 |
| MCAClassifier | MCA 7 分轴(B1-B7 含 B5a/B5b 拆分 + 影响下游机制参数选择) | Task schema 元数据 mca_bucket(不进 StructuredCognitionResult 本体) | 市场上下文分类器 |
| EvalHarness | 11 维评测 + 7 MCA 桶 + 70/20/10 三集 + IAA kappa 门槛 + 半人工标注 SLA + 退化追踪 | 离线评测报告 + Phase 5 治理触发信号 | 评测台架 |
与上位事实源的 cross-reference
- 行为契约(机制语义 / 触发条件 / 反向耦合 / 回路收敛上限 / 失败模式枚举):ADR-007 supplement 金融认知体系第一版正式构成。
- 工程契约(字段名 snake_case 终态 / 数据类型 / 必选可选 / 版本兼容策略 / 半人工标注承接 / 审计 trail 写入要求):ADR-008 supplement 机制层输出契约扩展。
- 半人工标注 SLA(4 任务 A / B / C / D 的延迟 / 准确率 / IAA / 升级路径 / 治理对接):Phase 7 半人工标注 SLA 附录。
- 治理流程(季度全量 / 月度增量 / 触发式专项 / 4 触发源 / 变更分级门槛 / 案例库 / 防退化机制):Phase 5 迭代治理机制。
跨子系统依赖关系
这张图表达什么:4 子系统的输入输出依赖。MCAClassifier 是横切强先验提供方,KnowledgeGraphService 与 ConsistencyMiddleware 协同产出 StructuredCognitionResult 1.1 的 6 个新顶层字段,EvalHarness 离线消费全量结果并反向触发 Phase 5 治理的子机制级修订。
这张图特意不表达什么:与既有 §9 六子系统(Input/Output Pipeline / Task Orchestration / Evidence + Synthesis / State Management / Capability Registry / Provider Adapter)的协作时序。两层正交,时序流转见每份子系统文档的「数据流」段。
与既有章节的关系
- 既有 6 子系统通路层:§9 每个子系统的内部组件。
- StructuredCognitionResult 字段定义事实源:上述 ADR-008 supplement。
- 状态持久化(图谱快照 / Case Library / 审计 trail):§15 数据存储划分 + §18 可观测性。
- 测试体系上位:§20 测试体系 + §21 评估闭环。
- M0 走通骨架的最小子集落地:M0 走通骨架工程包。
本节边界
本节是索引段,不重写既有架构章节。后续 v1 实现路径建议:
- M0 阶段以最小子集落地(参见 ADR-008 supplement §5.2):
phase_evidence.clocks/causal_graph.nodes+causal_graph.edges主体 /applicability_flags三支柱 level + reason /posterior.mode_a+posterior.mode_b/s1.s1_mode+s1.coupling_direction+s1.confidence/mca_bucket七轴 +bucket_label。 - M1–M3 里程碑逐步补齐剩余子字段(含
phase_matrix.cells/correlation_regime.pair_correlations/s1.second_order_branch/regulation_status.friction_layer等)。 - 半人工标注 SLA 落地(任务 A / B / C / D reviewer 工作流 24 小时 SLA)由 Phase 7+ 承接。
- v1 → v2 升级路径走 Phase 5 治理流程(≥ 4 case 跨 ≥ 2 桶 + ≥ 1 pending 桶证据)。
- 主架构防膨胀硬约束:见 主架构膨胀守门机制(≥ 80 行新增强制拆出指针段;M0 收尾按 5% / 10% 阈值复盘)。
Changelog / 演化记录
2026-06-04(kelly_cap 退役传播补扫 · 收尾确认 · 落实 ADR-021 · kelly_cap 退役):§29 M0 最小子集落地清单中的 kelly_cap 字段名引用已移除——不确定性仍由双峰重尾后验(posterior.mode_a / posterior.mode_b)承载,仅「凯利仓位上限」这个字段形态随 ADR-021 退役。连带补净 产品定义 §7.3 posterior 行残留的「凯利上限」措辞(ADR-021 原传播与实现侧补扫均漏覆盖 product-definition)。留 owner 处理(本次未擅自改):eval-harness §D6 的 C_kelly/凯利合规率权重重归一属评测契约决定,留 FinTecEval / owner;contracts/tasks-fields-mapping.yaml 的 kelly_cap_policy 属权威契约层、由 owner 统一处置(contracts/field-surface-mapping.yaml 的 block_tokens 含 kelly_cap 为「拦截退役 token」的正确兜底,应保留)。
2026-06-04(阶段 0 文档矫正 · (A) 类 frame 段 · 依据金融真智能体骨架蓝图(E)#2 + owner 议定结果):把架构层的 FinBayes 定性从「越往下游越退化成单次问答函数」矫正回「带自主循环的认知 agent」。①§2 新增 identity 级架构不变量「FinBayes 产品本体是带自主循环的认知 agent,主动信号 / 自主复盘循环是 identity 级能力、不是晚期里程碑增量功能」+ 快速核查补第 5 条;②§5 认知流转主线图从「以『用户是否沉淀』为可选支路」改为「agent 默认闭环」(自主监控循环为常开骨架、单回合问答为入口之一);③§6 场景集补 S10/S11/S12 三个 agent 自主行为场景,把被动:主动配比从 8:1 纠正为 8:4;④§9.2 Task Orchestration 加 frame 说明「单回合编排 + 主动信号触发器 = agent 的两个半」;⑤§25 里程碑头号偏移矫正:旧序把 agent 循环本体(主动信号)排到 M5,本次非破坏插入——最小自主循环切片前移到 M2(M1 备状态基础 + M2 端到端闭环 + agent 行为门首要验收),M5 退化为铺面(cron / Channel / 批量),并标注 M0–M4 为已知 pre-agent 阶段、agent 建造以蓝图阶段序为准、全量重编号为 owner 治理连带项(遵循 ADR-016 非破坏插入先例)。注:§29 line M0 最小子集仍含 kelly_cap 字段名(ADR-021 已退役),属 ADR-021 传播遗漏、非本次 frame 矫正范围;已落实:见本节顶部同日「kelly_cap 退役传播补扫」条目。
2026-05-29:清理 §21 评测体系中的旧 8 维 rubric 事实源漂移——把已被 11 维 D1-D11 取代的 v1 8 维 rubric 表显式标记为 DEPRECATED,明确指向权威事实源 contracts/evaluation-dimensions.yaml 与 Eval Harness 11 维评分公式(D1-D11),保留旧表作为 v1 演化历史上下文但移除其作为评分契约的语义。