06 RAG 调优就三个参数,调好了效果翻倍 摘要本文深入剖析了影响 RAG 系统效果的三个核心参数——chunk_size、top_k 和 embedding 模型通过生动的“切西瓜”比喻解释了它们的作用原理与调优策略。文章提供了针对不同文档类型的 chunk_size 经验值、top_k 的合理范围与相似度阈值过滤方法以及中文场景下 embedding 模型的选型建议。此外还介绍了混合检索技术以弥补纯向量检索的不足并给出了通过人工打分与自动化评估验证调优效果的具体方法。最后从面试官视角总结了 RAG 调优的标准回答框架。前五篇把 RAG 从原理到代码到部署全走了一遍。很多人照着做完了然后问我一个问题我跑起来了但效果不太好。答案不对或者答案太笼统怎么办好问题。这说明你不是复制粘贴党你是真的想用。RAG 效果不好80% 的问题出在三个参数上chunksize、topk、embedding 模型选型。这三个东西配好了效果直接翻倍。配不好神仙也救不了。打个比方你就懂了你吃西瓜。chunk_size 决定你把西瓜切多大。切太大一口塞不下满嘴都是汁上下文太长关键信息淹没。切太小全是皮没汁信息碎片化语义不完整。chunk 切西瓜不能太大也不能太小。top_k 决定你端几块给客人。你切了一桌西瓜端两三块过去——客人刚好解渴吃完还想吃。你端十块过去——客人吃不完桌上全是瓜皮噪音。你端一块过去——不够甜的那块刚好被端走了客人没尝到味儿。embedding 模型是你用来挑西瓜的那个好西瓜长什么样的标准。你用买菜大妈的标准挑随便看了一眼和用专业果农的标准挑看纹路、听声音、掂重量挑出来的西瓜品质差很多。这三个参数就是 RAG 的命门。参数一chunk_size——切西瓜切成多大chunk_size 是文档切块的大小。单位是 token不是字不是字符。为什么单位是 token因为大模型和 embedding 模型处理文本的粒度都是 token。一个 token 大约 0.7-1.2 个中文字。英文大约 1 token 4 个字符。chunk_size 设小了会怎样文档被切成几百个碎片。每个碎片只有一两句话语义不完整。你搜退货政策切到的块可能是本店支持七天无理由退换但下面那句生鲜食品除外被切到下一个块里了。大模型拿到前半句以为所有商品都能退。回答错了。这叫上下文断裂。块太小关键信息的上下文关系断了。chunk_size 设大了会怎样文档块巨大一块包含好几页内容。你搜退款到账时间返回的是一整章售后服务政策里面混着换货政策、维修政策、投诉流程……有用的信息被噪音淹没。大模型在这个块里找不到退款到账时间的具体条款因为太长了它自己也会忽略。这叫信号淹没。块太大准确信息被无关内容稀释了。经验值是多少中文场景512 - 1024 tokens 之间。具体多少看你文档类型文档类型建议 chunk_size原因技术文档API 文档、使用手册512-768每条定义独立短块更精准法律合同、论文768-1024需要保存完整段落和条款的上下文产品说明、FAQ300-512每条问答独立不需要长上下文对话记录512保留一轮对话的完整上下文还有一个关键参数overlap重叠。chunk 之间要有重叠。这个前面文章提到过这里再强调一下[块1] 本店支持七天无理由退换货。 [块2] 退换货时请保留原包装。 [overlap] [块2的实际开头] 货时请保留原包装及所有配件。如果没有 overlap生鲜食品除外刚好落在块1结尾和块2开头之间两个块都不完整。重叠的规模一般是 chunk_size 的 10%-20%。1024 的 chunk 设 150-200 的 overlap。Spring AI 里这样配TokenTextSplitter splitter new TokenTextSplitter(800, 200); // chunk_size ↑ overlap ↑参数二top_k——端几块西瓜给客人top_k 是向量检索时返回的最相关文档块数量。你搜一个问题向量数据库给你找出最像的 k 个块。你把它们全塞进 Prompt 的上下文里让大模型参考。top_k 设小了会怎样设 1。只返回最相似的那一块。如果这块刚好包含了正确答案效果好。如果没包含模型回答了一半就卡住了。更危险的情况这块包含的信息不够模型就开始脑补。它不知道正确答案但它又不想说不知道就自己编了一段。尤其是模型本身有取悦用户的倾向——只要你没明确说不知道就说不知道它会硬编。top_k 设大了会怎样设 20。返回一堆块其中真正相关的可能就 3 块其他 17 块是噪音。大模型处理上下文的能力虽然强但也不是无限。你把大量噪音喂给它它会在无关信息里找规律然后回答出一些奇怪的东西。我见过一个案例用户问今天午餐吃什么因为 top_k 设得太大系统搜到了公司福利页面的年度体检套餐模型一本正经地回答说建议你吃体检套餐。经验值是多少大部分场景 3-5 就够了。如果文档质量好每条都很精炼3 就够。如果文档碎片化严重一条信息散在多处可以试试 7-10。如果你的 embedding 模型质量一般准确率不高建议多返回几条靠大模型自己判断。不是设完就完了。你得用阈值过滤。光设 top_k 不够你还得设一个相似度阈值。余弦距离小于多少才返回ListDocument docs vectorStore.similaritySearch( SearchRequest.query(question) .withTopK(10 .withSimilarityThreshold(0.65) );withSimilarityThreshold(0.65)—— 余弦距离 ≤ 0.65 才返回。距离越小越相似。为什么要设这个因为你搜一个冷门问题可能库里只有 2 块沾边。但你不设阈值topK10 的话另外 8 块是硬拉进来的无关内容。不如只返回 2 块告诉用户相关资料可能不够。生产环境里你可以把这两条数据打日志返回了几条、平均相似度多少。用来监控 RAG 的召回健康状态。参数三embedding 模型——你挑西瓜的标准是什么这个坑最大也最容易被忽略。很多人做 RAG 的时候embedding 模型直接用 OpenAI 默认的text-embedding-3-small。够用吗够。是最优的吗不一定。embedding 模型决定了两件事1.你把文档转成的向量能不能准确表达语义2.你搜的时候向量比对能不能分出好坏如果 embedding 模型质量不好一批文档块转成的向量挤在一起。你搜任何一个问题所有块的距离都差不多。搜不出谁更相关。这叫向量坍塌。同个模型在不同语言上的表现也有差异。text-embedding-3-small是中英文混合训练的英文表现很好中文差一些。国内也有一些选择模型特点适合场景text-embedding-3-small便宜速度快通用成本敏感text-embedding-3-large维度高精度好高精度场景BAAI/bge-large-zh-v1.5中文优化开源纯中文知识库通义千问 embedding阿里云中文好用阿里云栈的项目m3e-large中文效果扎实开源自部署场景怎么选如果你的文档主要是中文内部知识库基本都是用bge-large-zh-v1.5或者m3e-large效果比 OpenAI 的默认模型好 5-10%。如果你不想自己部署 embedding 模型用 OpenAI 的选text-embedding-3-large维度从 1536 升到 3072精度有提升。Spring AI 里切换 embedding 模型很简单spring: ai: openai: embedding: options: model: text-embedding-3-large改成 yml 里的 model 名就行。代码不用改一行。进阶混合检索——两个标准一起用纯向量检索有个弱点它不能精确匹配关键词。你问订单号 20240615 的状态向量检索会把它转成一个向量在库里找语义最像的块。但订单号 20240615是一个精确值在向量空间里很可能跟别的订单号混在一起。解决方案混合检索Hybrid Search。关键词检索BM25 向量检索两条路径走最后取交集或加权合并。拿 pgvector 举例。PostgreSQL 本身就支持全文检索。你可以写这样的 SQLSELECT id, content, -- 向量相似度 embedding [0.12, 0.34, ...] AS vec_score, -- 关键词匹配BM25 ts_rank(to_tsvector(chinese, content), plainto_tsquery(chinese, 订单号 20240615)) AS text_score FROM docs WHERE embedding [0.12, 0.34, ...] 0.7 AND to_tsvector(chinese, content) plainto_tsquery(chinese, 订单号 20240615) ORDER BY (vec_score * 0.5 text_score * 0.5) ASC LIMIT 5;S 用向量分数和关键词分数加权后排序。各占 50%。Spring AI 本身没有内置的 Hybrid Search 支持但你可以自己写一个public ListDocument hybridSearch(String question, int topK) { // 1. 向量检索 ListDocument vecDocs vectorStore.similaritySearch( SearchRequest.query(question).withTopK(topK) ); // 2. 关键词检索假设用了 Elasticsearch ListDocument keywordDocs esClient.search(question, content, topK); // 3. RRFReciprocal Rank Fusion融合 // 把两个排序结果合并重新打分 return ReciprocalRankFusion.merge(vecDocs, keywordDocs, topK); }混合检索的效果通常比纯向量检索好 10-15%。如果你的知识库里有很多精确匹配的需求订单号、用户 ID、产品编码强烈建议上混合检索。怎么知道自己调对了很多人调完之后不知道效果好不好。没有评估标准瞎调。最简单的评估办法人工打分。从你的真实业务场景里抽 50-100 个问题。每个问题你期望的正确答案是什么记录下来。然后你跑一遍 RAG看看回答的对不对问题期望答案实际答案是否准确1-5分是否引用正确退款几天到账3-5 个工作日3-7 个工作日3否50 个问题跑完算个平均分。低于 4 分你需要调参数。对比测试把同样的 50 个问题用不同的参数组合跑一遍看哪个组合平均分最高。组合chunk_sizetop_kembedding平均分A5123bge-large-zh4.2B10245text-embedding-3-small3.5C5125text-embedding-3-large4.5一目了然。选 C 上线。自动化评估如果你嫌人工打分太慢可以用 LLM 来评估 LLM。让 GPT-4 当裁判你是一个 RAG 效果评估专家。 请判断以下回答是否准确回答了问题并且只使用了提供的资料。 回答完全准确按资料回答5分 回答基本正确但有小错误3-4分 回答有明显编造成分1-2分 问题{question} 资料{context} 回答{answer} 评分大模型打分大模型听起来有点玄学。但实验证明这种评估方式和人工评估的一致性可以达到 80% 以上。比没有强一百倍。 面试官视角的标准回答如果面试官问你的 RAG 效果不好怎么排查和调优我主要从三个维度调。chunk_size、top_k、embedding 模型。chunk_size 我设 512-1024 token加 10-20% 的重叠。技术文档用偏小块512法律条款用偏大块1024。核心原则是保证每个块的语义完整性。top_k 设 3-5。加 similarityThreshold 过滤小于 0.65 的不返回。宁可少返回几条也不让无关噪音干扰大模型。embedding 模型优先选中文优化的比如 bge-large-zh-v1.5。在纯中文场景下比 OpenAI 的 text-embedding-3-small 效果好约 10%。如果纯向量检索不足以覆盖精确匹配需求我会加上 BM25 关键词检索做混合检索。用 RRF 算法把两路结果融合重排序。调优的评估方法是用一个 50 题的测试集人工打 1-5 分跑不同的参数组合对比。自动化评估可以用 LLM 当裁判效率和人工评估一致性都在 80% 以上。AIGC 面试系列到这里就全写完了。从第一篇的为什么要聊 AIGC到第二篇的手把手搭 RAG demo第三篇的 Prompt 设计第四篇的向量数据库选型第五篇的大模型 API 高可用到这一篇的 RAG 调优——一共六篇把一个 Java 后端程序员在大模型时代需要的技能包讲全了。不吹不黑你把这六篇吃透了面试官问 AIGC 相关的问题你至少能答到 P6 水平。不是背答案是真的能聊。毕竟不是我说的。是面试官心里想的。私信回复「666」一次性领走面试宝典Java 高频考点速查表、HashMap/ConcurrentHashMap 源码笔记、JVM 调优案例、Spring Boot 面试 50 问AI 编程工具箱Cursor/Copilot/Codex 六工具对比表、10 个 Prompt 模板、Debug 万能公式、Cursor 速查手册、AI 图片生成入门、30 效率工具包一份资料包两个专栏都能用。「唠点键盘之外的」只讲干货。

本月热点