00-开篇:把 RAG 从知识点带回 NexaRAG 项目
GitHub项目链接:chenyu-hao/NexaRAG
00-开篇:把 RAG 从知识点带回 NexaRAG 项目
GitHub项目链接:chenyu-hao/NexaRAG
前面写 RAG 学习系列时,更多是在拆知识点:文档清洗的意义,chunk 切分的边界,embedding 和向量检索解决的问题,BM25 的价值,rerank 和上下文工程的位置,引用、拒答、评测、动态更新各自属于哪一层。
这些内容学完以后,会有一种“我知道 RAG 应该长什么样”的感觉。但真正回到项目里,问题会换一种方式出现。
比如,trace 字段的存放位置、上传文档时 metadata 的来源、chunk_id 的稳定性、BM25 和向量检索的合并方式、rerank 之后证据进入 prompt 的方式、模型输出 [E3] 以后的引用校验、删除文档后旧 chunk 的召回控制,都需要在项目里落地。
这些都是项目里的落点问题。
所以这组文章想做的事,是把 RAG 从知识点带回 NexaRAG 项目。它会以边改边写的施工记录为主线:看一个已经能跑的 RAG 客服系统,怎样一步步补齐证据链。
NexaRAG 是一个什么项目
NexaRAG 的业务场景是 智能客服。用户可以问产品参数、故障排查、购买建议、竞品对比,也可以带图片提问。系统背后有 FastAPI 后端、React 前端、DashScope 模型、Chroma 向量库、BM25 检索、RRF 融合召回、Agent 工具调用、会话记忆、答案校验、诊断面板和评测脚本。
它已经超过“接一个向量库再问大模型”的最小 demo。它有一条完整的运行链路:
用户请求
-> API 入口
-> 聊天编排服务
-> 会话和记忆上下文
-> Agent 节点链路
-> 工具调用检索知识库
-> 候选证据整理
-> 生成答案
-> 校验答案
-> 返回 trace、引用、校验和诊断信息
也正因为它已经能跑,才更适合拿来复盘。一个已经包含 API、Agent、RAG、Memory、评测和前端工作台的项目,会遇到那些让人真正头疼的细节。
这组文章的重点放在 RAG 能力如何一步步补起来。代码路径会以当前 NexaRAG 目录为准,旧文件名只在必要时作为历史背景提一下。
从施工记录写起
RAG 的学习很容易从结论开始:应该有 metadata,应该有 hybrid search,应该有 rerank,应该有 citation,应该有 evaluation。
项目通常会先出现一个能跑的版本,然后在一次次问题里补能力。
最开始,系统能回答问题,证据来源需要被看见,于是需要 Retrieval Trace。
文档能上传,稳定身份需要补齐,于是需要 metadata 和 document registry。
文本能切块,标题、段落和步骤边界需要保留,于是需要结构化 chunking。
向量检索能召回,关键词、型号、版本需要更稳,于是需要 BM25、RRF 和 filter。
候选片段有了,还要整理成 prompt 里的证据,于是需要 rerank 和 ContextBuilder。
答案能生成,还要约束引用、拒答和冲突处理,于是需要 citation、refusal 和 verifier。
手工试几个问题覆盖有限,于是需要 Golden Set 和评测链路。
知识库还要删除、回滚、重建索引,于是需要动态知识库治理。
这就是施工记录的价值。它记录每一步出现的原因、解决的内容,以及留给下一步的问题。
这组文章的路线
整个系列会按一条普通 RAG 证据链往下写:
Retrieval Trace
-> 文档入库与 metadata
-> 结构化 chunking
-> 混合检索与 Query Rewrite
-> Rerank 与上下文工程
-> 引用、拒答和答案校验
-> Golden Set 与评测体系
-> 动态知识库更新
-> 高级 RAG 原型
这个顺序里,trace 放在最前面。原因很简单:系统具备可观察性以后,后面的优化才方便判断效果。
假设答案错了,有 trace 时可以沿着链路排查:知识是否入库,query 是否改写偏了,BM25 和向量检索是否召回,rerank 是否把证据排低,final context 是否包含正确证据,生成时是否引用。
有了 trace,后面改 metadata、chunking、检索、rerank、引用和评测时,也都能基于证据链验证结果。
这组文章会怎样讲代码
正文会围绕关键模块讲清楚职责,不逐行贴完整源码。比如请求和 trace 会看:
api/chat_router/router.pycore/chat/service.pycore/chat/diagnostics.pyagent/groups/customer_service_group.pyagent/nodes/tool_reasoning_node.pyrag/_trace/records.pytools/_retrieval/builder.pyfrontend/src/features/diagnostics/*
文档入库会看:
api/knowledge_router/upload.pyrag/_ingestion/service.pyrag/_ingestion/pipeline.pyrag/_ingestion/metadata_builder.pyrag/_loaders/registry.pyrag/_schemas/models.pyrag/_metadata/builder.pyrag/_registry/*
后面讲 chunking、检索、rerank、引用、评测和动态更新,也会继续按当前代码位置展开。
每篇文章都会尽量围绕三个角度展开:
- 这个环节在 RAG 证据链里的职责。
- NexaRAG 里承担这个职责的代码模块。
- 这一步已经解决的内容,以及留给下一步的问题。
高级 RAG 放到后面
现在很多 RAG 讨论喜欢直接跳到 GraphRAG、Self-RAG、CRAG、Agentic RAG。它们当然重要,但在 NexaRAG 这组文章里会放到后面。
原因很直接:普通证据链稳定以后,高级范式才更容易落地。检索 trace 完整、metadata 稳定、final context 可引用、Golden Set 建立起来之后,再引入图、反思和多步 Agent,排查和评测都会更清楚。
所以这组文章的顺序会比较“朴素”:先让普通 RAG 证据链变得清楚,再讨论高级 RAG 能补哪些短板。
小结
这组 NexaRAG 复盘文章的核心,是把 RAG 里那些学过的概念放回真实项目。
在项目里,RAG 是一条证据链路:知识怎么进入系统,证据怎么被切分,问题怎么被改写,候选怎么被召回,片段怎么被重排,上下文怎么被组织,答案怎么被约束,结果怎么被评测。
下一篇就从最靠近请求入口的地方开始:一次用户问题进入 NexaRAG 后,Retrieval Trace 怎样把证据链照亮。