Make the governed RAG evidence path executable end to end
Some checks failed
verify / verify (push) Has been cancelled
Some checks failed
verify / verify (push) Has been cancelled
Separate local parsing from model indexing, bind review decisions to immutable manifests, persist vectors behind active profiles, and expose retrieval, chat, evaluation, and document workflows through the React workbench. Constraint: Live Bailian authentication currently fails for all three configured capabilities Rejected: Direct upload-to-embedding flow | bypasses local review and manifest binding Confidence: high Scope-risk: broad Directive: Keep private-data deployment blocked until authentication, RBAC, and separate database roles land Tested: make verify; fresh and replay Docker document smoke; worker recovery smoke; frozen synthetic evaluation; migration 0003-0004 roundtrip Not-tested: Successful live Bailian calls, OCR, real multi-user authorization
This commit is contained in:
56
docs/adr/0006-deterministic-local-ingestion.md
Normal file
56
docs/adr/0006-deterministic-local-ingestion.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# ADR-0006:采用确定性本地解析、切分与出域清单
|
||||
|
||||
- **状态:** accepted
|
||||
- **日期:** 2026-07-13
|
||||
|
||||
## 背景
|
||||
|
||||
文档进入百炼向量模型前,系统必须能证明“发送了哪段文本、来自哪个版本和页面、由什么配置
|
||||
产生、是否经过明确审批”。如果解析和切分结果随运行变化,embedding cache、引用锚点、审批
|
||||
manifest 和实验结果都会失去可复现性。PDF、DOCX 和扫描图件的能力也不能被模糊成同一种
|
||||
“已解析”状态。
|
||||
|
||||
## 决策
|
||||
|
||||
第一版建立纯本地、无模型调用的确定性入库核心:
|
||||
|
||||
- 严格验证文件大小、扩展名、声明 MIME 与内容签名;用户文件名永不作为存储路径。
|
||||
- TXT 支持严格 UTF-8/UTF-16;Markdown 恢复标题层级;DOCX 仅在 ZIP/XML 安全上限内提取
|
||||
标题、段落和表格行。
|
||||
- 不手写 PDF 文本或空间解析。没有可靠 parser/OCR adapter 时,PDF 明确进入
|
||||
`OCR_REQUIRED`,不产生切片或出域清单。
|
||||
- 规范化文本按结构块优先切分,默认 target 512、hard max 800、overlap 64。Tokenizer
|
||||
将 `ZK1203` 等字母数字地质标识符视为一个 token;块边界只能把窗口扩展到 hard max 内。
|
||||
- `display_text`、`cloud_text`、`embedding_text` 分离;embedding 输入固定为版本化前缀加
|
||||
已审批 cloud text。
|
||||
- parser、normalization、chunk、cloud policy 和 embedding 配置均计算 profile hash;规则变化
|
||||
生成新版本或 cache epoch,不能错误复用旧向量和审批。
|
||||
- chunk ID、source anchor 和 outbound manifest 由输入 hash、配置 hash、ordinal 与源范围
|
||||
确定性派生。每个锚点保留文档版本、页、块、行和字符范围;DOCX 无渲染引擎时物理页为
|
||||
`null`,不能伪造页码。
|
||||
- 任何外发必须在 manifest hash 与审核请求完全匹配后发生。上传/解析阶段无百炼调用。
|
||||
|
||||
## 安全限制
|
||||
|
||||
DOCX adapter 拒绝路径穿越、符号链接、重复条目、加密标志、宏、ActiveX、嵌入对象、DTD、
|
||||
XML entity、超大条目、过多条目和异常压缩比。错误只返回稳定 code,不包含文件名、正文、
|
||||
路径、密钥形态或底层异常。
|
||||
|
||||
凭证形态出现在上传文本时默认 fail closed,以防误把配置文件或日志当知识文档外发。未来如果
|
||||
确有合法语料包含类似字符串,必须新增受审计的本地脱敏策略,不能简单关闭该门禁。
|
||||
|
||||
## 被否决方案
|
||||
|
||||
1. **按固定字符数随意切片:** 中文、地质编号、表格和章节边界不可复现,无法稳定评测。
|
||||
2. **直接把原文同时用于展示、向量和生成:** 无法证明脱敏和出域审批覆盖的准确文本。
|
||||
3. **用标准库或正则手写 PDF 解析:** 不能可靠处理字体映射、多栏顺序、扫描页和加密状态。
|
||||
4. **把 OCR 图例视为空间理解:** OCR 只能识别局部文字,不恢复地图拓扑、比例和几何关系。
|
||||
|
||||
## 后续约束
|
||||
|
||||
- 调整 token 规则、target/max/overlap、前缀、脱敏策略或 parser 行为时,必须修改 profile hash
|
||||
版本并重跑 golden fixture、manifest、向量缓存和引用回归。
|
||||
- 引入 PyMuPDF、OCR 或多模态模型需要独立 adapter、依赖/镜像评审和 ADR;不能替换 raw
|
||||
artifact,必须保留新 revision。
|
||||
- 解析成功不等于可出域;只有 `CLOUD_APPROVED` 且 manifest/profile 绑定一致的 chunk 才能
|
||||
进入 Embedding、Rerank 或 Chat。
|
||||
78
docs/adr/0007-split-local-and-model-workers.md
Normal file
78
docs/adr/0007-split-local-and-model-workers.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# ADR-0007:拆分本地解析 Worker 与模型 Worker 的信任边界
|
||||
|
||||
- **状态:** accepted
|
||||
- **日期:** 2026-07-13
|
||||
|
||||
## 背景
|
||||
|
||||
文档入库同时涉及两类高风险资源:原始上传文件,以及访问云模型的能力。若一个通用 Worker
|
||||
同时挂载上传卷、内部模型 Token 和模型网络,那么解析器漏洞、恶意 DOCX/PDF 或任务 payload
|
||||
缺陷可能把未经审批的原文直接发送到云端。仅靠业务代码中的状态判断,无法形成可独立验证的
|
||||
最小权限边界。
|
||||
|
||||
本项目仍采用模块化单体和同一个后端镜像;拆分的是运行身份、capability、网络、卷和 Secret,
|
||||
不是拆成两套业务服务或数据库。两个 Worker 当前仍共用同一个 PostgreSQL 应用角色,因此该拆分
|
||||
只隔离上传卷、模型 Token 和网络能力,不构成数据库授权边界。
|
||||
|
||||
## 决策
|
||||
|
||||
Compose 运行两个互斥能力的长期 Worker:
|
||||
|
||||
| 边界 | `worker-local` | `worker-model` |
|
||||
|---|---|---|
|
||||
| capability | `document_parse` | `embedding` |
|
||||
| 数据库网络 | 有 | 有 |
|
||||
| 内部模型网络 | 无 | 有 |
|
||||
| 公网 egress | 无 | 无;只能访问 internal `model-gateway` |
|
||||
| 上传卷 | 有 | 无 |
|
||||
| 数据库 app Secret | 有 | 有 |
|
||||
| model-gateway Token | 无 | Worker 身份 Token |
|
||||
| 百炼 API Key | 无 | 无 |
|
||||
|
||||
`model-gateway` 是唯一持有百炼 API Key 和普通 egress 网络的进程;它不连接数据库、不挂载上传
|
||||
卷,也不发布宿主机端口。`worker-model` 只能发送数据库中已通过 manifest 审批的 `cloud_text`,
|
||||
不能读取原始文件。`worker-local` 能读取隔离上传卷,但没有模型网络与 Token,即使解析器被恶意
|
||||
文件影响,也缺少直接调用模型的凭据和路由。
|
||||
|
||||
两个 Worker 均以非 root 后端用户运行,根文件系统只读,使用临时 `/tmp`、`no-new-privileges`
|
||||
和 `cap_drop: ALL`,不暴露端口。它们共用 PostgreSQL 任务队列,但领取 SQL 只匹配各自
|
||||
`required_capability`。心跳、失败回写、阶段提交和最终激活必须匹配 `job_id + lease_owner +
|
||||
lease_token` 且租约仍有效,避免旧进程覆盖已重领任务。
|
||||
|
||||
上传卷初始化由一次性 `upload-init` 完成。该容器临时以 root 运行,但 `network_mode: none`、根
|
||||
文件系统只读,只保留初始化目录所需的最小文件能力,成功后正常 `Exited (0)`;长期 API 和
|
||||
`worker-local` 不获得这些额外 capability。
|
||||
|
||||
## 被否决方案
|
||||
|
||||
1. **单一通用 Worker 同时挂卷和模型 Token:** 部署简单,但把未审核原文与云出口放在同一
|
||||
攻击面,违背 manifest 审批门禁。
|
||||
2. **只靠 Python `if review_state == CLOUD_APPROVED`:** 状态判断仍然需要,但不能替代网络、
|
||||
Secret 和文件系统的纵深隔离。
|
||||
3. **每种任务拆成独立代码仓库/数据库:** 当前单机规模没有对应收益,会引入分布式事务、双写、
|
||||
部署和备份复杂度。
|
||||
4. **让 `worker-model` 直接访问百炼公网:** 会把供应商协议、Key 和公网出口扩散到业务进程,
|
||||
无法集中轮换、限流和脱敏错误。
|
||||
|
||||
## 影响
|
||||
|
||||
- 优点:原始文件与云调用能力不能在单个长期 Worker 中汇合;Compose 契约可直接验证卷、网络
|
||||
和 Secret;不同任务可独立扩缩容。
|
||||
- 代价:需要维护两个 Worker 服务和 capability 路由;跨阶段任务只能通过数据库中的已审批
|
||||
工件交接,不能依赖本地临时文件。
|
||||
- 限制:Docker internal network 是重要纵深防线,但不是形式化沙箱;API 与两个 Worker 当前共享
|
||||
数据库应用角色,文档 Actor 也仍是服务器固定的 synthetic 身份。真实多用户/私有数据部署必须
|
||||
先落地认证、对象级 RBAC、分离数据库角色或受控存储过程,并结合主机防火墙、出口 allowlist、
|
||||
集中 Secret Manager、容器运行时策略和审计。
|
||||
|
||||
## 后续约束
|
||||
|
||||
- 新增 OCR Worker 时默认归入本地高风险解析边界,除非独立 ADR 证明它需要模型出口;OCR
|
||||
结果仍须重新生成并审批 outbound manifest。
|
||||
- 任何服务若要同时获得上传卷与模型网络/Token,必须先做威胁建模、更新 ADR 并增加 Compose
|
||||
契约测试,不能通过临时排障静默扩大权限。
|
||||
- 新任务类型必须声明唯一 `required_capability`,并验证错误能力的 Worker 无法领取。
|
||||
- `DOCUMENT_NAMESPACE_MODE` 只能由服务端部署配置选择 `fake` 或 `bailian` synthetic 命名空间;
|
||||
请求不得携带任意 scope 绕过授权。真实多租户上线前必须用认证/RBAC 替代固定 Actor。
|
||||
- 变更 Worker 网络、卷、Secret 或部署拓扑时,必须重跑 document pipeline Docker E2E、租约
|
||||
fencing smoke、Secret 扫描和 Compose 安全契约。
|
||||
@@ -9,3 +9,5 @@ ADR 用于记录会长期影响系统的技术决策。状态使用 `proposed`
|
||||
- [0003-text-first-scope.md](0003-text-first-scope.md):第一版采用文本优先边界,不宣称地质图空间理解。
|
||||
- [0004-secretless-web-ingress.md](0004-secretless-web-ingress.md):用无 Secret 的 Nginx Web 与固定上游 gateway 隔离浏览器、API 和数据库网络。
|
||||
- [0005-isolate-model-egress.md](0005-isolate-model-egress.md):用独立 Model Gateway 隔离百炼 Key、模型出口与数据库感知服务。
|
||||
- [0006-deterministic-local-ingestion.md](0006-deterministic-local-ingestion.md):冻结本地解析、512/800/64 切分、文本分离和 outbound manifest 契约。
|
||||
- [0007-split-local-and-model-workers.md](0007-split-local-and-model-workers.md):拆分本地解析与模型 Worker 的网络、卷、Secret 和 capability 信任边界。
|
||||
|
||||
Reference in New Issue
Block a user