ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

AI Agent 工程实践:七要素拆解与七个关键决策点

AI Agent 工程实践:七要素拆解与七个关键决策点

AI Agent 这个词这两年几乎被说烂了,但真正动手搭过一套能跑起来的系统的人都知道,从"能对话"到"能干活"之间隔着一道很深的沟。我前后做过几个 Agent 项目,有帮团队做内部自动化的,也有给客户做垂直场景落地的,踩过的坑从工具调用参数对不上、循环停不下来,到记忆污染导致整个会话跑偏,几乎每一类都遇到过。这篇就把我理解的 Agent 工程实现拆开讲——不是讲概念,而是讲一个 Agent 到底由哪几个零件组成、每个零件在工程上意味着什么、以及开发过程中真正需要做决策的地方在哪里。如果你正在准备搭自己的第一个 Agent,或者已经搭了一个但总觉得哪里不对劲,这篇应该能帮你把脑子里那团乱麻理清楚。

1. 先把"七要素"这件事说透

很多人一上来就问"用哪个框架好",这其实是个伪问题。框架只是壳,真正决定一个 Agent 能不能干活的是它内部的七个组成部分。我习惯把这七要素分成两组:一组是"静态的",也就是你在写代码时就要定下来的东西;另一组是"动态的",也就是运行时才产生和变化的东西。分清楚这两组,后面做架构决策会轻松很多。

1.1 模型:不只是选个 LLM 那么简单

模型是整个 Agent 的大脑,但选模型这件事远不止"哪个强用哪个"。我在实际项目里会从三个维度去权衡:推理能力、指令遵循度、以及成本结构。

推理能力决定了 Agent 能不能处理多步任务。比如一个"帮我查一下上周的销售数据并生成图表"的任务,模型需要先理解意图、再规划步骤(查数据→处理数据→画图)、再逐步执行。推理弱的模型会在第二步就开始胡编。指令遵循度则决定了它能不能老老实实按你给的格式输出——这点在做工具调用时特别关键,因为你的解析代码是死的,模型输出格式一乱,整个链路就断了。

成本结构是最容易被忽略的。有些模型单次调用便宜,但因为它推理差,你需要多轮重试,实际总成本反而更高。我一般会做一个简单的测算:假设一个任务平均需要 N 轮交互,每轮平均消耗 T 个 token,那么单任务成本 ≈ N × T × 单价。把重试率算进去,往往能看出哪个模型真正划算。

提示:不要迷信"最强模型"。很多生产环境里的 Agent 用的是中等模型 + 好的提示词工程 + 严格的输出校验,效果比直接用最强模型裸跑还稳。

1.2 工具:Agent 的手和脚

工具就是 Agent 能调用的外部能力,可以是查数据库、调 API、读文件、发消息等等。工程上最关键的一点是:工具的接口设计比工具本身的数量重要得多。

我见过太多人一上来就给 Agent 塞二三十个工具,结果模型在选择时频繁选错。正确的做法是先把工具按场景分组,每组控制在 5 到 8 个以内,并且每个工具的描述要写得像给新人看的说明书——说清楚它做什么、需要什么参数、返回什么、什么情况下不该用它。

工具的参数定义也有讲究。能用枚举就别用自由文本,能加约束就别放任。比如一个"查询订单"的工具,状态参数如果定义成字符串,模型可能传"已完成""已发货""done"各种写法;如果定义成枚举["pending", "shipped", "completed"],解析就稳了。

1.3 记忆:短期、长期、以及那个容易被忽略的"工作记忆"

记忆这块是 Agent 工程里最容易做砸的部分。我把它分成三层来看:

  • 短期记忆:就是当前对话的上下文,通常直接放在 prompt 里。问题是它会随着轮次增长而膨胀,最后撑爆上下文窗口。
  • 长期记忆:跨会话保留的信息,一般存在向量数据库或结构化存储里,需要时检索出来。
  • 工作记忆:这是我自己起的名字,指的是 Agent 在执行一个多步任务时,中间产生的临时状态——比如"已经查到了数据""下一步要画图"。这部分如果不显式管理,模型很容易在长任务里"忘记"自己做到哪了。

我的经验是,工作记忆最好用结构化的方式存(比如一个 JSON 状态对象),每一步执行完就更新它,并在下一轮 prompt 里带上。这样即使上下文被截断,Agent 也能从状态里恢复。

1.4 规划:从"想到哪做到哪"到"先想后做"

规划能力决定了 Agent 是"走一步看一步"还是"先出方案再执行"。简单任务其实不需要显式规划,但复杂任务如果没有规划,模型很容易在中间迷失。

工程上常见的做法有两种:一种是让模型先输出一个步骤列表(plan),然后逐步执行;另一种是边执行边规划(replan),每完成一步就重新评估下一步。前者适合流程固定的场景,后者适合探索性任务。

我个人的偏好是混合:先让模型出一个粗粒度的 plan,执行过程中如果遇到意外(比如工具报错、结果不符合预期),再触发一次 replan。这样既有全局视角,又保留了灵活性。

1.5 执行:循环机制的核心

执行就是那个"循环"——模型思考→调用工具→拿到结果→再思考→再调用,直到任务完成或触发终止条件。这个循环看起来简单,但工程上有三个必须处理的问题:

第一是终止条件。必须有明确的判断:任务完成了、达到最大轮次了、还是出错了。我一般会设一个硬性的最大轮次(比如 15 轮),超过就强制停止并返回当前状态,避免无限循环烧钱。

第二是错误处理。工具调用失败是常态,模型需要知道失败了、失败原因是什么,然后决定重试还是换方案。这里的关键是把错误信息结构化地传回给模型,而不是丢一个异常堆栈。

第三是状态传递。每一轮的结果要正确地传给下一轮,包括工具返回的数据、中间产生的变量等等。这块如果设计得乱,后面调试会非常痛苦。

1.6 输出解析:模型说的话,代码得听得懂

模型输出的是自然语言,但你的代码需要的是结构化数据。这中间的桥梁就是输出解析。常见做法是要求模型输出 JSON,然后用解析器提取。但现实是模型经常会在 JSON 外面包一层解释文字,或者漏个引号。

我的做法是双保险:一是在 prompt 里明确要求"只输出 JSON,不要任何其他文字";二是在解析失败时做一次修复尝试(比如用正则提取 JSON 片段,或者让模型重新格式化)。如果两次都失败,就走降级逻辑。

1.7 安全与边界:别让 Agent 变成脱缰的野马

最后这个要素经常被放到最后考虑,但它其实应该在最前面就想清楚。Agent 能调用工具、能读写数据,这意味着它一旦跑偏,后果可能很严重。

工程上的基本措施包括:工具权限最小化(只给它完成任务必需的权限)、敏感操作加确认(比如删除数据前要求二次确认)、输出内容做过滤(防止泄露敏感信息)。这些不是可选项,是必选项。

2. 七个决策点:开发时真正要拍板的地方

理解了七要素,接下来就是实际开发中会遇到的七个关键决策。这些决策没有标准答案,但每个都有明确的权衡逻辑。

2.1 决策一:单 Agent 还是多 Agent

这是最先要回答的问题。单 Agent 就是一套模型 + 一套工具 + 一个循环;多 Agent 则是把任务拆给多个专职 Agent,各自负责一块,最后汇总。

我的判断标准很简单:如果任务能被清晰地拆成几个相对独立的子任务,且子任务之间交互不多,就用多 Agent;否则用单 Agent。多 Agent 的代价是通信开销和协调复杂度,如果拆得不好,反而比单 Agent 更乱。

举个例子,"写一份行业分析报告"可以拆成"搜集资料 Agent""分析数据 Agent""撰写 Agent",这三个职责清晰、交互有限,适合多 Agent。但"帮我订一张明天去上海的机票"这种任务,拆开反而累赘,单 Agent 足够。

2.2 决策二:工具怎么组织和暴露

前面说了工具数量要控制,但具体怎么组织?我一般按"领域"分组。比如一个电商 Agent,工具可以分成"商品域""订单域""用户域"三组,每组内部工具数量控制在 5 到 8 个。

暴露方式上,有两种选择:一次性全部暴露给模型,或者按当前上下文动态选择。前者简单但容易让模型选错,后者需要额外的路由逻辑但更精准。我的经验是,工具总数在 10 个以内就全暴露,超过 10 个就做动态路由。

2.3 决策三:记忆存哪里、存多久

记忆的存储方案取决于你的场景。如果是单次会话内的任务,短期记忆放内存就够了;如果需要跨会话,就得上持久化存储。

长期记忆的检索策略也很关键。常见的是向量检索,但纯向量检索有时候会召回不相关的内容。我一般会做混合检索:向量相似度 + 关键词匹配 + 时间衰减,三者加权。这样既能召回语义相关的,又能保证时效性。

2.4 决策四:循环的终止条件怎么定

这个前面提过,但值得单独说。终止条件至少要包含三类:任务完成信号、最大轮次限制、错误熔断。

任务完成信号通常由模型自己判断(比如它输出一个特定的结束标记),但不能完全信任模型,所以要有最大轮次兜底。错误熔断则是连续 N 次工具调用失败就停止,避免在明显跑不通的路上一直撞。

2.5 决策五:输出格式怎么约束

输出格式的约束强度,取决于你的下游代码有多"脆"。如果下游是严格的解析器,那就要用强约束(比如 JSON Schema、函数调用格式);如果下游能容忍一定灵活性,可以放宽。

我一般优先用模型厂商提供的结构化输出能力(比如 function calling 或 JSON mode),因为这比纯 prompt 约束可靠得多。如果厂商不支持,再退回到 prompt + 解析修复的方案。

2.6 决策六:错误怎么处理和恢复

错误处理的核心是"让模型知道发生了什么,并给它恢复的机会"。具体做法是:工具调用失败时,把错误信息(简化后的)作为工具返回结果传回去,让模型决定下一步。

但要注意,不能让模型无限重试同一个失败的操作。我一般会记录每个工具连续失败的次数,超过阈值就强制切换策略或终止。

2.7 决策七:怎么评估和迭代

Agent 不像传统软件,它的行为有随机性,所以评估不能只看"跑通没跑通"。我一般会建一个小型的测试集,包含典型任务和边界任务,每次改动后跑一遍,看成功率、平均轮次、平均成本这几个指标。

迭代时优先改提示词和工具描述,这两块改动成本最低、收益往往最大。模型和架构的调整放到后面。

3. 循环机制:Agent 的心跳是怎么跳的

循环机制是 Agent 最核心的运行时逻辑,也是最多人写不明白的地方。我把它拆成四个阶段来看。

3.1 感知阶段:把当前状态喂给模型

每一轮循环开始时,你需要把当前的所有相关信息组装成 prompt 喂给模型。这些信息包括:系统提示词、对话历史、当前任务状态、可用工具列表、以及上一轮的结果。

组装 prompt 时最容易犯的错是"什么都往里塞"。上下文窗口是有限的,塞太多无关信息反而会稀释关键信息。我的做法是分层:系统提示词和工具定义永远在最前面,任务状态紧随其后,对话历史按相关性截断,最近的几轮优先保留。

3.2 决策阶段:模型输出下一步动作

模型拿到 prompt 后,会输出它的决策。这个决策可能是"调用某个工具",也可能是"给出最终答案",还可能是"我需要更多信息"。

工程上,这个阶段的输出必须是可解析的。我一般要求模型输出一个结构化的动作对象,包含动作类型和参数。比如:

{ "action": "call_tool", "tool": "query_orders", "params": {"status": "shipped", "limit": 10} }

这样解析起来就非常直接。

3.3 执行阶段:真正去调用工具

拿到动作后,代码去执行对应的工具调用。这一步是纯工程逻辑,和模型无关。执行结果(成功的数据或失败的错误)会被记录下来,作为下一轮的输入。

这里有个细节:工具返回的数据往往很大,直接塞回 prompt 会撑爆上下文。我一般会做一层摘要或截断,只把关键信息传回去。比如查询返回 100 条记录,可能只传前 5 条 + 总数。

3.4 更新阶段:把结果写回状态

执行完一轮后,更新任务状态,然后回到感知阶段,开始下一轮。这个循环一直持续到触发终止条件。

状态更新这块,我强烈建议用显式的状态对象,而不是依赖对话历史。因为对话历史会越来越长,而状态对象是精简的、结构化的,模型更容易从中提取关键信息。

4. 工具调用:那些文档里不会写的细节

工具调用看起来就是"模型说要调什么,代码就去调",但实际做起来细节非常多。

4.1 工具描述怎么写才不容易被误用

工具描述是模型选择工具的唯一依据,所以它必须写得极其清楚。我的模板是:一句话说明用途 + 参数说明 + 返回值说明 + 使用场景 + 不适用场景。

比如一个查询天气的工具,描述不能只写"查询天气",而要写"根据城市名查询当前天气,返回温度和天气状况。适用于用户询问实时天气的场景。不适用于查询历史天气或未来预报。"

4.2 参数校验和默认值

模型传的参数不一定合法,所以代码层必须做校验。类型不对就报错,必填项缺失就报错,枚举值不在范围内就报错。这些错误信息要清晰地传回给模型,让它知道怎么改。

默认值也很重要。有些参数模型可能不传,这时候给一个合理的默认值能减少一轮交互。

4.3 工具返回结果的处理

工具返回的结果格式要统一,最好是结构化的。如果工具本身返回的是自然语言,也要在包装层转成结构化数据再传给模型。

另外,返回结果要控制大小。我一般会设一个上限,超过就截断或摘要,避免撑爆上下文。

5. 记忆管理:让 Agent 记住该记的,忘掉该忘的

记忆管理是 Agent 从"玩具"变成"工具"的关键。一个记不住上下文的 Agent,每次都要用户重复信息,体验极差。

5.1 短期记忆的压缩策略

短期记忆就是对话历史,它会随着轮次增长。压缩策略有几种:滑动窗口(只保留最近 N 轮)、摘要压缩(把早期对话总结成一段话)、以及关键信息提取(只保留实体和事实)。

我一般用组合策略:最近 5 轮保留原文,更早的做摘要,实体信息单独提取存起来。

5.2 长期记忆的写入和检索

长期记忆不是什么都存,而是存"值得跨会话记住的"。比如用户的偏好、历史任务的结果、重要的实体信息。

写入时机一般是任务完成后,或者用户明确说"记住这个"。检索时机是新一轮对话开始时,根据当前输入去检索相关记忆。

5.3 记忆污染的防范

记忆污染是个隐蔽但严重的问题。如果检索到的记忆不相关或错误,会直接把 Agent 带偏。防范措施包括:检索时做相关性阈值过滤、定期清理过期记忆、以及让模型对检索结果做一次确认。

6. 从 Demo 到生产:我踩过的那些坑

Demo 跑通和生产可用之间,差距比想象中大得多。分享几个我实际踩过的坑。

6.1 无限循环:那个烧了我一晚上额度的 bug

早期做的一个 Agent,因为终止条件写得不严谨,模型在某个任务上陷入了"调用工具→结果不符合预期→再调用→还是不符合"的死循环。一晚上跑掉了我不少额度。

修复方案是加了三重保险:最大轮次硬限制、连续相同工具调用次数限制、以及总 token 消耗上限。这三个任何一个触发都强制停止。

6.2 工具选择错误:模型总是选那个"看起来像"的工具

有段时间我的 Agent 总是选错工具,明明该用 A 却用了 B。排查后发现是两个工具的描述太相似了。解决办法是把描述改得更具体,明确写出各自的适用边界,并且在系统提示词里加一句"如果不确定用哪个,先询问用户"。

6.3 上下文爆炸:长任务跑到一半就崩了

长任务跑到十几轮后,上下文就撑满了,模型开始胡言乱语。解决办法是引入工作记忆对象,把关键状态结构化存起来,对话历史做压缩,这样即使历史被截断,模型也能从状态里恢复。

6.4 输出格式漂移:模型偶尔不按格式来

即使 prompt 里明确要求了 JSON 格式,模型偶尔还是会加一些解释文字。解决办法是解析层做容错:先用严格解析,失败就用正则提取,再失败就让模型重新格式化一次。

7. 评估与迭代:怎么知道你的 Agent 变好了

Agent 的评估不能靠"感觉",得有指标。我一般关注四个:任务成功率、平均交互轮次、平均 token 消耗、以及错误率。

建一个包含 20 到 50 个典型任务的测试集,每次改动后跑一遍,对比指标变化。改动优先级是:提示词 > 工具描述 > 工具实现 > 模型 > 架构。因为前面的改动成本低、见效快。

迭代过程中,我会把失败的 case 单独拎出来分析,看是模型理解错了、工具设计有问题、还是流程本身有缺陷。大部分问题其实出在提示词和工具描述上,真正需要改架构的情况很少。

这套东西我用了几个项目下来,最大的体会是:Agent 工程的核心不是"用多先进的模型",而是"把每个环节的边界和状态管理清楚"。模型再强,如果循环停不下来、工具选不对、记忆一团乱,照样跑不起来。反过来,一个中等模型配上严谨的工程实现,往往能稳定完成大部分任务。

返回列表