RAG Gateway Stack:从文档入库到可追溯回答的工程复盘
RAG Gateway Stack 已经从框架学习与服务骨架推进到文档入库、普通问答、Agent 和观测工作台。一次问答的价值,不只是生成了文字,还包括能解释检索范围、回查引用、观察工具调用,并在断线后继续接收同一次生成。
本文于 2026-10-03 对照 GitHub 已发布提交 0771a82 核对。这里区分源码实现、仓库验证入口和真实运行证据:功能存在不等于本文已在当前机器运行整套服务,也不等于生产验收完成。
1. 当前系统的边界
1 | React Workbench |
浏览器只访问 Gateway,FastAPI 保留为内部业务入口。C++ 处理协议与流量边界,Python 承担变化更快的 RAG 和 Agent 编排;前端用于调试、演示与观察执行流程。
1.1 数据以谁为准
| 组件 | 保存什么 | 工程含义 |
|---|---|---|
| MySQL | 文档状态、chunk 正文、消息、citations、任务和 Trace | 结构化业务事实来源 |
| LanceDB | 向量、chunk 标识与检索元数据 | 可重建的检索索引 |
| Redis | Celery broker / result backend、可选的网关限流状态 | 任务与短期运行状态 |
已发布检索实现使用 LanceDB。网站中的 FAISS 学习笔记 仍用于理解向量检索基础,不能据此把当前项目描述成 FAISS 或 BM25 + FAISS 系统。
2. 从文件和网页进入同一条入库链路
文件通过 POST /v1/documents 上传;网页通过 POST /v1/documents/web 抓取正文并保存为普通文档。文件入口支持 Markdown、TXT、JSON、CSV、PDF、DOCX 和 XLSX。网页入口不负责登录页面或复杂反爬。
1 | 创建文档记录 |
解析和 embedding 是两个任务,任务元数据记录 queued、document_loaded、document_chunked、chunks_written、embedding_started 等阶段。工作台因此可以显示 Parsing、Chunking、Embedding、Indexed 或 Failed,而不是仅显示一个没有依据的总体百分比。
2.1 上传成功不等于建库完成
上传响应包含文档和任务标识;调用方还需要通过 GET /v1/tasks/{task_id} 查询阶段,并确认文档索引状态。网页导入返回的 status_url 可能是内部路径,外部客户端应依据 task_id 请求 Gateway 的 /v1/tasks/ 入口。
3. 普通 RAG 怎样形成可回查答案
1 | 用户问题 |
没有传 doc_id / doc_ids 时,检索面向当前可用的 indexed 文档;传入后限制到指定文档。召回分数、重排分数、原始 rank 和最终 rank 分别保留,便于判断问题发生在召回、回表还是重排。
citations 保存文档和 chunk 标识,可以从已保存的消息重新查询。当前引用粒度是消息与 chunk;没有逐句 answer span 时,工作台展示本次检索证据,不虚构逐句来源连线。
4. Agent 增加的是决策与执行记录
4.1 只读工具和三层记忆
当前工具包括 knowledge_search、get_document_detail、list_ready_documents 和 list_message_citations。Agent 注入用户长期记忆、会话摘要及近期消息,再进行意图路由和工具循环。
| 工具结果 | 处理方式 |
|---|---|
ok=true |
将 data 作为工具观察加入上下文 |
ok=false |
记录错误与 Trace,允许根据已有观察降级回答 |
明显的知识库问题会通过轻量意图路由优先执行检索;问候和普通闲聊不会被强制检索。这个规则针对当前系统,不代表一个通用的意图分类器。
4.2 Trace 与答案事件
1 | agent_step -> tool_call -> tool_result -> delta -> final -> done |
工作台展示 run、step、工具名和事件 ID。工具返回时,LanceDB 召回、MySQL 回表和 rerank 信息可能一起到达,界面据真实事件推进,不编造逐节点实时耗时。当前 Agent 的最终答案在运行完成后一次性通过 delta 输出;普通 Chat 的 token 增量与 Agent 步骤流要分别理解。
5. SSE 续传为什么必须复用同一次运行
普通 Chat 首次请求携带 content,Gateway 创建用户消息,并通过 X-User-Message-ID 返回标识。重连移除 content,使用同一个 user_message_id 与 Last-Event-ID。Agent 使用同一个 session 与 trace_id 识别运行。
1 | 首次请求:创建消息 / 运行 -> 接收并保存事件 ID |
重发原始内容会被视为新消息,可能重复生成。源码默认在完成后保留续传状态 15 分钟;这份状态在进程内,过期或进程重启后不能保证恢复。状态缺失时返回明确错误,不静默重新生成。
6. 工作台能证明什么
React Workbench 展示文档索引阶段、Execution Flow、回答与引用、Agent SSE Trace 和依赖状态。它把“请求正在进行”拆成可观察的事实,但不能代替业务验收。
| 验证层次 | 当前仓库提供的入口 | 仍需记录的证据 |
|---|---|---|
| 逻辑回归 | 检索、切片、工具、记忆、Trace、续传测试 | 对应提交、测试命令与实际输出 |
| 服务联通 | /internal/health、/health、监控概览 |
依赖可用性与降级状态 |
| 完整用户路径 | scripts/e2e_all.sh |
上传、任务完成、回答与引用回查 |
| 模型质量 | 固定问题与 bad case 分析 | 召回、重排和答案支撑程度 |
运行与验收笔记 给出当前启动命令、API 示例与失败路径。本文没有在博客构建环境执行模型、数据库或跨服务 E2E。
7. 后续工作的实际边界
- Gateway SSE 代理仍按活跃流占用受限数量的 OS thread;高并发需要进一步验证传输模型。
- 对外没有历史 Sessions / Agent Runs 列表接口,前端刷新后的历史展示受此限制。
- LanceDB 没有独立健康接口,没有索引证据时不能显示已就绪。
- 多租户隔离、生产密钥管理、部署编排及逐句证据映射仍不属于当前完成能力。
下一轮应先固定问题集和断线测试,保存运行环境、提交、引用与失败日志,再围绕测得的瓶颈调整系统。学习笔记和实现源码都可以保留,但项目进度最终要落在可重复的用户路径上。