CLI-Anything × AnyGen:构建云异步内容生成任务的 Agent 原生 CLI 编排指南
【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything
导读
本文围绕 CLI-Anything 仓库中 AnyGen 模块的架构分析文档,讲解如何将 AnyGen 云端异步内容生成服务(PPT、DOCX、SmartDraw 图表、网页、故事书、数据分析报告)封装为面向 AI Agent 的状态化命令行工具。读完本文,你将掌握 AnyGen REST API 的任务全生命周期调用方式、cli-anything-anygen的安装配置与命令用法、.anygen-task.json本地持久化机制,以及结合仓库源码理解其轮询、下载、文件校验和会话撤销等底层实现。
一、AnyGen 与 CLI-Anything 的整体架构定位
AnyGen 是一个云端异步内容生成平台,通过 REST API 提供专业幻灯片(PPT)、文档(DOCX)、网站、故事书、图表(SmartDraw)和数据分析报告等生成能力。与仓库中大多数面向本地 GUI 的目标软件不同,AnyGen 没有可调用的本地软件本体——所有渲染均在服务端完成,CLI 只是负责提交任务、轮询状态并下载生成文件的"编排层"。
在 ANYGEN.md 中给出了其服务端与 CLI 的整体协作架构:云端一侧由 Slide / Doc / SmartDraw / Website / Storybook / Data Analysis 六类内容引擎承载生成能力,中间由 Task Orchestration Layer(异步队列、状态跟踪、文件存储)统一调度,最外层通过基于 OpenAPI 3.1 的 REST API(/v1/openapi/tasks等端点)对客户端开放;CLI 一侧则是基于 Click 的命令行加 REPL 的cli-anything-anygen,支持 JSON 与人类可读两种输出。
┌──────────────────────────────────────────────────┐ │ AnyGen Cloud Service │ │ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │ │ │ Slide │ │ Doc │ │ SmartDraw │ │ │ │ Engine │ │ Engine │ │ Engine │ │ │ └────┬─────┘ └────┬─────┘ └────────┬─────────┘ │ │ ┌────┘ ┌─────────┘ ┌─────────────┘ │ │ │ ┌────┴────┐ ┌─────┴─────┐ ┌───────────────┐ │ │ │ │ Website │ │ Storybook │ │ Data Analysis │ │ │ │ │ Engine │ │ Engine │ │ Engine │ │ │ │ └────┬────┘ └─────┬─────┘ └───────┬───────┘ │ │ │ │ │ │ │ │ ┌───────┴─────────────┴───────────────┴───────┐ │ │ │ Task Orchestration Layer │ │ │ │ Async queue · status tracking · file store │ │ │ └──────────────────┬──────────────────────────┘ │ │ │ │ │ ┌──────────────────┴──────────────────────────┐ │ │ │ REST API (OpenAPI 3.1) │ │ │ │ POST /v1/openapi/tasks │ │ │ │ GET /v1/openapi/tasks/:id │ │ │ │ POST /v1/openapi/files/upload │ │ │ │ POST /v1/openapi/tasks/prepare │ │ │ └──────────────────┬──────────────────────────┘ │ └─────────────────────┼────────────────────────────┘ │ HTTPS + Bearer sk-… ┌────────────┴─────────────┐ │ cli-anything-anygen │ │ Click CLI + REPL │ │ JSON / human output │ └──────────────────────────┘二、CLI 策略:为什么需要一个结构化 HTTP 客户端
由于 AnyGen 是纯云端服务,cli-anything-anygen本质上是封装 AnyGen OpenAPI 的结构化 HTTP 客户端,由以下几个部分组成:
- requests:Python HTTP 库,承担所有 API 调用;
- 轮询循环(Polling loop):任务创建后,按可配置间隔(默认 3 秒,最长 20 分钟)轮询
GET /v1/openapi/tasks/:id,直到状态变为completed或failed; - 文件下载:任务完成后下载生成文件(PPTX、DOCX、HTML、SVG、PDF 等)到本地路径;
- 文件上传:通过
POST /v1/openapi/files/upload上传参考资料,换取file_token用于创建任务; - Prepare(多轮对话):
POST /v1/openapi/tasks/prepare支持在创建任务前进行多轮需求澄清。
为什么 Agent 需要 CLI 包装器?
文档在 ANYGEN.md 的 "Why a CLI Wrapper?" 一节给出了四条核心理由:
- Agent 无法直接编排多步骤 HTTP 工作流(认证 → 上传 → prepare → 创建 → 轮询 → 下载);
- CLI 提供单条
task run命令即可编排完整生命周期; - 结构化的
--json输出便于 Agent 解析任务 ID、状态与文件路径; - REPL 支持对任务类型与参数进行交互式探索。
从源码看,这一设计贯穿整个命令树:全局--json开关在 anygen_cli.py 中被解析后置为模块级状态,所有命令的结果统一经output()函数输出——JSON 模式下用json.dumps(data, indent=2, default=str)输出可解析的结构,人类模式下则递归打印嵌套字典/列表。
三、安装与 API Key 配置
cli-anything-anygen由 setup.py 定义,包名为cli-anything-anygen,安装后提供cli-anything-anygen控制台命令(同时支持python3 -m cli_anything.anygen方式运行)。依赖为click>=8.0.0、requests>=2.28.0、prompt-toolkit>=3.0.0,要求 Python 3.10+。
# 源码方式安装(在 anygen/agent-harness 目录内) pip install -e . # 安装运行时依赖 pip install requests click prompt_toolkitAPI Key 的三种配置来源(按优先级)
认证信息解析实现在 anygen_backend.py 的get_api_key()中,按以下优先级依次解析:
--api-keyCLI 选项(优先级最高);ANYGEN_API_KEY环境变量;- 配置文件
~/.config/anygen/config.json。
# 方式一:CLI 选项(单次命令生效) cli-anything-anygen --api-key sk-xxx task status task_xxx # 方式二:环境变量 export ANYGEN_API_KEY="sk-xxx" # 方式三:写入配置文件(推荐,配置保存时会 chmod 0600 保护权限) cli-anything-anygen config set api_key "sk-xxx"值得注意的源码细节:get_api_key()中CLI 参数优先于环境变量、环境变量优先于配置文件;而最终发送请求时_make_auth_token()(见 anygen_backend.py)会自动为不以"Bearer "开头的 key 补上前缀,统一放入Authorization请求头。配置文件写盘时使用chmod(0o600)收紧权限;config set/get在回显 API Key 时会做掩码处理(仅显示前 10 位),避免密钥泄露到终端日志。若最终仍未找到 key,_require_api_key()会抛出带三种配置指引的RuntimeError。
四、支持的 Operation 类型与命令映射
VALID_OPERATIONS定义在 anygen_backend.py,与文档一致共 7 类;其中仅slide、doc、smart_draw三种在任务完成后返回可下载文件,其余以任务 URL 交付。
| Operation | API Value | Output Format | Downloadable File |
|---|---|---|---|
| Slides / PPT | slide | PPTX | Yes |
| Documents / DOCX | doc | DOCX | Yes |
| SmartDraw | smart_draw | drawio / excalidraw | Yes |
| General / Chat | chat | — | No (task URL) |
| Storybook | storybook | — | No (task URL) |
| Data Analysis | data_analysis | — | No (task URL) |
| Website | website | — | No (task URL) |
Agent 动作到 CLI 命令的映射
ANYGEN.md 中整理了一张"Agent 想做什么 → 敲什么命令"的速查表,是编写 Agent 技能(skill)时的命令级契约:
| Agent Action | CLI Command |
|---|---|
| Create a slide deck | task create --operation slide --prompt "..." -o task.json |
| Create a document | task create --operation doc --prompt "..." -o task.json |
| Draw a diagram | task create --operation smart_draw --prompt "..." -o task.json |
| Full workflow (create→poll→download) | task run --operation slide --prompt "..." --output ./ |
| Check task status | task status <task-id> |
| Poll until completion | task poll <task-id> [--output ./] |
| Download result file | task download <task-id> --output ./ |
| Download thumbnail | task thumbnail <task-id> --output ./ |
| Upload a reference file | file upload <path> |
| Multi-turn requirement analysis | task prepare --message "..." [--save conv.json] |
| Configure API key | config set api_key sk-xxx |
| View configuration | config get [key] |
| View task history | session history |
| Undo last operation | session undo |
命令实现上,task、file、config、session四组 Click 命令组定义于 anygen_cli.py,其中--operation参数使用click.Choice(VALID_OPERATIONS, case_sensitive=False)做输入校验,--ratio限定为16:9/4:3。不指定任何子命令时自动进入 REPL。
五、REST API 细节:端点、请求体与状态响应
Base URL:https://www.anygen.ioAuth:Bearer token(sk-…),经Authorization请求头传递。
端点一览
| Method | Endpoint | Description |
|---|---|---|
| POST | /v1/openapi/tasks | Create a new generation task |
| GET | /v1/openapi/tasks/:id | Query task status and metadata |
| POST | /v1/openapi/files/upload | Upload a reference file →file_token |
| POST | /v1/openapi/tasks/prepare | Multi-turn requirement analysis |
Create Task 请求体
{ "auth_token": "Bearer sk-xxx", "operation": "slide", "prompt": "Create a quarterly business review presentation", "language": "en-US", "slide_count": 10, "template": "business", "ratio": "16:9", "export_format": "pptx", "file_tokens": ["tk_abc123"], "files": [] }从 anygen_backend.py 的create_task()可看到请求体组装的几个隐藏行为:
operation会先校验是否在VALID_OPERATIONS内;style参数并不单独入体,而是以追加段落的方式拼进prompt(f"{prompt}\n\nStyle requirement: {style}"),即"风格要求"会被当作提示词的一部分交给生成引擎;language、export_format、file_tokens为通用可选参数,有值才加入 body;slide_count、template、ratio仅在operation == "slide"时才生效(从 CLI 与 API 两层都做了约束);- 请求体中的
files字段是 legacy 的 base64 内嵌方式:encode_file()(见 anygen_backend.py)会按扩展名推断 MIME 类型(pdf/png/jpg/gif/txt/doc/docx/ppt/pptx)并做 base64 编码——现代用法推荐改用file_tokens引用预上传文件; - 创建请求超时 30 秒,返回
{"task_id", "task_url"}。
Task 状态响应
{ "task_id": "task_xxx", "status": "completed", "progress": 100, "output": { "file_url": "https://...", "file_name": "presentation.pptx", "thumbnail_url": "https://...", "task_url": "https://www.anygen.io/task/task_xxx", "slide_count": 10, "word_count": 2500 } }query_task()(见 anygen_backend.py)对状态查询端点发起GET并返回完整任务字典;CLI 层的task status命令会从中抽取task_id/status/progress,若已完成则附带file_name与task_url。
六、本地任务持久化:.anygen-task.json
为了让 CLI 具备"历史与回放(history and replay)"能力,每次创建/轮询/下载都会把任务元数据持久化到本地,格式即文档所述的.anygen-task.json:
{ "version": "1.0", "task_id": "task_xxx", "operation": "slide", "prompt": "Create a quarterly business review presentation", "status": "completed", "created_at": "2026-03-09T12:00:00Z", "completed_at": "2026-03-09T12:01:23Z", "output": { "file_url": "https://...", "file_name": "presentation.pptx", "task_url": "https://www.anygen.io/task/task_xxx" }, "local_file": "./output/presentation.pptx", "metadata": { "file_size": 2048576 } }源码层面的实现位于 core/task.py:记录并非散落在任务目录,而是统一存入~/.cli-anything-anygen/tasks/<task_id>.json(TASK_HISTORY_DIR)。每个函数职责清晰:
create_task():写初始记录(status 为pending,含created_at与task_url);query_task()/poll_task():回填最新status/progress,轮询完成时补completed_at;download_file():回填local_file与metadata.file_size;list_task_records(limit, status_filter):按修改时间倒序列出本地缓存记录,支持按状态过滤——对应task list命令。
version: "1.0"字段为后续格式演进预留了兼容空间。
七、端到端实战:从上传素材到拿回成品文件
综合 README.md 与源码,下面是一条完整可复制的实战链路。
1. 配置 API Key
cli-anything-anygen config set api_key "sk-xxx"2. 上传参考资料(拿到 file_token)
cli-anything-anygen file upload ./quarterly_data.pdf # Output: ✓ Uploaded: quarterly_data.pdf → token: tk_abc123file upload的底层实现在 anygen_backend.py:以 multipart/form-data 方式POST /v1/openapi/files/upload,超时 60 秒,成功返回{file_token, filename, file_size};路径不存在会抛FileNotFoundError。
3. 多轮需求澄清(可选,但强烈推荐)
# 第一轮:提交需求,AnyGen 会追问澄清问题 cli-anything-anygen task prepare --message "I need a quarterly review slide deck" --save conv.json # AnyGen asks clarifying questions... # 第二轮:补充关键信息并回灌上下文 cli-anything-anygen task prepare --message "Focus on revenue growth, 10 slides" --input conv.json --save conv.json # Status: ready, suggested operation: slidetask prepare的 CLI 实现(anygen_cli.py)支持--file-token(可重复)、--input conv.json载入既有对话、--save conv.json保存会话。API 请求体包含auth_token、messages(结构为[{role, content:[{type:text/file, ...}]}])与可选的file_tokens,超时放宽到 120 秒以容纳多轮推理。响应中的suggested_task_params会直接建议operation等建参,Agent 可据此自动续接创建任务。
4. 一条命令走完全流程(create → poll → download)
cli-anything-anygen task run \ --operation slide \ --prompt "Quarterly business review..." \ --file-token tk_abc123 \ --slide-count 10 \ --style "business formal" \ --output ./output/5. 或按需分步执行
# 只创建(拿到任务 ID) cli-anything-anygen task create --operation doc --prompt "Technical design document" # Task ID: task_xxx # 轮询直到完成,并在完成后自动下载到 ./output/ cli-anything-anygen task poll task_xxx --output ./output/ # ✓ Downloaded: ./output/presentation.pptx (2,048,576 bytes) # 单独下载结果文件 / 缩略图 cli-anything-anygen task download task_xxx --output ./output/ cli-anything-anygen task thumbnail task_xxx --output ./output/ # 查看本地任务历史 cli-anything-anygen task list --limit 20 --status completed6. Agent 消费:JSON 输出模式
cli-anything-anygen --json task status task_xxx cli-anything-anygen --json task list --limit 5Create Task 参数完整表
| Parameter | Short | Description | Required |
|---|---|---|---|
--operation | -o | Operation type (slide/doc/smart_draw/chat/...) | Yes |
--prompt | -p | Content description | Yes |
--language | -l | zh-CN / en-US | No |
--slide-count | -c | Number of PPT pages (slide only) | No |
--template | -t | PPT template (slide only) | No |
--ratio | -r | 16:9 / 4:3 (slide only) | No |
--export-format | -f | pptx/image/thumbnail/docx/drawio/excalidraw | No |
--file-token | File token from upload (repeatable) | No | |
--style | -s | Style preference | No |
八、渲染管线:服务端异步模型与轮询原理
对 AnyGen 而言,"渲染"发生在服务端,CLI 负责编排。文档将其分为五步:
- 校验 operation 类型与 prompt;
- 携带认证头向 AnyGen API 提交任务(POST);
- 以 3 秒间隔轮询
GET /v1/openapi/tasks/:id(最长 20 分钟); - 完成后经 output 中的
file_url下载文件; - 保存到本地并校验文件完整性(大小 > 0、格式正确)。
轮询的核心实现在 anygen_backend.py 的poll_task():模块常量POLL_INTERVAL = 3、MAX_POLL_TIME = 1200与文档描述完全对应;每次轮询比对progress变化并通过on_progress(status, pct)回调输出进度;遇到failed状态会抛出携带服务端error信息的RuntimeError;超过max_time则抛TimeoutError。
渲染缺口评估:低(Low)
文档评估本模块的渲染缺口为Low,理由如下:
- 所有渲染均在服务端完成,CLI 只是一个薄编排层;
- 无需本地滤镜翻译或格式转换;
- 风险集中在网络问题与 API 可用性上;
- 唯一的例外:SmartDraw 生成的 drawio/excalidraw 若需转 PNG,可能依赖本地 Chromium 渲染。
九、文件下载与完整性校验:不轻信任何一个字节
AnyGen CLI 在拿到生成文件后并不是简单落盘了事,而是叠加了一层完整性验证。下载逻辑在download_file()(anygen_backend.py)中:先确认任务确为completed、存在file_url,再流式写入目标目录;遇到同名文件时自动追加_1、_2序号避免覆盖。缩略图则固定命名为thumbnail_<task_id>.png。
校验器在 core/export.py 的verify_file(),按魔数与结构判断格式:
- PPTX/DOCX/XLSX:检查 ZIP 魔数
PK\x03\x04,再确认 zip 内含[Content_Types].xml以判定为合法 OOXML(否则标记为普通 ZIP); - PDF:检查
%PDF-头部; - PNG:检查
\x89PNG\r\n\x1a\n魔数; - SVG / drawio / XML:读取文本并检测
<svg标签或 XML 声明; - JSON:实际执行
json.load验证可解析性。
该函数会被 E2E 测试直接调用,作为"下载物确实是合法 OOXML/ZIP"的证据链。
十、Session 会话机制与 REPL:为"误操作"留一条退路
除了任务记录,CLI 还维护一份命令会话:每次task create/poll/download/run、file upload都会在 core/session.py 中被Session.record()记录为一条HistoryEntry(command、args、result、timestamp),并自动持久化到~/.cli-anything-anygen/session.json。
session status # 查看历史条数、可 undo/redo 状态 session history --limit 20 # 查看最近命令 session undo # 撤销上一条操作 session redo # 重做被撤销的操作两个值得称道的源码细节:
- 撤销/重做是双向栈:
undo()将历史栈顶弹出并推入redo_stack,redo()反之;新record()会清空 redo 栈,符合标准编辑器语义; - 写盘带进程锁:
_locked_save_json()利用fcntl.flock独占锁实现原子化写文件(在无fcntl的平台自动降级),避免多进程并发写坏 session.json——详见 core/session.py。
交互场景下,直接运行cli-anything-anygen进入 REPL(基于 prompt_toolkit),可用help列出全部可用命令,或在提示符中输入与命令行相同的子命令(如task run ...)。
十一、测试覆盖计划:Mock 单测 + 真实 E2E 双轨
文档将测试策略划分为两层,对应仓库中的两个测试文件:
1. 单元测试(test_core.py)—— Mock HTTP,无需真实 API
覆盖点包括:
- task create/status/poll 的参数构造;
- 配置加载(API key 来自 env / 文件 / CLI 选项的优先级);
- 轮询逻辑(超时、重试、状态迁移);
- JSON 输出格式;
- 基于任务历史的 session undo/redo;
- 错误处理(认证失败、限流、服务端错误);
- 文件上传参数校验。
2. E2E 测试(test_full_e2e.py)—— 真实 API,需要ANYGEN_API_KEY
覆盖点包括:
- 完整工作流:create task → poll → download → verify file;
- slide 与 doc 操作产出可下载文件;
- 文件格式校验(PPTX 是合法 ZIP,DOCX 是合法 OOXML);
- 通过
_resolve_cli进行 CLI 子进程调用; - 错误场景(非法 operation、空 prompt、坏 API key)。
从 test_full_e2e.py 源码看,E2E 用pytest.mark.skipif(not API_KEY)在未配置 key 时自动跳过;_resolve_cli()优先查找已安装命令,找不到时回退到python3 -m cli_anything.anygen.anygen_cli,方便开发环境直接跑。测试会对下载文件断言"大小 > 1000 字节"并调用verify_file()校验格式。
运行方式:
# 单元测试(Mock HTTP,无需 API key) python3 -m pytest cli_anything/anygen/tests/test_core.py -v # E2E 测试(需 ANYGEN_API_KEY) ANYGEN_API_KEY=sk-xxx python3 -m pytest cli_anything/anygen/tests/test_full_e2e.py -v # 全部测试 python3 -m pytest cli_anything/anygen/tests/ -v十二、面向 Agent 的设计考量与使用边界
CLI 的 Agent 原生(agent-native)设计可归结为三点:
- 有状态的本地记录:任务与命令历史都落在
~/.cli-anything-anygen/下(tasks/*.json+session.json),配合session undo/redo,Agent 具备"可回放、可回滚"的容错能力; - 机器可读输出:全局
--json使任何命令的输出都能被 Agent 直接解析,错误也以{"error": ..., "type": ...}结构化返回(见handle_error装饰器); - 随包分发的技能文档:仓库在 skills/SKILL.md 提供描述命令组与用法的 agent skill 元数据,便于接入 LLM 工具注册。
最后需要明确边界:本 CLI 的正确性高度依赖 AnyGen 云端服务的可用性与 API 契约稳定性,生成质量与耗时由服务端引擎决定;若需要把 SmartDraw 结果本地渲染为 PNG 类位图,还需另行准备 Chromium 环境。在使用前,请通过 AnyGen 控制台(anygen.io/home → Setting → Integration)申请sk-格式的 API Key,并妥善保管——源码中对其回显做了掩码、写盘做了 0600 权限,Agent 在透传 key 时也应注意同样的安全策略。
本文基于 ANYGEN.md 写成,实现细节分别以 anygen_backend.py、core/task.py、core/export.py、core/session.py、anygen_cli.py 与两个测试文件为准。
【免费下载链接】CLI-Anything"CLI-Anything: Making ALL Software Agent-Native" -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考