第十三节 — 故障与降级路径
这一节回答: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 → 可观测性章节
- 测试如何覆盖各降级路径 → 测试体系章节