一天一个开源项目(第104篇):CLI-Anything - 让所有软件变成 AI 代理可调用的命令行接口,配合 TaoToken 统一 Key 打通调用链
1. 为什么你的 AI 代理“看得见”却“摸不着”我试过让 AI 代理帮我批量处理一批产品图它能写 Python 脚本、能调 REST API、能读数据库但当我让它“把 raw 目录里的图裁成 800x600 再转成 JPG”时它卡住了——因为 GIMP 只有 GUI没有给 AI 用的接口。这不是个例而是所有 AI 代理工作流的共同瓶颈代理能操作“有 API 的东西”却操作不了“只有界面的软件”。CLI-Anything 这个开源项目HKUDS 出品35.7k Stars解决的正是这个问题。它的核心思路很直接给定任意一个桌面或 Web 应用的路径自动分析其功能生成一套结构化的 CLI 封装输出确定性的 JSON并附带一份 SKILL.md 让 AI 代理能“读懂”怎么调用。换句话说它把“只有 GUI”的软件变成 AI 代理能像调函数一样调用的命令行接口。适合谁用三类人最直接受益一是 AI 代理开发者需要让代理控制没有 API 的桌面软件二是自动化工程师想用程序化方式驱动 GIMP、Blender、LibreOffice 这类图形工具三是企业自动化团队手里有一堆遗留图形软件想接入现代 AI 工作流。前置知识只需要命令行基础、Python 环境以及用过 Claude Code 或其他 AI 代理工具。但光有 CLI 封装还不够。代理要真正跑通调用链还需要一个统一的 API 通道来管理 Key、路由请求、控制成本。这就是 TaoToken 的角色——它提供统一的 Key 和 API 通道让 CLI-Anything 生成的 CLI 工具能被代理稳定调用不用每个工具单独配一套鉴权。下面我从零开始把 SKILL.md 配置、CLI 包装示例、TaoToken 接入、真实调用验证和排错全部走一遍。2. CLI-Anything 与 TaoToken 的接入前置准备在动手之前先把两件事理清楚CLI-Anything 负责“把软件变成 CLI”TaoToken 负责“让代理能统一调用这些 CLI 背后的模型能力”。两者配合才能形成端到端的调用链。CLI-Anything 的安装有两条路。最快的是在 Claude Code 里用插件市场# 添加插件市场 /plugin marketplace add HKUDS/CLI-Anything # 安装 cli-anything 插件 /plugin install cli-anything如果你不用 Claude Code也可以走 Python 手动模式pip install cli-anything python -m cli_anything generate ./target-appCLI-Hub 是它的包管理器类似 npm 或 pip 的逻辑社区贡献的 Harness 可以直接装pip install cli-anything-hub cli-hub list cli-hub install gimp cli-hub install blender cli-hub install libreoffice装完之后gimp-cli、blender-cli这些命令就直接在 PATH 里可用了。TaoToken 这边你需要先拿到一个统一的 API Key。访问官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台创建 Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。API 基础地址是 https://taotoken.net/api 注意这个不加 UTM 参数。这里有个关键点CLI-Anything 生成的 CLI 工具本身是本地执行的不依赖网络。但你的 AI 代理在决定“调用哪个 CLI、传什么参数”时需要模型推理能力。TaoToken 的统一 Key 就是给代理层用的——代理通过 TaoToken 的 API 通道调用模型模型输出 CLI 调用指令本地执行 CLI结果再回传给模型判断下一步。这样你只需要维护一个 Key不用为每个模型供应商单独配置。如果你用的是 Claude Code 做代理层接入 TaoToken 的方式是在 settings 里配置 Base URL 和 Key。Claude Code 的配置文件通常在~/.claude/settings.json或项目级的.claude/settings.json。配置片段如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-your-taotoken-key-here, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }如果你用的是 Cline 或 Roo Code 这类 VS Code 插件配置方式类似在插件的 API Provider 设置里选 “Anthropic Compatible”Base URL 填https://taotoken.net/apiAPI Key 填你的 TaoToken KeyModel ID 填你需要的模型标识。Codex 用户的话~/.codex/auth.json里配置{ OPENAI_BASE_URL: https://taotoken.net/api, OPENAI_API_KEY: sk-your-taotoken-key-here }三件套记住Base URL 是https://taotoken.net/apiKey 是你在控制台创建的Model ID 根据你的代理框架填对应的模型标识。这三样配齐代理层就能通过 TaoToken 统一调用模型了。3. 可复制的 SKILL.md 与 CLI 包装配置这一节是整篇的核心。CLI-Anything 最有设计感的部分就是 SKILL.md——它是专门给 AI 代理看的“软件使用说明书”。传统软件只有给人看的 README 和 man page而 SKILL.md 用结构化格式告诉代理这个 CLI 能做什么、命令怎么调、参数什么类型、输出什么格式。先看一个完整的 SKILL.md 示例以 GIMP CLI 为例--- name: gimp-cli version: 1.0.0 description: GIMP image manipulation CLI for AI agents author: HKUDS/CLI-Anything triggers: - process image - resize photo - batch images - convert image format commands: image resize: description: Resize an image to specified dimensions usage: gimp-cli image resize --input file --width int --height int --output file parameters: - name: --input type: file_path required: true description: Path to source image - name: --width type: integer required: true description: Target width in pixels - name: --height type: integer required: true description: Target height in pixels - name: --output type: file_path required: true description: Path to output image output_format: json example: | gimp-cli image resize --input photo.jpg --width 800 --height 600 --output resized.jpg # Output: {status: success, output: resized.jpg, dimensions: 800x600} image convert: description: Convert image format with quality control usage: gimp-cli image convert --input file --format str --quality int --output file parameters: - name: --input type: file_path required: true - name: --format type: enum values: [jpg, png, webp, tiff] required: true - name: --quality type: integer default: 85 description: Output quality 1-100 - name: --output type: file_path required: true output_format: json batch process: description: Batch process all images in a directory usage: gimp-cli batch process --input-dir dir --output-dir dir --operations str parameters: - name: --input-dir type: directory_path required: true - name: --output-dir type: directory_path required: true - name: --operations type: string description: Comma-separated operations, e.g. resize,sharpen output_format: json ---这个 SKILL.md 放在gimp-harness/目录下和gimp_cli.py、HARNESS.md、tests/同级。代理加载这个文件后就知道遇到“resize photo”这类触发词时该调用gimp-cli image resize参数类型和输出格式都一目了然。如果你要手动写一个 CLI 包装用 Click 框架是最顺手的。下面是一个最小可用的 GIMP CLI 包装示例# gimp_cli.py import click import json import subprocess from pathlib import Path click.group() def cli(): GIMP CLI wrapper for AI agents pass cli.group() def image(): Image manipulation commands pass image.command() click.option(--input, input_path, requiredTrue, typeclick.Path(existsTrue)) click.option(--width, requiredTrue, typeint) click.option(--height, requiredTrue, typeint) click.option(--output, output_path, requiredTrue, typeclick.Path()) def resize(input_path, width, height, output_path): Resize an image to specified dimensions script f (let* ((image (car (gimp-file-load RUN-NONINTERACTIVE {input_path} {input_path}))) (drawable (car (gimp-image-get-active-drawable image)))) (gimp-image-scale-full image {width} {height} INTERPOLATION-LINEAR) (gimp-file-overwrite RUN-NONINTERACTIVE image drawable {output_path} {output_path}) (gimp-image-delete image)) result subprocess.run( [gimp, -i, -b, script, -b, (gimp-quit 0)], capture_outputTrue, textTrue ) if result.returncode 0: click.echo(json.dumps({ status: success, output: output_path, dimensions: f{width}x{height} })) else: click.echo(json.dumps({ status: error, message: result.stderr })) raise SystemExit(1) if __name__ __main__: cli()这个包装的关键点输出必须是确定性 JSON代理才能可靠解析。错误也要用 JSON 格式返回代理才能判断是重试还是换策略。TaoToken 的配置片段再强调一次放在代理层的 settings 里{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-your-taotoken-key-here, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }如果你用 Cline MCP 模式MCP 配置里也要写全三件套{ mcpServers: { cli-anything: { command: python, args: [-m, cli_anything, serve], env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: sk-your-taotoken-key-here, TAOTOKEN_MODEL: claude-sonnet-4-20250514 } } } }Base URL、Key、Model ID 三件套缺一不可。配好之后代理就能通过 TaoToken 统一通道调用模型模型输出 CLI 指令本地执行结果回传。4. 验证请求与成功结果配置写完了得验证整条链路能不能跑通。我分三步验证先验证 CLI 本身能跑再验证代理能通过 TaoToken 调用模型最后验证端到端调用链。第一步验证 CLI 包装。装好gimp-cli后直接跑一条命令gimp-cli image resize --input photo.jpg --width 800 --height 600 --output resized.jpg期望输出{status: success, output: resized.jpg, dimensions: 800x600}如果输出是这个 JSON说明 CLI 包装没问题。如果报错看 stderr 里的 GIMP 脚本错误通常是路径问题或 GIMP 没装。第二步验证 TaoToken 通道。用 curl 直接打 TaoToken 的 APIcurl -X POST https://taotoken.net/api/v1/messages \ -H Content-Type: application/json \ -H x-api-key: sk-your-taotoken-key-here \ -H anthropic-version: 2023-06-01 \ -d { model: claude-sonnet-4-20250514, max_tokens: 100, messages: [{role: user, content: 回复 OK 两个字母}] }期望返回里包含content: [{type: text, text: OK}]这样的结构。如果返回 401说明 Key 不对如果返回 model not found说明 Model ID 写错了。第三步端到端验证。在 Claude Code 里加载 SKILL.md然后给代理一个自然语言指令把 raw 目录里的所有图片裁成 800x600输出到 processed 目录代理应该会读取 SKILL.md → 识别触发词 “resize photo” → 生成gimp-cli batch process --input-dir ./raw --output-dir ./processed --operations resize→ 执行 → 解析 JSON 结果 → 汇报完成。如果代理没按预期调用检查 SKILL.md 的 triggers 是否匹配以及代理的 settings 里 Base URL 和 Key 是否配对了。验证成功后你可以把这条链路固化到工作流里。比如写一个 shell 脚本让代理每天定时跑#!/bin/bash # daily-image-pipeline.sh gimp-cli batch process --input-dir ./raw --output-dir ./processed --operations resize,sharpen blender-cli render --scene scene.blend --output ./renders libreoffice-cli calc generate --template report.ods --data data.csv --output report.xlsx代理通过 TaoToken 调用模型做决策本地 CLI 做执行整个流程确定性输出 JSON可测试、可重复。5. 本篇常见错排查这一节列几个我踩过的坑和对应的报错。报错一401 Unauthorized{error: {type: authentication_error, message: invalid x-api-key}}原因通常是 TaoToken Key 没配对或者 Key 前面多了空格。检查settings.json里的ANTHROPIC_API_KEY值确保是sk-开头的完整 Key。如果你用的是 Cline MCP检查TAOTOKEN_API_KEY环境变量是否传进去了。报错二local proxy failedError: local proxy failed to connect to upstream这个通常出现在代理层配置了本地代理但没启动或者 Base URL 写成了http://localhost:xxxx。检查ANTHROPIC_BASE_URL是否写成了https://taotoken.net/api不要加多余的路径或端口。报错三reading choices 相关错误Error: reading choices: unexpected end of JSON input这个多半是 CLI 输出不是合法 JSON。检查你的 CLI 包装里click.echo输出的是不是纯 JSON有没有混入 print 调试信息。代理解析 JSON 失败就会报这个。解决方法是确保所有输出走json.dumps调试信息走 stderr。报错四OAuth 相关错误Error: OAuth token expired or invalid如果你用的是 Claude Code 的 OAuth 登录模式切到 API Key 模式。在 settings 里显式配置ANTHROPIC_API_KEY不要依赖 OAuth 缓存。TaoToken 的 Key 是长期有效的配好之后不会过期。报错五SKILL.md 没被加载代理没有按 SKILL.md 里的命令调用而是自己瞎编命令。检查 SKILL.md 的triggers字段是否包含了用户指令里的关键词。比如用户说“裁剪图片”但 triggers 里只有 “resize photo”代理可能匹配不上。把常见同义词都加进 triggers。报错六CLI 命令找不到gimp-cli: command not foundCLI-Anything 生成的 CLI 需要pip install -e .安装到 PATH。在gimp-harness/目录下跑pip install -e .然后确认which gimp-cli能找到。如果还不行检查setup.py里的entry_points配置。排错的核心思路先隔离是 CLI 层的问题还是代理层的问题。CLI 层直接跑命令验证代理层用 curl 打 TaoToken API 验证。两层都通了端到端就不会有大问题。6. 把 CLI-Anything 接入你的代理工作流整条链路跑通之后你可以开始扩展了。CLI-Anything 支持 80 应用GIMP、Blender、LibreOffice、Godot、FreeCAD、QGIS、Audacity 都在列表里。每个应用生成一个 Harness装到 CLI-Hub 里代理就能统一调用。如果你想贡献自己的 Harness流程是用/cli-anything ./your-app生成 → 测试 → 发布到 CLI-Hub。社区已经有 2600 测试用例覆盖关键路径。TaoToken 这边统一 Key 的好处是你不用为每个模型供应商单独配鉴权。代理层通过一个 Base URL 和一个 Key 调用所有模型CLI 层本地执行结果回传。整个调用链清晰、可测试、可重复。如果你需要长期跑编码或 Agent 任务可以看看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。如果只是想先验证模型对话用模型对话页https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite API Keys 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。最后给一个实用技巧把 SKILL.md 和 CLI 包装一起版本管理。每次改 CLI 参数同步更新 SKILL.md 的 parameters 和 example。代理读的是 SKILL.md不是你的代码注释。SKILL.md 和实际 CLI 行为不一致代理就会调错。这个坑我踩过排查了半天才发现是文档没同步。