本文档说明页证智答的端到端运行链路、主要耗时来源和后端 API。README 只保留入口说明,详细流程以本文档为准。
系统的主链路可以概括为:上传文档 -> 渲染页面图 -> 建立 ColPali / MUVERA 双表示索引 -> 检索证据页 -> 多模态模型生成答案 -> 返回原页截图溯源。
当前网页端默认不显式传 retrieval_mode,后端会按 two_stage 路径处理;评测脚本可切换到 colpali_only / muvera_only 做检索消融。默认路径会先使用 MUVERA 单向量 FDE 在 Qdrant 中进行第一阶段 Prefetch,再用 ColPali 原始多向量执行 MaxSim 精排。当前 20 题小规模 benchmark 尚未显示该路径优于 colpali_only 或 muvera_only,因此两阶段更适合作为面向更大规模语料的工程结构准备。
- 接收 PDF / 图片 / PPTX 文件。
- 将文档统一转换为页面图像。
- PPTX 会先转成 PDF,再复用现有 PDF 转页图链路。
- 使用 ColPali 为每一页生成多向量视觉特征。
- 使用 MUVERA 生成固定维度单向量 FDE,作为第一阶段快速召回特征。
- 将 ColPali 原始多向量与 MUVERA 单向量 FDE 一起写入 Qdrant。
- 用户问题先经过轻量规则 guard,拦截明显与文档内容无关的身份类或闲聊问题,例如“你是谁”“讲个笑话”;这一阶段只做快速规则匹配,不额外调用 LLM,避免无效检索开销。
- 如果问题包含多个由
?、?、;、;或换行拆出的独立子问题,后端会先做多子问题拆分与查询规划,再对子问题分别检索并在后端合并证据页。- 例如“文档提到了哪些人物?他们分别负责什么;结论是什么?”会被拆成多个子问题分别检索,减少多问合并时只覆盖单一主题的问题。
- 若后续子问题出现“他 / 它 / 那它”这类指代,后端会优先桥接前一个子问题的局部上下文,再进入后续检索改写逻辑。
- 对单问题或每个子问题分别生成查询向量。
- 默认
two_stage路径先用 MUVERA 单向量 FDE 做 Prefetch,再用 ColPali 原始多向量执行 MaxSim 精排。 - 若有页面达到最小相关性阈值(默认
score >= 0.60),则直接使用这些证据页生成答案。 - 若 strict evidence 不足以填满当前证据窗口,后端会补入少量 near-threshold 页面,减少 raw 命中但 final 丢页的情况。
- 若某个问题或子问题连 near-threshold 页面也没有,但仍检索到候选页,则回退到该问题或子问题得分最高的 1 页证据继续生成答案;若页面内容已明确写出答案,可直接作答,否则会在说明层提示证据质量或写明无法确认。
- 将最终合并后的证据页截图与证据元数据送给豆包多模态模型生成答案。
当前项目是多模态视觉 RAG,慢主要来自三类成本,而不是单一组件瓶颈:
- 文档预处理:PDF 转图、PPTX 转 PDF 再转图,本身就有 IO 与图像处理开销。
- 视觉嵌入:ColPali 要对每页图像做多向量推理,这是上传阶段最重的本地计算。
- 最终回答生成:检索完成后还要调用豆包多模态模型生成答案,这通常比 Qdrant 查询更慢。
项目当前已在日志中输出如下时序:
- 上传阶段:
document_render_ms、embedding_ms、point_build_ms、qdrant_upsert_ms、total_index_ms - 检索阶段:
query_embedding_ms、qdrant_query_ms、result_format_ms、total_retrieval_ms - 生成阶段:
first_token_ms、total_generation_ms
如果面试官问“为什么慢,是不是电脑性能太弱”,更准确的回答是:
这是一个以视觉理解和可追溯性为优先目标的多模态 RAG 原型。上传时要做文档转图和视觉嵌入,问答时当前默认走两阶段检索路径,并调用外部多模态模型生成答案,所以整体链路天然比纯文本 RAG 更重。机器性能会影响体验,但真正的优化方向应该基于分段时序数据来判断,而不是直接把问题归因为电脑弱。
现实中的产品之所以通常不会让用户感到这么慢,核心不是只靠更强的机器,而是靠系统设计把重活拆开:
- 异步索引:上传接口已改为先秒回
task_id,后台再做转图、嵌入和入库,并通过 SSE 推送阶段进度。 - 分层检索:优先走更轻的文本索引或缓存命中,只有必要时才回退到更重的视觉检索。
- 更轻的在线模型:先用更快的模型给出首答或首 token,再决定是否调用更重模型补全高保真答案。
- 缓存与预计算:对热门文档、热门问题、文档文本层和页面特征做预热,尽量避免重复计算。
所以,真实产品“感觉很快”的关键在于:用户不需要同步等待整条最重的视觉 RAG 链路跑完。
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/api/rag/upload |
上传文件并立即返回 task_id,后台异步索引 |
GET |
/api/rag/jobs/{task_id} |
查询上传任务当前状态 |
GET |
/api/rag/jobs/{task_id}/events |
通过 SSE 订阅上传任务进度 |
POST |
/api/rag/chat |
发起对话查询 |
GET |
/api/rag/files |
列出所有已索引文档 |
GET |
/api/rag/files/{id}/download |
下载原始文件 |
DELETE |
/api/rag/files/{id} |
删除文档及其索引 |
GET |
/api/health |
服务健康检查 |
- 评测指标与运行方式见 evaluation_guide.md。
- 当前 benchmark 结果和项目介绍表述见 project_pitch.md。