☰
从生成文本到执行任务:手写一个最小Agent的完整指南
2026/9/29 18:52:43 网站建设 项目流程

这篇是Agent开发学习笔记的第八篇。前六篇我们把上下文工程、Few-shot设计、Function Calling这些地基打完了,第七篇又补了结构化输出和提示词调优的细节,到今天终于可以聊那个真正把Agent从“玩具”变成“工具”的分水岭:从生成文本到执行任务。标题里这个“跨越”看起来轻飘飘,实际落地的时候牵扯到模型选型、工具注册、状态管理、循环控制、权限边界一大堆事。你如果现在已经能熟练地用API调大模型聊天,也尝试过让模型输出JSON,那这篇笔记正好适合你——它会告诉你如何让模型不再只是“说出答案”,而是亲手把结果做出来。

1. 从生成文本到执行任务,这个跨越到底跨了什么

1.1 文本生成与任务执行的本质差异

先说清楚一个很多人忽略掉的事实:大语言模型的原始能力是“预测下一个token”,也就是生成文本。你让它写一封邮件,它能写;你让它分析一段日志,它也能给你条理清晰的分析结论。但这些都停留在“表达”层面——邮件写出来了不会自己发出去,日志分析完了不会自己触发报警,计划制定好了不会自己执行第一步。

任务执行意味着模型产出的结果必须能落到真实世界里:调用一个接口、改写一条数据库记录、把文件移动到指定目录、在一个网页上完成表单填写。这件事比看起来难得多,因为真实世界是有状态、有副作用的。模型输出错一个token,聊天里只是句子不通顺,顶多被人笑两句;在任务执行里,可能就造成一笔重复支付、一条错误的生产配置,或者一个删错的文件。

这个差异引出了Agent设计的核心命题:模型负责“决策和表达”,而外围系统负责“约束和兜底”。你不可能指望模型永远不犯错,但你可以设计一套流程,让它在犯错的时候能发现、能纠正、不至于造成不可逆影响。

1.2 为什么“会说话”的模型需要“手脚”和“大脑”

我们常听到一个说法:Agent = 大模型 + 记忆 + 工具 + 规划。这个公式看似简单,但每一项展开都有讲究。

模型负责推理判断,这是“大脑”;工具是模型伸向外部世界的“手脚”;记忆让模型能跨对话跨步骤地保留信息;规划让模型面对复杂任务时懂得拆分目标、排定顺序。没有工具,模型就是个纸上谈兵的参谋;没有记忆,模型每次对话都像失忆患者,没法完成多步操作;没有规划,模型在面对“帮我把这周所有订单按金额排序并生成报表”这种任务时只会一股脑往前冲,干到一半发现漏了东西。

我在实际项目里的体会是:当模型从“生成文本”变成“执行任务”之后,写提示词的重心也变了。以前你关注的是“怎么让输出符合要求”,现在你更关注“怎么让每一步决策都留有可观测、可回退的空间”。模型在每一轮循环里不仅要输出“想做什么”,还要输出“为什么这么做”,再由框架判断能不能做、做了之后结果如何。

1.3 Agent开发学习路线:四个台阶

结合我自己的学习过程,我把Agent开发分成四个台阶,你照着这个顺序踩,不容易迷茫。

第一台阶是熟练使用Function Calling,让模型学会“请求调用工具”。这个阶段你不需要写复杂的循环,只需要给模型注入工具描述,让它输出结构化调用请求。

第二台阶是构建单Agent执行循环,也就是自己实现“模型思考、模型调用、拿到结果再喂回给模型”这个闭环,同时处理好终止条件和错误重试。

第三台阶是给Agent加上记忆和规划能力,让它能处理跨时段的长期任务,能自己拆解子目标,而不是每次任务都从头想。

第四台阶才是多Agent协作、复杂工作流编排、以及上线后的评估和安全加固。

很多同学一上来就扎进AutoGPT、LangGraph的花式框架里,结果连最基本的“工具调用失败后怎么重试”都没处理好。我的建议是:前两个台阶一定要手写一遍,把底层的运行机制搞明白,后面用任何框架都不会发怵。

2. Agent的五大核心组件:理解一套可运行的机制

2.1 决策大脑:模型与系统提示词

模型是Agent的决策大脑,选型直接影响任务执行的上限和下限。在任务执行场景里,我关心的不是“谁的文采好”,而是“谁的工具调用格式稳定、谁能严格执行指令、谁的上下文利用效率高”。有些模型聊天很流畅,但到了Function Call环节就频繁输出残缺JSON,这就是典型的“不适合干活的模型”。

系统提示词在前几篇笔记里已经聊过,这里补充一个任务执行场景特有的点:要把“Agent的身份定位”和“行为边界”写清楚。比如你可以告诉模型:“你是一个订单处理助手,只负责查询和汇总信息,不负责修改订单状态;当你需要执行写操作时,必须明确请求用户确认。”这一段话比“请你认真负责地完成任务”这种空话有用得多。身份定位决定了模型以什么视角理解用户请求,行为边界决定了它不会在意外情况下滥用工具。

另外,模型参数设置也很关键。执行任务时,我一般把temperature调低(0到0.3之间),减少随机性;把max_tokens设大一点,避免Agent在多步推理过程中因为输出长度限制被截断。这些参数看起来不起眼,但经常是“模型突然不听话”的隐形元凶。

2.2 工具系统:Agent的手和脚

工具系统是Agent连接外部世界的桥。一个工具本质上就是一个函数,但你得用模型能理解的方式描述它。我通常把每个工具拆成三部分:工具名称、工具用途描述、输入参数Schema。

工具名称要准确且简短,比如“search_orders”而不是“模糊查一下订单”。工具描述要说明它能做什么、不能做什么、什么时候该用、什么时候不该用。输入参数Schema要尽量精确,包含参数名、类型、是否必填、取值范围。

这里有个容易踩的坑:工具的描述写得太笼统,模型就会在不需要的时候调用它。比如一个“查询用户信息”的工具,如果你不写清楚“只能查询当前登录用户的信息”,模型可能就会用它去查各种不相干的人。反过来,描述写得太长太复杂,模型又会犯迷糊。我的经验是:描述控制在两到三句话,把触发条件、返回内容、边界限制讲清楚,就够用了。

工具注册之后还要考虑权限。同一个Agent内部,不同工具的敏感级别差异巨大:查天气的工具随便调用,删除用户账户的工具必须有二次确认机制。权限控制最好放在框架层实现,也就是在执行工具前先检查当前会话是否具备调用资格,不能把这种安全问题全扔给模型判断。

2.3 记忆机制:短期上下文与长期知识

记忆是Agent区别于普通问答系统的重要特征。普通问答是一问一答,Agent则要在多轮交互中保持状态。

短期记忆最直接的载体就是上下文窗口。模型能看到的对话历史、工具调用记录、中间思考过程,都属于短期记忆。它的优点是实时、准确、不额外消耗外部存储;缺点是容量有限,任务一长就会溢出。

长期记忆则需要外部存储的支持。常见做法是把重要信息用向量数据库存起来,需要时通过语义检索拉取相关片段;也可以用结构化数据库存储更明确的约束,比如“这个用户的主要工厂位于宁波”、“这个项目已确认的交付日期是7月30日”。

我试过一开始把所有对话历史全量塞进上下文,结果任务进行到半小时,上下文就满了,模型开始把旧信息和新信息混在一起。后来改成“滚动静默”策略:把已经完成的中低层执行细节压缩成摘要,只保留当前子任务相关的完整上下文,效果立竿见影。

记忆这件事还要警惕污染。如果Agent把一次失败的尝试、或者一个错误的中间结论存进长期记忆,后面它会反复基于这个错误信息做决策。在A-MemGuard这类研究里,专门有人讨论Agent记忆的防御机制,核心一点就是:写入长期记忆的知识必须先经过提炼、去重和校验,不能把原始对话一股脑塞进去。

2.4 执行循环:Agent的主运行逻辑

Agent运行时的主循环,业内叫法很多,最常见的精神内核来自ReAct模式,也就是“推理-行动-观察”不断迭代。一次完整循环大致是这样:模型根据当前状态和用户目标,输出下一步意图(思考);如果意图是调用工具,就输出工具名称和参数(行动);框架执行工具并返回结果(观察);结果再喂回给模型,进入下一轮推理。

这个循环看似简单,实现的时候有不少细节要处理。

第一是终止条件。循环不能无限跑下去,我一般设两个硬限制:最大循环次数(比如10次)和最大token消耗量。达到限制就强制终止,把当前状态和已执行步骤回传给用户。

第二是异常处理。工具调用可能抛异常、可能超时、可能返回空值。这些情况都要包装成“观察结果”回传给模型,让模型基于异常信息重新决策,而不是让整个程序崩溃。工具层面的报错应该被捕获、格式化、注入回上下文。

第三是消息队列的组织。每次循环都要把“用户请求、系统提示、助手思考、工具调用请求、工具结果”这五类消息按顺序追加进上下文列表,这样才能保证模型能理解当前处于哪个阶段。顺序一旦错乱,模型会立刻丧失对任务状态的理解。

我在最早实现时踩过一个低级错误:工具结果没有区分“执行成功但返回空”和“工具卡死”,结果模型拿到一个空字符串就以为自己成功了,直接把后续步骤跳了过去。后来我统一在工具返回结果前加一层包装,至少包含success、error、data三个字段,模型就稳了很多。

2.5 反思修正:让Agent学会复盘

让Agent在任务失败或结果不理想时进行自我修正,是吴恩达在Agent课程里专门讲过的主题,也是实际项目中最有用的技能之一。你可以让Agent在每轮循环末尾追加一个“反思”字段:回答两个问题——“刚才这一步是否达到了预期的效果?”和“如果效果不理想,下一步怎么调整?”

为什么要单独把反思拎出来?因为模型直接继续执行时,往往会沿袭已经跑偏的路径一路走下去,而一旦强制它停下来回顾,它很可能自己发现“我连续三次都在用同一个字段查询,但数据里根本没有这个字段”,从而及时转向。

反思不一定每轮都需要。频繁反思会成倍增加token消耗,还会让Agent变得犹豫不决。我的做法是:只在两种情况下触发反思——工具返回错误时、关键步骤完成时。其他步骤让模型按原计划推进。

3. 动手实现一个最小Agent:猜数字任务实战

3.1 需求拆解与选型

理论讲了这么多,我们来实际跑一个最小Agent。为了把原理讲透,我这里不引入任何外部Agent框架,用Python手写一个基础的执行循环。

任务设定是这样的:系统随机生成了一个1到100之间的数字,Agent需要通过工具查询来猜出这个数字。工具包括一个“判断数字大小”的API,输入一个数字,返回“大了”“小了”或“猜中了”。这个任务简单,但已经包含完整的“工具注册、模型决策、循环执行、结果终止”四个环节,非常适合理解Agent的本质。

技术选型方面,我用的是支持Function Calling的通用大模型API,模型名称你可以换成任何你日常用的。环境依赖只需要一个openai库作为API客户端,其余都用Python标准库实现。

3.2 定义Agent能用的工具

先定义工具描述。这个数字判断工具只有一个参数,但为了示范,我故意把它设计成通用接口,让模型自己决定如何传入参数。

def guess_number(number: int) -> dict: """对目标数字做一次比较猜测""" target = 73 # 系统生成的随机目标 if number > target: return {"success": True, "data": {"comparison": "大了", "input": number}} if number < target: return {"success": True, "data": {"comparison": "小了", "input": number}} return {"success": True, "data": {"comparison": "猜中", "input": number}}

对应的工具Schema写成这样:

{ "type": "function", "function": { "name": "guess_number", "description": "向系统发起一次数字比较请求,输入一个1到100之间的整数,返回系统提示该数字比目标值大、小还是相等。每次调用只能猜测一个数字。", "parameters": { "type": "object", "properties": { "number": { "type": "integer", "description": "要猜测的数字,必须是1到100之间的整数" } }, "required": ["number"] } } }

注意工具描述里特意写了“每次调用只能猜测一个数字”,这是为了让模型不要试图一次传多个候选值。实际项目中很多工具调用参数比这复杂得多,描述起的作用也会更明显。

3.3 主循环代码实现

接下来写主循环。核心思路是:维护一个消息列表,把每次模型返回的工具调用指令解析出来,执行工具,把结果追加回消息列表,直到模型给出最终文字回答。

import json from openai import OpenAI client = OpenAI() messages = [ {"role": "system", "content": "你是一个数字猜谜助手。每次你只能通过调用guess_number工具来获取线索,直到猜中目标数字为止。猜中后,请用一句话总结你的猜测过程和最终结果。"}, {"role": "user", "content": "请猜出系统设置的目标数字。"} ] MAX_STEPS = 10 step = 0 while step < MAX_STEPS: # 1. 调用模型,携带工具定义 response = client.chat.completions.create( model="your-model-name", messages=messages, tools=[TOOLS], tool_choice="auto", temperature=0 ) resp_message = response.choices[0].message messages.append(resp_message) # 2. 判断模型是否要求调用工具 if not resp_message.tool_calls: # 模型不要求调用工具了,说明已经得到结论 print(resp_message.content) break # 3. 执行工具调用 for tool_call in resp_message.tool_calls: if tool_call.function.name == "guess_number": arguments = json.loads(tool_call.function.arguments) result = guess_number(arguments["number"]) # 4. 把工具结果作为role=tool的消息追加进上下文 messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) step += 1 if step == MAX_STEPS: print("已达到最大步数,任务未在限定步数内完成")

这段代码虽然短,已经把前三节讲的关键组件都串起来了:消息列表对应记忆中的上下文管理,工具Schema对应工具系统,循环对应执行控制和终止条件。如果你要落地到真实项目,只需要把guess_number替换成真正的业务接口,再把终止条件加上超时和成本上限即可。

3.4 运行结果与效果分析

我拿这个最小Agent跑了几轮,观察到的过程大致是这样:模型第一次调用guess_number(参数是50),得到“小了”;第二次调用75,得到“大了”;第三次调用62,得到“小了”;第四步就直接猜63还是继续微调,取决于模型本身的推理倾向。整个循环在4到6步内结束,没有出现死循环或格式错误。

这个过程中有几件值得注意的细节:如果在返回报错时没做统一封装,模型的反应就会不可控。我专门做过实验:把工具返回改成一行裸字符串“小了”,绝大多数情况下模型也能处理,但偶尔会把字符串误当作历史对话里的人话,从而产生困惑。封装成结构化对象之后这种情况就很少见了。

另外一个观察是:给模型加上“猜中后请用一句话总结猜测过程”这句提示之后,它会在工具判断成功后主动输出最终总结文本,而不是继续调用工具。这其实就是终止条件的天然实现——当模型认为任务已达成,它自然停止工具调用。对于更复杂的任务,你可以再加一层评判器来判断模型是否真的该收工。

3.5 升级方向:加入记忆和规划

猜数字任务用到的只有工具调用,还没涉及长期记忆和复杂规划。你可以在这个小框架上一步步升级。

记忆模块的升级方向:把每轮循环产生的工具结果存入一个列表,下次任务开始时把历史结果注入系统提示词,让Agent记住“上次我猜到了62,目标比62大”。这其实就是长期记忆的最小实现。

规划模块的升级方向:把单次工具调用变成“先规划后执行”。可以让模型在每轮循环前输出一个“当前计划”,再输出“本步动作”;框架根据计划和动作决定是否要在执行前等待用户确认。这种方式在多步任务里能有效避免Agent“想到哪做到哪”的问题。

我把这个猜数字案例放在第三章,是因为它足够简单,能让你亲眼看到“文本生成”是怎么一步步变成“任务执行”的。如果你能完全看懂这段小实现,后面的框架学习会轻松很多。

4. 框架、Skill、Harness与安全边界

4.1 什么时候用框架,什么时候手写

手写过最小Agent之后,你再看LangChain、LangGraph、AutoGPT这些框架,视角会完全不一样。你不会再把它们当黑盒,而是能一眼看出它们在哪些环节替你做了封装:消息循环的整理、工具调用的映射、异常状态的注入、状态的持久化。

但框架不是万金油。我见过不少项目模板式地引入了LangGraph,最后发现业务逻辑全卡在自定义状态节点里,代码里充斥着对框架内部类型的强依赖,调试一次要翻好几层抽象,痛苦不堪。

我的选型原则是:如果核心流程只有“模型调两三个工具、做一次汇总”,直接用原生Function Calling就够了,手写循环不超过一百行,还更好维护;如果任务链路长、分支多、需要并行或人工审批,再用LangGraph这类带状态机的编排框架,让状态转换显式化;如果团队没人真正理解底层原理,那就更不建议一上来就上重型框架,先用最小实现给人练手。

4.2 Skill与Agent的区别与配合

最近经常看到有人在Agent项目里同时提“Skill”和“Agent”这两个词,两者关系很容易搞混。

简单来说,Skill是被动封装好的“原子能力”,它可以是一个文档模板、一段可执行的脚本、一个API的调用规范。Agent则是主动的“决策者”,它根据当前目标决定要不要调用某个Skill、以什么顺序调用、多个Skill冲突时怎么取舍。

打一个比方:Skill是工具箱里的电钻、锤子、水平仪;Agent是拿着工具箱的装修师傅,师傅通过对任务的判断来决定“这个活先用哪个工具、在哪一步用、用完之后怎么交接”。Skill解决的是“某个能力怎么做”,Agent解决的是“现在该做什么”。

在落地时,我们通常把团队反复使用的操作流程沉淀成Skill,放在独立目录里统一维护;Agent这边只维护决策逻辑和工具映射表。这样当流程逻辑变化时,只改Skill不改Agent,职责切得很干净。

4.3 Harness与Agent的职责划分

“Harness”这个词在国内讨论里热度不算高,但在一些开源Agent项目中是个关键概念。Harness直译是“安全带、线束”,在Agent语境里我把它理解为“运行外壳”。

Agent负责推理决策,Harness负责管理运行环境。具体来说,Harness要做的事情包括:把可用的工具集合注入给Agent、控制Agent能访问哪些系统资源、设置步数和时间的限制、记录运行时日志、在Agent提出危险操作时拦截或要求审批。你可以把Harness理解成Agent的“操作系统”,Agent在上面跑,但跑多快、能碰什么、不能碰什么,都归Harness管。

这个分离最大的好处是安全边界清晰。理论上,即使Agent本身被恶意提示词带偏,它也只能在Harness允许的范围内操作。我们在项目里把所有敏感工具都放在Harness的“需审批列表”里,凡是涉及资金、删除、外发消息的操作,必须走人工确认接口,Agent自身没有权限直接触发。

4.4 Agent安全:最小权限和人工兜底

关于Agent安全,我把最重要的原则浓缩成三点,都是实操中验证过有效的。

第一,权限最小化。给Agent注册工具时,不要图省事直接把整个API的权限都交出去。一个查询订单的工具,后端只暴露那些确实需要的字段,不让Agent有机会触达它不该看到的内部数据结构。

第二,输入校验前置。Agent产生的工具参数往往来自模型对自然语言的解读,天然充满不确定性。工具入口处必须自己做参数校验、清洗和边界检查,不能假设模型填的参数一定合法。这一步是在Agent框架之外再加一层防护,两条路独立,能多扛很多意外。

第三,关键操作必须有人工审批环节。这个不用多解释,凡是会产生不可逆副作用的行为,都应该在Harness层做成“待审批”状态,并设置审批超时自动取消。

5. 我踩过的坑:常见故障与排查实录

5.1 agent execution terminated due to error:崩溃问题如何定位

见过最频繁的报错就是类似于“agent execution terminated due to error”的运行时终止。这个信息非常粗,几乎什么细节都没给,刚开始排查时让人头大。后来我总结了一套定位路径。

第一步,先看是模型侧报错还是工具侧报错。把每次模型响应和工具执行结果都打印成结构化日志,确认终止是发生在调用模型API时(比如网络超时、上下文超限),还是发生在执行工具函数时(比如抛异常、返回格式不符合预期)。

第二步,查看终止前的最后一条消息。绝大多数终止都不是无缘无故的,最后一条消息里往往藏着线索——可能是工具返回了一个模型无法理解的畸形结构,也可能是模型连续若干次输出了同样的无效调用,触发了循环保护。

第三步,检查是不是参数校验把合法调用误杀了。我在项目里见过模型生成了一个看似合理的参数,但严格校验后发现边界值刚好越界,工具直接拒绝执行,导致任务终止。这种情况的解法通常是调整参数范围描述,或者对边界值做自动修正。

5.2 Agent陷入死循环:不断调用同一个工具

另一个我经常遇到的问题,是Agent在某个失败状态下反复调用同一个工具,每次都得到同样的错误,但它就是不换策略。这种死循环消耗token很快,对线上的影响也最大。

根本原因通常是提示词里没有明确告诉模型“同一个工具连续失败时要换方案”。我在系统提示词里加了一条硬规则:如果某个工具连续两次调用都返回错误或非预期结果,必须停下来反思,尝试调整参数或改用其他工具;禁止在未反思的情况下进行第三次同参数调用。

除了提示词层面的约束,框架层还要有熔断机制。我一般对单个工具设置连续失败阈值(比如3次),一旦触发就自动停用该工具,并把“该工具已暂时不可用”这个信息注入到系统提示词里,逼着模型换路。有了这层兜底以后,死循环问题基本绝迹。

5.3 上下文爆炸:长任务怎么保持清醒

上下文爆炸是长任务里的头号麻烦。一开始Agent上下文很干净,跑了几十轮工具调用之后,各种中间结果、报错日志、临时推理全堆在里面,后面的轮次模型就开始糊涂了——它会把很久之前的一条旧记录当作当前最新状态,基于过时信息做决策。

解决思路是“分层记忆”。把消息列表分成三层:第一层是核心指令和当前目标,永远保持精简、不轻易变动;第二层是最新若干轮的详细历史,给模型足够的近期上下文;第三层是早期历史压缩后的摘要,只保留关键结论,丢弃过程细节。

我现在习惯在每完成一个重要阶段后,让模型自己产出阶段摘要,然后用摘要替换掉该阶段的原始消息。这个做法成本不高,但对长任务的效果提升极其明显。

5.4 工具结果不可靠,模型产生幻觉

有时候工具本身返回的数据格式不稳定,可能是字段名变了、返回了空数组、或者把错误信息拼在HTTP 200里返回。模型拿到这些脏数据后,往往会“脑补”出一些不存在的结论,然后一本正经地汇报给用户。

最有效的对策是给工具输出做标准化网关:所有工具返回之前统一清洗、校验,不符合Schema的字段直接标成未知,而不是带着错误类型传进上下文。同时,在系统提示词里明确告诉模型:当工具返回数据不完整或明显异常时,必须向用户说明“数据存在缺失”,不能自己估算补全。

5.5 记忆污染:越用越傻的Agent

最后聊一下记忆污染。这个坑最隐蔽,因为问题不会立刻暴露,而是Agent用着用着就开始表现异常——之前正确的决策链开始断掉,或者反复出现一些不存在的“既定事实”。

DeepSeek:根因在于长期记忆里写进了错误信息。可能是早期某一步Agent在幻觉状态下生成了一个错误的结论,又被自动写入记忆库;也可能是多Agent协同时,一个Agent的错误输出被另一个Agent当作事实存了下来。

我的解法是分层写入制度。所有要写入长期记忆的信息,先经过一个独立的“记忆整理器”过滤,它判断这条信息是否具备可验证的事实依据、是否与已有知识冲突、是否需要保留细节。被判定为存疑的结论不写入记忆库,只留在短期上下文中等进一步验证。经过这个改造之后,记忆污染导致的“越用越傻”现象明显减少。

6. 上线前的测试与可观测性

6.1 离线评估集:给Agent打分

Agent写完了不能用“感觉还行”来验收,一定要有可量化的评估集。我给项目建的评估集里,每个case包含:标准任务描述、预期工具调用序列(至少标注关键工具和关键参数)、预期结果范围、以及“禁止事项”(比如不许调用某个敏感工具)。

评估时重点看四个维度:任务成功率、平均步数、平均token消耗、安全违规次数。任务成功率衡量Agent能不能完成目标;平均步数和token消耗衡量效率;安全违规次数衡量Harness和提示词约束是否到位。

我常用的做法是准备30到50个case,覆盖常规路径、边界路径和异常路径。每次改提示词或工具描述之后,全量跑一遍回归,用表格记录变化。这个过程很枯燥,但对Agent上线的帮助超过任何优化技巧。

6.2 每一步都要有日志

Agent和普通接口最大的不同在于它没有固定的调用路径,出了错很难复现。因此可观测性设计要更细致。

我要求每一步循环都输出结构化日志,包含以下字段:当前步数、本轮思考内容、工具名称、工具入参、工具返回摘要、累计token数、本轮耗时。有了这些日志,排查问题时就不需要靠猜,直接将某一轮完整放回上下文里就能看到模型是怎么一步步走到崩溃的。

日志里我还会记录概率分布,比如模型给每个工具候选打分的情况。虽然大多数API只返回最终结果,但可以通过多次重试的分布间接观察模型的决策稳定性。如果一个Agent在相同输入下五次给出三种不同的执行方案,说明它的决策还不稳定,需要进一步收敛提示词或调整温度参数。

6.3 生产环境兜底策略

即便离线测试全通过,线上环境仍然会有意想不到的问题。我给生产环境Agent定的兜底策略一共有五条,简单列出来供你参考。

一是硬性步数上限和超时中断,达到上限后自动把执行权交回给用户。二是关键写操作全部走审批队列,不自动执行。三是对工具的调用频率做限流,防止Agent在循环里把第三方接口打到限流。四是每执行完一个阶段就产出一份阶段小结,就算后面任务失败,至少能保留已完成的成果。五是设置全局“紧急停止开关”,线上发现问题时运维人员可以一键暂停所有Agent任务。

这五条看起来都是基础设施,但真正出事故的时候,靠它们兜住的损失远比任何模型调优都大。

最后再分享一个实际体会:我前几次给Agent加工具的时候,总喜欢一句话写一大堆参数,觉得这样“功能多”。后来被连续几个错误案例教育了之后才明白,工具越专注,Agent越稳。一个只查价格的小接口,和一个能查价格还能比价还能下单的大接口,看起来后者更有用,但实际运行时前者能让模型更准确地决策,后者则经常让模型犹豫该用哪个参数、哪个开关。把工具做小、做准,是Agent开发里最划算的投资。如果你正在纠结要不要给Agent叠更多能力,建议先回去看看最常用的三个工具到底做扎实了没有。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询