1. 别把AI全栈开发想复杂了先看清楚它到底是什么这两年AI开发领域最热闹的词除了大模型本身就是“全栈开发”这四个字。我见过不少朋友一听到AI全栈就头皮发麻以为要把模型训练、微调、部署、前端、后端、数据库全部自己撸一遍。实际上AI全栈开发这个概念在过去一年里已经被重新定义了它不一定要求你从零写Transformer甚至不一定要求你本地跑任何模型。我理解的AI全栈开发核心是围绕“把大模型能力稳定地落地成产品”这件事把从模型接入到用户可用的整个链路打通。这里的“全栈”不再是传统意义上的JavaScript一统天下而是指你能够处理模型层、应用层、数据层、评测层、监控层之间所有关键环节。换句话说你做的东西要能真正跑起来、有人用、出了Bug能排查而不是只会在Notebook里写两行调用代码。这个定位适合谁适合三类人。第一类是有传统后端或前端经验、想转型AI应用开发的工程师。第二类是已经在用各类AI编程工具、但总觉得“调API谁都会、做产品总翻车”的独立开发者。第三类更宽泛是团队里需要牵头把AI功能从Demo推到生产环境的技术负责人。这三类人需要的不是又一门模型训练课程而是一套能落地的工程化思维。我之所以想写这篇东西是因为过去大半年里我自己经历了从“拿OpenAI的Key写个脚本”到“在正式环境里稳定跑Agent任务”的全过程翻了不少车也积累了一些真正管用的套路。这篇内容不会去讲怎么训练模型也不会去讲那些每个大厂都发过的通用架构图而是把我在实际项目里验证过的选型逻辑、实现步骤、踩坑记录和排查方法逐一拆开讲清楚。就拿最近特别火的一组概念来说吧“vibe coding”大家已经听腻了但“harness × SDD全栈开发实战”这种提法很多人还没真正理解。Vibe coding强调的是用自然语言让AI帮你写代码靠感觉推进。SDD翻译过来就是场景驱动开发Scenario-Driven Development强调的是先把使用场景定义清楚再让AI在场景约束下生成和迭代代码。Harness这个词更直接意思是给AI套上“约束装置”相当于在模型能力和业务目标之间加一层可控的调度与控制。真正跑过AI项目的人都知道这三件事缺了哪个都会出问题只靠vibe coding代码库会失控只谈SDD没有AI辅助还是慢只搞harness但不懂场景拆解流程会变得极其僵硬。把这三个东西组合在一起才是今天AI全栈开发的最佳形态。2. AI全栈开发的整体设计与技术栈选型AI全栈开发落到技术选型上很多人第一反应是“直接用LangChain/LlamaIndex不就行了”实际上真不是这么简单。我这里先给出一套我自己验证过的分层设计思路然后逐个讲清楚每一层怎么选、为什么要这么选。2.1 四层架构模型层、编排层、应用层、运维层我习惯把AI全栈项目的工程结构分成四层分层的核心目的不是追求架构上的美感而是为了隔离变化。模型会频繁换提示词会频繁改业务逻辑也会频繁迭代如果全部混在一起任何一处调整都会引发连锁故障。第一层是模型层负责管理所有大模型接入。这一层要解决的核心问题不是“用哪个模型最强”而是“怎么让上层代码不受模型更换的影响”。我之前维护过一个项目一个月内从GPT-4切换到了Claude后来又接了国产模型做降级兜底如果没有做模型层抽象光是改接口调用就够熬夜了。所以模型层的接口设计要足够统一不管底层是哪家模型暴露给上层的始终是“模型名、温度、最大Token、消息列表”这些常规参数。第二层是编排层负责处理提示词管理、上下文组装、工具调用和Agent的任务调度。这是AI全栈开发中最核心、也最容易失控的一层。我见过太多项目的提示词散落在各个Python文件里改一句话要找半天。更常见的是上下文拼接过长导致Token费用失控工具调用没有超时机制导致Agent陷入死循环。编排层的价值就是把这些复杂度收纳在一个可控范围内。第三层是应用层也就是对外提供的API接口、定时任务、WebSocket消息推送等。这一层和传统后端没有本质区别唯一需要注意的是流式响应的处理和错误码的设计。AI接口的失败模式和传统接口完全不同超时、截断、内容审核、上下文超限这些都需要在应用层做统一封装而不是每次在业务代码里重复处理。第四层是运维层包括日志、监控、评测、成本统计。很多AI项目死在运维层的缺失上。模型输出的质量不会像传统Bug一样有明确报错你线上跑着跑着发现某些用户反馈变差了但没有任何指标告诉你“模型输出质量正在劣化”。没有一套评测集和监控体系AI应用上线就等于裸奔。2.2 模型接入直连SDK优先网关按需引入模型接入这个环节业界的常规做法是用OpenAI兼容的SDK直连各家模型服务。这个方案的优点在于接口协议统一迁移成本低。如果你只是做原型验证或者小流量产品直连是完全够用的别一上来就上一堆重型框架。但如果你有下面的需求就要考虑引入统一网关层需要同时接入多家模型并根据业务场景做路由比如简单任务用便宜的小模型复杂推理用旗舰模型需要做模型粒度的限流和降级比如某个模型供应商服务不稳定时自动切换到备选需要统一记录所有请求的Token消耗、延迟、成本用于统计和告警团队内多个人、多个项目共享Key需要做权限隔离和额度控制。我自己实际用的方案是LiteLLM Proxy。这个工具在业内已经非常成熟了它提供一个OpenAI兼容的代理服务底层可以对接OpenAI、Anthropic、Google、Azure以及众多国内模型厂商的API。配置方式很简单写一个config.yaml定义模型列表和供应商认证信息启动之后你的所有模型请求就统一走这一个入口了。model_list: - model_name: gpt-4o litellm_params: model: openai/gpt-4o api_key: os.environ/OPENAI_API_KEY - model_name: claude-sonnet litellm_params: model: anthropic/claude-3-5-sonnet-20241022 api_key: os.environ/ANTHROPIC_API_KEY - model_name: local-llama litellm_params: model: ollama/llama3.1:8b api_base: http://localhost:11434 litellm_settings: drop_params: true set_verbose: false general_settings: master_key: sk-your-master-key database_url: postgresql://user:passlocalhost:5432/litellm启动代理服务也很简单litellm --config config.yaml --port 4000之后你的应用代码只需要配置一个Base URL指向localhost:4000模型名填上面定义好的model_name全体请求就都走代理了。比较实用的是LiteLLM自带一个消费日志表会把每一次请求的模型、Token消耗、成本、延迟都记录下来你后面做成本归因和异常排查的时候会感谢自己用了这个工具。有人会问为什么不用LangChain的模型封装来做这层抽象LangChain在编排层确实有它的用处但在模型接入这一层它过于重了而且LangChain版本更新频繁接口变化大你花在适配框架版本上的时间往往比写业务逻辑还多。我的习惯是模型接入用轻量网关编排逻辑用代码手写或者搭配轻量框架只有任务复杂度真正高的时候才引入LangGraph这一级别的Agent框架。2.3 提示词与上下文的工程化管理提示词在很多人眼里就是“写在代码里的一段字符串”但这恰恰是AI全栈开发里最大的坑。我的经验是提示词和代码一样需要版本管理、需要测试、需要review。那些“昨天还能正常输出、今天莫名变差”的情况十有八九是提示词被改了但没人记录。我推荐的做法是把提示词外置为模板文件与业务代码分离。如果项目简单用JSON或YAML文件管理就够了项目复杂的话可以上专门的Prompt管理平台比如LangSmith的一部分功能也覆盖这个场景。关键在于模板要有版本概念每次修改都要能回溯到改动前的内容方便做A/B对照。提示词模板的示例我贴一个这里用的是Jinja2语法变量用双大括号包裹你是一个{{ role }}擅长{{ expertise }}。 ## 任务目标 {{ task_goal }} ## 用户输入 {{ user_input }} ## 输出要求 1. {{ requirement_1 }} 2. {{ requirement_2 }} ## 历史对话 {% for message in history %} {{ message.role }}{{ message.content }} {% endfor %}变量是渲染时填充的模板文件本身不包含具体业务数据这样既方便维护也避免改动时误操作真实数据。上下文管理比提示词本身更容易被忽略也更容易吃掉你的成本。现在的长上下文模型动辄128K、200K能塞不代表你应该塞。我见过有人把整个知识库的检索结果全拼进上下文一次请求消耗十几万Token费用高得离谱响应还特别慢。上下文组织的核心原则就一条只保留当前任务必要的信息能用工具实时查询的就不预置能分段处理的不一次性全喂进去。比如你要做一个文档问答系统正确做法是先做检索把最相关的几段内容择出来再放进上下文而不是把整篇文档一次性塞给模型。有一个比较管用的边界参数可以参考所有历史消息和系统提示加一起不要超过模型最大上下文长度的70%。为什么不是100%因为模型需要留出生成内容的空间而且相关研究反复表明上下文过长时中间部分的信息召回率会显著下降即便模型能“看到”那些内容也未必会正确使用。2.4 Agent框架选型LangGraph的价值和控制点如果你要开发的不只是简单的问答机器人而是有工具调用、多步推理、状态流转的Agent系统框架选型就绕不开了。市面上有很多选择AutoGPT、CrewAI、LangGraph各有拥趸。我个人的判断是从工程可控性的角度LangGraph是目前最适合生产环境的选择。AutoGPT那种自由规划的模式看起来酷炫但不可控适合玩具不适合正经产品。CrewAI的角色扮演协作模式思维上很有创意但多角色之间的消息传递和状态管理在复杂任务下容易混乱。LangGraph的核心思路是把Agent的一次运行建模成一幅图节点就是“调用模型”“执行工具”“判断条件”边就是状态流转的方向整个流程由你显式定义模型只是在每个节点处做局部决策这样你就能精确控制每个步骤也方便在任意节点插入日志、做超时保护。这里给一个LangGraph的基础示例用简单的天气查询Agent展示状态图的搭建思路from typing import TypedDict, Literal from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI class AgentState(TypedDict): messages: list next_step: str llm ChatOpenAI(modelgpt-4o, temperature0) def call_model(state: AgentState): response llm.invoke(state[messages]) return {messages: state[messages] [response]} def should_continue(state: AgentState) - Literal[tools, END]: last_message state[messages][-1] if last_message.tool_calls: return tools return END def execute_tool(state: AgentState): # 执行工具调用的逻辑比如查询天气API return {messages: state[messages]} graph StateGraph(AgentState) graph.add_node(model, call_model) graph.add_node(tools, execute_tool) graph.set_entry_point(model) graph.add_conditional_edges(model, should_continue, {tools: tools, END: END}) graph.add_edge(tools, model) app graph.compile()这段代码的逻辑非常简单模型节点负责推理判断如果它认为需要调用工具就转到tools节点执行执行完回到模型节点继续推理直到模型认为不需要调用工具为止流程才算结束。整个循环是显式的你可以在execute_tool内部加日志、加超时、加错误重试生产环境可控性比黑盒式Agent高得多。关于LangGraph我有几条建议图的每个节点都要单独做超时控制避免Agent在某个工具调用上卡死在关键路径上记录Token消耗Agent类任务的成本比普通问答高一个量级不监控会失控模型节点之间的状态传递尽量用不可变数据避免并发执行时共享状态出问题。3. 从vibe coding到harness × SDD的实操方法论讲完技术选型这一章我想重点聊聊现在讨论度很高的开发方法论。前面提到过vibe coding很多人把它理解成“躺着让AI写代码”这其实是误解。Vibe coding真正的价值是让AI承担重复性编码工作让人聚焦在架构和验收上。但要把它用好必须搭配SDD和harness这两套思路。3.1 SDD先定义场景再让AI写代码SDDScenario-Driven Development是一套在我看来非常匹配AI协作的开发流程。传统开发的起点是需求文档SDD的起点是场景。不要小看这个区别需求文档通常描述的是功能列表而场景描述的是用户在真实环境里怎么使用、遇到什么情况、期望得到什么结果。模型理解和执行场景化的描述远比抽象的功能描述要准确。举个实际例子。假设你要做一个“合同关键条款提取”功能。传统需求文档会写“系统应支持上传合同文件识别合同编号、签约主体、金额、有效期等关键信息”。这种写法直接给AI去开发它可能给你生成一个只能处理单一文件类型的脚本完全不考虑合同格式的多样性。换成SDD的写法场景是这样描述的“法务人员上传一份PDF格式的采购合同系统需要提取出其中与付款相关的条款包括付款比例、付款节点、违约责任。合同可能包含扫描件需要OCR识别和电子版直接可提取文本两种格式。提取结果要求以结构化JSON返回并标注每条信息的原文出处页码。”这两段描述的区别一眼就能看出来。场景描述里包含了用户角色、输入类型、异常情况和输出格式AI拿到这样的描述生成的代码质量远高于基于抽象需求生成的代码。所以SDD的第一步不是写代码而是把场景描述写到足够具体。关于场景描述我建议你在动手开发前先花时间梳理一个场景清单包含以下几类正常场景用户按预期使用输入符合格式要求系统给出正确结果边界场景输入为空、格式不符合、数据量超出预期系统应该如何处理异常场景外部依赖如模型服务超时、返回内容为空系统应该如何降级扩展场景未来可能需要支持的格式、语言、渠道当前不在范围内的要不要预留接口。场景清单不一定要做得很正式很厚但至少要覆盖上述四类否则设计出来的功能大概率是脆弱的。3.2 Harness给AI加约束装置Harness这个词直译过来是“马具”引申意思就是“约束装置”。在AI开发里Harness指的是围绕模型能力建立的一整套控制机制包括结构化输出、防火墙、评测验证、人审介入等。为什么要给AI加约束装置因为大模型输出天然是不稳定的同样一句话同一批参数跑10次可能有8种不同的结果。如果你的业务流程里需要稳定解析模型的输出就必须通过约束让模型输出严格符合预设格式。这里我给两个实用方法。第一个方法是定义严格JSON Schema并用工具强制格式化输出。从比较新的模型能力来看GPT-4o、Claude 3.5及以上都原生支持JSON结构化输出模式。拿OpenAI的API举例只需要在请求参数里增加response_format并传入你定义的JSON Schema模型就会尽量保证输出是合法JSON且字段类型正确。from openai import OpenAI import json client OpenAI() schema { type: object, properties: { contract_number: {type: string}, signing_date: {type: string}, total_amount: {type: number}, payment_terms: { type: array, items: { type: object, properties: { percentage: {type: number}, due_date: {type: string} }, required: [percentage, due_date] } } }, required: [contract_number, signing_date, total_amount, payment_terms] } response client.chat.completions.create( modelgpt-4o, response_format{type: json_schema, json_schema: schema}, messages[ {role: system, content: 你是专业合同分析助手请从用户提供的合同文本中提取关键信息。}, {role: user, content: contract_text} ] ) result json.loads(response.choices[0].message.content)这个方案比单纯的“在提示词里要求返回JSON”可靠得多因为输出格式的保障机制在模型API层就生效了而不是靠模型自觉。第二个方法是所有工具调用的入参都要经过校验。当你给Agent挂上工具时模型会生成调用参数这些参数是模型“猜”出来的不一定符合工具函数的真实约束。比如模型调用一个整数类型参数时可能传字符串调用日期参数时可能传“明天”这种不规范的文本。在工具执行之前加一层Pydantic校验或者简单的类型校验能拦截掉绝大多数低级入参错误比在工具函数里面写一堆防御逻辑要干净。3.3 实战从零搭建一个AI文档问答系统理论讲多了容易飘我拿一个真实做过的最小闭环项目来说明整套方法论怎么落地。这个项目是一个“内部知识库AI问答助手”用户上传文档AI基于文档内容回答问题。项目定义阶段我按照SDD的思路把场景写清楚用户上传PDF、Word、TXT格式文档系统做文本解析用户针对文档内容提问系统基于检索结果回答并给出答案对应的原文位置。边界场景包括文件过大、扫描版PDF无法解析文本、问题超出文档范围等。技术栈选型如下文档解析用PyMuPDF处理PDF、python-docx处理Word向量化存储用ChromaDB向量嵌入模型用的是开源的BGE-M3质量不错且可以本地部署问答链路直接用OpenAI兼容接口调用大模型。实现上有几个关键步骤值得展开说。第一步是文档解析。这一环节最容易翻车PDF解析出来的文本经常伴有乱码、多余换行、表格错乱。PyMuPDF的处理逻辑是先按页提取文本如果某一页提取出来的文本长度接近零就判定为扫描页转而用OCR处理。OCR我用的是PaddleOCR它对中文的支持在开源方案里算比较出色的。第二步是切片和向量化。把所有文档按固定长度切片我习惯用一个可重叠的滑动窗口窗口大小500个字符重叠100个字符。为什么要重叠因为段落的分隔点很可能正好落在切片边界上导致一个完整语义被切碎检索时召回的内容不完整。切片后再对每个切片做向量化插入向量库的同时要保留原始的文档名、页码、章节路径这些元数据方便溯源。第三步是检索增强。用户提问后先用Embedding检索出最相关的3到5个文本切片把它们和问题一起组装成提示词再交给大模型生成答案。这一步的关键是“检索质量决定答案质量”生成类模型没法输出它没看到的信息所以检索结果的准确性是上限。我曾经做过一个对比实验不换模型、不换提示词只优化检索从向量模型换成BGE-M3后问答准确率提升了接近20个百分点。核心代码逻辑大致是from sentence_transformers import SentenceTransformer import chromadb from openai import OpenAI embedder SentenceTransformer(BAAI/bge-m3) chroma_client chromadb.PersistentClient(path./kb_store) collection chroma_client.get_or_create_collection(documents) def add_document(chunks, metadata_list): ids [fchunk_{i}_{j} for i, j in enumerate(metadata_list)] embeddings embedder.encode(chunks).tolist() collection.add( idsids, embeddingsembeddings, documentschunks, metadatasmetadata_list ) def ask_question(question: str): query_emb embedder.encode([question]).tolist() results collection.query(query_embeddingsquery_emb, n_results5) context \n\n.join(results[documents][0]) prompt f基于以下资料回答问题如果资料中没有答案请明确说明。\n\n资料\n{context}\n\n问题{question} client OpenAI() response client.chat.completions.create( modelgpt-4o, messages[{role: user, content: prompt}], temperature0.2 ) return response.choices[0].message.content这个代码只是演示核心链路实际生产环境还要加上文件格式识别、分片大小自适应、权限校验、答案引用溯源等功能。不过一个可运行的最小闭环本身就比一堆高深的架构设计有价值得多。我特别想强调一点AI项目的第一版一定要在最短时间内跑通全链路哪怕是拿最简单的脚本串起来的。很多团队一开始就追求架构完美结果花了两周搭框架核心业务逻辑一行还没写。我的经验是先用最简单的方式把功能跑通再逐层替换掉那些临时的实现。3.4 实战开发一个AI Agent工作流系统文档问答系统相对简单只有“检索→生成”两步。如果你的项目需要Agent参与复杂度会急剧上升但方法论是相通的。我这里再分享一个实际做过的Agent工作流案例任务是“自动处理客户反馈工单”。需求是这样的客服团队每天收到大量用户反馈每一封都包含问题描述、产品版本、用户环境。传统流程是人工先判断问题类别再根据类别分配到对应的技术团队。我们要做的Agent是替客服完成第一轮分类和初步诊断。任务拆解下来有四个环节信息抽取从工单中提取关键字段包括产品模块、错误类型、用户操作步骤问题分类根据抽取结果判断属于性能问题、Bug、使用疑问还是需求建议知识库检索针对分类结果检索相关的历史解决方案判断是否能直接答复用户标准化输出如果检索到匹配方案直接生成回复草稿如果没有匹配方案输出转人工建议。这个任务的复杂点在于每个环节之间是有依赖关系的分类结果会影响知识库检索的范围检索结果又会决定是生成回复还是转人工。我用LangGraph来编排这个流程每个环节作为一个节点节点间的转换通过条件判断决定。实现这段流程时我有几个比较深刻的体会信息抽取用结构化输出模式把工单文本变成一个JSON对象后续节点处理起来很顺畅不需要反复让模型猜字段分类环节不是让模型自由发挥而是给它一个封闭的类别列表限定候选范围准确率会高很多这个在工程上叫“标签约束”每个节点都要打日志记录输入、输出、Token消耗和耗时如果某个环节出错排查速度能快很多。4. AI应用的可观测性日志、监控与评测体系传统软件开发讲究日志、监控、告警AI应用开发同样需要这些但方式不同。因为模型输出的正确性不能简单地用布尔值判断你需要从成本、延迟、质量和稳定性多个维度来观察系统。4.1 请求日志怎么记才有价值模型请求日志是排查一切问题的第一入口。但大多数项目的日志都记得太原始了只记了“谁调用了哪个模型”“返回了什么”完全无法支撑后续的分析。我的建议是每次模型请求至少要记录以下字段请求唯一ID用于关联整个业务链路的日志模型名称和参数温度、最大Token、Top P请求的Token数、响应Token数、总Token数和按模型单价计算出的成本首Token延迟和总响应时间系统提示词版本号方便回溯是不是改了提示词导致效果变差输入消息的摘要完整内容可能涉及隐私或太大存摘要或哈希即可输出的状态码如果模型返回截断finish_reason为length也要单独标记。如果你用了LiteLLM Proxy这些字段大部分会被自动记录你再结合业务层的日志做一个关联查询就可以了。如果项目规模小没有专门的可观测平台至少也要保证日志格式统一、能按请求ID链路追踪排查问题的时候才不用靠猜。4.2 用评测集守住质量底线AI应用上线后最怕的就是“模型悄悄变差”你还在按老参数运行但输出质量已经不如从前。应对这个问题最有效的手段就是准备一套评测集在每次更换模型、修改提示词、调整检索策略后都拿这套评测集跑一遍对比答案质量。评测集的构建其实不难核心是要有代表性。我建议收集三类样本历史真实用户问题中高频出现的类型已知容易出错的边界案例不同难度等级的典型问题。每个问题对应一份标准答案标准答案不要求字字精确但要求关键信息点齐全。评测评分我推荐人工评分和自动化指标结合。自动化方面现在有一些基于大模型作为评判者的方式也就是用另一个强模型来给当前模型的输出打分这在业内叫LLM-as-a-judge。实测下来让大模型按照你给出的评分标准打分并让多个模型交叉打分取平均比单纯的Rouge、BLEU这些传统指标更能反映答案质量。注意评分标准一定要写得很细致比如“答案必须包含合同金额且数字准确金额单位不得遗漏”否则评判模型也会跟着模糊。评测一定要纳入开发流程而不是发布前的临时动作。我自己的习惯是每次修改提示词或更换模型后先跑评测集结果不劣化再考虑上线。这个习惯帮我挡住了好几次“表面感觉还行、实际质量下降”的改动。4.3 成本、延迟与限流AI应用的生产级指标最后再说一下从开发调试状态切换到生产运行状态后必须盯住的三项指标。成本是最直观的。AI应用的Token消耗和用户使用量是线性关系1万个用户实现有成本10万个用户成本就是10倍。我建议现在就按“单次请求成本”来做估算然后倒推你的商业模式能不能支撑这个成本。如果单次回答消耗约2000Token用旗舰模型大约要几毛钱人民币那你的用户转化和留存率必须覆盖这个成本。延迟是用户体验的关键。如果用户等了5秒才看到第一个字他们会觉得系统卡顿。我常用的优化手段包括模型降级和流式输出。流式输出能让首Token延迟从几秒缩短到几百毫秒这对体感提升非常明显。另一招是对简单问题直接用小模型复杂问题才路由到旗舰模型可以在保证质量的同时显著降低成本和延迟。限流和降级是生产环境的保命手段。AI应用的流量突发性很强某个功能在社交媒体上火了流量瞬间翻几十倍。如果底层模型供应商的配额被击穿你的服务就会雪崩。我建议在网关层做两层保护第一层是按用户维度的限流防止单个用户刷爆你的额度第二层是模型维度的降级策略主模型超时或抛错时自动切换到备用模型哪怕结果质量差一点也要保住服务的可用性。5. 常见问题与排查技巧实录AI应用开发有一个特点报错类型高度集中但每种报错背后的原因可能千差万别。我把过去实践中高频出现的问题整理成一份速查表方便你遇到类似情况时快速定位。现象常见原因排查方向模型返回空内容或突然中断上下文过长触发截断、内容被安全策略过滤、流式连接断开检查finish_reason字段查看被截断的位置和原因检查请求是否触发了内容审核输出内容格式不符合预期提示词约束不足、模型版本变化、温度设置过高改用结构化输出模式降低温度到0.2以下检查当前模型是否支持response_formatToken费用异常飙升上下文未做裁剪、有循环调用、检索结果一次性注入过多查看单次请求Token统计定位Token消耗最大的环节给历史消息加长度截断逻辑Agent卡在某个环节不返回工具调用没有超时、工具返回异常格式导致模型反复重试为所有节点和工具调用加超时控制检查工具返回值是否符合模型预期格式检索质量差导致回答不准切片过大或过小、嵌入模型不适合领域、未做查询改写调整切片窗口更换领域适配的嵌入模型对用户问题进行同义词改写后再检索提示词未改但效果波动模型供应商更新了底层模型版本、缓存命中策略变化关注模型版本发布公告用评测集验证当前线上效果必要时固定模型版本除了表格里的问题再分享三个我反复踩过的坑。第一个坑是把温度调得太高。很多人为了追求“创意”把温度设置到0.7甚至1.0结果做结构化提取任务时经常出现字段丢失、格式不一致的问题。后来我的习惯是抽取类和分类类任务温度固定在0到0.2问答类任务不超过0.3只有文案生成类任务才会上到0.7以上。第二个坑是模型升版不验证。大模型厂商不会特意通知你“我们换了底座模型”但实际运行效果可能天差地别。去年我就遇到过GPT-4o一个小版本更新后某个工单分类任务准确率下滑了6个百分点。排查几天后才发现是模型版本变化导致的。现在我的应对方式是关键任务的提示词增加版本号配合评测集每次发现波动先把提示词版本和模型版本锁定。第三个坑是无限度相信Agent的“自主性”。你看Agent演示时觉得它什么都会但放到生产环境里没有对环境变化的感知能力。比如工具接口返回结构变了、数据库字段改了Agent不会像人一样立刻意识到它只会反复用旧逻辑尝试。最好的防范措施是给Agent的每个工具调用都加异常捕获失败后返回结构化错误信息给模型让模型基于错误信息做下一次决策而不是让它瞎猜。这些经验背后有一条共通的思路AI开发和传统开发最大的区别就是不确定性。传统开发所有行为由代码决定AI开发有一半行为由模型决定。所以你能做的不是彻底消除不确定性而是把不确定性约束在一个可控范围内通过日志、评测、监控和快速回滚机制在不稳定中维持稳定。这个思路说到底就是harness的本意也是最值得花时间去打磨的部分。