第十五节 — 数据存储划分
这一节回答: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 | 卸载 + 完全删除所有数据(不可恢复) |
战略不变量"用户画像主权"在数据操作层的完整承接。