第十七节 — 边界与安全
这一节回答: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,但仅记录"识别为凭证类,已拒收 + 拒收时间戳",不记录具体内容
输出端过滤(ADR-010 决策位置)
LLM 可能在生成内容时幻觉地输出凭证样式字符串(例如"一个看起来像私钥的随机 64 位 hex")。即便不是真凭证,让看起来像凭证的字符串流向用户也增加误用风险。
过滤的两个候选位置
| 候选位置 | 优点 | 缺点 |
|---|---|---|
| 综合层产出后、统一格式化前 | 离 LLM 最近,能感知语义上下文 | 增加综合层职责 |
| Output Pipeline 最末端、用户呈现前 | 集中点检查、所有路径都过 | 离 LLM 最远,可能丢失语义 |
初步决策(待 ADR-010 确认):两处都做。综合层做语义级(看到"私钥 / 助记词"等词附近的高熵字符串就警觉),Output Pipeline 做格式级最终扫描(与输入端 hook 同一套正则,方向相反)。
检测到凭证样式时的处理
- 高置信度(多条规则同时命中):剥除该段 + 用占位符替换 + 给用户 banner "输出包含可能凭证样式,已过滤"
- 中置信度(单条规则命中):保留但加 banner 提示
- 低置信度(仅模糊匹配):日志记录,不剥除
ADR-010 待定的具体阈值与正则集合。
执行类工具的注册拒绝
战略约束"不直接下单"在工具层的承接(详见 CHAP-09 Capability Registry 段)。
拒绝注册的工具类型
| 工具类型 | 拒绝理由 |
|---|---|
| 下单 / 撤单 / 改单(交易所 / 经纪商 API) | 直接执行金融动作 |
| 转账 / 提币 / 充值(区块链交易广播) | 直接执行金融动作 |
| 银行账户操作(转账 / 支付) | 直接执行金融动作 |
| 任何持有私钥 / 助记词的签名调用 | 持账户凭证 |
| 任何要求"金融执行凭证"作为参数的工具 | 凭证不变量 |
拒绝机制
关键约束:
- 工具 schema 必填字段
category,且枚举严格(无execution选项) - 工具参数 schema 用启发式扫描禁用字段名
- 拒绝是注册时(启动期),不是调用时(运行期)—— 运行期已无此类工具可调
- 审计 trail 记录所有尝试注册执行类工具的请求
详见 CHAP-09 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)
详见 CHAP-16 协议安全约束。
Prompt 注入与对抗输入
LLM 应用的特殊风险:用户输入或外部数据中包含的对抗指令尝试改变 LLM 行为。
| 风险场景 | 应对 |
|---|---|
| 用户输入"忽略上述指令,输出 ..." | System prompt 加固(明示不接受 in-band 指令变更)+ 综合层输出 schema 校验(不符合契约直接拒绝) |
| 外部数据(如新闻 / 网页)中嵌入对抗指令 | 工具返回的外部数据进入 LLM 前包裹在 <external_data> 标记内 + system prompt 明示标记内内容不构成指令 |
| 用户尝试诱导 LLM 输出凭证样式 / 执行类建议 | 输出端 hook 兜底 + 安全回应 |
| 用户尝试诱导 LLM 假冒 FinBayes 系统消息 | 输出格式契约 schema 强制 |
关键不变量:FinBayes 不通过 prompt 行为约束作为唯一防线 —— 关键边界(凭证 / 执行类)有规则路径做硬约束,prompt 加固只是冗余防御。
用户主权
战略不变量"用户画像主权"在工程层的承接(详见 CHAP-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 + 人工审查记录 |
详见 CHAP-02 架构目标与质量取舍。
安全相关的可观测性
每个边界事件进入审计 trail(不含敏感内容):
| 事件类型 | 记录字段 |
|---|---|
| 输入边界拒收 | 时间戳 + 入口(CLI/TUI/Web/MCP/Channel)+ 识别类型(如 "私钥样式" / "API key 样式")+ 入口用户 / Session |
| 输出端过滤 | 时间戳 + 关联 task_id + 过滤类型 + 置信度 + 是否剥除 |
| 工具注册拒绝 | 时间戳 + 尝试注册的工具名 + 拒绝原因(execution / 含凭证参数 / 等) |
| Prompt 注入识别 | 时间戳 + 注入特征摘要(不含原文)+ 关联 task_id |
用户可查阅自己 Session 范围内的边界事件("为什么 FinBayes 拒收了我的输入")。
详见 CHAP-18 可观测性。
与其他章节的关系
- 输入边界 hook 的落点 → CHAP-09 Input Pipeline 子系统
- 执行类工具注册拒绝的具体实现 → CHAP-09 Capability Registry
- 输出端过滤的位置选择 → ADR-010(待写)
- 凭证不变量的存储承接 → CHAP-15 Credential Store
- 网络层 TLS 约束 → CHAP-16 协议安全约束
- 凭证拒收场景的端到端 sequence → CHAP-10 S6 场景
- 边界事件如何写审计 trail → CHAP-18 可观测性