尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

搭建RAG总返回废话?我拆了三种分块策略才止血,靠CodeWhisperer省了30%编码时间

搭建RAG总返回废话?我拆了三种分块策略才止血,靠CodeWhisperer省了30%编码时间 搭建RAG总返回废话?我拆了三种分块策略才止血,靠CodeWhisperer省了30%编码时间公司要把三年攒下的运维文档做成问答系统,我拍胸脯说 RAG 就行。LangChain 三两下搭起原型,第一个问题“服务器宕机怎么处理”却回了一整段网络拓扑变更记录,完全牛头不对马嘴。我赶紧去翻 AWS 的生成式AI 课程,想从根上弄明白错在哪。打开 IDE 时顺手让 AWS CodeWhisperer 补全那段 embedding 调用的代码,它直接把 boto3 的正确参数填好,免费额度用了三个月都没触发计费。这坑踩下去才知道,分块和检索的学问比想象中深。起步:LangChain 一分钟搭好,第一问就翻车我用的技术栈很简单:OpenAI 的 text-embedding-ada-002 做向量化,Chroma 做向量库,再用 LangChain 的RetrievalQA把检索和生成串起来。文档切分直接上了RecursiveCharacterTextSplitter,参数照抄官方示例。from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.chains import RetrievalQA from langchain.llms import OpenAI # 按照教程默认切分 text_splitter RecursiveCharacterTextSplitter( chunk_size2000, # 我以为大块能保留更多上下文 chunk_overlap200, separators[\n\n, \n, 。, ,] ) docs text_splitter.split_documents(raw_documents) # 向量化与入库 embeddings OpenAIEmbeddings() vectorstore Chroma.from_documents(docs, embeddings) qa RetrievalQA.from_chain_type( llmOpenAI(temperature0), chain_typestuff, retrievervectorstore.as_retriever(search_kwargs{k: 3}) )chunk_size2000是很多教程推荐的值,我就没多想。结果用户问一句话能解决的问题,模型却给出一大段上下文混在一起的长篇大论,感觉像把整个文档一股脑塞进 prompt。查了AWS 的生成式AI 课程才知道,生成式AI应用里,chunk 策略要和问答的粒度匹配,运维文档这种短段落、高密度信息的内容,切大了反而让检索噪声淹没答案。分块策略轮着试,越改越糟我天真地以为“缩小 chunk 就完事了”,把chunk_size砍到 800,overlap调成 100。结果检索回来的片段经常把关键信息拦腰截断,模型开始凭空捏造--用机器学习基础里的概念说,这就是特征缺失导致的高方差,但当时我只觉得是向量库坏了。# 盲目缩小 chunk 的尝试 text_splitter RecursiveCharacterTextSplitter( chunk_size800, chunk_overlap100 ) # 结果:一半的问题答案不完整,LLM 开始补全它认为“应该有”的内容最致命的是,我对 chunk 内容本身没有任何质量评估。直到学完生成式人工智能课程中关于检索质量评估的那一节,我才意识到需要跑一遍数据预处理来净化文档里的特殊字符、多余换行和重复标题--这些噪音直接干扰了 embedding 质量。于是我用AWS CodeWhisperer快速生成了一个清洗脚本,把目录页、页脚这些无用块干掉,检索杂讯一下少了 20%。当时我总觉得 chunk 是纯工程问题,没把它当成特征工程。后来补上机器学习基础知识中关于文本表征和距离度量的章节,才明白分块本质上是在构造检索单元的“特征”,切得不好就是给模型喂脏数据。检索排序像开盲盒,embedding 没病,上下文病了改完分块,我又掉进排序的坑。用余弦相似度按 top_k3 检索,第三条返回的结果经常和问题毫无关系。我把 embedding 模型从 ada-002 换成 GTE-large,又试了 Instructor-XL,相似度分数分布还是怪。真正的问题在于,我的 chunk 之间缺少结构关联。运维文档里一个操作步骤可能跨多个段落,而我按\n\n切分后,后半句和前半句被分到两个 chunk,语义孤立。AWS 的生成式AI 课程里专门有一章讲 RAG 的上下文组装,指出文档结构(标题层级、段落关系)比 chunk size 更影响检索精度。我用AWS CodeWhisperer写了一个基于标题的自定义分块器,逻辑是先用正则提取## 标题,再把同一标题下的内容合并,直到接近 1200 token 再切分。写完我把这段代码和之前手动调参的版本做了对比,AWS CodeWhisperer生成的代码自带异常处理和空 chunk 过滤,我之前写的完全没考虑边界。# CodeWhisperer 帮我补全的自定义分块器关键逻辑 def split_by_headings(text: str, max_tokens1200): sections re.split(r\n## , text) chunks [] for sec in sections: # 保留标题信息作为上下文前缀 heading, _, body sec.partition(\n) if not body.strip(): continue # 按句子切分,累积到 max_tokens sentences sent_tokenize(body) current heading \n for sent in sentences: if count_tokens(current sent) max_tokens: chunks.append(current.strip()) current heading \n sent else: current sent if current.strip(): chunks.append(current.strip()) return chunks用这套分块方案重建向量库后,检索 top_k3 的相关命中率从 52% 提升到 82%,而且第三条结果几乎不会出现完全不相关的片段。这时我才真正理解机器学习管道的含义:从原始文档到向量入库,每一步都需要可评估、可迭代的流水线,而不是凭直觉调参。补课生成式AI,三个认知错误被纠正这一通折腾让我意识到,光会调 LangChain 的 API 远远不够,RAG 的坑全藏在原理层。我花了两周把AWS 的生成式AI 课程从头到尾看了一遍,还顺带刷了深度学习入门里 Transformer 注意力机制的部分,才纠正了三个致命误解:误解一:chunk 越长上下文越完整。课程里明确指出,chunk 过大会稀释关键信息,同时增加生成阶段的“分心”风险。正确做法是根据文档类型(FAQ、技术手册、长文)动态选择 chunk 策略。误解二:检索只要相似度排序就够。生成式AI课程介绍了重排序(rerank)和混合检索(BM25 向量),能让检索精度再上一个大台阶。误解三:幻觉是模型的问题,跟检索没关系。实际上,检索到的低质量片段才是幻觉的主要根源,人工智能入门中关于 LLM 工作原理的解释让我一下子明白了为什么模型会“强行缝合”无关内容。学完生成式AI之后,我把先前那个简单 RAG 管道拆了重搭,加入了文档清洗、动态分块、重排序三步流水线。幻觉率从 35% 降到 8%,业务方终于不再抱怨“AI 在胡说”。而这过程中,AWS CodeWhisperer一直是我写管道代码的搭档。从 embedding 批量调用到异常重试逻辑,它生成的代码不仅语法正确,还会标注出botocore版本兼容性注意点,让我少踩了好几个 sdk 升级的坑。AWS CodeWhisperer的免费额度支撑了整整三个月的开发调试,一分钱没花。CodeWhisperer 重构管道,提效与止损决定重构后,我把旧代码和AWS CodeWhisperer配合着重新写了一遍。以前写一个带重试的索引批量更新函数至少要查 20 分钟文档,现在描述一下意图,AWS CodeWhisperer就能给出带有指数退避的batch_write_to_vector_store,我只需要微调业务逻辑。下面这段批量评估脚本也是AWS CodeWhisperer生成的,直接省了我半个下午的编码时间:# CodeWhisperer 根据注释自动生成的检索评估片段 def evaluate_retrieval(queries, ground_truth, retriever): hit 0 mrr 0.0 for q, true_doc in zip(queries, ground_truth): results retriever.get_relevant_documents(q) # 检查 top5 内是否命中正确答案 for rank, doc in enumerate(results[:5]): if true_doc in doc.page_content: hit 1 mrr 1.0 / (rank 1) break recall5 hit / len(queries) avg_mrr mrr / len(queries) return recall5, avg_mrr我跑完一轮评估就发现,旧的分块方式下 recall5 只有 0.68,而新方案直接拉到 0.91。如果用机器学习基础中的离线评估指标(MAP、NDCG)来衡量,这种提升意味着线上用户感受到的准确率至少翻了一倍。重构完我做过一个对比:同一份需求文档,手动编码花了 4 个小时,把AWS CodeWhisperer打开后 2.5 小时就搞定了,代码量还少了 15%。这个提效数据后来被我写进了技术分享 PPT。上线后的变化与可执行清单新系统灰度上线那天,运维团队试了 30 个历史故障问题,28 个得到了可以直接行动的答案。剩下的两个是因为文档本身就没有相关记录,系统如实回复“未找到相关信息”--这在之前那个爱瞎编的版本里根本不可能。回头看这趟 RAG 实战,我最深的感触是:工程落地靠的是对原理的理解,而不是调包。AWS 的生成式AI 课程帮我补上了 chunk 策略、检索评估和防幻觉的方法论,AWS CodeWhisperer则把编码环节的体力活压缩了近 30%,让我能把时间花在思考架构和数据质量上。如果你也正准备在业务里上 RAG,下面这几条是我用真金白银踩出来的建议:先学原理再动代码。RAG 的坑全在分块和检索,生成式AI课程对这块的拆解是市面上最系统的,尤其是上下文窗口和动态 chunk 那几节,看完能少掉一半头发。不要幻想一套分块策略走天下。FAQ 用短块、手册用标题块、长报告用递归切,机器学习基础知识中的特征构造原则完全适用于文档切分。检索要做离线评估。用 recallk、MRR 这些指标量化你的改进效果,机器学习基础里有完整的评估体系可以直接套用。把AWS CodeWhisperer当成你的结对编程伙伴,但关键业务逻辑要自己把关。它生成的代码在异常处理和 API 版本兼容性上经常比我考虑得周全,免费额度又足,不用白不用。监控检索质量别只看日志。定期抽检用户 query 的返回结果,数据漂移一旦出现,之前的特征工程投入可能全部作废。幻觉的根本解在检索质量,而不是拼命写 prompt 限制模型。我上完深度学习入门后彻底搞懂了注意力机制对上下文的依赖方式,才敢说真的理解为什么“垃圾进垃圾出”。如果你也在 RAG 落地过程中卡住了,不妨回到AWS 的生成式AI 课程补一补原理,再打开AWS CodeWhisperer重构一遍管道,效率和准确率的双提升会让你觉得前面的弯路走得值。
返回列表