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
11 KiB
文档上传、审核、向量化与检索运行手册
本手册用于验证当前已经落地的 synthetic 产品主链:浏览器上传公开虚构文档,经本地安全解析、 人工绑定 outbound manifest 审批、异步向量化和原子激活后,能够被正式 Retrieval API 检索。 这条链路已经在 Docker 中连续两次端到端通过;它证明工程状态机、幂等性和向量写库契约可运行, 但不代替真实百炼授权、真实地质语料质量、PDF/OCR 或最终论文盲测验收。
1. 最短启动与验证
首次克隆后初始化仅存在于本机、已被 Git 忽略的 Secret 文件:
make setup-hooks
bash scripts/init-local-secrets.sh
make up
make status
make seed-offline
make smoke-document
make up 等价于 docker compose up -d --build,会启动数据库、两个 Worker、模型隔离网关、
API、入口 Gateway 和 Web,并等待迁移与上传卷初始化成功。make seed-offline 创建 synthetic
profile 和公开虚构检索基线;make smoke-document 使用
data/samples/public/upload_demo.md 加入本次运行 nonce 后,自动完成一次全新的上传、解析、审批、
向量化、激活和检索;随后在同一次运行中重放相同声明与内容,验证 ID 不变且不会重复建任务。
smoke 中的 SYNTHETIC_REVIEW_APPROVED 是只针对公开 fixture 的自动契约检查;真实资料必须由
有权限的审核人通过 /documents 检查 exact cloud text 与 manifest,不能自动批准。
成功的 smoke 输出只包含不透明 ID、状态、rank、citation、模型名和重排状态,不输出正文或 Secret。历史上曾用固定 fixture 连续两次验证相同 document/document-version ID,数据库计数均保持:
| 对象 | 幂等计数 |
|---|---|
| document version | 1 |
| chunk | 1 |
| vector assignment | 1 |
| background job | 2(解析 1 + 向量化 1) |
| model invocation | 1 |
当前 smoke 每次命令都会创建带随机 nonce 的新文档,避免历史 READY 数据让当前故障误通过;
同一次命令末尾会重放同一幂等键与内容,并要求 upload、document、parse job、active version 身份
保持不变。输出中的 replay_confirmed=true 才表示该双重检查完成。该结果只适用于提交的
synthetic fixture 和当前冻结配置;换文件、切分 profile 或 embedding profile 会生成不同身份。
2. Exited (0) 不是服务暂停
docker compose ps -a 中以下两个容器应当成功运行一次后退出:
migrate:执行alembic upgrade head;Exited (0)表示迁移已经应用成功。upload-init:以最小临时权限初始化上传卷属主和目录;Exited (0)表示初始化成功。
它们不是长期服务,不应保持 Up,也不应配置 restart: always。只有非零退出码才代表启动
失败。长期容器的期望状态如下:
| 服务 | 期望状态 | 说明 |
|---|---|---|
db |
Up (healthy) |
PostgreSQL + pgvector |
model-gateway |
Up (healthy) |
唯一持百炼 Key 与公网出口 |
api / gateway / web |
Up (healthy) |
API、固定上游入口、浏览器页面 |
worker-local |
Up |
只处理 document_parse,挂载上传卷,无模型网络/Token |
worker-model |
Up |
只处理 embedding,可访问模型网,不挂载上传卷 |
两个 Worker 的信任边界、Secret、网络和卷约束见 ADR-0007。
排查时使用:
make status
docker compose logs --tail=200 migrate upload-init api worker-local worker-model
curl -sS http://127.0.0.1:8000/health/ready
不要因为 Alembic 日志最后停在 Will assume transactional DDL 就判断服务挂起;先查看容器
退出码、API readiness 和依赖服务状态。
3. 浏览器操作
访问 http://127.0.0.1:8000/documents。页面按以下顺序工作:
- 在浏览器本地校验扩展名、MIME 和 100 MiB 上限,并计算 SHA-256。
- 创建带随机
Idempotency-Key的上传声明,随后流式写入隔离上传卷。 - 完成上传并轮询
PARSE_DOCUMENT任务;本地 Worker 不调用任何云模型。 - 展示
display_text、拟出域的cloud_text、来源锚点和 outbound manifest。 - 审核人确认 exact manifest 后批准,或选择稳定原因码拒绝。
- 批准后轮询
EMBED_DOCUMENT;向量完整性通过后文档才显示READY。 - 转到 http://127.0.0.1:8000/retrieval 检索刚刚激活的内容,或到 http://127.0.0.1:8000/chat 验证带引用的单轮问答。
当前页面的“停止”只会停止浏览器上传请求或任务轮询。后台任务一旦提交,不会因关闭页面而 被强制取消;Worker 依靠租约、心跳、fencing token 和 reaper 恢复。
4. 状态机与不可绕过的门禁
upload CREATED
-> STORED
-> COMPLETED
-> document QUARANTINED_LOCAL_REVIEW
-> PARSE_DOCUMENT / worker-local
-> LOCAL_PARSED_PENDING_CLOUD_REVIEW
-> OCR_REQUIRED 或 FAILED(禁止继续)
-> 人工审核 exact outbound manifest
-> REJECTED(终止)
-> CLOUD_APPROVED
-> EMBED_DOCUMENT / worker-model
-> PENDING -> EMBEDDING -> READY
-> version READY + document.active_version_id 原子切换
-> document READY + chunks searchable
-> 正式 Retrieval 候选
上传成功、解析成功和审批通过都不等于“已可检索”。正式 Retrieval 的 SQL 在 LIMIT 前要求
知识库、服务端授权 scope、active version、CLOUD_APPROVED、正确 profile、READY assignment
和 searchable=true 同时成立。审批使用 review_revision 乐观并发控制,并绑定 exact outbound
manifest hash;旧页面、变化后的正文或变化后的 profile 不能复用审批。
当前 TXT、Markdown、DOCX 走确定性本地解析;PDF 会 fail closed 为 OCR_REQUIRED。这表示系统
没有把 PDF/OCR 或地质图空间理解伪装成已完成能力。
5. API 级手工检查
Swagger 位于 http://127.0.0.1:8000/docs。入库主链使用以下接口:
| 方法与路径 | 用途 |
|---|---|
POST /api/v1/document-uploads |
声明文件名、MIME、大小和 SHA-256;要求 Idempotency-Key |
PUT /api/v1/document-uploads/{id}/content |
上传原始字节,入口上限 100 MiB |
POST /api/v1/document-uploads/{id}/complete |
校验摘要并创建文档/解析任务 |
GET /api/v1/document-jobs/{id} |
轮询解析或向量化任务 |
GET /api/v1/documents |
查看文档状态 |
GET /api/v1/documents/{id}/review-bundle |
分页查看解析结果与 manifest |
POST /api/v1/documents/{id}/review-decisions |
使用 revision + manifest 批准或拒绝 |
POST /api/v1/retrieval/search |
验证 READY 文档可检索 |
推荐用 make smoke-document 作为可重复验收;手工拼装请求时不要把文件正文、数据库 DSN、
内部 Token 或百炼 Key 写进 shell 历史、截图或工单。
6. 常见错误排查
| 现象/错误 | 含义 | 检查与处理 |
|---|---|---|
migrate 或 upload-init 为 Exited (0) |
正常一次性任务终态 | 检查长期服务是否 Up/healthy,不要反复重启一次性任务 |
UPLOAD_*、摘要/大小不匹配 |
声明与实际字节不一致或上传状态冲突 | 重新选择原文件;不要修改声明后复用 upload ID |
OCR_REQUIRED |
PDF 当前不在可靠解析范围 | 换用 TXT/Markdown/DOCX 验证;等待 OCR/PDF adapter |
REVIEW_REVISION_CONFLICT |
revision 或 manifest 已变化 | 刷新 review bundle,重新人工复核后提交 |
| 文档停在待审核 | 安全门禁正常工作 | 在 /documents 检查 cloud text 和 manifest,再批准或拒绝 |
embedding job FAILED |
profile、维度、模型调用或完整性校验失败 | 查看脱敏 error code 和 worker-model 日志;不要直接改 searchable |
| 文档 READY 但检索不到 | scope/profile/active version 或 seed 基线不一致 | 先运行 make seed-offline,再检查 retrieval 的生效 profile 与 trace |
| 百炼三能力返回 401 | Key、北京工作空间、端点或模型权限不匹配 | 按第 7 节重新做 provider smoke;401 不自动重试 |
日志和 API Problem 必须只包含稳定错误码、trace 和不透明 ID。若发现任何 Secret 或受限正文,
立即停止真实调用、轮换凭证并运行 make check-secrets。
7. 切换到真实阿里云百炼
synthetic E2E 使用 fake embedding/rerank,不需要百炼。切换真实模式前必须完成:
- 在百炼北京地域控制台撤销任何曾出现在聊天、日志或截图中的旧 Key。
- 创建具备
text-embedding-v4、qwen3-rerank、deepseek-v4-flash权限的新 Key。 - 只把新 Key 写入已忽略的
secrets/bailian_api_key;真实工作空间 URL 只写本地部署配置。 - 确认 Key、专属工作空间域名、北京地域和计费方案属于同一空间。
- 重启
model-gateway及调用方,运行:
docker compose restart model-gateway api worker-model
docker compose --profile tools run --rm provider-smoke
只有 Embedding、Rerank、Chat 三项最小实际调用全部成功,才能运行真实 seed-demo 和真实文档
向量化。当前已验证事实仍是三项请求到达供应商但均返回 401,因此真实百炼未验收;不能用
synthetic smoke 的成功替代这项外部门禁。
三项探测成功后,先运行 docker compose --profile tools run --rm seed-demo 创建独立的百炼
synthetic 知识库及 active profile,再在未提交的 .env 中设置
DOCUMENT_NAMESPACE_MODE=bailian,重建 API 和模型 Worker,最后运行 fresh + replay smoke:
docker compose --profile tools run --rm seed-demo
docker compose up -d --force-recreate api worker-model
make smoke-document
此时上传声明的知识库/scope 仍由服务端固定选择,请求不能自行越权指定;输出中的
knowledge_base_id 应为百炼 synthetic 命名空间,向量由 text-embedding-v4 生成并写入
pgvector,检索经 qwen3-rerank。切回离线回归时把该配置恢复为 fake 并重建 API。
在认证、RBAC 和资料出域审批完成前,这个开关只允许公开虚构资料,不能用于私有或真实报告。
API、浏览器、worker-local、seed/smoke 工具都不持百炼 Key。worker-model 只有内部 Worker
Token,真正的百炼 Key 始终只存在于 model-gateway。任何真实资料还必须先完成权利、涉密和
云处理审批;有效 Key 不等于有权把资料发送到云端。
8. 当前验证基线与剩余范围
截至 2026-07-13,提交前全量门禁记录为 296 项后端测试、53 项前端测试,并完成固定身份重放与 fresh + replay 两类 Docker synthetic 产品链 E2E。正式毕业验收仍需完成真实百炼认证、PDF/OCR、真实 授权语料、多租户/RBAC、至少 300 题正式双审盲测、备份恢复、性能/并发压测、论文定稿和答辩 彩排。这些未完成项不能由本手册的 smoke 结果替代。