Agent技能体系实战:从0到1搭建稳定可靠的智能体工具层
上周有朋友跟我吐槽说他的Agent项目卡在一个很尴尬的阶段——大模型该理解的理解了该生成的也生成了但真让它去执行任务总是差那么一口气让它查个天气它把城市名传错让它订个会议室它分不清时间格式让它分析一份报表它根本不知道先调哪个接口。这其实不是模型不行而是Agent的手脚没长好。这个手脚就是agent-skills也就是智能体的技能体系。这篇文章我不打算泛泛讲概念重点放在怎么把一套技能体系从0到1搭起来包含设计思路、完整代码、参数策略和排坑经验。适合正在做Agent应用开发、被工具调用不稳定坑过、或者想搞清楚Function Calling之外还有什么可玩的人。梳理清楚之后你会发现让Agent稳定干活靠的不只是模型而是一套能把模型能力转换成实际动作的技能层。1. Agent技能体系到底是什么为什么你的Agent经常“手脚不听使唤”1.1 先把架构摆清楚模型只是脑子技能才是手脚现在主流的Agent应用底层基本都有同一个结构大模型负责推理和决策外部工具负责执行Agent框架负责把两者串起来。这个结构本身没问题但工程落地时你会发现一个常见偏差——大部分人把大量精力花在写提示词上指望模型“理解”任务却很少花精力把Agent能做的事设计成一套标准化的技能。结果就是模型确实读懂了用户的意图但它不知道该怎么把意图落实到具体操作上。agent-skills的核心思路就是把Agent所有能执行的动作拆成一个个独立的、可配置的、可复用的技能包。每个技能包都有明确的名称、描述、输入参数和执行逻辑Agent根据任务判断要调哪个技能、怎么传参数、期望返回什么。技能层夹在模型和外部API之间负责把模型的抽象意图翻译成具体的函数调用。这个设计最大的价值是让“模型意图”和“系统执行”之间有了一个清晰的分界线。你不需要在提示词里写几百行“如果你要查天气请调用weather_api传入城市名参数格式为……”而是把这些细节全部放进技能定义里模型只需要知道有这个技能、这个技能处理什么场景参数怎么填由技能定义约束。1.2 技能层和Function Calling到底是什么关系很多人容易把agent-skills和Function Calling混为一谈我分开说一下。Function Calling是大模型提供的一种底层能力让模型在对话过程中输出一个结构化的函数调用请求比如{name: get_weather, arguments: {city: 北京}}。它是一个机制解决的是“模型怎么表达要调函数”的问题。agent-skills是基于这个机制之上的业务抽象。一个技能包最终会映射成一条或几条函数定义但它还包括了技能的触发条件、参数约束、执行逻辑、错误处理、返回格式约定。换句话说Function Calling是地基技能体系是在地基上盖的房子。没有技能层你也能做Function Calling但每个项目都要重新设计怎么描述函数、怎么写参数、怎么处理异常代码会越来越乱有了技能层这些都被封装进标准化的技能包里新项目直接复用就行。我还见过一种做法把Prompt里的工具说明写得像百科全书一样长一个functions数组动辄十几二十个函数结果模型在理解上频繁出错要么选错函数要么参数乱填。技能化的做法不是堆函数而是把函数按任务场景重新组织减少模型的选择压力同时把所有“非模型该管的事”从提示词里剥出去。1.3 和直接裸调API相比技能化到底解决了什么问题直接裸调API听起来更简单但实际跑起来坑很多。我给你列几个真实场景一个业务操作可能需要连续调用两三个接口比如“下单”要查库存、创建订单、扣减库存裸调API你得在代码里写死这条链路换成技能化之后整个链路被封装成一个create_order技能Agent只需要发起一次调用。外部API的参数五花八门时间格式、地点格式、单位换算各有各的规矩直接把API暴露给模型传参错误率极高。技能层可以在入参时做归一化把API的复杂度挡在技能内部。真实环境里API必然有调用频率限制、超时、限流、鉴权这些逻辑如果散落在业务流程里维护成本极高。技能化之后这些都是技能的内部实现细节对上层完全屏蔽。一句话总结技能层把“模型能做决策”和“系统能执行操作”这两件事解耦了这是Agent应用工程化的关键一步。2. 技能设计的第一课任务拆解和技能粒度怎么把握2.1 不要一功能一技能要一目标一技能刚开始做技能设计的时候最常见的错误是照搬API列表。你有10个接口就建10个技能结果看起来技能很全但Agent真正用起来效果反而差。为什么因为API是按资源划分的而Agent是按任务思考的。你给模型一堆细碎的工具它反而不知道哪个适合当前任务。我推荐按“任务目标”来拆技能。先站在用户视角列出Agent要完成的几类目标比如“查询信息”“执行操作”“生成内容”“分析数据”然后每个目标下再细分要处理的具体任务把每个任务沉淀成一个技能。一个技能对应一个完整、可交付的结果而不是一个底层API。举个例子一个客服Agent底层可能有查询订单接口、查询物流接口、查询退换货规则接口。按API拆你会得到三个技能但按任务拆你会得到“查询订单状态”和“处理售后申请”这两个技能。第一个技能内部自己决定要不要先查订单再查物流第二个技能内部封装了退换货规则匹配逻辑模型不需要知道这些细节它只需要选择一个正确的技能。这个思路的好处是模型的选择压力大大降低同时技能内部可以做出更智能的组合逻辑而不是让模型自己在多步调用中组合。2.2 技能粒度太大和太小分别有什么毛病技能粒度这个问题我真的是踩过几次坑才总结出感觉的。技能太粗表现在一个技能承担了太多职责。比如你做一个“处理报表”技能它既要查数据、又要做清洗、还要生成图表结果就是这个技能的输入参数会非常多内部的执行逻辑会非常复杂模型根本搞不清楚该传哪些参数。最要命的是不同的报表需求可能只需要其中一部分功能但模型没办法只调用其中一部分。这种技能开发的时候很爽用起来全是坑调试的时候你根本不知道是模型理解错了还是技能内部哪儿挂了。技能太细表现在技能的复用性确实高了但Agent调用次数爆炸式增长。比如你把“读文件”“解析JSON”“提取关键字段”这三级操作各自设计成独立技能一个任务就要连续调三四个技能每一步都有失败概率任何一个环节的传参有问题整个链路就崩了而且排查难度极大你还分不清是哪一步的问题。我现在的判断标准主要有三条这个技能能不能用一句话说清楚它干什么它的输入输出是否明确、有限它内部是否可以独立执行、不依赖外部编排。如果答案都是肯定的粒度就会比较合适。另外还得考虑复用频率一个技能如果只有一个场景用那就算粒度看起来很合理也没有单独拆出来的必要。2.3 不同场景下技能设计的优先级怎么排技能设计不是平均用力要根据Agent的主场景做取舍。比如一个偏信息查询的Agent技能设计重点是准确的数据获取和格式化返回一个偏任务执行的Agent技能设计重点是参数校验和操作确认一个偏分析推理的Agent技能设计重点是中间结果的可观测性和信息组合能力。我做过一个数据看板类的Agent最开始把“查订单量”“查GMV”“查同比”“查环比”这些都拆成独立技能结果模型经常选错后来我改成“查询经营指标”一个技能通过参数指定指标类型、时间段、对比维度调用准确率一下就上来了。这个经验说明当任务本质上属于同一个领域时合并成一个技能配合参数化比拆成多个技能更好因为模型只需要记住一个技能名剩下的用参数去细化就好。反过来如果任务之间差异很大、执行链路完全不同那就必须拆开。比如“发送邮件”和“生成周报”它们虽然都属于办公场景但目标完全不同合并到一起只会让模型混乱。2.4 技能除了单点能力还要设计组合和依赖关系现实任务常常不是一个技能能搞定的而是多个技能协同完成。技能化的设计阶段就要考虑到这种组合关系否则Agent每次都靠模型自由发挥成功率很低。组合的方式有两种一种是技能内部编排也就是一个技能内部调用其他技能的执行函数另一种是Agent层面编排由模型自己决定依次调用哪些技能。我倾向于把稳定、固定的流程在技能内部固化把灵活的流程留给模型去组合。比如“生成周报”这个技能内部稳定地包含拉取数据、生成摘要、渲染模板这三步Agent不需要知道这三步的顺序而“查一下竞品动态并分析对我们的影响”这种任务模型可能需要先调用“搜索竞品信息”技能、再调用“分析文本”技能这种顺序不固定就让模型自己规划。技能之间注意不要出现循环依赖A技能内部调了B技能B技能内部又调了A技能这种情况一旦出现轻则死循环重则把上下文打爆。设计阶段就要把技能依赖图画清楚定期检查。3. 从0到1搭一个技能包完整实操含代码3.1 先定场景和需求拆解这里做一个“股票行情分析”技能概念说再多不如动手跑一遍。我从最近做的一个投资助手项目里抽一个技能出来完整演示。场景是用户问“帮我看看最近几天茅台的股价走势顺便分析一下要不要入手”。这个需求里有两件事查行情、做分析。后者其实不太需要调外部工具模型自己会分析但前者必须有一个技能负责拿真实数据。把需求拆开我们发现核心技能是输入股票名称或代码输出一段时间内的收盘价、涨跌幅、成交量等历史行情数据。如果用户问的是实时价格那再补一个实时行情技能。这里我先实现一个历史行情技能时长为默认近30个交易日。这个技能的关键决策是把股票查询的细节全部封装起来包括股票代码映射、日期处理、数据格式化、异常处理。模型只需要告诉技能“要查什么股票、看哪个时间段”其他不用操心。技能返回的数据尽量整理成宽表格式让模型分析起来更省事而不是返回原始JSON让模型自己解析。3.2 技能定义的完整代码每个字段的含义要说透技能定义包含两个层面给模型看的描述信息以及给系统看的执行配置。下面的代码是完整的历史行情技能定义用JSON格式写可以直接塞进支持Function Calling的模型里。{ name: get_stock_history, description: 查询指定股票在某个时间段内的历史行情数据包括每日收盘价、涨跌幅、最高价、最低价、成交量。当用户问到股价走势、涨跌情况、历史表现、是否值得买入等需要参考行情数据的问题时使用此技能。, parameters: { type: object, properties: { symbol: { type: string, description: 股票代码或名称支持中文名称如茅台、贵州茅台也支持代码如600519。 }, start_date: { type: string, description: 开始日期格式为YYYY-MM-DD默认30个交易日前。 }, end_date: { type: string, description: 结束日期格式为YYYY-MM-DD默认为今天。 } }, required: [symbol] } }description这段文字特别讲究不只要描述技能能干什么还要写清楚在什么场景下触发。我见过很多定义只写“查询股票历史行情”结果模型在用户问“茅台最近涨了吗”这种间接问题时不会联想到调用它。把触发场景写在描述里能显著提高模型的调用准确率。参数里只设了三个symbol必填起止时间可选。有人可能会问日期为什么不设为必填原因是大部分用户不会精确到某一天他们只会说“最近几天”“上个月”这种模糊时间让模型自己按默认值处理反而更稳妥。默认值的逻辑在技能内部实现而不是在参数定义里写死这样更灵活。3.3 技能内部实现用Python写核心执行逻辑技能定义是给模型看的真正干活的是内部的执行函数。这里我用Python写一个简单的实现重点不在于数据源而在于技能内部怎么处理输入、怎么容错、怎么格式化输出。import json from datetime import datetime, timedelta class StockHistorySkill: def __init__(self): self.stock_map { 茅台: 600519, 贵州茅台: 600519, 600519: 600519, 腾讯: 00700, 阿里巴巴: 09988, } def execute(self, symbol: str, start_date: str None, end_date: str None) - str: # 1. 股票代码归一化 stock_code self.stock_map.get(symbol, symbol) if not stock_code: return json.dumps({error: f无法识别股票: {symbol}}) # 2. 日期归一化 if end_date is None: end_date datetime.now().strftime(%Y-%m-%d) if start_date is None: start datetime.now() - timedelta(days30) start_date start.strftime(%Y-%m-%d) # 3. 这里是实际拉取数据的逻辑项目里替换成真实数据源即可 raw_data self._fetch_history(stock_code, start_date, end_date) # 4. 输出统一格式化为文本表方便模型直接阅读和分析 lines [f股票代码: {stock_code} 查询区间: {start_date} 至 {end_date}] for item in raw_data: lines.append( f{item[date]} 收盘:{item[close]} 涨跌幅:{item[change_pct]}% f最高:{item[high]} 最低:{item[low]} 成交量:{item[volume]} ) return \n.join(lines) def _fetch_history(self, code, start, end): # 实际项目中在这里对接数据源比如akshare、tushare等 pass重点说说第4步的格式化成文本这个设计。很多技能实现习惯直接返回原始JSON觉得结构化数据更标准但站在模型的角度长串嵌套JSON非常消耗上下文而且模型从中提取关键信息时容易出错。我测试过多种返回格式最稳定的是用一行一条的纯文本表格模型直接拿去做分析基本不会看漏。execute方法返回的是字符串而不是字典这也是一个细节。统一技能接口返回字符串后面接各种Agent框架都方便不需要为每个框架改返回类型而且字符串天然就是给大模型消费的格式。3.4 把技能注册到Agent调用链路里完整交互流程技能定义好了、实现写好了接下来要把技能挂到Agent的调用链路里。现在主流的Agent框架都支持tools参数直接把技能定义传进去就行这里给出一个通用的对接写法。from openai import OpenAI client OpenAI() # 一个技能包可以包含多个技能定义 tools [ { type: function, function: { name: get_stock_history, description: 查询指定股票在某个时间段内的历史行情数据..., parameters: { type: object, properties: { symbol: {type: string, description: 股票代码或名称支持中文名称}, start_date: {type: string, description: 开始日期格式为YYYY-MM-DD}, end_date: {type: string, description: 结束日期格式为YYYY-MM-DD} }, required: [symbol] } } } ] # 第一轮模型决定要不要调用技能 response client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: 茅台最近一个月走势怎么样}], toolstools, tool_choiceauto ) # 如果模型返回了tool_calls就执行对应的技能实现 if response.choices[0].message.tool_calls: tool_call response.choices[0].message.tool_calls[0] skill StockHistorySkill() result skill.execute(**json.loads(tool_call.function.arguments)) # 第二轮把技能执行结果交给模型做分析 messages [ {role: user, content: 茅台最近一个月走势怎么样}, response.choices[0].message, { role: tool, tool_call_id: tool_call.id, content: result } ] final_response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolstools ) print(final_response.choices[0].message.content)这段代码就是Agent技能调用的最小闭环用户提问 → 模型决策是否调用技能 → 系统执行技能 → 结果回传给模型 → 模型生成最终回答。实际项目里你还需要加多轮对话历史、技能调用的超时控制、错误重试等但核心链路就是这几步。注意我在第一轮就传了tools参数这有两个作用一方面是给模型提供技能列表做决策参考另一方面是让模型在生成时知道系统具备什么能力。如果某些问题不需要调用任何技能模型会直接回答不会强制调用工具所以不用担心传了tools就让所有问题都走函数调用。4. 技能描述和参数设计的细节策略模型稳不稳就看这两块4.1 技能描述不是写给用户看的是写给模型看的很多技能定义的最大问题是description写得太简略或者太抽象。比如“查询股票数据”八个字人看了明白但模型判断是否调用时会比较模糊。用户问“茅台还能买吗”模型看到八个字的技能描述不一定会联想到底层需要行情数据支撑。好的description要做到两点一是明确触发场景二是说明技能输出能解决什么问题。看一下对比差的描述查询股票历史行情数据。中等的描述查询指定股票的历史行情数据返回收盘价、涨跌幅等信息。好的描述当用户询问股票走势、涨跌分析、历史表现、适合买入还是卖出等需要参考股票行情数据的问题时使用此技能。输入股票名称或代码输出指定时间段内的每日收盘价、涨跌幅、最高价、最低价、成交量。第三种描述的信息密度明显更高模型能更快地建立“问题类型”和“技能”之间的映射关系。有点像一个产品说明文档把用户场景写在最前面模型就是在读文档后决定要不要用你这个功能。我还建议在description里附带一些负面信息也就是明确这个技能不管什么。比如“本技能不提供实时行情不包含公司基本面数据”。这一招很管用能减少模型错误地用一个技能处理另一个领域问题的概率实际测试下来调用准确率能提升好几个点。4.2 参数Schema是技能的另一半灵魂这几个字段最容易被忽略参数的JSON Schema决定了模型能不能正确传参。我见过最典型的错误是把参数类型定义错比如日期字段定义成number模型传的数字五花八门系统根本没法解析。参数的type、description、required这三个字段是基本功但下面几个点才是真正拉开差距的地方。第一个是给参数加enum枚举约束。比如一个技能只支持“日线”“周线”“月线”这三种K线周期那就必须用enum限定不让模型自由发挥。不加enum的话模型有可能传“daily”“week”“monthly”这些变体每一种你都得在代码里做兼容很烦。加enum之后模型只能在预设值里选传参规范性会高很多。第二个是处理参数之间的依赖关系。有些技能里两个参数不能同时出现比如“按ID查”和“按名字查”属于两种不同的入口你必须在description里写清楚“id和name二选一优先使用id”。模型对这类约束的理解能力还行但你不能指望它自行领悟必须明确写出来。第三个是给参数设置合理的默认值说明。很多参数是可选但影响很大的比如返回条数、排序方式、时间范围如果不写默认值模型要么乱填要么不填导致技能内部用错误默认值。我建议在参数的description里写明“不填时默认返回最近30条”“不填时默认按时间倒序”把默认行为固定住结果更可控。4.3 返回结果怎么设计模型的分析质量才会高技能的返回结果直接决定了模型后续的分析质量。同样一份数据不同的组织方式模型的解读效果差很多。我做过一个实验同一个查询接口一种方式返回嵌套JSON另一种方式返回平铺的文本表格结果模型从JSON里漏读指标的概率明显更高文本表格的引用准确率更好。原因也不难理解嵌套JSON层级深、字段多模型在有限的上下文窗口内要自己定位关键信息注意力容易被无关字段稀释文本表格一行一个交易日日期和数值对齐模型很容易一眼扫出趋势。另一个建议是不要在返回结果里塞太多模型不需要的字段。比如查行情股票的全名、上市板块、市盈率这些如果不影响分析就别返回。返回字段越多模型越容易分心。要想清楚模型拿到这个技能结果是为了回答用户的提问需要哪些数据、哪些数据是噪音站在分析角度做筛选。我还会在返回结果的末尾附一段简短的说明文字比如“注最近一个交易日为2025-01-10数据来源为XX接口”。这个做法看起来不起眼但它给模型提供了一个事实锚点避免模型在时间判断上出错。大模型对“当前日期”的感知本身是模糊的有明确的数据时间戳它分析时就不容易张冠李戴。4.4 提示词里怎么引用技能才不会干扰模型判断技能定义放在tools参数里之后提示词里要不要提技能我的建议是不需要在系统提示词里逐个介绍技能但可以写清楚技能的总体使用原则。比如我习惯在系统提示词里加一段“你可以使用工具来获取实时信息或执行操作。当用户的请求需要特定数据支持时优先使用相关工具获取准确信息不要编造数据。工具返回的结果是权威依据如果工具返回错误信息如实告知用户。”这段内容的目的是建立模型的调用倾向而不是教你写操作说明书。真正让模型理解技能还是要靠tools参数里的定义本身。有些框架还支持在提示词里给技能做使用示例我觉得可以适度加一两个但不要多。示例隐含的规则很容易被模型过度泛化比如你给了一个查天气股票的示例它可能遇到所有查询类问题都先套用这个技能。5. 常见问题与排查技巧实录Agent不好好调技能多半是这几个原因5.1 技能该调用的时候不调用怎么排查这个问题排在所有Agent故障的第一位。技能定义得好好的模型就是不理或者直接自己编一个答案。我的排查顺序是固定的从概率最高的问题开始查。先检查技能描述里有没有明确的触发场景。如果description只写了技能能做什么没写什么时候该用模型很容易漏判。比如查行情时间的技能描述里如果连“股价走势”“涨跌幅”“是否值得买入”这些词都没出现模型在用户问“茅台还能买吗”的时候不调用就太正常了。再检查模型本身是不是被系统提示词带偏了。有些提示词里写了“你是数据分析专家可以根据已有知识回答”模型就会觉得自己什么都懂不愿意调用工具。如果有类似的表述建议改成“当需要最新数据或外部信息时务必使用工具获取”。最后检查技能数量。如果一次传了几十个技能模型的注意力会被稀释调用准确率急剧下降。这种情况我建议精简技能数量或者把技能按功能分组先在模型层面做一个粗分类再进细分类减少单次决策的候选数量。5.2 技能调用了但参数永远传不对参数传错是第二大类高频问题。最常见的是日期格式五花八门模型一会儿传“2025-01-01”一会儿传“2025/01/01”一会儿传“1月1日”。避免这个问题最有效的办法不是靠模型自觉而是在技能的description里把格式写死同时代码里做一层归一化兜底。我自己的做法是在execute方法内部对参数做容错解析不管模型传什么常见格式都能转成标准格式。这个兜底逻辑不能省因为模型输出有随机性同一个问题跑10次可能有1次格式不对有了容错逻辑这1次也能正常执行。还有一种情况是模型把参数名都传错了比如技能定义里是symbol模型传的是stock_name这种通常是模型的上下文太长了注意力分散导致理解偏差。解决办法是减少messages里的冗余历史精简提示词或者在技能参数里增加别名支持也可以在代码里做兼容映射。5.3 多个技能之间互相干扰让模型选错当Agent挂了多个技能时描述如果写得模糊模型就分不清边界。我见过最典型的案例是“查天气”和“查空气质量”两个技能description都没有明确写清楚两者的区别模型经常把“空气质量”问题交给“天气”技能处理。解决办法是在描述里主动做边界声明每个技能都写清楚“本技能不处理什么”。比如天气技能的描述末尾加一句“仅提供天气信息不包含空气质量数据”空气质量技能反过来写“专门提供PM2.5、AQI等空气质量数据不提供温度降水信息”。边界划清楚后模型的选择准确率会明显提高。还有一种是多个技能能完成同一个目标但路径不同导致模型选择困难。比如既有“查股票行情”又有“生成投资分析报告”用户问“帮我看看茅台股票”时模型可能两个都选或者挑一个。这种建议把技能层次做分层分析报告技能在description里注明“信息来源于行情数据”模型自然会更优先去调底层的数据技能。5.4 技能执行报错怎么给模型一个体面的失败反馈技能执行不可能永远成功外部接口超时、数据源没有数据、参数虽然合法但查询结果为空这些异常处理是必不可少的。这里的关键是设计一套统一的错误反馈格式避免把原始异常堆栈直接抛给模型。我常用的格式是三元组错误码、友好描述、替代建议。错误码方便系统层面做监控和告警友好描述让模型知道发生了什么、怎么向用户解释替代建议给模型一个补救方向。比如股票代码无效时返回“{错误码: STOCK_NOT_FOUND, 描述: 未能找到该股票的历史数据可能代码或名称有误, 建议: 请用户确认代码或尝试使用拼音或英文名查询}”模型拿到这个结果就能自然地接话而不是瞎猜。另外建议给技能加超时控制。一个技能内部调外部接口如果超过10秒还没返回就应该中断并返回超时错误否则Agent的整体响应时间会拖得很长而且上下文窗口也会被挂起的请求占住。这个在技能层做一次统一封装所有技能都复用同一套超时逻辑。5.5 附一个踩坑速查表建议直接收藏现象最可能的原因排查动作技能该调不调模型直接硬答技能描述缺少触发场景说明在description里补充用户问题关键词和触发条件技能该调不调但描述没问题系统提示词里写了“无需工具”或类似表达检查并修改系统提示词的引导倾向技能调用了但参数格式乱参数本身缺少格式约束在参数description里写死格式并加解析兜底技能调用经常选错目标多个技能描述边界模糊给每个技能加“不处理什么”的负面声明技能执行报错后模型瞎编错误反馈没有结构化的补救信息统一错误返回格式给替代建议同一问题调用结果不稳定模型上下文被无关信息污染精简messages控制历史轮次最后说点个人的实在体会技能体系这个东西看起来是技术架构问题实际上更像产品设计问题。技能的拆法、描述怎么写、参数怎么定决定了Agent这个“员工”到底好不好用。我自己的项目里很多次模型表现“差”不是模型不够聪明而是我把技能设计成了只有我自己才看得懂的样子——函数名叫a描述写一句b参数逻辑藏在代码深处模型自然用了也不顺手。把skills当产品来打磨描述文案像写用户需求文档那样反复迭代是我跑通这套体系之后最大的心得。最后再分享一个小经验技能不要一次性全部上线。我习惯先加两三个核心技能跑几天看日志记录模型调用时的选择行为和参数填法再根据真实数据调整技能定义。等核心技能的调用准确率稳定在90%以上再逐步加新技能用这个节奏推进Agent对外表现一直比较稳排查问题也好定位。希望这篇实战记录对正在折腾Agent的你有点帮助。