ARTICLE DETAIL

资讯详情

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

AI工程从零开始:RAG、Agent与评估体系的落地实战

AI工程从零开始:RAG、Agent与评估体系的落地实战 做AI工程化这一年多我最大的感触是从零做一个AI系统不难真正难的是把它“工程化”。所谓from scratch不是让你手写Transformer而是在大模型能力之上搭一套属于自己的、可维护、可评估、可观测的AI应用体系——从提示词管理、RAG链路、Agent编排到测试夹具、回归集、成本监控全都得有。这篇内容就围绕“AI工程从零开始ai-engineering-from-scratch”这条主线把我实际趟过的路径、踩过的坑、验证过的方案完整梳理一遍。适合正在从后端转AI应用开发的人、刚立项要带AI项目的技术负责人以及被MCP和多Agent协作搞得一头雾水的开发同学。不管你现在用哪家大模型这套方法论基本都能直接套用。1. 先想明白AI工程从零开始到底在工程什么1.1 AI工程不是“调API”而是三条流水线很多人一上来就问选哪个模型我真觉得这是最不该先问的问题。AI工程落到业务里从来不是某个模型单点能力的问题而是三套流水线能不能转起来的问题。第一是数据流水线包括文档采集、清洗、分块、向量化、入库、增量更新。第二是模型流水线包括模型选型、部署、路由、提示词管理、调用链路的稳定性治理。第三是评估流水线包括测试集建设、指标计算、回归检测、线上表现监控。传统后端开发习惯把这三块拆成若干独立系统但AI应用不行它们是一个闭环数据变了检索效果就变提示词变了回答质量就变模型换了一切都要重新验证。我做第一个RAG项目时把80%精力花在调提示词上结果换了一个embedding模型后线上回答质量明显下降提示词怎么调都救不回来。后来才意识到问题出在数据侧——文档分块粒度跟新模型的语义空间不匹配。那次教训让我彻底改变了做AI工程的顺序先定评估再定数据最后才谈模型和提示词。1.2 和传统软件工程的三个关键差异如果你带过纯后端团队会发现AI工程在很多地方是反直觉的。最核心的三个差异我建议团队每个人都要记熟。不确定性。传统代码是确定性逻辑同样的输入必然有同样的输出大模型是概率分布同样的提示词每次输出都可能不同。所以测试目标要从“对不对”变成“稳不稳”需要通过约束输出结构、限定答案范围、增加校验层来压缩不确定性。我常用的思路是让模型按JSON schema输出再用Pydantic做运行时校验不合格就重试一次而不是放任模型自由发挥。成本结构。传统应用边际成本趋近于零AI应用每次调用都是钱token就是真金白银。这意味着要在代码里做预算管理、缓存、模型路由长对话要做摘要压缩检索要控制送入上下文的块数。这些在设计阶段就要想清楚。可观测性。以前看日志、看RPS就够了现在还要看提示词版本、上下文窗口占用、token消耗、置信度、用户反馈信号。没有一套LLMOps工具链线上出了问题你连“当时模型看到了什么”都不知道排查会非常痛苦。1.3 从零起步的能力图谱如果现在让我带一个团队从零做AI工程我会先把能力图谱贴在墙上让每个人知道自己负责的是哪一块。能力域要解决的问题核心产出Prompt工程输出稳定性、指令跟随、低成本复用模板仓库、版本管理、评测集RAG检索增强知识更新、引用溯源、降低幻觉向量库、切块策略、召回与重排链路Agent编排多步骤任务自动执行工具注册、循环控制、人工审批HITL评估体系可回归、可验收、可灰度黄金数据集、指标计算、CI闸门可观测性线上问题定位、成本核算、反馈闭环链路追踪、token计量、看板这张表里的每一项在下面的章节我都会展开。这里只提一个原则不要试图一口气全做。最稳的路径是选一个窄场景比如“售后知识库问答助手”把五条流水线都跑通再横向扩展到其他场景。我见过太多团队一上来就做超级Agent结果连最简单的检索质量都没保障最后沦为大家都不愿意用的玩具。2. 核心细节实操要点Prompt、RAG、Agent逐个击破2.1 Prompt工程化落地模板、版本和上下文预算Prompt不是一个魔法咒语它就是一段不断演进的代码。我的团队把Prompt按Jinja2模板管理system、few-shot示例、工具定义分开存放每个模板带版本号发布前必须过评估集。这点看起来笨但能帮你少掉很多头发——我吃过亏线上偷偷改了Prompt没记录一周后回答风格突变评估集里的分数却显示一切正常因为评估脚本用的是旧模板。一个基本的模板长这样{% set sys_template 你是{{ product_name }}的智能客服。只根据【知识库】内容回答不要编造。若知识库无答案请直接说抱歉我还没有学会回答这个问题。回答不超过{{ max_tokens }}字。 %} 你叫{{ user_name }}请问{{ question }}上下文窗口是有限资源我习惯在代码里做“上下文预算”而不是拍脑袋决定传多少块文档。以32K上下文模型为例你可以这么算context_limit 32768 tokens system tools 2200 tokens # 常驻系统提示词和工具定义 history 2400 tokens # 最近5轮对话超出则摘要压缩 output_reserve 1024 tokens # 给模型生成留够冗余 budget_docs 32768 - 2200 - 2400 - 1024 27144 tokens # 单个chunk约800 tokens最多可以塞34块 # 但为了延迟和注意力质量实际检索TopK建议控制在5~8块这套计算逻辑比“凭感觉调retriever”靠谱得多。另外关于生成参数给你一份我常用的参考表参数取值范围适用场景备注temperature0.1~0.3代码生成、分类、结构化抽取越低越稳定temperature0.5~0.8文案改写、头脑风暴太高容易废话连篇top_p0.1~0.9核采样阈值一般不与temperature同时大幅调整max_tokens按需保护上下文不被撑爆宁可截断不要失控调参的经验法则先固定temperature为0.2把Promot和检索调好最后再微调生成参数。一上来就玩随机性你会分不清效果波动是来自Prompt还是来自采样。2.2 RAG链路切块、召回、重排的坑与参数计算RAG说简单也简单说深也深。很多人直接pip install一个向量库就开干结果线上召回率惨不忍睹问题多半出在切块和重排上。切块我按“先语义、再长度”的策略优先按Markdown标题、段落边界切块过大就再切一刀单块控制在200~500个汉字相邻块重叠80~120字避免语义断层。块太大检索出来的文档包含大量无关内容模型容易被带偏块太小语义不完整embedding质量也会下降。召回阶段embedding模型建议用bge-m3或text-embedding-3-small这类常见中文场景验证过的模型。向量库我推荐先上PostgreSQLpgvector原因很朴素从零起步时不想多维护一套中间件而且pgvector 0.5之后性能对百万级向量够用了。召回量级上我习惯先取Top20候选再用bge-reranker重排到Top5。不带重排的RAG只能叫向量搜索这句话是我花两星期踩坑换来的纯向量召回的前5条往往有2条以上在语义上是重复或偏离主问题的重排能把这些噪声压下去。还有一个隐藏瓶颈是query理解。多轮对话里用户说“那这个怎么退”——你直接拿这句话去检索库里根本找不到对应内容。正确做法是先做指代消解和改写把这句话改成“上一轮提到的商品如何申请退货”再去检索。这一步可以用轻量模型来做成本很低但效果提升立竿见影。2.3 模型选型、路由与Token预算模型不是越强越好而是越适合越好。我习惯把模型分层让不同难度的请求走不同的模型这就是模型路由。模型类型适用场景典型成本系数旗舰大模型复杂推理、代码生成、罕见问题10x轻量模型FAQ、分类、改写、结构化抽取0.2x专用小模型重排、意图判断0.05x路由判断不需要太花哨一个最简实现就是把历史请求按难度打标然后做规则分类命中FAQ关键词、问题模板明确的走轻量模型包含“为什么”“对比”“帮我设计”这类开放词的走旗舰。有个很直观的账可以算一下假设日请求30万次其中60%是简单问题如果不做任何路由全部走旗舰模型单次输入2000 token、输出300 token、按演示价格0.02元/千token输入、0.08元/千token输出算单次成本是0.064元一天1.92万元加了路由后简单问题走轻量模型价格约为旗舰的十分之一日成本降到不到9000元一个月省出的小三十万够养一整个AI团队了。价格会随市场波动但这个账的思路不会变。Token预算管理也是同样的逻辑。我每次调用前都会打印“本次请求预估消耗是多少 token其中历史占多少、检索块占多少”一旦发现history膨胀就启动分段压缩前面对话抽summary继续保留最近的原始消息完整保留。有朋友问我为什么他的长对话越聊越贵多半就是history无上限累加造成的。2.4 Agent编排从单轮到多轮的工程约束聊完纯问答进入现在最热的Agent。Agent的本质就四样大模型做大脑、工具当手脚、记忆存状态、循环控制保证不跑飞。真正难的不是让它跑起来是让它停下来、可追踪、不产生不可逆副作用。我在Agent里加入了HITL人在回路业务上所有写操作比如发邮件、改数据库、下单都必须经过人工确认。技术上给每个Agent定义YAML配置把工具、循环上限、超时都事先声明agent: name: code_review_agent model: qwen-plus tools: - fetch_repo - run_linter - diff_parser max_iters: 5 hitl: on_failure: true on_write: true timeout_ms: 15000循环上限是防跑飞的最重要防线。之前测过一个自动修Bug的Agent它修完一个Bug后又引入两个新Bug然后继续修整整跑了47轮才被我们停掉。从那以后我规定默认max_iters5每个工具调用必须有明确的成功/失败信号失败就停止而不是重试到底。这就是热词里讲的loop engineering循环工程它关注的不是怎么让Agent多绕几圈而是如何让每一圈都有意义、有边界、能收敛。多Agent协作上我踩过的坑是角色边界模糊。两个Agent共享同一份状态文件A写入、B覆盖最后完全乱掉。后来改成“一个任务一个Leader Agentn个Worker Agent”状态变更通过事件通知而不是共享可变全局量。如果你刚接触Agent建议先从单Agent多个工具开始等工具调用稳定了再上多Agent。另外MCP这层协议确实让工具接入标准化了不少但也不要迷信底层控制逻辑仍然要自己写好。3. 从零搭起一套可评估的AI工程基线完整实操过程3.1 项目骨架与最小闭环说一千道一万不如直接把一套能跑的基线摆出来。我的项目结构一般长这样ai-engineering-from-scratch/ ├── app/ │ ├── core/ # 配置、提示词模板仓库 │ ├── services/ # RAG、Agent、重排等核心服务 │ ├── api/ # FastAPI 路由 │ └── metrics/ # 自定义观测打点 ├── tests/ │ ├── golden_set/ # 黄金回归数据集 │ └── harness/ # 测试夹具与评估器 ├── deploy/ # 部署编排 └── pyproject.toml用FastAPI做API层是个人偏好社区生态成熟、异步支持好数据库上先用PostgreSQLpgvector数据量到了千万级再换专用向量库embedding服务用bge-m3模型调用先锁一个供应商的接口后续通过适配层替换。最小闭环的意思是能完成“传问题-检索-拼Prompt-调大模型-返回答案-记录trace”这一整条链路中间任何一环都不要用未经验证的花哨组件。3.2 用60行代码实现一个带评估的RAG服务下面这个简化版代码已经能说明问题主要展示链路骨架生产环境请加鉴权、限流、链路追踪和错误重试。# app/services/rag.py from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class AskRequest(BaseModel): question: str history: list[str] [] class AskResponse(BaseModel): answer: str sources: list[str] def recall(question: str, top_k: int 5) - list[dict]: # 1. 对question做embedding # 2. 在pgvector里做余弦相似度检索 # 3. 返回 [{doc_id, chunk_text, score}, ...] # 简化示意实际代码在src/services/recall.py ... def call_llm(system: str, user: str) - str: # 统一封装模型调用记录token用量和延迟 ... def build_user_prompt(question: str, chunks: list[dict]) - str: docs \n\n---\n\n.join( f[文档{d[doc_id]}]: {d[chunk_text]} for d in chunks ) return f【知识库内容】\n{docs}\n\n【问题】{question} app.post(/ask, response_modelAskResponse) def ask(req: AskRequest): chunks recall(req.question, top_k5) system_prompt load_prompt(default_system) user_prompt build_user_prompt(req.question, chunks) answer call_llm(system_prompt, user_prompt) return AskResponse( answeranswer, sources[c[doc_id] for c in chunks], )配套的评估脚本才是整套体系的关键它决定了你改Prompt、换模型之后有没有底气上线# tests/test_rag_accuracy.py import pytest from app.services.evaluators import semantic_similarity, faithfulness pytest.mark.rag def test_golden_set_accuracy(): golden load_golden_set(tests/golden_set/v3.jsonl) failures [] for case in golden: resp client.post(/ask, json{question: case[question]}) score semantic_similarity(resp[answer], case[golden_answer]) if score 0.75: failures.append((case[question], score)) assert not failures, f未达标的用例: {failures}这里的语义相似度不一定要用复杂模型bge重排模型顺手就能当相似度计算器用。阈值0.75是我个人经验值具体看业务对准确率容忍度调低容易放过问题调高容易误伤迭代。3.3 harness engineering落地把Capability装进测试夹具“harness engineering”这个词说白了就是给AI能力套一个可测试、可约束的“夹具”。打个比方给气球充气时你先套一个网兜就算充爆了也是可控地炸不会伤到人。我在团队里要求所有新增能力必须同步提供harness——能力是充气的气球夹具是那个网兜。落地的第一步是建黄金问题集。不用贪多从线上日志抽几百条真实query人工写好参考答案覆盖常见问题、边界问题、无答案问题三类。第二步是定义质量指标我常用三件套指标计算方式我的及格线忠实度检查回答是否超出知识库内容范围90%以上覆盖率参考回答中的关键信息是否都出现85%以上无关性检索出的chunk与问题是否主题一致95%以上第三步是把harness接入CI。每次合并代码前自动跑一遍黄金集任一指标下降超过3个百分点就阻断合并。这一步的意义在于让AI工程“可回归”——以后不管谁偷偷改Prompt、换模型、调切块参数只要跑一次测试就知道有没有退步。现在有些AI编程工具已经把这套思想做到了开发环境里比如CodeBuddy在生成代码时也会同步搭测试夹具让我这类强迫症选手省了不少事。关于自身开发中使用这类工具后面第5部分再展开。3.4 数据标注与回归集建设回归集是AI工程的地基地基不稳上面全是危楼。我见过团队准备了上万条测试数据但90%都是模板化的重复问题导致评估分数很好看线上体验却很差。我的经验是少量但有效200条高质量用例就够撑起一个初版基线关键要把这三类录进去高频真实用户问题、历史上导致回答翻车的失败case、故意来挑刺的恶意/边界问题。标注环节别偷懒每条case要带上原始上下文和“为什么这么答”这样后续别人接手才能看懂。新case的来源主要靠用户反馈闭环——线上加一个“这个回答有用吗”按钮觉得没用的记录自动进未标注池子定期抽人补标。数据版本也要管理起来golden_set目录下的每个版本都不能删除否则旧模型回归对比就没参考了。3.5 上线后的灰度策略与指标监控上线不是终点是另一个起点。我用的灰度策略简称为“影子模式”新模型或新提示词先跑在影子环境里把线上真实流量复制一份进去让新旧两个答案同时生成只把旧答案返回给用户后台人工抽样对比。等影子模式下评测指标稳定超过旧版再放量5%、10%、50%、100%。监控指标上除了传统的延迟、成功率、token消耗一定要看“对话轮次终止方式”用户主动结束、得到答案后结束、还是因为不耐烦流失。这个信号最能反映AI产品到底有没有解决问题。可观测性工具可以用Langfuse这类开源方案便宜且社区活跃没有预算也可以自建打点系统把每次请求的prompt版本、检索chunk、token数、模型输出全部落库。4. 上线后常见问题与排查技巧实录4.1 高频问题速查表真实上线后你遇到的坑95%都逃不出下面这张表现象可能原因排查路径解决套路回答胡编乱造检索没召回内容模型在裸答看trace中检索chunk列表是否为空增加“无答案拒答”约束降temperature检索质量差切块粒度与问题语义不匹配打印TopK召回的相似度分数分布调整切块大小、增加重排层Agent死循环工具副作用让状态无法收敛看循环计数与工具执行记录设max_iters、加状态快照、人工中断上下文Token爆掉history无限增长看输入token曲线旧消息摘要压缩只留最近N轮原文延迟高检索慢、重排慢、调用太重分步打点每一环节耗时缓存高频问题、缩减召回数量、升级基础设施每一条我都真实遇到过。最典型的要数检索为空导致的裸答问题——模型接不到知识库内容时并不会乖乖认错而是会用训练时的知识硬编一个答案看起来还挺像回事。这种幻觉是RAG类应用的头号风险排查时要盯着检索环节而不是急着调Prompt。4.2 实测中反复踩过的几个坑第一个坑是提示词“热更”后忘了同步评估集。有次同事直接改了线上Prompt效果看着不错但黄金集的语义相似度阈值已经旧版本早就绑定了测试一直通过直到客服反馈话术风格突然变了才追到是Prompt版本没跟评估版本绑定。现在系统里统一靠版本号对齐代码层使用哪个Prompt版本评估集就使用哪个。第二个坑是知识库越加越杂回答质量反而下降。我做知识库时候总有一种囤积癖看到什么都想塞进去结果检索出来的内容一半跟问题无关。后来砍掉一半低质量文档单问答案质量明显提升。信息太多时高质量的信息才会浮出水面这个教训在AI场景比在数据库里更放大了。第三个坑是对测试用例不加区分。有些easy case永远能过真正需要靠它拦住回归的困难问题反而被淹没。现在我在黄金集里给每个case打标签easy/hard/edgepytest配置里hard类必须单独过一遍且hard类指标权重更高。4.3 长上下文与幻觉的取舍还有一个很常见的思维误区既然模型窗口越来越大干脆把知识库文档全塞进一次调用里RAG都不用做了。我跟你说实际效果往往不行。窗口越大模型对中后部信息的注意力越容易衰减而且长上下文会显著增加延迟和成本。即使窗口有128K我也坚持限定每次送入的文档块数。宁可多一轮检索、多一次重排也不要把整篇几十万字直接甩给模型。另外长对话要定期做语义断点历史超过一定轮次先把前面压缩成摘要只保留用户最近的完整意图。这里的核心原则是“为模型减负”而不是“给模型堆料”。5. 工具链选型与一个让AI参与自身构建的飞轮5.1 框架、平台和观测工具的取舍工具圈更新太快我的原则是只选长期维护、社区活跃、能被公司DT数据技术体系接纳的组件。框架上LangChain适合快速验证原型LlamaIndex在RAG场景更顺手Dify这类平台适合非深度定制团队快速搭应用。但从零做AI工程、尤其是要长期维护的项目我更推荐“轻框架自研业务层”框架管编排、协议、集成你自己的代码管Prompt版本、评估逻辑、业务规则。层面我的推荐替代选项选型理由Web框架FastAPIFlask、Spring异步支持好类型提示友好向量库pgvectorQdrant、Milvus起步简单一套PostgreSQL顺带搞定编排框架自研 必要库LangChain、MCP可控性优先框架只做胶水层可观测Langfuse自建打点开源自带trace和评估能力测试pytest 自研评估器自定义CI脚本生态稳定黄金集直接变成测试用例不推荐一开始上太重的东西。我见过团队把K8s、监控大屏、复杂评估平台全搭好结果业务还没跑起来就被基础设施拖垮了。先把最朴素的组件跑通等用户量和问题复杂度上来了再逐步升级。5.2 让AI参与自己的构建最后讲一点我个人觉得很有后劲的实践当你把AI工程基线搭好后完全可以开一个让AI辅助自身构建的飞轮。我现在让开发团队的每个人把CodeBuddy这类AI编程工具当成结对伙伴生成代码时要求它同步补单测和测试夹具我们则在code review时检查AI生成的用例质量。这套流程跑起来之后黄金集和初版测试代码的产出速度明显加快团队对自动生成代码的信任度也在提高。要注意的是不要让AI直接改生产规则所有它生成的东西都必须走人审和回归闸门。这其实就是前面讲的harness engineering思想在开发流程上的延伸给AI装个网兜然后放心让它干活。从我个人经验看从零开始做AI工程最值钱的能力不是会调几行参数而是建立“任何改动都可度量、可回归、可回滚”的工程化心智。第一个版本用点心把评估、trace和成本这三根桩打下去后面不管是换模型、扩场景还是上Agent都会从容很多。所以如果你正准备启动AI项目别急着写业务代码先把黄金集和几条trace定义出来这会是你整个项目里最值得的一笔投资。
返回列表