ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI工程实战:从RAG到Agent的完整落地指南

AI工程实战:从RAG到Agent的完整落地指南 先把话说在前面如果你点进这篇文章大概率手里已经有一个“AI有点用但离能上线还差一口气”的场景。我自己的经历特别典型去年开始维护一个叫ai-engineering-from-scratch的项目本来目标是研究怎么用大模型做点正经事结果发现真正难的不是调模型而是怎么把数据切干净、怎么让 Agent 不乱跑、怎么在上线之后还能搞懂它到底在干什么。这篇文章就是我把这套东西从零到一跑通之后的完整记录。这篇文章适合两类人一类是刚开始学 AI 工程、只对着大模型 API 写过几个 demo 的新手另一类是已经在做 RAG、Agent、模型部署相关项目但总在产品化边缘反复挣扎的朋友。我会把整个链路拆开讲系统设计、技术选型、Prompt 工程、评估方法、检索与 Agent 实现、部署与监控最后再把我踩过的坑全部列出来能让你少走一条很长的弯路。1. 先把“AI工程”这个概念拆明白1.1 模型不是核心系统才是很多教程把 AI 工程等同于“调用大模型 API 写 Prompt”这其实是巨大的误区。你去问任何一个已经上线过 AI 产品的人他第一反应肯定不是“我的模型不够聪明”而是“为什么一阵子能用一阵子不能用”“这个回复 A 客户说好 B 客户就骂”“数据更新完效果反而变差”。这些都是工程问题不是模型问题。模型本身是一个不确定性很强的组件同一个 Prompt 可能在不同时间、不同输入下给出完全不同的答案。工程化的目标恰恰是控制这种不确定性让系统整体表现稳定可预测。我习惯用一个餐厅的比喻模型就像一个大厨他手艺很好但你要开一家餐厅不能只靠大厨。你得有稳定的食材采购数据管道、标准菜单Prompt 和流程设计、上菜顺序管理当前台输入、服务员应对突发事件异常处理还得有顾客满意度回访评估与回归。所以说AI 工程本质上是在构建一个围绕模型的完整系统。你选择哪个模型、用不用加大模型只是这个系统里的一个组件。真正决定项目成败的是你能不能把数据、评估、推理、工具调用、部署、监控这些模块串起来。1.2 为什么“从零开始”比“调现成模板”更有价值现在开源社区有很多现成的框架和项目模板比如 LangChain、Dify、RAGFlow拿来就能跑。但如果你只停留在“跑通 demo”的程度遇到真实业务复杂度时会很痛苦不知道文档切片为什么效果差、不知道 Agent 为什么进入死循环、不知道怎么把性能指标量化出来告诉老板。从零开始不等于不用现成模型或者不用框架而是要求你把每一步都拆开搞清楚为什么这么选、为什么这么实现。比如 FAISS 和 Milvus 都能做向量检索但一个适合单机小规模一个适合分布式大数据LangChain 的 AgentExecutor 很方便但了解 ReAct 循环的底层逻辑你才能给 Agent 加上安全边界。我是从几个基础组件开始做的文档加载、文本切块、嵌入模型调用、向量存入 FAISS、检索后拼接上下文再到用大模型生成答案。先把这个最小链路跑通再加入 Agent 工具调用最后套一个 FastAPI 服务。整个过程不依赖任何重型框架结果反而是我对这个链路的理解比之前看十篇教程都深。2. 全链路技术选型与项目拆解2.1 先把业务问题翻译成工程任务动工之前一定要先把业务问题翻译成工程能解决的问题。举个例子“我要做一个智能客服”是个愿望不是工程任务。工程任务应该是“收集产品手册和历史工单让系统能根据用户问题检索出相关段落并生成回答准确率达到 80% 以上单次请求延迟不超过 5 秒。”翻译完之后还要定义清楚约束条件。对大多数业务来说核心约束往往就三个准确性、延迟、成本。它们之间是互相博弈的。你为了准确率高一点给大模型输入更多上下文结果 token 费变贵、延迟变高你用小型开源模型降低成本可能回答质量又不够。技术选型本质上就是在这些约束里做权衡。我在 ai-engineering-from-scratch 里用的方法是先人工把问题分类统计高频场景再针对最高频的 20 个场景做深度优化。不要把目标定成“什么都能答”大模型本身兜底能力就很强你只要把高频路径的确定性做好这个项目就已经有价值了。2.2 技术栈选什么取决于你要交付什么选型逻辑很简单你的数据能不能出域团队有没有人能长期维护基础设施调用量多大下面这张表基本上覆盖了常见的几种情况场景推荐方案选择理由快速验证业务数据不敏感调用云上大模型 API使用 FAISS 或 Chroma 做本地向量检索开发效率高运维成本低容易拉动迭代企业内部数据必须私有化本地部署开源模型如 Qwen、DeepSeek 系列使用 vLLM 做推理数据不出域推理成本可控海量文档知识库使用 Milvus 或 OpenSearch 集群存储向量配置重排序并发高、数据量大时检索性能稳定复杂流程编排团队对 Prompt 经验不足使用 Dify 这类平台先搭骨架再逐步替换底层组件可视化管理 Prompt 和知识库便于业务人员参与高频 C 端应用需要精细控制 Agent 行为自己实现 Agent 调度循环配合 LangSmith 或 Langfuse 做追踪可观测性强出现问题时能复现链路选型最忌讳的是“哪个热用哪个”。我见过一个项目数据量就几千条却要搭一套 Kubernetes 哨兵集群搞得维护成本比业务成本还高。自己搭建简易后端 单机向量库反而能快速跑完一个完整闭环。2.3 Harness Engineering给模型装上缰绳热词里有一个概念很值得展开说就是Harness Engineering。它本意是给 AI 系统搭建“约束带”和“评估工具”避免模型像个脱缰的野马一样自由发挥。国内有些人把它译成“套笼工程”或者“护栏工程”其实核心就一句话在模型外面包一层机制定义什么能答、什么不能答、怎么保证可评估。具体怎么落地我举一个简单例子。先准备一个固定测试集比如 40 条真实用户提问每条配上标准答案或至少配上“应该包含哪些关键点”。每次改完 Prompt 或者新增检索逻辑就把这 40 条跑一遍自动计算命中率。这个方式非常接近经典软件工程里的回归测试。大模型项目特别需要这种“测试套件”因为模型输出不稳定你不把每一轮修改的效果记录成量化数据根本无法判断到底是改好了还是改坏了。Harness Engineering 还包括输入输出过滤、敏感信息脱敏、限定工具调用范围等。比如一个 Agent 只能调用“查订单”和“查物流”两个工具无论用户怎么绕都不能跳出去调用其他数据这就相当于给 Agent 划了边界。你会在后面的实操部分看到具体怎么做。3. 从零实现一个可上线的 RAG Agent 项目3.1 项目骨架与数据准备我建议你先把项目的仓库结构定下来一个清晰的结构能让你少犯好多糊涂错误。我用的结构大致是这样的ai-engineering-from-scratch/ app/ api.py # FastAPI 服务入口 rag.py # 文档加载、切块、检索 agent.py # Agent 循环与工具调用 pipeline.py # 串联主流程 data/ raw/ # 原始文档 processed/ # 清洗后的文本 tests/ # 单元测试与回归测试 eval/ queries.csv # 测试问题集 run_eval.py # 评估脚本 config/ config.yaml # 各项配置数据准备是最枯燥但最关键的一步。我踩过最大的坑就是直接拿 PDF 里的文本切片喂给嵌入模型。实际的 PDF 或者 Word 文档里经常有页眉页脚、表格、目录这些噪声混进去后检索出来的片段可能根本不是正文。所以我在 ai-engineering-from-scratch 项目里单独写了文档清洗模块先统一转成 Markdown 格式去掉页眉页脚把表格拆成结构化描述再把长文档按标题层级切段。切块长度也有讲究。太短了语义不完整太长了嵌入模型会截断检索精度也会掉。我常用的参数是每块 800 到 1000 字重叠 100 字。这个参数不绝对要先跑一轮检索看结果再调。网上有各种“最佳实践”但这些参数高度依赖你的文档类型和任务没有一劳永逸的案例。3.2 嵌入、向量检索与基础 RAG 实现先从最小链路开始。我用了一段简洁的 Python 代码避免引入太多框架黑盒from sentence_transformers import SentenceTransformer import faiss import numpy as np model SentenceTransformer(BAAI/bge-m3) chunks [第一章 产品参数, 第二章 故障排查, ...] # 实际代码里从文档加载 embeddings model.encode(chunks, normalize_embeddingsTrue) dim embeddings.shape[1] index faiss.IndexFlatIP(dim) index.add(embeddings) def search(query, top_k5): q_vec model.encode([query], normalize_embeddingsTrue) scores, idx index.search(q_vec, top_k) return [chunks[i] for i in idx[0]]这段代码虽然简单但它包含一个非常关键的原理检索质量和嵌入模型的语义匹配能力直接相关。如果用通用的中英文混合模型处理专业领域文档效果很可能不好。我当时用 bge-m3是因为它对中文长文本支持比较稳而且支持同时生成向量和稀疏向量。不过最好还是拿你自己的真实问题测试几个模型别听我一面之词。光有向量检索还不够实际项目中我还会配合重排序。第一步送给向量库检索出 top 30第二步用一个专门的重排序模型比如 bge-reranker把这 30 段重新打分最后只取 top 3 作为上下文。这样做的原因是向量检索擅长找“语义相近”的内容重排序更擅长精细判断“哪段真正回答了问题”。两步各干各的效果比单一步骤好不少。最终生成答案的 Prompt 要尽量简化让模型专注在“阅读上下文然后回答”这件事上你是一个知识库客服助手。请只基于以下文档片段回答问题。 如果答案不在文档中请明确说“根据文档无法回答”不要编造。 文档片段 {context} 用户问题 {question}这个 Prompt 虽然朴素但比那些花里胡哨的“角色扮演”要稳得多。你越让模型做小事它越能做对。3.3 让 Agent 学会自己调用工具RAG 解决的是“从文档里找答案”Agent 解决的是“动态决定下一步做什么”。比如用户说“帮我查一下订单号 12345 的物流顺便看看能不能改地址”这个需求很难通过一次检索完成需要模型自己拆解步骤。实现 Agent 最稳定的方式不是塞给它一个超长的 Prompt而是把工具定义清楚。我用 Pydantic 定义工具 Schemafrom pydantic import BaseModel class QueryOrderInput(BaseModel): order_id: str 订单号 TOOLS [ { type: function, function: { name: query_order, description: 查询订单物流状态, parameters: { type: object, properties: { order_id: {type: string, description: 用户订单号} }, required: [order_id] }, }, } ]然后在主循环里让模型根据用户问题判断是否调用工具def run_agent(user_message): messages [{role: user, content: user_message}] response llm.chat(messagesmessages, toolsTOOLS) if response.tool_calls: # 执行工具把结果追加到 messages再让模型生成最终回复 for tool_call in response.tool_calls: result execute_tool(tool_call.function.name, tool_call.function.arguments) messages.append({ role: tool, content: str(result), tool_call_id: tool_call.id, }) final_response llm.chat(messagesmessages) return final_response.content return response.content最核心的一点是不要相信“多轮思考会更聪明”要给循环加硬限制。我在项目里加了两个固定条件最大迭代次数限制 5 轮单次会话累计 token 上限到上限强制停止。没有这两个限制Agent 很可能在一个问题上反复横跳把你的预算烧光。还有一个容易忽略的细节工具描述要用口语化的业务语言写。e大模型是语义匹配不是正则匹配。你要是写“query_order(order_id: string)”模型很可能在用户没有订单号时也强行编一个出来。但如果你在 description 里写明“当用户没有提供订单号时先询问用户订单号”模型就不会硬猜。3.4 服务化与模型部署Agent 跑通了下一步就是把它变成一个 HTTP 服务。我用 FastAPI因为异步和文档都方便from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class ChatRequest(BaseModel): question: str app.post(/api/chat) async def chat(req: ChatRequest): answer run_pipeline(req.question) return {answer: answer}但这只是最表面的东西。真正要上线你还需要考虑并发和推理资源的问题。如果你用的是云 API那瓶颈就在你的业务逻辑和网络带宽异步处理就好。如果你是用本地开源模型那我强烈建议你用 vLLM 做推理服务它支持连续批处理和 PagedAttention吞吐量会比直接跑 Transformers 高很多。部署的时候用 Docker 包一层加上健康检查和容器内存限制比裸机跑要稳得多。成本计算也不能只看模型单次价格。我给你一个通用公式单次回答成本 (输入 token 数 输出 token 数) × 单价比如知识库客服的大量成本其实集中在输入侧因为每次调用都要塞进一堆上下文和检索片段。想办法减少无关上下文效果又不会掉这本身就是一种工程优化。我在项目里测试过把重排序后的 top 5 改成 top 3回答质量几乎没有变但 token 消耗少了 40%。这种优化看似小乘上日均上万次调用成本差异非常明显。4. 实操中必须避开的坑4.1 数据切块和检索里隐藏的魔鬼第一个最容易踩的坑文档切片不管标题层级。原始文档里一个章节可能有三层标题结果被当成一整块切出来几百个字混在一起嵌入模型根本捕捉不到重点。我的做法是保留标题元数据在切块时把标题作为前缀拼进文本里比如“故障排查 电源问题 指示灯不亮”。这样语义向量能够感知上下文检索相关片段更准。第二个坑是嵌入模型不一致。比如离线建索引时用了一个嵌入模型线上查询时不小心换成了另一个向量空间都不一样检索结果必然是乱的。我会用代码检查固定住模型名称和版本部署时强制记录模型 hash一旦不一致直接报错。第三个坑是“检索到了但答案就是不对”。这是典型的上下文污染文档中天然存在很多相似片段比如不同产品型号的“保修政策”内容高度重合检索出来三道全是最像但不对应型号的。解决方法是把产品型号等关键字段写进 Prompt并要求模型“如果上下文没有明确提到该型号必须拒绝回答”。这个方法看起来简单实际效果比调一百遍 Prompt 都强。4.2 评测盲区总觉得好用上线却翻车我在 2.3 节提到了测试集。这里我要强调测试集必须包含边界情况不能只挑“正常提问”。我在做客服知识库的时候第一版测试集里全是“你们产品怎么用”的正常问题模型表现很漂亮。结果一上线用户开始问“你的政策什么时候更新”“你能把我过期订单删了吗”系统直接崩了。所以你至少要有三类测试数据正常问题、边缘问题信息不完整、指代不清、恶意或者敏感问题诱导泄露系统 Prompt、越权操作。每一类单独统计通过率不要只算一个总准确率。关于“用大模型给大模型打分”这个做法可以用但要小心。LLM 作为评审的稳定性和偏见本身就是问题。我举一个真实例子问“这款手机电池能用多久”模型回答“根据文档中提到正常使用约为一天”评审模型评判时可能会主观认为“没有给具体时长”判定为错误。后来我调整了评估指标结构一是人工提供的关键点是否覆盖二是答案是否包含文档未提到的内容三是语气是否礼貌。结构化指标比一句笼统的“满不满意”更能反映真实质量。评估项通过标准示例关键信息覆盖率标准答案中的核心名词出现在回答中标准含“保修一年”回答含“一年保修”幻觉检查回答内容能在给定上下文中找到依据上下文没有“可以退货”回答就不能“可以退货”拒绝判断信息不足时明确拒绝回答“根据文档无法回答”稳定性同一问题连续调用 5 次结果无重大逻辑冲突回答不忽左忽右4.3 Agent 失控循环、幻觉和成本黑洞Agent 失控是大家在热词里反复提到的“AI Agent”最容易翻车的地方。我在实测中见过最夸张的一个场景用户问“帮我取消订阅”Agent 调用了查询订阅接口因为没有找到订阅又自动调了查询用户接口然后又因为无法确认身份开始向用户索要身份证号。整个流程五轮下来不仅没有任何有价值的信息还白白消耗了一万多个 token。想要限制这种失控我总结出三条硬规则工具数量不要贪多。一个 Agent 暴露给模型的工具最好控制在 5 个以内工具越多模型做决策的不确定性越大。失败路径要明确。每个工具执行失败后都要返回统一的“执行失败原因”结构并且下一轮生成的回复只允许向用户解释失败不允许继续调用其他工具。加预算护栏。在代码里写死单次请求的最大 token 数超过直接截断并提示“内容过长已强制结束”。别心疼那一点点可用性损失失控造成的损失永远比健康损失大。我还要多说一句很多团队迷信“多 Agent 协作”更高级但我看到的成功项目里绝大多数一开始都是单 Agent 工具。多 Agent 带来的通信成本和管理复杂度是指数级上升的先跑通单 Agent再考虑把不同职责拆成多个可复用的流程。4.4 部署与监控不能等上线后再补项目上线前一定要把监控做进去。这里的监控不只是看 CPU、内存这些传统指标更重要的是对话级别的可观测性。我项目里用的是 Langfuse每次请求都记录用户原始输入、检索命中的文档片段、Prompt 完整内容、模型输出、token 消耗、延迟。没有这些数据线上出问题你只能抓瞎。监控指标最优先看三个指标定义我设置的报警阈值平均响应延迟从请求到返回的时间P95 超过 5 秒报警Token 消耗速率每小时调用的输入输出 token 总量超过日预算线 80% 报警用户负面反馈率用户主动点“不喜欢”或投诉的比例超过 5% 人工复核这些数字不绝对但你必须有一个量化的报警标准。否则上线后的所谓“监控”只是挂着一块没人看的仪表盘。4.5 常见问题速查表我把实操中反复遇到的坑整理成一张表你遇到对应症状可以快速对照症状可能原因解决动作检索结果明显无关嵌入模型或文档切片问题检查切片标题是否保留换模型对比回答出现“编造”内容上下文里没有相关证据模型被强迫回答强化 Prompt 的“无证据拒绝回答”指令Agent 反复调用同一工具工具缺少失败反馈或 Agent 循环无限制增加失败返回结构设置最大迭代次数并发一高就超时模型推理服务没做批处理切换到 vLLM 并开启 continuous batchingtoken 预算很快烧完上下文塞了太多无关片段缩短 top_k增加重排序过滤上线一星期后效果变差业务数据变了测试集跟不上定期更新测试集新增真实用户案例不同环境检索效果差很多嵌入模型版本不一致锁定模型版本部署前跑向量一致性校验5. 从 Demo 到产品再往前走三步5.1 流程和自动化让迭代可持续很多项目死在了“效果时好时坏”上本质原因是迭代过程没有约束。你想软件工程里没有人敢在没有 CI 的情况下天天往主干提交代码但 AI 项目里很多人就是手动测两三个问题就推到线上。AI 的不可预测性比传统软件更高就更需要有反馈闭环。我的做法非常简单把所有 Prompt、工具定义、代码都放进 Git 仓库。每次修改本地先跑一遍完整测试集用脚本记录准确率和关键指标达标了才允许提交合并。这套流程不复杂但它把 AI 项目的迭代从“玄学”变成了“可回归的工程”。再进阶一步就是在测试集基础上做 A/B 测试。可以把线上流量按 10% 切到新版本对比两边的用户反馈率、重答率、延迟等指标。注意AI 项目的 A/B 测试周期不能太短因为用户输入非常多样一天的数据量不具备统计意义。我一般会跑一周最少三天。5.2 可以反复复刻的练习课题与扩展方向如果你看完这篇文章想自己动手练一下我给你几个按难度递增的课题本地文档问答机器人做一个小型 RAG提供 Web 上传入口实现“文档任意位置快速检索”。重点练切片、嵌入、检索、Prompt。客服工单分类 自动回复生成先用规则模型做工单分类再用大模型生成回复草稿。重点练结构化输出和评估。带工具的智能体做一个能查订单、改地址、咨询物流的小助手。重点练 Agent 循环、工具失败恢复、会话状态管理。多智能体协作把“客服工单”流程拆成“接线员 Agent”和“处理 Agent”用消息队列传递结果。重点练系统设计。将来如果要往深走可以从这几个方向延展提示词工程只是起点还要学模型微调和量化部署RAG 之外要理解搜索引擎的倒排索引混合检索能显著提升专业领域效果Agent 的可控性则和向量记忆、长期状态管理强相关。最后再分享一个我这大半年最深的体会AI 工程项目的核心不在于你把模型调得多好而在于你有没有一套能兜底的评估体系和容错机制。模型总会有意外系统却能通过护栏、回归测试和监控把意外的影响限制在可控范围。宁可让系统在边界情况下“笨笨地拒绝”也不要让它自信地胡说。这个原则我建议你放进所有 AI 项目的设计里。
返回列表