
1. 这不是“技能清单”而是一次对Skill概念的外科手术式解剖你肯定见过这样的场景团队里有人甩出一份叫skill.md的文档标题写着“用户画像构建Skill”内容却是一段Python伪代码加三行注释另一个项目里agent.md和skill.md并列放在根目录但打开后发现skill.md里混着API调用示例、错误日志片段、甚至还有未删干净的调试print语句更常见的是新成员入职第一天就被要求“先看懂我们所有的Skill文档”结果翻了两小时只确认了一件事——没人能说清“这个Skill到底在系统里干了什么”。这不是文档规范问题是概念污染。Skill这个词在当前Agent开发实践中已经被用得既宽泛又模糊它可以指一段可执行脚本可以是一份结构化描述可以是某个LLM调用的prompt模板也可以是某个微服务的接口契约。而最危险的是很多人把“写了个函数”就叫Skill“配了个工具插件”也叫Skill“抄了段coze workflow”还叫Skill——结果是工程交付时同一个Skill名在不同环境里行为不一致测试通过率跌到60%线上报错日志里反复出现agent execution terminated due to error.但根本找不到问题源头在哪。我过去三年带过7个Agent落地项目从金融风控Agent到工业设备巡检Agent踩过所有能把Skill玩坏的坑。最后发现真正稳定的Skill从来不是靠“写得快”或“命名酷”而是靠一套可验证、可隔离、可版本化的工程契约。它必须同时满足三个刚性条件有明确输入/输出边界不是一堆全局变量有独立执行上下文不依赖当前Agent状态有可复现的行为契约给定相同输入必得相同输出。这三点缺一不可。否则所谓Skill不过是披着工程外衣的临时脚本迟早会在多轮对话、异步调度、重试机制中露出马脚。所以这篇文章不教你“怎么写Skill”而是带你亲手拆开Skill这个黑盒从它在Agent架构中的真实定位开始看它如何与Prompt Engineering、Tool Calling、State Management三者划清界限接着用一个真实可运行的weather_skill.py和配套skill.md为例逐行解释每个字段为什么存在、为什么必须这样写、改错一个字符会引发什么连锁反应然后展示如何用最小成本实现Skill的本地验证、沙箱执行、版本灰度——不是靠“跑通就行”而是靠断言驱动、契约先行最后我会拿出我们团队正在用的skill.md目录规范模板包括/v1/版本路径设计、schema.json校验规则、test_cases/组织方式以及最关键的——如何让新成员5分钟内就能判断一个Skill是否“合规”而不是靠“问老同事”。如果你现在写的Skill还停留在“扔进agent目录就完事”的阶段或者你的团队还在为“这个Skill到底该谁维护”扯皮那这篇就是为你写的。它不讲虚的概念只讲你明天上班就能用上的判断标准和检查清单。2. Skill的本质不是功能模块而是能力契约2.1 Skill在Agent架构中的真实坐标系很多初学者误以为Skill是Agent的“插件”或“扩展包”这种理解直接导致后续所有工程实践走偏。实际上在现代Agent框架如LangChain、LlamaIndex、自研轻量框架中Skill的正确定位是Agent能力平面Capability Plane上的最小可验证契约单元。它和Prompt、Memory、Router一样属于Agent的横向能力切片而非纵向功能堆叠。举个生活化类比如果把Agent比作一辆智能汽车那么Prompt是导航语音指令“去最近的加油站”负责意图表达Memory是行车记录仪电子地图缓存记住上次加油位置、常去商圈Router是车载中控系统判断当前指令该调用导航模块还是空调模块Skill则是发动机ECU固件——它不决定“去哪”但严格定义“油门踩到30%时扭矩输出必须在XX牛·米±5%范围内”且这个定义独立于导航指令、不依赖历史路况数据。这个类比的关键在于ECU固件Skill的输入输出契约是硬编码在芯片里的不是靠司机喊话临时协商的。同理一个合格的Skill其input_schema和output_schema必须像API契约一样被静态声明且执行过程必须与Agent主循环解耦。我见过太多项目把Skill写成这样# ❌ 危险示例隐式依赖Agent状态 def get_user_info(): # 直接读取全局agent_state.current_user_id user_id agent_state.current_user_id # 调用数据库但没声明需要什么参数 return db.query(fSELECT * FROM users WHERE id{user_id})问题在哪表面看能跑通但一旦Agent开启多线程、做A/B测试、或进行重试agent_state.current_user_id可能已被覆盖。更致命的是这个Skill无法被单独测试——你没法给它传入user_id来验证返回结构。它本质上是个“状态泄漏器”不是Skill。2.2 Skill与Tool、Function Calling的本质区别网络热词里常把Skill和Tool混用尤其在pi agent、hermes agent等框架宣传中。但工程上二者有不可逾越的鸿沟维度ToolSkill定义主体LLM侧由模型理解并调用工程侧由开发者定义并部署调用触发基于LLM推理结果动态选择可能失败由Router或业务逻辑显式调度可预判失败处理LLM需生成fallback响应不可控可配置重试策略、降级方案、熔断阈值可控契约保障仅靠prompt约束无类型校验强制JSON Schema校验输入/输出结构可验证实操中Tool是“LLM想用就用”Skill是“系统必须确保它可用”。比如天气查询作为ToolLLM可能在用户问“今天穿什么”时自行决定调用天气API但若API超时LLM只能胡编个温度作为SkillRouter会根据用户明确问“北京天气”才触发且执行前校验{city: string, unit: celsius/fahrenheit}失败时返回结构化错误码而非自然语言。我们团队强制规定所有外部API调用必须封装为Skill而非直接暴露为Tool。原因很简单——Tool的调用链路在LLM内部你无法插入监控、限流、审计日志而Skill的执行路径完全在工程控制域内每个调用都有trace_id、耗时统计、成功率报表。2.3 为什么Markdownskill.md是Skill的黄金载体看到热搜词里高频出现skill.md、markdown语法、markdown preview enhanced很多人以为这只是“文档格式偏好”。错了。Markdown成为Skill事实标准源于它完美匹配Skill的三大工程需求人类可读 机器可解析.md文件天然支持YAML front matter既能写清晰的中文说明给新人看又能嵌入结构化元数据给CI/CD解析。比如--- name: weather_query version: v1.2.0 input_schema: city: string unit: enum[celsius, fahrenheit] output_schema: temperature: number condition: string humidity: integer timeout_ms: 3000 --- ## 功能说明 查询指定城市实时天气支持摄氏/华氏单位切换...版本可追溯Git对.md文件的diff极其友好。当你看到commit记录显示skill.md中timeout_ms从2000改为3000立刻知道这是为应对API抖动做的容错升级而如果是二进制配置文件你只能看到“配置已更新”。编辑门槛归零不需要IDE、不用装插件VS Code自带预览、Typora一键导出PDF、甚至手机备忘录都能编辑。我们曾让非技术的产品经理直接修改skill.md里的description字段上线后文案同步生效——这在JSON/YAML配置里根本不敢想。提示别用skill.md当纯文档它的YAML front matter才是核心。那些只写“本Skill用于查天气”的.md文件和没写Schema的Python脚本一样危险。3. Skill的工程实现从定义到验证的完整闭环3.1 Skill的最小可行结构一个可运行的weather_skill.py我们以真实项目中的天气查询Skill为例展示符合工程规范的完整实现。注意这不是教学代码而是生产环境已跑半年的精简版。# weather_skill.py import json import requests from typing import Dict, Any from pydantic import BaseModel, Field, validator class WeatherInput(BaseModel): city: str Field(..., min_length1, max_length50) unit: str Field(celsius, pattern^(celsius|fahrenheit)$) validator(city) def city_must_be_chinese_or_english(cls, v): # 简单校验实际用正则或第三方库 if not all(c.isalnum() or c in - for c in v): raise ValueError(city must contain only letters, numbers, space, hyphen) return v class WeatherOutput(BaseModel): temperature: float Field(..., ge-100, le100) condition: str Field(..., min_length1) humidity: int Field(..., ge0, le100) timestamp: str Field(..., patternr^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$) def execute(input_data: Dict[str, Any]) - Dict[str, Any]: Skill执行入口必须接收dict返回dict 不允许访问任何全局变量、不依赖Agent实例 try: # 1. 输入校验Pydantic自动完成 parsed_input WeatherInput(**input_data) # 2. 构造API请求硬编码base_url避免配置漂移 api_url https://api.example-weather.com/v1/current params { q: parsed_input.city, units: parsed_input.unit, appid: sk_prod_abc123 # 生产密钥不应放config } # 3. 执行HTTP调用带超时和重试 response requests.get( api_url, paramsparams, timeout2.5, # 比skill.md声明的3000ms略短留缓冲 headers{User-Agent: SkillRunner/1.0} ) response.raise_for_status() # 4. 解析响应并映射到输出模型 raw_data response.json() output WeatherOutput( temperaturefloat(raw_data[temp]), conditionraw_data[condition], humidityint(raw_data[humidity]), timestampraw_data[timestamp] ) return output.dict() except requests.exceptions.Timeout: raise RuntimeError(Weather API timeout) except requests.exceptions.ConnectionError: raise RuntimeError(Weather API unreachable) except (KeyError, ValueError, TypeError) as e: raise RuntimeError(fWeather API response malformed: {str(e)}) except Exception as e: raise RuntimeError(fUnexpected error: {str(e)})关键点解析输入/输出强类型用Pydantic而非dict确保类型安全。Field(...)表示必填ge/le定义数值范围pattern约束字符串格式。零全局依赖整个函数不引用任何global变量不调用get_current_agent()之类的方法。输入全靠参数传入输出全靠return返回。错误分类明确网络超时、连接失败、响应异常、未知错误四类异常分别抛出不同message便于后续监控告警。密钥硬编码看似违反安全原则实则是为避免配置中心故障导致Skill集体失效。生产中密钥由Secret Manager注入环境变量此处简化展示。实操心得我们曾因忘记在execute()函数签名里加- Dict[str, Any]导致TypeScript前端调用时类型推导失败花了3小时排查。记住——Python类型提示不是装饰是契约的一部分。3.2 skill.md让机器读懂你的意图weather_skill.py解决了“怎么做”skill.md解决“是什么”和“怎么用”。以下是生产环境使用的weather_skill.md完整内容已脱敏--- name: weather_query version: v1.2.0 category: data_fetching status: stable input_schema: city: type: string description: 城市名称支持中英文如Beijing或北京 example: Shanghai unit: type: string description: 温度单位celsius摄氏或fahrenheit华氏 enum: [celsius, fahrenheit] default: celsius output_schema: temperature: type: number description: 当前温度精确到小数点后1位 example: 23.5 condition: type: string description: 天气状况如sunny、rainy、cloudy example: partly cloudy humidity: type: integer description: 相对湿度百分比 example: 65 timestamp: type: string description: 数据获取时间ISO 8601格式 example: 2024-06-15T08:30:00Z timeout_ms: 3000 retries: 2 fallback: temperature: 0.0 condition: unknown humidity: 0 timestamp: 1970-01-01T00:00:00Z owner: platform-teamcompany.com last_updated: 2024-06-15 --- # Weather Query Skill ## 功能概述 查询指定城市的实时天气数据支持单位切换。适用于用户主动询问天气场景。 ## 使用场景 - 用户问“上海现在多少度” → Router识别意图调用此Skill - Agent生成回复时需嵌入温度数据 → 前端组件直接消费output ## 注意事项 - 城市名需准确模糊匹配可能导致错误如New York vs New York City - 单位切换仅影响temperature字段condition和humidity不变 - fallback值仅在API完全不可用时返回不用于网络抖动此时走重试 ## 版本变更 - v1.2.02024-06-15增加humidity字段timeout从2000ms提升至3000ms - v1.1.02024-03-22支持fahrenheit单位修复timestamp格式为什么这个.md文件比代码更重要因为它是跨角色沟通协议产品经理看description和example就知道怎么用运维看timeout_ms和retries就知道怎么设监控阈值安全团队看owner和last_updated就知道谁该对漏洞负责。它是自动化流程的输入源我们的CI流水线会自动解析YAML front matter生成Swagger文档、Postman集合、单元测试桩甚至自动创建Datadog监控面板。它是新人上手的第一道关卡新成员入职第一项任务是阅读skill.md然后用curl手动调用API验证再看代码实现——顺序不能颠倒。注意fallback字段不是可选项没有fallback的Skill在API雪崩时会让整个Agent卡死。我们规定所有Skill必须提供语义合理的fallback值哪怕只是{error: service_unavailable}。3.3 本地验证5分钟建立Skill质量防火墙写完代码和文档绝不能直接扔进生产环境。我们强制执行三步本地验证步骤1Schema校验防低级错误用开源工具markdownlint自定义规则检查YAML格式# 安装校验器 pip install markdownlint-cli2 # 运行校验检查front matter语法、字段完整性 markdownlint-cli2 **/skill.md --config .markdownlint.json.markdownlint.json包含我们定制的规则{ MD013: { code_blocks: false }, // 允许长代码块 MD041: { level: 2 }, // 要求H2标题 custom/rules/skill-schema: { required_fields: [name, version, input_schema, output_schema, timeout_ms], enum_values: [celsius, fahrenheit] } }步骤2输入/输出契约测试防逻辑错误用Pydantic自动生成测试用例# test_weather_skill.py from weather_skill import WeatherInput, WeatherOutput def test_input_validation(): # 测试正常输入 valid_input {city: Beijing, unit: celsius} assert WeatherInput(**valid_input) # 应成功 # 测试非法城市名 invalid_input {city: Beijing!, unit: celsius} try: WeatherInput(**invalid_input) assert False, Should raise validation error except ValueError: pass # 预期异常 def test_output_schema(): # 测试输出字段范围 valid_output { temperature: 23.5, condition: sunny, humidity: 65, timestamp: 2024-06-15T08:30:00Z } assert WeatherOutput(**valid_output) # 应成功 # 测试湿度超限 invalid_output {**valid_output, humidity: 150} try: WeatherOutput(**invalid_output) assert False, Should raise validation error except ValueError: pass运行命令pytest test_weather_skill.py -v覆盖率必须≥95%。步骤3沙箱执行测试防环境依赖用Docker模拟生产环境执行Skill# Dockerfile.skill-test FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY weather_skill.py . COPY skill.md . CMD [python, -c, from weather_skill import execute; print(execute({city: Shanghai, unit: celsius}))]构建并运行docker build -f Dockerfile.skill-test -t skill-test . docker run --rm skill-test # 输出应为类似{temperature: 25.3, condition: cloudy, ...}这一步卡掉过我们70%的“本地能跑线上挂掉”问题——比如某Skill依赖/tmp目录写临时文件但Docker容器里/tmp权限不对。实操心得曾经有个Skill在本地用requests能跑通但Docker里报ModuleNotFoundError: No module named requests。原因是requirements.txt里漏写了requests2.31.0。现在我们CI强制检查pip list输出是否包含所有import模块。4. Skill的生命周期管理从开发到下线的实战经验4.1 目录结构设计让100个Skill不打架当项目积累50个Skill时混乱的目录结构会成为最大技术债。我们采用四级分层法skills/ ├── core/ # 核心能力不可被业务覆盖 │ ├── auth/ # 认证相关 │ │ ├── login_v1.md │ │ └── login_v1.py │ └── data/ # 数据基础能力 │ ├── db_query_v1.md │ └── db_query_v1.py ├── domain/ # 业务领域能力 │ ├── finance/ # 金融域 │ │ ├── risk_score_v2.md │ │ └── risk_score_v2.py │ └── retail/ # 零售域 │ ├── inventory_check_v1.md │ └── inventory_check_v1.py ├── infra/ # 基础设施能力 │ ├── notification/ # 通知服务 │ │ ├── send_sms_v1.md │ │ └── send_sms_v1.py │ └── storage/ # 存储服务 │ └── s3_upload_v1.md └── deprecated/ # 已废弃Skill保留历史禁止新增 └── old_weather_v0.md关键设计原则版本号嵌入文件名risk_score_v2.py而非risk_score.py避免Git冲突和覆盖风险。禁止跨域调用finance/risk_score.py不能importretail/inventory_check.py必须通过API网关调用。deprecated目录只读CI检测到向deprecated/写入新文件立即失败。我们曾因skills/utils/目录下放了通用函数导致各业务Skill互相依赖一次utils/date_helper.py的bug引发全站Skill故障。现在utils/被彻底移除通用逻辑下沉到SDK层。4.2 版本灰度发布让Skill升级像换轮胎Skill升级不是“停机发布”而是渐进式替换。我们用NginxConsul实现流量染色新版本Skill部署到新服务器注册为weather_query_v1.2.0服务Consul中设置权重weather_query_v1.1.0占90%weather_query_v1.2.0占10%监控面板实时对比两版本的success_rate、p95_latency、error_types若新版本success_rate≥99.5%且p95_latency≤旧版本110%权重逐步提升至100%若任一指标跌破阈值自动回滚到旧版本。关键指标阈值设定依据success_rate基于历史SLA金融类Skill要求≥99.95%客服类≥99.5%p95_latency不能超过Skill声明timeout_ms的80%留20%缓冲给网络抖动error_types重点关注RuntimeError类错误requests.exceptions.Timeout可接受KeyError必须0容忍。注意灰度期间skill.md的version字段必须与实际部署版本严格一致。我们CI流水线会校验git tag、Docker image tag、skill.md version三者是否统一不一致则阻断发布。4.3 Skill健康度仪表盘一眼看清所有Skill状态我们用Grafana搭建Skill健康度看板核心指标来自每个Skill的埋点日志指标计算方式告警阈值业务含义success_ratesuccess_count / total_count99.0%核心Skill95.0%非核心Skill是否稳定可用p95_latencyP95响应耗时timeout_ms× 0.8是否存在性能瓶颈fallback_ratefallback_count / total_count5%依赖服务是否持续异常schema_violation_rateinvalid_input_count / total_count0.1%前端或Router是否传参错误看板设计原则红黄绿灯直观呈现绿色达标、黄色预警、红色告警下钻能力点击任一Skill查看最近1小时错误日志TOP5、调用来源分布、地域分布关联分析当weather_query成功率下跌自动高亮显示其依赖的api.example-weather.com健康状态。这个看板让我们把平均故障定位时间MTTD从47分钟缩短到8分钟。曾经一次agent execution terminated due to error.报警运维5分钟内就定位到是weather_query的fallback逻辑缺陷而非盲目重启Agent服务。4.4 Skill下线流程告别“不敢删”的技术债最危险的Skill不是写错的而是没人敢动的“祖传代码”。我们制定严格下线流程标记废弃在skill.md顶部添加status: deprecated并注明deprecation_date和replacement流量拦截Router层拦截所有对该Skill的调用返回410 Gone及迁移指引监控观察持续监控7天确认调用量归零代码归档将Skill文件移至skills/deprecated/YYYY-MM-DD_skill_name/保留commit历史文档清理删除Wiki中所有引用更新API文档。关键控制点禁止直接删除Git history必须保留便于审计强制迁移指引replacement字段必须指向一个真实存在的新Skill不能写“请联系平台团队”7天冷静期即使流量为0也必须满7天才执行归档防止监控漏报。我们曾下线一个old_user_profile_v1结果发现CRM系统还在调用。幸好7天冷静期捕获到异常调用及时通知对方改造。现在所有Skill下线前必须邮件抄送所有可能调用方。5. 常见问题与排查技巧实录那些年我们踩过的坑5.1 “Skill能跑通但Agent总报错”——Router契约错配现象weather_skill.py本地测试100%成功但Agent调用时频繁报agent execution terminated due to error.日志里只有Skill execution failed无具体错误。排查路径检查Router配置Agent的Router是否按skill.md的input_schema构造参数错误示例skill.md要求{city: string}但Router传入{city: [Shanghai]}数组而非字符串检查序列化Router传参是否经过JSON序列化Python字典直接传入会导致Pydantic校验失败检查超时传递Router设置的timeout是否≤skill.md声明的timeout_ms若Router设2000msSkill设3000msSkill会因超时被强制中断。解决方案在Router层增加Schema校验中间件用jsonschema.validate()验证传参所有Skill调用前强制json.dumps(input_dict)再json.loads()确保类型纯净Router timeout必须≥Skill timeout建议设为Skill timeout×1.2。实操心得我们曾因Router传参多了一个空格 city 导致Pydantic校验失败。现在所有Router输入都经过strip()处理。5.2 “Skill返回正常但Agent回复乱码”——编码与渲染陷阱现象Skill返回{condition: ️}emoji但Agent前端显示为或空白。根因分析Skill执行环境Docker容器的locale未设为en_US.UTF-8导致Python默认编码为ASCIIMarkdown渲染器如markdown-it-py未启用emoji插件前端CSS未声明font-family支持emoji字体。三步修复Dockerfile中添加ENV LANGen_US.UTF-8skill.md的output_schema中对含emoji字段添加encoding: utf-8声明前端Markdown组件初始化时启用emojiimport markdownit from markdown-it; const md markdownit({ html: true, emoji: true // 关键 });5.3 “Skill版本升级后旧功能突然失效”——隐式状态泄漏现象risk_score_v2.py上线后部分用户反馈“信用分计算结果变低”但risk_score_v2.md的output_schema未变。深度排查对比v1和v2代码发现v2新增了cache_key f{user_id}_{timestamp[:7]}但timestamp来自系统时间而非输入参数问题在于Skill声称“输入city返回温度”实际却依赖当前时间导致相同输入在不同时间返回不同结果——违反Skill契约。修正方案所有时间相关逻辑必须由Router传入as_of_time参数写入input_schemaSkill内部禁用datetime.now()只允许input_data.get(as_of_time)在skill.md的input_schema中明确标注as_of_time: string (ISO 8601, optional, default: current time)。注意这个bug导致我们暂停了所有Skill升级两周全员培训“Skill必须幂等”原则。现在Code Review Checklist第一条就是“检查是否有隐式时间/随机数/全局状态依赖”。5.4 “Skill文档和代码不一致”——自动化防护墙建设现象skill.md写timeout_ms: 3000但weather_skill.py里timeout2.5线上监控显示超时率飙升。防御体系CI预检提交PR时脚本自动提取skill.md的timeout_msgrepweather_skill.py中的timeout校验数值一致性运行时校验Skill启动时读取skill.md对比代码中硬编码值不一致则panic退出文档生成用pdoc从Python代码生成HTML文档与skill.md内容合并形成唯一可信源。校验脚本示例check-skill-consistency.sh#!/bin/bash SKILL_NAMEweather_query MD_TIMEOUT$(yq e .timeout_ms skills/domain/weather/$SKILL_NAME.md) PY_TIMEOUT$(grep timeout skills/domain/weather/$SKILL_NAME.py | head -1 | sed s/.*timeout//; s/,.*//) if [ $MD_TIMEOUT ! $PY_TIMEOUT ]; then echo ERROR: timeout mismatch! md$MD_TIMEOUT, py$PY_TIMEOUT exit 1 fi这套防护让“文档代码不一致”类问题归零。现在团队新人第一次提交SkillCI会自动跑这个检查失败即拒收。5.5 “Skill越来越多新人根本不会选”——Router智能化演进现象团队有83个Skill新人写Router时总选错比如用db_query_v1查天气导致agent execution terminated due to error.。解决方案Skill打标系统在skill.md中强制添加tags字段如tags: [data_fetching, real_time, public_api]Router语义路由用Sentence-BERT对Skill描述向量化用户问“北京天气”Router计算相似度自动匹配weather_query而非db_query新人引导模式CLI工具skill-select输入自然语言描述返回Top3匹配Skill及匹配度$ skill-select 查用户当前所在城市天气 1. weather_query_v1.2.0 (score: 0.92) - 查询指定城市实时天气... 2. location_detect_v1.0.0 (score: 0.76) - 根据IP或GPS获取用户位置... 3. user_profile_v2.1.0 (score: 0.43) - 获取用户档案信息...这套系统让Router准确率从68%提升到94%新人上手时间从3天缩短到2小时。6. 最后分享一个血泪教训别让Skill变成新形式的技术债我在第一个Agent项目里曾天真地认为“多写Skill能力强”。结果半年后项目里堆了127个Skill其中43个没人记得是干啥的29个skill.md里version字段还是v0.1.017个代码里还留着# TODO: remove this hack。最荒诞的是有个叫debug_log_v1.py的Skill作用是往日志里写DEBUG: skill executed——它被调用了23万次消耗了12%的CPU资源却没有任何业务价值。后来我们花了整整六周不是写新功能而是做Skill考古用Git Blame追溯每个Skill的最后修改者用ELK分析调用日志标记30天零调用的Skill人工review所有TODO注释要么实现要么删除把debug_log这种伪Skill替换成统一的日志中间件。这次清理让我们删掉了31%的代码系统启动时间缩短40%更重要的是团队终于敢重构了——因为大家知道每个Skill都是有主的、可验证的、可下线的。所以如果你今天要写第一个Skill请先问自己三个问题它的input_schema和output_schema能不能用一句话说清说