AI 工程从零开始:一个老工程师的完整落地路径
这几年我见了太多团队拿着大模型 API 却做不出能上线的产品,不是因为模型不够强,而是整个工程链路七零八落。提示词靠拍脑袋,上下文管理靠拼接字符串,评估靠肉眼观察,上线之后效果漂移了也没有监控。这不叫 AI 工程,这叫用 API 写脚本。
我整理了自己从零搭建 AI 工程体系的完整路径,从 Prompt Engineering 到 Agent 再到多 AI 协作,每一步都附上踩坑记录和可直接抄作业的配置方案。这篇文章不聊大模型内部原理,纯讲怎么把大模型能力变成稳定、可控、可评估的产品功能,适合后端工程师、测试开发、以及所有想把 AI 能力真正落地的人。
1. 整体架构思路:别一上来就写代码
1.1 先分清你做的到底是个什么 AI 应用
AI 应用和传统软件最大的区别在于,传统软件的输入输出是确定性映射,AI 应用则引入了概率性。这意味着你的工程体系必须围绕不确定性来设计。我见过太多人拿到需求就直接调 API,结果 prompt 写了三天,调通了就以为完事了,上生产第二天就被用户骂出幻觉。
做 AI 工程,动手前先想清楚你属于哪一类。我自己习惯把 AI 应用分成四层:
第一层是单轮问答,也就是输入一段文本,输出一段文本,典型场景是内容改写、翻译、总结。这类应用最简单,一个 prompt 加一个 API 调用就完事,难点只在 prompt 质量和输出稳定性上。
第二层是多轮对话,需要维护会话上下文,典型场景是客服机器人、聊天助手。这类应用必须设计上下文管理策略,否则对话超过十轮就开始"失忆"。
第三层是 Agent,也就是让模型调用工具、执行动作,典型场景是自动化测试、数据分析、代码生成。Agent 的核心难点不在模型本身,而在工具调用链路的可靠性和错误恢复机制。
第四层是多 AI 协作,也就是多个不同角色的模型协同完成复杂任务。这层我一直认为是 AI 工程的终极形态,我在后面的实操章节会专门拆解一个完整案例。
1.2 技术选型的三条铁律
选模型和服务商的时候,我给自己定了三条铁律,每条都是踩过坑之后总结的。
第一条铁律是"先算成本再选模型"。大模型 API 计费看着差别不大,实际用量上来之后差距惊人。我做过一个内容分析项目,一开始用高精度大模型做全文总结,一个月烧了四万。后来改成两段式方案,先用平价模型做过滤和预处理,只把一小部分难处理的请求交给高性能模型,成本直接降了 80%,效果几乎没有差别。所以选型前先估算你的调用量级和每轮请求的 token 消耗,把冷热路径分开,别一股脑全上最好的模型。
第二条铁律是"私有化部署不是必需品"。很多人一上来就要部署开源模型,担心数据安全。实际上如果你用的是公有云服务商,只要做好数据脱敏和合规审查,大多数场景都能用托管 API。私有化部署一个 70B 参数模型,光 GPU 采购就是几十万起,还有运维成本,这笔账算下来绝大多数团队根本不合算。做了三年 AI 工程,我手里真正需要私有化部署的场景只有两个:一是数据出域有强合规要求,二是单次调用量极大并且对延迟极其敏感。
第三条铁律是"把模型当可替换组件来设计"。我见过最痛苦的事,是代码里到处直接调用某个模型 API,模型名写死在参数里。一旦要切换模型,或者某个 API 升级了接口格式,整个项目都跟着重构。正确做法是抽象出一层模型网关接口,所有业务代码只依赖这个接口,这样换模型只需要改网关层配置。
2. 核心基础:Prompt Engineering 与 Harness Engineering
2.1 Prompt 提示词工程的关键参数拆解
Prompt Engineering 现在都快变成显学了。我梳理一下真正工程化必用的七个参数,每个参数在不同场景下该怎么配。
temperature(温度)是控制随机性的核心参数。粗略理解,温度越低输出越保守越稳定,温度越高越有创造性。我的习惯是:做事实性任务(比如信息抽取、分类、格式化输出)把温度调到 0,这是为了让输出尽量可复现;做创意生成(比如文案、头脑风暴)调到 0.7 到 0.9;做代码生成调到 0.2 左右,让代码尽量规整而不是有创意。很多人不知道,温度调到 0 后模型仍有可能输出不同结果,因为采样器还有其它随机因素,但这个参数依然是降低输出波动最有效的手段。
top_p(核采样)也叫 nucleus sampling,控制模型只从累计概率达到该阈值的 token 集合中采样。实际工程中我经常只调 temperature,把 top_p 固定在 0.9 附近。如果你的应用对输出多样性敏感,可以试着同时调低 temperature 和 top_p;但记住,两个参数一起拉高会让输出变得非常随机,生产环境要谨慎。
max_tokens(最大生成长度)很多人把它当输出长度限制,但更需要关注的是它会截断输出。如果模型在思考中途就被截断,你得到的就是一段残缺内容。所以我习惯把它设成预估回答长度的一倍,宁可浪费一点,不要让回答被切断。另外,代码生成场景 max_tokens 要调大,一段完整函数的代码通常比你想象的长得多。
frequency_penalty 和 presence_penalty这两个参数的作用是抑制重复表达。frequency_penalty 按频率惩罚,presence_penalty 按是否出现过惩罚。我当时做技术文档生成时,发现模型写长文会在同一个观点上反复绕圈子,调降了重复内容之后就是把 presence_penalty 调到 0.2 左右,效果好很多。日常场景我推荐这两个参数只在长文本生成时调整,短对话维持默认。
stop_sequences(停止序列)是控制生成边界的关键。比如你想让模型只输出 JSON,就把}之后的换行符作为停止序列,或者用更稳妥的方式,让模型只输出一段 JSON 代码块,解析时严格提取代码块内容。这个参数能让输出变得非常干净,我强烈建议所有做结构化输出的项目都用上。
系统提示词(system prompt)的长度与优先级我做过对比测试:系统提示词越往后写的内容优先级越高。所以把最重要的指令放在系统提示词末尾,模型遵从度会更高。这是个奇怪的规律,但多轮测试验证下来确实如此。另外,系统提示词要写成"行为规范",而不是"任务描述"。比如写"你是资深测试工程师"不如写"输出格式必须为 Markdown 表格,每行一个测试用例,包含前置条件、执行步骤、预期结果三列"。
2.2 Harness Engineering 不是 Prompt 的替代品
大家现在都在聊 Harness Engineering,这个词直译是"挽具工程",意思是给模型套上一套缰绳,让它按照你的规则来做事。和纯靠提示词引导不同,Harness Engineering 强调的是控制模型输出结构和行为的所有外部机制,本质上是一套工程框架。
我理解 Harness Engineering 的核心就是三件事:第一,输出约束。用结构化输出协议(比如 JSON Schema)强制模型按特定格式返回,而不是回到文本里"请以 JSON 格式输出"这种靠自觉的方式。第二,行为编排。把复杂任务拆成流水线式的多个阶段,每个阶段有独立的模型调用和校验逻辑。第三,错误恢复。对模型的失败输出设定重试、回退、人工兜底机制。
举个我自己实践过的案例:我用 CodeBuddy 实现了一套叫"测试用例生成流水线"的 Harness 方案。整个流程分成四段:第一段用低能力模型做需求理解和信息抽取,输出规格化需求描述;第二段用高能力模型生成测试用例,但生成的不是自然语言,而是按我定义的用例 Schema 输出结构化数据;第三段用代码生成模型把结构化的用例转换成可执行的测试脚本;第四段是执行引擎,拿真实 API 跑一遍测试,失败的用例自动回填到生成模型中重新生成。这套流程跑下来,测试用例生成的有效率从最初的 45% 提到了 87%,光靠调 prompt 根本做不到这个效果,关键是在生成和校验之间形成了闭环。
这种工程化的路子,我把它理解为"用系统能力弥补单次模型能力的不稳定性"。每次模型输出都是概率性事件,但多个校验关卡加进去之后,整个系统的稳定性就被兜住了。这比单纯优化提示词更有工程价值。
2.3 Harness 化三个步骤,你也能自己搭
第一步,先定义输出协议。不管模型返回什么,先规定好你的 JSON Schema。拿测试用例生成举例,我不会让模型自由发挥写测试步骤,而是定义成:
{ "test_case_id": "TC-001", "title": "验证用户使用正确凭据可以登录系统", "precondition": "用户未登录且无激活会话", "steps": [ {"action": "open_page", "target": "/login", "input": {}}, {"action": "fill_field", "target": "#username", "input": {"value": "tester01"}} ], "expected": "用户跳转到 /dashboard 页面" }还真有人质疑我,让模型输出 JSON 太死板了。但恰恰这种死板才是生产环境最需要的东西。模型自由发挥的结果就是解析器三天两头爆异常,每次爆异常还得人工排查。用了 Schema 约束后,生成结果可以直接进执行引擎,根本不需要人肉翻译。
第二步,搭校验层。模型输出之后不要直接信任,而是加一道结构化校验。把输出解析成 JSON 之后,用 JSON Schema 校验器验一遍,字段类型不对的、必填字段缺失的、枚举值不合法的全部打回重试。这一步能过滤掉大约 20% 到 30% 的错误输出。
第三步,建立重试与降级策略。模型第一次输出不合格,不要无限重试,设定两到三次的最大重试次数。重试仍失败就把这条数据标记为"需要人工处理",放进待办列表。生产环境里 95% 的请求走自动链路,剩下 5% 的人工兜底,比追求 100% 自动化要靠谱得多。
3. 进阶核心:从 AI Agent 到多 AI 协作
3.1 AI Agent 的核心机制拆解
Agent 系统近几年在各大 AI 应用里都快成标配了。我先说结论:Agent 系统做得好不好,关键不在那个"大脑"模型选得有多强,而在于你给它设计的"手脚"够不够稳。
Agent 的经典执行循环是:感知(Perception)-> 推理(Reasoning)-> 行动(Action)-> 观察(Observation),循环往复直到任务完成。听起来很简洁,真正落地的时候有三件麻烦事。
麻烦事一是工具调用不可靠。模型返回一个调用函数的 JSON,但它经常把函数名写错或者参数结构给错。我的解法是给每个工具写严格的参数 Schema,并且让模型"先看 Schema 再调用"。同时在网关层加一道工具参数校验,不合法就自动修正或者报错返回给模型重新生成。
麻烦事二是循环会卡死。Agent 在一个错误分支上反复重试,浪费 token 还浪费时间。这个必须在系统层面强加"最大迭代次数"限制,我通常设 10 次左右,超了就终止任务并返回当前状态。
麻烦事三是状态管理混乱。多步任务执行到一半,Agent 需要记住前面做了哪些事。我最开始用把所有对话历史一股脑塞给模型的办法,结果很快就把上下文窗口塞满了。后来我改用显式状态跟踪,把任务的中间结果存成结构化变量,关键节点的状态用变量引用,而不是把所有历史记录重新推给模型。这个改造的效果非常明显,复杂任务的成功率提升了将近两倍。
3.2 实操案例:用 Agent 做自动化测试开发
我团队里最成熟的 Agent 应用是自动化测试开发助手。流程设计如下:用户提交需求描述和接口文档,Agent 先读取文档做分析,再生成测试方案,然后调用代码生成工具写测试脚本,最后调用测试执行工具跑一遍。这中间 Agent 需要调用四个独立工具:文档解析器、用例生成器、代码生成器、测试执行器。
这个系统在测试开发这个岗位上,替代了大量重复性工作。过去一个测试工程师写一套接口测试脚本耗时半天,现在 Agent 大约十分钟生成初稿,人只要审改一下即可。我在这里面建了一套非常严格的工具接口协议,每个工具都有输入输出的 JSON Schema,Agent 调用失败时还会自动读报错信息修正调用参数。实测下来,工具调用的成功率从 71% 提到 96%,原因就是在每个工具调用点加了一个"自纠错环节"。
3.3 多 AI 协作的两种主流架构
多 AI 协作听起来很高大上,实际上做工程就是两种架构选一种。
一种是"中心化调度"架构。有一个主导 Agent 负责理解任务、拆解分配,再调度多个子 Agent 分别执行。像我自己做的需求分析系统就这么设计的:调度 Agent 接收需求文本,把内容抽取任务分给子 Agent 一,把测试用例生成任务分给子 Agent 二,把代码生成任务分给子 Agent 三,最后自己汇总校验结果。这种架构比较直观,但缺点是所有流量都过中心节点,调度 Agent 一旦出错,整个链路就瘫了。
另一种是"去中心化协作"架构。多个 Agent 各有职责,通过消息队列或者共享黑板(Blackboard)机制交换信息,没有中心节点。我做一个文档协作系统用的就是这种:一个 Agent 负责写作,一个 Agent 负责审校,一个 Agent 负责排版,各自独立运作,通过共享文档状态协调。这种架构容错性高,但协调成本也高,需要设计好任务互斥和数据一致性的处理。
我的经验是:初学阶段先做中心化调度,因为它最容易理解和调试。等你的多 Agent 系统到了需要高并发或者强容错的时候,再演进到去中心化架构。
3.4 多 AI 协作完整案例:AI 短剧剧本生成流水线
我前阵子帮做内容的朋友搭了一条 AI 短剧剧本生成的流水线,用到了多 Agent 协作,正好拿来说说完整方案。
短剧剧本生成一共四步:选题定位、大纲设计、逐场对白生成、修改润色。我建了四个 Agent 分别负责。选题 Agent 读取热点数据,输出带有热度评分和高概念描述的选题卡。大纲 Agent 读取选题卡后,按情节"起承转合"写出分集大纲,每集大概 150 字。对白 Agent 读取大纲后逐集生成角色对白,这是全流程中唯一调用高性能模型的环节。润色 Agent 检查所有对白,修正逻辑不通的地方,并统一角色语言风格。
这套系统跑下来的效果是:原来人工写一集短剧剧本大约需要两小时,现在整条流水线跑完一集大约十几分钟,而且内容的可读性相当不错。你可以想象一下,如果是一家一个月上架上百集短剧的工作室,这个效率提升意味着什么。
最关键的点在于:多 AI 并行工作不是把所有 Agent 同时调起来就完了,而是要在 Agent 之间设计清晰的"交接协议",每个 Agent 的输入输出都是结构化数据,下一个 Agent 不需要也不应该去看上一个 Agent 的全部思考过程,只需要读取它需要的输入即可。这就像工厂流水线,每个工位只对接上一工位交给你的零件。
4. 工程化落地全流程:从需求到上线
4.1 数据准备与上下文工程
AI 应用要做得好,喂给模型的上下文质量比模型本身的能力更关键。我们团队做过一个文档问答系统,一开始怎么调 prompt 答案质量都一般。后来我做了一件事:把所有上下文中和问题无关的内容全部过滤掉,只留与问题最相关的段落,正确率直接上了一个台阶。
上下文工程的核心是 RAG。整个流程:先对源文档做切片(chunking),再做向量化,存进向量数据库,查询时先做语义搜索找最相关的片段,再拼进 prompt 送给模型。
这里有两个坑必须讲。第一个坑是切片策略。切片切得太小,语义完整性不够;切得太大,向量匹配的精确度下降,还可能超出模型上下文限制。我的实践标准是:一般技术文档按段落切,每个切块控制在 200 到 500 字之间,保留段落标题。第二个坑是元数据。如果每个切块都带上来源文件名、章节路径、更新时间,追踪结果时可以回溯到原始出处,这个能力在产品上线后排查问题是一个刚需功能。
4.2 模型网关与统一接入层
我强烈建议所有 AI 工程都搞一个模型网关。网关的作用不单纯是转发请求,还能做三件事:第一,统一接口格式,业务层不感知后端用的什么模型;第二,做限流和降级,某个模型服务不稳定时自动切换备选;第三,记录所有请求日志,为后续的评估和监控提供数据基础。
网关层的配置我一般这样写:
# 模型网关配置示例 MODEL_ROUTES = { "default": { "provider": "openai_compatible", "model": "gpt-4o-mini", "temperature": 0.2, "max_retries": 2 }, "high_quality": { "provider": "openai_compatible", "model": "gpt-4o", "temperature": 0.1, "max_retries": 3, "fallback": "default" }, "code": { "provider": "anthropic", "model": "claude-3-5-sonnet", "temperature": 0.0, "max_retries": 2 } }看这个配置,不同任务走不同的模型路由,某个路由失败了可以降级到另一个。这个设计最大的优点就是,你有一天想把某条路线切换成国产模型或者开源部署模型,只需要改配置,业务代码一行都不用动。
4.3 评估体系与测试方法
AI 工程和传统软件工程最大的差别在于,你不能用"断言"来测模型输出。传统测试用例能精确判断结果对不对,模型生成的内容只能用"质量评分"衡量。所以 AI 工程的测试体系要设计成多层并行的结构。
第一层是格式校验。检查输出是不是合法 JSON、是否满足 Schema、必填字段是否都有。这层用程序可以自动完成,也是拦截野输出最有效的一道关卡。
第二层是规则校验。针对业务自定义规则,比如不能包含禁忌词、结果必须包含指定字段、长度必须在指定区间。这类规则也可以用程序写。
第三层是语义校验。这就需要第二个模型来打分或者做对比。评审一个模型输出质量好不好,最常用的方案是拿一个更强的模型当裁判,要求它对输出按多个维度打分,比如相关性、完整度、忠实度。当然裁判模型也会有偏差,所以最好是多种校验手段混用,而不是全部押在模型裁判上。
第四层是回归测试集。这一层是最重要的。我维护了一套大约两百条测试样本的标准数据集,每次换模型、改 prompt 之后,都必须跑一遍回归集,对比整体通过率和平均质量分。没有这套机制,你永远不知道一次 prompt 修改是不是顾此失彼、按下葫芦浮起瓢。
4.4 上线投产:效果监控与持续调优
AI 应用上线后,不能当甩手掌柜。传统应用上线后看错误率和延迟,AI 应用要额外盯三样东西。
第一是 token 消耗成本监控。AI 应用成本是随用量线性增长的,如果某个接口调用量暴涨而业务量没涨,多半是有人在刷接口或者某个环节出了问题。我习惯按天统计每个功能的 token 开销,和前一天做对比,异常偏离就拉告警。
第二是输出质量抽样监控。每天从线上请求中随机抽一部分,让人工或者裁判模型评估输出质量,跟踪平均质量分的趋势变化。我当时做客服助手的时候,上线两周后发现某个话术类型的质量分持续走低,排查下来是上下文长度增长导致关键信息被挤出了窗口,后来通过调整摘要策略解决了。没有质量监控这个动作,这类问题根本不可能及时发现。
第三是用户反馈回收。AI 应用尤其需要做"点赞/点踩"按钮,用户一句话的"回答错误"比你跑一百次自动评估都有价值。我建议把所有负面反馈的请求日志单独存一个池子,定期用它们刷新回归测试集,这样做模型调优的时候才不会偏离用户真实关注的方向。
5. 常见问题与排查避坑实录
5.1 高频问题速查表
我整理了一张快速排查表,几乎覆盖了我做 AI 工程时遇到的大部分常规问题。
| 症状 | 排查方向 | 解决方案 |
|---|---|---|
| 输出频繁不符合格式 | 检查是否用了结构化输出协议 | 上 JSON Schema 校验 + 重试机制 |
| 回答与问题不相关 | 检查上下文检索环节是否召回错误相关文件 | 优化 RAG 切片和检索策略 |
| 对话超过几轮开始失忆 | 上下文管理策略有缺陷 | 引入摘要和关键信息记忆模块 |
| 复杂任务执行一半进程就崩了 | 缺少状态持久化 | 设计显式状态跟踪,关键节点落库 |
| 切换模型后效果明显下降 | 新模型对细节遵守度不同 | 重新跑一版 Prompt 工程调优 |
| 成本快速增长无法控制 | 缺少用量监控与路由分流 | 建冷热路径,低价模型处理简单请求 |
| Agent 反复调用同一工具不肯结束 | 缺少最大迭代限制 | 强加 iterations 上限和退出机制 |
| 输出偶尔出现幻觉且影响业务 | 缺少事实校验层 | 引入检索校验 + 人工兜底审批 |
5.2 三个最值钱的避坑经验
第一个经验,结构化输出的可靠性远高于自然语言约束。让模型"请严格按照 JSON 格式输出"的结果,就是模型给你一段 JSON 包在 Markdown 代码块后面,或者某个字符串值里带了一堆注释,解析器直接炸开。正确做法是使用强制 JSON 输出模式,同时你的解析逻辑要能容忍 Markdown 代码块包裹的 JSON。
第二个经验,Prompt 越短往往效果越好。系统提示词不是论文,不要想着把所有规则写进去。你把规则写得越长,模型就越容易在细枝末节上犯浑。核心指令不超过五条,每条讲清楚"要什么"和"不要什么",比长篇大论更能提效果。
第三个经验,上下文窗口不是越大越好。很多人以为模型上下文长了,把所有历史一股脑塞进去就行。实际效果恰恰相反,历史信息太多很容易把关键指令淹没。我的做法是:只需要最近三到五轮的完整对话,更早期的内容压缩成摘要,每轮对话都标记时间戳和角色。这个做法让长对话场景的准确率比"全部塞入"高了不少,同时 token 消耗也降下来了。
5.3 技术债务案例复盘
最后分享一个真实翻车案例。当时做一个知识库问答系统,上线之前所有基于回归测试集的指标都表现很好,结果上线两周后用户投诉准确率骤降。排查流程是这样的:先看服务日志,没发现报错;再看模型调用记录,发现一样的问题请求用户输入的"问法"在搜索引擎里带了新词;然后检查了上下文管理逻辑,发现用户历史对话越来越长,系统在第十五轮左右开始因为 token 超限丢失关键信息,模型拿不到准确的背景,只能靠猜。最终解决方案是加了一个全局状态记忆模块,把用户的核心属性(会员等级、业务类型、历史偏好)向量化存储,不再依赖对话历史的全文拼接。改完之后准确率恢复并且还稳中有升。
这件事给我的启发是:AI 系统上线后的性能下降,不一定是模型本身出问题,多半是你自己的上下文管理、路由策略、检索质量这些周边设施出了状况。所以监控体系里,永远不要只盯着模型输出那一环,上下文管理、工具调用、数据流转这些基础设施更值得你花精力去监测。
我在实际开发中最深的体会是:AI 工程走到最后,大家比的已经不是谁的模型更聪明,而是谁的工程体系更扎实。Prompt 写得好只能让你在 demo 里赢,要真正扛住线上流量和用户挑剔的检验,还是得靠完整的评估、监控和容错体系。你不需要懂得怎么从零训练一个模型,但你必须懂得怎么把大模型这个"能力原子"接入到你的产品血脉里,让它稳定地发光发热。这,才是 AI 工程师真正的价值所在。