1. 为什么现在聊 Agent 不能只聊概念过去一年我参与过三个不同规模的 Agent 项目落地从最初用 LangChain 拼一个能查天气的玩具到后来给一家中型电商做售后自动处理流程中间踩的坑比写过的代码还多。市面上讲 Agent 的文章绝大多数停留在“Agent 等于 LLM 加记忆加工具”这种三件套公式上看完之后你依然不知道从哪下手。真正卡住工程团队的从来不是概念本身而是那些藏在细节里的决策循环什么时候停、工具报错了怎么办、上下文塞满了怎么裁、多个 Agent 之间怎么传话。这篇内容我想干一件事把 AI Agent 从抽象概念拽回到工程地面上。我会先拆解构成一个可用 Agent 的七个核心要素然后重点讲七个真正影响成败的决策点。每个决策点我都会给出我实际用过的方案、参数选择的理由以及踩过的坑。不管你是刚接触 Agent 开发的新手还是已经写过几个 Demo 想往生产环境推的老手应该都能从中找到能直接抄作业的东西。需要提前说明的是Agent 的工程实现没有银弹。我下面讲的所有方案都是基于“常见实践加个人经验”的合理补全具体到你的业务场景参数和策略都需要重新校准。但决策的逻辑和排查的思路是通用的。2. 拆解 AI Agent 的七个核心要素在聊决策点之前得先把 Agent 的构成说清楚。我把一个能跑起来的 Agent 拆成七个要素这七个要素缺一个Agent 要么跑不起来要么跑起来也是个智障。2.1 大脑LLM 的选型不是越强越好LLM 是 Agent 的推理核心负责理解意图、规划步骤、生成工具调用参数。很多人一上来就选最强的模型觉得贵有贵的道理。我实测下来的结论是选型要看任务复杂度不是看榜单排名。对于意图识别和简单工具调用一个 7B 到 14B 的模型微调后完全够用推理成本只有大模型的十分之一不到。我做过一个对比测试在售后工单分类任务上微调后的 Qwen 14B 准确率 94.2%而某个千亿参数大模型 zero-shot 是 96.1%差距不到两个点但成本差了将近二十倍。当然如果你的 Agent 需要做多步复杂推理比如根据用户模糊描述定位到具体订单再判断是否符合退款条件那大模型的优势就体现出来了。选型时我一般看三个指标工具调用格式的遵循率、多步推理的准确率、首 token 延迟。前两个决定能不能用第三个决定用户体验。工具调用格式遵循率低于 90% 的模型直接淘汰因为你会花大量时间在解析错误上。2.2 记忆短期和长期要分开设计记忆分两层。短期记忆就是当前对话的上下文窗口长期记忆是跨会话持久化的信息。很多新手把两者混在一起结果要么上下文爆炸要么 Agent 记不住用户上周说过的话。短期记忆的管理核心是裁剪策略。我常用的方案是滑动窗口加摘要压缩保留最近 N 轮完整对话更早的内容用 LLM 压缩成一段摘要。N 的取值取决于你的模型上下文长度和任务类型一般 5 到 10 轮是个合理起点。长期记忆我倾向于用向量数据库加结构化存储的组合。向量库存语义相关的片段结构化存储存用户 ID、订单号这类精确信息。检索时先走结构化过滤再做语义召回比纯向量检索准得多。2.3 工具接口设计比工具数量重要工具是 Agent 的手脚。我见过有人给 Agent 塞了三十多个工具结果模型选择困难调用准确率反而下降。工具不在多在于边界清晰。每个工具的描述要回答三个问题什么时候用、输入是什么、输出是什么。描述里要包含反例比如“当用户询问订单状态时使用此工具不要用于查询物流轨迹”。我习惯把工具按领域分组每组不超过七个超过就考虑拆分子 Agent。工具的参数设计也有讲究。能用枚举就不用自由文本能加默认值就不要让模型猜。我踩过一个坑一个查询工具的时间参数让模型自由生成结果模型经常生成“昨天”这种相对时间后端解析直接报错。后来改成枚举值加默认值错误率从 15% 降到 2% 以下。2.4 规划ReAct 不是唯一解规划能力决定 Agent 能不能把复杂任务拆成可执行的步骤。ReAct 是最常见的范式思考、行动、观察循环。但 ReAct 有个问题每一步都要调一次 LLM延迟高、成本高。对于步骤相对固定的任务我推荐用计划加执行的两阶段方案。先让 LLM 生成一个完整的步骤列表然后按列表逐步执行执行过程中只在必要时重新规划。这样 LLM 调用次数从 N 次降到 2 到 3 次延迟大幅下降。缺点是灵活性不如 ReAct适合流程标准化的场景。还有一种情况是任务完全开放比如“帮我规划一个三天的旅行”。这种就得用 ReAct 或者更复杂的树搜索方案。选哪种规划方式取决于你的任务空间是否可枚举。2.5 执行循环机制是 Agent 的心脏执行环节的核心是循环机制。Agent 不是一次调用就结束而是一个循环推理、调用工具、获取结果、再推理直到满足终止条件。循环机制要解决三个问题什么时候继续、什么时候停、出错了怎么办。我见过最粗暴的实现是固定循环五次不管任务有没有完成。这种方案在简单任务上能用复杂任务上要么提前终止要么浪费调用。合理的做法是设置多重终止条件任务完成信号、最大循环次数、连续无进展检测、超时控制。这四个条件任意一个触发就终止。最大循环次数我一般设 10 到 15连续无进展检测是如果连续两轮的工具调用结果高度相似就判定卡住主动终止并返回当前状态。2.6 编排单 Agent 还是多 Agent编排解决的是多个 Agent 或多次调用之间怎么协作。单 Agent 适合任务边界清晰的场景多 Agent 适合需要不同专业能力的复杂流程。我个人的经验是能用单 Agent 解决就不要上多 Agent。多 Agent 的通信开销、状态同步、错误传播都是指数级增长的。我做过一个客服场景单 Agent 加工具分组方案准确率 91%改成三个 Agent 协作后准确率反而降到 87%因为 Agent 之间的信息传递丢失了上下文。如果确实需要多 Agent我推荐用主管加专家的模式。一个主管 Agent 负责路由和汇总专家 Agent 各自处理特定领域。主管不参与具体执行只做分发和结果整合。2.7 安全从第一天就要考虑安全不是事后补丁是设计原则。Agent 的安全风险主要来自三个方面工具调用的越权、提示注入、输出内容的风险。工具调用要做权限校验每个工具声明自己需要的权限级别Agent 调用前先检查当前会话是否有对应权限。提示注入的防御比较难我的做法是在系统提示里明确指令边界同时对用户输入做敏感模式检测。输出内容的风险控制靠后置过滤用规则加模型双重校验。这七个要素构成了 Agent 的骨架。但骨架不等于能跑真正决定 Agent 好不好用的是下面七个决策点。3. 七个决策点Agent 工程实现的关键分岔路3.1 决策点一循环终止条件怎么设循环终止是 Agent 工程里最容易被低估的问题。设得太松Agent 会陷入死循环烧钱设得太紧任务没完成就退出。我的方案是四层终止条件叠加终止条件触发逻辑推荐参数优先级任务完成信号LLM 输出特定结束标记自定义标记最高最大循环次数计数器达到阈值10-15 次高连续无进展连续两轮工具结果相似度超阈值0.85中超时控制总耗时超过限制30-60 秒低任务完成信号是最理想的终止方式但依赖 LLM 正确输出结束标记。我一般会在系统提示里明确要求“当你认为任务已完成时输出 FINISH 标记并附上最终答案。”实测下来遵循率大概在 85% 左右所以需要其他条件兜底。最大循环次数是硬性保险。10 到 15 次是我反复测试后的经验值。低于 10 次复杂任务容易中断高于 15 次收益递减明显而且一旦模型陷入循环烧钱速度很快。连续无进展检测需要计算工具结果的相似度。我用的是简单的文本相似度加关键字段比对。如果连续两轮调用了同一个工具、参数相似、返回结果也相似就判定卡住。这时候不要直接退出而是让 LLM 做一次“反思”问它“你是否遇到了困难是否需要换一种方式”给它一次自救机会。超时控制是最后一道防线防止某个工具调用卡死导致整个流程挂起。30 到 60 秒是个合理范围具体看你的工具响应时间。注意终止条件不要只依赖 LLM 的自我判断。我踩过的坑是模型在任务没完成时输出了 FINISH导致用户收到不完整的答案。后来我在终止前加了一步校验用规则检查关键字段是否齐全不齐全就强制继续。3.2 决策点二工具调用失败怎么恢复工具调用失败是常态不是异常。网络抖动、参数错误、下游服务不可用都会导致失败。Agent 的健壮性就体现在失败恢复上。我把失败分成三类每类用不同的恢复策略第一类是可重试失败比如网络超时、限流。这类失败直接重试但要有退避策略。我一般用指数退避第一次等 1 秒第二次 2 秒第三次 4 秒最多重试三次。重试时要记录日志如果同一个工具连续重试都失败说明不是偶发问题要升级处理。第二类是可修正失败比如参数格式错误、缺少必填字段。这类失败要把错误信息返回给 LLM让它修正参数后重新调用。这里有个技巧错误信息要结构化包含错误码、错误描述、期望格式。我试过只返回“参数错误”模型完全不知道怎么改返回“参数 date 格式错误期望 YYYY-MM-DD实际收到 2024/01/01”模型一次就改对了。第三类是不可恢复失败比如权限不足、资源不存在。这类失败不要重试直接把错误信息返回给用户并给出替代方案。比如“查询订单失败该订单不存在请确认订单号是否正确”。恢复策略的选择逻辑可以用一个简单的决策树表示先判断错误类型可重试就重试可修正就修正不可恢复就上报。每类失败都要记录用于后续分析工具质量和模型能力。实操心得我会给每个工具设置一个失败计数器如果某个工具在短时间内失败率超过 30%就自动降级暂时从可用工具列表中移除避免 Agent 反复调用一个坏工具。这个机制在线上环境救过我好几次。3.3 决策点三上下文窗口满了怎么裁上下文窗口是稀缺资源。Agent 运行过程中对话历史、工具结果、系统提示都在消耗 token。窗口满了之后要么报错要么性能下降。裁剪策略我分三步走第一步是压缩工具结果。工具返回的原始数据往往很长但 Agent 只需要其中的关键字段。我一般会在工具层做一次预处理只返回必要信息。比如查询订单的工具原始返回可能有几十个字段但 Agent 只需要订单号、状态、金额、时间这四个。预处理后 token 消耗能降低 70% 以上。第二步是摘要历史对话。保留最近 N 轮完整对话更早的用 LLM 压缩成摘要。摘要要保留关键信息用户意图、已确认的事实、未解决的问题。我用的提示词是“请将以下对话压缩成一段摘要保留用户的核心诉求、已确认的关键信息、以及尚未解决的问题。不要添加任何新信息。”第三步是动态调整系统提示。系统提示里的工具描述、示例、规则可以根据当前任务阶段动态加载。比如任务刚开始时加载完整的工具列表任务进行到一半时只加载可能用到的工具描述。这样能省下不少 token。裁剪的时机也很重要。不要等到窗口满了才裁而是在使用率达到 70% 到 80% 时就开始。我一般设一个阈值超过就触发裁剪流程。裁剪后要重新计算 token 数确保留出足够的空间给后续的推理和工具调用。3.4 决策点四多轮对话的状态怎么管Agent 的多轮对话不是简单的消息追加而是有状态的任务执行。状态管理没做好会出现上下文丢失、重复执行、状态不一致等问题。我的方案是用一个显式的状态对象来管理。这个对象包含当前任务阶段、已完成的步骤、待完成的步骤、收集到的关键信息、工具调用历史。每次 LLM 调用时把状态对象序列化后注入到提示里。状态对象的更新由 LLM 的输出驱动。LLM 每次输出除了工具调用或最终答案还要输出状态更新指令。比如“已完成步骤 1当前进入步骤 2已收集信息订单号 12345”。这样状态始终和 LLM 的推理保持同步。状态持久化也很关键。对于长任务状态要存到数据库支持断点续跑。我一般用 Redis 存运行时状态用关系库存最终结果。Redis 的过期时间设得比任务超时时间长一些防止任务还没结束状态就丢了。注意状态对象不要太大否则会挤占上下文窗口。我一般控制在 500 token 以内只存关键信息详细历史放在外部存储需要时再检索。3.5 决策点五工具描述怎么写才准工具描述是 LLM 选择工具的唯一依据。描述写得模糊模型就会选错工具或者不选工具。我写工具描述遵循一个模板功能一句话、使用场景、输入参数说明、输出说明、反例。举个例子工具名query_order 功能根据订单号查询订单详情 使用场景当用户提供订单号并询问订单状态、金额、时间时使用 输入参数 - order_id (string, 必填)订单号格式为 16 位数字 输出订单状态、金额、创建时间、支付时间 反例不要用于查询物流轨迹不要用于修改订单这个模板的关键是反例。反例能帮模型划清边界减少误调用。我实测加了反例之后工具选择准确率提升了 12 个百分点。工具描述的长度也要控制。太短信息不足太长浪费 token。我一般控制在 100 到 150 字之间。如果工具逻辑复杂就把详细说明放在外部文档描述里只放摘要和文档链接。还有一个技巧是给工具加版本号。当工具接口变更时旧版本的描述要保留一段时间让 Agent 平滑过渡。我见过因为工具描述突然变更导致线上 Agent 大面积选错工具的事故。3.6 决策点六Agent 之间怎么通信多 Agent 场景下通信协议的设计直接决定系统能不能跑通。我见过太多多 Agent 项目死在通信上。通信要解决三个问题消息格式、路由机制、错误传播。消息格式我推荐用结构化的 JSON包含发送者、接收者、消息类型、负载、时间戳。消息类型分几种任务分派、结果返回、状态同步、错误上报。负载里放具体内容。结构化格式的好处是可解析、可追溯、可校验。路由机制分两种静态路由和动态路由。静态路由是预先定义好 Agent 之间的调用关系简单可靠但不够灵活。动态路由是主管 Agent 根据任务内容决定分派给谁灵活但依赖主管的判断准确率。我一般用静态路由做主干动态路由做补充。错误传播要特别小心。一个 Agent 出错不能让它静默失败也不能让错误无限扩散。我的做法是错误上报给主管 Agent由主管决定是重试、降级还是终止。同时设置错误传播深度限制超过三层就强制终止防止错误级联。实操心得多 Agent 通信一定要加超时和重试。我踩过的坑是一个 Agent 等待另一个 Agent 的响应结果对方挂了等待方一直阻塞整个流程卡死。后来加了超时机制超时后走降级逻辑系统稳定性大幅提升。3.7 决策点七怎么评估 Agent 好不好用Agent 上线不是终点评估和迭代才是。没有评估体系你根本不知道 Agent 是在进步还是在退步。我用的评估体系分三层单元测试、端到端测试、线上监控。单元测试针对单个能力比如工具调用准确率、意图识别准确率。我一般准备 100 到 200 条测试用例覆盖正常和边界情况。每次修改提示词或工具描述后跑一遍确保没有回归。端到端测试针对完整任务比如“用户要退款”这个场景从意图识别到最终回复全流程跑通。端到端测试用例不用多20 到 30 条覆盖主要场景就行但要定期跑最好每天一次。线上监控看四个指标任务完成率、平均循环次数、工具调用失败率、用户满意度。任务完成率低于 80% 就要排查平均循环次数突然升高说明模型能力下降或工具出了问题工具调用失败率超过 10% 要检查下游服务用户满意度靠反馈按钮收集。评估结果要形成闭环。发现问题后定位是提示词问题、工具问题还是模型问题针对性修复然后重新跑评估。我一般每周做一次评估复盘把问题分类统计优先解决高频问题。4. 从零搭建一个 Agent 的实操流程前面讲了要素和决策点这一节我把它们串起来给一个从零搭建的实操流程。以“电商售后自动处理 Agent”为例这个 Agent 要能识别用户意图、查询订单、判断是否符合退款条件、执行退款或转人工。4.1 环境准备与依赖选型技术栈我选的是 Python 加 FastAPI 加 Redis 加 PostgreSQL。LLM 用微调后的 Qwen 14B部署在内网延迟可控。向量库用 Milvus 存长期记忆。工具层用 FastAPI 暴露 HTTP 接口Agent 通过 HTTP 调用。为什么不用 LangChain 这类框架我试过对于简单 Demo 确实快但到了生产环境框架的抽象层反而成了负担。调试困难、定制化受限、版本升级容易出兼容问题。我现在的做法是核心逻辑自己写只借用框架的个别组件。依赖清单pip install fastapi uvicorn redis psycopg2-binary pymilvus httpx pydanticLLM 调用我封装了一个统一的客户端支持重试、超时、日志记录。这个客户端是所有 LLM 调用的入口方便统一管理。4.2 核心循环的实现核心循环的伪代码逻辑如下def run_agent(user_input, session_id): state load_state(session_id) state.add_message(user, user_input) for i in range(MAX_LOOPS): if check_timeout(state): return build_timeout_response(state) context build_context(state) llm_output call_llm(context) if is_finish(llm_output): if validate_finish(llm_output, state): return llm_output.answer else: state.add_message(system, 答案不完整请继续) continue if llm_output.has_tool_call(): result execute_tool(llm_output.tool_call) state.add_message(tool, result) state.update_progress(llm_output.tool_call, result) if is_stuck(state): state.add_message(system, 检测到卡住请反思并换一种方式) save_state(session_id, state) return build_max_loop_response(state)这个循环里build_context负责组装提示包含系统提示、状态摘要、最近对话、工具描述。execute_tool负责工具调用和失败恢复。is_stuck负责连续无进展检测。4.3 工具层的实现要点工具层我按领域分组售后场景下有订单工具、退款工具、用户工具三组。每组工具用独立的 FastAPI 路由方便权限控制和限流。订单查询工具的实现app.post(/tools/query_order) async def query_order(order_id: str): if not validate_order_id(order_id): return {error: INVALID_FORMAT, message: 订单号格式错误期望16位数字} order db.query_order(order_id) if not order: return {error: NOT_FOUND, message: 订单不存在} return { order_id: order.id, status: order.status, amount: order.amount, created_at: order.created_at.isoformat() }注意返回结构里只包含 Agent 需要的字段不返回原始数据库记录。错误返回也是结构化的包含错误码和可读描述方便 LLM 理解和修正。4.4 提示词的组织方式系统提示我分成四段角色定义、能力边界、工具说明、输出格式。角色定义告诉 LLM 它是售后助手能力边界说明什么能做什么不能做工具说明列出可用工具输出格式规定 LLM 的输出结构。输出格式我用 JSON Schema 约束{ type: object, properties: { thought: {type: string}, action: {type: string, enum: [tool_call, finish]}, tool_name: {type: string}, tool_params: {type: object}, answer: {type: string} } }用结构化输出能大幅降低解析错误率。我实测从自由文本解析改成 JSON 约束后解析失败率从 8% 降到 0.5% 以下。4.5 状态管理的落地状态对象我用 Pydantic 模型定义包含 session_id、task_stage、completed_steps、pending_steps、collected_info、tool_history、created_at、updated_at。状态存在 Redis 里key 是 session_idvalue 是序列化后的 JSON。每次循环结束更新状态设置过期时间为 1 小时。任务完成后把最终状态归档到 PostgreSQL用于后续分析。状态恢复的逻辑是新请求进来先查 Redis有状态就加载没有就初始化。这样即使用户中途离开再回来任务也能继续。5. 常见问题与排查技巧实录这一节我整理实际项目中遇到的高频问题和排查方法都是踩过坑之后总结出来的。5.1 工具调用格式错误排查现象LLM 输出的工具调用参数格式不对解析失败。排查步骤检查系统提示里的工具描述是否清晰参数类型和格式是否明确检查是否用了结构化输出约束没有的话加上检查模型是否支持工具调用有些小模型对工具调用格式遵循率很低检查参数是否有默认值没有默认值的必填参数容易出错解决方案我一般会加一层参数校验和自动修正。比如日期格式错误尝试用常见格式解析后重新格式化。修正不了的再返回给 LLM 重新生成。5.2 Agent 陷入死循环排查现象Agent 反复调用同一个工具循环次数达到上限才退出。排查步骤看工具返回结果是否包含足够信息让 LLM 判断下一步看系统提示是否明确要求 LLM 在获得足够信息后输出 FINISH看连续无进展检测是否生效阈值是否合理看工具是否有副作用有副作用的工具重复调用可能造成问题解决方案我遇到过一次是因为工具返回结果里没有明确的状态字段LLM 无法判断任务是否完成。后来在工具返回里加了is_complete字段问题解决。5.3 上下文溢出排查现象LLM 调用报 token 超限错误。排查步骤统计系统提示、对话历史、工具结果的 token 占比检查工具结果是否做了预处理有没有返回冗余字段检查历史对话是否做了摘要压缩检查是否有大对象被意外序列化进上下文解决方案我一般会在 build_context 里加 token 计数超过阈值就触发裁剪。裁剪顺序是先压缩工具结果再摘要历史对话最后精简系统提示。5.4 多 Agent 通信超时排查现象Agent A 等待 Agent B 响应长时间阻塞。排查步骤检查 Agent B 是否存活日志是否有报错检查通信链路是否有网络问题检查 Agent B 的处理逻辑是否陷入死循环检查超时设置是否合理解决方案所有 Agent 间调用必须设超时超时后走降级逻辑。我一般设 10 秒超时超时后返回默认结果并记录告警。5.5 常见问题速查表问题现象可能原因排查方向解决手段工具选错描述模糊、反例缺失检查工具描述补充反例和边界说明循环不终止终止条件缺失检查终止逻辑加多重终止条件上下文溢出裁剪策略缺失统计 token 占比加预处理和摘要状态丢失持久化缺失检查存储加 Redis 持久化响应慢循环次数多看平均循环数优化提示和工具答案不完整提前终止检查终止校验加完成度校验最后分享一个排查技巧我会给每次 Agent 运行生成一个 trace_id所有日志都带上这个 ID。出问题时用 trace_id 串起完整链路从用户输入到最终输出每一步的提示、LLM 输出、工具调用、状态变更都能看到。这个习惯帮我节省了大量排查时间。6. 一些关于 Agent 工程的个人体会做 Agent 这一年多最大的感受是Agent 的难点不在 AI在工程。模型能力固然重要但决定 Agent 能不能上生产的是循环控制、错误恢复、状态管理这些传统软件工程的功夫。我见过太多团队花大量时间调提示词、换模型却忽略了循环终止条件没设好、工具失败没恢复、状态没持久化这些基础问题。结果 Demo 很惊艳一上生产就各种问题。另一个体会是简单方案往往更可靠。单 Agent 能解决的就不要上多 Agent规则能解决的就不要上模型固定流程能解决的就不要上动态规划。每增加一层复杂度就多一个故障点。我现在的原则是先用最简单的方式跑通遇到瓶颈再逐步增加复杂度。还有一点是关于评估。没有评估体系的 Agent 项目就是在裸奔。你改了一个提示词怎么知道是变好了还是变坏了只能靠评估。我建议从项目第一天就建立评估集哪怕只有几十条用例也比没有强。最后说一个容易被忽略的点Agent 的响应时间。用户对 Agent 的耐心比对人少得多。一个需要 30 秒才能回复的 Agent用户大概率会关掉。所以延迟优化要贯穿始终能并行的工具调用就并行能缓存的就缓存能预处理的就预处理。我一般把首 token 延迟控制在 2 秒以内完整响应控制在 10 秒以内超过这个范围就要优化。这些体会没有什么高深的理论都是实际项目中撞了南墙之后总结出来的。Agent 这个领域变化很快新的框架、新的模型、新的范式层出不穷但底层的工程原则是相对稳定的。把循环、状态、错误处理这些基础打牢上层怎么变都能接得住。