开头(从业者口吻,直接引入)
我这几年一直在做AI相关的落地项目,经常被朋友问到一个问题:“你们做AI工程,跟网上那些调API的教程到底有什么区别?”每次我都得解释半天——调API只是最后一步,真正的AI工程是从需求拆解、方案选型、数据准备、Prompt设计、Agent编排,一路做到部署监控和回归测评。换句话说,Prompt Engineering只是AI工程里很小的一块拼图,而“ai-engineering-from-scratch”这个词,代表的是一条从零开始把AI能力稳定地、可维护地、成本可控地跑进业务系统的完整路径。
这篇笔记就是我个人从零搭建AI工程体系的实战总结。我会把整条路线拆开来讲:先搞清楚AI工程和AI开发有什么区别,然后从需求拆解、提示词工程、RAG检索增强、Agent工作流编排、模型选型、部署监控、以及常见的大坑排查,完整过一遍。适合正在从“调接口选手”往“AI系统工程师”进阶的开发者,也适合技术负责人做方案选型时参考。里面的每一条经验都是我在生产环境里踩过的,不是教科书上的标准答案,但至少是能帮你少走弯路的实操版本。
1. AI工程不等于调API:先搞清楚边界在哪
很多人有个误解,觉得AI工程就是把大模型的API接到业务代码里,跑通了就是AI系统了。真不是这样。API调用只是整条链路里最末端的一环,AI工程的核心矛盾,在于它面对的是一套“概率正确”的执行单元。
1.1 概率系统 vs 确定性系统:思维要先切换
传统软件工程的思维是:一样的输入,一样的代码路径,必然产生一样的输出,这叫确定性系统。但大模型不一样,同一个Prompt、同样的温度参数,模型每次返回的内容都可能不同——即使同一条输入,概率分布也决定了这次、下次、下下次的结果会有差异。这就是AI工程最大的思维转变点:你没法像对待普通接口那样对模型结果做单测断言。
我见过很多失败案例,团队用传统思维方式做AI功能,要求模型“必须输出JSON”“必须记住前面第5轮对话里提到的用户名”,出了问题就反复调Prompt,调不好就骂模型不行。其实问题出在工程架构上——系统设计上就没考虑“模型会犯错”这个前提。
AI工程的核心设计哲学,是把“不确定的模型输出”通过工程手段不断收敛为“确定可用的业务结果”。具体的手法包括:结构化输出约束、协议校验与自动纠错、将大任务拆解为多步小模型执行,以及用程序逻辑代替一部分模型推理。说白了,就是把不确定性关进笼子里,而不是指望模型自己变乖。
1.2 一条从零搭建AI工程的完整技术栈
从零开始做AI工程,需要的不是“一个大模型搞定一切”,而是一套组合栈。我目前线上跑的这套体系,差不多是下面这些组件的拼装:
- 主模型层:以闭源商用API(比如GPT-4o这类旗舰模型)为主力,承担复杂推理任务。
- 次模型层:开源模型(Qwen、Llama系列等)用于简单抽取、分类、摘要等高频低难度任务,大幅降成本。
- 编排层:LangGraph或自研的DAG工作流引擎,负责多步骤任务的状态传递和分支控制。
- 检索层:向量数据库 + 重排序模型,负责让模型获得真实、可控的上下文。
- 网关层:统一的模型接入层,做多Provider切换、请求重试、成本审计。
- 评估层:独立的评测数据集 + 自动化回归测试,每次改动后先过评测再上线。
- 可观测层:日志、Token消耗追踪、请求延迟和成功率监控,以及关键链路的用户反馈回收。
这套组合栈不是一次搭成的,最初我只有一个裸API,后来逐步长成了完整的体系。下面我按搭建顺序逐一讲清楚,每个环节我会尽量给出可复用的参考方案,而不是空谈概念。
2. 从需求到方案:一条可复制的AI工程落地路径
2.1 第一步永远不是选模型,而是拆解任务类型
很多人做AI项目,第一步就是选模型,这其实是本末倒置。正确流程应该是:先把业务需求拆成一组可量化、可验证的子任务,再逐个判断这些子任务分别适合API调用、Agent编排、还是根本不需要AI。
举个实际例子,比如你要做一个“智能客服工单分类系统”。看起来是个一个模型就能干的活,但拆开看就复杂了:需要意图识别(是问题咨询还是投诉)、情感判断、工单优先级划分、历史类似工单的检索匹配、回复草稿生成这五类子任务。如果直接甩给一个模型生成最终回复,通常效果不稳定——因为你没法对中间环节做质量把控。
正确做法是把它们拆开:意图识别用少样本分类,直接走轻量模型;工单匹配走向量检索;回复草稿才用主力大模型生成。每一层都有独立验证标准,出了问题能精确找到是哪一层坏了,而不是整个系统黑盒运行。
判断“某个环节是否需要AI”也有个简单标准:如果这条规则能被穷举、能被代码逻辑低成本写死,就不要用AI。我见过有人用大模型做“判断是否是公司内部员工工号开头有没有EMP前缀”——这就是典型的过度设计,一条正则就能搞定,非要让模型去猜。AI工程的进化方向,是让AI只干那些模糊的、语义化的、规则覆盖不了的事情。
2.2 任务拆解后要定义可验收的指标
任务拆解完,紧接着就要定义“什么叫做好了”。这一步做不扎实,后面的Prompt和Agent编排就是闭着眼睛开车。我对每个子任务会用可量化指标约束:
- 分类准确率(比如意图识别的Top-1命中率)。
- 抽取字段的召回率(比如从对话里抽取客户姓名时,漏提率不能超过2%)。
- 生成内容的质量评分(用专门评测集 + LLM作为评判者来打分)。
- 端到端成功率(比如工单从进来到正确分类、正确回复的完整链路过测率)。
每个指标背后要有具体的测评集。我一直强调:“没有评测集,就没有AI工程。”哪怕你的评测集只有50条真实业务数据,也好过裸奔上线。有了它,你每次改Prompt、换模型、调参数,都能跑一遍回归,不会出现“这次调好了A场景,结果B场景崩了”的尴尬。
我之前就是因为没有测评集吃亏过:给一个客户调整客服机器人的回复模板,手工测试了20个问题都正常,客户也满意。结果上线后,A渠道的咨询里问商品保修政策的,机器人答非所问——因为模板修改影响了连锁子任务。后来老老实实建了120条覆盖各渠道、各业务标签的回归语料,之后任何改动先过这120条再上线。虽然手工维护测评集很费功夫,但这是AI工程质量的生命线。
3. 核心环节逐个拆解:提示词、检索、Agent与工作流
3.1 Prompt Engineering从“写指令”到“立协议”
提示词工程是AI工程最基础的技能,但大多数人把它当成了“写小作文”。早期的Prompt教程教你“请你是一个XX专家,请你认真思考”,这种角色的泛泛描述在简单场景下有效,但在工程化体系里远远不够。
我把工程级的Prompt总结成“立协议”的思路。一个工程级Prompt不是一段话,而是一个完整协议,它包含以下部分:任务定义(这个模型输出要做什么)、输入约束(哪些字段必须从外部注入,哪些需要模型自己推理)、输出规范(JSON格式、字段名、取值范围、枚举类型)、边界规避(遇到哪些情况必须回答“信息不足”)、Few-shot示例(至少3-5个不同输入形态的示例)。
举一个我在邮件意图识别场景里用的Prompt结构简化示例:
你是邮件处理系统的意图识别器。你的任务是把邮件分类到以下枚举: buy_request / after_sales / partner_cooperation / unknown 输出要求:仅输出JSON格式,包含字段 intent 和 reason,reason不超过30字。 规则: - 如果邮件内容含订单号或发票号,优先归为after_sales。 - 如果邮件是商业合作提案,归为partner_cooperation。 - 如果无法判断,输出unknown,禁止猜测。 - 只基于邮件正文判断,不要推断发件人身份。 示例: 输入:...(示例1) 输出:{"intent": "after_sales", "reason": "..."}工程提示词的核心,是把裁决规则显性化、把输出格式协议化、把失败兜底明确化。这样模型的行为才能被预期、被校验、被监控。说白了,你要把Prompt当成一个接口契约来看,而不是一段话术。
3.2 检索增强生成RAG:不是只接个向量库就完事
RAG(Retrieval-Augmented Generation,检索增强生成)是很多AI应用的关键组件,我把它比喻成“给模型带上了参考资料进考场”。但很多人做RAG失败,原因不是向量库不好,而是检索链路过于粗糙。
一个完整的RAG链路通常包含这些环节:文档切块、Embedding向量化、向量检索、重排序(Rerank)、上下文组装。每个环节都有坑。
文档切块是最容易想当然的。我之前做内部知识库问答时,最开始按固定字符数切块,比如每500字一刀切,结果模型回答质量很拉——因为常把同一件事的相关上下文拦腰截断。后来调整为“语义句边界切分 + 标题层级补全”:切块时优先按段落边界断开;对结构化文档,切块后保留其所在章节的标题作为上下文前缀。这个改动让回答准确率提升了大概15个百分点。
向量检索的选型上,如果你用中文业务资料多,建议优先测试BGE这类中文表现更稳定的模型,而不是无脑套OpenAI的Embedding。嵌入模型的效果,要放到你自己的语料上评估,用“检索命中率+正答率”两个指标来判断,不要凭感觉。为了提升检索质量,我强烈建议加一个重排序环节,用Cross-Encoder模型对向量检索返回的Top-20结果重新打分排序,取Top-5作为模型上下文。这一步几乎是无脑提升效果,强烈推荐。
最后是上下文组装。这里有个触过底的教训:很多人把检索到的全部内容一股脑塞进Prompt,以为“给得越多模型越聪明”,结果模型反而被冗余信息干扰。需要设置总字数的硬上限,我通常控制在2500字以内,只选取跟当前用户问题向量相似度最高的几个块,宁可少给,也要给得精。
3.3 Agent编排与多AI协作:从单模型调用到系统智能
AI Agent是最近特别火的概念,本质上就是让模型能调用工具、能自主决策下一步。但工程化的Agent和Demo级别的Agent完全是两回事。后者只需用ReAct模式循环调用工具就行,前者必须面对“循环失控”“跑飞了”“费用超支”等问题。
我采用的Agent设计原则是“把所有能确定的都交给代码,只把不确定性留给模型”。比如工具选择,如果业务规则能确定“这个问题只能走A工具”,就不要让模型做选择,直接用代码写死;只有出现分支发散时,才让模型推理。这个原则能极大节约Token,同时降低模型幻觉概率。
多Agent协作是另一层内容。现在的AI工程里,单一Agent解决复杂任务往往力不从心,因为上下文窗口有限,一个Agent同时负责思考、执行、汇总容易出错。更稳的架构是“分工式”:规划Agent负责任务拆解和排期,执行Agent只负责调用特定工具完成任务,审核Agent对执行结果做质量审查。这三个Agent之间用结构化协议传递消息,而不是像人聊天那样自由对话。
热词里的“多AI协作”其实指的就是这类系统架构。我建议不要迷信“多个Agent会自己涌现出智能”的说法,工程上没有涌现,只有设计。分工、衔接、纠错、兜底都要明确写进代码和Prompt里。
4. 模型与API的工程化选型:托管服务还是自建模型
4.1 选模型的决策逻辑:质量、成本、延迟的三角博弈
模型选型是AI工程里最需要理性分析的一环。大模型没有“最好”,只有“在某个成本/延迟约束下最合适”。我个人的决策矩阵大致是这样的:
- 如果任务要求深度推理、复杂指令遵循,或者容错率极低(比如合同审查),用旗舰闭源模型。
- 如果任务是高频、短上下文、重复模式(例如工单分类、关键词提取),优先用中小开源模型或低档位API,先充分调Prompt;不行再加档位。
- 如果任务涉及敏感数据,不允许出内网,那只能本地化部署开源模型。
- 如果业务有强合规或离线要求,不能依赖外部API,本地模型是唯一选项。
以线上客服系统为例,我把高频的意图分类从主力模型迁移到一个小参数模型(实测精确率保持在93%以上),单次调用成本从原来的约0.02美元降到接近0.002美元,十倍压降。成本压缩并不会自动导致质量崩坏,关键在于任务类型是否匹配——高重复性、边界清晰的任务用轻量模型反而更稳。
4.2 多Provider兼容层与成本追踪
做AI工程第三个月,我就碰到了被单个API供应商限流的窘境。一个晚上流量压过来,对方的接口超时率暴涨,整个客服机器人直接瘫痪。从那时起,我就在模型接入层加了一个兼容网关,实现多Provider一键切换。这个兼容层不复杂,核心就是把不同厂商的接口格式统一成内部的模型调用抽象,让上游代码不需要感知下游换的是哪家模型。
具体实现上,可以在内部封装一个ModelRouter模块,对外只暴露一下三个能力:chat_complete(messages, model_spec)统一对话接口、embeddings(texts)统一向量接口、health_check()探活接口。每次调用前,Router读取配置(比如当前主力模型是A厂商,备胎是B厂商),当A厂商连续报错超过阈值,自动切到B厂商,并记录切换原因。
成本追踪也在这个网关层实现。每条请求耗费的Token数、单价、总成本都写入日志,汇总到看板。我习惯按业务线划分成本标签,比如“客服机器人”“文案生成”“知识库问答”分别记账。这样一来,哪个业务线烧钱多、哪个环节Token浪费严重,一目了然。有了这个数据,你才敢对老板说“这个功能月成本300元”,而不是拍脑袋。
5. 部署与监控:AI系统的上线不是终点
5.1 自建模型部署的工程细节
如果选了本地部署开源模型,典型路径有两种:以Python生态的vLLM / TensorRT-LLM做高性能推理,或者用Ollama等做轻量本地调试。生产场景我个人推荐vLLM,它对连续批处理、显存管理做了大量优化,吞吐量比naive的Transformers推理高很多。
部署时一个容易忽略的参数是max-model-len(最大上下文长度)。很多人只看模型支持多长上下文,却不看自己的显存够不够。上下文越长,KV Cache(键值缓存)占用显存也越大,并发一高就可能OOM。我踩过这个坑:在一个8卡A800的集群上部署32K上下文模型,并发60路请求,跑了两天开始频繁OOM,最后排查下来是KV Cache的显存预分配不足,调整gpu_memory_utilization和max_num_seqs参数后稳定下来了。
建议本地部署上线前,做一次显存预算计算。公式大约是:单请求占用显存 ≈ 模型权重 + 输入Token数×每Token KV Cache字节数 + 输出缓冲区。如果你的模型权重占用了单卡显存的70%,那留出的KV Cache空间是固定的,就得靠限制并发数来避免OOM。
5.2 监控三件套:成功率、Token消耗、ROI
上线后最需要盯的不是模型本身,而是稳定的运行指标。我每天会过一遍这几个数字:
- 请求成功率(目标99%以上,失败需要分错误类型统计)。
- 平均首Token延迟(用户感知的等待时间),P95尤为关键。
- Token消耗量(分别统计输入和输出Token,监控有没有Prompt爆炸)。
- 端到端业务完成率(比如100次咨询里,有多少次正确走到了工单创建)。
- 低成本质量抽检(每天随机抽30条人工打分,作为线上质量的底线监控)。
这个抽检机制对维护AI系统质量特别关键。再好的离线评测集也不可能完全覆盖线上的新表达方式,只有持续抽检才能发现长尾输入造成的质量漂移。我见过很多系统,离线评测90分,上线一周用户骂翻天,根本原因就是没有线上质量闸门。
5.3 灰度发布与A/B测试:AI系统也需要版本管理
AI系统的发布不能像传统发版那样“一键全量”。因为Prompt改动、模型升级都可能引入不可预期的影响面。我的流程是:先在隔离的小流量环境验证技术指标,再在灰度环境放5%用户,用A/B测试对比新版本与旧版本的关键业务指标,通常观察至少24小时后再逐步放量。
这套流程最大的价值不是防止模型崩了,而是防止“看起来没崩但其实业务指标掉了”。比如客服机器人回复流畅度没变,但用户支付环节点击率下降了——这大概率就是新版本回复风格诱导用户在关键节点流失了。没有A/B测试,这种隐性劣化根本不会被发现。
6. 常见问题与大坑排查实录(实证向)
6.1 表格:高频事故与处理方案
| 症状 | 常见根因 | 我的处理方案 |
|---|---|---|
| 模型输出JSON偶尔残缺 | 温度参数过高或Prompt中格式约束不强制 | 设置response_format为结构化模式,并用Pydantic做解析,失败自动重试 |
| 回答内容与检索资料无关 | 向量检索命中错误切块,或上下文超过窗口被截断 | 改切块策略、加Rerank、压缩Prompt上下文 |
| 多轮对话越聊越乱 | 历史消息被非线性截断,丢失关键上下文 | 用滑窗保留最近N轮 + 关键字段独立存储 |
| 模型幻觉编造数据 | Prompt未声明“数据只能从资料中提取” | 加来源约束,并让模型输出中携带引用片段 |
| 响应突然变慢 | 并发过高触发Provider限流,或自建模型KV Cache不足 | 网关层限流熔断、扩容推理节点 |
| 本地模型OOM | KV Cache显存预留不够,或并发数设置过大 | 提前做显存预算,调整并发参数 |
6.2 系统运行中的真坑记录
先说一个典型的连环事故。我有一次把文档的Embedding模型版本升了个级,升级前没重新跑一遍全量向量化,结果新旧向量混在同一个向量库里。上线后检索效果一塌糊涂——模型回答经常引用错文档,用户投诉“跟机器人说A,它回答B的”。排查了很久才定位到向量库里的向量语义空间不一致。
这个教训让我立了条规矩:更换嵌入模型版本,必须全量重新向量化文档,并把旧的向量索引立即下线,不能并行混用。这是一个运维细节,但带来的质量影响是灾难级的。
另一个我实际踩过的是Prompt里隐式要求模型输出悄悄被模型理解的偏差。比如你写“只输出JSON”,没有明说“不要输出任何其他文字”,三成的情况下模型就会“礼貌地”多输出“好的,这是您要的JSON:”这种废话。用结构化接口约束后,这个问题基本消失。
6.3 给新手的避坑顺序建议
如果从零开始做AI工程,我建议先去处理三类高风险问题,再考虑优化效果:
第一,刚需先做结构化输出校验。任何模型的输出都先解析、再校验、失败就重试,这是稳定性的最低成本护城河。第二,尽快建离线评测集,哪怕先有30条,保证每次改动不劣化。第三,提前做成本控制设计,从第一行代码起就记录Token消耗,避免月底账单爆炸。
工程能力是分层的:先把地基打得足够稳,再追求上层功能的想象力。
经验收尾:写给同样在搭AI工程体系的人
最后分享一个我自己的习惯。我每隔两周会把线上所有的Prompt、评测集、错误日志滚动复盘一遍,看看有没有能合并的步骤、有没有能删掉的冗余。AI工程的代码量不大,真正的复杂度都在边界、数据和系统设计里。保持精简和可控,比堆功能更重要。
还有一点,我在实际项目里体会到:构建AI工程不是选最聪明的模型,而是让每一层都变得可测量、可回滚、可解释。哪怕模型的输出是概率性的,只要我们能把不确定性约束在可控范围内,系统整体就是稳定的。这一点,是我从零搭建这套体系时最核心的收获。