AI工程从零实践:搭好提示词、RAG与评估体系的完整链路
1. 为什么“调API”不等于AI工程先清醒认识这件事这几年 AI 应用层的热度一直没降过身边不少做后端、做前端的同事也纷纷转过来写 AI 相关项目。但我发现一个很普遍的现象很多人以为会用 Python 调一次模型接口能跑通一个聊天 Demo就算入门了 AI 工程。等真把一个功能放到线上面对用户的各种输入、各种网络状况、各种边界 case才发现问题远不止“模型回答得对不对”这一件事。我自己也是踩了一整圈的坑才慢慢摸到门道。从零开始做 AI 工程核心难点不是“模型能力不够”而是“围绕模型的工作流没有工程化”。换句话说模型只是引擎真正决定项目能不能稳定跑起来的是引擎外围的数据处理、调用编排、结果校验、异常兜底、评估反馈这一整套系统。举一个最直白的例子同一套提示词模型在测试环境输出质量很稳定一旦换到生产环境同样的输入可能会因为请求并发、上下文长度、模型版本浮动而给出完全不同的结果。这中间如果没有可观测的手段和兜底的策略出了问题你连定位都无从下手。所以这篇内容我更想把它当作一份“从零起步的实操总结”来写而不是一份“手把手配置教程”。我会按自己从零搭一个 AI 应用时的真实推进顺序把环境准备、提示词工程化、RAG 链路、模型选型、评估体系和部署迭代这几块分别讲透。适合刚开始接触 AI 应用开发、准备把项目从 Demo 推向实际可用状态的读者也适合那些已经调通了接口但总觉得“哪里不对”的开发者对照参考。2. 从零开始的环境搭建一次把底子打好2.1 项目脚手架与依赖管理AI 项目的工程环境和传统 Web 项目有一个明显差异依赖的生态更新极快且模型 SDK、向量库、数据处理库之间经常有版本兼容问题。我第一次搭环境时偷懒直接用系统全局 Python结果装了一堆依赖后不同项目之间互相打架升级一个库直接牵连另一个项目跑不起来。建议从一开始就按独立项目环境来管理使用uv或conda创建隔离的 Python 环境固定 Python 小版本不要用“最新版”这种模糊概念。用pyproject.toml或requirements.txt把依赖版本全部锁定包括传递依赖。把模型 SDK、向量数据库客户端、文档解析库分成三组分别管理每组升级时单独评估影响面。关于pyproject.toml管理 AI 项目依赖我的习惯是在[project.optional-dependencies]里区分核心运行依赖和开发测试依赖。这样可以避免把pytest、ruff这些开发工具误装到生产环境中也让镜像构建时依赖层更小。依赖安装流程并不复杂但这一步值得认真做因为 AI 项目后期迭代频繁环境是否稳定直接决定了定位问题的速度。2.2 模型接入的初始化设计把“可替换性”留出来AI 项目里最容易踩的架构上的坑就是把模型调用写死在业务代码的各个角落。今天用某个大模型 API明天想换一个开源模型或者想从在线 API 切到私有化部署几乎需要重构整个项目。我现在的做法是模型接入层一开始就统一抽象成一个小小的接口里面只暴露几个方法chat(messages, toolsNone, **kwargs)普通对话补全。embed(texts)文本向量化。rerank(query, documents)重排可选。底层具体用哪家模型由配置中心或环境变量决定。业务层代码完全不需要关心模型是哪里来的只需要面向这个接口编程。这样做的成本很低但换来的灵活性却非常重要——模型评测阶段我经常需要在多个模型之间横向对比有这个抽象层之后切换模型只需要改配置代码一行都不用动。当然也要提醒一点抽象层不要设计得太厚。有些人一开始就想着“要能兼容所有主流大模型平台”结果抽象层本身变成一个大工程反而耽误了业务验证。先做到“换模型不换业务代码”就够了等真正有需要再扩展具体能力。3. 提示词工程的工程化从“写得巧”到“管得住”3.1 提示词也要版本管理我见过很多团队提示词直接写在代码字符串里改一次就在代码里搜索替换一次完全没有版本管理。这在一个快速迭代的 AI 项目里是一件非常危险的事情——你可能根本不知道当前线上跑的提示词是哪一版也就无法复盘“为什么这个回答质量下降了”。更合理的做法是把提示词当作一种“可配置的资源”来管理。我常用的方式是把提示词模板独立成文件按业务模块建目录prompts/ customer_service/ v1_base.txt v1_refined.txt v2_humanized.txt config.json content_summary/ summary_v1.txt每个提示词文件里预留变量占位符运行时由代码填充上下文。config.json则记录当前环境的激活版本。这样做有几个直接的好处提示词的改动可以走代码评审流程可以随时回滚A/B 测试时只需要切换配置版本新模型上线时也可以针对同一套业务提示词做批量评估。还有一个小细节可能很多新手意识不到提示词里的措辞对模型输出格式的影响非常敏感。同一个要求“请用 JSON 输出”不同写法放在开头、放在末尾、加不加“只输出 JSON”这五个字会导致格式稳定性差异很大。所以每次修改提示词都要配套做回归验证不要凭感觉认为“改动不大就没事”。3.2 结构化输出与容错解析模型输出天然是自然语言但工程系统需要的是结构化数据。如何把模型的自然语言输出稳定地转换为可解析的 JSON 或代码是 AI 工程里一个非常具体、非常常见的难题。我第一次做这个转换时直接把模型的输出丢给json.loads()然后在本地测试时一切正常上线后各种报错——模型偶尔会输出 Markdown 代码块包装的 JSON、偶尔会多一个逗号、偶尔在 JSON 后面附带一段解释性文字。任何一个看似微小的偏差在严格的 JSON 解析器面前都会直接崩溃。我的处理思路是这样的提示词层面尽量约束输出格式要求“只输出 JSON”并且给出示例模板。代码层面采用分层解析第一层用正则去掉 Markdown 代码块标记第二层用容错 JSON 解析库比如json_repair或dirtyjson尝试解析最后一层如果依然失败就走重试逻辑把解析错误信息反馈给模型让它重新输出。同时在解析结果上再做一层 schema 校验确保必填字段都存在、类型正确。这一步可以用pydantic轻松实现。这一套下来线上 JSON 解析失败率可以降低到很低。核心启发是把模型当作一个“偶尔不听话的组件”系统设计时必须假设它有概率输出任何格式所以校验和兜底是工程的一部分而不是多余的防御性代码。4. RAG 实战链路让模型学会“查资料”4.1 文档准备与切块策略RAG检索增强生成几乎是目前 AI 工程里写得最多的落地范式核心思路是“不直接让模型凭记忆回答而是先从一个外部知识库里检索出相关内容再交给模型生成答案”。这样能显著减少一本正经地胡说八道也能让回答覆盖到模型训练时没见过的私有资料。但 RAG 的前置环节——知识库建设——是最容易被低估的。拿 PDF、Word、网页抓取等不同来源的文档来说格式解析本身就充满了坑PDF 看起来有文字层提取出来顺序却经常是乱的表格内容被拆散页眉页脚混进正文。这些噪音会直接污染后续的向量检索质量。切片策略同样重要。切得太短每段内容独立但缺乏上下文检索时容易断章取义。切得太长向量表示被稀释且容易引入不相关信息影响回答准确度。我实践下来比较稳定的思路是先按文档自然结构标题级别分块尽量保持一个语义单元完整。每个块控制在 400 到 800 个 token 之间并设置相邻块之间 5% 左右的重叠避免关键信息被截断。对结构化较强的表格数据不要硬塞进文本块建议单独走“表格问答”或“列转文本摘要”的变体方案。切块后做一轮清洗去除重复块、识别并剥离页眉页脚、统一空白和换行符号。4.2 向量检索与重排的取舍检索阶段最基础的方案是纯向量相似度召回即把用户问题向量化在向量数据库里做最近邻搜索。这种方式对语义相近的表达往往能召回不少相关内容比如用户问“报销流程”文档里写“费用报销的操作步骤”也能匹配上。但纯向量检索也有明显短板对关键词精确匹配不敏感、对问题的细粒度意图判断偏弱。比如用户问“发票丢失怎么处理”如果知识库里有多个板块都提到发票向量召回可能会把“发票开具”“发票验真”“发票丢失”的片段各拿一块排序却未必合理。这时候就需要一个“重排”环节把向量召回的前 50 条候选交给一个更精细的重排模型reranker重新打分取前 5 条真正相关的片段送给大模型。如果说向量检索是“快速海选”重排就是“精准终选”。重排模型对计算资源的要求比向量模型高但只对少量候选打分所以在成本和效果之间可以做一个不错的平衡。我目前的默认链路是向量召回 50 条重排取 5-8 条作为上下文。值得注意的细节向量模型的更新频率通常高于文本切块流程更换向量模型后需要重新做一次全量向量化否则新旧向量空间不一致检索效果会明显下降。我因为没意识到这个问题曾经换了一个更新的 embedding 模型后没有同步重建索引导致线上召回质量肉眼可见地变差排查了很久才发现根因。4.3 RAG 链路评估不能只在 Demo 里看起来好RAG 项目最容易出现“演示阶段很惊艳上线之后平平无奇”的现象。原因其实不在模型而在链路里每个环节的损耗没有被量化。一个完整的 RAG 评估至少需要看三个维度召回质量相关问题到底有没有被检索到。排序质量正确答案是否排在被送入大模型的上下文里。生成质量给定正确答案片段后模型是否真的把它讲清楚、讲正确。我建议从项目一开始就手工标注一个小批量测试集覆盖典型的用户问题、带变体表述的问题以及边角 case比如问题是简称、错别字、英文名词。用这个小测试集定期跑一遍全链路把召回率、命中率、最终回答打分记成表格作为每次改动切块参数、embedding 模型、提示词、RAG 流程顺序的回归基准。没有这个基准你根本无法判断一次改动到底是在进步还是退步只能靠“感觉回答变好了”这种不可靠的判断这在工程上是致命的。5. 模型选型的决策逻辑不是越贵越好5.1 基础模型与向量模型的搭配AI 工程选模型很容易走入两个极端要么哪个名气大用哪个要么哪个便宜用哪个。真实的选型逻辑应该是按任务难度和延迟/成本要求去组合。以最常见的对话型应用为例我的经验是把任务拆成几档高难度推理数学、代码生成、复杂逻辑分析用顶配大模型不心疼钱。中等难度结构化信息提取、意图识别、改写润色用中端模型就可以满足关键是提示词要写清楚。简单任务分类打标、关键词抽取、情感判断甚至可以不用大模型直接用微调的小模型或规则方式完成。这套分级策略在一个真实项目里能让成本下降非常明显。我做过一个客服助手约 60% 的请求其实只是“查订单状态”“看退货政策”这类固定场景用中端模型加 RAG 就足够只有剩下 40% 的复杂对话才需要顶配模型兜底。如果所有人都走顶配通道费用可能会高出好几倍而用户体验的提升却很有限。向量模型的搭配则更多看领域兼容性。通用领域直接选主流的 embedding 模型即可但如果知识库是特定行业的比如医疗、法律、机械建议在领域语料上做一次小规模的检索效果对比不要只看模型在公开 Benchmark 上的分数。我发现不少领域里专业语料上的召回效果排序和公开榜单并不一致。5.2 推理成本的计算方式很多新手对“模型调用成本”没有概念只盯着单价。实际上成本的大头往往在输入 token 和输出 token 的总量上尤其 RAG 场景里塞给模型的上下文越长每轮成本越高。我建议在项目里做一次成本建模公式很简单单次调用成本 输入 token 数 × 输入单价 输出 token 数 × 输出单价把典型的用户问题长度、检索回的上下文长度、模型输出的期望长度代进去就能估算出单次调用的成本上限。再乘上月调用量就得到月成本预算。一个容易被忽略的优化点是对检索回后送入模型的文本做“相关性截断”也就是重排后不一定把 Top 5 都发给大模型可以只发 Top 3或者按字符数限制上限。上下文缩短带来的成本下降往往比想象中明显。我见过一个团队知识库里单轮能检索出几千字的资料全塞给模型结果单次调用成本蹭蹭涨更糟糕的是上下文过长后模型反而不聚焦回答质量也跟着下降。6. AI 应用的评估体系没有指标就没有工程6.1 评估数据集怎么建从用户反馈里挖AI 应用和传统软件最大的不同在于它在发布之前很难完整验证“所有输入的输出都对”。因此评估集的构建和维护就不是一次性工作而是贯穿项目始终的持续任务。我维护评估集的主要来源有三个线上用户反馈中标记为“不满意”或“没用”的真实会话、运营团队手动收集的高频问题、以及开发过程中主动想出的边界情况。每一条样本都记录“用户问题 期望行为描述 参考回复如果有”不需要太多几百条质量高的样本就比几千条随便抓的数据有用得多。有了评估集之后就可以用它做三类日常操作回归测试每次改提示词或换模型跑一遍评估集对比整体通过率。维度分析把失败样本按错误类型归因分为“检索不到对的资料”“检索到了但模型没答好”“提示词歧义导致格式错误”等几类定位主要瓶颈。新模型预审引入新模型前先跑评估集看分数再决定要不要全量切换。6.2 线上质量监控日志、延迟与兜底策略离线评估集只能覆盖已知场景线上总会出现评估集里没有的新问题所以一套可观测的日志体系必不可少。我目前在每个 AI 请求的链路里都会记录以下信息最终用户输入的原文。检索阶段返回了哪些片段按文档 ID 和得分。最终送入模型的上下文长度。模型输出原文。每阶段的耗时RAG 检索耗时、模型推理耗时、后处理耗时。是否有重试、是否有兜底触发。这些日志做成一个可搜索的看板线上用户一旦反馈“答得不对”我能立刻回放整条链路的每个环节快速判断问题出在哪个模块。很多时候用户觉得“AI 变笨了”其实是向量库里新增的文档质量差把检索结果带偏了而不是模型本身退化。兜底策略也要尽早设计。我的习惯是给所有对话请求配置三级兜底第一级是模型输出解析失败时自动重试第二级是重试仍失败时返回一个固定话术并记录日志第三级是整个链路超时的话业务侧直接给用户一个默认的“客服转接”入口。这听起来是很简单的设计但在真实系统里意义重大——它保证了任何时候用户都不会面对一个无响应的服务。7. 部署与迭代AI 应用上线只是起点7.1 异步任务与长耗时请求的处理AI 应用和普通 REST API 有一个显著差异单次请求可能很长。对话补全动辄几秒涉及长文档总结或多轮 RAG 检索时十几秒甚至几十秒都可能出现。如果照搬传统 Web 应用“同步等待返回”的模式用户体验会很差网关和服务端的超时压力也很大。我推荐的模式是“后台任务 异步推送”服务端接收请求后立即返回一个任务 ID。后台 Worker 执行完整的 RAG 模型调用流程。前端通过轮询或 WebSocket 订阅任务状态。这个模式对技术栈的要求并不高常见队列组件和消息中间件都能支撑。难点在于任务状态的持久化——如果进程重启或崩溃任务能不能恢复、用户能不能知道任务的进展这些在 AI 应用里比传统场景更值得关注因为任务时长的方差实在太大了。有使用流式输出streaming需求的场景则要考虑另一种方案保持长连接逐 token 推送。这种方式交互体验好但工程复杂度更高需要处理连接中断、客户端断连时的 token 计量、以及多个流式请求的并发控制。我建议先跑通非流式方案再按需加流式不要一开始就给自己上难度。7.2 灰度发布与线上故障的应对AI 应用的能力受模型和提示词影响而模型本身是黑盒且各家模型厂商不时会调整版本行为。这意味着“发一个新版本”可能不是整体回滚就能解决的因为你根本不知道用户侧的“感觉变化”具体是由什么改动引起的。我做灰度发布时常用的策略是“双通道随机分流”10% 流量先走新提示词/新链路配置90% 流量维持旧配置。线上评估指标对比两端的效果。这里的指标不只是“回答长度”更推荐“用户是否复制了回答”“用户是否继续追问”“用户手动纠错频率”这类行为信号。新配置稳定 24 到 48 小时后再逐步放量到 30%、50%、100%。这样做的底气来自前面讲的日志体系和评估集。灰度发现问题时我能快速定位是新链路的问题还是模型响应浮动的问题。遇到过几次“同一个提示词、同一个模型今天效果突然变差”的情况最后发现是模型服务商在后台悄悄更新了模型权重版本。这种黑盒风险只能靠监控和灰度来对冲没有任何静态配置可以一劳永逸。8. 针对“从零开始”人群的最后几条建议把前面七个章节的内容按真实项目的推进顺序过一遍基本就能覆盖从零到上线的全过程。最后我再分享几条倾向上更偏经验性的建议希望能帮后来的开发者少走一点弯路。第一点建议先跑通最小闭环再追求优化细节。很多人一上来就想把 RAG、多会话记忆、权限管理、模型路由全做进去结果项目迟迟没有可体验的版本。正确顺序应该是先做“单个问题输入返回一次可用回答”的最小闭环哪怕它在一台笔记本上也能跑起来然后在这个闭环上逐步加环节。每加一个环节都用评估集验证它到底带来了什么不带来价值的环节就要敢于砍掉。第二点建议把“模型会犯错”作为系统设计的前提。AI 工程在很大程度上是在管理模型的不可控性——重试机制、格式校验、知识库兜底、人工转接这些都是系统的正常组成部分而不是临时的补丁。一个稳定的 AI 应用不是因为它用的模型最强而是因为它把模型可能出的每一种错都做了预案。第三点建议一定留出时间做知识的沉淀。AI 领域的更新速度非常快但底层的方法论其实稳定了很多工具和方法比如“评估集驱动迭代”这件事从我接触 AI 工程到现在一直是提高项目质量最有效的手段。建议每完成一个阶段的迭代就把过程中新增的评估样本、调优参数和踩坑记录同步到团队的文档里让后来的人不用重复你走过的弯路。从我的实操体会来看AI 工程真正从零开始难的不是某一步而是“把看似简单的东西稳定地做好”。希望这些思路能给你一些参考少走几步我走过的弯路。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →