首页 / 资讯中心 / 文章详情

Agent Skills技能编排实战:从设计思路到落地避坑指南

Agent Skills技能编排实战:从设计思路到落地避坑指南 ★ FEATURED ARTICLE
agent-skills 这个名字我第一次看到是在一次内部技术评审的文档标题里。当时团队正在做一个“某跨平台系统”的AI助手遇到了一个很典型的问题同一个Agent业务方一会儿要它查订单一会儿要它算报表一会儿要它写邮件。 Prompt越写越长逻辑越改越乱新功能一加老功能就崩。后来我们把Agent的能力拆成一个个独立“技能包”——也就是Skills——按照统一接口动态加载整套系统的可维护性和扩展性才终于走上正轨。这篇文章就聊聊我在实际项目中围绕“agent-skills”总结出来的设计思路、实现流程和踩坑记录。如果你正在做智能体编排、工具调用或AI应用的后端架构不管你是入门还是已经写过几个Demo这篇文章里的方案和代码基本可以拿走直接改一改落地。我会尽量把“为什么这么设计”讲透而不是只丢给你一堆名词。1. 先理解Agent Skills到底在解决什么问题1.1 从“一个全能Agent”到“一套技能库”的思路转变很多刚接触Agent的人第一反应是做一个“什么都能干”的超级智能体。用户问什么它就答什么用户要什么工具它就临时写代码去调。这种思路在Demo阶段行得通但一旦进入真实业务场景很快就会碰到三堵墙第一堵墙是Prompt膨胀。所有的功能说明、参数格式、注意事项全塞进系统提示词里动不动就是几千字模型既要理解上下文又要记住工具用法输出质量直接下降。第二堵墙是职责耦合。所有能力都揉在同一套业务逻辑里改一个功能模块很容易影响其他模块。比如你给Agent加了“生成日报”的能力结果它调用“查订单”的时候突然开始写日报了排查半天发现是共享代码里的一个异常分支。第三堵墙是权限失控。一个Agent如果要调数据库、发消息、写文件如果所有能力都平铺在一起你很难控制它在什么场景下可以做什么也不能按用户等级或业务范围做细粒度限制。Skills的核心思路就是把“一个什么都会的Agent”拆成“一个会调度技能的主脑 一堆职责单一的工具模块”。Agent本身只负责理解意图、规划步骤、选择技能具体的执行动作全部交给Skills完成。这和你把做饭的流程拆成洗菜、切菜、炒菜三个独立环节是一个道理任何一个环节出了问题单独替换就好不需要重做整个厨房。1.2 技能Skills和工具Tools究竟有什么区别很多教程里把Skills和Tools混着说但在工程设计上它们是有明显边界的。Tools通常指一个具体的函数或外部API比如“发送HTTP请求”“读取文件内容”。而Skill是一个更上层的组合单元它可能包含多个Tools的调用顺序、内部的状态管理、甚至一套独立的Prompt模板。我习惯这么理解把Tool想象成螺丝刀把Skill想象成“用螺丝刀拆开手机后盖并更换电池”的完整流程。你需要螺丝刀这个工具但还需要知道先拆哪几颗螺丝、哪些卡扣需要小心、装回去要注意什么。这些知识组合在一起才是一个可复用的Skill。在实际系统中Skill通常会包含一段给Agent看的自然语言描述说明“这个技能什么时候用、能做什么、不能做什么”一个结构化的输入Schema描述调用这个技能需要哪些参数、参数的类型和约束一个可执行体内部可以调用单个工具也可以是组合逻辑或外部服务若干校验和回退机制确保参数不合法时不会直接把错误抛给用户理解了这层区别你再去设计系统就不会简单地把“技能”等同于“函数列表”而是会认真思考每个技能包应该封装多少逻辑、暴露什么接口、以什么粒度存在。1.3 一个真实场景里的技能编排示例举一个我实际做过的例子。当时我们的Agent需要支持“团队报销单审核”这个业务。如果不用SkillsPrompt大概长这样你是一个财务审核助手你需要根据报销单编号查询单据信息获取审批人列表检查金额是否超限对比历史报销记录最后输出审核结果审核通过还要调用通知接口告知报销人……这段Prompt又长又死一旦审核规则变化比如超过5000元需要二次审批整个Prompt就得重写。换成Skills之后系统变成了这样技能query_reimbursement输入报销单号返回单据详情技能check_amount_limit输入金额和规则版本返回是否超限技能analyze_history_claims输入报销人姓名返回历史报销频率和总额技能approve_and_notify输入报销单号和审核意见执行审批并发送通知Agent只负责根据用户请求决定先调哪个技能、根据结果判断下一步调哪个技能。审核规则变化时我只需要改check_amount_limit这单独一个技能完全不影响其他模块。这种做法无论是在开发效率上还是后期维护上都比一个大Prompt强得多。2. 核心设计Skill的粒度、接口与组织方式2.1 技能粒度怎么定才不容易出错设计Skills系统的第一个关键决策就是技能粒度。粒度太粗一个Skill干太多事内部的逻辑复杂度不降反升粒度太细一个简单的业务请求要编排五六个SkillAgent的调用次数和错误率都会上升。我在实践中总结出一个相对好用的判断标准一个Skill应该对应一个“业务子系统的一次完整动作”并且这个动作的结果是可以被Agent直接使用的。拿订单系统举例。“根据订单号获取订单详情”是一个合适的粒度“获取订单、计算折扣、生成短信、发送短信、记录日志”合在一起就太粗了“获取订单号”又太细因为这不是一次完整的业务动作只是操作中的一个片段。还有一个辅助判断办法就是看这个Skill被其他Skill复用的概率。如果两个动作经常被组合使用且组合的顺序稳定那可以考虑合并成一个Skill。如果两个动作几乎没有关联只是恰好出现在同一个业务流程里那就应该拆开。比如“查库存”和“计算运费”经常一起用但库存查询也可能单独被用来做库存盘点运费计算也可能单独用于价格估算所以这两个就不该合并。2.2 一个Skill的完整结构长什么样一个设计良好的Skill从数据模型上看至少包含五个部分。我贴一段简化版的代码注释里写了每个字段的含义dataclass class SkillDefinition: # 技能唯一标识Agent在规划时依赖这个字段做精确引用 skill_id: str # 技能名称尽量用人类可读的自然语言 name: str # 技能描述说明在什么场景下用、输入输出大概是什么 description: str # 输入参数定义用JSON Schema描述 input_schema: dict # 技能分类标签便于检索和管理 tags: list[str] # 安全级别比如公开、需要权限、管理员专属 permission_level: str # 技能实现的具体路径比如哪个python模块里的哪个函数 handler_module: str handler_method: str # 超时时间避免Agent长时间等待 timeout: int 30 # 是否允许Agent在未完全确认参数时调用 allow_partial_args: bool False你可能会问为什么input_schema一定要用JSON Schema而不是随意定义一个Dict因为Agent在调用技能时模型输出的参数往往不可靠需要一个明确的约束来做校验。用JSON Schema的好处是它既可以用代码校验也可以用LLM本身来校验而且很多现成的工具链都支持。一个简单的例子{ type: object, properties: { order_id: { type: string, pattern: ^ORD[0-9]{6}$ }, include_items: { type: boolean, default: true } }, required: [order_id] }这段定义明确告诉Agent传order_id是必须的而且格式必须以“ORD”开头并跟上六位数字include_items是可选参数。有了这种约束即使模型输出一个不符合格式的订单号系统也能在进入业务逻辑之前拦截掉而不是让错误一路传到数据库里。2.3 技能的组织命名空间、目录结构与检索当技能数量少的时候怎么组织都没所谓。但一旦超过二十个、五十个你就必须考虑三层问题空间划分、目录归属、检索排序。空间划分指的是权限边界。我见过有的系统把“查询字符串长度”这种通用技能和“发送银行转账指令”这种高权限技能放在同一个平面列表里。这种情况的隐患在于Agent有时候会优先选择描述更详细的那个技能而不是权限匹配的那个技能。正确的做法是把技能按业务域划分命名空间比如billing、user、report然后在命名空间上叠加权限声明。Agent在规划之前先过滤掉当前用户无权访问的技能列表它压根看不到不该看的技能。目录结构方面我建议按“域-子域-具体技能”三级目录组织存放的格式用YAML或JSON都可以。每个技能的文件夹里只放两种文件一个skill.yaml用来声明元数据一个handler.py用来放实现代码。文件系统本身就是技能注册表不需要额外维护一张数据库表前提是你的技能数量还在百级以下。检索排序方面最简单也最有效的策略是“关键词相关性 历史调用频率加权”。技能描述里的关键词命中越多排序越靠前经常被调用的技能排序也适当靠前。你还可以在描述里主动埋一些同义词或触发词比如“查订单”技能的描述里写上“查询、详情、物流、跟踪”这类词提高召回率。2.4 技能的版本管理要不要做、怎么做技能是代码代码就有版本。很多人做Agent时忽略了技能版本管理结果技能上线第二天行为变了但描述还没同步改Agent按照旧描述调用新逻辑产出结果完全不对。我在实际项目中至少做了最低限度的版本管理每个Skill定义里多一个version字段同时保留最近三个版本的实现代码以便快速回滚。如果你用的是Git管理代码库建议在技能文件头部写一个since和deprecated字段标记技能的引入和废弃时间。Agent检索技能时可以增加一个is_active过滤废弃的技能不再出现在可调用列表里但历史对话里已经生成的调用记录仍然可以被解析。版本管理的核心原则是让Agent看到的信息永远和当前环境里的真实行为一致。一旦描述与行为脱节整个技能编排系统的可信度就崩塌了。3. 实操从零实现一个轻量级的Skills系统3.1 整体设计核心模块拆解在动手写代码之前我习惯先画出整个系统的模块边界。一个最小可用的Skills系统至少包含四个模块注册中心负责加载、存储、更新技能定义提供查询接口路由分发根据Agent生成的调用意图匹配到具体的技能实现参数校验器对Agent传入的参数做格式、范围、必填项校验执行器真正运行技能代码捕获异常并汇总执行结果这四个模块之间的依赖关系是Agent调用入口 → 路由分发 → 注册中心查配置 → 参数校验器校验 → 执行器执行。我把执行器设计成不感知具体业务的通用模块技能逻辑全部封装在各自的handler里这样新增一个技能不会导致执行器代码变动。3.2 注册中心与技能加载器的实现注册中心看起来简单实际上有几个坑要注意。第一个坑是技能定义和技能实现的加载路径。如果是Python环境建议用importlib动态导入技能模块而不是在启动时把所有技能代码写死。这样技能的增删改不用重启服务。我贴一段简化版的注册中心实现包含了加载、查询、热更新三个基本能力import importlib import threading from pathlib import Path class SkillRegistry: def __init__(self, skill_dirs: list[str]): self.skill_dirs skill_dirs self._skills {} self._lock threading.RLock() def load_all(self): for skill_dir in self.skill_dirs: for yaml_file in Path(skill_dir).glob(*/skill.yaml): skill_def self._read_yaml(yaml_file) self._register(skill_def) def _register(self, skill_def: dict): skill_id skill_def[skill_id] # 动态导入handler模块 module importlib.import_module(skill_def[handler_module]) handler getattr(module, skill_def[handler_method]) with self._lock: self._skills[skill_id] { definition: skill_def, handler: handler, load_time: time.time(), } def get_skill(self, skill_id: str): with self._lock: return self._skills.get(skill_id) def list_skills(self, tags: list[str] | None None): with self._lock: skills list(self._skills.values()) if tags: skills [s for s in skills if set(tags).intersection(s[definition].get(tags, []))] return skills def reload_skill(self, skill_id: str): with self._lock: skill self._skills.get(skill_id) if not skill: raise KeyError(fskill {skill_id} not found) # 重新导入模块实现热更新 module importlib.reload(importlib.import_module( skill[definition][handler_module])) handler getattr(module, skill[definition][handler_method]) skill[handler] handler skill[load_time] time.time()这里有几个设计细节值得注意RLock的使用技能加载和查询可能同时发生用可重入锁避免同一个线程内重复加锁造成死锁。热更新的实现importlib.reload有一个隐含前提就是技能模块不能持有全局连接状态。如果你的技能代码里有一个模块级的数据库连接reload后旧连接会被替换新调用就不会复用旧连接——这既是优点也是坑。读取skill.yaml时必须做字段合法性检查防止手误写错导致Agent看到的技能描述和实际handler完全对不上。3.3 路由分发与参数校验路由分发最简单的实现方式就是让Agent返回一个结构化的调用请求例如{ intent: check_order_status, arguments: { order_id: ORD123456 } }然后系统根据intent去注册中心查找对应的Skill。这里有一个新手常踩的坑Agent返回的intent往往不稳定可能这次是check_order_status下次就变成order_status_query。我建议不要把Agent输出的意图名直接当作技能ID而是做一层“意图命名到技能ID”的映射。映射关系可以很简单就是让Agent在生成调用请求时必须先从技能的name字段里选一个值而不是自由发挥。如果Agent本身支持工具定义Function Calling模式你可以直接把技能描述和输入Schema转换成功能定义列表让模型在调用接口时自动完成意图匹配。这种情况下技能的description字段质量就变得极其重要。它不应该是一句话而应该是一个简短的“什么时候该用、什么时候不该用、需要注意什么”的说明。举例当用户想要查看订单的物流状态或签收情况时使用。如果用户只是询问订单金额或商品明细不要使用本技能应使用“查询订单详情”。如果用户未提供订单号请先反问用户获取。这段描述里包含了触发条件、排除条件、缺失参数时的处理方式能显著减少Agent误调技能的概率。反观很多糟糕的技能描述只写一句“查询订单状态”Agent在模糊场景下很容易选错。参数校验的代码逻辑也不复杂但要注意区分“缺参数”和“参数格式错误”两种处理方式。缺参数时系统应该把缺哪个参数的信息返回给Agent让Agent继续追问用户参数格式错误时系统应该直接拒绝执行并在错误信息里说明期望的格式。我贴一段基于JS库ajv风格的伪代码逻辑方便你看清校验分支def validate_arguments(schema: dict, provided_args: dict): errors [] for required_field in schema.get(required, []): if required_field not in provided_args: errors.append(f缺少必要参数: {required_field}) for field_name, field_spec in schema.get(properties, {}).items(): if field_name in provided_args: # 这里可以做更细的类型和模式校验 if not isinstance(provided_args[field_name], field_spec.get(type)): errors.append( f参数 {field_name} 类型不正确期望 {field_spec.get(type)} ) return errors实际项目中校验逻辑应该下沉到JSON Schema校验库不要自己写一堆if-else。但核心的思路必须明确校验不通过的参数最好的处理方式是“带回信息给Agent重新规划”而不是“尝试自动修复”。因为你无法保证模型对参数的“猜测性修复”是安全的。3.4 执行器与上下文传递执行器的设计决定了技能代码写起来舒不舒服。我建议执行器采用“上下文对象注入”的模式而不是把所有参数当普通位置参数传过去。原因是技能常常需要访问当前用户ID、会话ID、Trace-ID、调用来源等元信息这些信息不来自Agent的参数而来自Agent框架本身。一个简洁的执行器接口大致是class SkillContext: def __init__(self, user_id, session_id, trace_id, env): self.user_id user_id self.session_id session_id self.trace_id trace_id self.env env async def execute_skill(skill_id: str, args: dict, context: SkillContext): skill_entry registry.get_skill(skill_id) if not skill_entry: raise SkillNotFound(skill_id) # 安全校验技能本身的权限级别和当前用户权限比对 permission skill_entry[definition].get(permission_level, public) if not verify_permission(context.user_id, permission): raise PermissionDenied(skill_id, context.user_id) # 参数校验 errors validate_arguments( skill_entry[definition][input_schema], args ) if errors: raise ArgumentValidationError(errors) # 执行技能记录耗时和结果 start time.time() try: result await asyncio.wait_for( skill_entry[handler](argsargs, contextcontext), timeoutskill_entry[definition].get(timeout, 30) ) return result except asyncio.TimeoutError: raise SkillTimeout(skill_id, args) except Exception as exc: # 记录错误信息但不要把原始堆栈直接返回给Agent logger.error(skill %s failed: %s, skill_id, exc, exc_infoTrue) raise SkillExecutionError(skill_id)几个实操要点执行技能时一定要用asyncio.wait_for加超时。有些外部接口会卡死没有超时Agent会一直等用户会以为系统崩溃了。超时时间要按技能类型区分查数据库的可以设5秒调用外部AI生成文章的可能要设60秒。异常不要把堆栈返回给Agent。Agent无法理解Python Traceback反而会被带偏。返回一个结构化的错误信息只包含“技能ID、失败原因分类、可恢复建议”三个字段就足够了。执行结果建议统一包装一层比如{status: success, data: {...}}。原因是后续需要给调用链加上统一日志、统计指标和审计字段统一包装格式能省不少事。3.5 给Agent的“技能使用说明书”怎么生成有了注册中心和技能定义你还需要把这些信息有效地传给Agent。这一步的实现方式取决于你的Agent框架。如果你使用的是Function Calling类型接口那么每个Skill都要转换成一个Function定义字段映射大致是skill.name→ Function的nameskill.description→ Function的descriptionskill.input_schema→ Function的parameters如果你使用的是“把技能列表放在系统提示词里”的方案就要注意长度限制。技能数量多的时候不能把所有技能完整描述全放进提示词而应该先让Agent做一轮“技能预筛选”。具体做法是第一轮先给Agent提供“技能目录”——只包含技能名称、一句话摘要、标签Agent根据用户问题选出可能相关的3到5个候选技能第二轮再提供这3到5个技能的完整定义和Schema让Agent生成调用参数。这种方式能大幅降低提示词长度也减少无关技能对Agent规划的干扰。我见过有些团队想省钱省事无论用户问什么都把全量技能塞给Agent结果技能一多Agent经常选错。实际上做一轮粗筛并不复杂成本也不高却能显著提升调用准确性。4. 常见问题与排查技巧实录4.1 技能没有被命中Agent选错技能症状是用户问了一个明确的问题应该调用技能A但Agent压根没调用任何技能直接自己编了一个答案。排查步骤我习惯这么走查一下Agent可见的技能列表里有没有这个技能。如果没有说明技能的检索或过滤条件太严格把它过滤掉了。重点检查权限级别和is_active标记。查一下技能描述里的关键词覆盖。用户的原话是“我的快递到哪了”你的技能描述里却只写了“查询订单状态”没有“快递”“物流”“签收”这类词。这时需要扩充技能描述里的触发词。查一下是不是有多个技能描述高度相似导致Agent分不清。如果有就加强每个技能的“排除条件”描述明确说“该技能不负责XX场景”。在排查过程中一定要看Agent的完整推理过程日志而不是只看最终调用结果。很多框架支持开启思维链输出即便线上关掉调试模式也建议开着。4.2 技能互斥与冲突两个技能同时命中技能冲突通常发生在两个描述高度重叠的技能之间。举个例子技能A“获取订单详情”技能B“获取订单物流信息”。用户问“我的订单到哪了”理论上应该调用B但如果A的描述里写了“可以获取订单的物流跟踪信息”Agent可能就去调A了。解决办法有两个层面。第一层是描述层面技能A的说明里明确加一句“物流状态查询请调用技能B”第二层是路由层面在路由分发逻辑里增加一个“优先级”字段当两个技能都能匹配用户请求时优先选择优先级高的。我建议把第二层作为兜底手段第一层的思考过程虽然简单但效果往往更好。4.3 参数校验失败但Agent不重新提问这是我在实际运营中最头疼的问题之一。Agent调用技能时缺了参数系统返回错误信息“缺少参数user_name”但Agent不依不饶地再次调用同样的技能、传同样的参数陷入死循环。排查后发现大多数情况下是错误信息的措辞不够明确。Agent读了错误提示以后并不知道“接下来该做什么”。所以我在错误信息里加了明确的“建议动作”字段比如缺少参数 user_name。建议向用户询问“请提供您的用户名”在获得有效参数后重新调用“查询用户积分”技能。加了这一步之后Agent重新提问的概率显著提升。这个细节很值得提出来因为直接影响用户体验。另一种情况是Agent的参数生成逻辑有误传了一个空字符串而不是缺失字段。这种情况下参数校验要区分“字段不存在”和“字段存在但值为空”把后者也当作缺失参数来处理。4.4 技能执行超时与重试策略超时是最典型的技能执行故障。我的经验是超时不要立刻重试先看错误日志。如果超时原因是外部服务响应慢重试一两分钟之后可能有效如果是死循环或死锁重试多少次都一样。所以我给技能设计了重试开关写在Skill定义里retry: enabled: true max_attempts: 2 backoff_seconds: 1这种配置的好处是让单个技能的拥有者自己决定重试策略而不是全局统一。某些只读查询技能可以适当重试但执行写操作或发送消息的技能绝对要禁止重试否则用户可能收到两条重复的通知。4.5 技能更新与线上行为不一致技能上线之后如果出现“Agent明明调用了技能但效果和预期不符”的情况大概率是技能描述与代码行为不同步。比如代码改了返回值结构但skill.yaml里的描述还写的是旧结构Agent根据描述规划后续步骤就会出现偏差。一个很实用的防范手段是技能更新流程中增加一个“描述一致性检查”。每次handler代码变更都必须同时更新对应的skill.yaml描述检查由CI流水线自动执行。具体做法可以写一个简单的脚本对比代码里的返回值字段和描述里声明的输出字段不一致就阻断发布。这样虽然不是百分之百可靠但能拦截一大类低级错误。5. 实战中的取舍心得5.1 什么时候该用Skills系统什么时候不该用Skills系统给Agent带来了更强的模块化和可维护性但它本身也是有成本的。如果你的Agent只需要调用两三个接口技能系统反而是多余的直接用Function Calling就好。我的判断标准很简单可调用的工具或能力超过十个或者这些能力属于不同业务域或者你需要在不同场景下给不同用户开放不同能力——满足任何一条就可以考虑引入Skills系统。如果以上条件都不满足老老实实把工具定义写在Agent配置里反而更简单高效。另外如果你的业务变化极快技能定义和调用逻辑隔三差五就要大改那么技能系统初期建设和运维成本可能会拖慢你的节奏。这个阶段适合先把技能数量控制在五个以内重点关注描述质量和调用准确性而不是急着做平台化的技能管理后台。5.2 文本技能与代码技能的边界很多人忽略了“技能”这个概念的宽度。它既可以是执行代码的工具型技能也可以是一个纯文本的“提示词技能”。比如skill_id: summarize_report name: 生成团队日报摘要 description: 根据输入的日报Markdown内容生成一段150字以内的摘要 handler_module: text_prompt_skills.summarize handler_method: run input_schema: type: object properties: report_content: { type: string } required: [report_content]这种纯文本技能的实现体内其实只是调用了一层“把Prompt模板和用户输入拼接、然后交给LLM生成”的逻辑。它的好处是你可以把一类固定的提示词场景单独管理复用性更强也方便后续替换不同的底层模型。实操中发现将通用Prompt模板做成技能能让团队里非工程角色也参与技能维护——他们只需要编辑YAML文件和Prompt模板不需要碰复杂的业务代码。这对团队协作是一个不小的便利。5.3 监控与指标看不见数字就谈不上优化Skills系统上线之后建议尽早建立几个核心监控指标技能调用成功率按技能ID聚合哪个技能容易失败一目了然技能调用平均耗时超时技能需要优化这一点不用多说技能命中率Agent调用技能成功且返回有用结果的比例如果低说明描述质量差需要迭代Agent单次会话平均调用技能次数太高可能说明规划复杂或技能粒度过细我一般会在执行器里埋一个结构化的指标格式大体是skill_call_total{skill_id, status, duration_ms}后续随便接一个时序数据库或监控面板就能把整个体系的健康状况看得清清楚楚。没有数据支持任何对技能描述、路由策略的调整都只是凭感觉。5.4 一个容易被忽视的细节技能的“可解释性”最后想分享一个很多资料不会提的点。Agent调用技能后用户经常想知道为什么Agent做了某个操作。比如Agent自动调用了“根据历史记录修改用户标签”的技能用户可能完全没有意识到发生了什么。因此每个Skill在执行以后应该返回一段人类可读的“执行摘要”展示在Agent的回复里。这个摘要可以由技能代码自己生成比如“已查询订单ORD123456的物流状态当前运输中预计明天送达”也可以由Agent根据技能结果总结。无论哪种方式一定要让用户明白系统做了什么决策、依据是什么。这在很多合规要求严格的环境里尤其重要哪怕没有明文要求从用户体验角度也值得做。我见过一个非常好的实践执行器会自动记录“调用技能链”的完整日志并且在用户界面里提供“查看步骤详情”的入口用户展开后可以看到Agent经历了哪几个技能、每个技能的输入输出是什么。这一步彻底解决了“AI黑箱”的信任问题也让排查异常时不再需要从后台翻原始日志。如果你正在规划自己的Agent技能体系建议把“可解释性”放到和“可用性”同等的优先级去考虑。毕竟技能系统的本质是让Agent变得更可靠、更容易被理解和掌控而不是制造一个更难揣测的黑盒子。
阅读完成 · 觉得有帮助?
咨询建站