从零开始AI工程:从模型调用到稳定上线的完整实践路径

发布时间:2026/11/4 5:43:46
从零开始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工程里最核心也最容易被低估的环节。大模型不是说你把所有内容都塞进去就完事,上下文窗口有限,而且越长,模型越容易丢失关键信息,延迟和成本也随之上涨。我自己总结了一个三层原则:

  1. 只放必要的信息。能用检索摘要解决的,不要把全量文档塞进提示词。
  2. 动态裁剪。按token预估函数先算一下,超出预算就做“最近N轮对话保留 + 早期对话摘要化”的处理。
  3. 结构化存储。把对话历史、检索结果、用户画像拆成独立字段,按任务组装,而不是拼成一大段纯文本。

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-else,Agent则由模型根据用户的指令和当前上下文,动态决定调用哪个工具。

这里我踩过一个很深的坑:一开始我们给了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贯穿整个业务链路的追踪ID
Prompt版本用了哪一版提示词模板
模型版本哪个模型、哪个供应商
输入/输出摘要方便检索,不做全文存储
token用量输入/输出token数,方便对账
耗时与重试次数定位性能问题
业务结果该输出最终是否被采用、是否触发兜底

有了这套日志,我才能做“线下重放”:用户说回答质量差,我不用跑去问用户“当时怎么问的”,直接按请求ID把日志拉出来,用同一份输入重新跑一遍,对比新的模型输出和当时的输出。这个过程帮我们修掉了大量“偶发但真实存在”的Badcase。日志这件事不要等上线之后再补,第一版就带上,不然后面欠的债只会越来越多。

5.3 回归测试与版本升级流程

当评估集和日志就位之后,提示词和模型的每次变动都应该走一遍回归:

  1. 在评估集上跑旧的prompt版本,记录基线指标。
  2. 跑新的prompt版本,对比指标差异。
  3. 重点看“从好变差”的case,决定是调整还是回滚。
  4. 灰度发布,先在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工程路线时,少踩几个我踩过的坑。