news 2026/10/18 5:54:38

RAG实战:用检索增强生成十分钟搭建AI快讯系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RAG实战:用检索增强生成十分钟搭建AI快讯系统

1. 项目概述:RAG到底在解决什么痛点

1.1 从AI快讯这个场景说起

先解释一下这个项目的由来。有一次朋友问我,能不能弄一个“AI自动生成快讯”的小工具——就是抓取一堆新闻素材,让大模型自动整理成条理清晰的快讯。我第一反应是很简单,直接把素材丢给大模型不就行了?但真正试过之后才发现,这条路根本走不通。

第一个问题是时效性。底层的通用大模型训练数据有严格的时间截止点,它对最近发生的热点事件几乎一无所知。第二个问题是幻觉。如果素材里没有明确给出数字、人名和来源,大模型为了让内容“看起来合理”,会自动脑补出根本不存在的细节。第三个问题是可控性。你希望快讯的结论来自你提供的准确数据源,而不是模型自己发挥。

这时候RAG(Retrieval-Augmented Generation,检索增强生成)就派上用场了。它把“知识”从大模型的静态参数里剥离出来,变成一份可以动态查询的外部资料库。大模型在回答之前,先到资料库里去检索相关内容,再把检索结果作为参考资料拼接进提示词,最后才生成答案。说白了,就是给大模型配了一个“开卷考试”的资料库,让它翻着资料答题,而不是凭空回忆。

把这个方案用在AI快讯上非常匹配。快讯的特点就是信息来源固定、时效性强、对准确性要求高,这些恰好全是RAG的舒适区。而整个实现链路并不复杂,一套完整的最小可用版本,数据准备充分的情况下,确实可以在十分钟以内跑通。

1.2 适合谁看,能解决什么问题

如果你满足下面任何一个条件,这篇内容都会对你有帮助:

  • 刚接触大模型应用开发,想找一个低门槛、可上手的落地场景;
  • 有一定编程基础,但对“RAG怎么做”“为什么这么做”缺乏系统性认知;
  • 正在做知识库问答、文本摘要、自动报告之类的项目,需要把外部数据接入大模型;
  • 想理解“搜索+大模型”这套组合在实际工程中的完整形态,而不只是看概念。

我说的“3分钟生成AI快讯”不是说三分钟能做出一个生产级系统,而是指你已经具备数据、脚本和运行环境的前提下,核心链路可以在几分钟内完成一次成功跑通。剩下的时间主要花在数据处理、效果调优和错误排查上——这些才是RAG应用真正的工程重点。

2. 核心链路拆解:先搞清楚RAG的每个环节在做什么

2.1 离线部分:知识入库是怎么完成的

RAG的整体架构可以分成两条链路:离线索引链路和在线查询链路。前者负责把一堆原始文档变成模型能检索的格式,后者负责在收到提问时完成检索和生成。

离线部分的工作可以拆成三步:

第一步是数据清洗。原始素材并不是直接能用,新闻快讯里可能混有广告、重复段落、无关的页脚信息。清洗时要先去除HTML标签和无效字段,再按新闻ID去重,并确保每条记录都有标题、正文、发布时间这几个核心字段。数据不干净,后面所有环节都会受影响,这一步值得多花时间。

第二步是文本切分(Chunking)。大模型有输入长度限制,而且向量检索以文本块为单位,不能把整篇长文一次扔进数据库。切分需要考虑语义边界,比如按段落、按句子或者按固定长度切。不同切分方式会影响检索效果,后面我会专门展开讲。

第三步是向量化和入库。把切好的文本块通过嵌入模型转成向量数组,再写入向量数据库。嵌入模型的效果决定了“语义相似”判断的好坏,向量数据库的选型则决定了检索性能和后续扩展性。

“向量化”这个概念我用一个简单的比喻解释:把“苹果”和“水果”转换成高维空间里的两个坐标点,语义越接近的点距离越近。RAG就是把所有素材都转成坐标点,用户提问时也转成一个坐标点,然后去库里找距离最近的那些点对应的原文。

2.2 在线部分:一次提问背后的完整旅程

在线链路相对更直观,一共五个步骤,每一步都有对应的工程取舍。

第一步,用户输入一条查询,也就是“快讯”的生成指令。第二步,这条查询同样经过嵌入模型转成向量。第三步,在向量数据库中进行相似度检索,取回最相关的若干条文本块。第四步,也是容易被忽视的一步:把检索结果按照相关度排序,筛选掉明显无关的内容。这步称为重排,可以在一定程度上提升准确率。第五步,把“用户指令 + 检索到的参考文本 + 要求格式”拼接成完整的提示词,交给大模型生成。

在实际项目中,我建议在在线链路上加上一个日志中间层,把每次检索命中了哪些文本块、用了多长时间、模型输出了什么内容全部记录下来。调试时如果没有日志,效果差了只能靠猜,有了日志才能快速定位是检索的问题、提示词的问题还是模型本身的问题。

2.3 和微调相比,RAG在快讯场景下的优势

很多人在做类似项目时会纠结:到底是该用RAG还是微调?我直接说结论——知识类、事实类、时效性强的场景,优先选RAG。

微调的代价很高,需要准备大批量标注数据,训练过程耗时耗力,而且每次知识更新都需要重新训练。尤其对快讯这种高频更新、来源分散的场景,微调根本无法满足时效性。RAG的优势在于知识更新即时,换一批数据重新入库就行;回答可以追溯来源,给每条快讯附上原始素材链接;开发门槛也低,不需要训练模型。当然两者的边界不是绝对的,当业务需要固定语态风格、长期积累大量历史知识时,把RAG和微调结合起来用效果也很理想。

3. 实操篇:构建一个最小可用的AI快讯RAG应用

3.1 环境准备和工具选型

实操部分用的都是比较常见的开源组件,方便在不同环境复现。

  • Python 3.10以上
  • 嵌入模型接口:选择任一主流云服务商提供的文本嵌入API,或者本地开源的嵌入模型,优先保证中文语义效果
  • 向量数据库:我用了本地文件型的向量库,代码简单,适合快速验证;数据量大了以后建议迁移到独立向量库服务
  • 大模型接口:选择支持长上下文的对话模型,用于最终生成
  • 相关Python库:读取网页用Requests和BeautifulSoup,切分文本用LangChain或者递归字符文本分割器,向量计算用开源的相似度检索库

这里有几个关键参数需要提前了解。嵌入向量维度取决于你所选的嵌入模型,常见的从几百到上千维不等;切分块大小推荐500到800个字符,重叠度控制在100到200个字符之间,不是固定的,需要根据实际数据调试。

提示:如果只是做技术验证,没必要一开始就上一套复杂的向量数据库集群。本地文件型向量库对中小数据量完全够用,等真实业务量上来再迁移架构,这样更务实。

3.2 数据准备和切分逻辑

为便于演示,我模拟了一批新闻快讯数据,每条包含标题、发布时间、正文。真实场景里可以用爬虫定时抓取,但抓取时要注意目标站点的访问频率限制和robots协议,避免给对方服务器造成压力,这是一名从业者必须考虑的基本礼仪。

切分代码逻辑如下:

from langchain_text_splitters import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=600, # 每块目标长度(字符数) chunk_overlap=120, # 相邻块重叠长度 separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] ) chunks = text_splitter.split_text(document_full_text)

为什么一定要有重叠?因为如果把一段完整的话拦腰截断,上半个下半个都失去了完整语义,检索时容易漏掉关键信息。重叠能保证切分边界附近的上下文信息不丢失。

但切分块大小也并不是越大越好。块越大,向量中包含的噪声越多,检索精度可能下降;块太小则缺乏足够的上下文语境。600字符加120重叠是一个经过较多项目验证的起点,后续可以根据检索效果调整。

3.3 离线索引部分代码实现

接下来写数据入库脚本。主要任务是读取原始数据、切分成文本块、生成向量、写入向量数据库。

from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.schema import Document # 初始化嵌入模型,不同提供商的接口可能不同,核心是返回向量 embedding_fn = OpenAIEmbeddings(model="your-embedding-model") documents = [] for item in news_data: chunks = text_splitter.split_text(item["content"]) for i, chunk in enumerate(chunks): documents.append(Document( page_content=chunk, metadata={ "title": item["title"], "publish_time": item["publish_time"], "source": item["source_url"], "chunk_index": i } )) vector_store = Chroma.from_documents( documents=documents, embedding=embedding_fn, persist_directory="./news_fast_news_db" )

这里有一个经常被新手忽略的点:metadata一定要充分记录来源信息。后面生成快讯时要标注“信息来源”,如果入库时没有把来源链接保存下来,生成端就无法引用出处,整个系统的可信度会大打折扣。我在实际项目里甚至会把切分块的序号也记下来,便于排查是哪一块文本导致的错误。

3.4 在线检索与生成部分代码实现

在线部分的核心是:先检索出相关信息,再把信息拼进提示词里让模型生成。以下是完整的可运行逻辑。

from langchain.llms import ChatOpenAI from langchain.prompts import ChatPromptTemplate query = "生成今天最新的科技行业动态快讯,重点包括人工智能和芯片领域" retrieved_chunks = vector_store.similarity_search_with_score(query, k=5) # 按分数排序并过滤低分结果,分数阈值需要根据实际返回的相似度范围调整 filtered_chunks = [doc for doc, score in retrieved_chunks if score > 0.3] context_text = "\n\n".join( f"[来源: {doc.metadata.get('source', '未知')} | 标题: {doc.metadata.get('title', '未知')}]\n{doc.page_content}" for doc in filtered_chunks ) prompt_template = ChatPromptTemplate.from_messages([ ("system", "你是一名资深快讯编辑,请基于给定的参考资料生成简洁、客观、信息准确的快讯。" "禁止编造参考资料中没有的信息。每条快讯末尾需标注信息来源。"), ("human", "参考资料:\n{context}\n\n请生成快讯:{query}") ]) llm = ChatOpenAI(model="your-chat-model", temperature=0.2) response = llm.invoke(prompt_template.format_messages( context=context_text, query=query )) print(response.content)

温度参数我设置为0.2,这是一个偏向精准和保守的值。快讯类内容要求事实准确、风格稳定,不适合模型自由发挥。如果做创意写作或头脑风暴可以调高温度,但快讯场景温度越低越安全。

另外还有一个细节值得注意:把来源信息直接嵌入到参考文本中,而不是让模型自己去推理来源。这样模型在生成快讯时,引用来源的成功率会显著提高,因为它是在上下文里“读到”了这些信息。我在多个项目里都验证过这个小技巧,非常有效。

4. 效果调优:为什么检索结果总是不理想

4.1 三个常见问题对应的三种解决思路

RAG系统上线之后,最常见的三个问题分别是检索不到、检索不准、模型不听话。下面分别说排查思路。

检索不到,往往问题出在文档切分块太小或查询改写不足。用户问“今天芯片行业有啥大事”,库里存的是“半导体产业今日动态”,语义相近但用词不同,有可能检索不到。解决思路是扩大Top-K的数量,比如从5调到10,同时检查嵌入模型对不同表述的识别能力。如果还是不行,可以对用户提问做一次意图改写,把模糊问题转成更明确的几个子查询再分别检索。

检索不准,多数是块太大或噪声过多。比如一篇新闻通稿的开头可能是“各位观众大家好”,这种套话没有实质含义,却拉低了整块文本的向量质量。解决思路是清洗阶段要提前去掉套话和模板句,同时在切分时尽量按语义完整段落来切,而不是机械按固定长度硬切。

模型不听话,总是编造内容,这本质上是提示词约束力不足。需要在系统提示词里明确写清“如果参考资料中没有对应内容,请明确回答没有找到相关信息,不要自行推断”,并且可以在模型回复后进行自动校验,把生成内容的日期、时间、人名等字段与原文比对,不一致的命中断言错误。

4.2 用“重排”进一步提升精度

向量检索本质上是在做“语义近似匹配”,它对关键词的精确匹配和段落间细微差异的感知能力有限。实际工程中,可以把重排(Rerank)作为精度提升的关键一步。

基本思路是先粗召回Top 50个候选块,再用一个专门的重排模型对每一条做精细打分,最后保留分数最高的Top 5。粗召回用向量检索保证召回率,精筛用重排模型保证精确率。这套“两阶段检索”在多个项目里都显著提升了最终回答质量。

但重排也有代价:一是重排模型需要额外调用或者额外本地部署,二是增加了耗时。对于快讯这种对响应速度有一定要求的场景,建议做个开关,默认关,只在质量不达标时手动开启。工程上讲究按需取舍,不要为炫技增加不必要的复杂度。

4.3 切分策略的进一步实验

如果你有时间,可以做一个简单的对比实验来验证切分策略的影响。分别用200字小快、600字中块、1200字大块跑同一批数据,对同一组问题做检索,对比召回Top K内容的命中率和最终生成质量。实验结果通常会显示:短文档场景下小块效果更好,长文档场景下中块配合标题元数据效果更佳。

这个实验我做过的结论是:600字左右的切块配合120字重叠在新闻快讯场景下综合表现最优。但每次换数据源都要重新验证,不能复制粘贴了事。

5. 实操总结与经验补充分享

5.1 项目踩坑实录速查表

为了便于参考,我把实际项目中最常踩的坑整理成了一张速查表。这张表每一条都来自真实调试经历,能帮你省下不少排查时间。

症状根因解决方案
快讯内容张冠李戴切分边界切断语义增加重叠长度,按段落而非固定长度切分
引用来源对不上元数据未保存来源链接入库时同步存储source字段,生成时强制携带
检索结果完全无关嵌入模型对中文语义理解不足更换中文优化过的嵌入模型,测试相似度阈值
模型拒绝回答问题提示词约束过强且上下文过少调整提示词以灵活引导,同时增加Top-K候选数
响应时间过长单次检索质量不高,反复重试引入缓存机制,对高频查询做结果复用
重复内容多多条切块内容高度相似引入去重逻辑,按文本哈希过滤近重复块

5.2 下一步可以怎么扩展

这个快讯生成项目只是一个基础形态,它本身就是一个可演进的框架。按实际需求可以扩展的方向不少:加一个定时调度器,每天定时采集素材并重新入库;加一个流式输出接口,让快讯逐字输出而不是等全部生成完毕;加一个多级分类策略,把科技、财经、体育快讯分开查询和汇总;加一个用户审查反馈循环,让编辑人员可以对生成结果打标,打标后的样本积累到一定量后可以做二次微调或者提示词优化。

我个人在实际开发中的体会是,不要把RAG当成一个复杂的“高科技黑盒”。把它拆成“文档处理、索引入库、检索召回、提示词拼接、生成后处理”这五个模块,每个模块都可以独立调试、独立替换、独立优化。当效果不理想时,先定位是哪个模块出了问题,再用模块化的方式去替换它,而不是盲目调整整个系统。

还有一个小技巧值得分享:给系统加一个“最低相似度阈值”并跟踪阈值的变化趋势。如果系统每天返回的平均相似度在缓慢下降,说明新入库的数据与旧数据之间存在偏差,或者数据质量在下降。这个指标是检查RAG系统健康度的很灵敏的风向标,比用户反馈要早得多。

最后做一点提醒,任何RAG应用都要留出人工审核环节,尤其涉及对外发布的自动生成内容时。技术上可用的系统,流程上不一定是安全的。先把“自动生成+人工复核”的闭环建立起来,再逐步提高自动化比例,这个节奏才靠谱。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 5:53:37

OpenCode 限流报错全解析:三层限流机制、日志定位与修复实战

1. 限流报错背后的真实逻辑1.1 这个报错到底在说什么Rate limit exceeded这个报错,字面意思就是"请求速率超出限制"。但很多人第一次看到它的时候会懵——我明明没发多少请求,怎么就超了?这里要先厘清一个概念:限流&…

作者头像 李华
网站建设 2026/10/18 5:52:44

openEuler源码编译VLC:依赖配置与构建实践全记录

在openEuler上编译VLC这件事,我一开始以为就是常规的configure、make、make install三连,结果实际折腾了大半天。不是说openEuler有多特殊,而是它的软件源和依赖命名跟Debian系、CentOS系都有差异,加上VLC本身就是个依赖大户&…

作者头像 李华
网站建设 2026/10/18 5:49:57

语义层选型解析:Snowflake SVA与Aloudata CAN的路线之争

这两年只要做数据平台的人,应该都被“语义层”这三个字轰炸过。我自己的感受是,语义层这个概念已经从BI圈的边缘名词,变成了数据架构里绕不开的一道必答题。真正让人纠结的其实不是要不要做语义层,而是做哪一种语义层。正好最近Sn…

作者头像 李华
网站建设 2026/10/18 5:49:20

深入理解cgroups:从CPU内存限制到容器资源治理实战

在做容器相关的工作时,我最常被问到的问题不是“镜像怎么构建”,而是“进程明明进了容器,为什么 CPU 还是被打满”“内存限制设了 2G,怎么容器里面只看到 1.5G 就 OOM”。这些问题的答案,基本都落在 Linux 内核的 cgro…

作者头像 李华
网站建设 2026/10/18 5:47:01

AI发展太快,安全护栏跟不上:2028智能危机的工程预警与应对

“2028年AI发展速度会快到什么程度”这种话题,我以前一直觉得是科幻编剧操心的事,直到自己带的一个客服项目翻车,才意识到问题不是“AI会不会太聪明”,而是“整个行业根本来不及建立跟上这种速度的安全护栏”。这话听起来有点危言…

作者头像 李华
网站建设 2026/10/18 5:46:52

初心是原点不是情绪:如何在项目管理中校准方向

1. 初心不是一种情绪,而是一个原点很多人把初心理解成“刚入行时那股热情”,这其实是个误会。热情会退,状态会起伏,环境会变,如果初心只是一种情绪状态,那它注定留不住。我这些年反复琢磨“初心论”这个概念…

作者头像 李华