关于 devtu-fix-tool
用于诊断和修复 ToolUniverse 工具故障的开发技能,面向维护工具配置、实现与测试的开发者。它强调先用命令行复现问题,再按错误类型修复根因并验证结果。
主要功能
- 01先用 CLI 验证故障是否复现
- 02按错误类型定位配置或实现
- 03检查 API 文档与参数定义
- 04更新工具配置和测试
- 05重新生成工具并运行验证
适用场景
- 01排查返回数据与 schema 不匹配
- 02修复参数校验或 API 端点问题
- 03验证修复后的集成与单元测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mims-harvard/ tooluniverse --skill devtu-fix-tool安装后在 Claude Code 中输入/devtu-fix-tool确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
EXAMPLES.mdQUICK-REFERENCE.mdunit-tests-reference.md详细介绍
修复 ToolUniverse 工具
通过系统性地识别错误、针对性修复和验证,诊断并修复失败的 ToolUniverse 工具。
修复 Bug 的基本原则
编写任何修复前,请先问:用户为什么会遇到这种失败情况?
- 预防,而非补救 — 修复根本原因,让故障无法发生,而不是在故障发生后添加提示文本
- 在输入时验证,而非在输出时验证 — 应尽早发现并拒绝错误参数、未知疾病名称和不受支持的药物,并提供清晰的指导,而不是等到静默调用 API 后才发现问题
- 不要掩盖静默变更 — 如果输入会被自动规范化(融合表示法、标题大小写),就原生支持两种形式,或者明确拒绝并给出指导;绝不能静默转换并将其隐藏
- 区分“没有数据”和“查询错误” — 过滤条件错误导致零结果,与数据不存在导致零结果并不相同;响应必须清楚地区分两者
- 修复抽象,而非个例 — 如果参数名称不一致,就修复接口;不要添加一个只会不断增长的别名列表
应避免的反模式:
- 在零结果消息中添加提示文本,而不提前验证
- 添加参数别名,而不修复命名一致性
- 查询失败后再探测以挽救查询,而不提前验证
Bug 验证(重要)
实施任何 Bug 报告中的修复前,先通过 CLI 验证:
python3 -m tooluniverse.cli run <ToolName> '<json_args>'
许多由 Agent 报告的 Bug 都是由 MCP 接口混淆造成的误报。实施修复前,请务必确认该 Bug 可以复现。
说明
修复失败的工具时:
- 运行针对性测试以定位错误:
python scripts/test_new_tools.py <tool-pattern> -v
-
确认 API 正确 — 在线搜索官方 API 文档,确认端点、参数和模式均正确
-
识别错误类型(参见“错误类型”部分)
-
根据错误模式应用适当的修复
-
如果修改了 JSON 配置或工具类,请重新生成工具:
python -m tooluniverse.generate_tools
- 如果
tests/tools/中存在工具测试,请检查并更新:
ls tests/tools/test_<tool-name>_tool.py
-
重新运行集成测试和单元测试,验证修复
-
提供修复摘要,说明问题、根本原因、解决方案和测试结果
在何处修复
| 问题类型 | 要修改的文件 |
|---|---|
| 二进制响应 | src/tooluniverse/*_tool.py + src/tooluniverse/data/*_tools.json |
| 架构不匹配 | src/tooluniverse/data/*_tools.json (return_schema) |
| 缺少数据包装器 | src/tooluniverse/*_tool.py (operation methods) |
| 端点 URL | src/tooluniverse/data/*_tools.json (endpoint field) |
| 无效测试示例 | src/tooluniverse/data/*_tools.json (test_examples) |
| 工具测试更新 | tests/tools/test_*_tool.py (if exists) |
| 将 API 密钥用作参数 | src/tooluniverse/data/*_tools.json (remove param) + *_tool.py (use env var) |
| 工具未加载(可选密钥) | src/tooluniverse/data/*_tools.json (use optional_api_keys not required_api_keys) |
错误类型
1. JSON 解析错误
症状:Expecting value: line 1 column 1 (char 0)
原因:工具需要 JSON,却收到了二进制数据(图像、PDF、文件)
修复:检查 Content-Type 标头。对于二进制响应,应返回描述字符串,而不是解析 JSON。将 return_schema 更新为 {"type": "string"}。
2. 架构验证错误
症状:Schema Mismatch: At root: ... is not of type 'object' 或 Data: None
原因:缺少 data 字段包装器,或架构类型错误
修复方法取决于错误:
- 如果是
Data: None→ 在所有操作方法中添加data包装器(参见下方的多操作模式) - 如果是类型不匹配 → 在 JSON 配置中更新
return_schema:- 数据是字符串:
{"type": "string"} - 数据是数组:
{"type": "array", "items": {...}} - 数据是对象:
{"type": "object", "properties": {...}}
- 数据是字符串:
关键概念:架构验证的是 data 字段的内容,而不是完整响应。
3. 可空字段错误
症状:Schema Mismatch: At N->fieldName: None is not of type 'integer'
原因:API 对可选字段返回 None/null
修复:在 JSON 配置中使用 {"type": ["<base_type>", "null"]} 允许可空类型。此设置用于可选字段,不要用于必需标识符。
4. 互斥参数错误
症状:传入其他参数时出现 Parameter validation failed for 'param_name': None is not of type 'integer'
原因:工具接受参数 A 或参数 B(二者互斥),但两者都定义了固定类型。仅提供其中一个参数时,另一个参数为 None,导致验证失败。
示例:
{
"neuron_id": {"type": "integer"}, // ❌ Fails when neuron_name is used
"neuron_name": {"type": "string"} // ❌ Fails when neuron_id is used
}
修复:将互斥参数设为可空:
{
"neuron_id": {"type": ["integer", "null"]}, // ✅ Allows None
"neuron_name": {"type": ["string", "null"]} // ✅ Allows None
}
常见模式:
id或name参数(按 ID 或名称获取)acronym或name参数(按符号或全名搜索)- 可能不提供的可选筛选参数
重要:即使参数不互斥,也要将真正可选的参数(如 filter_field、filter_value)设为可空。
5. 混合类型字段错误
症状:Schema Mismatch: At N->field: {object} is not of type 'string', 'null'
原因:字段会根据上下文返回不同结构
修复:对于具有多个不同架构的字段,在 JSON 配置中使用 oneOf。这不同于可空类型({"type": ["string", "null"]}),后者表示相同的基本类型加上 null。
6. 无效测试示例
症状:404 ERROR - Not found 或 400 Bad Request
原因:测试示例使用了无效或过时的 ID
修复:使用以下“列表 → 获取”或“搜索 → 详情”模式查找有效示例。
7. API 参数错误
症状:400 Bad Request 或参数验证错误
修复:在 JSON 配置中更新参数架构,确保类型、必填字段和枚举值正确。
8. API 密钥配置错误
症状:API 密钥为可选项时工具未加载,或 api_key 参数造成混淆
原因:对本应为可选项的密钥使用了 required_api_keys,或将 API 密钥作为工具参数公开
关键区别:
required_api_keys:缺少密钥时会跳过工具optional_api_keys:没有密钥时工具仍会加载并运行(性能会降低)
修复:对于可匿名使用、但使用密钥时速率限制更宽松的 API,在 JSON 配置中使用 optional_api_keys。仅从环境变量读取 API 密钥(os.environ.get()),绝不要将其作为工具参数。
9. API 端点模式错误
症状:有效资源返回 404,或出现意外结果
修复:核对官方 API 文档,确认值应放在 URL 路径中还是查询参数中。
10. API 暂时性故障
症状:测试间歇性地因超时、连接错误或 5xx 错误而失败
修复:在单元测试中对暂时性错误使用 pytest.skip(),不要因外部 API 故障而导致测试失败。
常见修复模式
架构验证模式
架构验证的是 data 字段的内容,而不是完整响应。让 return_schema 类型与 data 中的内容(数组、对象或字符串)相匹配。
多操作工具模式
每个内部方法都必须返回 {"status": "...", "data": {...}}。不要在顶层使用其他字段名。
查找有效测试示例
当测试示例因 400/404 错误而失败时,可通过以下方式查找有效 ID:
- 列表 → 获取:先调用列表端点,再从结果中提取 ID
- 搜索 → 详情:搜索已知实体,并使用返回的 ID
- 遍历版本:如果支持,可尝试不同的数据集版本
单元测试管理
检查是否存在单元测试
修复工具后,检查是否存在单元测试:
ls tests/tools/test_<tool-name>_tool.py
何时更新单元测试
在以下情况下更新单元测试:
- 更改返回结构:更新检查
result["data"]结构的断言 - 添加/修改操作:为新操作添加测试用例
- 更改错误处理:更新错误断言
- 修改必需参数:更新参数验证测试
- 修复架构问题:确保测试验证正确的数据结构
- 添加二进制处理:为二进制响应添加测试
运行单元测试
# Run specific tool tests
pytest tests/tools/test_<tool-name>_tool.py -v
# Run all unit tests
pytest tests/tools/ -v
单元测试检查清单
- 检查
tests/tools/test_<tool-name>_tool.py是否存在 - 在修复前后运行单元测试
- 如果数据结构发生变化,更新断言
- 确保直接测试和接口测试均通过
有关单元测试模式和示例的详细信息,请参阅 unit-tests-reference.md。
验证
运行集成测试
python scripts/test_new_tools.py <pattern> -v
运行单元测试(如果存在)
pytest tests/tools/test_<tool-name>_tool.py -v
重新生成工具
修改 JSON 配置或工具类后:
python -m tooluniverse.generate_tools
在以下情况下重新生成:
- 更改
src/tooluniverse/data/*_tools.json文件 - 修改工具类实现
更改测试脚本时无需重新生成。
输出格式
修复后,提供以下摘要:
问题:[简要说明]
根本原因:[失败原因]
解决方案:[所做的更改]
所做更改:
- 文件 1:[说明]
- 文件 2:[说明]
- 文件 3(如适用):[单元测试更新]
集成测试结果:
- 修复前:X 项测试,Y 项通过(Z%),N 项失败,M 项架构无效
- 修复后:X 项测试,X 项通过(100.0%),0 项失败,0 项架构无效
单元测试结果(如适用):
- 修复前:X 项测试,Y 项通过,Z 项失败
- 修复后:X 项测试,X 项通过,0 项失败
测试最佳实践
测试前确认参数名称
重要:始终阅读工具的 JSON 配置或生成的包装器,以获取正确的参数名称。不要猜测参数名称。
错误的测试示例:
# ❌ WRONG - assumed parameter name
AllenBrain_search_genes(query='Gad1') # Fails: unexpected keyword 'query'
正确的方法:
# ✅ RIGHT - checked config first
# Config shows parameters: gene_acronym, gene_name
AllenBrain_search_genes(gene_acronym='Gad1') # Works!
如何查找正确的参数名称:
- 阅读 JSON 配置:
src/tooluniverse/data/*_tools.json - 检查生成的包装器:
src/tooluniverse/tools/<ToolName>.py - 查看 JSON 配置中的 test_examples
系统化测试方法
测试多个工具时:
- 先抽样:每个 API 测试 1-2 个工具,以识别模式
- 错误分类:按错误类型分组(参数验证、API 错误、数据结构)
- 系统化修复:一次性修复所有存在相同问题的工具
- 只重新生成一次:完成所有 JSON 更改后,运行
python -m tooluniverse.generate_tools - 全部验证:全面测试所有已修复的工具
了解数据结构
工具可以返回不同的数据结构:
- 对象:
{"data": {"id": 1, "name": "..."}}- 单个结果 - 数组:
{"data": [{"id": 1}, {"id": 2}]}- 多个结果 - 字符串:
{"data": "description text"}- 文本响应
相应地编写测试:
# For object data
result = tool()
data = result.get('data', {})
value = data.get('field_name') # ✅
# For array data
result = tool()
items = result.get('data', [])
count = len(items) # ✅
first = items[0] if items else {} # ✅
常见陷阱
- 架构验证的是
data字段,而不是完整响应 - 所有方法都需要
{"status": "...", "data": {...}}包装结构 - 更改 JSON 配置后必须重新生成
- 对于无需密钥即可使用的 API,请使用
optional_api_keys - 查阅官方 API 文档以确认正确的端点模式
- 遇到临时性 API 故障时,单元测试应跳过,而不是失败
- 互斥参数必须可为 null——这是新工具中最常见的问题
- 从配置中确认参数名称——不要假设或猜测
- 按照正确的数据结构预期进行测试——列表、字典还是字符串
调试
- 检查 API 响应:检查状态码、Content-Type 标头和响应正文预览
- 检查工具配置:加载 ToolUniverse 并检查工具的配置
- 添加调试输出:在 run 方法中记录 URL、参数、状态和 Content-Type
快速参考
| 任务 | 命令 |
|---|---|
| 运行集成测试 | python scripts/test_new_tools.py <pattern> -v |
| 运行单元测试 | pytest tests/tools/test_<tool-name>_tool.py -v |
| 检查是否存在单元测试 | ls tests/tools/test_<tool-name>_tool.py |
| 重新生成工具 | python -m tooluniverse.generate_tools |
| 检查状态 | git status --short | grep -E "(data|tools|.*_tool.py|tests/tools)" |
| 错误类型 | 修复位置 |
|---|---|
| JSON 解析错误 | src/tooluniverse/*_tool.py 的 run() 方法 |
| Schema 不匹配 | src/tooluniverse/data/*_tools.json 的 return_schema |
| 404 错误 | src/tooluniverse/data/*_tools.json 的 test_examples 或 endpoint |
| 参数错误 | src/tooluniverse/data/*_tools.json 的参数 schema |
| 单元测试失败 | tests/tools/test_*_tool.py 中的断言 |
| 工具被跳过(可选密钥) | src/tooluniverse/data/*_tools.json 中使用 optional_api_keys |
| API 密钥作为参数 | 从 JSON 参数中移除,并在 Python 中使用 os.environ.get() |