做了近两年的Agent开发,回头去看,真正沉淀下来的东西其实就五件事。最近带新人,翻了不少简历,也看了很多面试者的项目复盘,大多数人写的都是“精通LangChain”“熟悉Coze工作流”“会调各种大模型API”。可真到动手做项目的时候,你会发现框架好不好用、平台便不便利,都不是决定成败的地方——真正决定一个Agent能不能从Demo走向生产、从“能跑”变成“能打”的,恰恰是那些框架文档里不会明说的底层能力。这篇文章我就把这五件事摊开讲:任务拆解、函数调用、记忆管理、反思纠错、评估观测。每一件我都会结合自己踩过的坑、改过的代码和上线后遇到的事故来讲,希望能帮正在Agent开发这条路上摸索的朋友省点时间。
1. 任务拆解:决定Agent智能度上限的第一件事
我接触过不少团队,大家一开始做Agent都是同样的流程:把大模型API接上,写一个system prompt,然后丢给模型一个任务,等它输出。做出来的东西在小范围Demo里确实有模有样,但一上真实业务就露馅——经常做一半就卡住,或者直接跑偏,输出天马行空的内容。
问题几乎都出在同一个地方:我们让模型做的事太“大”了。
1.1 为什么大多数Agent看起来“笨”
大模型的强项是语言理解、知识调用和内容生成,但它本质上不是一个“自主规划机器”。你让它“帮我完成这份市场分析报告”,它就算能写出报告,过程中也谈不上真正的规划——它不知道先收集哪些数据、再做什么交叉分析、最后用什么结构呈现,它只是根据训练时的模式,一次性把最可能的文本生成出来了。
这种感觉就像你问一个新来的实习生“把项目推进一下”,他大概率会愣住,因为他不知道第一步做什么、里程碑怎么设、遇到阻碍找谁。但你要是说“先去看一下往期竞品方案,整理出三页摘要,明天下午两点前发我”,他就知道该怎么动。
Agent开发也是这样。一个成熟的Agent工作流,核心不是“让模型自己思考”,而是人为地把大任务拆解成一系列小步骤,把每一步的输入输出定义清楚,让模型在每一步只做一件它擅长的事。拆得越细,每一个环节就越可控,出错的可能性就越低,排查起来也越容易。
我早期犯过的一个典型错误,是让Agent同时承担“信息检索、方案撰写、格式美化”三个职责。结果Prompt写得再长,模型也经常顾此失彼——检索的时候写得像方案,写方案的时候又开始搞排版。后来我把这个Agent拆成三个子Agent:检索Agent负责找资料并输出结构化摘要,方案Agent只负责基于摘要写正文,排版Agent只做最后的美化。拆完之后准确率肉眼可见地提升,而且每个环节都能单独测试、单独优化。
1.2 任务拆解的落地方法:从业务目标到执行步骤
那具体怎么拆?我建议用一套比较笨但有效的方法:把自己当成一个“不会思考的执笔者”,逼迫自己把业务需求写成人能照着执行的标准作业程序(SOP)。这里有几个关键动作:
- 明确每个子任务的输入和输出。比如“抽取用户意图”这个子任务,输入是用户原始消息,输出是一段固定格式的JSON(意图类型+关键参数+置信度)。输入输出一旦模糊,模型就只能靠猜。
- 定义子任务之间的依赖关系。有些步骤必须在前一步完成后才能做,比如先查库存再报价;有些步骤则可以并行,比如同时查物流信息和查用户历史订单。依赖关系理清楚后,Agent的执行流程才是确定性的,而不是每次让模型自由发挥。
- 给每个子任务设一个验收标准。这个标准最好机器可判,比如“抽取结果是否包含必填字段”“检索结果是否大于10条”,让Agent在执行完某一步后能自己判断是否要继续还是重试。
在企业级Agent里,我通常会把这些任务节点用工作流引擎(比如Dify、Coze这类低代码平台,或者自己维护一套任务调度服务)串成一张执行图。这不是为了炫技,而是为了给每一步加上状态记录、超时控制、失败重试和人工介入点。你想想,如果Agent在执行到第7个步骤时挂了,没有工作流状态,调试的时候你连它“做到哪一步了”都不知道,那排查成本就太高了。
1.3 拆解到什么粒度才算合适
这里有个实操上的权衡:拆得太粗,模型做起来压力大、容易出错;拆得太细,一次任务要发起七八次模型调用,延迟和成本都直线上升。
我的经验是:如果一个步骤可以用两条规则写清楚、不需要模型做复杂推理,那就别用模型;如果一个步骤涉及信息整合和判断,且有明确的交付物,那才值得作为一个Agent子任务。比如“调用查询API获取订单状态”这种,就应该用代码直接做,而不是让模型来选工具、传参数——你不需要一个“AI”来帮我点按钮,你需要的是一个可靠的消息推送。真正应该交给模型的步骤,是那些“没有标准答案、需要归纳和判断”的部分,比如从一堆文档中提取用户的核心诉求、对不同报价方案进行权衡对比。
一句话总结这个部分:Agent的“智能感”很大程度上是任务拆解设计出来的,而不是模型自己长出来的。你拆得越清楚,Agent表现得越聪明。
2. 函数调用与工具设计:把模型的能力接到真实系统上
任务拆解是把“要做什么”理清楚,那“怎么做”就涉及到Agent的另一条腿——工具调用。没有工具的Agent只是一个会聊天的鹦鹉,有了工具的Agent才真正能干活:查库、下单、发消息、调接口、操作文件。这个领域有个专门的机制,叫Function Calling(函数调用),也是我认为做Agent开发必须彻底吃透的第二件事。
2.1 先理解Function Calling的底层逻辑
通俗地说,Function Calling就是让大模型在对话中“声明”它想调用哪个函数、传什么参数,然后由你的代码去真正执行这个函数,再把执行结果返回给模型,由模型根据结果生成最终回复。整个过程是一个循环:
- 用户提出需求;
- 模型判断需要调用某个工具,输出结构化的函数名和参数;
- 你的代码执行该函数,拿到真实结果;
- 结果被重新塞回模型,让它基于真实数据做下一步决策。
这条循环看起来简单,但我见过太多人在这里翻车。最常见的翻车方式:函数定义写得稀烂,模型根本不知道该用哪个函数;参数Schema写得不严谨,模型传参格式错误;函数返回的结果过于庞大冗杂,模型被垃圾信息带偏。
2.2 工具设计的四个实操原则
我在实际项目里慢慢总结出四个工具体验的原则,照着做基本不会踩大坑:
- 工具的description要像说明书一样具体。不要写“查询天气”这种一句话,而要写清楚“根据城市名和日期查询天气信息,城市名支持中文和拼音,日期格式为YYYY-MM-DD;当用户问到未来一周天气时,需要多次调用本工具获取每天的数据”。模型是在靠Description做路由选择,写得太简单,它就瞎选。
- 入参越少越好。每个工具只需要业务上不可省略的参数。我看到有人设计“查询订单”工具,带了用户ID、订单号、下单时间范围、订单状态、分页页码、每页数量、排序方式七个参数,结果模型要么漏填,要么填错。精简入参、能靠上下文推导出的参数就放进去而不是让用户提供,模型调用成功的概率会高很多。
- 返回结果要给模型“够用但不超载”的信息。不要直接把整个数据库记录全量返回,而是要做一个面向展示的结构化摘要。例如查询订单接口返回,不需要把日志表、回调记录都带回来,只需要订单状态、商品名、金额、更新时间这几个关键字段。返回内容越长,模型处理越慢,越容易被无关字段带偏。
- 工具与工具之间要有门槛区分。当工具数量超过20个时,模型选错的概率会明显上升。这时候我建议引入“工具分组”或者“二级路由”——比如先让模型决定“这属于库存操作还是订单操作”,再在对应分组内做具体工具选择。相当于先缩小候选集,再精确匹配,而不是让模型一次面对几十个工具。
2.3 工具调用失败也不能让链路直接崩掉
工具不可能永远成功,网络超时、权限不足、参数校验不通过都是常态。Agent开发里最容易忽略的就是这部分错误处理。
我踩过一个挺惨的坑:某次上线了一个“自动退款”工具,模型成功调用了它,但后端接口返回“余额不足,退款失败”。我当时没有设计失败回传逻辑,模型拿到结果后直接跟用户说“您的退款已处理”。用户在后台等了三天没到账,工单炸了。后来我才意识到,工具调用返回错误信息时,模型是能理解的,但前提是你要在工具返回格式里把“错误码”和“可读的错误说明”写清楚,并让模型在工具执行失败时必须如实告知,而不是自行脑补成功。
所以我现在的做法是:所有工具的返回结果统一包一层结构化格式,包含status、data、error_msg三个字段。当status不为success时,模型被明确告知“工具执行失败,请向用户说明原因,并询问是否重试或改用其他方案”。这套机制让工具调用的失败率对用户感知的影响降到了最低。
另外,关于现在很火的MCP(模型上下文协议)和各类Agent框架,我的观点是:框架只是帮你省了工程化的工作量,比如消息解析、工具注册、会话管理;但函数调用的核心问题——工具定义质量、参数Schema设计、错误处理策略——框架解决不了,必须自己一层层磨。
3. 记忆与上下文管理:让Agent既记得住又翻得对
第三个关键能力是记忆。Agent和单轮问答最大的区别在于,Agent要在多轮交互中持续推进任务,它需要记住用户前面说了什么、自己做到哪一步了、中途产生了哪些中间结果。记忆管理做不好,一个看起来聪明绝顶的Agent,聊到第三轮就开始“失忆”,客户体验极其拉胯。
3.1 记忆分层的设计思路
大模型的上下文窗口有限,这是物理约束。你不能把所有历史对话全部塞进去,也不能做一个什么都不记得的对话机器人。所以我比较推荐把记忆分成三个层次:
- 短期记忆(当前会话):就是当前对话窗口内最近的几轮内容,直接放在上下文中即可。它负责维持对话的连贯性,相当于人的“工作记忆”。
- 工作记忆(任务中间状态):Agent在跑一个多步骤任务时,每一阶段的中间结果(比如提取到的用户信息、查到的API返回、生成的任务计划)需要被缓存起来,供后续步骤读取。通常存在一个状态存储里,比如Redis或Mongo。
- 长期记忆(跨会话偏好和事实):用户的长期偏好、历史订单、常用地址、身份信息等,不能每次靠用户重新说,而应该从向量数据库或业务数据库中检索出来,按需注入上下文。
这三层记忆里,最容易出问题的是长期记忆。很多团队一上来就搞向量库,把用户所有历史消息都embedding了,然后每次请求时做相似度检索,把TopK结果塞进提示词。听起来很合理,实践里却经常翻车。
3.2 向量检索的两个常见误区
第一个误区是:相似度不等于相关性。用户昨天的聊天里提到“我最近在看新能源车”,今天问“那款车怎么样了?”——单纯用向量相似度检索,很可能会把“新能源车”相关片段找回很多,但真正需要的是对话状态里记录的那个具体车型。这就是为什么长期记忆不能只靠向量检索,业务数据库里的结构化事实(比如“用户最新关注车型:Model Y”)反而更可靠。
我现在的做法是“元数据过滤+向量排序”双通道:先用结构化标签(比如会话ID、用户ID、时间范围)做硬过滤,缩小候选集;再在候选集里用向量相似度排序。这样既保证相关性,又避免噪声。
第二个误区是TopK设置不理性。K设小了,关键信息经常漏掉;K设大了,一次性塞给模型几页无关内容,反而干扰判断。我的经验是K取3~5,而且每条记忆最好都是一段足够自包含的短句,这样模型读起来负担小。
3.3 上下文压缩:另一个被低估的工程点
当会话轮次很长时,短期记忆也会暴涨。为了控制token开销,需要做上下文压缩。我常用的策略是:把超过N轮的历史对话做一个“摘要”,只保留其中的关键事实(比如用户提过的需求、已经确认过的信息、已经完成的任务),然后让模型基于摘要继续对话。
这个压缩不是简单地截断前后文本,而是要“断点续传”。我的做法是每次压缩前,专门让模型分类输出:哪些信息必须保留(包括事实、承诺、偏好)、哪些可以丢弃(寒暄、重复信息、中间推理),再根据分类结果生成一份结构化摘要。这样即使上下文被截断,Agent仍然知道“客户要订周五下午三点的会议室,人数20人,需准备投影设备”这些关键信息。
记忆管理这块,我给你一个实用建议:给每一条记忆打审计标签——来源、时间、置信度。这样当Agent引用了一段记忆结果时,你能追溯它是从哪里来的、是不是过期了。没有这个标签,排查Agent答错问题时你会被记忆污染问题搞得极其痛苦。
4. 反思与自我纠错:从能跑到跑稳的关键一跃
前三年做Agent,大家追求的是“能跑”;今年开始,甲方和老板都在问“稳不稳”。一个Agent要变得稳定,“反思机制”是关键。这也是第四件必须学会的事。
4.1 什么是反思机制,常见的三种形式
反思机制大致有三类:
- 执行前规划验证:模型在执行任务前先给出计划,用一个独立的检查步骤判断计划是否合理、是否有遗漏或冲突,再决定是否执行。
- 执行中自我纠察:Agent每执行完一个工具调用,把真实返回结果跟预先的期望对比,看看是否一致。不一致时,要么重新调用工具,要么换一种思路。
- 执行后整体复盘:任务全部完成后,让模型回头评估最终输出是否满足用户原始需求,不满足就补充修订步骤。
理想状态下,这三层反思叠起来,Agent的稳定性和条理性会有质的飞跃。但这里有一个必须清醒认识的点:反思本身也是模型在推理,它同样会出错。让同一个模型既当运动员又当裁判,结果往往是不自纠的——它在第一步产生的幻觉,在第三步通常也能自圆其说。
4.2 真正可靠的“反思”是硬性校验,不是让模型自己批评自己
我做了几次实验之后,得出的结论是:模型的自我反思只能作为辅助,真正起决定性作用的,是外挂的规则校验和确定性断言。
举个例子,如果Agent的任务是“收集企业公开信息并输出工商报告”,那我就设计一条硬校验:报告里必须包含“统一社会信用代码”字段,且该字段必须符合18位格式。代码里写一个正则校验就行,不依赖任何模型判断。如果Agent输出的报告缺了这个字段,校验直接打回,让它重新生成。
当用户需求是“找出符合条件的所有订单并计算总金额”,那么在After Tool阶段,我可以直接用一条SQL去验证结果集数量和金额总和,而不是相信模型“我已经算完了”的断言。
看到没有?能白纸黑字用规则校验的,就不要留给模型自由裁量。反思机制不是为了“让模型意识到自己错了”,而是为了“让系统有机会在错的结果影响用户前拦截它”。
4.3 反思循环的边界:什么时候停
当然,反思不能无限做下去。每反思一次,就要多一次甚至多次模型调用,延迟和成本都会增加。我在生产环境里一般会给反思循环加上三条硬性约束:
- 最大重试次数:同一个子任务最多失败重试3次,超过就转人工,不再反复空转。
- 条件重试,而不是无条件重试:只有当失败原因明确可修(比如“缺了字段”“格式错了”)才重试;如果是模型幻觉性错误且二次生成仍然不一致,大概率是需求描述或工具定义有问题,重试也没用。
- 设置“反思成本预算”:一个任务的总token消耗超过预算时,强制终止执行,转人工闭环。
我见过一个团队做“智能客服退款Agent”,因为没设重试上限,模型在遇到一个晦涩的退款规则时连续自我纠错了11次,不仅把客户晾在那里,还烧掉了大量token。这种事看着好笑,真发生在线上就是事故。
换句话说,反思机制是一把双刃剑:设计得好,它能把Agent从“不稳”带向“稳定”;设计得不好,它就是一台无底洞式的token粉碎机。关键是搞清楚“哪些错值得反思、哪些错必须靠外部规则拦死”。
5. 评估与可观测性:上线之后才真正开始的另一半工作
最后一件事,可能是最容易被忽视但最要命的一件事:评估和可观测性。很多人做Agent,Demo阶段玩玩很开心,一上生产就抓瞎——模型行为千变万化,没人说得清它到底为什么会答错。原因很简单:没有建立评估体系和追踪机制。
5.1 没有评估体系的Agent开发,等于在盲写
我问过不少同行:“你的Agent成功率是多少?”很多人的回答是“感觉还行”“大部分能成”。这种直觉式的评判方式,在小范围试用时还能凑合,一旦面对真实流量和复杂多变的用户输入,就会靠不住了。
我现在养成的习惯是:每个Agent项目,从第一天就建立一份评估集。评估集不需要很大,三四十条高质量样本即可,但必须覆盖几个类型:
- 典型成功路径:常规输入,预期Agent按正常流程完成。
- 边界条件:输入信息缺失、格式怪异的特殊情况。
- 用户对抗场景:用户反复修改需求、要求取消已执行操作等情况。
- 工具异常场景:数据库无数据、接口超时、权限不足。
每次改完模型、Prompt或工具定义,就对着这份评估集跑一遍回归,记录成功率、工具调用准确率和单任务平均成本。有了这些数字,你才能知道“这次改动到底是变好了还是变坏了”。
在做评估时,请记住:不要让写这个Agent的人拍脑袋判定结果对不对。能硬编码判断的就硬编码判断,需要主观判断的,再用部分AI或人工抽检。否则,同一个模型在有时候会“无脑同意”你的判断,你的评估结果会被模型自评的乐观偏差影响。
我尝试过一个更好一点的方案:让一个外部的“审查Agent”来当评判员,给它一套独立的评分标准,不与执行Agent共享上下文。相当于让两个模型互相牵制,出错的概率低不少。
5.2 可观测性:你得能看见Agent到底做了什么
评估告诉你“好不好”,可观测性告诉你“为什么不好”。Agent的可观测性,至少要做到三个层面:
- 轨迹回放:完整记录Agent每一步执行的输入、输出、思考痕迹、工