我一个人闷头写了三周的Agent应用最后卡死的不是模型能力而是自己写的工具调用代码越来越像一坨意大利面。后来我把所有可复用的能力全部改造成独立技能包用一套统一的描述文件和入口脚本管理起来整个项目瞬间清爽了。这个思路就是 agent-skills 的核心把智能体能干的每一件事拆成一个一个可以单独维护、单独测试、单独替换的“技能单元”。这篇文章就围绕 agent-skills 的设计思路、技能包结构、调用机制和排查经验展开适合正在做 Agent 应用、被 Function Calling 和 Tool Use 折磨过的开发者参考。1. 整体设计与思路拆解1.1 为什么需要技能包而不是一堆函数大多数从零开始写 Agent 的人第一步都是把工具函数直接塞进一个 tools.py 文件里然后在调用大模型时把函数列表一股脑传进去。这个做法在工具数量少于五个的时候完全没问题但一旦工具数量超过十个甚至开始涉及多智能体协作、不同项目复用同一套能力的时候问题就来了。首先是上下文爆炸。每个函数的描述、参数说明都要转成 JSON Schema 传给模型OpenAI 等平台的接口对这个列表的长度非常敏感。实测下来二十个工具的 schema 文本量轻松超过三千 token而这些 token 是每个请求都要重复消耗的。其次是维护噩梦。改一个工具的入参定义你得在 tools.py 里翻半天还要担心其他函数是否引用了旧字段。更麻烦的是测试工具函数散落在业务代码里想单独跑一个工具的测试得先拉起整套服务。agent-skills 的思路是把“工具”这个概念升级成“技能包”每个技能包自带元信息描述、参数定义、入口脚本和依赖声明整个技能库就像一个插件目录Agent 运行时动态扫描目录、按需加载。这样每个技能就是一个小型独立应用可以单独开发、单独测试、单独部署。1.2 从硬编码到声明式技能注册硬编码工具列表的最大问题是工具的选择逻辑散落在业务代码里大模型只能被动接受你给它的函数列表。而 agent-skills 采用声明式注册技能包通过一份统一格式的配置文件声明自己“能干什么、需要什么参数、怎么被调用”运行时由统一的调度器读取这些配置注册成模型可识别的工具定义。这个设计带来的直接好处是新增一个技能不需要改任何业务代码只要往技能目录里放一个新的技能包。我曾经接过一个需求要在三天内给 Agent 增加“汇率查询”能力。传统写法是改 tools.py、改 schema、改调用逻辑用技能包方式我只需要写一个技能包目录里面放一个 config.yaml 和一个不到五十行的查询脚本重启服务后 Agent 自动就具备了这项能力。这个体验和插 U 盘差不多插上就能用。声明式注册的第二个好处是可控性。技能包可以在配置里声明自己的执行模式本地命令、HTTP 调用、Python 函数等调度器可以根据 Agent 的类型和安全策略决定哪些技能包对有权限的请求开放。这为多租户场景提供了基础同一个技能库给不同 Agent 暴露不同技能子集只需要在调度器上做一次过滤不用在代码层写死。1.3 技能包的核心分层描述层与执行层这是我踩了很多坑之后总结出来的关键设计技能包必须把“告诉模型怎么用”和“实际去执行”这两件事彻底分开。描述层就是模型的“使用说明书”它决定了模型在什么情况下会选择这个技能、怎么填参数。执行层则是真正干活的代码它接收描述层传来的参数完成具体任务返回结果。把这两层分开之后你可以花大量时间去打磨描述层的文本质量而不影响执行层的稳定性你也可以在完全不动执行代码的前提下针对不同模型比如弱模型和强模型调整描述措辞。举一个实际例子。我的技能库里有一个“网页正文提取”技能执行层就是简单的 requests 加 BeautifulSoup。但描述层我反复改了一个星期一开始写“输入 URL输出网页正文”结果模型经常在只需要取标题的时候也调用它浪费大量 token。后来改成“当用户需要阅读、总结、分析某个网页链接的具体内容时使用输入为完整 URL输出为清洗后的纯文本正文不包含导航、广告等噪声信息”调用准确率立刻就上来了。模型不是靠函数名理解工具的它靠的是你写的 description。2. 技能包目录结构与元信息设计2.1 一个标准技能包的目录长什么样我目前用的技能包结构是在参考了几个主流开源实现后调整出来的兼顾了简洁和可扩展性。一个标准技能包长这样skills/ ├── web_fetch/ │ ├── config.yaml │ ├── skill.py │ ├── requirements.txt │ └── README.md ├── calculator/ │ ├── config.yaml │ ├── skill.py │ └── requirements.txt └── shared/ └── utils.py每个目录就是一个独立技能包命名用下划线分隔的小写单词。shared 目录放的是跨技能包复用的公共代码比如统一的日志封装、HTTP 客户端封装、错误码定义。技能包之间不允许直接互相 import必须通过 shared 层访问公共能力这是为了避免循环依赖和职责纠缠。config.yaml 是技能包的“身份证”所有调度器需要的元信息都在里面。每个技能包至少包含一个入口脚本通常叫 skill.py脚本里暴露一个统一签名的 run 函数。2.2 config.yaml 的字段设计与意图直接看我目前在用的一个真实技能包配置文件是“今日热点新闻聚合”技能的name: news_digest version: 1.2.0 description: 当用户想要获取当天的重要新闻、热点事件、行业动态汇总时使用。 输入可选参数 category分类过滤和 limit返回条数 输出为结构化的新闻列表包含标题、来源、时间、摘要。 如果用户只是随口问天气或询问历史事件不要使用本技能。 author: ops-team tags: [news, search, digest] params: category: type: string required: false description: 新闻分类可选值为 tech / business / world / all默认 all example: tech limit: type: integer required: false description: 返回新闻条数范围 1-20默认 10 example: 10 entrypoint: skill.py runner: python timeout: 30这里每个字段都有它的用途我逐个说一下我的经验。name 和 version 是基础标识version 在调试的时候特别重要。Agent 应用跑久了之后你经常分不清当前生效的是哪一版技能有个版本号至少能让你在日志里定位问题。description 是全包最关键的字段它直接决定模型的判断准确率。要写成“什么场景下用、传入什么参数、返回什么结果、什么场景下绝对不要用”。负面说明尤其有用能显著降低误调用率。params 是对参数的结构化约束调度器会把它转成 JSON Schema 传给模型。这里的描述同样要写得细比如类型、取值范围、默认值模型在参数生成上的表现直接受这里约束密度的影响。entrypoint 和 runner 声明了技能用什么方式执行timeout 是超时保护防止一个技能卡死导致整个 Agent 响应超时。写到这里我想提醒一句timeout 千万别省。我见过太多 Agent 项目技能脚本里一个网络请求没有超时控制调用外部 API 等了整整两分钟整个对话直接断掉。给每个技能包设一个合理的超时上限是最便宜的稳定性保障。2.3 技能描述层的打磨技巧技能的 description 是整个系统中投入产出比最高的优化点但也是最容易被忽视的。很多开发者把 description 写成一行干巴巴的话就完事了模型自然就频繁选错技能。我打磨 description 时遵循三个原则。第一是触发场景前置。描述的开头必须直接说清楚“当用户想要……时”让模型在做工具选择时能够在第一句就匹配上用户意图。第二是参数和返回值的具体化。不写“输入查询词”而是写“输入为完整、明确的查询关键词避免模糊表述例如‘那个东西’”。不写“返回相关结果”而是写“返回按相关度排序的前 5 条结果每条包含标题和 URL 链接”。第三是负向约束明确。写明“如果用户只是闲聊……请不要调用本技能”这能有效避免模型把日常对话也路由到技能执行上。我这里还保留了一个真实的对比案例非常能说明问题。最初版本是获取股票价格。这个描述让模型在用户问“最近大盘怎么样”时也去调用股票技能返回结果却不匹配用户问题。打磨后版本是当用户要求查看某只股票或指数的当前价格、涨跌幅、成交量时使用。输入为股票代码或名称例如 600519 或 贵州茅台。输出为当前价格、涨跌幅、成交量、成交额。如果用户询问的是长期走势分析或投资建议请改用 stock_analysis 技能。第二版把触发条件、入参格式、输出范围、边界情况全部写清楚了误调用率下降了至少一半。描述不是写给人的注释是写给模型的路标。3. 技能调用机制与 Agent 接入实操3.1 统一调度器的实现思路技能包只是静态的“零件”真正让 Agent 用起来的是动态扫描并加载这些零件的调度器。我的调度器核心逻辑只有四步扫描技能目录、解析每个包的 config.yaml、把参数定义转换成模型需要的 JSON Schema 格式、把入口脚本包装成可调用的执行函数。为了控制复杂度我用 Python 实现了这个调度器核心代码大约只有一百行。扫描和解析直接用 PyYAML 完成执行阶段用 subprocess 或者 importlib 都行取决于你想把技能脚本放进哪个隔离级别。如果技能脚本都是可信的内部代码importlib 足够快如果想隔离第三方技能脚本的异常行为用 subprocess 更稳。我自己在跑本地技能时用 importlib在跑外部来源技能时一律 subprocess 隔离。下面是一个简化版的调度器核心展示了技能注册的全过程import os import yaml import importlib.util from pathlib import Path SKILL_DIR Path(./skills) def load_skill_package(skill_path: Path): config_path skill_path / config.yaml with open(config_path, r, encodingutf-8) as f: config yaml.safe_load(f) entry_path skill_path / config[entrypoint] spec importlib.util.spec_from_file_location( f{config[name]}_skill, entry_path ) module importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return config, module.run def build_tool_schema(config): properties {} required [] for pname, pinfo in config[params].items(): properties[pname] { type: pinfo[type], description: pinfo[description], } if pinfo.get(required, False): required.append(pname) return { type: function, function: { name: config[name], description: config[description], parameters: { type: object, properties: properties, required: required, }, }, } def scan_and_register(): tools [] runners {} for item in SKILL_DIR.iterdir(): if item.is_dir() and (item / config.yaml).exists(): config, run load_skill_package(item) tools.append(build_tool_schema(config)) runners[config[name]] run print(f[skills] registered: {config[name]} v{config[version]}) return tools, runners这段代码做的事情很直接扫描目录下所有含 config.yaml 的子目录加载技能配置和入口模块构建工具 schema 列表。实际项目里我还会加一层缓存机制技能目录的 mtime 变化时才重新扫描避免每次请求都做磁盘 I/O。3.2 与 OpenAI Function Calling 的完整对接调度器注册好了剩下的事情就是把这个注册结果塞给模型。我用的是目前最通用的 Function Calling 流程如果你用的是 Claude 或国产模型基本也是同一个套路只是字段名略有差异。完整流程分四步。第一步把 tools 列表传给模型接口作为 chat completion 的 tools 参数。第二步模型在需要调用技能时会返回一个 tool_calls 数组里面包含技能名称和模型生成的参数 JSON。第三步根据技能名称从 runners 字典里取出对应的入口函数传入模型给的参数执行拿到真实结果。第四步把这个结果作为 role 为 tool 的消息回传给模型让模型结合技能执行结果生成对用户的最终答复。我把这个流程封装成了一个方法方便直接在循环里调用def execute_tool_call(tool_call, runners): fn_name tool_call.function.name fn_args json.loads(tool_call.function.arguments or {}) if fn_name not in runners: return {error: fskill not found: {fn_name}} try: result runners[fn_name](**fn_args) return {result: result} except Exception as e: return {error: str(e)}注意执行结果不要裸返回最好统一包一层结构错误信息也要结构化。这样模型在拿到 tool 消息时能明确知道是执行成功还是失败避免它把一个报错文本当成正常结果继续胡编。3.3 本地脚本型技能如何写出规范接口之所以强调技能包必须暴露统一签名的 run 函数是因为调度器执行时不需要关心技能内部用了什么库、做了什么复杂的计算它只认一个入口。每个技能的 skill.py 大概长这样def run(url: str, timeout: int 10) - dict: 抓取指定网页的正文内容。 Args: url: 目标网页的完整 URL必须包含协议头例如 https://example.com timeout: 请求超时时间单位秒默认 10 Returns: dict: 包含 status、content、content_length 的字典 import requests from bs4 import BeautifulSoup headers { User-Agent: Mozilla/5.0 (compatible; MyAgent/1.0) } try: resp requests.get(url, headersheaders, timeouttimeout) resp.raise_for_status() except requests.RequestException as e: return {status: error, error: str(e)} soup BeautifulSoup(resp.text, html.parser) for node in soup.find_all([script, style, nav, footer]): node.decompose() content soup.get_text(separator\n, stripTrue) return { status: success, content: content[:5000], content_length: len(content), }注意几个细节。return 一定是 dict 而不是裸字符串因为 agent-skills 的调度器要统一处理结果格式dict 方便拼接后续的 tool 消息。函数入口参数名和 config.yaml 里的 params 字段要严格对齐否则模型生成的参数在执行时会对不上。所有网络请求必须带超时宁可返回一个超时错误也不能让技能卡死整个 Agent。最后返回的正文内容要截断防止一个网页把上下文撑爆。这个 5000 字的上限是我调出来的经验值既能满足日常总结需求又不会让 token 消耗失控。3.4 API 型技能的接入方式与密钥管理除了本地脚本很多技能实际上是调用第三方 API。比如查天气、查地图、发邮件本质上是把模型生成好的参数转发给外部服务。这类技能我单独做了 api_runner 支持在 config.yaml 里增加两个字段runner: api api: endpoint: https://api.example.com/v1/weather method: GET auth: type: bearer key_env: WEATHER_API_KEY params_map: city: city units: units调度器读到 runner 是 api 时不再执行 skill.py而是走一个通用的 API 执行器从环境变量里读密钥、按 params_map 映射参数字段、发 HTTP 请求、把返回的 JSON 原样包装后返回给模型。这个设计的价值在于不写一行业务代码只靠配置就能接入一个新 API 技能。而且密钥永远只存在环境变量里不落在技能包的配置文件里即便技能包被分享出去也不会泄露凭据。3.5 一个多技能协作的完整场景演示只看单个技能的调用还不够Agent 的价值在于多个技能串起来完成一个复杂任务。我经常用来验收 agent-skills 的测试场景是用户说“帮我搜一下最近一周 AI Agent 领域的重大进展重点看技术突破和产品发布整理成摘要”。这个请求实际上拆成了三步。第一步模型判断需要调用 web_search 技能执行搜索返回一周内的相关新闻列表。第二步模型发现列表里有多个值得深入阅读的链接分别调用 web_fetch 技能抓取详细内容。第三步模型综合多次搜索和抓取的结果生成一篇结构化摘要。整个过程中调度器的循环会连续执行三轮工具调用模型在这一轮里先调一次 web_search拿到结果后决定再调 web_fetch最后把汇总结果组织成自然语言回复。我在日志里观察过整个执行链路大概三到五个工具调用就能完成这个任务。如果把这段逻辑写死在代码里你要为每一种用户问法单独写分支用技能包加模型决策一套通用循环就覆盖了无穷多的组合可能。这是 agent-skills 这个架构最核心的价值点。4. 常见问题与排查技巧实录4.1 description 写不好导致模型选错技能这类问题在日志里的特征是模型的 tool_calls 里出现了技能名但从参数和上下文的匹配度看完全不合理。比如用户聊到“苹果”这种水果模型却去调股票行情技能查 AAPL 的股价。判断这类问题我会先翻出被调用的技能的 description对照用户当前消息看一下是否在触发条件上存在模糊地带。解决办法有两个抓手。一是把 description 里描述触发场景的句子再写具体一点比如从“当用户提到苹果时”改成“当用户明确要求查看苹果公司股票行情时”把多义词的歧义切割掉。二是在 params 里加强约束比如要求股票代码参数必须是完整代码或合法名称这样即便模型选错了技能参数校验阶段也会拦截住。参数层校验是我后来专门加的一层防线作用等同于代码里的断言宁可误杀不能放过。下面这张表是我在实际项目中积累的 description 问题对照和修改方向。问题形态典型描述修改方向触发场景太宽泛获取股票价格。限定为“用户明确要求查看某只股票的当前价格或涨跌幅时”。缺少负向约束查询天气信息。补充“如果用户是在写小说、编故事中提及天气不要调用本技能”。参数表述模糊输入搜索关键词。改为“输入为完整、具体的搜索词优先使用用户原文中的关键词组合”。返回值不明确返回查询结果。明确“返回按时间排序的前 N 条列表每条包含标题、链接、发布时间、摘要”。4.2 JSON Schema 参数与实际执行函数不一致这类问题经常在技能包更新后爆发。config.yaml 里的 params 定义调整了但 skill.py 的函数签名没有同步改模型按新 schema 生成了参数执行时直接 TypeError。根本原因是配置文件和人写代码之间没有一道自动化校验。我现在给每个技能包写了一个自检入口在注册阶段自动做参数对齐检查把 config.yaml 里声明的参数名和 skill.py 的函数签名做对拍发现不一致直接拒绝注册并打印警告。具体做法是在加载模块后用 inspect.signature 获取 run 函数的参数列表和配置文件里的 params 键集合做差集判断。这个检查两分钟就能写完但能把一类很难发现的运行时问题提前到启动阶段暴露。技能包多了以后这个防线是刚需。4.3 技能执行超时和外部依赖过重技能包本质上是在 Agent 的响应链路上插入了外部调用外部服务的延迟和稳定性会直接拖垮用户体验。我遇到过天气 API 第三方服务偶发 15 秒才返回的案例如果没有超时控制Agent 的整个响应就被这个技能卡死。这也是为什么我在每个技能包的 config.yaml 里强制设置 timeout 字段并且要求所有网络型技能脚本内部也要有自己的请求级超时。双重超时控制意味着即使技能包内部的脚本忘了设置请求超时调度器层面的强制超时仍然能兜住。另外一点是依赖管理。每个技能包带一个 requirements.txt但安装时不能全局安装。我推荐为不同技能包建虚拟环境或者至少用依赖隔离方案不然两个技能包依赖了同一个库的不同版本会互相打架。我这里采用的是 shared 依赖统一锁定版本特殊依赖单独建环境运行的策略执行层接到调度器的 subprocess 调用时会自动激活对应的虚拟环境。4.4 上下文长度与 token 消耗失控技能描述和工具调用结果都会占用上下文这是 Agent 应用一个不可忽略的成本项。我实测过一个场景tools 列表里挂了二十个技能每个技能 description 写的又长又啰嗦光工具定义就占了四千多 token再叠加多轮对话的历史消息和工具执行返回结果很快就把大模型的上下文窗口吃掉了大半。控制 token 消耗我从三个方向下手。第一description 控制在两百字以内只在必要时写负向约束不写废话。第二技能返回结果尽量精简web_fetch 这类技能我强制截断到五千字以内而且返回前先做一层 summarize 预处理只保留核心内容第三启动时做技能分组不是所有技能都注入给所有 Agent比如负责写作的 Agent 只需要挂内容生成类的技能不需要挂股票行情类技能。这个按需注入的思路能把 tools 数量从二十个降到五六个token 消耗锐减。4.5 技能间副作用与共享状态污染技能包做到后期会出现技能 A 修改了某个全局状态、技能 B 依赖这个状态的情况。这在本地脚本型技能里尤其容易发生。比如我的“网页抓取”技能内部维护了一个共享的 requests.Session 连接池同时“批量截图”技能也复用了同一个 Session由于两个技能的执行间隔很短、连接池状态混乱偶发出现连接复用报错。我解决这个问题的原则是技能包内部必须无副作用所有状态要么是函数内局部变量要么显式通过参数传递。任何涉及跨技能共享的数据一律走一个显式的临时文件或专用的 KV 存储接口不允许隐式共享。这会让技能包看起来更“笨”但正是这种笨保证了整个系统的可预测性。分布式系统里有一句名言猜测别人怎么用你的模块最后一定会出问题显式优于隐式。4.6 排查问题的实用速查表整理一张我在上线运维中按经验总结的速查表遇到问题可以按图索骥。现象可能原因排查方向模型完全不调用任何技能tools 列表为空或 schema 格式不正确检查 scan 日志里是否注册成功尝试用最小工具列表直连调试模型频繁调用同一个错误技能description 触发条件覆盖过宽重写 description增加负向约束和具体场景限制技能执行报 TypeErrorconfig 参数名与函数签名不一致启用注册阶段的参数对拍校验检查 skill.py 的默认值技能卡住不返回外部请求无超时控制设置请求级超时与调度器级 timeout 双层保护响应速度明显变慢技能包依赖安装过重或外部 API 延迟检查技能执行日志耗时考虑异步执行或换更快的 API部分 Agent 出现莫名的失败多个技能共享了可变全局状态将技能状态改为局部变量或引入显式共享存储一个技能更新后其他技能异常共享依赖库版本冲突技能包依赖隔离关键依赖统一锁定版本排查 Agent 问题时我习惯先看调度器的注册日志确认技能有没有正确挂载再看模型返回的 tool_calls 原始 JSON确认模型意图最后看技能执行的结果回传确认返回值格式。这三段日志对上了问题基本就能定位。很多初看像是模型“抽风”的故障查到最后都是技能包配置或执行层的低级错误。5. 从技能包到技能生态的扩展思考5.1 技能包粒度怎么定做 agent-skills 一段时间后我面临最频繁的问题就是技能粒度的取舍拆太细会导致技能数量爆炸描述层占用上下文过多拆太粗又会导致单个技能内部逻辑臃肿复用性差。我目前采用的判断标准是一个技能应该对应一个用户可感知的完整能力而不是一个底层操作。比如“网页正文提取”单独做一个技能是合理的因为它对应“把乱糟糟的网页变成干净文本”这个能力“提取网页标题”就不要单独做一个技能它可以作为网页提取技能返回内容的一部分。再比如“搜索新闻”和“抓取新闻详情”是两个技能因为模型的决策边界清晰用户可能只搜索不抓取也可能直接在某个链接上要求总结详情。反过来“根据用户兴趣推荐新闻”就不适合做成技能它属于多个基础技能的编排层逻辑应该交给 Agent 的提示词或工作流去处理。粒度过粗的典型问题是技能内部写了复杂的分支逻辑相当于把模型的决策提前写死在了代码里。比如“处理文档”技能里同时包含了提取文字、识别表格、转 PDF 三个功能参数需要一个 action 字段区分。这样看起来技能少了但模型需要额外理解 action 枚举的含义执行结果的确定性也差。我倾向于让技能保持单一职责多技能协作的任务编排交给模型去完成而不是在技能内部加开关。5.2 技能版本管理与灰度发布技能包变成了独立更新的单元之后版本管理就成了新的课题。我的做法是把整个 skills 目录放入单独的 Git 仓库每个技能包更新时按语义化版本递增config.yaml 里的 version 字段同步更新。调度器启动时会打印所有技能包的版本号方便和日志对照。上线方式上我偶尔会遇到单个技能需要紧急修复的情况。这时候如果直接替换技能目录下的脚本Agent 所有会话都会受影响。稳妥一点的做法是调度器对技能包目录做多版本并存支持config.yaml 里增加一个 enabled 标志新版本技能先以 disabled 状态推上去在测试环境验证完成后再打开。这个机制不需要额外开发只需要在扫描阶段过滤掉 enabled 为 false 的包即可。对多 Agent 场景我会上线开关前先只让一部分测试 Agent 请求路由到新技能版本确认稳定后再全量放开类似于传统的灰度发布。5.3 社区共享技能包的标准化价值技能包做到最后最花时间的永远是重复开发同样能力的技能。比如网页抓取、文本摘要、格式转换、数据查询这些能力几乎所有 Agent 项目都会用到。如果大家各自维护一套互相不兼容的技能包等于整个生态在重复造轮子。agent-skills 这类标准化结构的价值在于只要大家遵循同一套目录格式和配置规范技能包就能跨项目、跨团队复用。理想的形态是团队里建一个内部技能仓库统一 CI 校验每个技能包的配置格式、函数签名和依赖声明代码评审通过后自动同步到技能仓库服务所有 Agent 部署后自动发现新版本。这个流程普及了以后新增一个能力就从“写一个工具”变成了“引进一个技能包”成本大幅降低。5.4 agent-skills 后续可以扩展的方向当前我这个 agent-skills 实现还比较朴素但它预留了两个重要的扩展方向。一个是技能执行的鉴权体系。现在所有技能对调用方一视同仁但实际场景里有些技能只对特定角色开放有些技能会操作真实的外部系统必须有权限控制。另一个是技能调用的观测面板。目前通过日志可以清楚看到每次调用了哪个技能、耗时多少、结果是什么但缺少跨请求的统计视图。如果把这些数据汇聚到一个面板上就能直观看到哪些技能被高频调用、哪些技能频繁报错给技术优化提供方向。这些扩展的共同点是都不需要改动技能包本身的格式只是围绕技能包增加管理能力。这验证了一个判断标准化技能包结构是这套系统最核心的投入产出比所在。如果你正在搭建自己的 Agent 应用我建议先别急着堆功能把技能包这个底座打扎实后面加能力只是“放一个新包进目录”的事。