这几年我一直在做AI相关的一线开发被问到最多的问题就是AI工程到底怎么入门网上的教程铺天盖地但大多数是教你调个接口、跑个demo真正丢到生产环境里就崩了。今天想跟你分享的是我自己梳理的一套从零开始的AI工程落地路线也就是标题里写的 ai-engineering-from-scratch。它不是什么高深算法课而是一套能落到代码、能上线、能持续维护的实操方法。这篇内容适合刚接触AI开发的后端工程师、想转型的测试或运维同学也适合已经在用AI API但总觉得不稳定的技术负责人。读完你会明白AI应用和传统软件差在哪里以及如何用工程手段把不确定性一点点摁住。1. 先把AI工程这件事的版图搞清楚1.1 AI工程到底在“工程”什么很多朋友有一个误区以为AI工程就是学会调用大模型API。其实不是。调用API只能算“会用工具”离“工程”还差着十万八千里。我理解的AI工程是把一个以自然语言为交互界面、以概率模型为核心的系统做成可测试、可维护、可演化的软件。传统软件工程面对的是确定性的逻辑if-else、数据库事务、状态机输入输出一目了然。而AI应用的输入输出都是自然语言模型本身的回答又带有随机性你很难用单元测试去断言“这句话一定等于那句话”。所以AI工程真正要解决的问题不是让模型更聪明而是让整个系统在被模型“不确定性”包裹的前提下依然稳定。这就要靠三层结构来兜底第一层是数据与知识准备决定模型能利用什么第二层是提示词和Agent编排决定模型怎么利用第三层是测试、监控和降级方案决定模型出错时系统怎么办。这三层缺一不可。我画过一条完整的生命周期差不多是这样的需求拆解、知识准备、模型与工具选型、提示词与Agent编排、离线评测、灰度上线、线上监控、持续迭代。你会发现这里面的每一个环节都不是一次性动作。尤其是评测和监控很多团队直接跳过结果就是Demo跑得飞起上线第一天就被用户骂。1.2 一张可执行的12周路线图如果你问我“从零开始”到底要多久我的答案不是三个月精通而是十二周走通。时间太短你连踩坑的机会都不够时间太长又容易陷进理论出不来。我给自己带的新人设计的路线一般分五个阶段第一阶段是第1到第2周只做一件事把主流大模型API吃透。重点是搞明白消息结构、超参、流式输出、函数调用这几个基础能力。第二阶段是第3到第4周练Prompt工程要求能用一套模板稳定输出结构化结果。第三阶段是第5到第6周做检索增强生成也就是RAG解决“模型不知道你的私有数据”的问题。第四阶段是第7到第8周做Agent和工具调用让AI能够查数据库、调接口、执行动作。第五阶段是第9到第12周专门做评测、监控和成本优化。每个阶段结束的时候必须有一个可检验的产出。比如第一阶段的产出是“能写一个带对话历史的CLI聊天机器人”第二阶段的产出是“有一个版本化的提示词模板库”第三阶段的产出是“一个能回答私有文档问题的问答接口”。没有产出就不算学会。我见过太多人花了两周研究各种Prompt技巧结果连一个温度参数的原理都说不清楚这种学习是无效的。1.3 AI工程不是银弹投入产出比要算清楚第四个必须提前说透的问题AI工程不是万能的。我做过不少项目之后得出的经验比例是需求拆解和数据准备大约占40%的精力Prompt与Agent编排占30%系统集成和运维占20%算法调优只占10%。为什么数据和准备这么重要因为大模型的能力是固定的你能改的只有喂给它的东西。很多系统跑出来的效果差问题不在模型而在知识库的垃圾进垃圾出。另外要有心理预期AI应用在对准确率要求极高的场景里并不可靠。比如财务对账、医疗建议、法律条款解释这类场景需要结合规则引擎和人工审核兜底。AI适合做的是把“非结构化信息变成结构化信息”、把“复杂检索变成自然语言问答”、把“重复性创作变成辅助生产”这三大类事情。你拿它去做硬核计算那就用错了地方。2. 工程化开发环境工具链与模型选型2.1 最小化开发环境备齐这几样就够了工欲善其事必先利其器但AI工程的环境真的不需要太复杂。我目前的主力配置是Python 3.10以上、uv做包管理、VS Code配Jupyter插件再加一套统一的SDK封装。很多人一上来就搭Kubernetes、上微服务完全没必要。起步阶段单体服务加一个异步任务队列就够用了把复杂的部分留给模型调用层。这里我特别想说一下AI编程辅助工具。现在主流IDE基本都内置了AI补全PyCharm、VS Code都有对应的AI插件还有像CodeBuddy这类独立工具。我的使用习惯是用它们来写样板代码、补测试用例、做代码解释但绝不盲目信任它们的重构建议。有一次AI插件自作主张把我一个处理异常的try-except块给删了理由是“这段代码过于冗余”实际上那是防止上游超时的关键保护。记住一句话AI编程工具是你的副驾不是你的司机你依然要自己握着方向盘。环境里还有一个容易被忽略的东西密钥管理。我见过有人把API Key直接写在代码仓库里结果整个仓库泄漏之后被刷爆了几万块的token费用。正确做法是用环境变量或者专门的密钥管理服务在本地用.env文件、在服务器上用KMS或Vault这类工具并且给Key设置调用限额和告警阈值。这些虽然是老生常谈但在AI项目里往往做得最差。2.2 模型选型与成本预算别一上来就上旗舰版选模型是件很有意思的事。我早期做项目闭眼就选能力最强的模型结果一个月下来成本报表惨不忍睹。后来才学乖了用一个表格去做选型对比维度包括推理能力、上下文窗口长度、输入价格、输出价格、延迟表现、服务稳定性和数据使用条款。表格里的每一项要和你的业务需求挂钩比如做日志分析就看重长上下文做客服问答就看重延迟和成本做写作辅助就看重语言风格一致性。以一个日活一万的问答应用为例假设每次请求消耗2000个输入token加500个输出token用旗舰模型的话每千token的成本可能相差十倍。算下来一天可能就是几百块和几千块的区别一个月差距大到能决定项目生死。所以我的选型原则是能用轻量模型完成的绝不上旗舰模型能用提示词解决的先不碰微调能缓存结果的尽量走缓存。把模型当成算力资源去调度而不是每一句话都去找最强的模型。还有一句话提醒别迷信某个模型“永远最强”。这个领域的迭代速度非常快每隔几个月就有新的模型能力越级。我现在的做法是做一个模型路由层统一封装调用接口内部可以通过配置自由切换模型。这样好处很明显哪家模型性价比高就切到哪家不会被单一厂商绑架。2.3 上下文工程把token当成钱来花上下文窗口是AI工程里最需要精打细算的资源。一个常见的误区是“既然窗口有128K那我把所有资料都塞进去不就好了”。理论上没错但实际上你真的全部塞进去会发现模型被大量无关信息干扰回答质量反而下降而且每个请求的token费用会直线上升。我把它叫作上下文淹没效应太长的上下文会让模型抓不住重点。我现在做上下文预算一般分四块系统提示词固定占用一块对话历史压缩后占用一块检索到的参考资料占用一块最后是用户的当前输入。系统提示词尽量控制在1000个token以内对话历史如果超过阈值就做摘要压缩检索片段按相关度截断。用一套动态修剪机制保证每次请求的上下文总量在可控范围内。这么做的好处不仅是省钱更重要的是响应速度和稳定性。实测下来同样的任务把上下文从8K压缩到2K响应耗时能下降30%以上。所以我现在跟团队反复强调长上下文不是让你什么都往里塞的而是给你更多腾挪空间。上下文工程的核心是知道什么是模型必须看到的什么是它不应该看到的。3. Prompt工程从写提示词到设计提示词系统3.1 一套可复用的System Prompt模板结构Prompt工程有一大坑把提示词当成一段写作文案每个人都有自己的风格改起来全凭手感。实际上生产环境的提示词是要版本化、模板化、可测试的得当成代码来管理。我常用的System Prompt结构大概是这样的角色定义你是XX领域的资深助手擅长…… 任务范围你只做以下三类事情其他问题一律拒绝回答 输入说明用户会提供XXX格式的内容其中可能包含噪声 输出规范必须按给定JSON结构输出字段说明如下…… 约束条件 - 只依据参考材料回答不得自行编造 - 当信息不足时明确回复“根据现有资料无法确认” - 禁止输出任何身份猜测以外的元信息 示例给出1-2个输入输出样例 兜底策略如果请求超范围返回固定错误码这套结构的好处是每个模块都承担一个职责。角色定义解决“模型以什么立场说话”任务范围解决“不乱接活”输出规范解决“解析时不出错”约束条件是防幻觉的关键示例则是最有效的输出对齐方式。我把它们都写进一个模板文件用配置驱动的方式加载这样后续换模型、改需求只需要动配置不动代码。写提示词还有一个容易被忽视的问题版本管理。我吃过一次亏上线前手滑改了一行提示词忘了通知同事被当成bug排查了整整两天。后来我要求团队所有提示词必须走Git仓库每次改动都要写change log并且配一个回归评测集来验证改动的影响。提示词跟代码一样没有版本控制就是事故现场。3.2 四种范式怎么选Few-shot、CoT、ReAct、工具调用Prompt的范式选择会直接决定效果。我见过不少人不管什么任务都用“请你一步一步思考”结果让模型在简单分类任务上也输出一大段推理过程又慢又费钱。实际项目中我一般按任务类型来选零样本范式适合通用任务比如情绪识别、关键词提取写清楚指令直接问就行。少样本范式适合格式严格、逻辑可枚举的任务比如信息抽取、意图分类你给三五个高质量样例模型输出格式基本就稳定了。思维链范式适合数学推理、多步推断让模型先列推理过程再给结论。ReAct和工具调用范式适合需要联网、查库、计算的复杂任务模型先思考“需要什么信息”再调用工具获取最后基于工具结果回答。选错范式的代价我举一个真实例子有个项目要做合同关键条款抽取一开始用零样本抽取结果非常飘字段名忽高忽低。后来我在提示词里加了两个合同样例用XML标签把需要抽取的字段框出来准确率直接提升了二十个百分点。这就是Few-shot的价值。但反过来如果你的样例给得不好或者样例场景和实际数据差异太大效果可能比零样本还差因为模型会被错误样例带偏。所以少样本提示词里的样例一定要从真实数据里选不要自己拍脑袋编。3.3 控制输出质量的三个关键参数很多人对超参的理解停留在“温度越低越稳定”这句话对但不完全对。我在实践中的建议是先调Prompt再调参数最后才考虑换模型。参数的调节顺序也很讲究。温度控制的是随机性做抽取、分类、格式化输出时我习惯调到0.2以下做创意文案时可以调到0.8以上但注意温度只是改概率分布不会帮你纠正逻辑错误。Top-p和温度类似一般只调一个就行两个同时调容易互相打架。最大输出长度也很关键尤其是做流式输出或者严格JSON时必须预留足够的空间。我有一次做长文档总结max_tokens设得太小结果每次输出都在一半被截断JSON解析一直报错。后来把输出上限提到合理范围问题立刻消失。还有一个容易被忽略的是停止符配置如果你的模型SDK支持stop参数一定要把输出结束标记、换行符、特殊分隔符都配置进去这样可以避免模型把多余内容一起吐出来。关于JSON模式现在的模型基本都支持结构化输出。我的做法是在提示词里给出严格的JSON Schema示例然后把响应格式强制切换成JSON模式最后在代码里做schema校验。三层保险下来解析失败率基本可以降到千分之一以下。千万别只靠提示词要求“输出JSON”因为你永远不知道模型会在哪个边界上给你来个文字解说。3.4 做一个专属的评测集把Prompt改动变成回归测试这个可能是整篇内容里我最想强调的一句话没有评测集就不要改Prompt。我见过太多团队改一句话之后“感觉效果变好了”上线之后指标反而掉了。原因很简单你觉得好只是你人眼看了两三个例子样本太小完全不能说明统计意义上的变化。我的做法是建一个黄金评测集包含三部分核心场景题、边界题、陷阱题。核心场景题覆盖日常请求边界题覆盖输入缺失、超长输入、语气变化等特殊情况陷阱题专门用来测试幻觉比如“你的知识库里没有这个信息你会怎么回答”。每次改Prompt都要在评测集上跑一遍记录格式合法率、关键要素命中率、幻觉率和人工评分这几个指标。然后把改动和结果一起提交到文档里。评测集可以有人工来审也可以用能力较强的模型来自动打分但一定要抽检。我一般是让大模型先判分然后每周人工抽查五十条校准判分标准。这样做的投入不大但收益率极高你的Prompt工程从此不再是玄学。4. RAG与Agent让AI用上你的数据、替你干活4.1 RAG不是加个向量库就完事检索增强生成这个词被说得太多了但真正把它做得能用的团队其实不多。RAG的完整链路是知识切分、向量化、建立索引、混合检索、重排序、增强生成。很多人的实现只做了中间两步文档切一切、向量库一存、相似度一查结果就是搜出来的东西乱七八糟回答漏洞百出。切分这一步就很有讲究。我试过按固定长度切分比如每500个字符一段效果一般因为一通语义完整的句子被拦腰截断是常有的事。后来改成递归式切分优先按段落层级切再按句子边界切每段带50到100个字符的重叠区域。这样既能保证上下文连续性又能控制单段长度。经验值上中文场景下每段300到500个字符比较合适太短信息量不够太长又稀释了检索相关性。检索环节我强烈建议用混合检索。纯向量检索对语义相似敏感但对专有名词、编号、型号这类精确匹配很弱。你搜“HP-3000打印机”语义相近的向量可能返回一堆“打印机维修指南”但精确匹配才能命中参数表里的那一行。所以我把BM25关键词检索和向量检索的结果做加权融合再让重排序模型统一打分。这一步做完检索质量会有直观的提升用户能明显感觉到它“更懂我了”。最后说生成。Prompt里要明确告诉模型只依据提供的参考文档回答如果参考文档里没有就直接说不确定。这个约束很重要。没有这个约束模型就会把预训练阶段见过的通用知识混进来看起来答得挺顺实际上已经编造了。检索出来的相关片段也要做去重和截断别一股脑全塞给模型。4.2 用Function Calling给Agent装上行动力附示例代码Agent和普通聊天的最大区别就是它能执行动作。所谓工具调用本质上就是让模型输出一个结构化的函数调用请求然后由你的代码去执行真实的API再把结果返回给模型继续处理。我用一个很简单的例子来说明假设要给Agent加一个“查订单物流”的工具。先定义工具的schema包含函数名、参数说明、参数类型。然后把请求发给模型模型在需要查询时会返回类似“我要调用query_logistics参数是order_id12345”。你的代码负责解析这个返回调用真实的物流查询接口拿回结果后再组装一条新消息发给模型让模型基于真实数据做最终回答。下面是一段简化版的实现逻辑def run_agent(user_query: str) - str: messages [{role: system, content: SYSTEM_PROMPT}, {role: user, content: user_query}] # 第一轮让模型决定要不要调用工具 response client.chat.completions.create( modelMODEL_NAME, messagesmessages, toolsTOOL_SCHEMAS, # 工具定义列表 tool_choiceauto ) msg response.choices[0].message # 如果模型决定调用工具 if msg.tool_calls: tool_call msg.tool_calls[0] # 执行真实函数 result execute_local_function(tool_call.function.name, tool_call.function.arguments) # 把工具结果回传给模型 messages.append(msg) messages.append({ role: tool, tool_call_id: tool_call.id, content: result }) # 第二轮模型基于工具结果给出最终回答 second client.chat.completions.create( modelMODEL_NAME, messagesmessages, toolsTOOL_SCHEMAS, tool_choicenone ) return second.choices[0].message.content return msg.content这段代码虽然简化但已经体现了工具调用的核心循环。实际工程里要注意三点一是函数参数必须做白名单校验避免模型生成的参数越界二是所有工具调用要记录日志方便追溯模型走了哪些路径三是执行函数要设置超时和失败重试别让一次外部接口超时拖垮整个Agent。我在做生产级Agent时还会限制工具调用轮数最多三轮超过就强制结束防止模型陷入死循环。4.3 多AI协作与工作流编排单个模型的能力天花板摆在那里所以很多复杂任务需要多AI协作。我用过最顺手的场景是内容生产流水线第一步用发散模型生成选题第二步用收敛模型做大纲评审第三步用长文本模型写正文第四步用一个严格的校对模型检查事实错误和格式问题。每个环节的输出就是下一个环节的输入整条链路像一条装配线每一站都有明确的质检标准。工作流编排的落地方式主要看复杂度。简单的串行流程用代码直接调用就行。复杂一点的可以用状态机或者工作流引擎去管理每一步都有状态、有超时、有重试机制。我倾向于少引入重量级框架先用最直白的方式把流程跑通等到节点真的多了再考虑抽象层。因为AI应用的编排逻辑变化很快过早抽象会让项目变得难以调整。这里有一个很重要的设计原则人工参与的关键节点不能省。比如最终文案在发布之前一定要经过人工审核即使你的校对模型评分很高也不能完全放开。我做过一个营销文案生成系统一开始追求全自动结果有篇文案把产品参数写错了发出去之后被客户投诉。后来加了人工确认节点系统自动生成初稿和审核建议人工一键确认或者修改后再发布既保留了效率又守住了底线。4.4 给Agent画好边界防失控比追功能更重要Agent跑起来之后最怕的就是失控。我见过Agent因为一个循环调用把第三方接口刷到限流也见过它在错误的数据上反复横跳疯狂消耗token。所以给Agent定边界条件是一项必须在一开始就做好的工作。我通常给Agent设置四个边界最大迭代次数、单次运行超时时间、单次会话预算上限、敏感操作复核开关。迭代次数超了强制停超时了强制停花费超了强制停涉及删除、写库、发消息这类敏感操作必须回到用户确认。这些边界不是一个一个独立地随便设而是要有全局的熔断逻辑任何一个条件触发整个Agent会话立即进入安全兜底。在实现层面最简单的做法就是用一个包装层把所有Agent循环包在里面。循环每走一步检查预算、步数、时间这三个值任何一项达到上限就抛异常或者返回预设文案。代码上可能只需要几十行但它是Agent系统里最值钱的防护网。我踩过的坑太多了现在宁可多写几层校验也绝不放任Agent裸跑。5. 测试、灰度与上线运维AI应用的稳定性方法论5.1 AI应用的测试金字塔怎么搭传统软件的测试金字塔到了AI应用这里要稍微变形。最底层是单元测试依然测那些工具函数、解析逻辑、数据处理的代码这些是确定性的可以全量覆盖。往上一层是集成测试测API请求是否通、模型返回是否符合schema、向量库检索是否正常。再往上是回归测试跑评测集。最顶层是端到端测试模拟真实用户走完整条链路。非确定性是AI测试最大的干扰项。我的经验是测试环境一律把temperature设成0并且固定输入顺序和随机种子保证同一份测试数据多次跑出来的结果尽量一致。但这只能保证“尽量”不能保证“绝对”所以我在CI里不会用“结果必须完全相等”做断言而是用评测指标做阈值判断比如“关键字段命中率不低于95%”这样。还有一个测试手段很值得推荐录制回放。把线上真实的请求响应录制下来存成固定的夹具测试时直接回放用录制的结果比对新代码跑出的结果。这样既能重现线上问题又不受模型服务波动的影响。我自己的团队就是用这套方式把AI应用的回归测试从一个星期跑一次提速到了每次提交代码都自动跑。5.2 日志与可观测性别等出事了才去翻聊天记录AI应用的日志比传统应用更复杂因为你不仅要记录系统状态还要记录模型每一次的输入输出和消耗。我的日志结构一般长这样{ request_id: a1b2c3d4, timestamp: 2025-06-18T10:00:00Z, user_id: user_9527, model: qwen-max, prompt_hash: sha256:abc..., input_tokens: 1823, output_tokens: 462, latency_ms: 890, error_code: null, task_type: knowledge_qa, context_items: [doc_01, doc_07], output_summary: 回答包含3个关键点 }这份日志做三件事一是成本归因每个用户、每个功能花了多少token一目了然二是质量追溯如果用户投诉了某个回答能快速找到当时模型看到了什么内容三是错误监控超时、限流、内容安全拦截、JSON解析失败这些错误都要有独立的错误码并接入告警。线上监控指标里我最关心的五个是响应成功率、平均延迟、token消耗增长率、评测集跑分变化、用户负反馈率。特别是最后一个我建议在应用里加一个“回答有没有帮助”的反馈按钮哪怕只有1%的用户会点也是一手的质量信号。这些数据汇总起来才能支持你做持续的迭代决策。5.3 上线前必须准备好的降级预案模型服务不是永远稳定的。第三方API可能限流、可能超时、可能短暂不可用你自己的服务也可能在模型层出问题。我见过太多团队只写了调用模型的代码没有写模型挂了怎么办结果线上事故时只能干瞪眼。我建议至少准备三层降级第一层接口重试加指数退避处理瞬时抖动第二层缓存策略把高频相似问题走缓存直接返回既省钱又抗压第三层备用模型切换当主模型连续失败时自动把流量切到备用模型或者切到规则引擎。你甚至可以做一个降级矩阵把“模型服务不可用”“模型质量下降”“成本超预算”这些故障场景和对应的响应动作列成表每一级都明确负责人和操作步骤。这里有个容易被忽视的细节降级时返回的文案也要设计好。系统不可用时别让用户看到一堆堆栈错误而是返回“当前AI服务繁忙请稍后重试”之类的统一话术。重要的是别让用户觉得你的产品挂了而是让他觉得只是暂时网络波动。可这也不是糊弄而是基本的用户体验素养。5.4 持续迭代每次只改一个变量AI应用上线之后迭代节奏和传统应用不太一样。传统应用可以大版本迭代AI应用我建议小步快跑每周一个小版本每版只改一个变量。这个变量可以是提示词、检索策略、切分参数或者某个外部工具的调用逻辑。只改一个变量的好处是一旦线上指标出现波动你能明确知道是哪个变更导致的不会陷入“到底是改了提示词还是改了数据”的迷思。我自己的迭代流程是这样的先记录当前评测集的基线分数然后修改一个变量在评测集上验证如果分数提升并且人工抽检也认可再灰度放量灰度比例从5%开始观察成本、延迟、用户反馈三个指标确认没问题再逐渐放大。整个过程都记录在实验表格里哪次改动有效、哪次无效、为什么无效都有据可查。这一套流程做下来你会发现AI工程没有那么多玄学。一个模型的效果好坏完全可以通过系统化的实验管理来度量而不是靠“感觉”和“运气”。6. 完整案例复盘企业知识问答Agent从0到16.1 需求与边界先搞清楚什么能答、什么不能答最后用一个我实际做过的项目来复盘全过程。需求很简单给公司内部做一个知识问答Agent员工可以问“年假怎么申请”“出差报销标准是什么”“公司网络故障怎么报修”。核心诉求有三个回答必须准确、必须能追溯到具体文档原文、绝不能瞎编。第一个版本我决定只做政策文档问答不接入实时数据不接业务系统这样才能控制范围。数据准备阶段我们收集了几十份内部政策文档加起来大概一千多页。这个阶段做了三件事文档格式统一转成markdown清理掉页眉页脚重复内容按照章节层级做切分。切分之后大概得到两千多个片段每个片段控制在三百到五百字。这里踩了一个大坑原始文档里有好多表格直接转成文本之后结构全乱了导致后面检索经常召回一半表格字段。后来我针对表格单独做了处理把每行转成“字段名值”的自然语言句子再重新切分。边界控制方面我在系统提示词里写得很死只回答公司政策相关的问题其他问题一律拒绝。这里说的拒绝不是生硬地说“我不能回答”而是引导用户去问HR系统或者IT支持。实际效果很不错因为用户知道这个Agent是干嘛的也清楚它的边界在哪里。6.2 实现细节混合检索加严格的生成约束这个项目在技术选型上我用的是混合检索加重排然后接生成模型。向量检索负责语义召回BM25负责精确匹配重排模型把两路结果统一打分取Top5作为上下文。生成层的Prompt约束得比较严格要求模型只能使用上下文提供的信息当信息不足时必须回复“根据现有资料无法确认”不得猜测不得使用上下文以外的知识。代码层面核心的生成函数长这样def answer_question(question: str) - dict: # 1. 混合检索 candidates hybrid_search(question, top_k20) # 2. 重排序 reranked rerank(question, candidates, top_k5) # 3. 组装上下文 context \n\n.join([doc[content] for doc in reranked]) # 4. 带约束的生成 response client.chat.completions.create( modelMODEL_NAME, messages[ {role: system, content: QA_SYSTEM_PROMPT}, {role: user, content: f参考信息\n{context}\n\n问题{question}} ], temperature0.1, response_format{type: json_object} ) return json.loads(response.choices[0].message.content)这套实现里上下文拼接的顺序是有讲究的。我一开始把参考信息放前面问题放后面后来测试发现模型对最后一句更敏感所以问题要放在最靠近结尾的位置。还有一个小细节参考信息里要标注每段内容的来源编号模型在回答时被强制要求输出citation字段这样就能实现“来源可溯源”的核心诉求。6.3 踩坑记录五个让人抓狂的问题和解决办法这个项目踩过的坑我挑五个有代表性的说。第一个问题是检索召回不全明明文档库里有答案但检索回来的是无关内容。排查发现是切分粒度太粗一个段落五六百字几种不同主题混在一起检索时被其他内容稀释了。解决方法是细化切分逻辑先按标题分块再按语义段落拆分。第二个问题是上下文淹没。有一段时间我们把Top5的文档片段全部塞进上下文经常塞进去五千多字。模型反而抓不住重点回答质量明显下降。后来把Top5截断到每个片段200字用重排分数最高的部分效果提升明显。第三个问题是模型复述原文时丢标点和数字格式。这个看起来是小问题但用户感知很强比如报销比例“50%”被写成了“50 %”。根因是模型在自然语言输出时对格式不敏感解决方法是把数字和百分比用占位符替换生成完之后再还原。第四个问题是成本超预算。上线第一周token消耗比预估高了三倍。数据分析发现高频问题大量重复而且每次都在重复检索和生成。后来加了缓存层完全一样的问题直接返回缓存答案新增了语义缓存相似度超过0.92的问题也走缓存成本立刻降了下来。第五个问题是模型偶尔越过提示词约束输出“可能”“大概”这类不确定词汇。这部分是模型概率行为很难完全根除。我的应对是加了一个输出后置检查用简单的关键词扫描和规则校验过滤掉不合格回答触发兜底逻辑让模型重新生成一次。重试一次还不够就直接返回错误提示保证绝不把不确定内容带给用户。6.4 上线后的真实数据与优化路径系统上线运行两个月之后我把数据做了一次复盘还是很有参考价值的。第一版上线时评测集上的准确率大概是五成八距离可用还有距离。问题主要集中在检索召回不够准确和模型偶尔输出多余信息两个维度。经过几轮优化准确率提升到了八成六已经达到了内部上线标准。优化路径是有顺序的。先修数据把切分和清洗做扎实准确率提升了差不多十个百分点。再修检索加上混合检索和重排又提升了七八个百分点。最后修生成层把Prompt约束收紧、加上输出后置校验稳定在八成六附近。这个顺序很关键先解决上游的数据和检索问题再去抠下游的生成细节才不至于返工。成本方面加了缓存和轻量模型分流之后单次请求成本下降了四成。线上用户满意度调研里七成以上的用户认为“回答比较准确”两成用户认为“偶尔搜不到但他们理解这是基于文档库的边界”。这个结果让我对AI工程有了更笃定的认识只要把数据、评测、迭代三个环节认真做透效果是能被工程手段稳定托住的。如果你问我做AI工程这几年最大的体会是什么我的回答是不要迷信某个模型也不要迷信某个框架真正值钱的是你手里的评测集和故障预案。把一次次的失败记录成清单比收藏一百篇教程都有用。AI工程没有一劳永逸的捷径但你可以把自己迭代得比模型还快。最后再分享一个小技巧第一次接触一个新模型时不要急着调Prompt先用最原始的零样本方式跑一遍评测集拿个基线再开始优化。有了基线你才知道后面每一步改动到底有没有用。这套方法帮我省下了无数个无意义的调整周末你应该也用得上。