编程 CLI-Anything 深度拆解:香港大学如何用 7 阶段流水线把任何软件变成 AI Agent 原生工具——从 Agent Harness 架构到 CLI-Hub 生态的全栈工程哲学

2026-08-03 20:43:01 +0800 CST views 3

CLI-Anything 深度拆解:香港大学如何用 7 阶段流水线把任何软件变成 AI Agent 原生工具——从 Agent Harness 架构到 CLI-Hub 生态的全栈工程哲学

引言:AI Agent 的「最后一公里」困境

2026 年,AI Agent 已经不再是概念。Claude Code 能写代码、Codex 能做重构、OpenClaw 能管理你的日常——它们的推理能力已经强到可以处理复杂的多步骤任务。但有一个问题始终困扰着所有 AI Agent 开发者:

当 Agent 需要操作桌面软件时,它们无能为力。

想象一个场景:你让 Claude Code 帮你画一张 draw.io 架构图。Claude 理解你的需求,知道什么是架构图,甚至能写出 Mermaid 语法。但 draw.io 是一个 GUI 软件,它没有 AI 可以调用的接口,只有一堆按钮和菜单。Claude Code 只能「望洋兴叹」。

这个问题不只存在于 draw.io。GIMP、Blender、LibreOffice、QGIS、Obsidian、Audacity——几乎所有专业桌面软件都面临同样的困境:它们是为人类设计的图形界面,不是为 AI 设计的程序接口。

传统解决方案有两条路,但都有致命缺陷:

方案一:GUI 自动化(截图+点击)

让 AI 实时截屏,识别界面元素位置,模拟鼠标点击。这种方式不仅慢(每一步都要截图、识别、计算坐标),而且极其消耗 Token,更重要的是——脆弱。窗口大小变了、分辨率不同、主题换了,整个流程就崩了。

方案二:手动封装 API

找到软件的脚本接口(如 LibreOffice 的宏、Blender 的 Python API),手动编写 CLI 工具。这需要对每款软件都吃得很透,写起来繁琐,而且不是每款软件都有现成的 API——draw.io 就没有。

CLI-Anything 换了个思路:它不造新轮子,而是分析现有软件的源码,搞清楚 GUI 背后实际在调用哪些函数,然后自动生成一套命令行接口来对接这些函数。

Claude Code 发命令,draw.io 在后台干活,结果和你手动操作完全一样——因为调用的就是同一套引擎。

这个项目来自香港大学数据智能实验室(HKUDS),2026 年 3 月 9 日开源,到 3 月 27 日就拿到了两万多 Star。截至 2026 年 8 月,GitHub Star 数已突破 5 万,成为 AI Agent 工具链领域增长最快的开源项目之一。

今天这篇文章,我们就来深度拆解 CLI-Anything 的架构设计、7 阶段流水线、Agent Harness 概念,以及它如何重新定义「AI Agent 能控制什么」。

一、核心概念:Agent Harness 是什么?

在深入 CLI-Anything 之前,我们需要先理解一个关键概念:Agent Harness

1.1 从 Agent 到 Agent Harness

AI Agent 本身只是一套推理系统——它能思考、能规划、能决定下一步做什么。但要真正执行任务,Agent 需要一个「执行层」。这个执行层就是 Agent Harness。

用一个类比来说明:

  • Agent = 一个经验丰富的项目经理
  • Agent Harness = 项目经理手下的执行团队 + 项目管理工具
  • 底层软件 = 实际干活的工程师

项目经理再厉害,也需要有人帮他干活。Agent 再聪明,也需要 Harness 帮它把意图转化为具体操作。

Agent Harness 的核心职责包括:

  1. 任务生命周期管理:创建、执行、监控、重试、清理
  2. 状态追踪:记录当前执行到了哪一步,有没有出错
  3. 输出标准化:把各种软件的输出格式统一成 JSON,方便 Agent 解析
  4. 错误恢复:出错时自动重试或回滚
  5. 资源管理:文件、进程、网络连接等的分配和回收

1.2 为什么需要 Agent Harness?

你可能会问:Claude Code 已经有工具调用能力了,为什么还需要 Harness?

答案是:可靠性。

普通的工具调用是「单步」的——Agent 调用一次工具,拿到结果,再决定下一步。但真实任务往往是「多步」的——你让 Agent 用 GIMP 打开一张图片、调整亮度、添加文字、导出为 PNG,这中间有 4 个步骤,任何一个步骤出错都可能导致整个任务失败。

Agent Harness 就是为了解决这种多步任务的可靠性问题。它提供:

  • 事务性操作:要么全部成功,要么全部回滚
  • 中间状态持久化:即使 Agent 断连,任务也能从断点恢复
  • 幂等性保证:同一个操作执行多次,结果一致
  • 超时和资源限制:防止 Agent 陷入死循环或耗尽资源

二、CLI-Anything 架构全景

CLI-Anything 的架构可以分为三层:

┌─────────────────────────────────────────────────────┐
│                   AI Agent 层                        │
│   Claude Code / Codex / OpenClaw / Hermes Agent     │
├─────────────────────────────────────────────────────┤
│                 Agent Harness 层                      │
│   CLI-Anything 自动生成的命令行接口                    │
│   ┌──────────┐ ┌──────────┐ ┌──────────┐           │
│   │ Blender  │ │  GIMP    │ │ draw.io  │  ...       │
│   │  CLI     │ │  CLI     │ │  CLI     │           │
│   └──────────┘ └──────────┘ └──────────┘           │
├─────────────────────────────────────────────────────┤
│                  底层软件层                            │
│   Blender (Python API) / GIMP (Script-Fu) / ...     │
└─────────────────────────────────────────────────────┘

顶层是各种 AI Agent,它们不需要知道底层软件的具体实现细节,只需要调用统一的 CLI 命令。

中间层是 CLI-Anything 自动生成的 Agent Harness——每个软件对应一套 CLI 工具,负责将 Agent 的命令转化为软件的原生操作。

底层是实际的桌面软件,通过它们的原生 API(Python 脚本、宏、插件接口等)被 Harness 调用。

2.1 为什么是 CLI 而不是 API?

这是一个关键的设计决策。CLI-Anything 选择了 CLI 作为统一接口,而不是为每款软件封装 REST API。原因有三:

CLI 是人和 AI 都能用的接口。 人类开发者可以通过命令行直接调试,AI Agent 可以通过工具调用执行。不需要两套不同的接口。

--help 让 AI 自己探索工具能力。 Agent 不需要提前知道所有命令,它可以通过 --help 动态发现可用的操作。这比固定 API 更灵活。

--json 输出方便 AI 解析。 所有 CLI 命令都支持 --json 参数,输出结构化的 JSON 数据,Agent 可以直接解析,不需要处理各种格式的文本输出。

工作流可以随意组合。 CLI 命令天然支持管道、重定向、条件执行。Agent 可以像人类开发者一样,把多个命令组合成复杂的工作流。

三、7 阶段流水线:从源码到可执行 CLI

CLI-Anything 最核心的技术创新是它的 7 阶段自动化流水线。你把一个本地代码仓库或 GitHub 仓库路径交给它,它会按固定流程自动生成一套完整的 CLI 工具。

阶段 1:源码分析(Source Analysis)

流水线的第一步是对软件源码进行深度分析。这不是简单的文件扫描,而是理解软件的架构和能力。

# 源码分析阶段的伪代码
def analyze_source(repo_path):
    # 1. 识别项目语言和构建系统
    project_info = detect_project(repo_path)
    
    # 2. 扫描入口点(main 函数、脚本入口)
    entry_points = find_entry_points(project_info)
    
    # 3. 分析 GUI 组件到后端逻辑的映射
    gui_mappings = trace_gui_to_backend(project_info)
    
    # 4. 提取可操作对象(文件、图层、节点等)
    operable_objects = extract_operable_objects(project_info)
    
    # 5. 识别原生 API 和脚本接口
    native_apis = discover_native_apis(project_info)
    
    return SourceAnalysis(
        entry_points=entry_points,
        gui_mappings=gui_mappings,
        operable_objects=operable_objects,
        native_apis=native_apis
    )

以 draw.io 为例,分析阶段会发现:

  • 它是一个基于 Electron 的桌面应用
  • 核心引擎在 src/main/webapp/js/ 目录下
  • 有 XML 格式的图形描述语言
  • mxGraph JavaScript API 可以操作图形元素
  • 文件格式是 .drawio(本质是 XML)

阶段 2:命令设计(Command Design)

基于源码分析的结果,设计 CLI 命令的结构。这一步需要决定:

  • 哪些操作应该暴露为命令
  • 每个命令需要哪些参数
  • 命令的层次结构(子命令 vs 参数)
  • 输出格式(JSON schema)
# 命令设计阶段
def design_commands(source_analysis):
    commands = []
    
    # 为每个可操作对象设计命令
    for obj in source_analysis.operable_objects:
        cmd = Command(
            name=f"{obj.type}-{obj.action}",
            description=f"操作 {obj.type} 的 {obj.action} 方法",
            params=[
                Param("input", type="file", required=True),
                Param("output", type="file", required=False),
                *obj.parameters
            ],
            output_schema=obj.output_format
        )
        commands.append(cmd)
    
    # 设计工作流命令(组合多个原子操作)
    workflows = design_workflows(commands)
    
    return CommandDesign(commands=commands, workflows=workflows)

阶段 3:CLI 生成(CLI Generation)

这是最关键的阶段。流水线会自动生成完整的 CLI 代码,包括:

# 自动生成的 Blender CLI 示例
#!/usr/bin/env python3
"""Auto-generated CLI harness for Blender"""
import argparse
import json
import subprocess
import sys

def cmd_render(args):
    """渲染 3D 场景"""
    # 生成 Blender Python 脚本
    script = f"""
import bpy
import json

# 加载场景
bpy.ops.wm.open_mainfile(filepath='{args.input}')

# 设置渲染参数
bpy.context.scene.render.resolution_x = {args.width}
bpy.context.scene.render.resolution_y = {args.height}
bpy.context.scene.render.resolution_percentage = {args.quality}

# 执行渲染
bpy.ops.render.render(write_still=True)

# 输出结果
result = {{
    "status": "success",
    "output": "{args.output}",
    "resolution": f"{args.width}x{args.height}",
    "render_time": bpy.context.scene.render.timestamp
}}
print(json.dumps(result))
"""
    
    # 写入临时脚本并执行
    with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
        f.write(script)
        script_path = f.name
    
    result = subprocess.run(
        [args.blender_path, '--background', '--python', script_path],
        capture_output=True,
        text=True
    )
    
    if result.returncode != 0:
        print(json.dumps({"status": "error", "error": result.stderr}))
        sys.exit(1)
    
    print(result.stdout)

def cmd_create_mesh(args):
    """创建网格物体"""
    script = f"""
import bpy
import json
import math

# 清空场景
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()

# 创建网格
bpy.ops.mesh.primitive_{args.primitive}_add(
    radius={args.radius},
    location=({args.x}, {args.y}, {args.z})
)

# 输出结果
obj = bpy.context.active_object
result = {{
    "status": "success",
    "object": obj.name,
    "vertices": len(obj.data.vertices),
    "faces": len(obj.data.polygons)
}}
print(json.dumps(result))
"""
    # ... 执行逻辑类似

def main():
    parser = argparse.ArgumentParser(
        description='Blender Agent Harness - AI 可调用的 Blender CLI',
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    subparsers = parser.add_subparsers(dest='command', help='可用命令')
    
    # render 命令
    render_parser = subparsers.add_parser('render', help='渲染 3D 场景')
    render_parser.add_argument('--input', required=True, help='输入 .blend 文件')
    render_parser.add_argument('--output', required=True, help='输出图片路径')
    render_parser.add_argument('--width', type=int, default=1920)
    render_parser.add_argument('--height', type=int, default=1080)
    render_parser.add_argument('--quality', type=int, default=100)
    
    # create-mesh 命令
    mesh_parser = subparsers.add_parser('create-mesh', help='创建网格物体')
    mesh_parser.add_argument('--primitive', choices=['cube', 'sphere', 'cylinder', 'plane'])
    mesh_parser.add_argument('--radius', type=float, default=1.0)
    mesh_parser.add_argument('--x', type=float, default=0.0)
    mesh_parser.add_argument('--y', type=float, default=0.0)
    mesh_parser.add_argument('--z', type=float, default=0.0)
    
    # export 命令
    export_parser = subparsers.add_parser('export', help='导出场景')
    export_parser.add_argument('--input', required=True, help='输入 .blend 文件')
    export_parser.add_argument('--format', choices=['obj', 'fbx', 'gltf', 'stl'])
    export_parser.add_argument('--output', required=True, help='输出路径')
    
    args = parser.parse_args()
    
    if args.command == 'render':
        cmd_render(args)
    elif args.command == 'create-mesh':
        cmd_create_mesh(args)
    elif args.command == 'export':
        cmd_export(args)
    else:
        parser.print_help()

if __name__ == '__main__':
    main()

阶段 4:交互式 REPL(Interactive REPL)

除了标准 CLI,流水线还会生成一个交互式 REPL(Read-Eval-Print Loop),方便 Agent 在对话模式下使用:

# REPL 模式示例
def blender_repl():
    """Blender 交互式 REPL"""
    context = {"scene": None, "objects": []}
    
    while True:
        try:
            line = input("blender> ")
            if line.strip() in ('exit', 'quit'):
                break
            
            # 解析命令
            cmd, args = parse_command(line)
            
            # 在 Blender 中执行
            result = execute_in_blender(cmd, args, context)
            
            # 更新上下文
            update_context(context, result)
            
            # 输出结果
            print(json.dumps(result, ensure_ascii=False))
            
        except Exception as e:
            print(json.dumps({"status": "error", "error": str(e)}))

REPL 的优势在于:

  • 状态保持:不需要每次都重新加载场景
  • 增量操作:可以逐步构建复杂场景
  • 错误恢复:出错时可以从当前状态重试

阶段 5:测试规划(Test Planning)

流水线会自动规划测试用例,覆盖:

  • 单个命令的正确性
  • 命令组合的工作流
  • 边界条件(空文件、超大文件、特殊字符)
  • 错误处理(文件不存在、参数无效)

阶段 6:测试生成与执行(Test Generation)

# 自动生成的测试示例
import pytest
import subprocess
import json

class TestBlenderCLI:
    
    def test_render_creates_output(self, tmp_path):
        """测试渲染命令能正确生成输出文件"""
        input_file = create_test_blend_file(tmp_path)
        output_file = tmp_path / "render_output.png"
        
        result = subprocess.run(
            ["cli-anything-blender", "render",
             "--input", str(input_file),
             "--output", str(output_file),
             "--width", "800", "--height", "600"],
            capture_output=True, text=True
        )
        
        assert result.returncode == 0
        assert output_file.exists()
        
        output = json.loads(result.stdout)
        assert output["status"] == "success"
        assert output["resolution"] == "800x600"
    
    def test_render_invalid_input_returns_error(self, tmp_path):
        """测试无效输入返回错误"""
        result = subprocess.run(
            ["cli-anything-blender", "render",
             "--input", "/nonexistent/file.blend",
             "--output", str(tmp_path / "out.png")],
            capture_output=True, text=True
        )
        
        assert result.returncode != 0
        output = json.loads(result.stdout)
        assert output["status"] == "error"
    
    def test_create_mesh_default_values(self, tmp_path):
        """测试创建网格的默认参数"""
        result = subprocess.run(
            ["cli-anything-blender", "create-mesh",
             "--primitive", "cube"],
            capture_output=True, text=True
        )
        
        assert result.returncode == 0
        output = json.loads(result.stdout)
        assert output["status"] == "success"
        assert output["vertices"] == 8  # 立方体有 8 个顶点

阶段 7:文档生成与打包(Documentation & Packaging)

最后一步是生成完整的文档和打包:

  • README.md:包含安装说明、命令列表、示例用法
  • setup.py / pyproject.toml:Python 包管理
  • CLI-Hub 注册:自动注册到 CLI-Hub 生态
  • Agent 适配文件:为 Claude Code、Codex 等生成适配配置

四、CLI-Hub 生态:从工具到平台

CLI-Anything 不仅仅是一个工具,它正在构建一个生态系统——CLI-Hub

4.1 CLI-Hub 是什么?

CLI-Hub 是一个 CLI 工具的注册表和分发平台,类似于 npm 之于 Node.js。开发者可以:

  • 浏览:在 clianything.cc 上查看所有可用的 CLI 工具
  • 安装:一键安装到本地
  • 贡献:为新软件生成 CLI harness 并提交
  • 评分:对已有工具的质量和实用性打分

截至 2026 年 8 月,CLI-Hub 已经收录了超过 100 个 CLI 工具,覆盖以下类别:

类别代表工具说明
图形编辑GIMP, Inkscape, Krita图像处理和矢量绘图
3D 建模Blender, FreeCAD, Godot3D 建模和游戏引擎
办公套件LibreOffice, Joplin, Obsidian文档编辑和知识管理
开发工具LLDB, iTerm2, QGIS调试、终端、地理信息
音视频Audacity, Kdenlive, OBS Studio音频编辑、视频编辑、直播
网络工具AdGuard Home, JumpServer网络安全和运维
数据分析ChromaDB, Exa向量数据库和搜索
工作流N8N, Dify, Mermaid自动化和可视化

4.2 多 Agent 平台支持

CLI-Anything 的一大优势是它支持多种 AI Agent 平台。同一个 CLI 工具可以同时被 Claude Code、Codex、OpenClaw、Hermes Agent 调用。

# Claude Code 安装
/plugin marketplace add HKUDS/CLI-Anything

# Codex 安装
/install-skill HKUDS/CLI-Anything

# OpenClaw 安装
openclaw skill install CLI-Anything

# Hermes Agent 安装
hermes skill add CLI-Anything

每个平台都有对应的适配层(adapter),负责将平台的工具调用格式转换为 CLI 命令:

# Claude Code 适配器
class ClaudeCodeAdapter:
    def to_tool_definition(self, cli_command):
        return {
            "name": f"cli_anything_{cli_command.name}",
            "description": cli_command.description,
            "input_schema": cli_command.params_to_json_schema()
        }
    
    def execute(self, tool_name, params):
        # 将 Claude Code 的工具调用转换为 CLI 命令
        cmd = self.parse_tool_name(tool_name)
        args = self.params_to_args(params)
        return subprocess.run(
            ["cli-anything", cmd, *args, "--json"],
            capture_output=True, text=True
        )

# Codex 适配器
class CodexAdapter:
    def to_skill_definition(self, cli_command):
        return {
            "name": cli_command.name,
            "description": cli_command.description,
            "parameters": cli_command.params_to_codex_schema()
        }

五、实战:用 CLI-Anything 让 AI 画架构图

让我们通过一个完整的实战案例,展示 CLI-Anything 的实际效果。

5.1 需求

你需要让 Claude Code 帮你画一个微服务架构图,包括:

  • API Gateway
  • 3 个微服务(用户服务、订单服务、支付服务)
  • 1 个数据库集群
  • 服务之间的调用关系

5.2 传统方式(没有 CLI-Anything)

# Claude Code 只能输出 Mermaid 代码
# 你需要手动打开 draw.io,导入,调整格式...
# 或者接受一个不太精确的 ASCII 艺术图

5.3 使用 CLI-Anything

# 第一步:安装 CLI-Anything
/plugin marketplace add HKUDS/CLI-Anything

# 第二步:Claude Code 自动发现 draw.io CLI
claude> 用 draw.io 画一个微服务架构图

# Claude Code 自动调用以下命令序列:
$ cli-anything-drawio create --output microservices.drawio
$ cli-anything-drawio add-shape --input microservices.drawio --type rectangle \
    --label "API Gateway" --x 400 --y 50 --width 200 --height 60
$ cli-anything-drawio add-shape --input microservices.drawio --type rectangle \
    --label "用户服务" --x 150 --y 200 --width 150 --height 60
$ cli-anything-drawio add-shape --input microservices.drawio --type rectangle \
    --label "订单服务" --x 400 --y 200 --width 150 --height 60
$ cli-anything-drawio add-shape --input microservices.drawio --type rectangle \
    --label "支付服务" --x 650 --y 200 --width 150 --height 60
$ cli-anything-drawio add-shape --input microservices.drawio --type cylinder \
    --label "MySQL 集群" --x 400 --y 350 --width 150 --height 80
$ cli-anything-drawio add-edge --input microservices.drawio \
    --from "API Gateway" --to "用户服务" --label "REST"
$ cli-anything-drawio add-edge --input microservices.drawio \
    --from "API Gateway" --to "订单服务" --label "REST"
$ cli-anything-drawio add-edge --input microservices.drawio \
    --from "API Gateway" --to "支付服务" --label "REST"
$ cli-anything-drawio add-edge --input microservices.drawio \
    --from "用户服务" --to "MySQL 集群" --label "SQL"
$ cli-anything-drawio add-edge --input microservices.drawio \
    --from "订单服务" --to "MySQL 集群" --label "SQL"
$ cli-anything-drawio add-edge --input microservices.drawio \
    --from "支付服务" --to "MySQL 集群" --label "SQL"

# 最终输出:microservices.drawio(可直接在 draw.io 中打开编辑)

5.4 效果对比

维度传统方式CLI-Anything
操作方式手动点击 GUICLI 命令序列
精确度依赖鼠标操作像素级精确
可复现每次手动操作同一命令同一结果
可编程不支持支持脚本化
Agent 友好不友好天然友好
速度10-30 分钟10-30 秒

六、Agent Harness 的设计哲学

CLI-Anything 的 Agent Harness 设计遵循几个核心哲学:

6.1 「不做假设」原则

Harness 不假设 Agent 知道底层软件的任何细节。每个命令都自带完整的 --help 文档,Agent 可以动态发现能力:

$ cli-anything-blender --help

用法: cli-anything-blender [命令] [选项]

Blender Agent Harness - AI 可调用的 Blender CLI

可用命令:
  render        渲染 3D 场景
  create-mesh   创建网格物体
  export        导出场景
  list-objects  列出场景中的所有物体
  modify        修改物体属性

全局选项:
  --json        以 JSON 格式输出
  --verbose     输出详细日志
  --timeout     超时时间(秒)

运行 'cli-anything-blender [命令] --help' 查看命令详情

6.2 「防御性输出」原则

所有输出都经过防御性处理:

def safe_output(data):
    """确保输出总是合法的 JSON"""
    try:
        return json.dumps(data, ensure_ascii=False)
    except (TypeError, ValueError) as e:
        return json.dumps({
            "status": "error",
            "error": str(e),
            "raw": str(data)
        })

6.3 「幂等性」原则

同一个命令执行多次,结果一致。这对于 Agent 的重试机制至关重要:

def cmd_export(args):
    """导出命令 - 幂等设计"""
    # 检查输出文件是否已存在
    if os.path.exists(args.output):
        if args.force:
            os.remove(args.output)
        else:
            # 已存在则直接返回成功
            print(json.dumps({
                "status": "success",
                "output": args.output,
                "skipped": True,
                "message": "文件已存在,跳过导出"
            }))
            return
    
    # 执行导出
    do_export(args)

6.4 「渐进式复杂度」原则

简单的任务用简单命令,复杂的任务用组合命令:

# 简单任务:一行命令
$ cli-anything-gimp rotate-image --input photo.jpg --angle 90 --output rotated.jpg

# 中等任务:组合命令
$ cli-anything-gimp batch-process --input ./photos/ --output ./processed/ \
    --operations "resize:800x600|sharpen|watermark:logo.png"

# 复杂任务:REPL 交互模式
$ cli-anything-gimp repl
gimp> load "photo.jpg"
gimp> select-rect 100 100 200 200
gimp> apply-filter blur:5
gimp> add-text "Hello World" --x 50 --y 50 --font "Arial:24"
gimp> export "output.jpg"
gimp> exit

七、性能优化与工程实践

7.1 进程池管理

频繁创建和销毁 Blender/GIMP 进程非常耗时。CLI-Anything 使用进程池来优化:

import multiprocessing
from concurrent.futures import ProcessPoolExecutor

class BlenderProcessPool:
    def __init__(self, pool_size=4):
        self.pool = ProcessPoolExecutor(max_workers=pool_size)
        self.processes = {}
    
    def execute(self, script, timeout=30):
        """在 Blender 进程池中执行脚本"""
        future = self.pool.submit(
            self._run_blender,
            script,
            timeout
        )
        return future.result(timeout=timeout + 5)
    
    def _run_blender(self, script, timeout):
        """实际执行 Blender 脚本"""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as f:
            f.write(script)
            f.flush()
            
            result = subprocess.run(
                [BLENDER_PATH, '--background', '--python', f.name],
                capture_output=True,
                text=True,
                timeout=timeout
            )
            
            return json.loads(result.stdout)

7.2 缓存机制

对于重复的查询操作(如列出场景物体),CLI-Anything 使用缓存:

from functools import lru_cache
import hashlib

class SceneCache:
    def __init__(self, ttl=60):
        self.cache = {}
        self.ttl = ttl
    
    def get_or_compute(self, key, compute_fn):
        now = time.time()
        if key in self.cache:
            value, timestamp = self.cache[key]
            if now - timestamp < self.ttl:
                return value
        
        value = compute_fn()
        self.cache[key] = (value, now)
        return value
    
    def invalidate(self, key=None):
        if key:
            self.cache.pop(key, None)
        else:
            self.cache.clear()

7.3 错误处理策略

CLI-Anything 采用「不崩溃」原则——即使底层软件出错,Harness 也能优雅地返回错误信息:

def robust_execute(blender_path, script, timeout=30):
    """健壮的 Blender 执行"""
    try:
        result = subprocess.run(
            [blender_path, '--background', '--python', '-'],
            input=script,
            capture_output=True,
            text=True,
            timeout=timeout
        )
        
        if result.returncode != 0:
            # Blender 报错,但我们不崩溃
            return {
                "status": "error",
                "error": result.stderr,
                "exit_code": result.returncode
            }
        
        # 尝试解析 JSON 输出
        try:
            return json.loads(result.stdout)
        except json.JSONDecodeError:
            return {
                "status": "success",
                "raw_output": result.stdout
            }
    
    except subprocess.TimeoutExpired:
        return {
            "status": "error",
            "error": f"执行超时({timeout}秒)",
            "suggestion": "尝试增加 --timeout 参数"
        }
    
    except FileNotFoundError:
        return {
            "status": "error",
            "error": f"找不到 Blender: {blender_path}",
            "suggestion": "请检查 Blender 安装路径"
        }

八、与其他方案的对比

8.1 CLI-Anything vs 浏览器自动化(Playwright/Puppeteer)

维度CLI-Anything浏览器自动化
稳定性⭐⭐⭐⭐⭐ 调用原生 API⭐⭐ 依赖 UI 元素定位
速度⭐⭐⭐⭐⭐ 直接调用⭐⭐ 截图+识别+点击
Token 消耗⭐⭐⭐⭐⭐ 极低⭐ 截图消耗大量 Token
覆盖范围⭐⭐⭐ 需要源码⭐⭐⭐⭐⭐ 任何浏览器应用
精确度⭐⭐⭐⭐⭐ 像素级精确⭐⭐⭐ 受渲染影响

8.2 CLI-Anything vs MCP(Model Context Protocol)

维度CLI-AnythingMCP
抽象层级命令行接口工具调用协议
实现方式自动生成手动编写
覆盖范围桌面软件外部服务
生态CLI-HubMCP Registry
适用场景操作复杂 GUI 软件调用外部 API

CLI-Anything 和 MCP 是互补的,不是竞争关系。MCP 适合调用外部服务(搜索引擎、数据库、API),CLI-Anything 适合操作桌面软件。

九、未来展望:Agent-Native 软件时代

CLI-Anything 正在推动一个新趋势:Agent-Native 软件

9.1 从 GUI-First 到 Agent-Native

过去 40 年,软件的设计范式是 GUI-First——为人类设计图形界面。未来的软件可能需要同时为人类和 AI 设计接口:

传统软件:用户 → GUI → 核心逻辑
Agent-Native 软件:用户 → GUI → 核心逻辑 ← CLI/API ← AI Agent

9.2 软件可组合性

当所有软件都有 CLI 接口时,Agent 可以自由组合不同软件的能力:

# 这个工作流在 CLI-Anything 生态中已经可行
$ cli-anything-gimp resize --input photo.jpg --output resized.jpg --width 800
$ cli-anything-mermaid generate --input architecture.mmd --output diagram.svg
$ cli-anything-libreoffice create-doc --title "技术方案" --template proposal.docx
$ cli-anything-drawio import --input diagram.svg --output arch.drawio

Agent 可以像人类开发者一样,把多个工具串联成复杂的工作流。

9.3 开发者的新角色

CLI-Anything 正在改变开发者的工作方式。未来的开发者可能不只是写代码,还需要:

  • 为软件编写 Agent Harness
  • 设计 Agent 友好的命令行接口
  • 在 CLI-Hub 上发布和维护工具
  • 评估和优化 Agent 工作流的效率

十、总结

CLI-Anything 解决了一个关键问题:如何让 AI Agent 操作复杂的桌面软件

它的核心创新在于:

  1. Agent Harness 概念:为软件创建可靠的执行层,而不是脆弱的 GUI 自动化
  2. 7 阶段自动化流水线:从源码分析到 CLI 打包,全自动完成
  3. CLI 统一接口:人和 AI 都能用的接口,--help 发现能力,--json 结构化输出
  4. CLI-Hub 生态:100+ 工具,多 Agent 平台支持
  5. 防御性设计:幂等性、错误恢复、超时控制,确保长时间任务的可靠性

这个项目来自香港大学数据智能实验室(HKUDS),是 2026 年 AI Agent 工具链领域最重要的开源项目之一。

如果你是 AI Agent 开发者,CLI-Anything 值得深入研究。它不仅提供了现成的工具,更重要的是提供了一种设计思路——如何让软件真正变得 Agent-Native


项目信息

  • GitHub:https://github.com/HKUDS/CLI-Anything
  • CLI-Hub:https://clianything.cc
  • 开源协议:MIT
  • 主要语言:Python
  • 支持平台:Claude Code, Codex, OpenClaw, Hermes Agent

推荐文章

10个极其有用的前端库
2024-11-19 09:41:20 +0800 CST
php 连接mssql数据库
2024-11-17 05:01:41 +0800 CST
js迭代器
2024-11-19 07:49:47 +0800 CST
Nginx 实操指南:从入门到精通
2024-11-19 04:16:19 +0800 CST
程序员茄子在线接单