REPL JSON双模式,Agent与人类使用区别何在?

摘要:同一个 CLI,两种使用方式 CLI-Anything 生成的每个 CLI 都支持两种交互模式。 第一种是传统的命令调用方式: cli-anything-blender scene new --name MyScene cli-anythi
同一个 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 而直接规划使用策略了。