如果你已经学完了 LLM 的基础用法看过几个 RAG 教程也跑通过一个“能问答”的 Demo那么接下来最困惑你的问题通常是为什么换个数据源就崩为什么检索出来一堆无关内容为什么回答看起来对但一到生产环境就没人敢用这就是从“会调用模型”到“能做 LLM 工程”的分水岭。“Udemy - AI LLM Engineering Mastery: GenAI, RAG Complete Guide part2”这类课程恰恰是瞄准这个阶段来设计的。它不太像入门课那样把大模型 API 当黑盒去调而是把重心放在工程链路上数据怎么处理、检索怎么做、Agent 怎么编排、生成结果怎么评估、精度和成本怎么权衡。换句话说Part 1 大概率在教你“怎么让模型说话”Part 2 则在教你“怎么让模型在真实系统里可靠地工作”。这篇文章不打算复述课程目录而是把 Part 2 这类进阶内容背后真正重要的技术主线拆开讲清楚。你会看到 RAG 从概念到落地的完整流程Agent 和工具调用为什么是 LLM 工程的下一个台阶FP16/BF16 这些精度问题为什么会影响推理效果以及一个生产级 GenAI 应用在评估和排错时到底应该看什么。文章会给出可复制的代码示例、项目结构和排查清单而不是空谈架构。1. 这篇文章真正要解决的问题先说一个比较直接的判断LLM 应用开发最大的成本已经不在模型本身而在工程编排。早期做 GenAI 项目很多团队先兴奋地调用 GPT 或开源模型跑通对话然后立刻撞上一堵墙——模型输出的不确定性、知识库更新不及时、检索召回质量差、Token 成本失控、响应延迟波动大。这些问题没有一个是“换个更强模型”就能解决的。它们分散在数据管道、索引策略、推理服务、评估机制和 Agent 调度链路里。Part 2 这类进阶课程的价值就是帮助开发者建立一套系统化的问题拆解框架。它通常不会教你“什么是 Transformer”而是教你在生产环境里怎么做文档解析、怎么设计 chunk 策略、怎么选 Embedding 模型、怎么优化检索、怎么用 ReRanker 提高精度、怎么为 Agent 设计工具和护栏。什么样的读者最适合读这篇文章已经会用 Python 调用 OpenAI/开源模型但没做过完整 RAG 项目的人。在公司里负责“把大模型接入业务系统”的工程师正在被知识库问答、私有数据检索、Agent 自动化等问题困扰。准备系统学习 LLM Engineering想在动手前先建立全局认知的人。这篇文章会帮你解决的问题RAG 全链路怎么做、Agent 工程和普通 API 调用差在哪、推理精度对结果的影响有多大、以及一个 RAG 系统上线前应该做哪些验证。2. LLM 工程的核心概念与底层逻辑在进入代码之前先把几个高频概念讲清楚。因为这些词在博客、课程简介、技术讨论里经常混着用如果概念边界不清晰后面看代码也会费劲。2.1 RAG检索增强生成RAGRetrieval-Augmented Generation的全称是检索增强生成。它的核心思想是大模型本身不懂你私有的业务数据那就先从一个外部知识库中检索出相关内容再把这些内容拼进 Prompt让模型基于这些材料生成回答。通俗解释以前的模型回答靠“背课文”RAG 是让模型“开卷考试”。你先把参考书给它它再去写答案。RAG 解决了三个问题知识时效性模型训练数据有截止时间RAG 可以接入最新文档。私有数据接入企业内部的 PDF、Word、数据库内容不会出现在模型训练集里RAG 让模型可以“临时阅读”。可追溯性回答可以引用来源文档方便人工验证和审计。这也是为什么 RAG 几乎成为企业落地 LLM 的第一个标配方案。2.2 Agent从单次问答到多步任务Agent智能体这个词近两年被用得很宽泛。在 LLM 工程语境下一个相对准确的定义是能够让大模型在循环中调用工具、观察结果、决定下一步行动的系统。如果说 RAG 是一个“查询型”应用那么 Agent 就是一个“任务型”应用。它不再满足于回答“合同里违约条款是什么”而是去执行“帮我分析这份合同把异常条款标出来并写一封提醒邮件”。Agent 的工程难点在于流程控制。模型每一步的决策都可能出错工具调用的参数可能不符合 Schema执行结果可能和预期偏差很大。这也是 Part 2 课程中“Harness Engineering”这个词反复出现的原因——它强调的不是让模型自由发挥而是用工程手段给 Agent 套上缰绳。2.3 Prompt Engineering不是玄学是输入输出约束Prompt Engineering提示工程并没有那么神秘它的本质是在不微调模型的前提下通过输入文本的结构和示例提高模型输出质量。进阶课程里更关注的是结构化输出让模型返回 JSON而不是自由文本。少样本示例给模型几个输入输出对减少格式错误。Chain-of-Thought让模型先推理再回答适合复杂逻辑问题。护栏指令约定“不知道就回答不知道”“不要编造来源”。一个很容易踩的坑是很多人以为 Prompt 写一次就完事实际项目中 Prompt 也是要版本管理的和代码一样需要回归测试。2.4 精度问题FP16、FP32、BF16 到底影响什么这是很多开发者入门时会忽略的问题。大模型推理和训练时浮点数精度直接决定显存占用、计算速度和数值稳定性。FP3232 位浮点数精度最高但显存占用大推理速度慢。FP1616 位浮点数显存减半速度更快但表示范围小容易溢出。BF16Brain Floating Point同样是 16 位但保留了和 FP32 相同的指数位表示范围大适合大模型训练和推理。在实际工程里模型部署经常用 FP16 或 BF16 来降低显存成本。但精度降低可能带来效果波动尤其在小数敏感的任务上比如评分、时间计算、财务数值提取。这也是“LLM 大模型之精度问题FP16、FP32、BF16”这个话题在工程圈流行起来的原因。在课程和实战中建议至少跑一次“同一模型在不同精度下的推理对比”你会发现结果差异在某些场景下不是可忽略的。3. 环境准备与前置条件进入实操部分之前先把环境说清楚。本文演示的是一个最小可运行的 RAG 项目面向学习场景不需要 GPU 也能跑通全部流程。3.1 基础环境组件说明操作系统Windows 10/11、Ubuntu 20.04 及以上均可Python3.10 或 3.11包管理pip 或 poetry模型服务可使用 OpenAI API或本地部署开源模型如 Qwen、ChatGLM向量数据库使用 Chroma 或 FAISS便于学习生产环境可换 Milvus / Qdrant版本说明本文不绑定某个具体版本重点演示通用实现思路。安装依赖时请以最新稳定版为准如果遇到版本冲突优先查看官方文档。3.2 安装依赖创建一个新的项目目录并准备虚拟环境mkdir llm_rag_demo cd llm_rag_demo python -m venv venv # Windows 激活方式 venv\Scripts\activate # Linux/macOS 激活方式 # source venv/bin/activate安装核心依赖pip install langchain langchain-community langchain-openai pip install chromadb pip install pypdf pip install beautifulsoup4 pip install tiktoken如果使用 OpenAI 模型还需要配置环境变量。这里不建议把 Key 写死在代码里而是使用环境变量或配置文件export OPENAI_API_KEYyour-api-key如果使用本地模型可以通过 Ollama 或 vLLM 启动一个 OpenAI 兼容接口代码里的 Base URL 换成本地地址即可。3.3 验证环境运行以下命令检查环境和模型接口是否正常import openai client openai.OpenAI() response client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: 你好请用一句话介绍 RAG。}], ) print(response.choices[0].message.content)如果输出正常说明模型调用链路没问题可以继续后面的 RAG 构建。4. RAG 系统完整流程拆解RAG 看起来简单但每个环节都有讲究。一个标准的 RAG 流程可以拆成两个阶段索引阶段Indexing和查询阶段Querying。4.1 索引阶段让知识库可以被检索索引阶段的输入是原始文档输出是向量索引。这中间要经过四步第一步文档加载Load。从 PDF、HTML、Word、TXT 等文件中读取文本。不同格式对应不同的解析器PDF 尤其容易踩坑因为扫描版 PDF 没有文本层需要 OCR。第二步文档分割Split。把长文档切成多个块chunk。切得太大会引入无关噪音切得太小会丢失上下文。常见策略是按固定字符数切分并设置重叠overlap来保留上下文连贯性。第三步向量化Embedding。将每个文本块通过 Embedding 模型转成向量。向量可以理解为文本语义的“数字指纹”。选择 Embedding 模型时要额外注意它的最大输入 token 数例如文本超过限制时需要二次截断。第四步存储Store。把向量写入向量数据库并记录对应的原始文本和元数据如来源文件名、页码。4.2 查询阶段从检索到生成查询阶段的输入是用户问题输出是最终回答。流程如下将用户问题向量化。在向量数据库中执行相似度检索召回 Top-K 个相关文本块。可选用 ReRanker 对召回结果做重排序提高精度。把召回文本和用户问题一起放入 Prompt。调用大模型生成回答。检索质量是整个 RAG 系统效果的上限。如果召回的内容不对后面 Prompt 写得再好也没有用。这也是为什么“RAG 知识库有哪些指标、如何理解各指标”会成为热搜话题。4.3 做一个最小可运行的 RAG Demo下面给出一个可直接运行的 Python 脚本。它使用 LangChain 的轻量封装流程清晰适合学习时逐段阅读。# 文件路径rag_demo.py from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import Chroma from langchain.chains import RetrievalQA # 1. 加载 PDF 文档请替换为你的本地文件路径 loader PyPDFLoader(./data/sample_contract.pdf) documents loader.load() # 2. 文本分割每块 500 字符重叠 50 字符 text_splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50, separators[\n\n, \n, 。, , , , ], ) texts text_splitter.split_documents(documents) # 3. 向量化并写入 Chroma embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentstexts, embeddingembeddings, persist_directory./chroma_db, ) # 4. 构建检索问答链 llm ChatOpenAI(modelgpt-4o-mini, temperature0.2) qa_chain RetrievalQA.from_chain_type( llmllm, retrievervectorstore.as_retriever(search_kwargs{k: 4}), ) # 5. 提问 query 这份合同中的违约金条款是什么 answer qa_chain.invoke({query: query}) print(回答, answer[result])代码有几个地方值得注意chunk_size和chunk_overlap不是固定值需要根据文档类型和 Embedding 模型的最大输入调整。k4表示召回 4 个文本块。k 太小可能漏信息k 太大会把无关内容塞进 Prompt干扰生成。temperature0.2让模型输出更聚焦于事实减少创造性发挥。如果这个脚本能跑通恭喜你你已经实现了一个基础版 RAG。5. 从基础 RAG 到可用的知识库问答系统基础 RAG 能跑通但离“可用”还有距离。实际项目中会有几个明显问题PDF 解析失败、检索结果乱、回答引用没有来源、知识库更新成本高。Part 2 类进阶课程里很大一部分内容就是在解决这些问题。5.1 文档加载与解析的完整流程很多人把文档加载想得太简单以为和读 TXT 一样。实际上真实世界的文档往往长这样PDF 里同时有文字和图片部分文字是扫描件。Word 文档里有页眉页脚、表格、批注。HTML 页面有导航栏、广告、正文正文混杂。如果这些不处理后面所有环节都会被污染。推荐的做法是# 文件路径loader_utils.py from langchain_community.document_loaders import PyPDFLoader, BSHTMLLoader from langchain_community.document_loaders import Docx2txtLoader def load_document(file_path: str): 根据文件后缀选择加载器返回 Document 列表 if file_path.endswith(.pdf): loader PyPDFLoader(file_path) elif file_path.endswith(.html) or file_path.endswith(.htm): loader BSHTMLLoader(file_path) elif file_path.endswith(.docx): loader Docx2txtLoader(file_path) else: raise ValueError(f不支持的文件类型: {file_path}) return loader.load()对于扫描版 PDF需要额外接入 OCR 服务。现阶段一个务实的思路是把扫描件先交给文档解析工具如本地 OCR 模型转成文本再进入 RAG 流程。5.2 检索优化混合检索与重排序向量检索擅长语义相似但有时会把“字面完全一致但语义不相关”的内容召回。比如问“苹果的市值”知识库里有一篇讲“苹果公司历史”的长文向量检索可能召回了一整段无关历史。优化的第一个手段是混合检索同时使用向量检索和关键词检索BM25再把两种结果融合。优化的第二个手段是重排序ReRank。先用向量检索召回 Top-50再用一个更强但更重的排序模型把最相关的 Top-5 挑出来。这种方式比直接向量检索 Top-5 效果更稳定代价是多一次模型调用和额外的延迟。5.3 为回答添加引用来源生产环境的 RAG 系统回答必须能溯源。做法是在检索阶段保留每个文本块的元数据然后在 Prompt 中要求模型在回答后附上来源编号。# 文件路径rag_with_source.py from langchain.schema import Document # 在构建 Prompt 时把源文档信息带入 context_parts [] for i, doc in enumerate(retrieved_docs): source doc.metadata.get(source, unknown) page doc.metadata.get(page, unknown) context_parts.append(f[{i1}] 来源: {source} 第{page}页\n{doc.page_content}) context_text \n.join(context_parts) prompt f请根据以下知识库内容回答问题。回答末尾请标注引用来源编号。 知识库内容 {context_text} 问题{query} 要求如果知识库中没有相关信息请直接回答“知识库中未找到相关信息”不要编造。 回答添加引用有两个好处一是方便用户验证二是倒逼模型只依据检索内容回答降低幻觉概率。6. 从 RAG 到 Agent工具的引入与编排RAG 解决“从知识库里找答案”的问题Agent 解决“执行多步任务”的问题。Part 2 课程通常会把这两块放在一起讲因为它们在技术栈上是衔接的。6.1 为什么需要 Agent假设用户提出这个需求“帮我查一下项目文档中提到的所有截止日期并按照时间远近整理成一个表格。”这个任务不是一次检索能完成的。系统需要搜索包含“截止日期”的文档。从多个文档中提取日期和对应事项。对日期排序。生成 Markdown 格式表格。如果全部写死在代码里需求一变就要重新改代码。Agent 的思路是让模型自己决定调用哪些工具并把结果汇总。6.2 一个简单的 Agent 示例LangChain 和 OpenAI Function Calling 都可以实现 Agent 的基础版本。下面用 OpenAI 的 tools 机制演示# 文件路径agent_demo.py from openai import OpenAI import json client OpenAI() # 1. 定义工具 def get_weather(city: str) - str: 根据城市名返回模拟天气 weather_map { 北京: 晴25 度, 上海: 小雨22 度, 广州: 多云28 度, } return weather_map.get(city, 暂无数据) tools [ { type: function, function: { name: get_weather, description: 查询指定城市当前的天气, parameters: { type: object, properties: { city: {type: string, description: 城市名称如北京} }, required: [city], }, }, } ] messages [ {role: user, content: 北京和上海今天天气怎么样} ] # 2. 第一轮调用模型可能返回工具调用指令 response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools, ) message response.choices[0].message print(模型返回, message) # 3. 执行工具调用并回填 if message.tool_calls: messages.append(message) for tool_call in message.tool_calls: function_name tool_call.function.name arguments json.loads(tool_call.function.arguments) result get_weather(**arguments) messages.append({ role: tool, tool_call_id: tool_call.id, content: result, }) # 4. 第二轮调用模型基于工具结果生成最终回复 final_response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools, ) print(最终回答, final_response.choices[0].message.content)这个例子很基础但它展示了 Agent 的核心链路模型输出工具调用指令 → 代码执行工具 → 结果回填 → 模型继续生成。6.3 Agent 工程的常见陷阱Agent 比 RAG 更难上线原因是它多了一层“循环”和“不确定性”。常见问题包括模型陷入死循环同一个工具调用反复执行不退出。参数幻觉模型生成了不存在的参数名。安全边界失控Agent 调用工具时没有权限校验越权访问数据。成本不可控多轮循环导致 Token 消耗快速上涨。所以进阶课程中才会频繁讨论“Harness Engineering”。这个概念强调的不是让 Agent 自由发挥而是用约束、验证、白名单工具、超时机制、人工审核等方式把 Agent 关在笼子里干活。7. 运行结果与效果验证代码写完之后如何判断 RAG 系统是否真的有效如果没有一个验证方法很容易陷入“看起来答得不错”的错觉。7.1 运行方式如果你复制了上面的rag_demo.py执行方式很简单python rag_demo.py预期输出应该包含“回答……”开头的一段文字内容是知识库中相关信息的总结。如果脚本报错优先检查以下三项OPENAI_API_KEY是否配置正确。PDF 路径是否存在且可读。网络是否能访问 OpenAI API。7.2 效果验证的四个维度一个 RAG 系统是否合格可以从四个维度看维度问题通俗解释召回率正确的内容有没有被检索出来相关文档是否漏掉了精确率检索出来的内容是否相关无关内容是否混进来了忠实度回答是否忠于检索内容模型有没有自己瞎编答案相关性回答是否解决了用户问题用户是否满意7.3 用简单脚本评估检索质量在还没有完整评估平台时可以先写脚本统计“检索结果里有多少是真正相关的”。下面是一个简化版本# 文件路径eval_retrieval.py # 假设已经加载 vectorstore retriever vectorstore.as_retriever(search_kwargs{k: 5}) query 合同中的付款方式是什么 docs retriever.invoke(query) for i, doc in enumerate(docs): print(f--- Top {i1} ---) print(doc.page_content[:200]) print(来源, doc.metadata.get(source, unknown)) print()人工查看召回结果比直接看最终生成结果更接近“定位问题”的目的。如果检索出来的前几条明显不相关就不用再调 Prompt 了问题出在分块策略或 Embedding 模型上。8. 常见问题与排查思路RAG 和 Agent 项目里很多报错和异常效果是可以按套路排查的。下面整理了一份高频问题清单。问题现象可能原因排查方式解决方案PDF 加载后内容为空PDF 是扫描件无文本层用 pdfplumber 或 OCR 工具检查接入 OCR或使用带 OCR 的文档解析服务检索结果和问题不相关分块太大/太小向量被语义稀释打印召回文本检查 Top-K 的内容调整 chunk_size尝试混合检索回答引用了错误来源ReRank 未生效检索排序靠前的是无关内容检查最终喂给模型的上下文顺序引入 ReRanker调整 k 值Token 消耗异常高上下文过大或 Agent 多轮循环记录每次请求的 token 用量限制最大上下文长度设置 Agent 最大迭代次数同一问题答案不稳定temperature 设置偏高多次运行同一问题对比输出降低 temperature 到 0.1-0.3模型回答“不知道”时仍编造缺乏护栏指令和来源约束查看 Prompt 中是否要求“不知道就回答不知道”在 Prompt 中加入否定指令和来源要求Agent 工具调用频繁报错工具参数 Schema 定义不严谨打印工具调用参数对比定义简化参数增加参数校验逻辑这组排查思路的核心原则是先看数据再看模型。很多问题表面上像模型能力不够实际上是因为送入模型的上下文质量太差。9. 最佳实践与工程建议Part 2 类课程讲到最后一定会落到工程实践上。以下几条建议来自我在多个 RAG/Agent 项目中的经验按优先级整理。9.1 分块策略要写配置文件不要硬编码不同的业务文档适合不同的分块策略。法律合同可能需要按条款分割技术文档可能需要按标题分割客服问答适合按问答对分割。把分块参数放到配置文件里方便为不同数据源调优。# 文件路径config.yaml chunk_size: 500 chunk_overlap: 50 embedding_model: text-embedding-3-small retriever_k: 5 use_rerank: true9.2 日志要记录完整链路生产环境里用户说“回答不对”时你必须有办法还原现场。最少要记录用户问题、召回文本预览、最终 Prompt、模型回复、token 用量、延迟。否则根本没法定位是检索问题还是生成问题。9.3 安全边界要先于效果调优如果你做的 Agent 能在内部系统里执行操作必须做权限校验。Agent 工具的最小权限原则是默认拒绝按需放行。尤其是涉及数据库修改、文件删除、对外发送消息的工具一定要有二次确认和操作审计。9.4 评估不是上线后的事从第一个 Demo 开始就要准备一组基准问题Golden Set。每次改分块策略、换模型、调 Prompt 后都在这组问题上回归。没有评估所有优化都是凭感觉。9.5 精度问题要纳入部署评估清单如果模型要在 GPU 上部署FP16 或 BF16 量化几乎是必须的。但量化后一定要跑一遍基准问题集确认精度下降在可接受范围内。对财务、医疗等对数值敏感的场景建议优先保留 FP32 或使用 BF16 而不是 FP16避免溢出导致的数字错误。10. 总结与后续学习方向在这篇文章里我重点做了几件事解释了 LLM 工程从 Demo 到生产之间真正难在哪拆解了 RAG 的索引和查询全流程并给出一个可运行的代码示例介绍了 Agent 的基础实现和工程陷阱讨论了 FP16/BF16/FP32 精度问题对推理效果的影响最后给出了效果验证指标和排查清单。如果你正在学习类似“AI LLM Engineering Mastery: GenAI, RAG Complete Guide part2”的课程建议不要只跟着课程敲代码而是给自己定一个真实的小项目比如“把公司某类文档做成知识库问答系统”或“让 Agent 自动整理周报”。只有带着真实数据跑一遍你才会遇到分块不合理、检索召回差、模型依赖上下文、成本失控这些问题。踩过一遍坑再看理论才能真正理解为什么 RAG 和 Agent 工程需要一整套方法论。下一步可以往这几个方向深入向量数据库的索引原理HNSW、IVF、Embedding 模型的微调与领域适配、ReRanker 的实现原理、Agent 的记忆机制与多智能体协作、RAG 的可观测性与评估平台搭建。每一条都足够写很多篇实战文章也是 LLM 工程领域真正缺经验的环节。尤其建议优先补评估和可观测性因为任何系统一旦进入生产稳定性和可维护性会立刻变成第一优先级。