1. 从“七要素”到“七个决策点”为什么 Agent 工程化需要一套拆解框架1.1 一个真实场景引出的问题去年下半年我接手了一个内部知识库问答助手的改造项目。最初的需求听起来很简单让模型能回答公司内部文档相关的问题。我当时的想法也很朴素——把文档切片、做向量检索、拼进提示词、调模型生成答案一套标准的 RAG 流程走完就收工。上线第一周效果确实还行但第二周开始运营同事反馈的问题就变得五花八门有人问“帮我查一下上季度的报销政策顺便算一下我这种情况能报多少”模型检索到了政策文档却不会做那一步计算有人问“这个流程走完之后下一步找谁”模型答得头头是道但引用的文档其实是两年前的旧版本还有人连续追问三轮之后模型把第一轮说过的结论完全忘了。这些问题单独看都不难但放在一起就暴露了一个本质我做的那个东西严格来说只是一个“检索增强的问答接口”而不是一个 Agent。它没有决策能力没有工具使用能力没有记忆管理也没有对自身行为的校验。后来我把这套系统推倒重做引入了工具调用、状态管理和循环控制才真正把它变成了一个能处理多步任务的智能体。这段经历让我意识到一件事Agent 的工程实现难点从来不在“让模型说话”而在于“让模型在正确的时机做正确的决策”。而要把这件事讲清楚光靠“Agent LLM 记忆 工具 规划”这种公式是不够的因为公式只告诉你组件有哪些没告诉你这些组件在运行时是怎么协作的、每个环节要做哪些取舍。1.2 七要素Agent 的静态解剖业内比较通用的一个拆解方式是把 Agent 的构成归纳为七个要素。我把它整理成下面这张表方便对照理解要素作用缺失后的典型症状大模型LLM推理与决策核心系统退化为规则引擎无法处理开放输入提示词与角色设定定义行为边界与输出格式输出漂移格式不稳定角色混乱记忆短期/长期维持上下文与跨会话知识多轮对话失忆无法积累经验工具/函数调用与外部世界交互只能“说”不能“做”规划与任务分解把复杂目标拆成可执行步骤面对多步任务直接卡死或乱答执行循环驱动“思考-行动-观察”反复进行只能单轮响应无法迭代逼近目标校验与容错检查结果、纠正偏差错误一路传导最终输出不可信这七个要素里前两个几乎所有做 LLM 应用的人都会碰中间三个是区分“聊天机器人”和“Agent”的分水岭最后两个则是决定一个 Agent 能不能上生产的关键。我见过太多项目前五个要素做得像模像样一到执行循环和容错就草草了事结果 demo 惊艳、上线翻车。1.3 七个决策点Agent 的动态视角但光有静态拆解还不够。真正写代码的时候你会发现七要素是“名词”而工程实现里你面对的全是“动词”——你要决定什么时候调工具、什么时候停止循环、记忆存什么丢什么、失败了重试几次。这些决策点才是代码里真正要写逻辑的地方。我把它们归纳为七个决策点意图判定这一轮输入到底是要闲聊、要检索、还是要执行一个多步任务工具选择在当前上下文下应该调用哪个工具、传什么参数循环控制什么时候继续下一轮什么时候终止记忆写入哪些信息值得持久化哪些用完即弃记忆读取当前这一步需要召回哪些历史信息结果校验工具返回或模型输出是否可信、是否需要重试失败降级当重试也解决不了时如何优雅地兜底七要素回答“系统由什么组成”七个决策点回答“运行时怎么运转”。前者是架构图后者是流程图。两者结合才是一套能落地的工程认知。下面我就按这个框架把每个环节的实现细节和踩坑经验展开讲。2. 七要素的工程落地每个组件到底该怎么写2.1 大模型选型不是越大越好而是越“听话”越好选模型这件事新手最容易犯的错是唯参数论。我早期也这样觉得 70B 一定比 7B 强闭源旗舰一定比开源强。但实际做 Agent 的时候模型的核心能力要求跟做纯对话完全不一样。Agent 对模型的要求排在第一位的不是知识量而是指令遵循能力和结构化输出稳定性。因为 Agent 的每一步输出都要被程序解析——你要从模型输出里提取出“调用哪个工具、参数是什么”如果模型时不时给你加一句“好的我来帮你查一下”解析就崩了。我实测下来的经验是一个 7B 到 14B 级别、经过函数调用专项微调的模型在 Agent 场景下的表现往往比一个没做过工具调用对齐的大模型更稳。原因很简单前者被训练成“该输出 JSON 就输出 JSON”后者还保留着强烈的对话惯性。具体选型时我会看三个指标结构化输出成功率连续跑 100 次工具调用请求能正确解析的比例。低于 95% 的基本不能上生产。首 token 延迟Agent 是多轮循环每轮延迟会累加。单轮 2 秒和单轮 5 秒跑五轮就是 10 秒和 25 秒的差距。上下文窗口的实际可用性标称 128K 不代表 128K 都好用很多模型在超过 32K 之后注意力就明显涣散。我会用“大海捞针”测试实际有效窗口。提示不要用同一个模型干所有事。意图判定、工具选择这类结构化任务用小模型需要深度推理的规划任务用大模型。这种“大小模型混用”的架构成本和延迟都能降一大截。2.2 提示词与角色设定把“人设”写成“契约”很多人写 Agent 的提示词写的是角色描述“你是一个专业的客服助手要热情、耐心……”这种写法对聊天机器人够用对 Agent 远远不够。Agent 的提示词本质上是一份行为契约它要明确规定你能做什么、不能做什么、输出什么格式、遇到什么情况走什么分支。我习惯把 Agent 的系统提示词拆成五块身份与目标一句话说清这个 Agent 存在的目的。能力边界明确列出可用工具以及每个工具的适用场景。输出格式规范用 schema 或示例固定输出结构。决策规则什么情况下直接回答什么情况下必须调工具什么情况下要追问用户。失败处理约定工具报错时怎么表述信息不足时怎么处理。这里有个反直觉的经验提示词里“不要做什么”比“要做什么”更重要。因为模型天生倾向于“帮忙”你不明确禁止它就会在信息不足时编造、在工具失败时假装成功。我通常会在提示词里硬性写几条禁令比如“如果工具返回为空必须如实告知禁止基于猜测作答”。2.3 记忆系统短期靠上下文长期靠检索记忆这块我踩过最大的坑是“什么都想记”。早期我设计了一个长期记忆模块把每轮对话都摘要存进向量库结果检索时召回一堆无关的旧信息反而干扰了当前推理。后来我调整了策略把记忆分成两层短期记忆就是当前会话的上下文窗口。这里存的是原始对话和工具调用记录不做摘要保证信息无损。但要有窗口管理策略超出长度就按“保留最近 N 轮 保留关键节点”的方式裁剪。长期记忆只存三类东西——用户明确表达的偏好、已经确认的事实结论、跨会话需要延续的任务状态。其他一律不存。判断一条信息该不该进长期记忆我用一个简单的标准这条信息在下一个会话里被用到的概率是否大于它造成干扰的概率。如果拿不准就不存。宁可少记不可乱记。2.4 工具调用接口设计比模型能力更影响成功率工具调用失败很多人第一反应是“模型不行”。但我排查下来相当一部分失败其实是工具接口设计的问题。举个例子我做过一个查询订单状态的工具参数是order_id。模型经常传进来一个带前缀的字符串比如 “订单号12345”导致查询失败。后来我在工具描述里明确写了参数格式并且在服务端做了一层清洗成功率立刻从 80% 出头涨到 98%。工具设计我总结了几条原则参数尽量少而明确能用一个参数说清就别用三个能枚举就别用自由文本。工具描述要写“什么时候用”不只是写功能还要写适用场景帮模型做选择。返回值要结构化且精简返回一大坨原始数据既占上下文又干扰推理最好在工具层就做裁剪。错误信息要可读返回“参数 order_id 格式错误应为纯数字”比返回一个 500 错误码有用得多模型能据此自我纠正。2.5 规划与任务分解让模型“先想后做”规划能力是 Agent 处理复杂任务的关键。我的做法是在正式执行前加一个规划阶段让模型先把任务拆成步骤列表再逐步执行。但这里有个陷阱——不是所有任务都值得规划。简单任务强行规划反而增加延迟和出错概率。我的判断标准是如果这个任务需要调用两次以上工具或者步骤之间有依赖关系就值得规划否则直接执行。规划的输出我要求是结构化的步骤列表每步包含“目标”和“预期使用的工具”。执行过程中如果某一步的结果与预期偏差较大允许回到规划阶段重新拆解。这种“规划-执行-再规划”的弹性比一次性规划到底要稳得多。2.6 执行循环Agent 的心脏执行循环是 Agent 区别于单轮问答的核心机制。它的基本形态是一个 while 循环模型思考 → 决定行动 → 执行工具 → 观察结果 → 判断是否继续。这个循环看起来简单但工程上有几个必须处理的点最大轮数限制一定要设上限否则模型可能陷入死循环。我一般设 8 到 10 轮。循环终止条件不只是“模型说完成了”还要有程序侧的判断比如“连续两轮没有新的工具调用”就终止。每轮的状态记录把每轮的思考、行动、观察都记下来既用于下一轮上下文也用于事后排查。2.7 校验与容错决定能不能上生产这是最容易被忽视、但最重要的一环。校验分两层输出格式校验和内容合理性校验。格式校验好做用 schema 验证就行。内容校验难一些我的做法是引入一个轻量的“裁判”环节——用另一个模型调用或者同一个模型的不同提示词来判断当前结果是否回答了原始问题、是否与已知事实矛盾。这就是业内常说的 LLM as judge 思路。容错则要设计重试和降级策略。我的默认配置是工具调用失败重试 2 次每次调整参数或换工具重试仍失败则降级为“告知用户当前无法完成并说明原因”。永远不要让 Agent 在失败时假装成功这是信任的底线。3. 七个决策点的实现细节代码里真正要写逻辑的地方3.1 意图判定第一道分水岭意图判定决定了后续走哪条路径。我的实现方式是用一次轻量模型调用做分类把输入归到几个预定义类别闲聊、知识问答、工具执行、多步任务、澄清追问。这里的关键是分类粒度要适中。太粗后续逻辑没法分支太细分类本身容易出错。我一般控制在 5 到 7 类。还有一个实用技巧把意图判定和路由合并。与其先分类再路由不如让模型直接输出“应该走哪个处理函数”减少一次信息转换的损耗。3.2 工具选择给模型一份“菜单”工具选择本质是一个受限的选择题。我的做法是把所有可用工具整理成一份带描述的清单放进提示词让模型输出工具名和参数。提升选择准确率的几个手段工具数量控制在 10 个以内超过之后选择准确率明显下降需要做分组或分层。给每个工具写正例和反例明确“这个工具适合什么、不适合什么”。允许模型输出“无需工具”否则它会硬凑一个工具来调用。3.3 循环控制什么时候该停循环控制有两个方向该继续时别停该停时别继续。该继续的典型场景任务还没完成、还有未处理的子目标、上一轮工具返回了需要进一步处理的数据。该停的场景任务完成、达到最大轮数、连续无进展、遇到无法恢复的错误。我实现时会给每轮打一个“进展分”如果连续两轮进展分为零就强制终止并返回当前最佳结果。这个机制救过我好几次避免了无限循环烧 token。3.4 记忆写入与读取两个独立的决策写入和读取要分开设计这是很多人会混淆的地方。写入决策这一步产生了什么值得记住的信息我的规则是——用户偏好、确认的事实、任务状态三类写入长期记忆其余只留在短期上下文。读取决策当前这一步需要哪些历史信息我的做法是基于当前输入做一次检索召回相关记忆但限制召回数量一般 3 到 5 条避免上下文被稀释。3.5 结果校验三道防线我通常设三道校验格式校验schema 验证不通过直接重试。一致性校验与已知事实、前序结论比对矛盾则标记。相关性校验判断结果是否真的回答了问题用 judge 模型打分。三道都过才进入下一轮或返回给用户。3.6 失败降级优雅地认输降级策略我分三级一级重试调整参数或换工具。二级换策略比如从工具执行降级为知识问答。三级如实告知说明卡在哪一步、需要用户提供什么。第三级最重要也最考验产品设计。一个好的失败提示应该让用户知道“系统尽力了但确实需要更多信息”而不是一句冷冰冰的“抱歉我无法处理”。4. 常见问题与排查技巧实录4.1 工具调用成功率低怎么办先别急着换模型按这个顺序排查排查项检查方法常见问题工具描述读一遍描述是否说清了适用场景描述太笼统模型不知道何时用参数格式看失败案例的参数格式不匹配缺清洗层工具数量数一下当前可用工具超过 10 个选择困难提示词是否有明确的调用规则缺少“何时必须调用”的约束模型能力换一个做过函数调用微调的模型对比模型本身不擅长结构化输出4.2 循环停不下来这是最烧钱的问题。我的排查清单最大轮数是否设置没设就是无限循环。终止条件是否包含“无新工具调用”只靠模型自述“完成”不可靠。是否有进展检测连续无进展必须强制终止。工具是否返回了空结果导致模型反复重试空结果要有明确处理。4.3 多轮对话失忆先确认是短期记忆还是长期记忆的问题。如果是同一会话内失忆检查上下文裁剪策略是不是裁太狠了。如果是跨会话失忆检查长期记忆的写入和召回是否正常工作。我遇到过一个隐蔽的 bug长期记忆写入了但召回时用的相似度阈值太高导致几乎召不回任何东西。把阈值调低之后立刻正常。4.4 输出格式不稳定这是结构化输出的经典问题。三个手段一是用 schema 约束二是给 few-shot 示例三是加格式校验和重试。三者叠加基本能压到 99% 以上。注意格式校验失败后的重试要把失败原因一起喂回给模型比如“上次输出缺少 tool_name 字段”这样它才知道怎么改。4.5 成本失控Agent 的成本是乘法级的——多轮循环乘以每轮的模型调用。控制成本的核心是减少不必要的轮次和调用。我的几个做法意图判定用小模型、简单任务不规划、工具返回精简、记忆召回限量、设置合理的最大轮数。实测下来这些优化叠加能把成本压到原来的三分之一左右而效果几乎无损。5. 一套可复用的 Agent 工程骨架把上面的内容串起来我给出一套我常用的工程骨架你可以直接照着搭入口层接收输入做意图判定和路由。规划层判断是否需要规划需要则生成步骤列表。执行层循环执行“模型思考-工具调用-结果观察”。记忆层负责短期上下文管理和长期记忆读写。校验层格式、一致性、相关性三道校验。降级层重试、换策略、如实告知三级降级。每一层都可以独立替换和优化层与层之间通过明确的数据结构通信。这样设计的好处是当某个环节出问题时你能快速定位是哪一层的责任而不是在一坨耦合代码里大海捞针。我在实际项目里用这套骨架改造过好几个系统从知识库问答到自动化流程处理适配性都还不错。核心不在于骨架本身多精妙而在于它强迫你把每个决策点都想清楚——Agent 工程的本质就是把一堆模糊的“让模型自己搞定”翻译成一个个明确的、可测试的决策逻辑。这件事没有捷径但一旦想通了后面就是体力活了。