搞AI工程这件事我从2023年初做到现在前前后后经历了从调一下大模型接口就完事到认真把AI系统当成一套完整工程体系来设计的转变。今天这篇文章想把从零开始搞AI工程这条路线完整梳理一遍围绕模型接入、提示词设计、Agent开发、测试评估这条主线把我踩过的坑和沉淀下来的做法一次性倒出来。适合刚入行的后端开发、想转AI方向的前端和测试同学也适合那些已经调过API但总觉得差点工程味的人。我见过太多项目死在第一阶段接上大模型APIprompt写了个大概demo能跑通一上真实数据就崩。不是模型不够强而是压根没把AI当作一套需要设计、需要测试、需要迭代的系统来对待。AI工程的核心不是学会调用某个模型而是掌握一套应对不确定输出的工程方法。1. 先把AI工程这件事想明白1.1 它和传统软件开发的核心区别传统后端开发里同样的输入必然产生同样的输出出bug了可以靠断点、日志一步步定位。AI工程完全不一样最难受的点在于给你同一个prompt模型两次返回的结果可能不一样而且它错了还经常不承认。这就带来三个传统工程里不太会遇到的问题。第一不确定性管理输出是概率性的你得在设计阶段就假设它会出错而不是假设它会正确。第二质量评估困难没有明确的断言不能说输出预期结果得靠人去判断、靠规则去抽检、靠评测集去量化。第三成本与延迟波动不同的输入长度、输出长度、工具调用次数直接导致花费和响应时间大幅变化这在传统接口里很少见。我自己的体会是做AI工程必须接受一个事实你控制不了模型内部的推理过程只能控制输入、约束输出格式、设计兜底逻辑、建立评测闭环。把这四件事做好系统的稳定性就能从全靠运气变成基本可控。1.2 AI工程的五个分层我习惯把一套完整的AI工程系统拆成五个层从下往上分别是接入层、语义层、工具层、应用层、评估层。接入层管模型API、鉴权、重试、降级语义层管提示词模板、检索增强RAG、上下文组装工具层负责给模型提供可调用的函数和外部能力应用层是业务流程编排比如客服对话、内容生成、代码审查评估层是容易被忽略但最重要的部分负责把线上日志、用户反馈、评测用例汇总成可量化的指标。这五层不是随意划分的每层解决一个独立的问题。接入层解决模型挂了怎么办语义层解决怎么让模型更准确地理解任务工具层解决怎么让模型能真正干活应用层解决怎么编排多个能力完成业务闭环评估层解决怎么知道这套系统改得好不好。如果一上来就直接写业务代码不考虑这五层的边界后面每次调整prompt或者换模型都会牵一发动全身。2. 从零搭建AI工程的技术栈与架构选择2.1 接入层模型选型与统一封装模型选型是第一个坑。很多团队上来就选最大最贵的模型其实大部分业务场景用中等规模的模型就够了。我常用的选型思路是这样的先用一个偏强的模型跑通demo确认效果边界再用一批真实样本去对比中型模型看质量损失是否能接受。比如做结构化信息抽取gpt-4o-mini或者更便宜的国产模型完全够用没必要上旗舰型号但做复杂的多步推理Agent就值得用推理能力更强的模型。接入层一定要做统一封装。不管后面用哪个厂商的模型对外暴露的接口应该保持一致。我通常封装一个LLMClient类统一处理API鉴权、超时、重试、流式返回、错误分类。下面是我沉淀过的一个最小封装import os import time from openai import OpenAI class LLMClient: def __init__(self, model: str, base_url: str | None None): self.client OpenAI( api_keyos.getenv(LLM_API_KEY), base_urlbase_url or os.getenv(LLM_BASE_URL), ) self.model model def call( self, system_prompt: str, user_content: str, temperature: float 0.3, max_tokens: int 2000, retry: int 3, ) - str: for attempt in range(retry): try: resp self.client.chat.completions.create( modelself.model, messages[ {role: system, content: system_prompt}, {role: user, content: user_content}, ], temperaturetemperature, max_tokensmax_tokens, ) return resp.choices[0].message.content except Exception as e: if attempt retry - 1: raise time.sleep(2 ** attempt) # 指数退避 return 这个封装看起来简单但解决了几个实际问题统一了系统提示词和用户内容的入口把重试逻辑收敛到一处后续换模型或者接多个模型时业务代码完全不用改。2.2 语义层提示词工程的落地细节提示词工程不是写几句漂亮话让模型听懂而是一套可复用、可测试、可版本管理的方案。我建议把提示词拆成几个固定模块角色定义、任务说明、输入输出格式、约束条件、示例。角色定义告诉模型以什么身份处理问题任务说明描述目标和边界输入输出格式用JSON Schema或Markdown模板约定约束条件列出不许做什么示例给出1到3个典型输入输出对。示例的选择很关键。我踩过的坑是给模型看的示例太特殊导致模型把示例当成了唯一正确答案反而把其他场景答偏了。正确做法是示例要覆盖典型分布最好包含一个边界情况。比如做意图识别示例里既要有明确的查询天气意图也要有模糊的明天出门要带伞吗这类隐含意图模型才能学会泛化。系统提示词里温度参数也值得重视。做事实性抽取、分类、代码生成温度设成0到0.3就行减少随机性做文案润色、创意写作、头脑风暴温度可以调到0.7到1.0。千万别所有任务都用一个默认值。我见过有人做提取任务设了0.7结果同一个合同每次抽出来的字段都不一样排查了半天才发现是温度的问题。2.3 语义层RAG的搭建与检索优化RAG是目前解决大模型知识不足、幻觉问题的主流方案。核心思路是用户问题进来先从自己的知识库里检索出相关片段把片段拼接进上下文让模型基于这些内容回答。搭建RAG有几个关键参数需要实测。分块大小建议从300到500字开始测太小导致语义不完整太大导致检索噪音多且浪费token重叠长度设为分块大小的10%到15%避免关键信息被切断向量模型的选择直接影响召回质量中文场景实测下来bge系列和m3e等模型效果不错英文场景可以用OpenAI的text-embedding-3-small。检索方式上我一般用混合检索向量召回加上关键词召回再用RFF或简单加权合并结果。纯向量检索在专业术语、人名、编号上经常召不回加上关键词检索能补上这块短板。注意RAG的效果90%取决于能不能检索到对的东西而不是模型多强。先花时间清洗知识库、优化分块和检索再考虑换更强的大模型。3. 让AI具备干活能力Agent与工具调用3.1 Agent的基本运转逻辑Agent和普通对话的最大区别在于它能调用工具、执行动作、根据结果继续推理直到完成目标。最简单的Agent循环是拿到用户任务 → 模型决定调用哪个工具 → 执行工具拿到结果 → 把结果反馈给模型 → 模型判断任务是否完成没完成就继续下一步。我最初以为Agent很神秘其实核心就是函数调用function calling。给模型声明一批工具函数模型输出一个结构化的调用请求代码负责执行再把结果塞回对话里。关键在于工具函数的描述写得是否清楚模型才能判断什么时候该调、参数该怎么填。我踩过的坑是工具描述写得太简略模型经常把参数填错比如日期格式、单位换算这类问题。3.2 工具注册与参数设计工具注册的关键是把每个函数的名称、描述、参数结构定义清楚。我用JSON Schema格式声明参数举一个查询订单状态的例子order_tool { type: function, function: { name: query_order_status, description: 根据订单号查询订单当前状态和物流信息订单号格式为纯数字字符串, parameters: { type: object, properties: { order_id: { type: string, description: 用户提供的订单号例如 202501012345 } }, required: [order_id] } } }这套声明的经验是description里写清楚参数格式、取值范围、常见错误模型填错的概率会低很多。还有一个小技巧如果用户没提供订单号可以在工具参数里加一个required检查在调用前做一次参数校验而不是直接透传给模型因为模型生成的参数偶尔会幻觉出根本不存在的订单号。3.3 多AI协作的编排方式单Agent的能力有限复杂任务可以拆成多Agent协作。我这里说的多Agent不是指那种动不动就开十几个角色的军团而是务实的拆分方式一个规划者Agent负责任务拆分若干执行者Agent各自负责一个子任务一个审查者Agent检验最终结果。我实现过一个文档分析系统规划者先判断文档类型、确定分析维度再把任务分给数据抽取、摘要生成、风险识别三个执行者最后审查者做一遍完整性校验并汇总输出。跑通的要点是每个执行者的输入输出格式必须严格约定否则它们之间互相传话会出现信息丢失子任务之间的依赖关系要在规划阶段理顺避免出现一个Agent等另一个Agent结果导致循环等待的情况。4. 工程质量与测试评估4.1 怎么评估一个AI系统好不好用没有评估体系AI工程就无从优化。我建议做一个评测集不要用感觉要用数据说话。评测集至少包含300到500条有代表性的样本每条样本标注好标准答案或者评判标准覆盖正常场景、边界场景、错误输入。评估时可以用两种方式有标准答案的任务用精确匹配或相似度比如抽取任务提取出来的字段比对是否一致没有标准答案的开放任务用LLM作为裁判让一个强模型按评分标准打分。我用下来的心得是LLM裁判要给出明确的评分维度和示例比如内容完整性、准确性、格式合规度各占多少分否则它打分不稳定。评测集要固定下来每次改动prompt、换模型、调RAG参数后跑同一套评测集对比指标变化这叫回归测试。4.2 数据冻结与版本管理AI系统改代码之外还要管prompt和数据。prompt的每次调整都应该纳入版本管理我习惯把提示词模板、评测集、测试结果放到同一个目录结构里每次迭代记录一个版本号这样后面出现线上效果回退能立刻定位到是哪一次改动引起的。评测数据本身也要冻结。线上的真实用户反馈会不断产生新样本但不要随手往评测集里加而要先人工标注、确认无误后再进测试集否则脏数据混进去评测指标会失真。我自己吃过这个亏往评测集里加了一大批重复的客服问题准确率虚高到90%上线后实际效果只有70%出头后来发现是评测集里重复样本太多导致的。4.3 成本与延迟的平衡模型调用是有成本的AI工程必须算经济账。我常用三层策略控成本第一层简单任务用小模型、少token比如意图识别用迷你模型第二层复杂任务先让模型做分类或路由能走小模型的就不走大模型第三层设置输出长度上限和调用次数上限防止Agent陷入死循环烧钱。延迟方面流式输出能大幅改善用户体验对不需要流式输出的内部任务可以用批量异步调用。还有一个容易被忽略的点缓存。完全相同的用户输入可以直接缓存结果相似输入可以用语义缓存向量检索命中高相似度的回答就直接返回省一次模型调用。实测下来加了语义缓存后我们的查询类接口成本降了约三成平均延迟从2秒降到0.4秒。5. 常见问题与排查技巧实录5.1 模型输出格式不稳定这是最常遇到的问题。要求模型输出JSON它偶尔夹带解释文字、或者把JSON包在Markdown代码块里、甚至直接截断。解决思路分两层第一层在系统提示词里明确写只输出合法的JSON不要任何额外说明并提供一个严格示例第二层代码侧做好解析兜底先把响应里的Markdown代码块剥掉再提取第一个{到最后一个}之间的内容用json.loads解析解析失败就给默认值并记录日志。这个兜底逻辑非常重要因为无论模型多强线上总会有解析失败的case直接把异常抛给用户是不可接受的。5.2 上下文窗口被撑爆Agent一次交互可能产生很多轮工具调用结果上下文越来越长最终超过模型窗口限制。我的做法有三个第一只保留必要的对话轮次超过一定轮数后把早期内容总结成摘要替换掉原文第二长文档不一次性塞进去用RAG检索相关片段第三工具调用结果尽量精简只保留关键字段不把整个返回体塞进去。比如查询订单工具返回几十个字段实际只需要状态和时间就截取这两个字段能省下大量token。5.3 幻觉与虚假信息模型一本正经地编造不存在的接口、法条、数据这是最难处理的。我的经验是三点一是强制要求模型基于提供的上下文回答如果上下文中没有相关信息明确说不知道二是关键数据要求模型给出溯源回答的每个结论都标出来源片段编号三是在业务流程里加一道人工复核节点高风险操作必须人工确认不能全自动放行。5.4 排查方法论AI系统的排查要和传统系统区别对待。遇到线上某个回答不对先看这五个地方输入是否被正确处理、检索结果是否相关、提示词是否覆盖这个场景、工具调用参数是否正确、输出解析是否成功。多数问题出在检索和解析这两环而不是模型本身。排查的时候一定要把完整的上下文日志打出来包括系统提示词、用户输入、检索片段、模型原始输出、解析后的结果缺一环都很难定位。我现在的习惯是给每一条线上请求生成一个trace_id从入口到模型调用到工具执行全链路埋点出了问题直接按trace_id拉日志一分钟就能定位到是哪一环出的问题。这套东西做起来不复杂但对AI系统的可维护性是决定性的。最后再分享一个小技巧AI工程里最值钱的东西不是你调通了哪个API而是你沉淀下来的提示词模板、评测集和复盘文档。每踩一次坑就把原因和解决方法写进团队的知识库里下一轮迭代的效率会高很多。从零开始搞AI工程难的不是起点而是你能不能坚持建立这套闭环。
阅读完成 · 觉得有帮助?