
理解 RAG:从检索增强生成的原理到 ZenML 的工程化落地【免费下载链接】zenmlZenML : One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenml本文以 ZenML 官方 LLM Ops 指南中《Understanding RAG》一节为核心,系统讲解检索增强生成(Retrieval-Augmented Generation,RAG)的动机、管道组成与适用场景,并结合仓库中的源码实现,说明 ZenML 如何通过步骤化 Pipeline、工件(artifact)追踪与元数据记录,把一条 RAG 流水线变成可复现、可扩展、可协作的工程资产。读完本文,你将能判断 RAG 是否适合自己的场景,并理解如何用 ZenML 把检索 生成两个环节纳入完整的 MLOps 生命周期管理。为什么需要 RAG:LLM 的固有局限大语言模型能力强大,但并非没有边界。使用 RAG 之前,先要明确它要解决哪些问题:回答准确性问题:LLM 倾向于生成看似合理但实际错误的响应(即幻觉),尤其是在输入 prompt 意图不明确时。上下文窗口限制:模型能理解和生成的文本量是有限的。尽管少数模型可以处理超过 100 万 token 的输入,但大多数开源模型能处理的规模远小于此。成本与资源问题:很多应用场景并不需要运行超大 LLM 所带来的全部复杂度与开销。RAG 于 2020 年由 Facebook 的研究者提出,其核心思想是:用检索机制来补充 LLM 等基础模型的内置能力——先从大规模语料库中检索出相关文档,再基于这些文档生成回答。这一做法融合了检索型模型与生成型模型的优点:既保留了 LLM 的生成能力,又针对性地缓解了上述局限。RAG 管道里到底发生了什么一条 RAG 管道由两类角色构成:检索器(Retriever):在大规模语料库中找出与查询最相关的文档片段;生成器(Generator):基于检索到的文档,用 LLM 产出最终回答。这种组合对需要上下文理解与长文本生成的任务特别有用,例如问答(Question Answering)、摘要生成(Summarization)和对话生成(Dialogue Generation)。RAG 对前述局限的缓解机制可以从三个角度理解:上下文补全:检索步骤为生成器提供了有依据的信息,使回答锚定在相关内容上,降低了生成错误或不当回答的概率;缓解 token 限制:生成器只需关注一小批最相关的文档,而不必处理整个大语料库;成本效益:由于 LLM 运行成本不低,RAG 让生成器的资源集中在小范围的相关文档上,比纯粹的生成式方案更经济——这在处理大型语料库或部署到资源受限环境时尤为重要。最小可运行示例:用 85 行代码看清检索 生成为了直观理解上述两个角色,该指南的姊妹章节(85 行 RAG 实现)给出了一个刻意保持简单的最小实现:加载一个关于虚构ZenML World的文本语料,对查询做分词,检索最相关的文本块,再交给 GPT-3.5 生成回答。其核心逻辑如下(省略语料数据):import os import re import string from openai import OpenAI def preprocess_text(text): text text.lower() text text.translate(str.maketrans(, , string.punctuation)) text re.sub(r\s, , text).strip() return text def tokenize(text): return preprocess_text(text).split() def retrieve_relevant_chunks(query, corpus, top_n2): 检索器:用 Jaccard 相似度找出与查询最相关的 top_n 个文本块。 query_tokens set(tokenize(query)) similarities [] for chunk in corpus: chunk_tokens set(tokenize(chunk)) similarity len(query_tokens.intersection(chunk_tokens)) / len( query_tokens.union(chunk_tokens) ) similarities.append((chunk, similarity)) similarities.sort(keylambda x: x[1], reverseTrue) return [chunk for chunk, _ in similarities[:top_n]] def answer_question(query, corpus, top_n2): 生成器:把检索到的文本块作为上下文,让 LLM 基于上下文回答。 relevant_chunks retrieve_relevant_chunks(query, corpus, top_n) if not relevant_chunks: return I dont have enough information to answer the question. context \n.join(relevant_chunks) client OpenAI(api_keyos.environ.get(OPENAI_API_KEY)) chat_completion client.chat.completions.create( messages[ { role: system, content: ( fBased on the provided context, answer the following fquestion: {query}\n\nContext:\n{context} ), }, {role: user, content: query}, ], modelgpt-3.5-turbo, ) return chat_completion.choices[0].message.content.strip()对照这个例子,可以清晰地看到 RAG 的两个组件在代码层面的落点:retrieve_relevant_chunks就是检索器。它用 Jaccard 相似度系数衡量查询与每个文本块的相似度——即两个词集合交集的大小除以并集的大小(统计共有词数除以两方的总唯一词数)。这个实现非常朴素、低效,仅用于教学示意;answer_question就是生成器。它把检索到的 top_n 个文本块拼接为上下文,写进 system prompt,让 LLM基于给定上下文回答。当检索不到相关内容时,直接返回信息不足的兜底回答——这正是 RAG 让回答锚定在证据上的直接体现。这个示例的运行结果值得注意:对于语料外的问题(如帕ングロジア的首都是哪座城市?),模型会回答提供的上下文中没有提到,而不是凭空编造。这正是 RAG 相比纯生成式调用在准确性上的关键优势。指南中后续各节展示的就是用 ZenML 以更高性能、更可扩展的方式完成同样的事:把朴素分词换成嵌入(embedding),把 Jaccard 相似度换成向量数据库中的相似度检索。什么时候该选 RAG判断 RAG 是否合适,原文档给出了一条清晰的决策标准:当你需要生成依赖上下文理解的长文本回答,且手头有大规模相关文档语料时,RAG 是合适的选择。具体而言:适合的任务类型:问答、摘要、对话生成等回答必须锚定在相关信息上的场景;RAG 通常是接触 LLM 世界的第一站。原因在于:它提供了一种合理的方式来理解 LLM 应用的工作流程,而且相比其他方案(如直接微调),它对数据和算力的要求都更低;当你需要在LLM 的收益与当前代际模型的局限之间取得平衡时,RAG 也是一个稳妥的起点。反过来说,如果你的任务根本不需要访问外部文档知识(例如通用语言改写),那么 RAG 的检索环节就没有价值,不必为此付出额外工程成本。RAG 如何融入 ZenML 生态在 ZenML 中,RAG 管道被拆解为一系列明确的、可独立运行与重跑的 Pipeline 步骤。ZenML 为此提供了三类平台能力:数据摄取(data ingestion)、索引存储(index store)管理、以及 RAG 关联工件的追踪。下面结合仓库源码逐项说明。将 RAG 拆解为可复现的 Pipeline 步骤指南给出的基本 RAG 管道按顺序包含以下环节,各环节的完整实现见指南对应章节:环节说明参考文档数据摄取用step抓取 URL 列表并用unstructured库解析 HTML,得到纯文本语料data-ingestion.md文本切分将长文档切分为小 chunk,指南示例中取chunk_size500、chunk_overlap50data-ingestion.md嵌入生成用嵌入模型把文本块映射为高维向量,作为检索机制的基础embeddings-generation.md向量存储将嵌入写入向量数据库(指南示例为 PostgreSQL pgvector,并用ivfflat索引配合vector_cosine_ops余弦距离算子)storing-embeddings-in-a-vector-database.md检索与生成基于查询向量检索最相关的文本块,拼接上下文后交给 LLM 生成回答basic-rag-inference-pipeline.md这里有两个值得强调的工程细节:切分参数是需要了解你的数据后调优的。chunk 太小,检索步骤难以找到足够的上下文传给 LLM;chunk 太大,LLM 处理起来又慢又贵。指南示例面对的是软件库文档类网页,因此选择 500 字符块、50 字符重叠——重叠能避免关键信息恰好被切断在两个 chunk 之间。若你的数据是长篇论述,可能需要更大的 chunk;若是问答式对话数据,则可能需要更小的 chunk。索引更新策略与数据变化频率相关。指南在向量存储章节中说明:如果数据频繁且显著变化,可以整体重置嵌入;如果变化轻微或不频繁,则只增量插入新文档。示例代码采用内容已存在则跳过插入的幂等策略,这使得重跑管道是安全的——这正是把 RAG 管道交给 Pipeline 框架管理带来的直接收益。追踪 RAG 关联的工件与元数据理解 RAG 的为什么,落到 ZenML 的怎么做,核心是工件追踪机制。ZenML 把管道每一步的输入输出都登记为带版本的 artifact,并提供 Materializer 体系来落地不同类型的产物。以 RAG 管道中最具 LLM 特征的一类产物——向量存储(vector store)为例,仓库中内置了对应的 Materializer,见 LangchainVectorStoreMaterializer:class LangchainVectorStoreMaterializer(CloudpickleMaterializer): Handle langchain vector store objects. ASSOCIATED_ARTIFACT_TYPE: ClassVar[ArtifactType] ArtifactType.DATA ASSOCIATED_TYPES: ClassVar[Tuple[Type[Any], ...]] (VectorStore,)从源码结构看,该 Materializer 继承自CloudpickleMaterializer,将 LangChain 的VectorStore对象序列化为ArtifactType.DATA类型的工件。也就是说,管道产出的向量存储会像其他数据工件一样被登记、版本化并落盘,后续推理步骤可以直接声明依赖该工件。配合 src/zenml/materializers/ 下的通用 Materializer 注册机制(pandas、numpy、dataclass、Pydantic 等类型均有对应实现),RAG 管道中每一类中间产物都有统一的追踪路径。元数据追踪同样有源码层面的对应。指南中的数据摄取步骤使用了log_artifact_metadata(metadata{count: len(docs_urls)})这类调用,把抓取了多少 URLchunk_size 是多少等信息挂到工件上,从而在 Dashboard 中可见。在仓库源码 src/zenml/artifacts/utils.py#L460-L490 中可以看到,log_artifact_metadata目前已被标记为弃用,官方建议改用log_metadata(metadata{...}, infer_artifactTrue, ...)这一新接口:logger.warning( The log_artifact_metadata function is deprecated and will soon be removed. Instead, you can consider using: log_metadata(metadata{...}, infer_artifactTrue, ...) instead. ... )这意味着:如果你现在基于指南编写代码,应直接使用log_metadata的infer_artifactTrue形式,为同一步骤内新创建的工件自动关联元数据。无论是超参数、模型权重、元数据、性能指标,还是链(chain)、agent、分词器、向量存储这类 RAG/LLM 专属产物,都能被记录在 Model Control Plane 中,并在 ZenML Pro Dashboard 里可视化——这是把一条脚本变成一项可审计的工程资产的关键差别。ZenML 为 RAG 管道带来的工程优势综合原文档的论述,把 RAG 组织成一条 ZenML Pipeline 后,可以明确得到五类收益:可复现性(Reproducibility):可以随时重跑管道,用新文档更新索引存储,或调整切分(chunking)参数。历史版本的工件会被保留,可以对比不同版本管道的表现;可扩展性(Scalability):管道可以轻松扩展以处理更大的文档语料——部署到云服务商,并换用更可扩展的向量存储即可。指南中还提示,若嵌入生成或建索引步骤在 CPU 上过慢,可通过 step operator 让该步骤运行在 GPU 机器上;工件与元数据追踪:管道产出的所有工件都可以关联元数据,提供关于管道的额外上下文与洞察,并在 Dashboard 中可见,便于监控表现、排查问题;可维护性(Maintainability):清晰、模块化的管道结构使得新增步骤、修改现有步骤参数、尝试不同配置都更容易;协作(Collaboration):管道可以分享给团队共同维护,Dashboard 也可以用于向团队同步洞察与发现。从基础 RAG 出发:进阶路线需要指出的是,这条基础 RAG 管道是刻意设计好的起点,而非终点。原文档明确给出了后续演进方向:重排序(reranking)检索到的文档:先召回一批候选,再用更强的排序模型精选,可显著提升检索质量;微调嵌入模型(finetuning embeddings):让向量表示更贴合你的领域语料;微调 LLM 本身:当检索与生成各自都到瓶颈时,再考虑对生成器做领域适配。指南中对应的章节分别位于 reranking、finetuning-embeddings 与 finetuning-llms 小节。由于每个环节都已作为带版本的工件与步骤被追踪,从简单 RAG切换到复杂 RAG是一次渐进式替换,而非推倒重来——这正是把 RAG 纳入 Pipeline 框架的最大价值:起步足够简单,扩展有明确路径,且每一步都留有可回溯的版本记录。【免费下载链接】zenmlZenML : One AI Platform from Pipelines to Agents. https://zenml.io.项目地址: https://gitcode.com/GitHub_Trending/ze/zenml创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考