1. “agent-skills”不是功能模块,而是一套可插拔的能力交付协议
你第一次在 GitHub 上看到agent-skills这个仓库名,或者在 CLI 工具的文档里读到skills install --from github.com/xxx/xxx-skill这行命令时,大概率会下意识把它理解成“智能体(Agent)自带的一组技能列表”——就像手机预装的计算器、备忘录那样,属于 Agent 的出厂配置。但实际完全相反:agent-skills本质上是一套轻量级、声明式、面向开发者的能力封装与分发标准,它的核心价值不在于“提供什么”,而在于“如何让任意第三方能力被任意 Agent 安全、可靠、可验证地加载和执行”。
这背后对应的是当前 LLM 应用开发中一个真实且日益尖锐的矛盾:模型能力越来越强,但落地场景却越来越碎片化。一个电商客服 Agent 需要调用订单查询 API、物流轨迹解析、退换货规则引擎;一个研发助手 Agent 需要读取 Git 日志、生成 PR 描述、检查 CI 状态、调用代码补全服务;一个个人知识管理 Agent 则要连接 Notion、同步微信读书笔记、提取 PDF 关键信息。这些能力彼此无关,由不同团队开发、部署在不同环境、遵循不同认证方式、暴露不同数据结构——如果每个 Agent 都要硬编码对接所有这些服务,维护成本会指数级上升,版本升级变成噩梦,安全审计形同虚设。
agent-skills正是为解决这个问题而生。它不定义“技能该做什么”,而是定义“技能该怎么被识别、安装、配置、调用和卸载”。你可以把它类比成Linux 的.deb/.rpm包管理机制,但对象不是二进制程序,而是具备明确输入输出契约、可独立生命周期管理的 AI 能力单元。一个weather-skill不是写死在 Agent 代码里的函数,而是一个包含skill.yaml描述文件、invoke.py执行逻辑、schema.json输入校验规则、README.md使用说明的独立目录。它能被skills list查看,被skills install https://github.com/xxx/weather-skill下载,被skills configure weather-skill --api-key xxx设置密钥,最终被 Agent 在运行时按需加载、沙箱隔离、超时控制、错误重试。
这个设计直接回应了热搜词中反复出现的关键词:CLI(命令行是技能管理最自然的入口)、slash commands(如/weather Beijing是技能调用的用户侧表达)、API(所有技能最终都需对接外部服务,但agent-skills层屏蔽了底层差异)、zcode cli/codex cli/boos cli(这些工具本质都是agent-skills协议的 CLI 实现者)。它不是某个厂商的私有方案,而是一种事实标准——当你看到claude agent skills: a first principles deep dive这样的热帖,讨论的正是这套协议的设计哲学:最小可行契约、零信任执行环境、开发者友好元数据、与现有 DevOps 流程无缝集成。
提示:不要把
agent-skills当成一个“库”去pip install。它更像一套规范文档 + 一组参考实现(CLI 工具 + SDK)。你真正需要的,是理解它的三个核心契约:技能描述契约(what)、执行契约(how)、安全契约(when & under what constraints)。后面章节将逐层拆解这三个契约在真实项目中的落地细节。
2. 技能描述契约:skill.yaml是技能世界的身份证与说明书
一个技能要被agent-skills生态识别和管理,第一步不是写代码,而是写好skill.yaml。这不是可有可无的配置文件,而是整个技能生命周期的唯一权威元数据源。它决定了这个技能能否被发现、是否兼容当前 Agent 版本、需要哪些权限、如何被用户调用、以及失败时该如何提示。忽略它的严谨性,等于给后续所有环节埋下雷区。
我们以一个真实的github-pr-review-skill为例,展示一份生产级skill.yaml的关键字段及其设计逻辑:
# skill.yaml name: github-pr-review version: "1.3.0" description: "自动分析 GitHub Pull Request 中的代码变更,生成结构化评审意见,支持指定语言规则" author: "devops-team@company.com" homepage: "https://github.com/company/github-pr-review-skill" license: "Apache-2.0" # 核心契约:定义技能能做什么、接受什么、返回什么 interface: # 用户触发方式:支持 slash command 和自然语言意图匹配 triggers: - type: slash-command name: /review-pr description: "对当前 PR 进行深度代码评审" - type: intent name: "review this pull request" confidence-threshold: 0.85 # 输入契约:严格定义用户或 Agent 传入的数据结构 input-schema: type: object properties: pr_url: type: string format: uri description: "GitHub Pull Request 的完整 URL,例如 https://github.com/owner/repo/pull/123" review_rules: type: array items: type: string enum: ["security", "performance", "style", "test-coverage"] default: ["security", "performance"] required: [pr_url] # 输出契约:定义技能执行后返回的标准结构,便于 Agent 统一渲染 output-schema: type: object properties: summary: type: string description: "本次评审的总体结论,如 '高风险,建议阻断合并'" findings: type: array items: type: object properties: file_path: type: string line_number: type: integer severity: type: string enum: ["critical", "high", "medium", "low"] message: type: string suggestion: type: string raw_response: type: object description: "原始 API 响应体,供高级用户调试" # 运行约束:告诉 Agent 这个技能需要什么才能安全运行 runtime: # 最小 Agent 版本要求,避免因 API 变更导致崩溃 min-agent-version: "2.7.0" # 所需系统能力,Agent 启动时会检查并拒绝加载缺失能力的技能 required-capabilities: - http-client - json-parser - environment-variable-access # 显式声明所需环境变量,避免运行时密钥缺失 required-env-vars: - GITHUB_TOKEN - DEEPSEEK_API_KEY # 安全策略:定义技能的执行边界 security: # 沙箱网络策略:只允许访问特定域名,禁止 DNS 泄露 allowed-domains: - api.github.com - api.deepseek.com # 最大执行时间,防止无限循环或慢响应拖垮 Agent timeout-ms: 120000 # 内存限制(单位 MB),防止单个技能耗尽资源 memory-limit-mb: 256 # 构建与分发信息 build: # 指定主执行文件,Agent 加载时会执行此脚本 entrypoint: "invoke.py" # 依赖列表,Agent 会在安装时自动处理 dependencies: - "requests>=2.28.0" - "pydantic>=2.0.0"这份skill.yaml的设计逻辑远不止于“填空”。每一个字段都服务于一个具体问题:
triggers字段解决了用户触达路径混乱的问题。很多团队早期让技能只响应/command,结果用户记不住命令,或者用自然语言提问时技能无法响应。agent-skills强制要求同时定义slash-command和intent,意味着技能必须提供两种入口,并且intent的confidence-threshold参数迫使开发者思考:我的 NLU 模型在什么置信度下才该触发这个技能?低于阈值时,是静默忽略,还是返回“我还不太确定,您能说得更具体些吗?”——这直接影响用户体验。input-schema和output-schema采用 JSON Schema 规范,而非简单文字描述。这带来两个关键好处:第一,Agent 可以在调用前进行静态参数校验,比如用户传入pr_url: "not-a-url",Agent 会直接返回结构化错误,而不是让技能内部抛出ValueError;第二,前端 UI(如 Web Chat 界面)可以基于input-schema自动生成表单,用户无需记忆参数格式,只需填空即可。required-env-vars和allowed-domains是安全契约的基石。热搜词中频繁出现的permission denied while trying to connect to the docker api、choosemedia:fail api scope is not declared in the privacy agreement等错误,根源往往是技能在未声明的情况下尝试访问敏感资源。agent-skills要求所有外部依赖必须显式声明,Agent 启动时会做白名单校验,任何未声明的os.environ.get("SECRET_KEY")或requests.get("http://192.168.1.100/api")都会被拦截并记录审计日志。timeout-ms和memory-limit-mb直接回应了api error: 400 this model's maximum context length is 1048576 tokens这类超长上下文错误。当技能调用 LLM API 时,如果未设置合理超时,可能因网络抖动或模型响应缓慢导致整个 Agent 卡死。agent-skills将资源约束下沉到技能层,确保单个技能故障不会引发雪崩。
注意:
skill.yaml必须放在技能根目录,且文件名固定。Agent 在扫描技能目录时,会首先查找此文件。如果缺失或格式错误,该技能会被直接忽略,不会进入安装队列。我见过太多团队因为version字段写成"v1.3.0"(带v前缀)导致skills install失败,错误信息却是模糊的invalid version format。经验是:所有版本号严格遵循语义化版本(SemVer)规范,不加前缀。
3. 执行契约:invoke.py如何在沙箱中安全、可靠地完成任务
skill.yaml定义了“是什么”和“能做什么”,而invoke.py(或其他语言的主入口文件)则定义了“怎么做”。但agent-skills对invoke.py的要求远超普通脚本:它必须是一个可预测、可审计、可中断、可重试的确定性过程。任何副作用(如修改全局状态、写入本地文件、启动后台线程)都是被禁止的。这听起来严苛,却是保障多技能共存、Agent 稳定性的唯一路径。
我们继续以github-pr-review-skill的invoke.py为例,剖析其核心结构与设计哲学:
#!/usr/bin/env python3 # invoke.py - agent-skills 执行契约的参考实现 import os import sys import json import time import logging import requests from typing import Dict, Any, Optional from pydantic import BaseModel, ValidationError # 初始化日志,所有输出将被 Agent 拦截并结构化 logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", handlers=[logging.StreamHandler(sys.stdout)] ) logger = logging.getLogger("github-pr-review") class SkillInput(BaseModel): """严格遵循 skill.yaml 中 input-schema 的 Pydantic 模型""" pr_url: str review_rules: list[str] = ["security", "performance"] class SkillOutput(BaseModel): """严格遵循 skill.yaml 中 output-schema 的 Pydantic 模型""" summary: str findings: list[dict] raw_response: dict def validate_environment() -> None: """强制执行环境校验,对应 skill.yaml 中 required-env-vars""" required_vars = ["GITHUB_TOKEN", "DEEPSEEK_API_KEY"] for var in required_vars: if not os.getenv(var): raise RuntimeError(f"Required environment variable '{var}' is missing") def extract_pr_info(pr_url: str) -> Dict[str, Any]: """从 GitHub URL 解析 owner/repo/pr_number,这是安全的第一步""" try: # 仅允许 github.com 域名,且必须是标准 PR URL 格式 if not pr_url.startswith("https://github.com/"): raise ValueError("Invalid GitHub URL format") parts = pr_url.strip("/").split("/") if len(parts) < 5 or parts[4] != "pull": raise ValueError("URL does not point to a Pull Request") return { "owner": parts[3], "repo": parts[4], "pr_number": int(parts[5]) } except (ValueError, IndexError, TypeError) as e: raise ValueError(f"Failed to parse PR URL: {e}") def fetch_pr_diff(owner: str, repo: str, pr_number: int, token: str) -> str: """安全调用 GitHub API 获取 diff,使用预设的 allowed-domains 白名单""" headers = {"Authorization": f"token {token}"} url = f"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}" # Agent 会在此处注入网络代理和超时控制,脚本无需自己处理 response = requests.get(url, headers=headers, timeout=30) response.raise_for_status() data = response.json() # 仅提取 diff_url,避免下载整个 PR 数据 if not data.get("diff_url"): raise RuntimeError("PR does not have a diff URL") return data["diff_url"] def call_deepseek_llm(diff_content: str, rules: list[str]) -> Dict[str, Any]: """调用 DeepSeek API,注意:API Key 来自环境变量,非硬编码""" api_key = os.getenv("DEEPSEEK_API_KEY") headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} payload = { "model": "deepseek-coder:33b", "messages": [ { "role": "system", "content": f"You are a senior code reviewer. Analyze the following git diff and generate review comments based on these rules: {', '.join(rules)}. Return ONLY valid JSON with keys 'summary' and 'findings'." }, {"role": "user", "content": diff_content} ], "temperature": 0.1 } # Agent 会监控此请求的内存和 CPU 使用,超出 memory-limit-mb 会强制终止 response = requests.post("https://api.deepseek.com/v1/chat/completions", headers=headers, json=payload, timeout=90) response.raise_for_status() return response.json() def main() -> None: """agent-skills 的标准入口函数,必须命名为 main()""" try: # 1. 读取 stdin 的 JSON 输入(由 Agent 注入) input_json = sys.stdin.read().strip() if not input_json: raise ValueError("No input provided") # 2. 解析并校验输入(强类型保证) input_data = SkillInput.model_validate_json(input_json) # 3. 执行环境校验 validate_environment() # 4. 核心业务逻辑:解析 URL -> 获取 diff -> 调用 LLM -> 结构化输出 pr_info = extract_pr_info(input_data.pr_url) diff_url = fetch_pr_diff(pr_info["owner"], pr_info["repo"], pr_info["pr_number"], os.getenv("GITHUB_TOKEN")) # 注意:这里不直接下载 diff,而是将 diff_url 传给 LLM,减少中间数据传输 llm_result = call_deepseek_llm(diff_url, input_data.review_rules) # 5. 构建符合 output-schema 的输出 output = SkillOutput( summary=llm_result.get("choices", [{}])[0].get("message", {}).get("content", "No summary generated"), findings=[], raw_response=llm_result ) # 6. 输出到 stdout,Agent 会捕获并结构化处理 print(output.model_dump_json()) except ValidationError as e: # Pydantic 校验失败,返回结构化错误 error_msg = f"Input validation failed: {e}" logger.error(error_msg) print(json.dumps({"error": error_msg})) except requests.exceptions.Timeout: logger.error("API request timed out") print(json.dumps({"error": "Request to external service timed out"})) except Exception as e: logger.exception("Unexpected error occurred") print(json.dumps({"error": f"Internal error: {str(e)}"})) if __name__ == "__main__": main()这段代码体现了agent-skills执行契约的三大支柱:
第一支柱:输入/输出的强类型契约。SkillInput和SkillOutput类直接映射skill.yaml中的input-schema和output-schema。Pydantic 的model_validate_json()方法不仅做类型检查,还执行格式校验(如pr_url是否为合法 URI)、范围校验(如review_rules是否在枚举列表内)。这意味着,即使用户通过 CLI 传入了错误参数,错误也会在技能执行最开始就被捕获,并返回清晰的{"error": "Input validation failed: ...}",而不是让技能内部逻辑崩溃。
第二支柱:环境与资源的显式依赖。所有外部依赖(GITHUB_TOKEN,DEEPSEEK_API_KEY)都通过os.getenv()获取,且在validate_environment()中集中校验。这杜绝了“密钥缺失导致技能静默失败”的常见陷阱。更重要的是,fetch_pr_diff和call_deepseek_llm函数中,URL 是硬编码的字符串(api.github.com,api.deepseek.com),这与skill.yaml中的allowed-domains白名单完全一致。Agent 的沙箱运行时会拦截所有非白名单域名的网络请求,因此即使技能代码被恶意篡改,也无法绕过此限制。
第三支柱:副作用隔离与可观测性。整个invoke.py没有open()文件操作、没有threading.Thread、没有sys.exit()。所有日志都通过logging模块输出到stdout,由 Agent 统一收集、打标、存储。所有错误都通过print(json.dumps({"error": ...}))返回结构化错误,而非抛出未捕获异常。这种设计让 Agent 能够精确知道技能的执行状态:成功、输入错误、API 超时、内部异常——每种状态都有对应的处理策略(重试、降级、告警)。
实操心得:
invoke.py的main()函数必须是唯一的入口点,且不能有参数。Agent 会通过stdin注入 JSON 输入,通过stdout读取 JSON 输出。我曾遇到一个技能因在main()外部定义了全局变量并初始化数据库连接,导致每次调用都新建连接,最终耗尽 MySQL 连接池。教训是:所有初始化逻辑(如logging.basicConfig)必须放在main()内部,或在if __name__ == "__main__":块中,确保每次执行都是干净的进程。
4. 安全契约:沙箱、白名单与审计日志如何构筑最后一道防线
agent-skills的最大价值,不在于它让技能开发变简单,而在于它让技能运行变安全。在热搜词中反复出现的minimax cli、智谱api、海康威视api接口、permission denied while trying to connect to the docker api等,无不指向同一个痛点:当一个 Agent 需要集成数十个第三方 API 时,如何确保其中任何一个技能的漏洞(如 SSRF、命令注入、密钥泄露)不会危及整个系统?agent-skills的答案是:不信任任何技能,用沙箱、白名单、审计日志三重机制,将风险控制在单个技能的边界内。
4.1 进程级沙箱:每个技能都在独立容器中运行
agent-skills的参考实现(如zcode cli或codex cli)默认使用bubblewrap(bwrap)或firejail创建轻量级 Linux 命名空间沙箱。这不是 Docker 容器,而是更底层的clone()系统调用,开销极小(毫秒级启动),但隔离性足够强。一个技能进程的沙箱配置大致如下:
# bwrap 命令示例(由 Agent 自动构造) bwrap \ --unshare-pid \ --unshare-net \ --ro-bind /usr/lib/python3.11 /usr/lib/python3.11 \ --ro-bind /lib/x86_64-linux-gnu /lib/x86_64-linux-gnu \ --bind /tmp/skill-workdir /tmp \ --proc /proc \ --dev /dev \ --setenv PATH "/usr/bin:/bin" \ --cap-drop ALL \ --seccomp-filter /path/to/seccomp.json \ --timeout 120 \ --rlimit-as 268435456 \ # 256MB 内存限制 python3 invoke.py这个命令创建了一个与宿主机几乎完全隔离的环境:
--unshare-net:启用独立网络命名空间,技能进程只能看到自己的网络栈。--ro-bind:只读挂载 Python 运行时和系统库,防止技能篡改基础环境。--bind:仅挂载一个临时工作目录/tmp/skill-workdir,技能无法访问宿主机其他路径。--cap-drop ALL:剥夺所有 Linux Capabilities(如CAP_NET_ADMIN),技能无法配置网络、挂载文件系统。--seccomp-filter:加载一个精简的 seccomp BPF 过滤器,只允许read,write,openat,close,getpid等必需系统调用,execve(执行新程序)、socket(创建 socket)等高危调用被直接拒绝。--timeout和--rlimit-as:强制执行skill.yaml中定义的超时和内存限制。
这意味着,即使一个技能的invoke.py中存在os.system("rm -rf /"),由于os.system依赖execve系统调用,而该调用已被 seccomp 过滤器拦截,进程会立即收到SIGSYS信号并退出,宿主机毫发无损。
4.2 网络白名单:allowed-domains是铁律,不是建议
skill.yaml中的allowed-domains字段,是agent-skills安全模型的核心。它不是一个简单的配置项,而是 Agent 网络栈的硬性防火墙规则。Agent 的网络代理组件(通常是一个嵌入式 HTTP 代理)会拦截所有技能进程发出的connect()系统调用,并与白名单比对:
| 技能请求的域名 | allowed-domains配置 | 结果 | 原因 |
|---|---|---|---|
api.github.com | ["api.github.com"] | ✅ 允许 | 完全匹配 |
raw.githubusercontent.com | ["api.github.com"] | ❌ 拒绝 | 子域名不匹配,白名单不支持通配符 |
192.168.1.100 | ["api.github.com"] | ❌ 拒绝 | IP 地址不在白名单中 |
github.com | ["api.github.com"] | ❌ 拒绝 | 主域名不匹配 |
这个机制直接解决了热搜词中choosemedia:fail api scope is not declared in the privacy agreement的根源问题。传统做法是让技能自己调用requests.get(),然后在应用层做域名校验。但恶意技能可以绕过requests,直接用socket.socket()建立 TCP 连接,或调用subprocess.Popen(["curl", "http://evil.com"])。agent-skills的网络白名单是在内核网络栈层面拦截,任何绕过requests的尝试都会失败。
4.3 审计日志:每一次技能调用都留下不可篡改的证据链
安全不仅是防御,更是追溯。agent-skills要求 Agent 必须记录详尽的审计日志,每条日志包含:
timestamp: 调用发生的时间(UTC)skill_name: 技能名称(来自skill.yaml)skill_version: 技能版本(来自skill.yaml)trigger_type: 触发方式(slash-command或intent)input_hash: 输入 JSON 的 SHA256 哈希(保护用户隐私,不记录原始输入)output_status: 执行结果(success,input_error,timeout,network_blocked,internal_error)duration_ms: 执行耗时(毫秒)memory_used_mb: 实际内存消耗(由cgroups统计)network_requests: 发出的网络请求数量及目标域名(仅记录白名单内的)
这些日志被写入一个只追加(append-only)的 WORM(Write Once Read Many)存储,例如一个加密的 SQLite 数据库或一个不可变的区块链账本。管理员可以通过skills audit --since "2024-05-01" --skill "github-pr-review"命令,快速检索某技能的所有调用记录。当出现api error: 400 this model's maximum context length is 1048576 tokens时,审计日志能立刻告诉你:是哪个版本的技能、在什么时间、对哪个 PR URL、消耗了多少 token(通过duration_ms和memory_used_mb间接推断),从而精准定位问题。
关键提醒:
agent-skills的安全契约是“零信任”,即默认拒绝一切,只允许明确声明的。这意味着,如果你的技能需要调用https://api.pdd.com/order(拼多多 API),你必须在skill.yaml中显式添加pdd.com到allowed-domains,并在required-env-vars中声明PDD_API_KEY。任何遗漏,都会导致技能在安装或运行时失败,并在审计日志中留下清晰的network_blocked记录。这不是 Bug,而是 Feature——它强迫开发者正视每一个外部依赖的安全影响。
5. CLI 工具链实战:从skills install到skills test的完整工作流
agent-skills的理念再先进,最终都要落到开发者每天敲的命令上。热搜词中高频出现的zcode cli、codex cli、boos cli、openspec cli,本质上都是agent-skills协议的不同 CLI 实现。它们共享同一套核心命令,但 UI 和扩展性各有侧重。下面以最通用的skillsCLI(参考实现)为例,带你走一遍从零开始开发、测试、发布一个技能的完整工作流。
5.1 环境准备:三步搭建本地开发沙箱
在开始写代码前,先确保你的开发环境满足agent-skills的最低要求。这不是简单的pip install,而是一套协同工作的组件:
安装
skillsCLI 工具# 推荐使用官方发布的静态二进制,避免 Python 环境冲突 curl -L https://github.com/agent-skills/cli/releases/download/v1.2.0/skills-linux-amd64 -o /usr/local/bin/skills chmod +x /usr/local/bin/skills skills --version # 应输出 v1.2.0安装
bubblewrap(Linux)或firejail(macOS)skillsCLI 依赖它们创建沙箱。Ubuntu/Debian 用户:sudo apt update && sudo apt install -y bubblewrapmacOS 用户(需 Homebrew):
brew install firejail配置本地技能仓库(可选但强烈推荐)
创建一个目录作为你的私有技能市场,用于存放和测试本地开发的技能:mkdir -p ~/my-skills echo "file:///home/$(whoami)/my-skills" > ~/.skills-repos # 这样 skills install 会优先搜索本地目录
注意:
node安装codex cli很慢这类热搜问题,根源在于npm install试图下载大量前端依赖。agent-skills的 CLI 是纯二进制,无 Node.js 依赖,安装速度极快。如果你看到codex cli安装慢,那很可能你安装的是一个 Web UI 前端,而非核心 CLI。
5.2 开发一个技能:skills init自动生成骨架
告别手动创建skill.yaml和invoke.py。skillsCLI 提供了init命令,一键生成符合规范的项目骨架:
# 在任意目录下执行 skills init my-first-skill # 生成的目录结构 my-first-skill/ ├── skill.yaml # 已填充基础字段,等待你编辑 ├── invoke.py # 已包含 main() 框架和日志模板 ├── README.md # 标准化文档模板 └── tests/ # 空的测试目录,供你添加单元测试现在,编辑skill.yaml,填写你的技能信息。重点修改:
name: 技能唯一标识(小写字母、数字、连字符)description: 清晰说明技能用途triggers: 至少定义一个slash-commandinput-schema和output-schema: 用 JSON Schema 描述你的数据契约runtime.required-env-vars: 列出所有密钥security.allowed-domains: 列出所有要访问的域名
5.3 本地测试:skills test模拟真实运行环境
写完代码,别急着skills install。先用skills test在沙箱中运行,这是最接近生产环境的测试方式:
# 进入技能目录 cd my-first-skill # 用模拟输入测试(输入 JSON 从 stdin 读取) echo '{"query": "What is the weather in Shanghai?"}' | skills test # 或者用文件输入(更方便调试复杂输入) echo '{"query": "What is the weather in Shanghai?"}' > test-input.json skills test --input test-input.json # 查看详细日志(包括沙箱启动、网络请求、内存使用) skills test --verboseskills test会:
- 自动检测
skill.yaml并验证其格式。 - 在真实的
bubblewrap沙箱中启动invoke.py。 - 将
--input的内容通过stdin注入。 - 捕获
stdout的 JSON 输出,并格式化显示。 - 记录沙箱的
duration_ms和memory_used_mb,并在终端输出。
如果测试失败,skills test --verbose会显示完整的沙箱启动命令和错误日志,让你精准定位是skill.yaml错误、环境变量缺失,还是invoke.py逻辑 bug。
5.4 安装与配置:skills install和skills configure的协作
测试通过后,就可以安装到你的 Agent 环境中了:
# 从本地目录安装(开发阶段) skills install ./my-first-skill # 从 GitHub 安装(发布后) skills install https://github.com/yourname/my-first-skill # 查看已安装技能 skills list # 配置必需的环境变量(如 API Key) skills configure my-first-skill --api-key "sk-xxxxx" # 这会将密钥安全地存储在 Agent 的密钥环中,而非明文写入文件skills install的核心动作是:
- 下载技能目录(Git clone 或 tarball 解压)。
- 验证
skill.yaml的签名(如果启用了 GPG 签名)。 - 检查
min-agent-version是否兼容。 - 将技能复制到 Agent 的技能库目录(如
~/.agent-skills/my-first-skill)。 - 不执行
pip install!所有依赖由invoke.py在沙箱内按需安装(通过pip install --target到沙箱临时目录),确保依赖隔离。
5.5 运行与调试:skills run和skills logs的组合技
安装配置完成后,即可运行:
# 通过 slash command 触发(最常用) skills run /my-first-skill --query "What is the weather in Shanghai?" # 或者直接调用技能名(跳过 trigger 匹配) skills run my-first-skill --query "What is the weather in Shanghai?" # 查看最近 10 条执行日志(结构化输出) skills logs --limit 10 # 查看某个技能的详细日志 skills logs --skill my-first-skill --since "1 hour ago"skills logs是调试神器。当你的技能在生产环境报错api error: 400 this model's maximum context length is 1048576 tokens时,skills logs --skill my-first-skill --tail会立刻告诉你:
- 是哪次调用失败(
output_status: internal_error) - 调用耗时多久(
duration_ms: 118200,接近 2 分钟超时) - 内存消耗多少(
memory_used_mb: 245,接近 256MB 限制) - 网络请求了哪些域名(
network_requests: [{"domain": "api.deepseek.com", "count": 1}])
结合这些信息,你就能判断:是 LLM API 响应太慢,还是技能处理逻辑有死循环,或是invoke.py中的timeout参数设置不合理。
实操避坑:
skills install后,技能并不会自动启用。你必须通过skills enable my-first-skill显式启用。禁用则用skills disable。这个开关机制让你可以在不影响其他技能的情况下,灰度上线新版本。我曾因忘记enable,导致新技能一直不生效,