ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

从零构建AI工程:RAG、Agent与部署监控的完整实践路线

从零构建AI工程:RAG、Agent与部署监控的完整实践路线 1. 项目缘起为什么我要从零开始折腾 AI 工程我得先交代一下背景。做这个 ai-engineering-from-scratch 项目之前我其实已经在传统后端领域写了七八年代码Java、Go、Python 都摸过一轮。但真正让我下定决心从零系统梳理 AI 工程的是一次让我非常尴尬的线上事故我用 LangChain 搭了一个内部知识库问答机器人结果上线第一天它把一份过期的财务文档当成最新政策回答给了业务部门。当时我就意识到光会调 API、会用几个框架的皮毛根本算不上 AI 工程顶多算是个提示词搬运工。所以这个项目的核心目标很简单**把 AI 工程从能跑 demo推进到能扛生产。**它不是什么新鲜理论更不是某个框架的教程而是一条自底向上的学习路线——从最基础的 Python 工程能力到模型 API 的熟练运用再到 RAG 检索增强、Agent 自主决策、最后落地的部署与可观测性。整条链路走下来我踩过的坑、验证过的方案、否决掉的技术选型都会在这篇文章里如实交代。这篇文章适合谁如果你是刚转 AI 方向的开发者或者已经有了一些应用开发经验但总感觉在调包侠和AI 工程师之间隔着一层窗户纸那我这条路线对你应该很有参考价值。我会尽量说人话把每个方案背后的为什么讲清楚而不是丢给你一堆名词。老规矩先列个全景路线图后面每一部分我都会单独展开。2. 学习路线的全景设计别急着碰大模型很多人一上来就学 LangChain我觉得这是最大的误区。AI 工程这个领域工具链更新速度快到让人窒息你今天学的框架接口下个月可能就 deprecated 了。所以这个项目的第一原则是把根基打在一两年内不会变的东西上。2.1 三层能力金字塔基础、核心、应用我在设计路线时把 AI 工程能力拆成了三层每一层都有明确的学习目标和验收标准第一层是工程基础层。包括 Python 的类型系统、异步编程、装饰器、设计模式以及最基础的线性代数和概率论。这一层不过关后面读源码、调 bug 会非常痛苦。我的验收标准是能不看文档写出一个带类型标注、异常处理、日志记录的多线程爬虫框架。第二层是模型交互层。包括 OpenAI/Anthropic 等 API 的接入、Prompt 设计、函数调用Function Calling、结构化输出、流式传输处理。这一层解决的是如何让模型稳定地输出你要的东西是从能调用到调得好的分水岭。第三层是工程化应用层。包括 RAG 检索增强、向量数据库、Agent 工作流、效果评估、部署监控。这一层才是真正意义上的AI 工程——因为它涉及的已经不只是模型本身而是数据管道、系统架构、稳定性治理这些经典工程问题。2.2 为什么我把 RAG 放在 Agent 前面很多教程把 Agent 放在最高优先级渲染得特别玄乎。但在这个项目里我是先完整做了一个 RAG 系统才去碰 Agent。原因很简单Agent 的内部逻辑本质上就是一个检索-决策-执行的循环你不把 RAG 的问题摸透直接上 Agent 只会被各种不可控行为折磨。具体的路线顺序我是这么排的阶段核心内容验收指标1Python 工程化能力AI 基础能独立完成一个带测试的爬虫工具2模型 APIPrompt结构化输出能稳定输出 JSON 并对接业务系统3RAG切分、向量化、检索、重排问答准确率 85% 以上自建评测集4Agent规划、工具调用、记忆能完成多步骤任务如自动化调研5部署、评估、监控、成本优化系统稳定运行 30 天无重大事故这个顺序的核心理念是每个阶段都解决前一个阶段留下的痛点。比如你不做完 RAG就不会真正理解为什么上下文一长模型就开始胡编乱造不做完 Agent也不会明白为什么工具调用失败率这么高需要设计重试机制和人工确认。3. 筑基工程能力和 AI 基础到底要学到什么程度现在聊第一层。很多 AI 初学者犯的毛病是数学和代码基础还没扎实就急着跑模型。我见过太多人连 Python 的async都没搞明白就开始复制 LangChain 代码报错了只能 Google——这种学习方式效率极低。3.1 编程语言Python 之外的加分项Python 是 AI 工程的主语言这个没什么可争论的。但我想额外强调一下类型提示和异步编程的重要性。在写 AI 应用的时候类型提示能让你在写 Prompt 和解析模型输出时少犯很多低级错误。我实际项目里pydantic几乎成了标配——不光用来校验输入更多是用BaseModel定义模型输出结构然后让大模型按这个 schema 输出 JSON。这一招在工程化落地上极其关键后面会展开讲。异步编程同样重要。调用大模型 API 是典型的 I/O 密集型操作一次请求可能要等 2-8 秒。如果你同步调用10 个并发就要等 80 秒但如果用asyncio配合httpx.AsyncClient同样 10 个请求总耗时还是 8 秒左右。在我做内部知识库工具时这个优化直接把接口的吞吐量提升了 5 倍。实操建议就算你不用 FastAPI也建议了解它的依赖注入机制和 Pydantic 集成方式。FastAPI 的生态本身就是 AI 应用后端的最佳实践范本。3.2 数学与机器学习基础不啃课本按需取用大学课本里的线性代数学完你大概率就忘了。我更推荐按需学习遇到什么补什么向量与高维空间在学 RAG 的时候必然会遇到。你只需要理解一段文本被 Embedding 成几百维的向量语义相似的文本在空间中距离更近就够用。概率基础理解困惑度Perplexity、温度参数Temperature的影响就够。评估指标精确率、召回率、F1、RAG 的忠实度、答案相关性这些是评估系统效果时必须用的。我的经验是别在理论上追求深入优先建立直觉。比如温度参数你只要记住越低越确定越高越发散然后亲手跑几组实验远比你背十遍公式有用。3.3 核心工程工具Git、Docker、CI 的三板斧AI 工程的从零开始不能只是模型相关的从零。Git 分支管理、Docker 镜像构建、CI 自动化测试这些基础工程能力在 AI 项目落地时一个都躲不掉。我在项目里把这三样也纳入了第一阶段的学习清单Git要求掌握常规的工作流每天提交每次提交对应一个可运行状态。Docker要求能把 Python 应用打包成镜像并且能写 Dockerfile 做依赖缓存这一步对后期部署太关键了。CI要求用 GitHub Actions 跑单元测试和 lint哪怕只有一个测试文件也要把流程跑通。这三样当时看起来平平无奇但后面我拆 RAG 服务的依赖、迁移数据库、切换向量库版本的时候多亏了 Docker 隔离环境才没有把宿主机弄成一团浆糊。4. 模型应用从第一个 API 调用到稳定的结构化输出前面基础打完了就到了有趣的阶段。这部分的核心不是怎么调 API因为每个大模型厂商的 SDK 用法都差不多。真正的核心是如何让模型的输出变成你的工程系统里一个可靠的组件。4.1 接入模型 API别局限在单一厂商我的建议是第一阶段的实验统一用 OpenAI 兼容接口的格式它实际上是行业事实标准。不管你后面用哪个模型走 API 网关还是本地部署协议基本都是 OpenAI 风格。这样做的好处是抽象了一层迁移成本低。一个完整的接入要考虑三件事超时与重试模型服务是典型的慢接口网络抖动、服务端过载都很常见。必须设置合理的超时时间我一般用 30 秒并实现指数退避重试。流式与缓冲流式输出能提升用户体验但工程上要处理半截 JSON 的问题。我的做法是流式阶段只做展示层数据入库时仍然用一次完整的非流式请求避免解析残缺内容。成本控制Prompt 里塞的内容越多Token 消耗越大。我做过最长一次事故是忘了清理对话历史把几万字的上下文都发给了模型一次请求花了上百块人民币。注意实际项目中我强烈建议加一层模型网关统一管理 API Key、限流、日志和预算。就算开始只是简单封装一个函数也比到处裸调 SDK 强得多。4.2 Prompt 工程稳定性的第一道关卡Prompt 工程是个被过度玄学化的话题。我的实践结论是它本质上是接口契约设计不是文学创作。你写 Prompt 就像设计函数签名一样输入是什么、输出是什么、边界条件是什么都得清清楚楚。我常用的 Prompt 骨架分四段角色你是一个严谨的金融数据分析助手 任务根据提供的财报数据回答用户关于营收增长的问题 约束只使用以下数据来源不要猜测如果信息不足直接回答资料不足 输出格式JSON 对象包含 answer字符串、confidence0到1的数字、sources字符串数组这套模板帮我解决了很多问题。特别是输出格式这一节我后来用 JSON Schema 或 Pydantic 模型定义好了之后直接转成字符串塞进 Prompt模型的输出就再也不会出现乱七八糟的格式错误。4.3 函数调用让模型触达系统能力的钥匙当你的应用不只是聊天而要真正执行业务动作比如查数据库、发工单、调用第三方 API的时候就得用函数调用。函数调用的本质是你给模型提供几个函数的 JSON 描述模型根据对话内容决定要不要调用某个函数、参数是什么。你可以用开源的 Function Calling 框架也完全可以手写一个小调度器准备函数列表名称、描述、参数 schema带上对话记录请求模型如果返回结果里有tool_calls就执行对应的函数把执行结果作为新的消息发回给模型让它生成最终的回复我在早期实现的时候踩过一个很隐蔽的坑函数描述写得含糊模型就会乱传参。比如获取用户信息这个描述模型可能会传一个不存在的用户 ID。后来我把描述写成根据用户提供的姓名和工号精确查询工号不存在时返回 None参数校验的问题一下少了很多。5. RAG 实战让模型的回答长在你的数据上如果你只记住这篇文章的一个部分那就记这个部分。RAG检索增强生成是当前 AI 工程落地避不开的基础设施。它解决的问题非常朴素大模型再强也不知道你公司内部的数据。RAG 的答案不是靠模型猜的而是真的查到的。5.1 文档切分最容易被忽略的精度瓶颈在 RAG 链路里很多人把精力都花在调 Embedding 模型上结果检索效果还是差。最后发现问题出在文本切分上。切分粒度太粗一段文本里混杂了好几个主题向量化之后语义被稀释检索精度自然上不去。切分粒度太细句子的上下文被切断了iPhone 15和上一代产品对比这种跨句信息就丢失了。我实测下来的一个可靠 baseline 是用 400-600 个字符为一个 chunkchunk 间重叠 50 个字符优先按段落切、按句子兜底。这个参数看似随意但它是检索精度和上下文完整性之间的一个平衡点。切分完了不要急着灌库。先看几段切分结果问自己几个问题每个 chunk 是否聚焦一个主题有没有关键信息被拆到两个 chunk 里表格、代码块这类特殊格式有没有被破坏5.2 向量化与召回策略向量检索关键词兜底向量检索是 RAG 的主干负责找语义相近的内容但纯向量方案遇到专有名词、代码符号、缩写的时候常常翻车比如 CQRS 这种词语义相近不容易靠向量体现。我的做法是混合检索向量检索用开源的text-embedding-3-large或者开源的 bge-m3召回 top 20关键词检索用 BM25 做文本匹配召回 top 10合并两边结果去重后再用基于交叉编码器Cross Encoder的重排序模型把最终 top 5 作为上下文送给模型。这个方案比单纯向量检索效果强了不止一个档次。代价只是多维护一个倒排索引以及重排阶段多花几百毫秒。5.3 上下文构造把系统的可用上下文控制住RAG 到了最后一步是决定最终答案质量的关键一环。它也是你在工程上最容易失控的地方上下文越长回答越偏离token 越昂贵推理越慢。上下文构造要分优先级始终只发送检索到的相关段落而不是整份文档把与问题最相关的段落放在开头和结尾因为模型对这两部分的注意力往往更强为每个段落标注来源强制模型在回答里引用编号这样能显著减少幻觉。这里必须提一个我反复犯的错误为了不遗漏信息我把 top 20 个 chunk 全部塞进上下文。结果模型反而被不相关内容干扰答案质量直线下降。后来我只保留 top 5准确率反而提升了。实操心得RAG 的调优本质上是一场召回-干扰-成本三者间的平衡测试。你最好自己造一个 50 条的评测集包含分支问答、跨文档问答、陷阱问答三个类别每次改完参数跑一遍评测集用可量化的指标判断方案能不能上生产。6. Agent 开发从问答收发到自主执行做完 RAG你就理解了如何让模型读资料。下一步是让模型动手干活——这就是 Agent。Agent 不是一个神秘的自动编程机器人它是一套决策循环由模型负责想下一步做什么由工程代码负责做这个动作。6.1 最小可用的 AgentReAct 模式我在项目里实现的最简 Agent核心逻辑其实只有四步也就是 ReAct 模式思考Thought根据用户请求推理出下一步需要什么信息。行动Action选择一个工具比如搜索资料库、调用接口。观察Observation拿到工具执行结果。重复Repeat把结果加入上下文继续下一次思考直到推理出最终答案。这是一段非常容易实现的伪代码流程循环调用模型解析出Action和Action Input执行对应工具函数把结果追加进消息列表继续下一次请求。看起来很简单但循环上限必须设置我通常限制在 8 次以内否则模型会在某些任务上陷入死循环疯狂调用工具不给出结论。6.2 工具设计描述质量决定成败Agent 能调用什么样的工具取决于你能给模型提供什么样的函数描述。工具描述和 Prompt 一样本质是模型视角的接口文档。写工具 Description 的时候多用在什么场景下用这个工具、参数含义是什么、什么情况下返回空值这样的描述。举个例子一个查询菜价的工具差的描述是获取价格太含糊模型不知道什么时候该用好的描述是当用户询问某商品的市场价格时用该工具按日期和品类查询返回元组 (最低价, 最高价)。另外Agent 的工具执行结果一定要做错误信息的结构化返回。如果工具抛异常不要直接把堆栈丢给模型那样它只会胡说八道。我的做法是返回一个标准的错误对象{status: error, message: 品类不存在可用品类为: 蔬菜、水果}。6.3 记忆与多轮对话短期、长期、业务态Agent 系统的状态管理比一般后端系统复杂得多。至少要考虑三层记忆短期记忆最近 2-3 轮对话的原始内容用于保持连续话题。长期记忆用户画像、偏好、历史结论通常存 Redis 或向量库需要时才检索取回。业务状态当前任务执行到哪一步哪些动作已完成哪些待确认必须放在可持久化的存储里比如数据库中的任务状态表防止进程重启后任务丢失。我最开始做 Agent 的时候总想把所有上下文都塞进模型请求里结果 token 消耗直线上升而且模型经常被一堆陈旧信息干扰。后来改成按需检索记忆 短期窗口的方案成本和稳定性都好了很多。7. 工程化落地评估、部署、监控三板斧如果说前面几章讲的是怎么把功能做出来那这一章就是怎么把它安稳地跑起来。很多人止步于 demo 和原型就是因为在工程化这一步被劝退了。其实 AI 工程的工程化比传统后端更像持续调优的长期服务你不可能一上来就指望它很准确。7.1 评估体系没有评测集等于在盲改系统RAG 也好Agent 也好改一次 Prompt、调一次参数你都不知道到底是变好了还是变坏了那还怎么迭代所以我在项目里做了一个简单但能跑的评测集50 条问答对覆盖 5 大类业务问题每条问题标注了标准答案和来源文档 id用三类指标做自动评估忠实度回答中的事实是否都有检索到的参考内容支撑答案相关性是否准确回应了用户意图上下文相关性检索回来的内容与问题的相关比例。每跑一轮改动就把指标打一张报表。这个流程能帮你把感觉好像变好了的玄学变成清晰的数据。至于怎么自动评估忠实度我现在的做法是用一个大模型当裁判把问题和模型回答以及参考片段一起喂给评估模型让它按 1-5 分打分并给出理由。再用 BLEURT 或 RAGAS 做交叉验证。有条件的可以人工抽检 10% 的样本校准调用裁判模型的 prompt。7.2 部署从 Flask 到异步网关的演进我把 RAG 服务的部署演进分了三步第一步是单体 Flask 应用适合原型验证但并发能力很差因为 Flask 的同步模型扛不住模型 API 的长耗时请求。第二步是 FastAPI 异步接口 Gunicorn 多进程部署。把模型调用改成异步后单机并发量上涨明显500 QPS 以下其实不够稳定但中小型内部工具够用了。第三步是补上模型网关层统一管控限流与缓存。命中缓存的重复问题比如报销流程是什么响应时间从 3 秒降到 100 毫秒以内成本也直接砍半。一个容易被忽视的部署细节如果模型服务部署在外网必须留意连接的 keep-alive 和连接池复用。否则每次请求都要重新握手耗时轻松翻倍。用httpx时建议显式配置limitshttpx.Limits(max_keepalive_connections20)这类参数。7.3 可观测性日志、追踪、成本三位一体传统后端看日志、看监控AI 应用除了这些还必须能追踪模型是怎么一步步得出结论的。所以我实现了三层可观测请求日志记录每次对话的完整 Prompt、输出、耗时、token 用量。这是排查为什么它这么回答的第一手材料。链路追踪为 RAG 场景记录检索了哪些 chunk、重排后选择了哪些、最终拼接的上下文长度为 Agent 场景记录哪一步调了什么工具、输入输出是什么。成本报表按用户、按部门、按接口维度聚合的 token 消耗。AI 应用如果不盯成本月底账单一定让你怀疑人生。这是我踩过的最惨教训之一我们早期没有日志Agent 在线上乱调用了一次付费接口直到月末出账才发现一个月烧掉了够买一辆小汽车的费用。后来做了一套预算预警单日消耗超过阈值就自动熔断才把成本控制住。8. 常见问题与排查实录那些能让你少掉头发的坑这一部分完全来自实操我挑了三个出现频率最高、也是最难发现原因的问题来写。8.1 模型失忆多轮对话越绕越偏现象用户在对话里问了很多轮模型开始答非所问甚至把更早的话题当成当前的问题。排查过程先看请求日志发现我们确实把完整的历史消息都传给了模型。但问题是场景太长已经有几十轮对话早期的信息与当前问题的关联被稀释了。而且每次检索摘要的过程本身会进一步引入噪声。解决方案给多轮对话加一个滑动窗口 摘要策略——最近的 6 轮完整保留更早的对话由模型总结成摘要作为系统消息放在最前面。同时每次问答完成后把最终答案单独存档为记忆点下一轮优先参考记忆点而不是原始历史。8.2 检索返回空为什么明明该有的资料却搜不到现象某个问题的答案明明在知识库里但 RAG 系统回复资料不足。排查过程一步步拆链路。先用同一个问题去查向量库和 BM25发现向量检索确实召回了相关 chunk但在重排阶段被排到很后面最终被 top 5 截断了。原来是这段文档的描述和用户问法用了完全不同的表达用户问产品质保多久文档写的是自签收之日起一年内提供免费维修服务向量相似度够但交叉编码器的排序偏好把更短的匹配排到了前面。解决方案重排之后额外加一个关键短语匹配规则对包含质保、保修、售后、免费、期限这类强信号短语的 chunk 做加权。同时把每个 query 扩展出同义词变体比如质保-保修后再去检索。8.3 Agent 死循环模型一直在调用同一个失败工具现象Agent 在一个任务上不断重复调用某个工具每次都报错但模型不吸取教训继续用同样的参数重试。排查过程观察 Agent 循环日志后发现工具方的错误信息里有参数格式错误 xxx但模型每次构造的参数还是错的。原因出在工具描述里给出了一个误导性的示例模型一直在照抄示例里的格式。解决方案修改工具描述把正确示例和错误示例都写清楚明示不要使用旧版参数格式新版参数格式如下。另外在工程层面加了一个重试熔断同一个工具连续失败 3 次就从 Agent 的可用工具列表里暂时移除强制模型换思路。9. 关于这个项目我最后想分享的几点体会再次强调这套学习路线不是标准答案更不是唯一路径。它只是我自己在 ai-engineering-from-scratch 这个项目里走通的方案经过多次推翻重来后沉淀下来的经验。如果你真的打算从零开始我给的建议是不要一上来就追求生产级完美先做通一个最小的端到端场景。哪怕只是一个读 PDF 回答问题的小工具也会逼你把 API 接入、切分、向量化、检索、上下文拼接、模型调用、结果输出全部走一遍。这条路走通了后面再谈优化和工程化才有意义。我自己的下一步计划是把这套体系扩展成一套轻量级的 AI 工程训练营让更多人可以通过实际项目而不是单纯看文档建立起对 AI 工程的整体直觉。这个领域变化很快但工程方法的内核——数据质量、系统设计、稳定可观测永远会留在那里。
返回列表