从零开始AI工程:从模型调用到稳定上线的完整实践路径
一年前有朋友问我“AI工程从零开始到底怎么入门”的时候我正在为一个RAG项目的检索效果熬夜。当时我们团队内部流行一句话跑通一个AI Demo只需要一个下午把一个AI功能稳定放上生产需要一整个冬天。这话看着夸张但真正从后端开发转过来做AI工程之后你会发现它一点也不夸张。AI工程并不是“调用大模型接口”这么简单而是一整条涉及模型选型、提示词管理、上下文预算、工具编排、评估回归、成本治理的复杂链路。这篇文章会把我的完整路径、踩坑记录和最终沉淀下来的工程方式写下来适合那些跟我一样从传统开发转过来、或者刚接触AI应用层、想系统做AI工程的朋友。我不打算讲那些教科书式的概念只讲我实际验证过的东西以及那些说了很多次但依然有人踩的坑。1. 从零开始的第一步不是选模型而是先分清demo和系统1.1 AI工程和传统软件工程的本质差异我第一次把大模型接入业务代码的时候第一反应是“这不就是一个HTTP调用吗”。但很快我就发现传统软件工程的所有默认前提在AI工程里全都不成立。传统接口的返回值是确定性的传相同参数永远返回相同结果AI接口不是。传统系统可以精确测试因为预期输出是可枚举的AI系统没有标准答案只有“质量好坏”。从认知上做一次彻底的切换其实是第一关。我把这个差别理解为传统开发像解一元二次方程答案就摆在那里你只要把步骤写对AI工程更像带一个很有天赋但偶尔走神的新人同事你需要交代背景、说明边界、给足示例、检查结果、准备兜底。它做对90%的时候你几乎感觉不到它的存在但剩下的10%如果没被拦住它会表现得非常自信然后用一整段流畅的话给出错误的结论。所以搞AI工程首先接受一个事实系统的核心是一个概率模型工程的目标不是消除概率性而是把概率性控制在业务可接受的范围内。这个心态不转换后面所有工具、框架、方法论都学不进去。我见过太多人卡在第一步因为他们始终在用“传统系统必须100%正确”的标准要求大模型然后陷入无休止的提示词调优反而忽略了整个系统层面的兜底设计。1.2 为什么人人都能跑通demo但真正交付的人少我见过太多人包括当时的我卡在同一个位置拿一个jupyter notebook或者脚本调通了大模型接口觉得自己“会AI工程了”。但一旦放进真实业务场景立刻四分五裂。原因通常集中在几个点上真实输入千奇百怪。Demo里你喂给模型的是你精心准备好的句子生产环境里用户会给你半句话、错别字、中英混杂、甚至一大段粘贴的合同正文。没有评估标准。你不知道“当前提示词”和“修改后的提示词”到底哪个好只能靠感觉而感觉在十万次调用里是失效的。没有上下文管理。真实业务的长文本、多轮对话、历史记录会把上下文窗口撑爆输出质量断崖式下降。没有兜底和降级方案。模型接口超时、限流、返回非结构化内容时业务直接就挂了。所以“从零开始AI工程”里的“从零”我认为不是从安装pycharm或者跑通API开始而是从搭建一套“能持续演进的工程骨架”开始。也正因为这个判断我的技术路线不是随便抓一个开源框架就开干而是先把基础设施、提示词、评估、可观测性四件事想清楚。前面几次失败让我意识到AI工程真正拼的其实不是模型的“聪明程度”而是围绕模型搭起来的那一圈工程能力。2. 基础设施选型先把“模型从哪来”这个地基搭稳2.1 模型选型不是越强越好选模型通常是最容易让人纠结的环节但我的经验恰恰相反模型不是越强越好而是“够用、稳定、可监控”最好。我们团队在选型时先列了一张判断维度表判断维度关注点我的经验能力是否覆盖任务所需推理、指令理解、输出格式简单分类任务选小模型复杂逻辑推理选强模型稳定性输出格式漂移率、接口可用性大厂商业化API通常更稳定但需要评估数据合规成本输入/输出单价调用量放大后的总成本一定要算峰值场景而不是测试时的几次调用延迟单次响应时间是否影响用户体验交互场景要求高异步任务可以放宽数据边界数据是否允许出域、是否有私有化需求涉及隐私数据优先考虑本地部署实际项目中我采用的是“分级路由”策略简单任务意图识别、格式规整、关键词抽取用便宜、快的小模型复杂任务长文档理解、复杂推理、多步骤规划用更强的模型。像网关一样在系统入口做一次请求分类大概能省30%到50%的成本同时整体延迟也更低。这个思路特别适合调用量放大之后越早定下来越好不然后面改路由逻辑会很痛苦。2.2 本地部署与商业API的取舍另一个典型决策是“本地部署开源模型”还是“直接用商业API”。我两条路都走过各有各的坑。本地部署比如Ollama、vLLM这一套生态的好处是数据不用出域敏感场景能过合规调用量大了之后边际成本低而且可以针对特定任务微调但坏处也很明显你需要GPU服务器需要处理推理框架的版本兼容问题需要自己监控显存、吞吐和排队还需要面对开源模型在复杂指令理解上的差距。我原先以为本地部署门槛不高结果第一次跑vLLM就遇到CUDA版本和模型权重不匹配的问题光环境排查就花了两天。商业API的好处是开箱即用、模型能力逐年拉高、配套工具成熟坏处是数据出域、单次调用成本按token算、以及你被对方平台的稳定性和计价策略绑定。我最后采用的方案是“混合路由”核心的、涉及敏感数据的链路走本地小模型做初筛和抽取需要高质量推理的部分走商业API。两个入口封装在一个统一的LLM接口层里对业务代码完全透明。这个方案真正落地之后既保住了隐私底线也没有放弃大模型的能力上限。2.3 开发环境最小配置现在很多人一上来就装一堆重量级框架其实没必要。我给自己定了一个“最小化可运行”的标准这套东西从项目第一天用到现在Python 3.10依赖管理用uv或poetry环境隔离必须从一开始就做。所有的API Key、模型地址、模型名称、路由规则放在环境变量或配置中心严禁写死在代码里。把所有模型调用封装成一个模块统一处理超时、重试、日志。业务代码只调用一个complete()方法。提示词和工具定义等都要单独放在配置目录下不混在业务代码里。一个最小接口层的结构大致是class LLMClient: def __init__(self, provider: str, model: str): self.provider provider self.model model def complete(self, messages: list[dict], **kwargs) - LLMResponse: # 统一在这里做超时控制、重试、日志记录 pass这个封装看着简单但它保证了一件事将来不管换模型还是换供应商业务代码一行都不用改。我在做工程骨架时最早定下的就是这条边界。你越早统一入口后面做缓存、做监控、做成本统计就越省事。3. 提示词工程化的落地写法版本管理、上下文预算、失败分支3.1 把提示词当成代码来管理很多刚入门的朋友把Prompt Engineering理解为“写一段优秀的提示词”这没错但工程化之后它远不止是一段话。提示词是会演进的东西。同一个功能今天用v3版本明天改成v5你怎么知道v5比v3好没有版本管理、没有回归测试就没有答案。我习惯把每个提示词拆成四个槽位system role模型的身份、任务边界、语气规范。business logic业务流程相关规则比如必须引用来源、禁止编造。few-shot examples典型输入输出示例3到5条最佳。output format输出结构定义尽量要求JSON等结构化格式。四个槽位放在独立的配置文件里谁改了哪个部分一目了然。同时每次修改都要在评估集上跑一遍。这样提示词就从“随意改的一行文字”变成了“有版本、有测试、可回滚的代码资产”。我一度因为提示词改得太随意导致线上输出行为完全变了还没发现最后是靠日志里记录的prompt版本才定位到问题那时候才知道版本管理这件事不是流程负担而是救命网。3.2 上下文管理的本质是token预算上下文管理是我认为AI工程里最核心也最容易被低估的环节。大模型不是说你把所有内容都塞进去就完事上下文窗口有限而且越长模型越容易丢失关键信息延迟和成本也随之上涨。我自己总结了一个三层原则只放必要的信息。能用检索摘要解决的不要把全量文档塞进提示词。动态裁剪。按token预估函数先算一下超出预算就做“最近N轮对话保留 早期对话摘要化”的处理。结构化存储。把对话历史、检索结果、用户画像拆成独立字段按任务组装而不是拼成一大段纯文本。token预估有个粗略的公式中英文混合场景下大概1个token约等于1到2个汉字英文单词约等于1到1.3个token。我把这个估算函数写进代码里组装请求前先检查def estimate_tokens(text: str) - int: # 粗略估算中文字符按1.5英文单词按1.2 chinese_chars sum(1 for c in text if \u4e00 c \u9fff) other_tokens len(text.split()) return int(chinese_chars * 1.5 other_tokens * 1.2)超出预算时优先压缩“业务价值最低”的输入比如历史对话可以摘要化检索文档可以按相关性截断。宁可少给信息给精准信息也不要让大模型面对一堆噪声自己找重点。你需要记住上下文管理本质上是在做信息筛选而不是信息堆砌。3.3 输出解析与异常兜底我第一次做结构化输出时让模型“输出JSON”它确实返回了JSON但前面多了一行“好的以下是结果”——就这一行json.loads直接崩了。后来我总结了一套三层兜底第一层输出格式严格化。提示词里写清楚“只输出JSON不要包含任何额外文字”能解决大部分情况。第二层解析失败自动修复。把模型输出扔给一个“修复提示词”让它清理非法JSON再解析一次。第三层返回业务默认值。修复仍然失败时不能把报错抛给用户给出一个降级结果并记录日志。def parse_model_output(content: str) - dict: try: return json.loads(content) except json.JSONDecodeError: # 尝试清理代码块标记 cleaned content.strip().removeprefix(json).removesuffix().strip() return json.loads(cleaned)输出解析这一块看着不起眼但在生产环境里它决定了系统的稳定性。很多AI应用挂掉不是因为模型能力不够而是因为“模型给了95分的内容代码却没有能力消化那5分的格式抖动”。这类问题做多了你就知道越是不起眼的边界处理越能体现工程功底。4. 从问答到Agent工具调用与任务编排的工程实践4.1 Agent的本质让模型接管部分路由决策我们聊到“AI Agent”时很多人的第一反应是“能自动干活的机器人”。但从工程角度我更愿意把它理解成模型在系统里承担了一部分“路由决策”的职责。传统函数调用链是人肉写死的if-elseAgent则由模型根据用户的指令和当前上下文动态决定调用哪个工具。这里我踩过一个很深的坑一开始我们给了Agent一堆工具以为它能像科幻电影一样自动做完整个任务结果它经常在工具之间反复横跳把简单问题搞复杂。后来我意识到工程上要做的是把Agent的“决策自由度”限制在一个合理的边界内模型负责选择工具、判断参数代码负责权限校验、执行超时、结果校验。简单说模型是大脑但方向盘上得有程控的限位器。后来我们把每个Agent的应用场景限定得很窄只让它在一个明确的业务目标内做决策效果立刻稳定了很多。4.2 工具注册与调用的落地细节工具调用落地时最核心的是工具描述和函数Schema。每个工具必须定义清楚名称、用途、参数结构。这个Schema会被发给模型模型根据它生成调用参数。{ name: query_weather, description: 查询指定城市的当前天气, parameters: { type: object, properties: { city: {type: string, description: 城市名如北京} }, required: [city] } }实际执行时有几个细节必须处理工具执行的超时时间防止Agent把某个工具卡死工具返回内容要截断否则一个数据库查询返回两万行直接把上下文撑爆工具执行失败的错误信息要原样传回给模型让它能基于错误调整下一步。最后一个细节特别重要模型如果看不到失败原因会反复用同样的错误参数重试浪费token和时间用户体感也非常差。4.3 编排模式的选择顺序、并行、条件分支Agent不是只能做“无限多轮对话”。我实际做下来发现工程上更好用的做法是把任务划分成多个阶段用显式流程控制加上Agent分支处理。常见编排模式有顺序执行先检索再总结每个步骤都依赖前一个结果。并行执行同时调用多个工具拿回结果后汇总适合信息收集类任务。条件分支根据前面结果决定走哪条后续路径适合售后、客服类场景。循环对于“执行-验证-重试”的任务设置最大循环次数防止模型死循环。我见过不少团队把Agent做到完全开放结果上线后没人能解释输出为什么是这个样子。我的建议是能用预定义流程解决的问题就不要开放决策Agent真正发挥价值的地方是在那些“流程中确实需要动态判断”的分支节点上。把自由度留给需要的地方其他位置用代码锁死。5. 上线前必须补的课评估集、日志链路与回归5.1 怎么搭一个能帮你做决策的评估集一个AI应用能不能上线不该取决于“我试了几条用例觉得不错”而应该取决于评估集上的指标。我从零开始搭评估集时分了三步走第一步收集真实case。从历史日志、客服记录、用户反馈里挑选至少50到100条样本覆盖正常、边界、异常三大类。我最开始抠门只选10条结果每次改完提示词都觉得“效果好多了”一上线就被打脸。后来样本量上去之后那些自我感动式的优化基本消失了。第二步定义判断标准。对每一条case明确“什么样的输出算对”。比如知识库问答判断标准可以拆成答案是否准确、是否有来源引用、语气是否合规。每一条case标注好期望行为。第三步设计评分器。简单场景用规则检查比如是否包含指定字段、是否引用正确来源复杂语义场景用大模型打分让另一个模型当裁判按1到5分直接给质量标准。我个人经验评分模型不要用被评估的同一个模型给自己人打分总有偏向。5.2 日志不只要记“调了什么”还要能重放AI工程的日志比传统后端日志更重要也更难做。传统系统你记下入参出参就行AI系统里你还得知道prompt模板版本、模型版本、随机参数、token用量、耗时、以及最终业务结果是否被采纳。我在项目里给每次模型调用统一记录了这些字段字段说明请求ID贯穿整个业务链路的追踪IDPrompt版本用了哪一版提示词模板模型版本哪个模型、哪个供应商输入/输出摘要方便检索不做全文存储token用量输入/输出token数方便对账耗时与重试次数定位性能问题业务结果该输出最终是否被采用、是否触发兜底有了这套日志我才能做“线下重放”用户说回答质量差我不用跑去问用户“当时怎么问的”直接按请求ID把日志拉出来用同一份输入重新跑一遍对比新的模型输出和当时的输出。这个过程帮我们修掉了大量“偶发但真实存在”的Badcase。日志这件事不要等上线之后再补第一版就带上不然后面欠的债只会越来越多。5.3 回归测试与版本升级流程当评估集和日志就位之后提示词和模型的每次变动都应该走一遍回归在评估集上跑旧的prompt版本记录基线指标。跑新的prompt版本对比指标差异。重点看“从好变差”的case决定是调整还是回滚。灰度发布先在5%流量上观察日志和用户反馈。这个过程听上去很重但做一次之后你会发现它其实是把原来“靠感觉优化”变成了“靠数据决策”的必经之路。也是从这一步开始我才觉得自己做的东西能叫“AI工程”而不是“调参魔法”。你甚至可以把这套流程用脚本半自动化但核心不是自动化而是“每次都带着基线指标上线”这个习惯。6. 成本、延迟与安全三个容易被忽视的工程变量6.1 成本的精算方法很多项目死在了“谈技术的时候很兴奋月底看账单很沉默”上。大模型成本不是按次算的是按token算的。你得把输入、输出、缓存、重试全部算进去。单次调用成本公式非常简单成本 输入token × 输入单价 输出token × 输出单价但放大到100万次调用之后差别就很吓人了。如果一个任务平均输入2000 token、输出500 token商用API按一个大概的价位一次调用成本约几厘钱看起来不高可一旦日活10万、每个用户触发10次调用一天就是100万次一个月就是几万块钱量级。这也是为什么前端一定要做“分级路由缓存去重”。我在实际项目里做了三件事来压成本一是内容缓存相同或高度相似的问题直接返回历史结果不再调用模型二是用小模型优先处理简单任务不把所有流量都打到最大的模型上三是给输出设置合理的max_tokens上限防止模型啰嗦地把预算烧光。6.2 延迟和稳定性能并行就不要串行AI调用是可观测的但也是不稳定的。接口超时、限流、偶发5xx这些再大的平台也没法百分之百避免。工程上必须要做的就是超时时间设定、有限次重试、熔断、降级。延迟方面最常见的优化是“拆并行”。比如一个任务需要检索三个数据源如果串行调用每次1.5秒三次就是4.5秒优化成并行之后总体延迟基本就是最慢的那一次。这里需要小心并发上限和供应商限流所以我还加了一个简单的信号量控制防止一把梭把接口打爆。交互式场景我还会开流式输出让用户先看到内容逐字出现体感上比干等5秒再一次性返回好非常多。异步场景则直接走消息队列把AI任务放到后台执行完成后再推送结果。这两条优化路线几乎适用于所有AI应用先做哪个取决于你更在意用户体验还是系统吞吐。6.3 安全提示词注入与最小权限最后的变量是安全。AI应用的安全边界与传统系统不太一样最大的威胁是提示词注入用户或第三方数据里的恶意指令试图让模型执行预设之外的动作。我的工程化处理是三层输入侧过滤敏感词、异常指令模式检测可疑输入直接拒绝或标记。工具权限最小化Agent可以调用工具但每个工具背后都有独立的权限校验比如“查询订单”必须附带用户身份校验不能信模型拿着参数就去查。输出侧校验对关键信息金额、账号、地址做规则校验模型输出与数据源不一致时宁可拒绝。安全这块没有银弹。但核心逻辑很朴素别让模型拥有不受控的执行权。模型可以提出一个动作真正执行之前必须过一道代码权威门禁。7. 一个从零到一落地的实际项目复盘7.1 项目背景与需求还是用一个实际项目串一遍完整链路。去年我们给内部团队做了一个知识库问答Agent需求很朴素员工可以在系统里提问“新员工的报销流程是什么”“公司年会是什么时候”“某个项目的技术文档在哪”系统基于内部知识库回答并且必须给出引用来源。选型上因为涉及公司内部文档我们优先考虑了本地部署AI这条路线敏感数据不出域同时配合部分商业化API做复杂摘要任务。7.2 整体链路与架构取舍整个系统的核心链路是文档接入与解析 - 文本切片与向量化 - 检索召回 - 重排 - 提示词组装 - 模型生成 - 答案校验 - 记录日志文本切片是第一个坑。最开始我们按固定长度切每段512个字符结果检索效果很差因为一个完整的业务规则经常被拦腰切断。后来改成按章节和语义边界切片同时做了重叠召回质量立刻上一个台阶。这个案例很好地说明了一件事AI工程里很多问题的瓶颈不在模型而在模型外面的数据工程。重排环节我们也踩了坑。最开始只用向量检索Top-5的召回结果经常有两条完全不相关。后来加了一个轻量级重排模型对召回结果重新打一遍分最终效果稳定很多。这个思路很简单第一轮用高召回低精度的方案把候选捞回来第二轮再用更强的语义匹配做精排。7.3 提示词组装与答案校验知识库问答的提示词组装我采用的是前面讲的“四槽位”结构。System role设定“你是企业内部知识库助手只能依据提供的内容回答禁止编造”业务逻辑里写“如果检索内容没有答案明确告知员工‘知识库中未找到相关信息’并且建议联系对应部门”Few-shot示例给一正一反两个Output format要求输出结果包含answer和source两个字段。答案校验这步很关键。模型生成的回答里如果提到了“报销流程需要三个月”而实际检索文档里并没有这个数据这就在编造。我们的做法是把生成答案里的关键实体和数值抽出来去检索原文里做一次核对对不上的情况直接打回重生成。你不用去校验每一个词只要抓住“数值、时间、金额、人名、文件名”这几类高风险信息就够了。7.4 上线后的迭代节奏第一版上线后大概两周我们统计到的Badcase主要集中在三类一是检索召回不到正确内容造成“答非所问”二是多文档冲突时模型选择了错误来源三是用户问法和知识库原文表达差异太大导致召回失败。每一类都对应不同的解法召回问题靠优化切分和重排来源冲突靠提示词里增加优先级规则问法差异靠扩充同义改写案例。这里我想强调一个比较重要的经验AI项目上线不是结束而是评估集开始积累的起点。每解决一批Badcase都把典型case补进评估集防止后续改动造成回归。这个循环转起来之后系统质量是能持续向上的。单靠上线前那几十条测试样本根本兜不住真实世界的复杂度。8. 如果让我回到项目第一天我会先钉死这几件事如果时间能倒流回到我刚开始从传统后端转AI工程的那一刻我会在第一周就做这几件事而不是等踩完坑才补。第一先定义“好”再谈“用模型”。我一开始就急着接模型、写提示词整整两周没有碰评估。结果后面每次改动都是盲人摸象根本不知道哪个版本更好。后来补评估集时才发现早期很多优化其实都在原地打转。没有评估标准的AI工程后面每一步都是在赌。第二模型之外的工作才决定上限。检索质量、上下文管理、工具边界、错误兜底、日志链路这些传统工程能力才是AI应用能不能稳定运行的护城河。我见过不少团队反复换更强的模型效果却没什么起色问题就出在数据没洗干净、上下文没有管理、输出没有校验这些“非模型”的环节上。第三不确定性要管理不是消灭。接受模型偶尔出错然后把错误控制在可接受的范围内比追求“100%正确”现实得多。我的做法是给每个AI功能都配一个“兜底路径”模型失败或乱来时系统能退回到规则代码或默认回复。这套兜底设计比任何提示词技巧都更能保证线上体验。第四日志和评估是你的眼睛。没有这两样东西你甚至不知道系统是变好了还是变坏了。我在实际排查中有一个体会AI系统的很多问题看起来很玄学但只要请求ID、版本、输入输出都在手里九成问题都能定位到具体环节。因为我本人是从传统后端一步步转过来的所以这些话可能跟很多“AI速成课”讲得不一样。但真正把一个AI应用从零开始做到上线、做到稳定迭代之后我会愿意用这些踩出来的经验换掉一切更华丽的理论。也希望这篇内容能让读到这里的你在开始自己的AI工程路线时少踩几个我踩过的坑。