ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

AI工程落地指南:从Demo到稳定上线的完整链路与实战经验

AI工程落地指南:从Demo到稳定上线的完整链路与实战经验 这两年我经常碰见一种情况很多人跑通了几个开源模型的Demo或者用API做了个小工具就觉得自己已经是AI工程师了。等真正把功能推到线上才发现从“模型能跑”到“系统能稳定服务业务”中间隔着一整条工程链路。这个链路就是AI工程要解决的核心问题。今天我想好好聊聊一个AI项目从零开始做工程化落地到底要经历哪些环节、踩过哪些坑以及有哪些可直接复用的经验。先说一个结论ai-engineering from scratch重点不在“模型”而在“工程”。模型只是链路里的一个组件真正的难点是数据怎么准备、评估怎么做、效果怎么稳定、成本怎么控制、出问题怎么排查。这篇文章我会从需求定义开始一直讲到部署上线和问题排查全程用自己做过的真实项目来举例希望你看完能少走不少弯路。1. AI工程到底在解决什么问题1.1 从“跑通Demo”到“稳定上线”之间缺了什么很多人第一次接触AI应用都是跑个现成的开源模型比如部署一个ChatGLM或者Llama然后在网页上问几句输出看起来像模像样就觉得完事了。但这和真正的AI工程化落地差了十万八千里。举个例子我见过一个项目团队用开源模型做了个文档问答功能Demo演示非常惊艳结果一到上线用户随意传一个十几页的PDF系统就开始乱答甚至把完全无关的内容说成是文档里的结论。问题出在哪不是模型选错了而是整个链路没有工程化。文档怎么解析、怎么切分、检索怎么排序、模型输出怎么约束、超时怎么处理、答错了怎么反馈这些环节全都没设计。AI工程的核心就是把这些散落的环节串起来让系统在真实业务的高不确定性下依然能稳定输出一个“虽然不完美但可用”的结果。我再补一个常见误区很多人以为AI工程就是从零手写一套深度学习框架。恰恰相反真正做工程的人会用成熟框架和工具但会用工程的视角去审视它们。你用自己的数据实测过LangChain的检索效果吗你知道某个版本的向量化模型在你这个领域的召回率是多少吗这些才是工程问题。1.2 工程化视角下的AI链路从输入到输出一个标准的AI应用至少要经过五个环节场景定义、数据工程、模型调用、评估观测、部署运维。每个环节都有一堆坑。场景定义要回答“这个功能到底给谁用、解决什么问题、能忍受多蠢的错”。数据工程要解决“数据从哪来、要不要清洗、要不要格式化、切分成多大合适”。模型调用要考虑“选哪个模型、温度调多少、超时怎么设置、要不要支持流式”。评估观测要解决“怎么知道这版改动比上一版好、用户哭诉的问题怎么复现”。部署运维要考虑“并发上来怎么办、接口挂了有没有降级方案、token成本怎么监控”。这五块缺一块项目迟早出问题。最典型的就是只关注模型调用这层其他全都不管。结果就是模型换了一个又一个效果永远不稳定因为瓶颈根本不在模型本身。2. 开始动手前先把目标和评估体系定下来2.1 别急着上模型先回答三个问题我踩过最大的坑就是团队一上来就花两周选模型、调Prompt结果做到一半才发现连业务成功的定义都没对齐。产品经理说要“提高用户找资料的效率”研发觉得是“做一个搜索框”领导觉得是“自动生成报告”。三个人对目标的想象完全不同做出来的东西自然四不像。所以每次开工之前先逼着自己回答三个问题这个AI功能的输入是什么输出是什么给谁用输入可能是一段用户提问加一份文档输出可能是一段带引用的回答。用户可能是内部客服也可能是外部访客。成功的长什么样是回答准确率超过90%还是用户平均浏览时长缩短30%还是人工客服转接率下降一半这个标准必须可量化。系统答错了会有什么后果如果是给医生看诊断建议那错误容不得半点如果是给用户推荐菜谱说错了无非重来。这个判断会直接影响你对模型能力的要求和兜底方案的设计。这三个问题看着简单但真正做完之后技术选型的范围会迅速收敛。比如容错极低的场景就要想办法约束模型输出给更严格的Prompt、用结构化输出、甚至规则校验容错高的场景就可以用速度更快的模型不用强行上大参数。2.2 离线评估指标不能只靠“感觉还行”没有评估体系就没有迭代。你改了一版Prompt凭肉眼看了五条回答觉得“好像好一点”这种判断方式在AI工程里完全不成立。AI系统的输出是概率性的可能这次运气好碰上了几个加分Case下次立刻翻车。所以必须建一套离线评估集把模型的输出量化打分。我常用的做法很简单但很有效。准备一百条到三百条真实业务问题提前写好标准答案。每次改动之后拿这一批问题跑一遍用几个维度打分准确率、完整性、格式合规率、无关信息率。准确率看核心回答对不对完整性看是不是只答了一半格式合规率对结构化输出特别重要无关信息率则是看模型有没有“编造”。这块不需要一上来就搞复杂的大模型评测体系甚至最初可以人工打分。但要注意样本量不能太少且要覆盖边界情况。我有一回改了个Prompt整体得分涨了5%以为自己优化得很成功结果一细看只是把简单问题答得更好了所有复杂追问全部崩了。后来我按照问题难度把评测集分了三层每层单独看分才发现这种“偏科”现象。评估集一定要分层简单、中等、困难分开统计。2.3 一份高质量数据集的诞生过程数据是AI工程最容易低估、但对效果影响最大的环节。很多项目最后效果不行追根溯源都是数据质量太差。这个“差”不是数量少而是脏、乱、分布不均衡。脏数据最常见的情况是PDF里有两列排版直接抓文本就变成一行读不通的乱序网页爬下来的内容带着导航栏和广告表格跨页被截断成残缺信息。乱数据则是混乱的格式排列。不均衡更隐蔽你做一个电商客服问答80%的问题是“我的订单到哪了”但10%的用户在问“如何开发票”数据里却几乎没有这种问题训练出来的检索和回答自然就偏向高频问题。我自己处理数据的时候会建立一套“输入校准”流程。第一步是把各种格式统一成纯文本PDF、Word、扫描件分开处理第二步是清洗噪音去页眉页脚、去掉重复模板文本、修正OCR乱码第三步是归一化格式日期、金额、电话统一表达第四步才是切分和索引。每一次清洗都要记录处理规则方便后面追查某一类问题是否由清洗方式引起。用一句行话说数据决定效果上限模型只是逼近这个上限。3. 核心环节拆解数据、模型与提示词3.1 文档切分最不起眼却最容易翻车的一步做检索增强生成RAG的时候文档切分是最容易被随便对待的环节。大多数团队直接按固定字符数切一段512字切完就灌进向量库然后发现检索效果怎么调都不好。我见过最离谱的案例一份技术规格文档把“最大功率为30kW”和“推荐使用6平方毫米电缆”这两个本来在同一个注意事项里的信息切到了两个块里。用户问“这个功率应该配多粗的电缆”检索系统一个句子都拼不完整自然答得稀碎。切分策略要跟着文档结构走。Markdown标题、HTML的H标签、PDF的章节标题都是天然边界优先按语义块切语义块太大再往下切割到512字上下相邻块要保留一定重叠比如50个字符左右避免一句话正好被拦腰截断。再说一个细节表格不要硬切成纯文本尽量用“表格原样”的方式存储让模型能看懂行列关系代码片段要用代码块包住别让注释和代码分离。切分之后还有一道检查工序把每个块的首尾20个字自动拉出来看一遍确认没有半截话。这一步能筛掉很多低级问题。3.2 模型选型不要永远只追最强的那一个模型选型是个权衡题不是单项选择题。现在的开源和闭源模型选择非常多你不需要每一次都选效果最强的而是选“这个场景下ROI最高”的。我给自己定了几条选型原则简单任务用快模型。比如意图识别、实体抽取这种单点能力用轻量模型就够了没必要每次都召唤大模型。生成复杂内容用强模型。写长文、做总结、多步推理这些任务确实需要更强的模型否则省下的token成本还不够填错误返工。对自己数据做批量测试再拍板。很多团队只看跑榜分数到了自己领域就不一定灵。务必要用你自己的50条业务问题跑两三个候选模型看效果再决定用什么。优先考虑可切换方案。选型时就要把模型接口抽象成一层别把具体模型的调用散落在代码各个角落。否则以后换模型你会发现半个工程都要重写。另外Embedding模型的选择也别忽略。做中文知识库bge系列的模型在中文语义上就比很多英文预训练模型靠谱召回率肉眼可见地高。这个环节你可以用一套自己的检索测试集去对比Top5命中率差5个点以上整套系统体验会差一大截。3.3 提示词工程不是堆字数是约束与引导很多人以为提示词写得越长越细越好结果写了一大段模型反而抓不住重点。提示词工程更接近“给一个聪明但粗心的实习生写任务卡”信息要给全但结构要清晰。我常用的提示词四段式角色、任务、要求、输出格式。角色告诉模型它是什么比如“你是客服助手”任务描述当前用户的具体问题和上下文要求写清楚边界比如“只能基于提供的资料回答资料中没有的信息要明说‘未找到相关内容’”输出格式约束结构比如“先出结论再给理由最后附上引用来源”。特别提一下结构化输出。如果模型输出的是一段自由文本后面接任何程序化处理都会很痛。尽量让Prompt要求JSON输出并且用代码强制解析解析失败就自动重试一次。这样后续流程能拿着字段直接做逻辑判断而不是靠字符串匹配去猜。温度参数方面大多数问答场景温度设到0.1到0.3就够了太高的温度会让同样的问题每次回答都不一样后面做评测时会非常头疼。类似“请从下面A/B/C选一个”这种题目温度直接设0。3.4 上下文管理你的token是有限的但消息可以无限做大模型应用一定会碰上上下文超限的问题。用户聊了十轮以后历史消息已经远超模型窗口强制截断又会丢失关键信息。这个问题没有银弹只能分层处理。我常用的策略是摘要化。把早期的对话内容用模型压缩成一个摘要保存到上下文的最前面。中间的明细细节如果后面需要再检索就落到外部存储中。还有一种做法是“只保留最近N轮全局摘要”的混合结构兼顾短期精准和长期记忆。缓存也不能忽略。完全相同的用户提问每天可能有大量重复尤其在企业内部。上一版回答的缓存如果命中连模型都不用调用直接把历史结果返回延迟和成本同时下降。当然这种缓存要注意时效性数据每天更新的场景慎用一天以上的长缓存。4. 实操从零搭建一个RAG问答系统4.1 需求定义与整体链路设计按上面的思路走下来我用一个最经典的RAG问答项目来演示完整落地过程。假设场景是企业内部的规章制度问答输入是员工问题的自然语言输出是要有据可查的回答必须指出依据来自哪份制度文件的哪一条。这套系统的链路分为五段数据入库、文档切分、向量化存储、检索召回、生成回答。我用PythonFastAPI搭了一套简单的服务向量库用的开源方案模型调用走标准接口。整套代码结构很轻但每一层都做了细节控制。先看数据入库的代码框架def build_knowledge_base(docs): chunks [] for doc in docs: parsed parse_document(doc) # 解析PDF/Word/HTML cleaned clean_text(parsed) # 去页眉页脚、统一空白 for block in split_by_semantic(cleaned): # 按标题结构切块 if len(block) 512: block split_fixed_chars(block, size512, overlap50) chunks.append(block) return chunks # 生成向量并写入向量库 for idx, chunk in enumerate(chunks): emb embedding_model.encode(chunk) vector_db.upsert(idstr(idx), vectoremb, payload{text: chunk, source: chunk.metadata})这段代码看着简单但每行背后都有讲究。parse_document要按文件类型分派不同的解析器PDF和Word策略完全不一样clean_text必须处理全角半角符号的问题split_by_semantic要优先按照标题层级切分而不是无脑按字符数切。4.2 解析与切分的实操细节文档解析是最脏的活。PDF要先把扫描版和文本版区分开文本版还好扫描版必须走OCR。中文OCR我建议优先用PaddleOCR它对中文的识别效果比较稳尤其表格结构还原比很多开源方案都靠谱。Word文档在线版处理要小心docx本质上是一堆XML解析时容易丢失图片里的信息。如果图片是表格截图那就得拎出来单独OCR。HTML网页又要剔除标签、导航栏、版权信息。统一输出成Markdown格式是我比较推荐的做法因为它既能保留结构又方便后续切分和模型阅读。切分阶段我用了两级策略。第一级按Markdown标题切比如“第三章 请假制度”直接是一整章的内容。如果这一章的字数少于512个字符那就整章作为一个块不切更碎。如果超过512个字符再按段落边界做二次切分切完保留50字重叠。这样做的效果是块与块之间存在上下文粘连但又不是整块塞给模型避免噪声过多。这里有一个特别要注意的点切分之后的块要有独立的编号和元数据比如文件名、章节路径、页码。这不仅能帮模型回答时引用出处更能在后续排查问题时快速定位是哪一块数据导致回答出错。4.3 向量检索召回率比精确率更重要RAG系统的检索环节不追求“只返回正确的那一块”而是希望尽量多地把相关块召回。因为最终还有生成环节兜底检索召回少了后面的模型再好也白搭。我通常设置召回数量在4到8条之间具体看文档块大小。块大就少召回几块块小就多召回几块。然后做个简单重排把相关性打分最高的Top-K块作为上下文。考虑预算的话可以用轻量的bge-reranker模型做重排效果提升挺明显的尤其当候选集里混杂着多个主题的相似文本时。检索这边一个常见的坑是用户问题本身很简短直接拿去向量检索结果经常不理想。比如用户问“年假怎么算”如果你的制度文档里写的是“累计工作满一年不满十年者年休假5天”向量匹配分数可能不高。解决方法是把用户问题稍微扩写一下改成“年假计算规则 累计工作年限 年休假天数”再做检索。这个扩写可以用小模型自动生成也可以手工定义规则效果随业务场景而定。检索结果要按相关度从高到低排列然后拼入Prompt的“参考资料”部分。拼接顺序不能乱尤其当几块内容之间有承接关系时。如果发现模型经常引用后面的块作为结论而前面的块作为补充说明说明顺序可能反而打乱了逻辑链条需要人工微调。4.4 生成阶段把检索结果用起来生成阶段的核心约束是模型只能使用传入的资料不允许自由发挥。我的Prompt大致是这样你是一名企业内部制度问答助手。请基于以下参考资料回答用户问题。 参考资料 {context} 回答要求 1. 首先直接给出结论。 2. 然后说明依据标注来源文件名称和章节。 3. 如果参考资料中没有答案请明确回答“资料中未找到相关内容”不要编造。 4. 回答使用简体中文简洁清晰。生成阶段的参数也很关键。temperature设0.2是为了让回答在稳定性和一点多样性之间平衡max_tokens至少给到512以上防止长回答被切断。下面是一个流式输出的实现片段from fastapi import FastAPI from fastapi.responses import StreamingResponse app FastAPI() app.post(/ask) async def ask(query: str): docs retrieve(query) context format_context(docs) prompt build_prompt(query, context) stream llm.chat_stream(prompt, temperature0.2, max_tokens512) return StreamingResponse(stream, media_typetext/event-stream)流式输出在交互体验上是刚需用户看到第一个字在动就不会觉得系统卡死了。但要注意流式输出时代码没法事后篡改开头的内容所以如果有合规过滤或敏感词检查那些逻辑要放在生成之前或者干脆切成两段流。4.5 部署、测试与迭代部署方面我推荐用FastAPI或者类似的轻量框架包一层然后直接丢到容器里跑。这里最容易被忽略的是“并发控制”。大模型服务不仅是CPU/GPU密集更是内存密集。并发请求一高显存或内存溢出是常事。所以对上游API要做限流对本地模型要做并发队列。我一般用信号量控制在同时最多处理的请求数比如2到4个剩下的排队处理。上线之前一定要做一轮“脏数据测试”。就是专门挑那些格式最乱、内容最长的文档喂进去看系统会不会崩溃、检索会不会异常、回答会不会跑偏。这种测试在Demo阶段几乎没人做但生产环境里用户上传的文件千奇百怪不提前兜住上线第一天就能被投诉淹没。上线之后把每一次用户的真实提问和系统回答都记录下来。我习惯在数据库里建一张问答日志表至少包含时间、问题、回答、引用来源、用户是否点了“有用”。这些数据才是后面持续优化的金矿。5. 常见问题与排查技巧实录5.1 回答开始胡说八道怎么追根因“幻觉”问题是所有AI应用最头疼的但它并不是无迹可寻。我处理过的幻觉案例有较大比例根子不在模型而在检索。排查顺序很重要。第一步先查检索结果把这条回答对应的Prompt上下文原样打出来看参考资料里有没有答案。如果资料里本身就有正确答案模型答错了那是生成环节问题可以优化Prompt或换强模型如果资料里压根没有这个信息那模型自然只能编了。这时候要追溯检索为什么没召回正确内容可能是切分破坏句子、Embedding模型相关性不够、或者问题扩写不当。还有一种隐蔽情况模型把资料里的“不相干内容”当成背景知识联想加工了。比如资料里提到“公司在北京有分部”用户问“公司在哪些城市有办公室”模型可能自己补了一句“以及上海”——这不是检索也不是Prompt的问题而是模型基于预训练知识的自由发挥。对策是Prompt里加强“不得引入参考资料之外的信息”并在评测集里加入这类“不可知问题”专门观察模型是否乱猜。5.2 响应延迟居高不下瓶颈在哪个环节系统慢了第一件事是定位瓶颈链路。RAG系统的耗时通常分三块检索耗时、生成耗时、网络耗时。检索一般几十到几百毫秒不会成为主要瓶颈生成耗时是大头尤其长文本回答可能占掉总耗时的一半以上网络耗时则取决于你调用的是本地模型还是API。优化策略按性价比排列最简单的就是做结果缓存命中直接返回其次是把第一轮生成的token前几字做成流式输出用户感知延迟大幅下降再接着是缩减上下文把不必要的历史记录剪掉最后才是换更强的硬件。我自己实测过一个案例原本平均响应8秒做了缓存后一大半请求2秒内返回剩下的请求通过限制回答长度从8秒压到5秒。这个维度的优化不需要换模型效果立竿见影。5.3 token成本飙升先别急着骂模型贵成本问题多数不是模型单价问题而是调用方式太浪费。最常见的是把整本手册全文当上下文丢给模型每问一次就烧一次。换成RAG只召回最相关的几个块之后成本能降一个数量级。第二个浪费大户是反复调用。同样的数据转换、同样的摘要生成每次请求都重复跑一遍。建议把中间结果缓存下来。比如把文档切块后先做一次预处理嵌入向量存库这些一次性成本只付一次。这里说一个我自己用过很有用的技巧对高频问题做“固定回答路由”。比如“公司年假标准是什么”这种问题命中标准FAQ之后直接在缓存里返回完全不用走大模型。一个企业内部问答机器人经常一半以上的流量都是那几十个高频问题这个优化能把成本打骨折。5.4 第三方接口不稳定怎么保证服务可用如果你的模型调用依赖第三方API那就得接受一个现实再稳的供应商也有抖动。我见过上游服务超时连续持续十分钟的情况对于业务方就是一场事故。降级方案必须有。做一个简单但实用的兜底逻辑先调主模型超时3秒就切换备用模型备用模型也失败就返回缓存的旧答案如果连缓存都没有就返回一个文案“服务暂时繁忙请稍后再试”同时把失败消息发到告警群。这套降级链路的代码量不大但价值极高。有一次我的上游供应商挂了大量用户还是能正常拿到之前缓存过的回答投诉量比完全不可用少了一个量级。6. 从零到一之后继续往前走6.1 建设你自己的评测回归集系统上线只是开始。没有评测回归集后面每一次Prompt微调、模型升级、数据清洗都像是在黑暗中飞。评测集一定要包含三类内容标准高频问题、边界case、不可答问题。标准高频问题盯基线效果边界case盯稳定性不可答问题盯幻觉程度。每次改动都跑一遍全套记录分数变化。分数上升就合入分数下降就回滚这套流程往简单了说就是AI工程的“单元测试”。用下来的经验是评测集不要太追求自动化打分最开始人工跑一遍就够了。真正重要的是“每次用同一套题”这样改动的收益才能横向对比。等人工评测稳定后再逐步引入LLM自动评测可以节省大量时间。6.2 日志和可观测性越早做越好AI系统的日志比传统软件更复杂。不仅要记请求参数和返回结果还要记录模型调用的token数、耗时、检索的命中间隔、Prompt完整内容以及最终的流式输出。这些都是排查问题的依据。好的日志设计应该能回答四个问题这个回答用了哪些上下文模型生成的原始输出长什么样为什么检索召回的是这几块这次请求花了多少钱把这些信息以结构化日志方式落地比如JSON按行写入文件或直接进日志系统之后不管出什么问题都能快速定位。6.3 什么时候值得做微调微调这个词被炒得很热但实际工程里并不是所有问题都需要微调。很多事情用更好的数据、更好的检索、更好的Prompt就能解决根本走不到微调那一步。我看到有些项目数据量只有几千条就急着要微调结果不仅提升有限还丢失了通用能力。如果非要做前提是有几千到几万条的高质量、配对数据而且这些数据代表的场景是Prompt怎么描述都覆盖不到的。比如模型需要学习某种特殊的格式化输出或者回答要高度贴合公司内部的黑话式表达。微调的ROI才会真正体现出来。更常见的性价比路径是先把数据清洗和Prompt做到极致仍然遇到明显瓶颈时再考虑微调。我自己的项目里RAG加好用的Prompt已经解决了绝大多数实际问题到目前为止只有少数专业术语极强的领域真正需要微调。回头看看从零开始做一个AI工程最大的体会不是选哪个模型、调什么Prompt而是“把确定的工程做扎实”。数据从哪来、怎么切、评测集怎么建、上线之后怎么观测每一环都是笨功夫。但正是这些笨功夫让模型的能力真正落地成为业务价值。这个方向没有捷径慢慢来反而最快。
返回列表