AI工程实战:从零搭建可靠、可迭代的AI应用系统
去年年初我接了一个内部工具优化的需求一开始以为只是换个模型、调个参数结果整整折腾了快两个月。那段时间让我彻底意识到AI项目里真正难的从来不是模型本身而是把模型放进一个可靠、可维护、可迭代的工程体系里。这也是我写这篇“ai-engineering-from-scratch”的初衷——把从零开始摸爬滚打总结出的路线、方法和坑整理出来给准备入坑AI工程、或者正被“模型效果不错但上线总出问题”折磨的同行一份能直接参考的实战清单。这篇文章不聊晦涩的数学推导也不堆概念而是围绕一个真实的端到端AI项目逐步拆解工程落地需要做哪些事、为什么要这么做、会遇到什么典型问题。适合三类人一类是刚接触AI想做点真实项目的开发者一类是已经在调模型但不知道怎么把能力稳定上线维护的算法工程师还有一类是做测试、运维想了解AI工程工作流该怎么设计的同学。1. 从零起步AI工程到底是什么我靠什么把它跑通1.1 算法、建模和AI工程分工到底差在哪很多新手会把“AI工程”和“算法建模”混为一谈但它们其实是两件事。算法建模关注的是给定数据和任务怎么训练或选用一个效果达标的模型核心是模型结构、损失函数、训练参数这些。而AI工程关注的是这个模型怎么稳定地进入业务流程怎么被人调用、被人监控、被人迭代核心是系统架构、数据流、评估闭环、部署运维。举个例子训练一个文本分类模型准确率95%这在建模视角看是成功的。但从工程视角看剩下的5%错误落到线上会产生什么后果输入格式变了怎么办模型服务挂了怎么降级用户反馈怎么回流成新的训练数据这些问题才是AI工程要解决的。我自己第一次做AI项目时就是只盯着准确率模型测试集分数很好看一上线就频繁出问题用户换了一种问法答案就偏了请求一多服务就超时没有日志出了问题完全不知道模型看到了什么输入、输出了什么结果。那段时间的体验就是模型一切正常但系统一直在报错。所以后来我重新整理思路把“从零开始做AI工程”的路线定为数据、模型、评估、部署四个环节缺一不可。1.2 从零到上线一个AI功能要经历哪些环节一个AI功能从想法到真正可用大体要经过七个环节需求定义、数据准备、方案选型、模型实现或微调、评估验证、服务化部署、监控迭代。需求定义是最容易被跳过的但也是最关键的。你要先搞清楚用户到底想问什么、容忍什么、紧急程度如何。比如做一个售后服务问答机器人用户的真实目标是“快速解决问题”而不是“回答得多有文采”。所以产品形态、允许的错误率、响应时间、成本上限都要在需求阶段定清楚。数据准备则决定了AI能力的上限。模型再强没有贴合业务场景的数据效果一样上不去。这里不只是“量够不够”还要看覆盖度、噪声比例、标注一致性。方案选型则是“用大模型API还是开源模型微调”需要综合效果、成本、数据安全、并发能力几个维度来判断。后面我会用实际案例展开讲。1.3 我推荐的六个月学习路线如果你是纯新手建议不要一上来就啃深度学习框架而是按“能跑通一个最小闭环”的思路走。我给身边同事推荐过一条路线大致是这样第一个月补Python和数据处理基础重点掌握pandas、requests、json处理能独立完成数据清洗。第二个月学习调用大模型API理解Prompt的基本写法学会用LangChain或类似工具做简单管线。第三个月挑一个小场景比如简历筛选、工单分类完整做一遍数据准备、Prompt开发、效果评估。第四个月学习FastAPI部署和服务化把写好的推理逻辑封装成接口用Docker跑起来。第五个月加入RAG检索增强生成和Agent的概念做一个带知识库的问答系统。第六个月回头优化评估闭环给项目加上自动化回归测试和监控日志。这条路线不一定适合所有人但核心思路是对的先跑通一个端到端的窄业务再逐步扩展深度。不要在第一步就陷在“我要不要学Transformer源码”里出不来。2. 核心技能拆解不敢说精通但这四块绕不开2.1 Python与数据处理AI工程的地基AI工程里几乎所有环节都绕不开数据处理。我见过不少同学模型知识很扎实但一遇到真实数据就手足无措原因就是数据处理基本功没打牢。具体来说需要掌握的核心操作包括读取csv、excel、json等各种格式用pandas做去重、填充、筛选对文本做基本的清洗比如去除多余空格、统一大小写、处理乱码把原始数据组装成适合模型输入的格式。这里有一个很容易踩的坑清洗规则不要拍脑袋定要基于数据分布。比如你去重的时候发现重复率高达30%不要直接全删而是先查一下是否真有这么多重复还是因为抓取逻辑有问题。我做过一个工单分类项目最初清洗时把所有空格删掉结果“客户经理”和“客户经 理”这两种写法全被合并了反而破坏了原有文本结构。后来改成只去除多余空格保留单空格分词。我的建议是所有数据处理步骤都用脚本记录别在Excel里手动改完就继续。因为AI项目强调可复现数据清洗逻辑也是要版本化的。这行代码注释清楚下次换一批数据还能跑团队协作时不至于靠“我记得当时我手改过”这种方式沟通。2.2 模型调用与Prompt工程把大模型用明白现在很多AI工程都是在大模型API之上做应用所以Prompt工程成了基本能力。我个人的理解是Prompt工程本质上是“用一套更精确的语言约束模型行为”。核心要素有三个角色设定、任务描述、输入输出格式。角色设定让模型知道它该用什么身份思考比如“你是售后服务专员请用温和、简洁的口吻回复客户”。任务描述要清楚说明要做什么最好包含边界条件“如果信息不足请不要猜测直接说明需要补充的信息”。输入输出格式则要约定结构比如“输出JSON包含answer和confidence两个字段”。还有一个容易被忽视的点给模型“示例”。Few-shot示例比单纯描述规则更有效。比如你要模型抽取工单里的原因类别与其写一大段规则不如给3到5条“输入-输出”对照样例模型会照猫画虎。但Prompt工程也不是万能的。我试过很多次靠反复改Prompt也无法消除某些错误这时候就该考虑换方案比如加上检索、加验证规则或者微调小模型。所以“Prompt不稳定”不一定是你写得不努力而是工程方案本身到了需要升级的时候。2.3 评估与回归测试AI项目的安全网这是AI工程里最容易被砍掉但最不该被砍掉的部分。纯传统软件开发里有单元测试、集成测试AI项目也需要对应的评估机制。没有评估你无法回答两件最基本的事这次改动是变好了还是变坏了能上线吗评估要分层第一层是面向效果的指标比如准确率、召回率、F1或者回答任务里的人工打分第二层是面向服务的指标比如响应时间、超时率、失败率第三层是面向业务的指标比如用户问题解决率、转人工率。回归测试的核心思路是维护一个“黄金评测集”。这个评测集里的样本要覆盖典型场景、边界情况、易错情况。每次修改Prompt或模型版本都拿这份评测集跑一遍对比结果。我习惯给每个样本标注预期答案然后写一个自动对比脚本输出通过率。这里有一个很实用的经验评测集规模不用太大100到200条覆盖好场景就够。关键是样本质量要高要能代表线上真实流量。千万不能用训练数据当评测集否则结果虚高线上立刻现原形。2.4 部署与监控让模型真正服务用户模型只有被用户调用才算产生价值。部署这一块我推荐从FastAPI加Docker的组合入手简单直接社区资料多。部署时最关心四件事接口设计、并发控制、缓存、日志。接口设计尽量做到输入输出结构明确不要直接把原始Prompt暴露给外部调用方可以在服务层做隔离。并发控制尤其要注意大模型推理往往比普通接口慢很多如果不加队列和超时保护一旦流量上来服务会快速打崩。日志是监控的基础至少要记录每次请求的输入、输出、耗时、模型版本、Prompt版本这样线上出问题才能回溯。监控层面可以先从三个指标做起请求量、平均耗时、错误率。如果使用了付费API还要单独统计token消耗。刚开始不用上特别复杂的监控系统记好日志、定期汇总就行。别一上来就搭Prometheus、Grafana全家桶系统复杂了反而管不住。3. 实操回放我如何从零做出一个FAQ智能问答机器人3.1 需求定义与方案选型别急着选模型这次项目背景很普通公司内部有一个运维知识库几百篇文档分散在wiki里员工遇到问题习惯在群里问但没人及时回答。需求就是做一个内部FAQ问答机器人能根据知识库内容回答问题回答不了就给出相关文档链接。需求定下来后我先做方案选型。候选方案有两个微调一个小模型让它记住知识库内容或者用检索增强生成RAG先检索文档再让大模型总结回答。我最终选了RAG原因有三个第一知识库文档会持续更新RAG不需要因为新增一篇文档就重新训练模型只要把新文档切块入库就行第二RAG的回答可以附上来源用户更信任出问题时也方便追责第三微调的成本和时间投入更大在内部工具阶段性价比不高。这个选型逻辑在大多数企业内部知识问答场景都适用。除非文档高度机密、不能出内网或者模型回答风格需要极其定制否则RAG是更稳的起点。3.2 数据清洗与知识库构建做了三件关键事原始数据是wiki导出的html和一堆pdf处理起来并不干净。我先统一转成纯文本然后用正则处理残留的HTML标签和乱码。这一步看起来很基础但做了之后发现至少10%的文档内容原本是格式错乱的不处理的话检索时会出现大量无意义字符。接下来是文档切块。这是RAG效果好坏的关键环节。我的做法是先把每篇文档按章节标题切成大块再对超过长度限制的块做二次切分。这里有一个需要注意的参数chunk_size块大小和overlap重叠长度。我试过几种组合最后用的是chunk_size512overlap64按字符数计算。块太大检索时容易混入无关内容块太小语义不完整模型读起来费劲。切完块之后我用嵌入模型给每块文本生成向量存入向量数据库。这一步我用的是常见的embedding模型维度是1024。入库前还做了一道过滤把纯表格、纯图片、空文本删掉。表格内容如果直接转成文本效果很差我后续专门写了一个表格转Markdown的逻辑再纳入知识库。做完这些知识库大概有1400多个块。数量不算大但对内部FAQ来说覆盖面已经基本够了。而且这个流程是脚本化的以后wiki有更新重新跑一遍就能同步。3.3 Prompt模板与检索增强生成RAG实现核心代码拆解RAG的推理流程可以拆成四步接收用户问题、向量检索、拼装Prompt、返回答案。我写了一个简化的Python示例便于理解整个链路def rag_answer(question): # 1. 生成问题向量 q_embedding embedding_model.encode(question) # 2. 从向量数据库检索最相关的top_k块 docs vector_db.search(q_embedding, top_k5) # 3. 拼装Prompt context \n\n.join([d[text] for d in docs]) prompt_template 你是一个企业内部运维助手。请根据下面提供的文档内容回答用户问题。 要求回答要简洁不超过200字如果文档中没有明确依据请直接说明“知识库中未找到相关信息”并建议用户联系运维组不要编造文档中没有的内容。 【文档内容】 {context} 【用户问题】 {question} prompt prompt_template.format(contextcontext, questionquestion) # 4. 调用大模型返回结果 response llm_call(prompt) return response, docs这段代码虽然简单但有几个细节值得展开说。第一top_k的选择直接影响答案质量。我最初设成3结果经常漏掉关键信息调到5之后好了一些但调成8后发现模型会把多个不相关段落混在一起开始编造连接性内容。最后停在5算是一个平衡点。第二Prompt里明确写了“不要编造文档中没有的内容”。这句听起来像废话但不写的话大模型在信息不足时会脑补而且脑补出来的答案还特别像回事。加了这句之后回答“未知”的情况明显变多虽然牺牲了一点回答率但换来的是可信度大幅提升。第三我用了一个简单的“引用来源”机制在返回结果时把检索到的文档标题一并返回没有用复杂的引用溯源算法只是在接口里多加一个source字段。用户点开来源文档就能自己确认回答是否靠谱。这种小设计对内部工具来说非常加分。3.4 评估集设计与自动化回归让每次改动都有底做完第一版我没有急着上线而是先建了一个评估集。我找了100条常见问题覆盖了网络配置、账号权限、软件安装、报销流程、会议室预约几大类。每一条都人工写好预期要点然后写一个脚本自动调用RAG服务把回答和预期做对比。对比方式不追求完全一致而是做了两层判断第一层回答里是否包含预期中2到3个核心关键词第二层是否出现“知识库中未找到”这类兜底描述——如果该答却没答就是漏答。这个评估集的用途在后续迭代中体现得非常明显。有一次我调整了切块参数期望提升检索准确率但跑完回归发现整体准确率反而降了1个百分点。如果没有评估集我根本发现不了这个回退。后来我把这套脚本放进项目的CI流程里每次代码合并前自动跑一遍相当于给AI项目上了一个保险丝。做这个踩过一个大坑评估样本里英文关键词大小写不一致导致自动对比失败。后来我统一在对比前做小写化处理。这看起来是小事但提醒我评估逻辑本身也需要被测试。3.5 用FastAPI和Docker把服务跑起来顺便解决并发问题服务化我用FastAPI实现结构很简单一个/ask接口接收问题内部调用RAG逻辑返回答案和来源文档一个/health接口做健康检查。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class AskRequest(BaseModel): question: str class AskResponse(BaseModel): answer: str sources: list[str] app.post(/ask, response_modelAskResponse) def ask(req: AskRequest): answer, docs rag_answer(req.question) return AskResponse(answeranswer, sources[d[title] for d in docs])部署时用Docker镜像里面装好Python依赖和向量数据库客户端。这里要注意的是不要把模型文件和向量数据打进同一个镜像里。因为向量数据更新频繁而模型权重几乎不变分开管理能大幅减少镜像构建时间。我是把向量数据放在一个共享存储路径容器启动时挂载进去。并发问题也同样重要。大模型API的响应时间经常在1到3秒如果接口不加限制别人用脚本连续打就会占满所有上游配额。我加了一个简单的信号量控制并发数设置为5超过的信号直接返回429提示稍后重试。同时给每个请求设置了超时时间15秒防止模型API卡住时拖垮整个服务。上线后我在日志里加了三行请求文本摘要、响应摘要、耗时毫秒数。别看就这么点信息后来排查问题全靠它们。有一次某用户连续问同一个问题响应时间从2秒变成15秒通过日志发现是向量数据库连接池被耗尽连接没有正确释放。定位到问题后我在向量数据库初始化逻辑里加了一个连接复用机制耗时立刻恢复正常。4. 工程进阶从单点调用到Agent协作工作流4.1 为什么要从单次调用走向多个环节编排FAQ问答机器人跑通之后你会发现用户的需求远比“问一答一”复杂。比如有的用户会问“我想报销差旅费但不知道发票丢了怎么办顺便告诉我流程大概需要多久。”这个问题包含了好几个意图报销流程、发票丢失处理、处理时限。单次检索加Prompt很难同时覆盖三个意图。这种场景就需要把模型调用编排成一个工作流。业界常说的Agent本质就是把一个大任务拆成几步每一步交给合适的模型或工具去执行最后汇总结果。这不玄乎就像你处理复杂问题时先查资料、再问同事、最后写邮件一样Agent只是把整个过程自动化。从工程角度看工作流编排带来的好处非常实际每个节点可以单独测试、单独替换、单独打日志。如果某个环节效果不好可以只优化那部分不用推倒重来。4.2 一个可落地的Agent工作流demo我基于FAQ机器人做了一个升级版当用户问题包含多个意图时先做意图识别再分别检索最后汇总回答。整个过程我直接用Python脚本编排没有引入重量级框架因为内部工具不需要特别复杂的Agent能力。简单示意如下def agent_flow(question): intents intent_classifier(question) # [报销流程, 发票丢失] sub_answers [] for intent in intents: docs search_by_intent(intent, question) sub_answer generate_answer(intent, docs) sub_answers.append(sub_answer) final_answer merge_answers(sub_answers) return final_answer这个流程里有几个关键点。第一意图识别本身也是一个模型调用但它只接收一个分类任务输入输出简单效果稳定不会漏掉子问题。第二每个子意图的检索范围可以收窄。比如意图是“报销流程”时只检索报销类文档减少噪声。第三汇总回答的Prompt要求模型不要重复相同内容而是把不同子答案按顺序组织成一段通顺的文字。实测下来这种“先拆后答”的方式比单次调用效果提升明显。我专门拿20条多意图问题做过测试单次调用能完整回答的只有6条换成Agent工作流后提升到了15条。虽然多花了几次API调用但在正确率面前这点成本是值得的。4.3 多模型协作与质量问题兜底在做Agent工作流时我还尝试过让两个不同的模型互相校验一个模型负责生成答案另一个模型负责检查答案是否与知识库内容矛盾。这个思路有点像让同事帮你复核一遍文档。具体做法是在生成答案后将答案和检索到的Top5文档片段一起送给“校验模型”让它判断答案是否有出处、是否与文档矛盾。如果校验不通过就把答案标记为“低置信度”在对话里主动提醒用户“答案可能不够准确建议人工确认”。这个兜底机制特别好用。因为大模型有时候会一本正经地输出错误信息单纯靠Prompt约束很难根治。引入第二道校验后明显减少了“看起来正确但实际内容错误”的输出。不过多模型协作也有代价响应时间变长成本变高。所以我没有让所有请求都走校验而是只对置信度较低的问题做二次校验。置信度怎么来的我让生成模型在返回答案的同时输出一个self_confidence字段低于阈值就走校验逻辑。这样既控制了成本又保住了效果。5. 我在实际操作中踩过的坑常见问题与排查实录5.1 Prompt结果飘忽不定怎么定位这是我遇到最多的问题。同一套Prompt上午测试效果很好下午再跑就变了一个风格。很多人第一反应是“模型抽风了”其实背后往往有更具体的原因。我自己的排查顺序是先确认输入是否变了再确认模型版本是否变了然后确认温度参数是否合理最后再怀疑Prompt本身。有一次我发现回答突然变长了很多追查下来原来是上游同事在传参时把temperature从0.1改成了0.7参数覆盖了默认配置。这类问题在工程里非常常见模型本身没变是调用方引入了不确定性。应对Prompt不稳定我积累了两个策略。第一把temperature等参数固定设置为默认值并在代码里写死不要暴露成可配置项。需要调整时走代码评审流程而不是线上随便改。第二把Prompt做成版本敏感日志里记录使用的Prompt版本号一旦效果异常能快速定位是哪一版Prompt引入的问题。5.2 成本失控的几种典型情况AI项目的成本大头是模型API调用费。我最开始没在意直到一个月末收到账单发现费用是预期的3倍。复盘后找到了几个原因第一重试机制写得太激进。模型接口偶尔超时我加了自动重试3次结果高峰期大量请求都重试了费用翻倍。后来我改成只对连接错误重试对超时不重试改为返回降级结果。第二日志里存了大量答案文本虽然费用不是这里产生的但数据存储成本涨了。我改成只存长度和摘要。第三最隐蔽的是长文档重复被切分进多个上下文。RAG检索时同一个文档的不同片段可能同时被选中导致上下文里出现大量重复内容token消耗剧增。我在检索后加了一个去重逻辑根据来源文档ID过滤重复片段成本立刻降了15%。成本控制不是上线后才做的而是一开始就要埋点统计。我给每个请求记录了token使用量按天汇总这样费用异常能及时发现而不是等月底账单来“惊喜”。5.3 数据质量引发的“模型错觉”案例有一次用户集中反馈某类问题的答案“经常是错的”。我查日志发现这类问题的知识库文档本身就有冲突同一份流程两篇文档给出了不同的截止时间。模型把两个来源都放进了上下文生成答案时做了错误的时间取舍。这个案例让我深刻明白一件事AI工程的前置条件是知识库本身要干净。模型不是数据库它没有能力判断两篇文档谁的优先级更高。你需要先通过数据治理解决冲突或者至少在Prompt里明确“当文档内容冲突时请直接说明存在两种说法不要自动选一个”。我后来做了一件事在知识库里增加了一个字段doc_priority检索时按优先级排序冲突时以高优先级文档为准。这个修复比调整模型快多了也稳多了。所以遇到“模型总说错”的反馈先别盯着模型看去翻一下喂给它的资料是不是有问题。5.4 部署环境里那些想不到的坑部署阶段我也碰到不少问题。最经典的是Python包版本不兼容。本地跑得好好的Docker里一启动就报错排查发现是C编译器版本不同导致某个依赖装不上。后来我把基础镜像固定成某个版本并且把requirements.txt里的包全部锁到精确版本号不再用范围写法原则上是“能锁多死就锁多死”。还有一次向量数据库在测试环境正常生产环境查询速度极慢。查了半天发现生产环境的向量数据库没有创建索引。这种问题在测试环境通常不会暴露因为数据量小全表扫描也快。所以我在部署检查清单里加了一项确认向量索引已创建、数据量统计正常。这些坑单独看都很小但在工程链条上会连环引爆。我的建议是维护一份“部署检查清单”每次上线前逐项过一遍。这看起来不酷但特别有效。6. AI工程后面还可以怎么扩展以及我的一点个人体会6.1 把AI测试开发放进日常流程以前提到测试大家想到的是后端接口测试和前端UI测试AI项目里测试的地位经常被边缘化。我在这个项目里尝到了甜头为RAG服务建了自动评测集之后每次改Prompt、换模型、调参数心里都有底。所以我强烈建议做AI工程的同学把测试开发作为标配。具体做的时候不复杂。你可以先从“最小回归集”开始30条高价值样本就够了维护一个简单的对比脚本每日跑一遍输出通过率变化。后面再逐步加样本加分类维度。我用的是最朴素的Python脚本加Markdown报告连Web UI都没做团队一样每天都在用。6.2 过了这么久我的真实感受是什么从我接手第一个AI工程需求到现在最大的体会是AI工程没有想象中那么玄也不需要把模型训练得多么深入才配叫AI工程师。它更像是一种综合能力把数据处理、Prompt设计、服务开发、评估运维揉在一起让AI能力在真实业务里站得住。这个过程中最容易让人抓狂的反而不是模型效果而是那些“看不到的工程债”数据不干净、Prompt不版本化、评估缺失、日志没有、部署不可复现。每一样都像一根针扎在项目生命周期的某个阶段。如果你正在从零开始做AI工程我的建议很简单先把能自动化的环节都自动化把评估和日志当成一等公民把每一次改动都记录在案。慢一点没关系稳了自然就快了。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →