关于 dynamic-api-integration
面向 Agent 的提示驱动 Skill,指导其在运行时发现并调用外部 HTTP REST API。它通过 API 规范或手动模板选择端点、构造请求、验证响应,并在安全限制下串联调用。
主要功能
- 01从 OpenAPI 规范发现端点
- 02将意图匹配到 API 端点
- 03构造带认证的 HTTP 请求
- 04使用 curl 或 WebFetch 执行调用
- 05验证响应并串联调用
适用场景
- 01探索不熟悉的 REST API
- 02依据提供的 API 规范提取数据
- 03串联搜索与详情请求
- 04处理 API 认证和分页
MCP 相关
此 Skill 用于尚未封装为 MCP 工具的 API;如果 API 已有 MCP 封装,则建议直接使用 MCP 工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ oimiragieo/ agent-studio --skill dynamic-api-integration安装后在 Claude Code 中输入/dynamic-api-integration确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
commands/dynamic-api-integration.mdhooks/post-execute.cjspre-execute.cjsreferences/research-requirements.mdrules/dynamic-api-integration.mdschemas/input.schema.jsonoutput.schema.jsonscripts/main.cjstemplates/implementation-template.md详细介绍
模式:认知式/提示词驱动 — 没有独立的实用脚本;需通过 Agent 上下文使用。
动态 API 集成
概述
此技能将教 Agent 如何在运行时动态发现、解析并调用外部 HTTP API。它改编自 Universal Tool Calling Protocol (UTCP) 模式,并转换为 Node.js / Claude Code 工具模式。
核心工作流(5 个阶段,灵感来自 UTCP Agent 状态机):
- 发现 — 获取并解析 OpenAPI/Swagger 规范(或定义手动工具模板)。
- 匹配 — 将用户意图在语义上匹配到合适的 API 端点。
- 构造 — 使用正确的方法、路径、参数、标头、请求体和身份验证构造 HTTP 请求。
- 执行 — 通过 Bash(curl)或 WebFetch 调用 API 并捕获响应。
- 串联 — 如果任务尚未完成,则重新分析并执行另一次调用(最多 max_iterations 次)。
适用场景
在以下情况下使用此技能:
- Agent 需要调用一个此前未使用过的外部 REST API
- 用户提供 API URL 或 OpenAPI 规范 URL,并希望提取数据
- Agent 必须先从规范中发现可用端点,再选择要调用的端点
- 需要迭代串联多次 API 调用(搜索 -> 获取详情 -> 筛选)
- Agent 需要构造包含身份验证和参数的 HTTP 请求
请勿在以下情况下使用:
- API 已封装为 MCP 工具(直接使用 MCP 工具)
- 集成只是一次性硬编码调用(直接使用 Bash curl)
- API 需要通过用户交互式重定向完成 OAuth 2.0 授权码流程
- API 使用 WebSocket 或仅支持流式传输的协议(而非 HTTP REST)
铁律
- 绝不在请求、curl 命令或源文件中硬编码 API 密钥、令牌或机密信息 — 始终使用环境变量(
$ENV_VAR)或机密管理器。 - 始终先发现 API 规范(OpenAPI/Swagger),再编写任何集成代码 — 在没有规范依据的情况下猜测端点结构,会导致集成无法正常工作。
- 绝不跳过 API 列表响应的分页处理 — 假设结果只有一页,会在数据集超过页面上限时悄无声息地丢失数据。
- 始终为瞬态故障(429、503)实现带指数退避的重试逻辑 — 动态 API 天生不可靠;没有重试机制的集成在正常的生产环境中会失败。
- 绝不在使用 API 响应前跳过对每个响应结构的验证 — 动态 API 的结构可能在不另行通知的情况下发生变化;未经验证的响应会导致调用方运行时崩溃。
阶段 1:发现 — 获取并解析 API 规范
选项 A:发现 OpenAPI/Swagger 规范
当 API 提供 OpenAPI 规范时(大多数现代 API 都会提供):
# Step 1: Fetch the OpenAPI spec
WebFetch({
url: "https://api.example.com/openapi.json",
prompt: "Extract all API endpoints. For each endpoint, list: HTTP method, path, description, required parameters, optional parameters, authentication requirement. Return as a structured list."
})
从规范中提取的内容:
| 字段 | 规范中的位置 | 用途 |
|---|---|---|
| 基础 URL | servers[0].url | 所有请求的 API 根地址 |
| 端点 | paths.* | 可用操作 |
| 方法 | paths.*.get/post/put/delete | 每个端点的 HTTP 方法 |
| 参数 | paths.*.*.parameters[] | 查询、路径、标头参数 |
| 请求体 | paths.*.*.requestBody | POST/PUT 负载结构 |
| 身份验证 | components.securitySchemes | API 密钥、Bearer、OAuth |
| 响应结构 | paths.*.*.responses.200 | 预期的响应格式 |
常见的 OpenAPI 规范位置:
https://api.example.com/openapi.jsonhttps://api.example.com/swagger.jsonhttps://api.example.com/v3/api-docshttps://api.example.com/.well-known/openapi.jsonhttps://api.example.com/docs(HTML 页面可能会链接到规范)
选项 B:手动工具模板(无可用规范时)
当不存在 OpenAPI 规范时,可手动定义工具模板:
{
"name": "search_books",
"description": "Search Open Library for books by query",
"base_url": "https://openlibrary.org/search.json",
"method": "GET",
"auth": null,
"parameters": {
"q": {
"type": "string",
"required": true,
"in": "query",
"description": "Search query (title, author, ISBN)"
},
"limit": {
"type": "integer",
"required": false,
"in": "query",
"description": "Max results to return (default 10)"
},
"page": {
"type": "integer",
"required": false,
"in": "query",
"description": "Page number for pagination"
}
},
"response_hint": "Returns { numFound, docs: [{ title, author_name, first_publish_year }] }"
}
工具模板 JSON Schema
工具模板格式(灵感来自 UTCP manual_call_templates):
{
"name": "string (required) — unique tool identifier, lowercase_snake_case",
"description": "string (required) — what this tool does, used for semantic matching",
"base_url": "string (required) — full URL including path",
"method": "string (required) — GET | POST | PUT | PATCH | DELETE",
"content_type": "string (optional) — default: application/json",
"auth": {
"type": "string — api_key | bearer | basic | none",
"header": "string — header name (e.g., X-Api-Key, Authorization)",
"env_var": "string — environment variable name holding the secret",
"prefix": "string (optional) — e.g., 'Bearer ' for bearer auth"
},
"parameters": {
"<param_name>": {
"type": "string | integer | boolean | array | object",
"required": "boolean",
"in": "query | path | header | body",
"description": "string — what this parameter does",
"default": "any (optional) — default value if not provided"
}
},
"response_hint": "string (optional) — brief description of response shape"
}
第 2 阶段:匹配 — 将语义意图映射到端点
调用 API 之前,将用户意图与正确的端点匹配:
第 1 步:了解用户的目标
问问自己:用户想要什么数据?他们希望执行什么操作?
第 2 步:将意图映射到端点
| 用户意图 | 可能的 HTTP 方法 | 端点模式 |
|---|---|---|
| “查找 / 搜索 / 列出 / 获取” | GET | /search、/list、/{resource} |
| “创建 / 添加 / 注册” | POST | /{resource} |
| “更新 / 修改 / 更改” | PUT 或 PATCH | /{resource}/{id} |
| “删除 / 移除” | DELETE | /{resource}/{id} |
| “获取有关 X 的详细信息” | GET | /{resource}/{id} |
第 3 步:选择参数
- 必需参数: 必须提供(检查规范/模板中的
required: true)。 - 可选参数: 仅在用户指定或有助于改善结果时使用。
- 路径参数: 替换到 URL 中(例如,
/repos/{owner}/{repo})。 - 查询参数: 以
?key=value&key2=value2的形式追加。 - 请求体参数: 在 POST/PUT/PATCH 中以 JSON 负载发送。
第 3 阶段:构造 — 构建 HTTP 请求
请求构造检查清单
- URL: 基础 URL + 路径 + 路径参数替换
- 方法: GET、POST、PUT、PATCH、DELETE
- 标头: Content-Type、Authorization、Accept、自定义标头
- 查询参数: 进行 URL 编码后追加到 URL
- 请求体: POST/PUT/PATCH 的 JSON 负载
- 身份验证: 从环境变量注入
身份验证模式
API Key(标头):
curl -s -X GET "https://api.example.com/data?q=test" \
-H "X-Api-Key: $API_KEY"
Bearer Token:
curl -s -X GET "https://api.example.com/data" \
-H "Authorization: Bearer $AUTH_TOKEN"
Basic Auth:
curl -s -X GET "https://api.example.com/data" \
-u "$USERNAME:$PASSWORD"
无需身份验证(公共 API):
curl -s -X GET "https://api.example.com/data?q=test"
各方法的请求模板
带查询参数的 GET:
curl -s -X GET "https://api.example.com/search?q=test&limit=10&page=1" \
-H "Accept: application/json" \
-H "Authorization: Bearer $TOKEN"
带 JSON 请求体的 POST:
curl -s -X POST "https://api.example.com/items" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name": "New Item", "category": "tools", "price": 29.99}'
带路径参数的 PUT:
curl -s -X PUT "https://api.example.com/items/123" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name": "Updated Item", "price": 39.99}'
DELETE:
curl -s -X DELETE "https://api.example.com/items/123" \
-H "Authorization: Bearer $TOKEN"
第 4 阶段:执行 — 调用 API 并处理响应
使用 Bash(curl)——首选方法
# Execute and capture response + HTTP status
RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "https://api.example.com/search?q=test" \
-H "Accept: application/json")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
echo "Status: $HTTP_CODE"
echo "Body: $BODY" | head -c 2000 # Truncate to 2KB for context safety
使用 WebFetch——需要 AI 处理时
WebFetch({
url: 'https://api.example.com/search?q=test',
prompt:
'Extract the top 5 results with their titles and descriptions. Format as a numbered list.',
});
何时使用哪种方式:
| 场景 | 工具 | 原因 |
|---|---|---|
| 需要原始 JSON 以便进一步处理 | Bash(curl) | 完全可控,输出可解析 |
| 需要摘要/提取后的数据 | WebFetch | AI 可内联处理响应 |
| 需要检查 HTTP 状态码 | Bash(curl) | WebFetch 会隐藏状态信息 |
| 响应较大(>50KB) | Bash(curl)+ 截断 | WebFetch 处理大页面时可能超时 |
| HTML 页面(非 JSON) | WebFetch | 将 HTML 转换为 Markdown |
错误处理
HTTP 状态码处理:
| 状态 | 含义 | 操作 |
|---|---|---|
| 200-299 | 成功 | 解析响应并继续 |
| 400 | 请求错误 | 检查参数,修正后重试 |
| 401 | 未授权 | 检查 API Key/Token,重新进行身份验证 |
| 403 | 禁止访问 | 检查权限并向用户报告 |
| 404 | 未找到 | 检查 URL/资源 ID,尝试其他端点 |
| 429 | 请求过多 | 等待(检查 Retry-After 标头),然后重试 |
| 500-599 | 服务器错误 | 等待并最多重试 3 次 |
使用指数退避重试:
# Retry pattern for transient errors (429, 5xx)
for attempt in 1 2 3; do
RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$URL" -H "Authorization: Bearer $TOKEN")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" -lt 400 ]; then
break # Success
fi
echo "Attempt $attempt failed ($HTTP_CODE), retrying in $((attempt * 2))s..."
sleep $((attempt * 2))
done
响应处理
解析 JSON 响应(Bash):
# Extract specific fields from JSON response
echo "$BODY" | node -e "
const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
console.log('Total:', data.totalResults);
data.items?.slice(0, 5).forEach((item, i) => {
console.log(\`\${i+1}. \${item.title} — \${item.description?.substring(0, 80)}\`);
});
"
截断大型响应:
# Safety: never pass >10KB of API response into context
BODY_TRUNCATED=$(echo "$BODY" | head -c 10000)
if [ ${#BODY} -gt 10000 ]; then
echo "[TRUNCATED: Response was $(echo "$BODY" | wc -c) bytes, showing first 10KB]"
fi
阶段 5:链式调用 — 迭代式多次调用工作流
许多任务需要将多次 API 调用串联起来。使用受 UTCP 启发的迭代模式:
链式调用模式
Iteration 1: Search -> Get list of results
Iteration 2: Get details for top result
Iteration 3: Perform action on result
(max_iterations guard: stop at 5)
迭代保护机制(必需)
MAX_ITERATIONS = 5
Before each API call:
IF iteration_count >= MAX_ITERATIONS:
STOP. Summarize what was gathered so far and respond.
ELSE:
Execute the call, increment counter, re-analyze task.
**为什么这很重要:**如果没有迭代保护机制,Agent 可能会不断循环调用 API。UTCP 的默认值为 3;对于更复杂的多步骤工作流,我们建议设为 5。
链式调用示例
示例 1:搜索并获取详情
User: "Find information about the book '1984' by George Orwell"
Iteration 1:
Call: GET https://openlibrary.org/search.json?q=1984+george+orwell&limit=5
Result: Found 5 matches, top result has key "/works/OL1168083W"
Iteration 2:
Call: GET https://openlibrary.org/works/OL1168083W.json
Result: Full book details (title, description, subjects, covers)
Task complete: Return summarized book information.
示例 2:GitHub — 查找并分析仓库
User: "What are the most recent issues in the react repository?"
Iteration 1:
Call: GET https://api.github.com/repos/facebook/react/issues?state=open&per_page=10&sort=created
Headers: Authorization: Bearer $GITHUB_TOKEN
Result: 10 most recent open issues
Task complete: Summarize issue titles, labels, and dates.
示例 3:多 API 链式调用
User: "Find news about AI safety and summarize the top article"
Iteration 1:
Call: GET https://newsapi.org/v2/everything?q=AI+safety&sortBy=publishedAt&pageSize=5
Headers: X-Api-Key: $NEWS_API_KEY
Result: 5 articles with titles, URLs
Iteration 2:
Call: WebFetch({ url: articles[0].url, prompt: "Summarize this article in 3 bullet points" })
Result: Article summary
Task complete: Return article title + summary.
真实 API 示例
GitHub API(Bearer Token 认证)
# List repositories for a user
curl -s -X GET "https://api.github.com/users/octocat/repos?sort=updated&per_page=5" \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $GITHUB_TOKEN"
工具模板:
{
"name": "github_list_repos",
"description": "List repositories for a GitHub user, sorted by most recently updated",
"base_url": "https://api.github.com/users/{username}/repos",
"method": "GET",
"auth": {
"type": "bearer",
"header": "Authorization",
"env_var": "GITHUB_TOKEN",
"prefix": "Bearer "
},
"parameters": {
"username": {
"type": "string",
"required": true,
"in": "path",
"description": "GitHub username"
},
"sort": {
"type": "string",
"required": false,
"in": "query",
"description": "Sort field: created, updated, pushed, full_name",
"default": "updated"
},
"per_page": {
"type": "integer",
"required": false,
"in": "query",
"description": "Results per page (max 100)",
"default": 10
}
}
}
Open Library API(无需认证)
# Search for books
curl -s -X GET "https://openlibrary.org/search.json?q=george+orwell&limit=5" \
-H "Accept: application/json"
JSONPlaceholder(测试/原型开发)
# GET all posts
curl -s https://jsonplaceholder.typicode.com/posts?_limit=5
# POST new item
curl -s -X POST https://jsonplaceholder.typicode.com/posts \
-H "Content-Type: application/json" \
-d '{"title": "Test Post", "body": "Hello world", "userId": 1}'
Weather API(API Key 认证)
# Get current weather
curl -s "https://api.open-meteo.com/v1/forecast?latitude=51.5074&longitude=-0.1278¤t_weather=true"
大型响应的上下文管理
API 响应可能非常大。请遵循以下规则,以避免上下文溢出:
响应大小限制
| 响应大小 | 操作 |
|---|---|
| < 5 KB | 使用完整响应 |
| 5-20 KB | 仅提取相关字段 |
| 20-50 KB | 使用 WebFetch 或 node 脚本进行摘要 |
| > 50 KB | 截断为前 5KB + 统计剩余内容 |
提取模式(建议用于大型响应)
# Instead of dumping full response, extract what you need
curl -s "https://api.example.com/search?q=test" | node -e "
const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
// Extract only what the user asked for
const results = data.results.slice(0, 5).map(r => ({
id: r.id,
title: r.title,
summary: r.description?.substring(0, 200)
}));
console.log(JSON.stringify(results, null, 2));
"
安全检查清单
- 所有 API 密钥均存储在环境变量中(绝不写入代码/命令)
- 所有 API 调用均使用 HTTPS(经过身份验证的请求绝不使用 HTTP)
- 使用前验证响应数据(检查状态码)
- 不记录用户机密,也不将其写入文件
- 遵守速率限制(检查标头:X-RateLimit-Remaining)
- 不将敏感响应数据(个人身份信息、令牌)存储在记忆文件中
- 为所有请求设置超时(
curl --max-time 30)
验证检查清单
完成动态 API 集成任务之前:
- 已获取 API 规范并确定端点
- 已将用户意图对应到正确的端点和方法
- 请求包含适当的身份验证(如有要求)
- 请求参数符合 API 架构(包含必需参数)
- 已检查 HTTP 状态码并处理错误
- 如果响应超过 5KB,已对其进行截断/摘要
- 迭代次数未超过 max_iterations(5)
- 没有在任何命令或文件中硬编码 API 密钥
反模式(避免)
| 反模式 | 失败原因 | 正确做法 |
|---|---|---|
| 硬编码 API 密钥 | 有安全风险,密钥轮换后会失效 | 在所有命令中使用 $ENV_VAR |
| 未先阅读规范就调用 API | 端点错误、参数错误 | 先发现 API(阶段 1) |
| 将完整的 100KB 响应传入上下文 | 上下文溢出、性能下降 | 截断/提取(阶段 4) |
| 链式调用不设置迭代保护机制 | 无限循环消耗令牌 | 始终强制执行 max_iterations |
| 猜测参数名称 | 导致 400 错误,浪费调用 | 构造请求前阅读规范/文档 |
| 忽略 HTTP 错误码 | 静默失败、结果错误 | 检查状态并处理 4xx/5xx |
| 正确方法应为 GET 时却使用 POST | API 拒绝请求或创建非预期资源 | 根据意图匹配方法(阶段 2) |
快速参考卡
DISCOVER → WebFetch(spec_url) or define manual tool template
MATCH → Map user intent to endpoint + method + params
CONSTRUCT → Build curl command with URL, headers, auth, body
EXECUTE → Bash(curl) for JSON, WebFetch for HTML/summarize
CHAIN → Re-analyze task, call again (max 5 iterations)
认证快速参考:
API Key: -H "X-Api-Key: $KEY"
Bearer: -H "Authorization: Bearer $TOKEN"
Basic: -u "$USER:$PASS"
None: (no auth header needed)
快速创建工具模板:
{
"name": "...",
"description": "...",
"base_url": "...",
"method": "GET",
"auth": { "type": "api_key", "header": "...", "env_var": "..." },
"parameters": { "q": { "type": "string", "required": true, "in": "query" } }
}
研究依据
此技能改编自:
- 通用工具调用协议(UTCP) — 面向 AI Agent 工具调用的开放标准
- UTCP Agent — 基于 LangGraph 的参考实现
- UTCP 规范 — RFC 和协议定义
- OpenAPI 规范 3.1 — API 描述标准
- OpenAPI 最佳实践 — 社区指南
- agents.json 规范 — API-Agent 契约标准
- API 集成模式(2026) — 模式分类
相关技能
auth-security-expert— OAuth 2.1、JWT、加密模式nodejs-expert— Node.js HTTP 模式debugging— API 调用失败调查research-synthesis— 集成前调研新 API
记忆协议
开始前:
阅读 .claude/context/memory/learnings.md
完成后:
- 发现新的 API 模式 ->
.claude/context/memory/learnings.md - 发现 API 问题或限制 ->
.claude/context/memory/issues.md - 做出 API 设计决策 ->
.claude/context/memory/decisions.md - 创建可复用的工具模板 -> 保存到
.claude/context/memory/named/api-templates.md
假设工作可能会中断:如果内容不在记忆中,就等于从未发生。