☰
RAG进阶实战:从检索增强到智能体工程化落地
2026/10/5 14:24:04 网站建设 项目流程

1. 为什么现在还要聊RAG进阶

RAG这个词,从2023年火到现在,已经不算新鲜了。但凡做过LLM应用的人,几乎都搭过一个"文档切块→向量化→检索→拼prompt"的demo。问题也恰恰出在这里:demo能跑通,不代表系统能用。我见过太多团队,第一版RAG上线时效果惊艳,三个月后用户量一上来,检索质量断崖式下跌,回答开始胡编,运维成本飙升,最后整个项目被砍掉。

《RAG进阶实战》这个专栏策划案,核心要解决的就是这个断层——从"能跑"到"能扛"之间的那段路。它面向的不是刚听说RAG的新手,而是已经踩过基础坑、准备把系统推向生产环境的开发者。专栏会围绕RAG、LLM、Agent、pgvector、Milvus这几个关键词展开,把检索增强这件事从单点技巧升级成一套工程方法论。

我个人的判断是:2024年之后,RAG的竞争点已经不在"会不会用向量库",而在"能不能把检索、记忆、推理、工具调用这几件事编排成一个稳定的系统"。这也是为什么Agent会频繁出现在RAG的讨论里——单纯的检索已经不够了,用户要的是能查、能算、能记住、能行动的智能体。这个专栏的策划思路,就是沿着这条主线往下拆。

2. 专栏整体设计与内容主线拆解

2.1 从"检索增强"到"检索增强智能体"的定位升级

传统RAG的定义很窄:给LLM外挂一个知识库,让它回答时有据可依。但实际项目里你会发现,用户的问题往往不是"帮我查一段资料"这么简单。他可能先问"我上个月那份合同里付款条款怎么写的",接着问"那按这个条款我这次该付多少",再问"帮我生成一封催款邮件"。这三个问题分别对应检索、计算、生成,单一RAG链路根本接不住。

所以专栏的定位从一开始就定在"进阶"两个字上:不是教你怎么调LangChain的RetrievalQA,而是教你怎么把RAG当成一个可编排的组件,嵌进更大的Agent架构里。检索负责"找事实",LLM负责"做推理",Agent负责"决定下一步做什么",三者各司其职。这个定位决定了专栏的内容不会停留在API调用层面,而会深入到路由策略、记忆管理、工具编排这些真正影响效果的地方。

2.2 技术选型背后的取舍逻辑

专栏里会重点讲pgvector和Milvus这两个向量库,不是随便选的。pgvector适合什么场景?你的业务数据本来就在Postgres里,量级在百万级以下,团队不想再维护一套独立服务,那pgvector就是最优解——一个数据库搞定关系数据和向量数据,事务一致性还天然有保障。Milvus适合什么场景?向量规模上千万甚至上亿,需要分布式、需要多种索引类型、需要高并发检索,那Milvus的独立架构就值得那份额外的运维成本。

我在实际项目里两种都用过。小团队做内部知识库,pgvector从零到上线两天搞定;做面向C端的产品,日活几十万,Milvus standalone模式先扛着,量再涨就上集群。专栏会把这两种路径的决策依据、迁移成本、性能拐点都讲清楚,而不是简单说"Milvus更强"。

2.3 内容模块的编排思路

整个专栏我规划成四条主线并行推进。第一条是检索质量线,从切块策略、embedding选型、混合检索到重排序,解决"找不准"的问题。第二条是架构线,讲pgvector和Milvus的部署、索引、调优,解决"扛不住"的问题。第三条是Agent线,讲工具调用、记忆管理、多步推理,解决"不够用"的问题。第四条是评测线,讲怎么用LLM as judge、怎么建评测集、怎么定位badcase,解决"说不清哪里坏了"的问题。

这四条线不是割裂的,每一章都会交叉。比如讲重排序的时候,会顺带讲它在Agent多轮检索里怎么用;讲Milvus调优的时候,会讲它怎么影响Agent的响应延迟。这种编排方式更贴近真实项目的复杂度,读者学完能直接迁移到自己的系统里。

3. 核心细节解析与实操要点

3.1 切块策略:RAG效果的第一道分水岭

很多人做RAG效果差,根子就在切块上。固定长度512字符一切,看起来整齐,实际上把一句话从中间劈开,检索出来的片段语义残缺,LLM拿到手里也拼不出完整意思。我的经验是,切块要跟着文档结构走,而不是跟着字符数走。

具体怎么做?Markdown文档按标题层级切,代码文档按函数边界切,合同按条款切,论文按章节切。切完之后再做一层"语义合并":如果相邻两个块合起来不超过阈值,就合并;如果某个块明显是标题或页眉,就丢掉。这套逻辑用LangChain的RecursiveCharacterTextSplitter配合自定义分隔符就能实现,不需要多复杂的代码。

注意:切块大小没有万能值。中文技术文档我一般用300到500字,英文用500到800 token,法律合同这种需要精确引用的场景,块要更小,200字左右,保证检索出来的片段能直接作为证据。

还有一个容易被忽略的点:元数据。每个块除了文本内容,还要带上来源文件、章节路径、页码、更新时间。这些元数据在后续做过滤检索、引用溯源、增量更新时都是刚需。我见过太多项目上线后想加"只搜最近三个月文档"的功能,结果发现元数据根本没存,只能重跑全量。

3.2 Embedding选型:别只看榜单排名

Open LLM Leaderboard这类公开榜单可以参考,但不能照搬。榜单测的是通用语义相似度,你的业务场景可能是法律、医疗、工业设备手册,通用模型未必最优。我的做法是:先选两三个候选模型,用自己业务里的真实query-doc对做小规模评测,看召回率,再决定用哪个。

中文场景下,BGE系列和M3E系列是稳妥选择,维度768或1024都够用。如果预算充足,可以用API型的embedding服务,省去部署和GPU成本,但要注意数据出境和调用延迟问题。本地部署的话,一张消费级显卡就能跑BGE-large,吞吐量对中小规模知识库完全够。

提示:embedding模型换了,整个向量库必须重建。所以选型阶段多花两天做评测,比上线后返工划算得多。另外,query和doc最好用同一个模型编码,混用不同模型会导致向量空间不对齐,检索质量直接崩。

3.3 混合检索与重排序:把召回率拉满

纯向量检索有个天然短板:对精确匹配不敏感。用户搜"GB/T 19001",向量检索可能返回一堆语义相近但标准号不对的文档。这时候就需要混合检索——向量检索负责语义召回,BM25负责关键词召回,两路结果融合后再重排序。

融合策略我常用RRF(Reciprocal Rank Fusion),简单有效,不需要调权重。重排序用Cross-Encoder模型,比如BGE-reranker,把粗排的top50精排到top5,效果提升非常明显。代价是延迟增加,所以重排序一般只对top50做,不要对全量做。

检索方式优势短板适用场景
纯向量语义理解强精确匹配弱开放问答
BM25关键词精确无同义扩展编号、术语检索
混合+重排兼顾两者延迟略高生产环境推荐

3.4 Agent记忆管理:token的三个点怎么理解

热词里有个说法很形象:LLM的token三个点——key是"我是谁",query是"我在找什么",value是"我能提供什么"。这其实是在讲记忆的检索逻辑。Agent在多轮对话里,不能把所有历史都塞进context,那样token爆炸且噪声大。正确做法是把历史对话也做成可检索的记忆库,每轮根据当前query去检索相关记忆。

短期记忆放context里,保留最近几轮;长期记忆存向量库,按需检索。key用对话主题或实体,value用对话内容摘要,query用当前用户输入。这样Agent既能记住"用户上周提过预算有限",又不会把整段历史都拖着走。这个设计在客服、助理类Agent里特别关键,直接决定用户体验。

4. 实操过程与核心环节实现

4.1 用pgvector搭一个最小可用RAG

先讲pgvector这条路,适合快速验证。环境准备很简单,Postgres 14以上,装个vector扩展就行。

# 安装pgvector扩展 CREATE EXTENSION vector; # 建表,embedding维度按模型定,BGE-large是1024 CREATE TABLE documents ( id SERIAL PRIMARY KEY, content TEXT, metadata JSONB, embedding vector(1024) ); # 建HNSW索引,比IVFFlat更适合动态数据 CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);

检索的时候用余弦距离,pgvector的<=>操作符就是余弦距离。查询语句大概长这样:

SELECT content, metadata, 1 - (embedding <=> $1) AS similarity FROM documents WHERE metadata->>'source' = 'contract' ORDER BY embedding <=> $1 LIMIT 5;

这套方案我从零搭到能跑,半天时间。优点是事务一致,插入文档和插入向量在同一个事务里,不会出现数据不一致。缺点是向量规模超过500万后,查询延迟开始明显上升,这时候就该考虑Milvus了。

4.2 Milvus standalone模式部署与踩坑

Milvus standalone模式适合单机部署,用Docker Compose拉起最省事。在Mac上装的话,注意Docker Desktop的内存要调到至少8G,否则Milvus的etcd和minio容易OOM。

# 下载官方compose文件 wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml -O docker-compose.yml # 启动 docker-compose up -d # 验证 docker-compose ps

连接的时候有个坑:milvus_uri如果写成./data/milvus.db这种本地路径,那是Milvus Lite的用法,standalone模式必须用http://localhost:19530。我见过有人本地加载提示连接失败,排查半天发现是URI写错了。

建collection的时候,索引类型选HNSW,metric_type选COSINE。Milvus的余弦值计算和pgvector略有差异,Milvus返回的是相似度分数,越大越相似,pgvector返回的是距离,越小越相似,写代码时别搞反了。

from pymilvus import Collection, CollectionSchema, FieldSchema, DataType fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1024), FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=65535), ] schema = CollectionSchema(fields) collection = Collection(name="rag_docs", schema=schema) collection.create_index("embedding", { "index_type": "HNSW", "metric_type": "COSINE", "params": {"M": 16, "efConstruction": 200} })

M和efConstruction这两个参数,M控制图的连接度,越大召回越高但内存占用越大;efConstruction控制建索引时的搜索范围,越大索引质量越好但建索引越慢。生产环境我一般M=16,efConstruction=200,平衡效果和成本。

4.3 检索链路串起来:从query到answer

完整链路是这样的:用户query进来,先做query改写(把口语化问题转成检索友好的表达),然后并行走向量检索和BM25检索,结果用RRF融合,取top50送重排序,重排序取top5拼进prompt,最后LLM生成答案。

query改写这一步很多人省了,但效果差异很大。用户问"那个啥来着,就是上次说的付款的事",直接检索基本废掉。用一个小模型做改写,输出"付款条款 付款时间 付款方式",检索质量立刻上来。改写模型可以用本地小模型,也可以用API,成本很低。

prompt拼装也有讲究。不要简单把5个片段堆进去,要带上来源标注,让LLM知道每段话出自哪里。生成答案时要求LLM引用来源编号,这样用户能溯源,也方便后续做评测。

4.4 Agent工具调用的最小实现

Agent的核心是"决定调用哪个工具"。最简单的实现是ReAct模式:LLM输出思考过程,决定调用检索工具还是计算工具还是直接回答。检索工具就是上面那套RAG链路,计算工具可以是Python执行器,回答工具就是直接生成。

tools = [ {"name": "search_knowledge", "description": "检索知识库", "func": rag_search}, {"name": "calculate", "description": "执行数学计算", "func": python_calc}, ]

LLM根据用户问题选择工具,拿到工具返回结果后再决定下一步。这个循环跑几轮,直到LLM认为可以给出最终答案。关键点是工具描述要写清楚,LLM才能选对。描述模糊是工具调用失败的头号原因。

注意:Agent循环一定要设最大轮数,否则LLM可能陷入死循环,反复调用同一个工具。我一般设5轮上限,超过就强制返回当前最优答案。

5. 常见问题与排查技巧实录

5.1 检索质量突然下降怎么排查

这是最高频的问题。排查顺序我总结成一张表:

现象可能原因排查方法
召回内容不相关embedding模型换了检查模型版本是否一致
精确匹配失效索引未重建确认新数据是否已建索引
结果重复切块重叠过大检查chunk_overlap参数
延迟飙升索引参数不当检查HNSW的ef参数
部分文档搜不到元数据过滤错误检查filter条件

我遇到过一次诡异的情况:检索结果突然全是旧文档。排查半天发现是增量更新时,新文档的embedding用了新模型,旧文档还是老模型,向量空间不一致。解决办法就是全量重建,没有捷径。

5.2 Milvus连接与性能问题速查

Milvus standalone最常见的三个问题:连接超时、内存不足、索引加载慢。连接超时一般是端口没通,检查19530和9091端口。内存不足调Docker内存上限。索引加载慢是正常的,HNSW索引加载到内存需要时间,collection.load()之后要等一会儿才能查。

还有个坑:Milvus的collection删除后,数据不会立即释放,要等GC。频繁建删collection会导致内存泄漏。生产环境建议复用collection,用分区或字段过滤来隔离数据。

5.3 Agent调用失败的典型场景

Agent调用工具失败,八成是这几个原因:工具描述不清、参数格式不对、返回值太大。参数格式问题最常见,LLM生成的JSON有时候多一个逗号就解析失败。解决办法是用结构化输出约束,或者加一层容错解析。

返回值太大也是个坑。检索工具返回5个长文档,塞进context直接爆token。要在工具内部做截断,只返回最相关的片段,控制在2000 token以内。

5.4 评测怎么做才靠谱

没有评测的RAG系统就是盲人摸象。我的做法是建一个200条左右的评测集,覆盖常见问题类型,每条标注标准答案和应召回的文档。每次改动后跑一遍,看召回率和答案准确率的变化。

LLM as judge可以辅助评测,但不能全信。我一般用LLM做初筛,人工复核争议case。judge的prompt要写清楚评分标准,否则LLM打分很随意。评测集要持续更新,把线上badcase加进去,这样评测才越来越贴近真实场景。

6. 从专栏到落地:我的一些实操体会

做RAG进阶这件事,最大的体会是:没有银弹,只有权衡。pgvector和Milvus没有绝对优劣,切块大小没有标准答案,Agent轮数没有固定值,一切都要看你的数据规模、延迟要求、团队能力。专栏能做的,是把这些权衡的维度和依据讲清楚,让你在做决策时有据可依,而不是拍脑袋。

另一个体会是,评测要趁早。很多人把评测放到最后做,结果发现系统已经烂到没法救。正确的顺序是:先建评测集,再搭系统,每改一处就跑评测。这样你能清楚知道每一步改动是正向还是负向,不会越改越乱。

最后分享一个小技巧:把线上用户的query都存下来,定期抽样分析。你会发现很多你没想到的问法,这些才是真正驱动系统迭代的燃料。我负责的一个项目,就是靠分析query日志,发现用户大量在问表格数据,于是专门加了表格检索链路,效果提升立竿见影。RAG进阶的路,说到底就是被真实需求推着往前走。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询