从七要素到七个决策点:AI Agent 工程化落地的完整思考链路
AI Agent 这个词在过去一年里被反复提起但真正动手搭过一套能跑起来的系统之后你会发现大部分公开资料都停留在概念层面。七要素、决策点这些说法听起来很完整可一旦落到代码里问题就变成了循环到底怎么写才不会失控工具调用失败了谁来兜底上下文塞满了怎么办我前后搭过几套不同规模的 Agent从最简单的单工具问答到带记忆、带多轮编排的复杂流程踩过的坑基本都集中在这些工程细节上而不是模型本身。这篇就把我从七要素到七个决策点的完整思考链路摊开讲重点放在为什么这么设计和实际写的时候会撞到什么适合已经了解 LLM 基础、准备动手做 Agent 的开发者也适合已经在做但总觉得系统不稳的人对照排查。1. 先把七要素拆开看它们不是清单是依赖关系很多人第一次接触 Agent 的七要素会把它当成一个 checklist——模型、工具、记忆、规划、执行、反馈、循环挨个实现一遍就以为完事了。我一开始也是这么想的结果搭出来的东西能跑 demo一上真实任务就崩。后来才明白这七个要素之间存在强依赖顺序错了或者某一环偷懒整个系统就会在某个意想不到的地方断掉。1.1 模型是地基但它决定的不只是聪不聪明选模型这件事新手最容易只看 benchmark 分数。我早期也这样挑了个榜单上很强的模型结果发现它在工具调用格式上极其不稳定同样的 prompt 有时候输出标准 JSON有时候夹带一段解释文字解析器直接报错。后来换成工具调用能力专门优化过的模型虽然通用问答分数低一点但整个系统的稳定性上了一个台阶。这里的关键认知是Agent 场景下模型的指令遵循能力和结构化输出稳定性比纯推理能力更重要。因为 Agent 的每一步输出都要被程序解析、被下游消费格式一乱后面全乱。你可以做个简单测试给候选模型同一个工具调用 prompt 跑 50 次统计格式合规率低于 95% 的基本可以直接排除。另一个容易被忽略的点是上下文窗口和成本的关系。窗口大不代表要全用上我见过有人把整个对话历史无脑塞进去token 消耗飞快而且模型在超长上下文里的注意力会稀释反而容易漏掉关键指令。合理的做法是分层管理系统提示词固定近期对话保留原文早期对话做摘要压缩。1.2 工具是手脚但能调用和调得好是两回事工具这一环最朴素的实现就是给模型一个函数列表让它自己选。但实际跑起来你会发现几个问题工具描述写得含糊模型就选错工具太多模型就挑花眼工具返回结果太长直接把上下文撑爆。我现在的做法是给每个工具写三件套一句话功能说明、明确的入参 schema、以及一个典型调用示例。别小看这个示例它对模型选择正确率的提升非常明显。另外工具数量控制在 10 个以内比较稳妥超过之后要么分组要么做一层路由先筛选候选工具。工具返回值的处理也有讲究。比如一个查询数据库的工具返回了 200 行数据你不能原样丢回给模型。我的处理是结构化数据先在代码层做聚合或截断只把模型决策真正需要的字段传回去。这一步做得好能省下大量 token也能避免模型被无关信息干扰。1.3 记忆不是存聊天记录那么简单很多人把记忆理解成把历史对话存下来下次拼回去。这只对了一半。真正的记忆要分三层工作记忆当前任务的临时状态、短期记忆本次会话的上下文、长期记忆跨会话的知识沉淀。工作记忆最容易被忽略但它恰恰是 Agent 稳定性的关键。比如一个多步任务Agent 执行到第三步时需要知道第一步产出的中间结果。这个结果如果只存在于对话历史里很容易被后续内容挤掉。我的做法是显式维护一个状态对象把关键中间结果结构化存起来每一步都从状态对象里读而不是从对话历史里回忆。长期记忆则要考虑检索问题。全量塞进去不现实得做向量化检索。但检索的召回质量直接决定 Agent 会不会记错事所以嵌入模型的选择和分块策略要花心思不能随便切。1.4 规划、执行、反馈三个容易被合并却必须分开的环节规划是想清楚要做几步执行是真的去做反馈是判断做得对不对。新手常把这三个揉在一起让模型一步到位输出最终答案。这在简单任务上没问题但复杂任务必然翻车。分开之后的好处是每一环都可以独立优化和调试。规划错了你能定位到是拆解逻辑的问题执行错了是工具或参数的问题反馈错了是判断标准的问题。混在一起你只能看到结果不对根本无从下手。1.5 循环是骨架但它的终止条件才是灵魂七要素里循环排在最后但它是把所有东西串起来的那根线。循环本身不难写难的是什么时候停。终止条件设计不好要么死循环烧钱要么提前退出任务没做完。我一般会设三重保险最大步数限制、连续无进展检测、以及显式的完成信号。三者任一触发就停。最大步数防死循环无进展检测防原地打转完成信号让正常任务能及时收尾。这三重里无进展检测最容易被漏掉但它在实际运行中救场的次数最多。2. 七个决策点Agent 真正做选择的地方七要素讲的是系统由什么组成七个决策点讲的是系统在运行时要在哪些地方做判断。这两者不是一回事前者是静态结构后者是动态行为。我把这七个决策点按执行顺序梳理一遍每个都说说实际实现时的取舍。2.1 决策点一这一轮要不要调用工具这是每一轮循环的第一个判断。模型需要决定是直接回答还是调用工具获取更多信息。听起来简单但这里有个经典陷阱——模型倾向于过度调用。明明自己知道答案也要调个工具确认一下白白增加延迟和成本。我的应对是在系统提示词里明确写清楚调用工具的边界比如仅当需要实时数据或外部信息时才调用工具。同时可以在反馈环节加一个判断如果工具返回的信息和模型已知的重合就在下一轮提示它直接回答。实测下来这个调整能把无效工具调用降低三成左右。2.2 决策点二调用哪个工具工具选择错误是 Agent 最常见的失败模式之一。原因通常有三个工具描述重叠、任务表述模糊、候选工具太多。解决思路是描述差异化 路由前置。描述差异化是指确保每个工具的功能说明互不重叠边界清晰。路由前置是指当工具数量多时先用一个轻量模型或规则做初筛把候选缩小到 3-5 个再让主模型选。这样既降低了选择难度也省了 token。2.3 决策点三参数怎么填工具选对了参数填错一样白搭。参数填充的难点在于模型需要从上下文里抽取正确的值还要符合 schema 的类型要求。我的经验是给每个参数都写清楚从哪来和什么格式。比如日期参数明确写格式为 YYYY-MM-DD从用户消息中提取。另外在代码层做一层校验类型不对或必填缺失时不要直接报错终止而是把错误信息回传给模型让它重填。这个重试而非终止的策略能显著提升任务完成率。2.4 决策点四结果怎么解读工具返回结果后模型要判断这个结果意味着什么。这里最容易出问题的是异常结果的处理。比如查询返回空、接口报错、数据格式和预期不符。很多实现直接把这些异常结果原样丢给模型模型可能理解不了就瞎编。正确做法是在代码层先做一轮归一化把异常转成模型能理解的描述比如查询返回空结果可能原因是没有匹配数据。同时明确告诉模型遇到这种情况该怎么办是重试、换工具、还是告知用户。2.5 决策点五任务是否完成这是循环终止的核心判断。模型需要根据当前状态判断任务是否已经达成目标。难点在于部分完成和完全完成的区分。我的做法是让规划环节就定义好完成标准每一步执行后对照标准检查。标准要具体可验证比如已获取用户指定的三个字段而不是任务基本完成。模糊的标准会让模型过早收尾。2.6 决策点六出错后怎么恢复Agent 运行中出错是常态关键是恢复策略。我把错误分成三类可重试的如网络抖动、可替代的如换个工具、不可恢复的如参数根本性错误。对应三种处理可重试的自动重试有限次可替代的让模型重新规划不可恢复的明确告知用户并给出建议。这个分类逻辑要写进系统提示词让模型知道遇到不同错误该怎么反应而不是一律卡死。2.7 决策点七上下文怎么管理这是贯穿全程的决策点。每一轮循环都会往上下文里加内容加着加着就满了。什么时候压缩、压缩什么、保留什么都需要策略。我的策略是近期保原文、中期做摘要、远期做检索。具体阈值根据模型窗口定一般用到 70% 就开始触发压缩。压缩时优先保留系统提示词、当前任务状态、最近几轮对话早期的工具调用结果可以摘要成一句话。3. 循环机制写一个不会失控的 Agent 主循环循环是 Agent 的心脏但公开资料里很少讲清楚怎么写才稳。我把自己的主循环结构拆开讲重点说几个关键控制点。3.1 主循环的基本骨架一个稳健的主循环大致是这样的结构初始化状态对象进入循环每轮先检查终止条件然后让模型决策执行决策更新状态再回到循环开头。这个骨架看起来简单但每一环都有细节。初始化阶段要把系统提示词、工具定义、任务目标、初始状态都准备好。这里有个容易漏的点任务目标要写得足够具体最好包含明确的完成标准。我见过太多因为目标模糊导致 Agent 跑偏的案例。循环开头的终止检查要放在模型调用之前这样能避免不必要的模型调用。检查项包括步数上限、时间上限、无进展计数、以及显式的完成标志。3.2 无进展检测怎么做才准无进展检测是防死循环的关键但做得太敏感会误杀正常任务太迟钝又起不到作用。我的做法是维护一个状态指纹每轮结束后计算当前状态的哈希如果连续 N 轮指纹相同就判定为无进展。指纹要包含哪些内容很关键。我一般包含当前任务进度、最近一次工具调用及结果摘要、模型输出的关键决策。这样能捕捉到看起来在动但实际原地打转的情况。N 的取值我一般设 3实测比较平衡。3.3 状态对象的维护状态对象是整个循环的记忆中枢它要记录任务目标、已完成步骤、当前进度、关键中间结果、错误历史。每一轮循环都要读写这个对象。维护状态对象的原则是显式优于隐式。不要依赖对话历史来隐式传递状态而是每一步都显式更新状态对象。这样即使对话历史被压缩了状态也不会丢。我踩过的坑就是早期依赖对话历史结果一压缩就丢关键信息任务直接跑偏。3.4 异常中断与恢复循环运行中可能遇到各种异常模型调用超时、工具执行报错、解析失败等。这些异常不能直接让整个循环崩掉要有捕获和恢复机制。我的做法是在循环内做 try-catch捕获后把异常转成结构化信息写入状态对象然后让模型在下一轮基于这个信息决定怎么处理。同时设一个异常计数器连续异常超过阈值就终止并上报。这样既给了恢复机会又防止无限重试。4. 工具调用从定义到执行的完整链路工具调用是 Agent 和外部世界交互的唯一通道这条链路的每个环节都可能出问题。我把它拆成定义、选择、填充、执行、解读五段来讲。4.1 工具定义的规范一个好的工具定义应该包含名称简洁明确、功能描述一句话说清做什么、参数 schema类型、必填、说明、返回值说明、以及调用示例。名称要避免歧义比如search和query这种就很容易混。功能描述要写做什么而不是怎么做比如查询指定城市的当前天气比调用天气 API更好。参数说明要具体到格式和来源。调用示例这一项很多人省掉但它对模型理解工具用途帮助极大。我一般给每个工具配一个真实的调用例子包括输入和预期输出。4.2 工具选择的降错策略前面提过路由前置这里展开说。当工具数量超过 10 个我会加一层轻量路由先用关键词匹配或小模型做初筛把候选缩到 3-5 个再让主模型在候选里选。路由的实现可以很简单给每个工具打几个标签根据任务描述匹配标签。也可以用嵌入模型算相似度。关键是这一层要快、要便宜不能成为瓶颈。4.3 参数填充的校验与重试参数填充后必须校验校验不通过不要直接失败而是把错误信息回传模型重填。重试次数设 2-3 次超过就放弃这个工具让模型换方案。校验内容包括必填项是否齐全、类型是否正确、格式是否符合、值是否在合理范围。这些校验在代码层做比让模型自己检查可靠得多。4.4 执行层的超时与隔离工具执行要有超时控制不能让它无限等待。超时时间根据工具性质定查询类可以短一点计算类可以长一点。超时后要返回明确的超时信息而不是空结果。隔离是指工具执行失败不能影响主循环。每个工具调用都包在独立的错误处理里失败就返回错误信息主循环继续。4.5 结果解读的归一化工具返回结果后先做归一化再给模型。归一化包括截断过长内容、提取关键字段、把异常转成描述性文本。比如一个返回 JSON 的工具如果返回了错误码归一化时就转成调用失败原因xxx。如果返回正常但数据量大就只保留模型决策需要的字段。这一步做得好能大幅提升模型解读的准确率。5. 记忆与上下文让 Agent 记得住又不撑爆记忆和上下文管理是 Agent 工程里最考验设计功力的部分。做得好Agent 表现得像个有经验的助手做得差它就像个失忆症患者每轮都在重新开始。5.1 三层记忆的分工工作记忆存当前任务的临时状态生命周期就是一次任务。短期记忆存本次会话的对话历史生命周期是一次会话。长期记忆存跨会话的知识生命周期是永久。三层的存储介质和检索方式都不同。工作记忆直接放内存对象读写最快。短期记忆放会话存储按时间顺序组织。长期记忆放向量库按语义检索。5.2 上下文压缩的触发与策略压缩触发阈值一般设在窗口的 70% 左右。压缩时优先保留系统提示词、当前任务状态、最近 3-5 轮对话。早期的工具调用结果可以摘要成一句话比如已查询天气结果为晴。压缩本身也可以让模型来做但要给明确的指令比如把以下对话压缩成不超过 200 字的摘要保留关键决策和结果。压缩后的内容要标注清楚这是摘要避免模型误以为是原文。5.3 长期记忆的写入与检索长期记忆不是什么都存要有选择。我一般只存用户偏好、重要事实、成功的问题解决模式。写入前做一轮判断值得存才存。检索时用向量相似度召回 top-k再让模型判断哪些相关。k 一般设 3-5太多会引入噪声。检索结果要标注来源和时间方便模型判断时效性。5.4 记忆冲突的处理当新信息和旧记忆冲突时怎么办我的做法是让新信息优先但保留旧记忆并标注冲突。比如用户之前说喜欢 A现在说喜欢 B就记录用户偏好从 A 变为 B。这样模型能理解变化而不是困惑。6. 容错与安全Agent 跑得稳的底层保障Agent 一旦接入真实系统容错和安全就不是可选项而是必选项。这部分我踩过的坑最多也最想提醒后来者。6.1 错误分类与分级处理错误要分类不同类不同处理。我分四级提示级不影响继续、警告级需要调整但可继续、错误级当前步骤失败需重试或换方案、致命级必须终止。分级的标准是是否影响任务目标达成。提示级和警告级记录即可错误级触发恢复逻辑致命级终止并上报。6.2 重试策略的设计重试不是无脑重试要有策略。我一般用指数退避第一次等 1 秒第二次 2 秒第三次 4 秒。重试次数上限 3 次。超过就放弃当前方案让模型重新规划。重试时要区分可重试错误和不可重试错误。网络超时可重试参数错误重试也没用直接换方案。6.3 权限与边界控制Agent 能调用的工具要有权限控制。危险操作如删除、支付要么禁止要么加二次确认。工具的参数也要做范围校验防止模型填出离谱的值。我一般会给工具打权限标签高危工具在系统提示词里明确标注需谨慎使用并在执行前加一道确认逻辑。6.4 输出内容的过滤Agent 的输出要过滤防止泄露敏感信息或产生不当内容。过滤在代码层做不依赖模型自觉。过滤规则包括敏感词、格式校验、长度限制。6.5 可观测性建设Agent 运行过程要可观测否则出问题无从排查。我一般记录每轮的输入输出、工具调用详情、状态变化、错误信息。这些日志按任务 ID 组织方便回溯。可观测性还包括指标监控任务成功率、平均步数、工具调用分布、错误率。这些指标能帮你发现系统性问题。7. 从零搭一个最小可用 Agent 的实操路径讲了这么多原理最后落到实操。我给一条从零到最小可用的路径按这个顺序走能少踩很多坑。7.1 第一步定义任务和完成标准先别写代码先把任务想清楚。任务是什么、输入是什么、输出是什么、怎么算完成。完成标准要具体可验证。7.2 第二步选模型和工具模型选工具调用稳定的工具先选 2-3 个最核心的。别一上来就堆工具先把主流程跑通。7.3 第三步写主循环骨架按前面讲的骨架写初始化、循环、终止检查、模型决策、执行、状态更新。先跑通单轮再跑多轮。7.4 第四步加状态管理和终止条件状态对象和终止条件是稳定性的关键这一步不能省。三重终止保险都要加上。7.5 第五步加错误处理和日志错误处理和日志是排查问题的基础越早加越好。别等到出问题才补。7.6 第六步压测和调优用真实任务压测看成功率、步数、成本。根据数据调优提示词、工具定义、终止阈值。7.7 第七步加记忆和上下文管理最后再加记忆和上下文压缩因为这部分复杂度高前面跑稳了再加不容易乱。8. 几个我踩过的坑和对应的解法最后分享几个具体的坑都是实际跑出来的不是理论推演。8.1 坑一模型过度调用工具表现是明明能直接回答也要调工具。解法是在提示词里明确边界并在反馈环节加判断。8.2 坑二上下文压缩丢关键信息表现是压缩后任务跑偏。解法是压缩时显式保留任务状态和完成标准不依赖对话历史。8.3 坑三工具返回异常导致模型瞎编表现是工具报错后模型编造结果。解法是归一化异常结果明确告知模型这是错误。8.4 坑四死循环烧钱表现是任务卡住反复调用。解法是三重终止保险尤其是无进展检测。8.5 坑五状态丢失导致重复劳动表现是 Agent 重复做已完成的步骤。解法是显式状态对象每步读写。这些坑的共同点是都不是模型能力问题而是工程设计问题。把工程做扎实Agent 的稳定性会有质的提升。我现在的习惯是每上一个新 Agent先把这五个坑的防护都加上再考虑功能扩展。