# 文档上传、审核、向量化与检索运行手册 本手册用于验证当前已经落地的 synthetic 产品主链:浏览器上传公开虚构文档,经本地安全解析、 人工绑定 outbound manifest 审批、异步向量化和原子激活后,能够被正式 Retrieval API 检索。 这条链路已经在 Docker 中连续两次端到端通过;它证明工程状态机、幂等性和向量写库契约可运行, 但不代替真实百炼授权、真实地质语料质量、PDF/OCR 或最终论文盲测验收。 ## 1. 最短启动与验证 首次克隆后初始化仅存在于本机、已被 Git 忽略的 Secret 文件: ```bash 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](adr/0007-split-local-and-model-workers.md)。 排查时使用: ```bash 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. 浏览器操作 访问 。页面按以下顺序工作: 1. 在浏览器本地校验扩展名、MIME 和 100 MiB 上限,并计算 SHA-256。 2. 创建带随机 `Idempotency-Key` 的上传声明,随后流式写入隔离上传卷。 3. 完成上传并轮询 `PARSE_DOCUMENT` 任务;本地 Worker 不调用任何云模型。 4. 展示 `display_text`、拟出域的 `cloud_text`、来源锚点和 outbound manifest。 5. 审核人确认 exact manifest 后批准,或选择稳定原因码拒绝。 6. 批准后轮询 `EMBED_DOCUMENT`;向量完整性通过后文档才显示 `READY`。 7. 转到 检索刚刚激活的内容,或到 验证带引用的单轮问答。 当前页面的“停止”只会停止浏览器上传请求或任务轮询。后台任务一旦提交,不会因关闭页面而 被强制取消;Worker 依靠租约、心跳、fencing token 和 reaper 恢复。 ## 4. 状态机与不可绕过的门禁 ```text 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 位于 。入库主链使用以下接口: | 方法与路径 | 用途 | |---|---| | `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,不需要百炼。切换真实模式前必须完成: 1. 在百炼北京地域控制台撤销任何曾出现在聊天、日志或截图中的旧 Key。 2. 创建具备 `text-embedding-v4`、`qwen3-rerank`、`deepseek-v4-flash` 权限的新 Key。 3. 只把新 Key 写入已忽略的 `secrets/bailian_api_key`;真实工作空间 URL 只写本地部署配置。 4. 确认 Key、专属工作空间域名、北京地域和计费方案属于同一空间。 5. 重启 `model-gateway` 及调用方,运行: ```bash 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: ```bash 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 结果替代。