Loading

REPL + JSON 双模式:给 Agent 用和给人用的区别

同一个 CLI,两种使用方式

CLI-Anything 生成的每个 CLI 都支持两种交互模式。

第一种是传统的命令调用方式:

cli-anything-blender scene new --name MyScene
cli-anything-blender object add -t cube -n Cube
cli-anything-blender render start --output ./render.png

第二种是 REPL 交互方式——不带任何子命令直接运行,就会进入一个交互式界面:

$ cli-anything-blender
╔══════════════════════════════════════════╗
║       cli-anything-blender v1.0.0       ║
║     Blender CLI for AI Agents            ║
╚══════════════════════════════════════════╝
[blender]>

两种模式共享同一套后端逻辑,区别在于使用场景:单条命令适合写脚本和 CI/CD,REPL 适合探索和 Agent 的多轮对话。


为什么 Agent 需要 JSON 模式

CLI 输出供人阅读和供机器消费,是两个完全不同的设计问题。

人类看 CLI 输出,需要的是可读性——成功消息有没有颜色、进度条漂不漂亮、表格对齐得整不整齐。这些对 Agent 来说是噪音,反而增加解析成本。

Agent 需要的是结构化数据——一个 JSON 对象,字段名固定,类型清晰,不需要做任何文本解析就能直接用。

所以每个命令都内置了 --json 参数:

# 人类可读模式(默认)
$ cli-anything-gimp project info --project poster.json
Project: poster.json
Size: 1920 × 1080
Layers: 3
Modified: Yes

# JSON 模式
$ cli-anything-gimp --json project info --project poster.json
{
  "project": "poster.json",
  "width": 1920,
  "height": 1080,
  "layers": 3,
  "modified": true,
  "format": "xcf"
}

Agent 的工作流就变成了:调用命令 → 解析 JSON → 根据结果决定下一步。这个模式在 Claude Code 的日常使用中被验证是稳定可靠的。


JSON 输出的实现方式

技术上实现起来并不复杂,用 Click 的 option flag 模式就能搞定:

import click
import json

@click.command()
@click.option('--json', 'as_json', flag_value=True, default=False)
@click.option('--project', required=True)
def project_info(as_json, project):
    info = load_project(project)

    if as_json:
        click.echo(json.dumps({
            "project": info.path,
            "width": info.width,
            "height": info.height,
            "layers": len(info.layers),
            "modified": info.modified
        }, indent=2))
    else:
        click.echo(f"Project: {info.path}")
        click.echo(f"Size: {info.width} × {info.height}")
        click.echo(f"Layers: {len(info.layers)}")

关键是 --json 的默认值是 False。也就是说,在没有显式指定 --json 的情况下,命令输出对人类友好;显式指定 --json 时,输出对机器友好。这个设计让 Agent 不会意外污染人类用户的输出,同时也让交互式调试变得自然。


REPL 的设计意图

REPL 模式不是简单地把命令包装成 input() 循环。CLI-Anything 的 REPL 有几个关键特性:

状态持久化。在 REPL 里创建的项目状态会保存在一个 .json 项目文件中。退出 REPL 再重新进入,加载同一个文件就知道之前做了什么:

[blender]> scene load myproject.json
✓ Loaded scene: myproject.json

[blender]> object add -t cube -n Box
✓ Added cube object: Box

[blender]> exit
# 保存退出

$ cli-anything-blender
[blender]> scene load myproject.json
✓ Loaded scene: myproject.json
✓ 1 object(s): Box

命令历史。REPL 内置了命令历史支持,可以用上下箭头翻找之前用过的命令。这对 Agent 来说不是刚需,但人类调试的时候很方便。

上下文感知的帮助。在 REPL 里输入 help 或者 ?,可以看到当前上下文下可用的命令列表和简短说明。


ReplSkin:统一的面子

每个 CLI 的功能不同,但 REPL 界面看起来是一样的。这个统一性靠的是 repl_skin.py——一个被所有生成的 CLI 共享的模块。

ReplSkin 负责:

  • 统一的启动 banner,带版本号和工具描述
  • 统一的彩色提示符样式
  • 统一的成功/错误/警告消息格式
  • 统一的进度指示器

这样做的好处是:Agent 学会了一个 CLI 的界面,切换到其他 CLI 不需要重新适应。 这对 Agent 的多软件协作场景特别重要——Agent 在 Blender REPL 里知道看到 ✓ 是成功,看到 ✗ 是失败,换到 GIMP REPL 还是同样的语义。


两种模式的典型场景

脚本/CI 场景,用命令模式:

# 在脚本里调用
cli-anything-blender scene new --name "Frame_001" -o scene.json
cli-anything-blender --json object add -t cube -n "Cube" --project scene.json

调试/探索场景,用 REPL:

$ cli-anything-blender
[blender]> scene new --name Demo
✓ Created new scene

[blender]> object add -t sphere -n Earth
✓ Added sphere: Earth

[blender]> object list
1. Earth (sphere, at origin)

Agent 多轮对话,用 JSON 模式:

# Agent 的思考链
result = subprocess.run(
    ["cli-anything-blender", "--json", "render", "status"],
    capture_output=True, text=True
)
status = json.loads(result.stdout)
if status["rendering"]:
    wait_for_render(status["output"])
else:
    start_render()

SKILL.md:给 AI 看的元数据

生成的 CLI 还有一个值得注意的地方:Python 包内部打包了一份 SKILL.md。

Agent 安装了 CLI 之后,REPL 启动时会显示 SKILL.md 的绝对路径:

╔══════════════════════════════════════════╗
║       cli-anything-blender v1.0.0       ║
║  Skill: /path/to/site-packages/cli_anything/blender/skills/SKILL.md
╚══════════════════════════════════════════╝
[blender]>

这份 SKILL.md 是 AI Agent 可读的格式,描述了这个 CLI 支持哪些命令、参数如何传递、典型工作流是什么。Agent 读取它之后,就可以不需要 --help 而直接规划使用策略了。

posted @ 2026-03-22 13:59  饭勺oO  阅读(1412)  评论(0)    收藏  举报