☰
AI工程从零到一:大模型应用落地与部署实战指南
2026/9/29 18:59:01 网站建设 项目流程

做AI工程这一年多,我最大的感受是:到处都是“三分钟跑通Demo”的教程,但真正把一个模型能力变成能上线、能维护、能迭代的产品,中间隔着一整条工程链路。“ai-engineering-from-scratch”不是某个现成仓库,也不是一门PPT课程,它代表的是从零开始搭建AI应用的一套完整打法:提示词怎么设计、模型怎么调用、Agent怎么编排、服务怎么部署、故障怎么排查。这篇文章是我自己的完整复盘,适合想系统落地AI应用的人参考,也适合那些已经会调API但总觉得差一口气的工程师。

我不会只讲概念,会把踩过的坑和验证过的套路都写出来。你如果按照这里的路线走,至少能避开我当年交过学费的几道坎。

1. 先想清楚:从零到一的AI工程到底在做什么

1.1 学模型和做工程是两条完全不同的路

很多人一上来就抱着大模型原理啃,或者只会在网页上聊天,这其实离“AI工程”还很远。工程侧真正要解决的问题有几个:怎么把杂乱输入变成模型能理解的结构,怎么让模型输出符合业务格式,怎么在模型说错时不至于直接崩给用户,怎么监控每次调用的成本和延迟。简单说,模型是大脑,工程是给大脑装上眼睛、手和记忆系统。

拿一个最简单的场景举例:你要做一个工单自动分类工具。业务输入可能是截图、语音转文字、乱糟糟的表格。你需要做图片解析、文本清洗、字段拼接,再把整理好的文本交给模型做分类输出,最后校验分类结果是不是在合法枚举里。这些环节里,模型只占了中间一小段,但它恰恰是最容易被错误使用的一环。没有工程思维的人会把原始垃圾文本直接丢给模型,效果差了就怪模型,其实问题出在输入清洗和输出约束上。

我见过一个团队花了两周调提示词,想解决“模型总是漏掉订单号”的问题。后来发现他们的上游系统把订单号格式统一成了带横杠的版本,但传给模型前又被中间处理脚本给截断了。调查了半天,问题根本不在模型,而在数据管道。这就是典型的把工程问题误当成模型问题。做AI工程的第一课不是学会调模型,而是学会区分问题到底出在哪一层。

1.2 一条可执行的从零路线图

我自己比较推荐按下面的顺序推进,每走一步都要能拿出可验收的结果:

  1. 摸清模型能力边界:用标准测试集去试同一批任务的反复输出,搞清楚什么任务模型做得稳,什么任务它天生做不好。
  2. 提示词工程:学会用系统提示、示例样例、输出格式约束来稳定行为,这是成本最低的杠杆。
  3. 工程接入:把API调用封装成函数,加上超时、重试、日志,替换掉手动调试的脚本。
  4. Agent与工具:让模型通过函数调用操作外部工具,用代码控制判断循环。
  5. 工作流与评估:把多个模型步骤串起来,建立自动化评测集,每次调整都能对比效果。
  6. 部署与运维:根据数据敏感性和成本选本地部署或云服务,补齐监控、缓存、权限。

每一步之间都有明显的依赖关系。很多人直接跳到第4步,架子搭得很漂亮,连最基础的上下文管理都做不好,后面所有环节都在还债。从零开始不是从“最新模型”开始,而是从“最可控的一条链路”开始。先保证输入输出可控,再往上叠复杂能力,这条原则我后面会反复提到。

这里有一条经验想重点说:路线图里的每一步都要有“验收标准”。比如提示词工程这一步,不要说自己“学会了”,而是给同一个任务写十组不同风格的提示词,跑同样的输入样本,把结果差异记录成表格。有了这个表格,你才真正知道哪些设计在起作用,哪些只是自我感觉良好。没有验收标准的学习,本质上是在感动自己。

2. 提示工程:把模型的脾气摸透再谈效率

2.1 系统提示与示例样例的配合方式

提示词工程(prompt engineering)经常被误解成“写好一大段话”。其实关键在于你如何设计模型收到的上下文结构。系统提示用来定义长期身份和约束,用户消息放当前任务数据,历史对话负责衔接前文。我一般会这样组织系统提示:第一段说明角色和目标,第二段列出必须遵守的硬规则,第三段给出输出格式要求。

这里给一个我做数据清洗时用过的实际模板:

系统提示: 你是数据清洗助手,任务是将用户提供的原始文本转换为标准JSON。 硬规则: 1. 只输出一个JSON对象,不要包含Markdown代码块。 2. 字段必须为:category, urgency, summary。 3. category只能是["order", "after_sale", "consult"]中的一个。 4. summary不超过50字。 用户消息: 【原始工单】刚买的键盘第三天就连不上了,联系客服半天没人回,很生气!

配合模型输出后,还需要在代码里做一次JSON解析和枚举校验,防止模型犯低级错误。我见过很多人只依赖提示词里的“只输出JSON”就去做解析,遇到模型偶尔多包一层代码块,整个流程直接报错。这种边界情况必须靠工程代码兜底,而不是靠运气。

有一次我处理客服工单,模型在99%的情况下都听话,但突然有个工单的内容里出现了“```”字样,模型就把完整回复用Markdown代码块包起来了,解析直接失败。我后来把代码块剥离逻辑写进解析函数,才彻底解决。你要记住:提示词降低的是坏输出的概率,而工程要做的是把剩下那1%的坏输出兜住。

2.2 关键参数和控制策略

大模型接口里最常见的参数是temperature、top_p、max_tokens和stop。我的经验是:凡是做分类、抽取、格式化输出这类确定性任务,temperature调到0.2以下,top_p调到0.3左右,效果会可靠很多;凡是做文案生成、头脑风暴,temperature可以到0.8以上。max_tokens一定要设,不设的话一个失控的模型可能连续生成几千个token,账单非常难看。

还有一个容易被忽视的参数是seed。有些推理引擎支持固定随机种子,配合temperature=0,能让同一段输入在相同环境下产生几乎一致的结果。这在做自动化测试时太有用了。不过别指望完全一致,我实测下来不同硬件、不同版本引擎之间仍可能有微小差异,所以评估还是要以多次采样为准。

下面是一段简化但完整的调用示例,用OpenAI兼容接口统一封装,方便切换不同服务:

import json from openai import OpenAI client = OpenAI( base_url="http://127.0.0.1:8000/v1", api_key="local-key", timeout=30, ) def classify_ticket(text: str) -> dict: resp = client.chat.completions.create( model="qwen2.5-7b-instruct", messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": f"【原始工单】{text}"}, ], temperature=0.1, max_tokens=256, seed=42, response_format={"type": "json_object"}, ) content = resp.choices[0].message.content data = json.loads(content) if data.get("category") not in VALID_CATEGORIES: raise ValueError(f"非法分类: {data.get('category')}") return data

这里有一点必须提醒:response_format并不是所有模型都支持。本地部署的开源模型如果后端不支持该参数,代码会直接抛异常。工程上我会加一个能力探测开关,或者在后端配置里关掉这个参数,再用正则和二次校验来保证输出结构。兼容层写得好,后续换模型才不伤筋动骨。

我用过一个开源模型,接口文档里写着支持JSON模式,但实际开起来经常超时;关掉JSON模式反而快很多。后来发现是这个版本的引擎对JSON模式的实现有性能缺陷。所以参数和模式一定要做真实性验证,不能只看文档,文档和实测之间的差距,往往是藏坑最多的地方。

3. Agent与工作流:让AI真正干活而不是陪聊

3.1 Agent的本质:用代码控制模型的判断循环

AI Agent是当前热词,很多人把它理解为“给模型无限自由让它自己跑”。真正可用的Agent恰恰相反,它应该是一段由代码控制的循环:模型负责思考和选择下一步动作,代码负责执行工具调用、收集结果、判断循环是否结束。

我常用的Agent骨架长这样:

def run_agent(task, max_steps=5): messages = [{"role": "system", "content": AGENT_SYSTEM}] messages.append({"role": "user", "content": task}) for step in range(max_steps): resp = chat(messages, tools=TOOLS) msg = resp.choices[0].message if not msg.tool_calls: # 模型给出最终答案,退出循环 return msg.content messages.append(msg) for call in msg.tool_calls: # 代码执行工具函数,而不是让模型自己编造结果 result = execute_tool(call.function.name, call.function.arguments) messages.append({ "role": "tool", "tool_call_id": call.id, "content": json.dumps(result, ensure_ascii=False), }) return "max_steps exceeded"

这段代码最关键的地方是max_steps限制和工具由代码执行。没有这两个设计,模型一旦进入循环就会无限烧token,甚至自己伪造工具返回结果。我还习惯把工具的函数名和参数做成白名单,每次新增工具都要过一遍权限评审,不要直接开放任意代码执行。

我见过一个很典型的事故:一个Agent接入了“执行SQL”的工具,提示词里没有做足够强的隔离。测试的时候输入一句“删除表中所有数据”,模型居然真的把工具参数生成了对应的DELETE语句,然后代码直接执行了。虽然目标库是测试库,但那次之后我把所有写操作工具都加上了“必须人工确认”的前置条件。记住:Agent工具的本质是远程控制开关,开关越大,风险越大。

3.2 工作流编排从单步到多步的实战套路

工作流(Workflow)和Agent并不冲突。工程上我更喜欢把确定性的流程和模型判断区分开:能用规则解决的用规则,需要语义判断的才交给模型。设计一个售后工单处理流程时,我会分成这样几步:

  1. 输入预处理,用规则把图片、语音统一转成文本。
  2. 模型分类并抽取关键信息。
  3. 代码进行信息补充,比如去用户库查订单状态。
  4. 模型根据补充信息生成处理建议。
  5. 人工审核环节,高风险动作必须人点头才执行。

第3步不是让模型去调数据库,而是代码查完把结果拼进上下文,再让模型做下一步判断。这是很多人容易搞反的地方。模型适合做语义理解和生成,不适合做精确查询和事务操作。你把数据库连接直接暴露给Agent,一旦提示词注入,后果很严重。

我做过一个知识库问答工作流,第一版把所有资料一股脑塞进上下文,效果差还费钱。后来改成检索增强生成:先用向量检索找出最相关的3-5个片段,只把这几个片段喂给模型,并注明了片段来源。生成答案时要求模型先判断资料是否足够,不够就明确说不知道。这个改动之后,回答质量提升得非常明显,也变相降低了幻觉概率。

这里有个细节值得展开:向量检索的切片长度怎么定。我一开始按固定512字切,结果很多段落语义被截断,检索到的片段牛头不对马嘴。后来改成按标题、段落边界做结构切分,再配合滑动窗口做重叠,效果好很多。工程里没有“万能的参数”,只有“符合你文档结构的参数”,这个要靠人工抽样检查来调整。

关于工作流里“是否要让人审核”的问题,我的原则很简单:凡是会修改数据、发送消息、扣减资金的步骤,都必须有一个人工确认节点。哪怕这个节点只是点击一下“批准”,也能拦住很多模型误判导致的直接损失。别为了“全自动”的噱头把最终控制权完全交给模型,那是给自己埋雷。

4. 本地部署:一份能落地的模型服务搭建清单

4.1 什么场景应该选择本地部署

不是所有项目都要上云调API。当我面对下面几种场景时,会优先考虑本地部署:数据不能出公司内网,业务需要完全离线运行,单次调用量很大导致按量计费成本失控,或者需要深度定制模型服务。本地部署不等于自己训练模型,大多数时候是部署开源模型,再用推理引擎提供一套OpenAI兼容接口。

我见过不少团队一上来就买卡跑70B大模型,结果显存不够、速度极慢、运维成本高得离谱。其实很多内部任务用7B到14B的量化模型就完全够用。做选择题不需要杀鸡用牛刀。选模型前先算清楚:你的输入输出平均多少token、需要多大上下文、并发量多少、单次响应目标延迟是多少。把这些数字列出来,再决定参数规模和量化等级。

成本计算也得提前做。按量计费的API虽然省事,但在批量处理场景下,一次百万级的调用很可能比你自己租一台带GPU的服务器贵得多。我帮朋友做过一个文档批量分析项目,初期用云API跑了一个星期,账单赶上半个月服务器租金,而且数据还要脱敏。后来换成内部部署小型模型,成本立刻降下来,虽然效果有轻微波动,但配合规则校验也能满足业务要求。

4.2 从零装出一个可用服务的步骤

第一步是确认基础环境。拿到一台带GPU的机器,先检查命令行工具:

git --version python --version nvidia-smi

git和python版本确认好,再确认显卡驱动和CUDA版本,这决定了推理框架怎么装。第二步是安装推理框架,我比较常用的是Ollama和vLLM,两者定位不一样:Ollama适合快速体验和个人调试,命令短,上手快;vLLM适合生产环境,吞吐高,支持并发和连续批处理,还带OpenAI兼容服务。

第三步是选择模型和量化等级。以7B模型为例,全精度FP16大概要14GB显存,INT4量化后可能只有4到5GB。如果你只有一块消费级显卡,优先选量化版本;如果显存富余,用更高精度换取效果。这里需要说一下量化对效果的影响:通用对话场景可能感知不明显,但涉及抽取类任务时,量化有时会产生更多格式错误,建议在评测集上对比后再决定。

我整理过一张简单的量化选型参考表,供你根据自己硬件情况做初步判断:

模型参数规模精度预估显存占用适合场景
7BFP1614GB左右显存充足,对效果要求高
7BINT44-5GB消费级显卡,日常任务够用
14BINT48-9GB需要更强推理能力,显卡配置较好
70BINT435GB以上复杂任务,多卡或大显存服务器

第四步是把服务跑起来,给前端或业务层提供标准接口。本地部署后一定要做并发测试,因为本地引擎的并发能力和云端的按量服务完全不同,不提前压测,上线后一个页面多点几次接口就挂了。

压测时我习惯从1个并发开始逐步往上加,同时观察显存占用和响应延迟。如果延迟突然从200ms涨到2000ms,说明已经到引擎的瓶颈附近,就要在前面加排队机制或者扩容。很多本地服务的坑不是模型不好,而是并发一高就集体超时,最后被当成模型质量问题排查了很久。

第五步是配好监控和日志。本地部署同样要记录请求数、平均延迟、显存占用、失败率。哪怕是自用的工具,也建议把这些数据落到文件或简单看板里。没有监控的本地部署就像没有仪表盘的飞机,飞得起来,但不知道什么时候会坠。

5. 技术栈选型:从原型到上线的关键取舍

5.1 语言和框架别盲目跟风

AI工程的主流程我建议用Python,因为模型生态、数据处理库和Agent示例都在Python这边最全。但你如果是在已有Java或TypeScript团队里做集成,硬上一套Python服务反而增加运维复杂度。Java生态里有Spring AI这类集成方案,TypeScript社区也有类型安全的AI框架,都可以用。重点不是语言多热门,而是团队能不能长期维护。

我见过最尴尬的选型是:用一个看起来很酷的编排框架,把流程封装得特别抽象,结果框架版本一升级,文档不向下兼容,整个项目卡死。对于中小型项目,我的建议是核心调用层自己写,只把检索、缓存这些通用能力交给成熟的库。框架可以省时间,但不要让它替你决策业务结构。

这里给一份简化的语言选型对比,是我做项目时实际考量的维度:

对比维度PythonJava/Spring AITypeScript
模型生态最全,示例最多中等,企业集成方便增长快,类型安全
团队上手快,但大型工程要约束企业团队熟悉前端团队顺手
典型场景数据处理、Agent原型内部系统集成浏览器端AI应用
维护成本依赖管理需留意框架较重异步生态成熟

选型时还有一个小技巧:先做一个两周时间的“切片验证”,只把最小核心流程跑通,再评估哪个方案最符合团队现状。不要一开始就铺开架构图,两周后你会发现需求和初始想象差距很大。

5.2 从原型到产品要补的模块

Demo只关心模型能不能答对,产品还要关心下面这些模块:

  • 缓存层:重复请求直接命中,减少模型调用成本,比如按输入文本哈希做短时缓存。
  • 向量存储:负责切分文档、生成嵌入、近似检索,支撑知识库问答。
  • 评估集:沉淀一批真实业务样本,每次改动后跑一遍,避免这个修好那个坏了。
  • 日志与追踪:记录每次请求的输入、输出、token数、延迟,异常链路能回溯。
  • 限流与权限:控制调用频率,防止内部接口被滥用;敏感操作前加人工审批。

这些模块不是一开始就要全部做完,但要在一开始留出位置。我和团队协作时有个习惯:每接一个新模型能力,先建一个evaluation目录,放至少20条典型输入和期望输出,后面任何提示词修改都靠它说话,而不是靠“感觉变好了”。这个习惯帮我省了非常多来回调优的时间。

举个实际例子:有一版提示词把工单分类的准确率提升了,但抽取订单号的格式错了。因为有评估集,我立刻能发现是抽取规则被分类提示词的附加说明影响了。没有评估集的话,这类回归问题可能要过几周才被业务方发现,到时候排查成本高得多。评估集不要追求大,要追求代表性,覆盖正常情况、边界情况和明显捣乱的输入,三五十条也能管很大用。

缓存层容易被低估。模型调用再便宜,也比一次Redis读取贵几个数量级。在内部工具里,一些用户高频点击同一个按钮的请求,输入完全相同,完全可以用输入内容的哈希值做缓存,把重复调用直接干掉。我做过一个报表生成工具,加了缓存之后,模型调用量降了接近一半,体验还提升了不少,因为缓存命中时响应几乎零延迟。

6. 常见问题与排查:我踩过的坑和急救方案

6.1 模型输出不听话、格式总是错

这是最多人问的问题。我踩过最深的坑是让模型直接输出复杂嵌套JSON,它时不时就漏一个逗号或者多一层代码块。后来换成两层方案:先让模型输出一个简单的JSON结构,代码解析成功后再根据内容去补充字段;同时用pydantic做强类型校验,解析失败的请求进入重试队列,用一个修正提示词让模型重新输出。重试后成功率能接近满分,代价是极少数请求会多跑一次,但相比人工清理数据,这点成本很划算。

还有一个反直觉的经验:别在提示词里同时布置太多任务。比如让模型“先判断情绪,再提取订单号,再生成回复,再判断是否升级”时,效果反而差。拆成多个步骤,每步一个简单目标,输出质量和一致性都会有明显提升。模型不是多线程CPU,一次做好一件事,工程上才可控。

遇到输出格式错误时,我的排查顺序是:先看原始返回内容,判断是格式问题还是内容问题;再检查解析器是不是把合法内容误杀了;接着看是不是输入里包含了类似代码块的干扰文本;最后才考虑调提示词。很多时候改解析器比改提示词更快、更可靠。

6.2 上下文丢失、并发报错和成本失控怎么办

上下文丢失最常见的原因是超过了模型的上下文窗口,或者历史消息里塞了太多噪音。我的处理办法是给历史对话做滚动摘要:超过一定轮数后,把旧对话用模型压缩成一段总结,只保留最近几轮原文。这样既保留长期信息,又把token开销控制住。并发报错则要区分是后端引擎扛不住还是网络超时。本地方案先用压测工具打一下最大并发,再在前面加一层队列,超时时间设置成30秒以上并配合重试策略。

这里把三类高频问题的排查方向整理成一张速查表:

问题现象可能原因排查方向急救手段
答案经常答非所问上下文被无关内容撑爆检查请求里的messages长度和窗口占用做滚动摘要,只保留关键信息
并发一高就报错推理引擎带宽不足或超时配置太短看压测曲线和错误日志的HTTP状态码加排队、限流、加大超时时间
成本突然爆涨循环调用、缓存失效、没有上限检查日志里的调用次数和token总数加总预算熔断,检查循环退出条件

成本失控是一个容易被忽视的事故现场。我做过一个批量处理任务,脚本写了个双层循环忘记退出,一晚跑了上百万次调用,账单直接爆表。后来我给自己立了规矩:所有模型调用统一走一个封装函数,函数里默认打日志、统计token数;批处理任务必须设置总预算上限,达到阈值就自动熔断。别高估自己在深夜的清醒程度,自动化刹车比自觉更可靠。

另外一个小经验:把模型调用的日志格式固定成JSON一行一条,内容包括时间戳、模型名、输入摘要、输出摘要、token数、延迟、错误码。这样后面无论做成本分析还是故障回溯,都能直接用标准日志工具处理。别嫌麻烦,这个习惯在项目进入维护期之后,会帮你节省大量“当时到底发生了什么”的争论时间。


如果只让我说一条经验,那就是在写第一行调用代码之前,先把你的评估样本和失败兜底想清楚。我刚开始做AI工程的时候也迷信模型能力,总觉得提示词写得精妙就万事大吉,后来一次次被格式错误、上下文超限、链路超时教会做人。现在我的项目里永远有一个evaluation文件夹、一个重试队列、一张成本预算表。这三个东西不酷,但它们才是把AI从玩具变成工具的真正分界线。

最后再分享一个小技巧:每次调试完一个AI工程问题,都顺手把“问题现象、根因、解决办法、验证方式”写四行笔记放到项目docs目录下。坚持半年,你就会拥有一本完全属于你自己的AI工程避坑手册,比任何外部教程都实用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询