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:
@@ -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。
|
||||
@@ -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