ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Agent技能体系实战:从工具堆砌到可复用技能抽象,让Agent真正干活

Agent技能体系实战:从工具堆砌到可复用技能抽象,让Agent真正干活 去年下半年我接手了一个内部项目核心诉求很简单让Agent别再当一次性对话玩具而是能真正连续处理真实业务。最开始我的做法跟大家一样把所有工具函数塞进system prompt写了一大段你是全能助手的咒语再把十几个API接口直接暴露给模型。结果用起来很糟——模型经常把参数传错一个无意中的工具调用把上下文搞得乌烟瘴气而且每当要加一个新能力整个prompt就要重写一遍。后来我才意识到问题不是模型不够聪明而是缺少了一层技能抽象。所谓agent-skills就是把这层抽象落地成一套可注册、可发现、可复用、可校验的模块化技能体系。今天这篇内容我不打算讲什么高深理论就围绕我自己从零搭建Agent技能体系的全过程把目录怎么设计、技能怎么注册、运行时会踩哪些坑一条条说清楚。适合正在做Agent应用工程、或者想把手头的一堆API封装成Agent能力但又不知道从哪下手的开发者参考。1. Agent Skills到底是什么——先搞清楚它解决了一个什么问题在动手写代码之前我花了很久去纠结一个听起来很虚的问题技能和工具到底有什么区别如果只是把一个个函数挂给模型调用那跟之前的Function Calling有什么区别想清楚了这个问题后面所有设计都有了解释。1.1 从工具堆砌到技能抽象最早的做法是把所有工具直接挂在模型可调用的函数列表里。比如我写了十几个函数get_weather、create_ticket、search_docs、send_email、calc_commission……然后把它们的JSON Schema全部塞给模型。表面上看这没什么问题但真实跑起来会碰到三个很难受的情况。第一是模型会挑肥拣瘦。函数描述写得太短模型就搞不清楚这个函数在什么业务场景下用描述写得详细了prompt长度又爆炸尤其是每个函数还带参数说明一起并发调用时模型经常晕头转向。第二是函数之间完全没有层级关系。有些操作其实是组合技能比如生成一份周报这个动作实际需要先拉取数据、再调用模板、最后发送到指定频道。如果只暴露三个底层函数给模型模型需要自己搞清楚调用顺序但模型往往不擅长这种东西。第三是错误处理严重缺失。函数调用一旦报错模型根本不知道该做什么回退策略。没有一套技能层面的容错机制Agent就跑不出稳定效果。技能这层抽象恰恰解决的是从这个动作怎么做到这个任务怎么达成的跳跃。一个技能可以是一个底层工具也可以是多个工具按固定顺序编排出来的流程还可以是带状态、带校验逻辑、带后置处理的完整能力单元。我当时给自己定了一个判断标准凡是我知道下一步该做什么的逻辑就封装进技能里别让模型去推理凡是模型需要根据用户意图灵活决定的才开放给模型决策。技能是确定性逻辑的容器模型只负责选容器和传参数。1.2 技能、工具、插件三者到底怎么划边界很多人在聊Agent架构时会把工具Tool“技能Skill”“插件Plugin”混在一起说。我自己的工程划分是这样的概念我的定义举例工具原子操作不做业务决策调用一次天气API、执行一条SQL、发一封邮件技能一个完整的业务能力单元可编排底层工具包含自己的输入校验与错误处理自动生成销售周报、客户信息聚合查询、定时任务调度插件技能的集合常以独立包形式分发带依赖与权限清单一套CRM助手插件内含销售分析、客户查询、跟进提醒三个技能这个划分不一定是标准答案但它让我在设计agent-skills时有了明确的边界感工具层面我不做业务逻辑技能层面不写底层实现细节插件只负责打包和权限声明。在这个模型下Agent的核心工作变成了输入理解—技能选择—参数组装—结果加工所有脏活累活都被技能收编了。1.3 一个合格的技能包应该长什么样我后来把每个技能设计成一个自包含的文件夹包含以下四类文件技能主程序核心执行逻辑可能是一个Python模块里面可以有若干内部函数只暴露一个统一入口函数给运行时调用。描述清单用结构化的YAML或JSON记录技能的名称、用途、适用场景、参数定义、输出说明。这是决定模型能否正确选它的关键。依赖声明该技能需要的Python依赖包、内部工具API、外部网络权限、密钥权限等。验证用例一组输入输出样例注册技能或每次升级后跑一遍确认技能行为没有漂移。我见过很多团队做Agent技能只写一个函数加一段docstring就完事。短期看没问题等技能数量超过二十个你就会发现模型选错技能的频率急剧上升技能之间参数风格不一致升级一个技能还会连累另外三个。技能包的自包含和规范化越早做越省钱。2. 技能目录与契约设计把模型能看懂当作第一优先级确定要构建agent-skills后我做的第一件事不是写代码而是设计技能目录结构和契约规范。因为技能这套东西最终使用者一半是人类开发者、一半是大模型契约设计必须两头讨好既要让编译器检查时不崩溃又要让模型一眼就看明白这个技能是干嘛的、什么时候用我。2.1 目录结构普通文件夹就够了别把架构搞复杂我项目的技能目录长这样agent-skills/ ├── registry.json ├── skills/ │ ├── weather_query/ │ │ ├── SKILL.md │ │ ├── skill.json │ │ ├── main.py │ │ └── test_cases.json │ ├── report_generator/ │ │ ├── SKILL.md │ │ ├── skill.json │ │ ├── main.py │ │ └── requirements.txt │ └── calendar_scheduler/ │ ├── SKILL.md │ ├── skill.json │ ├── main.py │ └── test_cases.json └── runner/ ├── loader.py ├── validator.py └── executor.py这里没有引入什么奇特的框架就是最朴素的文件夹结构。SKILL.md是给人看的详细说明skill.json是给模型和运行时看的机器可读契约main.py是执行入口test_cases.json是回归测试用例。registry.json是全局技能注册表运行时启动时会扫描加载。之所以用文件夹加约定而不是上来就上数据库、上服务发现是因为技能的第一批用户是开发者自己。保持改文件夹、改文件的低门槛可以让技能的数量快速长起来等规模大到需要分布式调度时再做抽象也不迟。2.2 技能描述清单这里写的每一个字模型都会认真读skill.json是整个技能体系里最不能糊弄的文件。模型不会阅读你的源码注释它只能看到你在描述清单里提供的信息。我经过很多轮调优后沉淀出以下字段结构{ name: report_generator, version: 1.3.0, display_name: 销售周报自动生成, description: 根据销售数据自动生成结构化周报支持多团队对比、环比分析、异常标注。当用户需要查看周度销售情况、生成汇报文档、或分析销售趋势时使用本技能。如果用户只需要单个数字如总销售额请优先使用sales_query技能。, tags: [sales, report, weekly], input_schema: { type: object, properties: { team_ids: { type: array, items: {type: string}, description: 需要生成周报的团队ID列表不传则默认所有团队 }, week_offset: { type: integer, description: 相对当前周的前N周0表示本周默认0 }, format: { type: string, enum: [markdown, html, pdf], description: 输出格式默认markdown } }, required: [week_offset] }, output_schema: { type: object, properties: { report_content: {type: string}, generated_at: {type: string}, summary_stats: {type: object} } }, permissions: [sales_data:read, file:write], timeout_seconds: 30 }这里有几个我认为很关键的设计心得description字段里一定要写正面触发场景和反面排除场景。比如我在description里加了如果用户只需要单个数字请优先使用sales_query技能这句话能显著降低模型用错技能的概率。大模型的函数选择机制对描述里的排除性语言非常敏感。input_schema必须用JSON Schema而且每个字段都要写description。模型在解析参数时字段描述直接决定它传参的准确率。我对比过带字段描述的参数错误率比不带描述低一半以上。别在skill.json里写长篇大论。模型处理长文本时注意力容易被稀释。我的经验是description控制在150字到200字参数描述控制在30字以内反而是最优区间。2.3 统一入口规范让运行时只需要面对一种调用姿势技能主程序main.py需要遵循一个简单的统一入口规范。我采用的方式是每个技能暴露一个run(payload: dict, context: dict) - dict函数# main.py from typing import Any def run(payload: dict, context: dict) - dict: team_ids payload.get(team_ids, []) week_offset payload.get(week_offset, 0) output_format payload.get(format, markdown) # ... 技能内部逻辑 return { report_content: ..., generated_at: 2025-01-05T10:00:00Z, summary_stats: {} }payload是模型按schema传入的参数context是运行时注入的全局上下文用户ID、租户信息、日志追踪ID、已授权的凭证等。统一入口带来的直接好处是加载器、执行器、监控逻辑全部可以做成通用组件每个技能的开发者只需要关注给我参数我干活返回结果不需要理解Runner内部的细节。这看起来微不足道但一旦团队里有四五个人同时在贡献技能统一接口带来的约束价值就会指数级上升。我见过有人把技能函数定义为async def有人用def有人喜欢返回字符串有人喜欢返回复杂对象——统一入口之后这些全都被规范掉了绕开了最典型的协作泥潭。3. 技能注册与路由决策让Agent在合适的时机选中合适的技能技能文件写好了下一步就是让Agent知道什么情况下该调什么。这是整个agent-skills里最影响实际效果的部分。我一开始也天真地以为只要把技能描述丢给模型它自然就会选对。真实跑起来才发现技能多了之后选择逻辑必须分两层处理先粗筛再精挑。3.1 技能注册启动时全量加载还是动态发现我的Runner实现里有一个加载器启动时扫描skills/目录逐个读取skill.json校验必填字段和格式然后注册进内存中的技能表。加载完打印一行日志[skill-loader] registered skill: report_generator (v1.3.0) in 12ms。这种全量加载模式目前完全够用几十个技能的加载时间也就几百毫秒根本不需要搞动态热加载。但注册时有个细节容易被忽略技能依赖校验。比如某个技能声明需要httpx库但当前Python环境里没装那加载器应该在启动时就报错而不是等到Agent运行到一半才抛ModuleNotFoundError。我在validator.py里做了这个检查启动即失败而不是运行时爆炸这在生产环境里能省下无数排查时间。3.2 意图匹配先粗筛再让模型精挑我最初的做法是把几十个技能的描述全部拼成一个大字符串塞给模型让它自己挑。当技能数少于10个时效果不错超过20个后模型的选择准确率明显下降甚至会出现因为描述太相似而选错的情况。后来我把路由改成了两层第一层基于关键词和标签的粗筛。我先用轻量匹配包括关键词命中、用户消息中的实体识别、历史对话的上下文主题把所有技能筛一遍保留可能相关的3到5个候选。比如用户说帮我生成上周的销售数据周报粗筛层会命中report_generator和sales_query两个候选。第二层模型在候选技能中做精挑。我只把候选技能的描述和参数Schema发给模型做function calling选择。由于候选数量只有个位数模型的决策准确率能稳定维持在高位。这层设计的收益非常明显。它本质上是把几十选一的高难度决策拆解为先按规则缩小范围、再让模型做最终选择的两段式方案。模型不擅长从超大候选集里做精确选择但很擅长在几个相近选项中挑出最合适的一个。这个分工和人类做事的逻辑是一样的——先靠经验和索引缩小包围圈再细看具体条款做决定。3.3 技能冲突消解当两个技能看起来都很像时怎么办技能多了之后一定会出现功能重叠。例如我曾经同时有get_sales_data获取销售明细和generate_sales_report生成销售报告两个技能模型经常在用户说看看这个月销售情况时不知所措。我在sales_report的描述里加了一句如果需要原始数据明细而非总结报告请使用get_sales_data并在get_sales_data的描述里写了本技能只返回原始数据不做汇总分析用户需要解读数据时请调用generate_sales_report。通过双向互斥描述两个技能的边界一下就清晰了。除了描述上的互斥还可以在路由层配置显式规则。我在registry.json里增加了一个priority_conditions字段可以给某些技能设置触发优先级。比如当检测到周报“月报”“定期汇总”等词时直接优先选report_generator不再需要模型二次判断。这就是把明确规则前置到路由层的做法——凡是能枚举的业务规则就不要依赖模型临场发挥。4. 从零实现一个带四大技能的Agent完整跑通一个业务案例理论说了不少下面进入实操环节。我拿自己当时搭建的一个最小可用版本作为例子完整演示从加载技能到Agent自主编排的过程。这个案例里我设计了四个技能天气查询、销售数据查询、周报生成、日程安排。看起来很简单但它把agent-skills的完整链路都覆盖了。4.1 系统架构一个极简但可扩展的Runner我用的技术栈是Python 3.11 OpenAI Function Calling接口没有上LangChain或LlamaIndex这类框架。原因是这类框架在技能路由方面抽象层往往太重不太方便自定义。Runner本身只有三个模块loader.py扫描技能目录、解析skill.json、做依赖校验、加载main.py。executor.py接收模型选中的技能名和参数找到技能入口函数注入上下文执行统一处理超时与异常。router.py粗筛逻辑 组装候选技能列表传给模型做function calling。代码核心大致如下注意我刻意把框架依赖降到最低# executor.py import importlib.util import json from pathlib import Path class SkillExecutor: def __init__(self, skills_dir: str skills): self.skills_dir Path(skills_dir) self.skill_map {} self._load_skills() def _load_skills(self): for skill_dir in self.skills_dir.iterdir(): manifest_path skill_dir / skill.json main_path skill_dir / main.py if not manifest_path.exists() or not main_path.exists(): continue manifest json.loads(manifest_path.read_text(encodingutf-8)) spec importlib.util.spec_from_file_location( fskill_{manifest[name]}, main_path ) module importlib.util.module_from_spec(spec) spec.loader.exec_module(module) self.skill_map[manifest[name]] { manifest: manifest, run: module.run, } def execute(self, skill_name: str, payload: dict, context: dict, timeout: int 30): skill self.skill_map.get(skill_name) if not skill: raise KeyError(fskill not found: {skill_name}) return skill[run](payload, context)_load_skills里的动态加载用的是importlib不是__import__原因是我希望每个技能模块的加载路径是独立的避免同名模块冲突。这里动态加载的代价是每次技能升级后需要重启Runner但对我们这种技能数量不大、变更频率不高的场景完全够用。4.2 四大技能的代码与契约示例第一个是weather_query。这个技能负责调用外部天气API它展示的是一个标准的API型技能写法# skills/weather_query/main.py import os import httpx def run(payload: dict, context: dict) - dict: city payload[city] api_key context[credentials][weather_api_key] resp httpx.get( https://api.example.com/v1/weather, params{city: city, key: api_key}, timeout10, ) resp.raise_for_status() data resp.json() return { city: city, temperature: data[current][temp_c], condition: data[current][condition][text], humidity: data[current][humidity], }第二个是sales_query这个技能展示的是数据库型技能。它在内部执行一条参数化SQL返回聚合数据但对外只暴露team_id和date_range两个参数不让模型直接编写SQL这也算一条安全边界# skills/sales_query/main.py import sqlite3 def run(payload: dict, context: dict) - dict: team_id payload.get(team_id) date_range payload.get(date_range, ()) conn sqlite3.connect(context[config][db_path]) if not date_range: query SELECT SUM(amount) FROM sales WHERE team_id ? total conn.execute(query, (team_id,)).fetchone()[0] return {total_amount: total} # ... 按日期区间查询第三个是report_generator这是一个组合型技能。它内部会调用sales_query技能来获取数据再调用内部模板渲染函数生成Markdown。这就体现出技能内部调度的意义——模型只需要告诉它要周报不需要关心数据怎么查# skills/report_generator/main.py from skills.sales_query import run as sales_query_run def run(payload: dict, context: dict) - dict: week_offset payload.get(week_offset, 0) # 内部直接调用另一个技能的run方法 sales_data sales_query_run( {team_id: payload.get(team_id), date_range: _calc_week_range(week_offset)}, context, ) report _render_markdown_report(sales_data) return {report_content: report, summary_stats: sales_data}这里有一个设计点report_generator内部调用sales_query是直接用Python import方式而不是让模型再调一次sales_query技能。原因很简单内部调用是流程的确定性部分不应该让模型有机会干扰或中断。技能之间的确定性编排永远走代码不确定性选择才交给模型这是我非常认定的原则实践效果也验证了这条原则的可靠性。第四个是calendar_scheduler。这个技能负责创建日程它有一个特殊点需要控制不可逆操作的确认机制。具体来说如果用户说明天上午开个会Agent应该先调用scheduler.preview生成一个日程预览然后询问用户确认确认后再真正写入日历。我在技能内部将其分为preview和commit两个路径由技能代码强制判断# skills/calendar_scheduler/main.py def run(payload: dict, context: dict) - dict: action payload.get(action, preview) event { title: payload[title], start_time: payload[start_time], end_time: payload[end_time], attendees: payload.get(attendees, []), } if action preview: return {preview: event, require_confirm: True} if action commit: # 真正写入日历服务 created _create_calendar_event(event) return {created: created, confirmed: True} raise ValueError(funknown action: {action})这个先预览、后确认的机制非常值得无脑抄。因为Agent一旦对接了写操作发邮件、下单、删除数据如果没有确认闸门模型的一个幻觉就能造成真实损失。后来我发现凡是涉及外部副作用、且不可逆的技能都应该走这种两段式确认初级技能的开发者默认开启不要给关闭选项。4.3 完整执行链路一次对话背后的调用过程以用户输入帮我查一下本周北京的天气顺便生成一份销售周报为例真实执行链路大概是这样的Runner把用户消息交给粗筛器关键词天气命中weather_query关键词周报命中report_generator同时销售命中sales_query。Router把这三个技能的描述与Schema发给模型模型选择同时调用weather_query和report_generator并行使能。Executor并行执行两个技能。weather_query直接返回天气数据report_generator内部又自动调度sales_query来取数。结果统一收集后Runner将结构化结果透传给模型让模型用自然语言组织回复。模型综合两个结果生成最终回答北京今天多云气温24度。销售周报已生成本周总销售额为35.6万元环比增长了12%。这五个步骤看起来简单真正跑通之后我才意识到技能体系的价值在于让Agent从一个什么都能说的聊天对象变成了一个什么都能做的执行终端每个环节都有清晰的确定性抓手出错了也知道去哪里排查。5. 运行时避坑清单这些坑我踩过你大概率也会踩技能体系搭好、能跑通demo之后距离生产可用还有一段路。我在压测和真实使用中踩了不少坑整理成下面的清单每一类都是真实代价换来的经验。5.1 超时控制技能不是无限等你的第一个坑是健忘。早期我的技能代码里没有显式超时结果有次天气API上游服务挂了整个Agent线程卡在那里用户等了两分钟没响应其他任务也被阻塞。后来我在Executor里给所有技能执行包了一层超时控制使用concurrent.futures中的ThreadPoolExecutorfrom concurrent.futures import ThreadPoolExecutor, TimeoutError def execute_with_timeout(func, timeout_seconds15): with ThreadPoolExecutor(max_workers1) as pool: future pool.submit(func) try: return future.result(timeouttimeout_seconds) except TimeoutError: future.cancel() raise RuntimeError(fskill execution timed out after {timeout_seconds}s)这个设计配合每个技能skill.json里的timeout_seconds字段可以实现不同技能不同超时策略——查询类技能给10秒报告生成类给30秒涉及外部API调用的可以给20秒。需要注意的是超时只是兜底真正靠谱的方式还是在技能内部把HTTP连接池、读超时都设好两者配合才能避免线程被卡死。5.2 上下文污染输出太大怎么防第二个坑是技能返回结果过大。有一个技能把完整的销售明细几千行JSON塞回了返回体模型不得不在一次上下文中消耗大量tokens来理解这些数据。更糟糕的是这个巨型结果还会残留在多轮对话历史中后续每次请求都会携带它token消耗成倍增长。我的解决办法是引入结果摘要化。技能返回值分为main_result给模型做决策的精简数据和raw_result完整数据可选存储到临时文件或对象存储。模型只需要拿到摘要部分比如总数、平均值、Top N、异常标记足够组织回答即可。如果用户确实需要明细数据再触发另一个导出明细技能把完整数据输出为文件。记住一个原则Agent的技能返回体不是给模型看越全越好而是恰到好处。给模型喂超量数据不单是浪费token还会稀释模型对关键信息的注意力。5.3 权限边界每个技能都要有显式的权限声明第三个坑是权限过于宽松。早期我把所有技能的调用凭证都放在同一个全局上下文里report_generator里甚至可以通过context[credentials][admin_token]去删库。一旦技能代码有漏洞或者模型被prompt注入诱导就可能导致越权操作。我在skill.json里增加了permissions字段声明技能需要的最小权限范围并在Executor执行前做鉴权required set(skill[manifest].get(permissions, [])) granted set(context.get(granted_permissions, [])) if not required.issubset(granted): raise PermissionError(fskill {skill_name} missing permissions: {required - granted})这个设计虽然不能解决所有安全问题但能规避一个技能跑起来什么都能干的最危险局面。每个技能只拿最少的权限按需申请这样就有效减少了被利用的爆炸半径。5.4 技能版本演变改一个技能别炸一片Agent最后一个坑是技能升级的兼容性问题。以前我更新技能时直接改main.py结果某一次sales_query的返回字段从amount改成了sales_amount下游三个用到它的技能全部失效。痛定思痛之后我定了两条规矩技能返回结构不兼容的变更是大版本升级必须新增一个技能版本目录保留旧版本技能做平滑迁移。每个技能注册时带上version字段技能之间的依赖关系精准到版本范围类似sales_query: 1.0,2.0。这个版本管理不需要引入什么重型工具只要在技能目录里保留v1/、v2/子目录外加Runner加载时读取依赖约束做检查就够了。等到技能数量上了百再考虑弄个私有仓库做分发。6. 技能质量评估怎么知道你的技能体系到底好不好用代码跑通只是第一步一个技能体系好不好用不能靠感觉好像行。我在运行了一段时间后建立了一套轻量的质量评估机制。6.1 四个关键指标选择准确率、参数错误率、执行成功率、修复成本我盯住的指标只有四个指标定义健康阈值技能选择准确率模型在N个候选技能中选对了正确技能的比例大于92%参数错误率技能执行时因参数缺失、格式错误导致首次调用失败的次数占比小于5%执行成功率技能从开始执行到成功返回结果未抛异常且结果通过校验的占比大于98%修复成本单个技能线上故障从发现到修复的平均时长目标小于30分钟选择准确率和参数错误率这两个指标直接反映技能契约写得好不好。如果选择准确率低多数情况下是技能之间的描述有重叠需要在description里增加互斥说明如果参数错误率高多半是input_schema的字段描述不够清晰或者缺少必要的枚举约束。6.2 回归测试每次改完技能必须跑一遍我在每个技能目录下维护了一个test_cases.json文件里面保存了多组输入输出样例供Validator做回归测试。例如sales_query的测试样例是[ { input: {team_id: team_a, date_range: [2025-01-01, 2025-01-07]}, expected: {total_amount: 123456} }, { input: {team_id: team_b}, expected: {total_amount: 654321} } ]每次技能代码有变更Runner启动时就会自动跑一遍该技能目录下的测试用例跟expected做对比不一致就直接报错。这套机制看起来土但拯救过我好几次——尤其是改公共依赖的时候经常有技能会悄悄回归异常回归测试能第一时间兜住。6.3 行为漂移监测把Agent的每次调用记录下来除了技术指标之外我还养成了一个习惯把Agent每次的调用日志选了哪个技能、传了什么参数、返回结果摘要、模型最终回复完整记录下来定期人工复盘。日志分析常常能发现一些自动指标发现不了的问题。比如我通过日志发现模型在用户说我这周卖的怎么样时偶尔会先调report_generator而不是sales_query但用户其实只想要一个数字。虽然模型最后也能答对但走偏了一步响应时间和token消耗都会增加。这类行为漂移只能靠日志复盘发现纯靠指标很难暴露。7. 后续扩展技能体系跑起来之后还能往哪些方向长最后聊一下扩展方向因为技能体系一开始会很简陋但它的扩展性决定了这个架构能不能陪你走远。7.1 跨会话技能记忆一个我很想强化但还没完全做好的方向是技能记忆。目前的技能是无状态的每次调用都从零开始。但很多业务场景其实需要技能记住上一次的结果。比如跟上周比怎么样这个上周需要技能在内部解析当前时间并自动推算或者从对话上下文中提取。我目前的做法是把多轮对话的关键参数放入context传入技能让技能利用上下文做参考。7.2 技能的组合编排与自动发现另一个方向是技能的组合编排。目前的技能编排写在代码里比如report_generator内部import了sales_query。这种硬编码可靠但不够灵活。我在考虑是否引入一个轻量的编排描述文件用类似skills/report_generator/pipeline.yaml的配置来声明执行流程这样非工程师也能编排技能。不过这块对可靠性的要求很高一旦引入配置化编排就需要考虑分支、循环、失败重试等复杂度我还在权衡投入产出比。7.3 不止是给Agent用还可以给自动化场景用最后分享一个意外的收获。agent-skills最初是给对话式Agent设计的但后来发现有好多非对话的场景也能复用这套体系。比如定时任务、消息队列消费者、甚至一些内部监控报警的自动处置流程本质上都是根据输入触发一个技能、执行、返回结果。我把技能体系抽成了独立的库之后多个系统可以共用同一套技能实现Agent只是其中一个调用方。这种技能一次封装、多处复用的价值比最初设想的要大得多。我在实际使用中最大的体会是技能体系的核心资产不是你写的那些调用代码而是那份结构化的技能契约库。它把业务能力沉淀成了机器和人都能读懂的标准格式让Agent应用从每次都在写一次性代码变成了持续积累可复用能力。现在每次新接一个业务需求我的第一反应不是直接写工具函数而是先想清楚这个能力该不该封装成一个新技能、放在哪个目录、契约怎么写、权限怎么声明。这种思维转变才是agent-skills真正带给我最大的收获。
返回列表