ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从零构建AI工程:RAG、Agent与质量保障实战路线

2026/10/5 14:53:30 拓冰建站 浏览量
从零构建AI工程:RAG、Agent与质量保障实战路线 1. 从零开始先搞懂AI工程到底在做什么这半年多我一直在折腾一个叫 ai-engineering-from-scratch 的项目目标是纯手工打通“从零开始做AI工程”这件事。之所以想写下来是因为我发现多数人一上来就调大模型API能跑通demo就以为自己会了可真往生产环境里一放问题全冒出来答案胡编、上下文超限、token烧钱、线上改个prompt都提心吊胆。这篇笔记记录的是我自己的路线和踩坑不是教材。适合两类人准备转岗做AI应用开发的工程师以及还没想清楚技术栈就被各种新词砸晕的产品或技术负责人。1.1 大模型是发动机AI工程才是整车很多人把AI工程等同于“调模型”。单看一个问答demo确实是选个模型、写个prompt、拿数据一怼就出结果。但真实业务里模型只是发动机AI工程是整车。你还需要油箱和管路知识库与数据流、方向盘和刹车提示词约束与工具权限、仪表盘监控与评估、维修手册测试与回归。没有这些发动机再猛也没法上路。我见过最典型的翻车现场一个团队只用了三天就接好了模型试用时非常惊艳但上线后频繁出现两件事——第一模型会根据“想当然”编造不存在的客户信息业务方直接炸锅第二每条请求拼上十几篇参考文档token消耗是预算的十倍。这说明他们缺的不是模型效果而是可复用的工程能力检索精度控制、提示词约束、成本监控。所以AI工程的重点是把模型放进一个可控、可度量的系统里。1.2 六个核心组件一张图记清楚如果要把AI工程的关键模块拆出来我习惯分成六块分别对应落地时一定会碰到的环节。这六块不是教科书式分类而是我每次做项目评审时都会逐项过一遍的检查清单少一个后面肯定要返工。模型层选基座模型。是闭源API还是开源权重是通用模型还是领域微调模型这是所有决策的地基。上下文工程也就是常说的prompt engineering包括提示词模板、few-shot示例、格式约束、上下文窗口管理。它决定模型在特定任务里的行为上限。知识层外部知识怎么进来。文档加载、切块、向量化、检索、重排序构成RAG检索增强生成的基础也是解决“私有知识和时效性”的主流方案。工具层模型需要调用外部能力才能完成真实动作。API调用、数据库查询、代码执行器、浏览器工具的定义和权限管理是Agent化的前置条件。编排层把多个模型调用、工具调用、条件分支和循环组织成一个流程。可以是简单链式调用也可以用Agent循环做动态规划。质量层评估、测试、监控、反馈循环。AI应用输出随机性很强没有这一层你根本不知道系统是变好了还是变坏了。这六块不是孤立存在的。举个例子一个智能客服可能需要模型层选一个延迟低的小模型知识层挂产品手册上下文工程沉淀一套客服话术模板工具层查订单状态编排层把“查订单→查售后规则→生成回复”串起来最后质量层用一批历史工单持续回归。只有六块都跑通才算一个完整的AI工程。1.3 四个阶段的自学路线我自己的实践路径大致分四个阶段每次卡住就说明该补哪块第一阶段先把模型行为摸熟。单纯玩prompt理解温度、top_p、系统提示词、少样本这些基础。这一阶段不需要懂后端重点是建立“模型是概率系统”的直觉。第二阶段做一个最小RAG。选一份自己的文档切块、向量化、检索、生成把每个环节手工过一遍。做完之后你会对检索质量、上下文长度、幻觉来源有切身体会。第三阶段把流程Agent化。从“一问一答”变成“多步规划”让模型学会调用工具。这时候才会真正遇到循环失控、工具权限、状态同步这些工程问题。第四阶段补全评估和监控。没有评估的AI项目后期寸步难行。等你开始维护线上效果就会明白离线评测集和线上日志有多重要。这四个阶段不是学完再动手而是动手过程中反复迭代。我的建议是尽早把一个RAG跑起来后面所有概念都围绕它展开。2. 起步阶段环境与基础工具选型2.1 本地模型还是云API选型第一刀切在“本地还是API”。如果做原型验证必须优先云API。云API的好处是接入简单、效果稳定且不用处理显卡问题缺点是数据要出网对安全性要求高的场景要评估。本地模型比如Qwen、Llama适合私有化部署、数据合规、长线成本可控的场合但前期你要为GPU资源、推理框架、模型量化额外花时间。个人实践下来建议刚开始不要纠结“我要私有化”。先用API把流程搭建好理解系统瓶颈再决定有没有必要迁移到本地。我就是先用了云端模型调通所有代码后来才花两天时间把模型替换成本地的Qwen量化版。只要接口是OpenAI兼容格式切换成本其实很低。2.2 最小技术栈哪些省不掉我最终选定的最小组合很简单Python LangChain或LlamaIndex FAISS/Chroma FastAPI。Python没什么好说的生态最全。LangChain不是必选但它把文档加载、分割、链式调用、Agent这些常见轮子都封装好了能大幅减少起步代码量。向量库选FAISS或者Chroma一个轻量一个带服务先本地跑用FAISS就够了。FastAPI用来把整个流程包装成HTTP服务方便后面接前端或做回归测试。这套组合最大的好处是替换成本低。嵌入模型可以换LLM可以换向量库存硬盘可以换程序结构不需要大改。我见过有人一上来就铺Kubernetes、上Milvus、搞分布式追踪结果连一个稳定调用都还没跑通全在运维里挣扎。相信我先小后大够了再升级。2.3 工程纪律版本、实验与预算模型应用最大的坑是“改个prompt效果飘忽不定”。我今天调了一个版本明天忘了存的什么三天后线上出了问题回滚都不知道回哪。所以我从项目第一天就建立三条纪律。第一条代码进Gitprompt也进Git。把提示词模板作为独立文本文件管理改动要有diff禁止在代码里写死裸提示词。第二条每次实验记录完整的模型版本、温度、top_p、检索参数和评估结果哪怕简单到一个CSV文件也比靠脑子记强。第三条对API调用做token级成本统计。不做成本预算的AI项目最后基本都是账单爆炸收场。把这些基础设施做在前面后面调优才有据可查。3. 实操案例从零构建一个可用的RAG问答系统3.1 需求拆解与数据准备理论看再多不如动手做一个RAG。我选了一个最常见的场景公司内部产品知识库问答。需求很简单员工提问“退款周期是几天”系统根据知识库内容回答并附上来源。第一步是收集数据。真实场景里文档往往乱七八糟有PDF、Word、Markdown、网页导出的HTML。我的做法是先统一转成Markdown或纯文本再按章节清洗。清洗的意义很多人低估了页眉页脚、目录、无关广告链接都会干扰切块质量直接影响后续检索效果。接着是切块。切块策略直接影响召回。固定长度切块比如每500字符一块实现简单但容易把语义切断递归字符分割器会按段落和句子边界分层切效果更好。块之间保留少量重叠比如50字符避免关键句子被拦腰截断。经验是先看文档结构按语义完整单元切再控制块大小在模型上下文可容纳的范围内。3.2 嵌入模型与向量库检索的地基文档切好之后要把文本变成向量。嵌入模型把一段文字映射成一个高维向量语义相近的文本在向量空间里距离更近。这里注意嵌入模型和问答模型的供应商不需要完全一致可以混用。我常用的是OpenAI的text-embedding-3-small或本地的BGE-M3中英文都能cover。向量库做的事是存向量、算相似度、返回TopK。以FAISS为例它会构建索引查询时计算query向量和文档向量的余弦相似度返回最接近的若干条。这里有个细节TopK不是越大越好。K大了会塞进去不相关内容浪费token还干扰生成。我之前默认K4后来根据评测调到2到3回答准确率反而更稳。3.3 检索与生成串起来核心代码代码部分其实不复杂但它是整个体系能不能串联起来的分水岭。下面这段代码做了四件事加载并切块文档、把切块向量化建立检索库、查询时检索TopK、拼接上下文调用大模型。我没有用框架的高级Agent特性就是最小可跑通的闭环便于你一行行读懂。from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_community.vectorstores import FAISS from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_core.prompts import ChatPromptTemplate # 1. 加载并切块 loader TextLoader(docs/knowledge.md) doc loader.load() splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) chunks splitter.split_documents(doc) # 2. 建索引 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore FAISS.from_documents(chunks, embeddings) vectorstore.save_local(faiss_index) # 3. 查询时检索 vectorstore FAISS.load_local(faiss_index, embeddings, allow_dangerous_deserializationTrue) retriever vectorstore.as_retriever(search_kwargs{k: 3}) retrieved retriever.invoke(退款周期是几天) # 4. 生成 llm ChatOpenAI(modelgpt-4o-mini, temperature0) prompt ChatPromptTemplate.from_messages([ (system, 你是产品客服助手请只根据给定资料回答不要臆造。), (human, 资料\n{context}\n\n问题{question}) ]) chain prompt | llm resp chain.invoke({context: \n\n.join([d.page_content for d in retrieved]), question: 退款周期是几天}) print(resp.content)这段代码虽然简单却包含了很多工程要点。检索出来的context不能原样全塞最好拼接后控制总长度温度设为0是为了降低输出随机性但要注意即使设了0也不是完全确定后面测试部分会细说。另外FAISS的load_local在本地跑需要allow_dangerous_deserializationTrue原因官方文档说得很清楚你自己权衡。3.4 提示词工程与结构化输出RAG上线后最先遇到的问题是模型不按规矩来。比如问“退款周期是几天”它回答了一堆无关售后政策甚至说“我可以帮你查”。这时候需要prompt engineering出手。我的提示词模板包含四部分角色、约束、资料、输出格式。角色可以写“你是客服助手”约束必须明确“只能根据资料回答资料中没有的信息回答不知道”资料部分就是检索结果拼接输出格式必要时要求JSON方便程序解析。少样本也有用放一两个正确答案的例子模型会学得更快。结构化输出建议用ChatOpenAI的response_format{type: json_object}或Pydantic输出解析器让它老老实实生成JSON而不是你肉眼去解析。这一环节最容易犯的错是系统提示词里塞太多内容把上下文窗口撑爆。提示词要精简规则宁可少而执行到位也不要堆砌十条然后模型全忽略。我试过写五条要求效果反而不如三条清晰要求。4. 进阶玩法Agent与多步任务编排4.1 从RAG到Agent为什么需要多步执行RAG解决了“回答需要信息”的问题但真实业务很少是“查一下资料就能答”。比如客服要处理一个退款申请需要先查订单是否存在再查是否过了有效期必要时还要调用退款接口。这种多步骤、带条件判断的流程单纯RAG无能为力。Agent就是让模型能规划步骤、调用工具、观察结果再继续执行的一种系统形态。一个Agent循环说白了就是模型看到当前状态决定调用哪个工具工具返回结果模型根据结果决定下一步直到达到终止条件。这看起来很酷但它把传统程序的“确定性流程”变成了“模型动态决策”一旦失控影响面和排查难度都成倍上升。所以Agent工程的关键不是让它多聪明而是给它加多少约束。4.2 工具调用与循环控制把一个Agent接上真实工具第一步是把工具描述清楚。模型没有直接执行代码的能力它只能根据你的函数名、参数说明和用途描述决定“此刻该调用哪个工具”。工程师在这个环节最大的失误是把工具写得含糊名字笼统、描述不清模型就会瞎猜。下面这个OpenAI函数调用的例子定义了查询订单状态的工具。from openai import OpenAI client OpenAI() tools [ { type: function, function: { name: query_order, description: 根据订单号查询订单状态和退款进度, parameters: { type: object, properties: { order_id: {type: string, description: 订单号} }, required: [order_id] } } } ] resp client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: 帮我查一下订单A123的退款状态}], toolstools ) print(resp.choices[0].message.tool_calls)模型返回的tool_calls里是结构化的调用指令你需要自己在代码里分发执行再把结果作为新消息返回给模型。这里有个工程细节要规定最大循环次数避免模型在两个工具之间反复横跳。我给Agent设了max_iterations5超过就强制结束宁可让用户觉得“未知错误”也不能让它一直空转烧钱。还要给每个工具设置超时和异常捕获工具抛错不能让整个Agent崩溃。4.3 Multi-agent协作多AI如何不打架单个Agent处理不了复杂任务时就要拆成多个专门Agent。比如一个“旅行规划助手”Planner负责拆解“用户想去哪里玩几天”SearchAgent负责查景点和航班BudgetAgent负责算预算最后WriterAgent汇总行程。多个AI协作的本质是各司其职、消息互通而不是让一个Agent同时干所有事。工程上的难点在于状态同步。各Agent之间需要共享一份可读的上下文我通常用一个轻量的AgentState字典保存已获取的信息每个Agent执行后把结果写回去。还要注意不要把所有中间结果都堆给最后一个Agent摘要式传递往往更有效。多Agent架构听起来高级但先问自己单Agent加几条工具调用真的解决不了吗盲目上多Agent只会增加延迟和出错面。4.4 harness engineering给Agent套上缰绳提到harness engineering很多人觉得是个概念词其实翻译过来就四个字护栏工程。它说的是围绕大模型建立的一整套约束、校验、观测机制让模型的行为在可控范围内。所谓harness就是马具、缰绳。模型是引擎AI应用是车身harness是缰绳。具体做法有三块。第一工具权限最小化每个Agent只能访问自己任务需要的工具不能给一个“万能数据库查询工具”。第二输出校验模型生成的JSON必须经过schema校验字段缺失就重试或走兜底分支。第三可观测性记录每一步的工具调用、模型输入输出、耗时和token消耗关键节点打日志。没有这些Agent在测试环境表现良好一上生产就是个黑盒子。我这边的实操体会是harness engineering比提示词调优重要得多。提示词能让模型“更听话”护栏能让模型“不逾矩”。对于追求稳定性的业务场景我宁可少一点聪明多一点约束。5. 质量保障AI应用的测试、评估与监控5.1 为什么传统测试不够用传统软件测试的核心是断言输入X输出Y。但AI应用的输出是概率性的同一个问题换一种表述答案可能不一样期待精确匹配根本不现实。所以AI测试要从“是不是完全对”转向“是不是足够好”。我把评估分成三类检索质量、生成质量、端到端质量。检索质量看命中率、召回率比如预期的知识片段是否进了TopK。生成质量看忠实度有没有凭空捏造、相关性、格式合规。端到端质量则用一批标注好的问答对让大模型做裁判LLM-as-judge评分。这个方法我一开始也怀疑但实践下来只要裁判模型指令设计清楚和人工评分的相关性很高性价比远高于请一堆人去标。5.2 建立评估集和回归流水线质量保障不是上线后补而是从第一天就同步建评估集。评估集可以慢慢攒但必须有。我建议至少准备50到100条覆盖典型场景的问答对每一条带上规范答案、预期参照文档。初始不需要全部人工标用模型生成初稿再人工修正速度会快很多。有了评估集每改一次提示词、切块策略、模型版本都跑一遍离线回归输出一个分数对比表。我把这个流程接到CI里只要改了prompt或代码自动跑评测任务分数低于阈值就阻断合并。这套机制看着麻烦但能救命——尤其是多人协作时你永远不知道队友改了一行模型配置会把线上效果带偏多少。评估不准的AI项目后期基本靠瞎猜。5.3 线上监控与数据飞轮离线评估不能覆盖所有真实用户表达所以线上监控必须跟上。我常用的指标有几个95分位响应延迟、单次请求token数、检索无结果的占比、用户端给出的反馈按钮有用/无用。出现用户大量点“无用”时系统会自动把对话采样入库。这批坏案例是数据飞轮的燃料。每两周做一次badcase review把新案例加入评估集再针对性地优化提示词、调整检索策略或补充知识库。跑一段时间你会发现评估集越来越大系统效果越来越稳定。所谓的数据飞轮其实就是“线上问题→沉淀样本→回归优化→再上线”的闭环并不神秘。6. 常见问题与避坑实录6.1 问题排查速查表把我在项目里踩过的坑整理成一张表方便排查。这不是全部问题清单而是出现频率最高的六类每一类我都实际遭遇过不是纸上谈兵。现象常见原因解决思路回答内容看起来很合理但事实是编的检索没召回相关内容或提示词约束不够提高K值、优化切块提示词强调“没有资料就说不知道”上下文超限检索拼接内容过长或历史聊天记录堆积限制拼接长度历史做摘要或用滑动窗口同一问题两次回答结果不一致模型温度偏高或检索排序不稳定温度调低固定TopK必要时让向量库返回稳定排序延迟高模型规格太大或检索串行换小模型并行检索多个子查询缓存高频问题token成本飙升系统提示词过长、K值过大、无缓存精简提示词控制上下文对重复问题做缓存Agent死循环缺少最大迭代限制工具设计模糊加max_iterations规范工具描述增加超时中断这张表不是万能药但覆盖了我遇到的大部分问题。排查顺序有个经验先看检索结果对不对再看提示词有没有漏约束最后才怀疑模型能力。80%的AI工程质量问题出在前两层。6.2 容易被忽略的工程细节除了上面的问题还有三个细节值得单独提醒。第一个是非确定性。即使temperature0不同批次仍可能输出不同结果因为采样和GPU浮点计算都有微小随机性。所以测试时不要因为一次通过就认定稳定要跑多次取稳定结论或者用固定seed试几次观察波动范围。第二个是提示词版本管理。我吃过一次亏某天线上问答风格突变查了半天发现是有人在不显眼的地方改了一个提示词里的标点符号导致模型理解偏移。从那以后所有prompt都进Git每次变更都走diff review。第三个是token统计与配额。API提供方有每分钟请求限制生产环境必须做限流和重试。我不止一次在压测时被429打满后来统一在服务层加了带指数退避的重试才稳定下来。这个坑很小却十分致命。6.3 个人体会把ai-engineering-from-scratch整个流程走下来我现在最大的感受是AI工程和传统工程的区别不在技术栈而在“确定性的丧失”。传统工程是在一个确定系统上做加法AI工程是在一个概率系统上做约束。所以越是追求稳定的业务越要把重心放在检索、提示词约束、评估护栏这些“外围”工作上而不是一味追求更聪明的模型。如果你也打算从零开始搞AI项目我给的建议很简单挑一个真实的小需求用RAG跑通全链路再逐步加上Agent和评估。不要一上来就追新概念先把地基打牢。过程中踩的每一个坑最后都会变成别人翻不过去的护城河。