name: dynamic-api-integration description: 在运行时使用OpenAPI规范、工具模板和迭代链式调用,发现、解析和调用外部HTTP API。基于UTCP(通用工具调用协议)模式,适用于Node.js和Claude Code代理。 version: 1.0.0 model: sonnet invoked_by: both user_invocable: true tools: [Read, Write, Edit, Bash, WebFetch, WebSearch] best_practices:
- 在构建请求之前,始终获取并验证OpenAPI规范
- 所有API密钥和机密使用环境变量;切勿硬编码
- 应用最大迭代次数防护,防止无限API调用循环
- 截断或总结大型API响应,以保持在上下文预算内
- 在调用前,语义匹配用户意图到API端点
- 对临时失败显式处理错误,包含重试逻辑 error_handling: strict streaming: supported
模式:认知/提示驱动 — 无独立实用脚本;通过代理上下文使用。
动态API集成
概述
这个技能教导代理如何在运行时动态发现、解析和调用外部HTTP API。它基于通用工具调用协议(UTCP)模式,转换为Node.js / Claude Code工具模式。
核心工作流程(5阶段,受UTCP代理状态机启发):
- 发现 — 获取并解析OpenAPI/Swagger规范(或定义手动工具模板)。
- 匹配 — 语义映射用户意图到正确的API端点。
- 构建 — 构建HTTP请求,包含正确的方法、路径、参数、头部、正文和认证。
- 执行 — 通过Bash(curl)或WebFetch调用API并捕获响应。
- 链式 — 如果任务未完成,重新分析并执行另一个调用(最多到最大迭代次数)。
何时使用
使用此技能时:
- 代理需要调用之前未使用的外部REST API
- 用户提供API URL或OpenAPI规范URL,并希望提取数据
- 代理必须在选择调用之前从规范中发现可用端点
- 多个API调用需要迭代链式调用(搜索 -> 获取详情 -> 过滤)
- 代理需要构建带有认证和参数的HTTP请求
不要使用时:
- API已封装为MCP工具(直接使用MCP工具)
- 集成是一次性硬编码调用(直接使用Bash curl)
- API需要OAuth 2.0授权码流程,涉及用户交互重定向
- API使用WebSocket或仅流式协议(非HTTP REST)
铁律
切勿在请求中硬编码API密钥 — 仅使用环境变量
如果发现自己在curl命令中键入API密钥,请停止。使用$ENV_VAR语法。
阶段1:发现 — 获取并解析API规范
选项A:OpenAPI/Swagger规范发现
当API提供OpenAPI规范时(大多数现代API提供):
# 步骤1:获取OpenAPI规范
WebFetch({
url: "https://api.example.com/openapi.json",
prompt: "提取所有API端点。为每个端点列出:HTTP方法、路径、描述、必需参数、可选参数、认证要求。返回为结构化列表。"
})
从规范中提取的内容:
| 字段 | 规范中的位置 | 目的 |
|---|---|---|
| 基础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": "通过查询搜索Open Library中的书籍",
"base_url": "https://openlibrary.org/search.json",
"method": "GET",
"auth": null,
"parameters": {
"q": {
"type": "string",
"required": true,
"in": "query",
"description": "搜索查询(标题、作者、ISBN)"
},
"limit": {
"type": "integer",
"required": false,
"in": "query",
"description": "返回的最大结果数(默认10)"
},
"page": {
"type": "integer",
"required": false,
"in": "query",
"description": "分页的页码"
}
},
"response_hint": "返回 { numFound, docs: [{ title, author_name, first_publish_year }] }"
}
工具模板JSON架构
工具模板格式(受UTCP manual_call_templates启发):
{
"name": "string (必需) — 唯一工具标识符,小写下划线形式",
"description": "string (必需) — 此工具的功能,用于语义匹配",
"base_url": "string (必需) — 包括路径的完整URL",
"method": "string (必需) — GET | POST | PUT | PATCH | DELETE",
"content_type": "string (可选) — 默认: application/json",
"auth": {
"type": "string — api_key | bearer | basic | none",
"header": "string — 头部名称(例如,X-Api-Key, Authorization)",
"env_var": "string — 存储机密的环境变量名称",
"prefix": "string (可选) — 例如,'Bearer ' 用于bearer认证"
},
"parameters": {
"<param_name>": {
"type": "string | integer | boolean | array | object",
"required": "boolean",
"in": "query | path | header | body",
"description": "string — 此参数的作用",
"default": "any (可选) — 未提供时的默认值"
}
},
"response_hint": "string (可选) — 响应形状的简要描述"
}
阶段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密钥(头部):
curl -s -X GET "https://api.example.com/data?q=test" \
-H "X-Api-Key: $API_KEY"
Bearer令牌:
curl -s -X GET "https://api.example.com/data" \
-H "Authorization: Bearer $AUTH_TOKEN"
基础认证:
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": "新项目", "category": "工具", "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": "更新项目", "price": 39.99}'
DELETE:
curl -s -X DELETE "https://api.example.com/items/123" \
-H "Authorization: Bearer $TOKEN"
阶段4:执行 — 调用API并处理响应
使用Bash(curl) — 主要方法
# 执行并捕获响应 + HTTP状态
RESPONSE=$(curl -s -w "
%{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 "状态: $HTTP_CODE"
echo "正文: $BODY" | head -c 2000 # 截断到2KB以确保上下文安全
使用WebFetch — 当需要AI处理时
WebFetch({
url: 'https://api.example.com/search?q=test',
prompt:
'提取前5个结果及其标题和描述。格式化为编号列表。',
});
何时使用哪个:
| 场景 | 工具 | 原因 |
|---|---|---|
| 需要原始JSON进行进一步处理 | Bash(curl) | 完全控制,可解析输出 |
| 需要总结/提取数据 | WebFetch | AI内联处理响应 |
| 需要检查HTTP状态码 | Bash(curl) | WebFetch抽象了状态 |
| 大型响应 (>50KB) | Bash(curl)+ 截断 | WebFetch可能在大型页面上超时 |
| HTML页面(非JSON) | WebFetch | 将HTML转换为markdown |
错误处理
HTTP状态码处理:
| 状态 | 含义 | 操作 |
|---|---|---|
| 200-299 | 成功 | 解析响应,继续 |
| 400 | 错误请求 | 检查参数,修复并重试 |
| 401 | 未授权 | 检查API密钥/令牌,重新认证 |
| 403 | 禁止 | 检查权限,报告给用户 |
| 404 | 未找到 | 检查URL/资源ID,尝试替代端点 |
| 429 | 速率限制 | 等待(检查Retry-After头部),然后重试 |
| 500-599 | 服务器错误 | 等待并重试最多3次 |
带指数退避的重试:
# 对临时错误的重试模式(429, 5xx)
for attempt in 1 2 3; do
RESPONSE=$(curl -s -w "
%{http_code}" -X GET "$URL" -H "Authorization: Bearer $TOKEN")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" -lt 400 ]; then
break # 成功
fi
echo "尝试 $attempt 失败 ($HTTP_CODE),在 $((attempt * 2))s 后重试..."
sleep $((attempt * 2))
done
响应处理
解析JSON响应(Bash):
# 从JSON响应中提取特定字段
echo "$BODY" | node -e "
const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
console.log('总计:', data.totalResults);
data.items?.slice(0, 5).forEach((item, i) => {
console.log(`\${i+1}. \${item.title} — \${item.description?.substring(0, 80)}`);
});
"
截断大型响应:
# 安全性:切勿将>10KB的API响应传递到上下文中
BODY_TRUNCATED=$(echo "$BODY" | head -c 10000)
if [ ${#BODY} -gt 10000 ]; then
echo "[截断: 响应为 $(echo "$BODY" | wc -c) 字节,显示前10KB]"
fi
阶段5:链式 — 迭代多调用工作流程
许多任务需要链式调用多个API。使用受UTCP启发的迭代模式:
链式模式
迭代1:搜索 -> 获取结果列表
迭代2:获取顶部结果的详情
迭代3:对结果执行操作
(最大迭代次数防护:在5次停止)
迭代防护(强制)
最大迭代次数 = 5
每次API调用前:
如果 迭代计数 >= 最大迭代次数:
停止。总结到目前为止收集的内容并响应。
否则:
执行调用,增加计数器,重新分析任务。
为什么重要: 没有迭代防护,代理可能无限循环调用API。UTCP使用默认3次;我们推荐5次用于更复杂的多步骤工作流程。
链式示例
示例1:搜索并获取详情
用户: “查找乔治·奥威尔的书籍《1984》的信息”
迭代1:
调用: GET https://openlibrary.org/search.json?q=1984+george+orwell&limit=5
结果: 找到5个匹配,顶部结果有关键字“/works/OL1168083W”
迭代2:
调用: GET https://openlibrary.org/works/OL1168083W.json
结果: 完整书籍详情(标题、描述、主题、封面)
任务完成: 返回总结的书籍信息。
示例2:GitHub — 查找并分析仓库
用户: “react仓库中最新的问题是什么?”
迭代1:
调用: GET https://api.github.com/repos/facebook/react/issues?state=open&per_page=10&sort=created
头部: Authorization: Bearer $GITHUB_TOKEN
结果: 10个最新的开放问题
任务完成: 总结问题标题、标签和日期。
示例3:多API链式
用户: “查找关于AI安全的新闻并总结顶部文章”
迭代1:
调用: GET https://newsapi.org/v2/everything?q=AI+safety&sortBy=publishedAt&pageSize=5
头部: X-Api-Key: $NEWS_API_KEY
结果: 5篇文章,带标题和URL
迭代2:
调用: WebFetch({ url: articles[0].url, prompt: “用3个要点总结这篇文章” })
结果: 文章摘要
任务完成: 返回文章标题 + 摘要。
现实世界API示例
GitHub API(Bearer令牌认证)
# 列出用户的仓库
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": "列出GitHub用户的仓库,按最近更新排序",
"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用户名"
},
"sort": {
"type": "string",
"required": false,
"in": "query",
"description": "排序字段:created, updated, pushed, full_name",
"default": "updated"
},
"per_page": {
"type": "integer",
"required": false,
"in": "query",
"description": "每页结果数(最多100)",
"default": 10
}
}
}
Open Library API(无认证)
# 搜索书籍
curl -s -X GET "https://openlibrary.org/search.json?q=george+orwell&limit=5" \
-H "Accept: application/json"
JSONPlaceholder(测试/原型)
# GET所有帖子
curl -s https://jsonplaceholder.typicode.com/posts?_limit=5
# POST新项目
curl -s -X POST https://jsonplaceholder.typicode.com/posts \
-H "Content-Type: application/json" \
-d '{"title": "测试帖子", "body": "你好世界", "userId": 1}'
Weather API(API密钥认证)
# 获取当前天气
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 + 计数剩余 |
提取模式(推荐用于大型响应)
# 而不是转储完整响应,提取所需内容
curl -s "https://api.example.com/search?q=test" | node -e "
const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
// 仅提取用户要求的内容
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)
- [ ] 敏感响应数据(PII、令牌)不存储在内存文件中
- [ ] 所有请求设置超时(
curl --max-time 30)
验证检查清单
完成动态API集成任务前:
- [ ] 已获取API规范并识别端点
- [ ] 用户意图已映射到正确端点和方法
- [ ] 请求包含正确认证(如果需要)
- [ ] 请求参数匹配API架构(必需参数存在)
- [ ] 已检查HTTP状态码并处理错误
- [ ] 如果> 5KB,响应已截断/总结
- [ ] 迭代计数未超过最大迭代次数(5)
- [ ] 任何命令或文件中未硬编码API密钥
反模式(避免)
| 反模式 | 为什么失败 | 正确方法 |
|---|---|---|
| 硬编码API密钥 | 安全风险,轮换时失效 | 所有命令中使用$ENV_VAR |
| 未先阅读规范就调用API | 错误端点,错误参数 | 先发现(阶段1) |
| 传递完整100KB响应到上下文 | 上下文溢出,性能下降 | 截断/提取(阶段4) |
| 链式调用无迭代防护 | 无限循环消耗令牌 | 始终强制执行最大迭代次数 |
| 猜测参数名称 | 400错误,浪费调用 | 构建前阅读规范/文档 |
| 忽略HTTP错误码 | 静默失败,错误结果 | 检查状态,处理4xx/5xx |
| 当GET正确时使用POST | API拒绝或创建意外资源 | 匹配方法到意图(阶段2) |
快速参考卡
发现 → WebFetch(规范URL) 或定义手动工具模板
匹配 → 映射用户意图到端点 + 方法 + 参数
构建 → 构建curl命令,带URL、头部、认证、正文
执行 → Bash(curl)用于JSON,WebFetch用于HTML/总结
链式 → 重新分析任务,再次调用(最多5次迭代)
认证快速参考:
API密钥: -H "X-Api-Key: $KEY"
Bearer: -H "Authorization: Bearer $TOKEN"
基础认证: -u "$USER:$PASS"
无认证: (无需认证头部)
工具模板快速创建:
{
"name": "...",
"description": "...",
"base_url": "...",
"method": "GET",
"auth": { "type": "api_key", "header": "...", "env_var": "..." },
"parameters": { "q": { "type": "string", "required": true, "in": "query" } }
}
研究基础
此技能基于:
- 通用工具调用协议(UTCP) — AI代理工具调用的开放标准
- UTCP代理 — 基于LangGraph的参考实现
- UTCP规范 — RFC和协议定义
- OpenAPI规范3.1 — API描述标准
- OpenAPI最佳实践 — 社区指南
- agents.json规范 — API-代理合同标准
- 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
假设中断:如果不在内存中,则未发生。