跳转到内容

CLI

5 篇包含标签 "CLI" 的文章

如何安装和使用 Hermes:从本地 CLI 到 Feishu 接入快速上手

想安装并开始使用 Hermes,最短路径其实只有三步:

  1. 运行官方安装命令
  2. 在终端里用 hermes 启动 CLI
  3. 如果你想在飞书里继续用,再配置 hermes gateway setup

这篇文章不打算把 Hermes 的所有能力一次讲完,而是先帮你完成最关键的入门闭环:装上、跑起来、开始用,然后再接一个最常见的消息平台场景。

Hermes Agent 是一个既可以在本地终端使用,也可以通过消息平台网关使用的 AI agent。

对大多数开发者来说,它有两个最常见的入口:

  • CLI:在终端里输入 hermes,直接进入交互式界面
  • Messaging Gateway:运行 hermes gateway,再从 Feishu、Telegram、Discord、Slack 等平台和它对话

如果你现在的目标只是快速上手,建议顺序不要反过来,先走这条路线:

  • 先安装 Hermes
  • 先从 CLI 验证是否可用
  • 再决定要不要接消息平台

这样更容易定位问题,也更适合第一次接触 Hermes 的用户。

根据 Hermes README,官方快速安装路径支持这些环境:

  • Linux
  • macOS
  • WSL2
  • Android via Termux

Hermes 当前不支持原生 Windows 直接运行。如果你使用 Windows,推荐先安装 WSL2,再在 WSL2 里执行安装命令。

这点最好在文章开头就说清楚,因为很多安装失败其实不是命令问题,而是运行环境不符合要求。

Hermes README 给出的快速安装命令是:

Terminal window
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

这条命令会执行官方安装脚本,处理平台相关的初始化流程。

安装结束后,先重新加载 shell 环境。最常见的是:

Terminal window
source ~/.bashrc

如果你用的是 zsh,也可以改成:

Terminal window
source ~/.zshrc

最直接的检查方式就是运行:

Terminal window
hermes

如果你想进一步确认配置和依赖是否正常,可以再执行:

Terminal window
hermes doctor

hermes doctor 适合在这些时候使用:

  • 安装后命令行为不正常
  • 模型配置失败
  • gateway 启动失败
  • 不确定环境依赖是否完整

如果你只是想尽快确认 Hermes 能不能用,最简单的方法就是:

Terminal window
hermes

这会启动 Hermes 的交互式 CLI。对于第一次接触 Hermes 的用户,这也是最推荐的起点,因为你可以先验证最核心的几件事:

  • 命令是否真的可用
  • 当前模型配置是否正常
  • 终端工具链是否工作正常
  • 交互体验是不是你需要的那种方式

这几个命令足够你完成第一轮配置

Section titled “这几个命令足够你完成第一轮配置”

Hermes README 里列出的几条高频命令,基本就构成了第一轮上手路径:

Terminal window
hermes model
hermes tools
hermes config set
hermes setup
hermes update
hermes doctor

如果你不知道它们各自是做什么的,可以先这样记:

  • hermes model:选模型、切模型
  • hermes tools:看和配当前可用工具
  • hermes config set:改具体配置项
  • hermes setup:跑一次完整初始化向导
  • hermes update:更新 Hermes
  • hermes doctor:做故障排查

对新手最实用的顺序通常是:

  1. 先运行 hermes model
  2. 如果你希望一次把常用项配完整,再运行 hermes setup

1. 在终端里把 Hermes 当成日常开发助手

Section titled “1. 在终端里把 Hermes 当成日常开发助手”

CLI 模式适合这些场景:

  • 本地写代码时直接问问题
  • 查项目、改文件、跑命令
  • 做一次性调试或 review
  • 在当前工作目录里持续协作

它最大的优点就是路径最短:不用额外接平台,不用先处理机器人配置,也最适合建立第一轮使用习惯。

如果你希望在飞书、Telegram、Discord 等平台上和 Hermes 对话,就需要使用 messaging gateway。

最常见的入口命令是:

Terminal window
hermes gateway setup
hermes gateway

其中:

  • hermes gateway setup 用来做交互式平台配置
  • hermes gateway 用来启动网关进程

根据官方文档,gateway 是一个统一的后台进程,用来连接你已配置的平台、管理会话,并处理定时任务等功能。

以 Feishu 为例,如何把 Hermes 接入消息平台

Section titled “以 Feishu 为例,如何把 Hermes 接入消息平台”

如果你的日常工作主要在飞书里,那么 Feishu/Lark 会是一个很自然的 Hermes 接入方式。

官方文档对 Feishu/Lark 的推荐入口是:

Terminal window
hermes gateway setup

运行后,在向导中选择 Feishu / Lark 即可。

Feishu 文档给出的两种连接模式是:

  • websocket:推荐
  • webhook:可选

如果 Hermes 跑在你的笔记本、工作站或者私有服务器上,优先使用 websocket 会更简单,因为不需要额外暴露公网回调地址。

如果你手动配置,至少要知道这些变量

Section titled “如果你手动配置,至少要知道这些变量”

如果你不是通过向导配置,而是手动写配置,Feishu 文档里列出的核心变量包括:

Terminal window
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=***
FEISHU_DOMAIN=feishu
FEISHU_CONNECTION_MODE=websocket
FEISHU_ALLOWED_USERS=ou_xxx,ou_yyy
FEISHU_HOME_CHANNEL=oc_xxx

其中最值得注意的是两项:

  • FEISHU_ALLOWED_USERS:建议配置,避免任何能接触到 bot 的人都可以直接使用它
  • FEISHU_HOME_CHANNEL:可以预先指定一个 home chat,用来接收 cron 结果或默认通知

这一点很容易被忽略:在 Feishu 群聊里,Hermes 默认不是看到每条消息都响应。

官方文档明确说明:

  • 私聊时,Hermes 会响应消息
  • 群聊里,必须显式 @ bot,它才会处理消息

如果你想把某个飞书会话设成 home channel,也可以在聊天里使用:

/set-home

或者提前在配置里写:

Terminal window
FEISHU_HOME_CHANNEL=oc_xxx

不管你是在 CLI 里,还是在消息平台里,先记住下面这些命令就已经够用了:

  • /new/reset:开始新会话
  • /model:查看或切换模型
  • /retry:重试上一轮
  • /undo:撤销上一轮交互
  • /compress:手动压缩上下文
  • /help:查看帮助

如果你主要在消息平台里使用,再额外记住一个:

  • /sethome/set-home:把当前聊天设为 home channel

这些命令覆盖了新手阶段最常见的操作:重开、调整、回退、查看和继续用。

不能。当前官方文档明确说明,原生 Windows 不支持,推荐使用 WSL2。

安装之后输入 hermes 没反应怎么办?

Section titled “安装之后输入 hermes 没反应怎么办?”

建议按下面顺序排查:

  1. 先重新加载 shell,例如 source ~/.bashrc
  2. 再重新运行 hermes
  3. 如果还是异常,执行 hermes doctor

先检查这三项:

  • 你有没有在群里 @ Hermes
  • FEISHU_ALLOWED_USERS 是否限制了当前用户
  • 当前群聊策略是否允许处理群消息

根据官方 Feishu 文档,群聊场景里,显式 @mention 是必要条件。

如果你只是想尽快开始使用 Hermes,最推荐的顺序是:

  1. 先执行安装命令
  2. 先用 hermes 在本地 CLI 里开始
  3. 再用 hermes modelhermes setup 补齐基础配置
  4. 如果你希望在飞书里继续使用,再配置 hermes gateway setup

如果这篇文章作为一个系列的第一篇,它最适合承担的角色不是“把所有高级功能一次讲完”,而是先把用户带进门。

后续更适合继续拆分成这些主题:

  • Hermes Feishu 接入完整指南
  • Hermes 常用 slash commands 指南
  • Hermes gateway 配置与排错指南

如果你准备继续做 Hermes 内容,这篇就可以作为后续文章的起点,并逐步把内部链接体系补起来。

为什么使用 Skillsbase 维护自己的 Skills 收藏仓库

为什么使用 Skillsbase 维护自己的 Skills 收藏仓库

Section titled “为什么使用 Skillsbase 维护自己的 Skills 收藏仓库”

说起来也挺好笑的,AI 编程时代来了,我们手里的 Agent Skills 越来越多,可随之而来的麻烦也越来越多。这篇文章就是想聊聊我们是怎么用 skillsbase 解决这些问题的。

在 AI 编程时代,开发者需要维护越来越多的 Agent Skills——这些是可复用的指令集,用于扩展 Claude Code、OpenCode、Cursor 等编码助手的能力。然而,随着技能数量的增长,一个现实问题逐渐浮现:

其实也不能说是什么大问题,只是东西多了,管理起来就麻烦了。

  • 本地技能散落在多个位置:~/.agents/skills/~/.claude/skills/~/.codex/skills/.system/
  • 不同位置可能存在命名冲突(例如 skill-creator 同时存在于用户目录和系统目录)
  • 缺乏统一的管理入口,备份和迁移困难

这点挺烦人的。有时候你自己都不知道某个技能到底在哪,像丢了东西一样,找起来费劲。

  • 手工复制技能容易出错,难以追踪来源
  • 没有统一的验证机制,无法保证技能仓库的完整性
  • 团队协作时,难以同步和共享技能集合

手工操作嘛,总是容易出错的。毕竟人的记忆力有限,谁记得住那么多东西是从哪来的呢?

  • 更换开发机器时,需要重新配置所有技能
  • CI/CD 环境中无法自动验证和同步技能仓库

换个电脑就得重新来一遍,这种感觉,怎么说呢,就像搬家一样麻烦。每次都得重新适应新的环境,重新配置所有东西。

为了解决这些痛点,我们尝试过多种方案:从手工复制到脚本自动化,从直接管理目录到全局安装再回收。每种方案都有各自的缺陷,要么无法保证一致性,要么污染环境,要么难以在 CI 中使用。

其实也是走了不少弯路。

最终,我们找到了一套更优雅的解决方案——skillsbase。这个方案的核心思想是:先本地安装验证,再转换结构写入仓库,最后卸载临时文件。这样既能确保仓库内容与实际安装结果一致,又不会污染全局环境。

说起来简单,只是踩了不少坑才琢磨出来罢了。

本文分享的方案来自我们在 HagiCode 项目中的实践经验。

HagiCode 是一个 AI 代码助手项目,在开发过程中我们需要维护大量的 Agent Skills 来扩展各种编码能力。正是这些实际需求,促使我们开发了 skillsbase 这套工具来规范化管理技能仓库。

其实这东西也不是凭空想出来的,都是被逼的。技能多了,自然就需要管理。管理的过程中遇到问题,自然就需要解决。一步一步,就走到今天了。

如果你对 HagiCode 感兴趣,可以访问 官网了解更多 或在 GitHub 上查看源码。

要建立一个可维护的技能收藏仓库,需要解决以下核心问题:

  1. 统一命名空间冲突:当多个来源存在同名技能时,如何避免覆盖?
  2. 来源可追溯性:如何记录每个技能的来源,以便后续更新和审计?
  3. 同步与验证:如何确保仓库内容与实际安装结果一致?
  4. 自动化集成:如何与 CI/CD 流程集成,实现自动同步和验证?

这些问题看似简单,但每一个都够头疼的。不过话说回来,做什么事不难呢?

方案一:直接复制目录

优点:实现简单 缺点:无法保证与 skills CLI 实际安装结果一致

这个方案嘛,说真的,我们也想过。只是后来发现,CLI 安装的时候可能有一些预处理逻辑,直接复制就跳过了。结果就是,复制的东西和实际装的东西不一样,这就有问题了。

方案二:全局安装后回收

优点:可以验证安装过程 缺点:污染执行环境,CI 与本地结果难以保持一致

这个方案更糟糕。全局安装,会污染环境。更麻烦的是,CI 环境和本地环境很难保持一致,导致”本地能跑,CI 失败”的问题。这种感觉,谁懂啊?

方案三:本地安装 → 转换 → 卸载(最终方案)

这是 skillsbase 采用的方案:

  • 先通过 npx skills 把技能安装到临时位置
  • 转换目录结构并添加来源元数据
  • 写入目标仓库
  • 最后卸载临时文件

这种方案确保了仓库内容与实际消费者安装结果一致,同时不污染全局环境,转换过程可标准化,支持幂等操作。

其实这个方案也不是一开始就想到的,只是试错试多了,自然就知道什么可行、什么不可行了。

决策项选择理由
运行时Node.js ESM无需构建步骤,.mjs 足以完成文件系统编排
配置格式YAML (sources.yaml)可读性强,支持人工维护
命名策略命名空间前缀用户技能保持原名,系统技能添加 system- 前缀
工作流add 修改清单 → sync 执行同步单一同步引擎,避免规则双份实现
文件管理受管文件标识添加注释头,支持安全覆盖

这些决策,说到底都是为了一个目标:让事情变得简单。毕竟,简单才是王道。

skillsbase CLI 提供四个核心命令:

skillsbase
├── init # 初始化仓库结构
├── sync # 同步技能内容
├── add # 添加新技能
└── github_action # 生成 GitHub Actions 配置

命令不多,但也够了。毕竟,工具这东西,够用就好。

┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ init │───▶│ add │───▶│ sync │───▶│github_action│
│ 初始化仓库 │ │ 添加来源 │ │ 同步内容 │ │ 生成 CI │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘

一步一步来,急不得。

sources.yaml → 解析来源 → npx skills 安装 → 转换结构 → 写入 skills/ → 卸载临时文件
.skill-source.json (来源元数据)

这个流程设计得还算清晰。至少我自己看的时候,能明白每一步在做什么。

repos/skillsbase/
├── sources.yaml # 来源清单(单一真相源)
├── skills/ # 技能目录
│ ├── frontend-design/ # 用户技能
│ ├── skill-creator/ # 用户技能
│ └── system-skill-creator/ # 系统技能(带前缀)
├── scripts/
│ ├── sync-skills.mjs # 同步脚本
│ └── validate-skills.mjs # 验证脚本
├── docs/
│ └── maintainer-workflow.md # 维护者文档
└── .github/
├── workflows/
│ └── skills-sync.yml # CI 工作流
└── actions/
└── skillsbase-sync/
└── action.yml # 复用型 Action

文件多了点,不过也还好。毕竟,组织结构清晰了,维护起来也方便。

Terminal window
# 1. 创建空仓库
mkdir repos/myskills && cd repos/myskills
git init
# 2. 使用 skillsbase 初始化
npx skillsbase init
# 输出:
# [1/4] create manifest ................. done
# [2/4] create scripts .................. done
# [3/4] create docs ..................... done
# [4/4] create github workflow .......... done
#
# next: skillsbase add <skill-name>

这一步会生成一堆文件,不过不用担心,都是自动生成的。接下来就可以开始添加技能了。

Terminal window
# 添加单个技能(会自动执行同步)
npx skillsbase add frontend-design --source vercel-labs/agent-skills
# 添加到本地来源
npx skillsbase add documentation-writer --source /home/user/.agents/skills
# 输出:
# source: first-party ......... updated
# target: skills/frontend-design ... synced
# status: 1 skill added, 0 removed

添加技能挺简单的,一条命令就够了。只是有时候会遇到一些意外情况,比如网络不好、权限问题之类的。不过这些都是小事,慢慢来。

Terminal window
# 执行同步(对账所有来源)
npx skillsbase sync
# 仅检查是否漂移(不修改文件)
npx skillsbase sync --check
# 允许缺失来源(CI 场景)
npx skillsbase sync --allow-missing-sources

同步的时候,系统会把 sources.yaml 里定义的来源都检查一遍,然后和 skills/ 目录里的内容对账。有差异就更新,没差异就跳过。这样就不会出现”配置改了但文件没变”的问题。

Terminal window
# 生成 workflow
npx skillsbase github_action --kind workflow
# 生成 action
npx skillsbase github_action --kind action
# 生成全部
npx skillsbase github_action --kind all

CI 配置也是自动生成的。只是你需要自己调整一些细节,比如触发条件、运行环境之类的。不过这些都不难。

# 技能根目录配置
skillsRoot: skills/
metadataFile: .skill-source.json
# 来源定义
sources:
# 第一方:本地用户技能
first-party:
type: local
path: /home/user/.agents/skills
naming: original # 保持原名
includes:
- documentation-writer
- frontend-design
- skill-creator
# 系统:系统提供技能
system:
type: local
path: /home/user/.codex/skills/.system
naming: prefix-system # 添加 system- 前缀
includes:
- imagegen
- openai-docs
- skill-creator # 会变成 system-skill-creator
# 远程:第三方仓库
vercel:
type: remote
url: vercel-labs/agent-skills
naming: original
includes:
- web-design-guidelines

这个配置文件是整个系统的核心。所有的来源都在这里定义,改了这里,下次同步就会生效。所以说,这算是一个”单一真相源”。

{
"source": "first-party",
"originalPath": "/home/user/.agents/skills/documentation-writer",
"originalName": "documentation-writer",
"targetName": "documentation-writer",
"syncedAt": "2026-04-07T00:00:00.000Z",
"version": "unknown"
}

每个技能目录下都会有这个文件,记录了它的来源信息。这样以后出问题的时候,能快速定位是从哪来的、什么时候同步的。

Terminal window
# 验证仓库结构
node scripts/validate-skills.mjs
# 使用 skills CLI 验证
npx skills add . --list
# 检查更新
npx skills check

验证这东西,说重要也重要,说没必要也没必要。不过为了保险起见,偶尔跑一下也无妨。毕竟,谁知道会不会有什么意外呢?

.github/workflows/skills-sync.yml
name: Skills Sync
on:
push:
paths:
- 'sources.yaml'
- 'skills/**'
workflow_dispatch:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Validate repository
run: |
npx skills add . --list
node scripts/validate-skills.mjs
- name: Sync check
run: npx skillsbase sync --check

CI 集成之后,每次改 sources.yaml 或者 skills/ 目录,都会自动触发验证。这样就不会出现”本地改了忘了同步”的问题了。

  1. 命名冲突处理:系统技能统一添加 system- 前缀。这样既能保留所有技能,又能避免命名冲突。
  2. 幂等操作:所有命令支持重复执行,多次运行 sync 不会产生副作用。这点在 CI 里特别重要。
  3. 受管文件:生成的文件包含 # Managed by skillsbase CLI 注释,方便识别和管理。这些文件可以安全覆盖,手工修改不会被保留。
  4. 非交互模式:CI 环境默认使用确定性行为,不会因为交互式提示而中断。所有配置都通过 sources.yaml 声明。
  5. 来源可追溯:每个技能都有 .skill-source.json 记录来源信息,出问题的时候能快速定位。
Terminal window
# 团队成员安装共享技能库
npx skills add your-org/myskills -g --all
# 本地克隆验证
git clone https://github.com/your-org/myskills.git
cd myskills
npx skills add . --list

通过 Git 管理技能仓库,团队成员可以轻松同步技能集合,确保每个人都使用相同版本的工具和配置。

这点在团队协作里特别有用,不会出现”我这边能跑你那边不行”的情况。毕竟,环境统一了,问题就少了一半。

使用 skillsbase 维护技能收藏仓库的核心价值在于:

  • 安全性:来源验证、冲突检测、受管文件保护
  • 可维护性:统一入口、幂等操作、配置即文档
  • 标准化:统一的目录结构、命名规范、元数据格式
  • 自动化:CI/CD 集成、自动同步、自动验证

通过这套方案,开发者可以像管理 npm 包一样管理自己的 Agent Skills,实现可复现、可共享、可维护的技能仓库体系。

本文分享的这套工具和流程,正是我们在开发 HagiCode 过程中实际踩坑、实际优化出来的方案。如果你觉得这套方案有价值,说明我们的工程实践方向是正确的——那么 HagiCode 本身也值得关注一下。

毕竟,好的工具是值得被更多人使用的。

如果本文对你有帮助:


本文首发于 HagiCode 博客

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。

Hagicode 联合 GLM-5.1 多 CLI 集成指南

Hagicode 联合 GLM-5.1 多 CLI 集成指南

Section titled “Hagicode 联合 GLM-5.1 多 CLI 集成指南”

在 Hagicode 项目中,用户可以选择多种 CLI 工具来驱动 AI 编程助手,包括 Claude Code CLI、GitHub Copilot、OpenCode CLI、Codebuddy CLI、Hermes CLI 等。这些 CLI 工具本身是通用的 AI 编程工具,但通过 Hagicode 的抽象层,可以灵活地接入不同的 AI 模型提供商。

智谱 AI(ZAI)提供了与 Anthropic Claude API 兼容的接口,使得这些 CLI 工具可以直接使用国产 GLM 系列模型。其中 GLM-5.1 是智谱最新发布的大语言模型,相比 GLM-5.0 有显著的改进。

Hagicode 通过 AIProviderType 枚举定义了 11 种 CLI 提供商类型,覆盖了主流的 AI 编程 CLI 工具:

public enum AIProviderType
{
ClaudeCodeCli = 0, // Claude Code CLI
CodexCli = 1, // GitHub Copilot Codex
GitHubCopilot = 2, // GitHub Copilot
CodebuddyCli = 3, // Codebuddy CLI
OpenCodeCli = 4, // OpenCode CLI
IFlowCli = 5, // IFlow CLI
HermesCli = 6, // Hermes CLI
QoderCli = 7, // Qoder CLI
KiroCli = 8, // Kiro CLI
KimiCli = 9, // Kimi CLI
GeminiCli = 10, // Gemini CLI
}

每种 CLI 都有对应的模型参数配置,支持 modelreasoning 参数:

private static readonly IReadOnlyDictionary<AIProviderType, IReadOnlyList<string>> ManagedModelParameterKeysByProvider =
new Dictionary<AIProviderType, IReadOnlyList<string>>
{
[AIProviderType.ClaudeCodeCli] = ["model", "reasoning"],
[AIProviderType.CodexCli] = ["model", "reasoning"],
[AIProviderType.OpenCodeCli] = ["model", "reasoning"],
[AIProviderType.HermesCli] = ["model", "reasoning"],
[AIProviderType.CodebuddyCli] = ["model", "reasoning"],
[AIProviderType.QoderCli] = ["model", "reasoning"],
[AIProviderType.KiroCli] = ["model", "reasoning"],
[AIProviderType.GeminiCli] = ["model"], // Gemini 不支持 reasoning 参数
// ...
};

Hagicode 的 Secondary Professions Catalog 中定义了完整的 GLM 系列模型支持:

Model IDNameDefault ReasoningCompatible CLI Families
glm-4.7GLM 4.7highclaude, codebuddy, hermes, qoder, kiro
glm-5GLM 5highclaude, codebuddy, hermes, qoder, kiro
glm-5-turboGLM 5 Turbohighclaude, codebuddy, hermes, qoder, kiro
glm-5.0GLM 5.0 (Legacy)highclaude, codebuddy, hermes, qoder, kiro
glm-5.1GLM 5.1highclaude, codebuddy, hermes, qoder, kiro

AcpSessionModelBootstrapper.cs 的实现中,我们可以清楚地看到 GLM-5.1 与 GLM-5.0 的区别:

GLM-5.1 是独立的新模型标识,没有任何 legacy 处理逻辑:

private const string Glm51ModelValue = "glm-5.1";

在 Secondary Professions Catalog 中的定义:

{
"id": "secondary-glm-5-1",
"name": "GLM 5.1",
"family": "anthropic",
"summary": "hero.professionCopy.secondary.glm51.summary",
"sourceLabel": "hero.professionCopy.sources.aiSharedAnthropicModel",
"sortOrder": 64,
"supportsImage": true,
"compatiblePrimaryFamilies": [
"claude",
"codebuddy",
"hermes",
"qoder",
"kiro"
],
"defaultParameters": {
"model": "glm-5.1",
"reasoning": "high"
}
}

智谱 AI 提供最完整的 GLM 模型支持:

{
"providerId": "zai",
"name": "智谱 AI",
"description": "智谱 AI 提供的 Claude API 兼容服务",
"category": "china-providers",
"apiUrl": {
"codingPlanForAnthropic": "https://open.bigmodel.cn/api/anthropic"
},
"recommended": true,
"region": "cn",
"defaultModels": {
"sonnet": "glm-4.7",
"opus": "glm-5",
"haiku": "glm-4.5-air"
},
"supportedModels": [
"glm-4.7",
"glm-5",
"glm-4.5-air",
"qwen3-coder-next",
"qwen3-coder-plus"
],
"features": ["experimental-agent-teams"],
"authTokenEnv": "ANTHROPIC_AUTH_TOKEN",
"referralUrl": "https://www.bigmodel.cn/claude-code?ic=14BY54APZA",
"documentationUrl": "https://open.bigmodel.cn/dev/api"
}

特点

  • 支持最多样的 GLM 模型变体
  • 提供 Sonnet/Opus/Haiku 三层级的默认映射
  • 支持 experimental-agent-teams 功能

Claude Code CLI 是 Hagicode 的核心 CLI 之一,通过 Hero 配置系统设置:

{
"primaryProfessionId": "profession-claude-code",
"secondaryProfessionId": "secondary-glm-5-1",
"model": "glm-5.1",
"reasoning": "high"
}

对应的 HeroEquipmentCatalogItem 配置:

{
id: 'secondary-glm-5-1',
name: 'GLM 5.1',
family: 'anthropic',
kind: 'model',
primaryFamily: 'claude',
compatiblePrimaryFamilies: ['claude', 'codebuddy', 'hermes', 'qoder', 'kiro'],
defaultParameters: {
model: 'glm-5.1',
reasoning: 'high'
}
}

OpenCode CLI 是最灵活的 CLI,支持 provider/model 格式指定任意模型:

方式一:使用 ZAI provider 前缀

{
"primaryProfessionId": "profession-opencode",
"model": "zai/glm-5.1",
"reasoning": "high"
}

方式二:直接使用模型 ID

{
"model": "glm-5.1"
}

方式三:前端配置界面

HeroModelEquipmentForm.tsx 中,OpenCode CLI 有特殊的占位符提示:

const OPEN_CODE_MODEL_PLACEHOLDER = 'myprovider/glm-4.7';
const modelPlaceholder = primaryProviderType === PCode_Models_AIProviderType.OPEN_CODE_CLI
? OPEN_CODE_MODEL_PLACEHOLDER
: 'gpt-5.4';

用户可以输入:

zai/glm-5.1
glm-5.1

OpenCode CLI 的模型解析逻辑

internal OpenCodeModelSelection? ResolveModelSelection(string? rawModel)
{
var normalized = NormalizeOptionalValue(rawModel);
if (normalized == null) return null;
var slashIndex = normalized.IndexOf('/');
if (slashIndex < 0)
{
// 无斜杠:直接使用模型 ID
return new OpenCodeModelSelection {
ProviderId = string.Empty,
ModelId = normalized,
};
}
// 有斜杠:解析 provider/model 格式
var providerId = normalized[..slashIndex].Trim();
var modelId = normalized[(slashIndex + 1)..].Trim();
return new OpenCodeModelSelection {
ProviderId = providerId,
ModelId = modelId,
};
}

Codebuddy CLI 有特殊的 legacy 处理逻辑:

{
"primaryProfessionId": "profession-codebuddy",
"model": "glm-5.1",
"reasoning": "high"
}

注意:Codebuddy 对 GLM-5.0 有特殊保留,不走 legacy normalization:

return !string.Equals(providerName, "CodebuddyCli", StringComparison.OrdinalIgnoreCase)
&& string.Equals(normalizedModel, LegacyGlm5TurboModelValue, StringComparison.OrdinalIgnoreCase)
? Glm5TurboModelValue
: normalizedModel;
// CodebuddyCli 时,glm-5.0 不会被规范化为 glm-5-turbo
Terminal window
# 设置 API Key
export ANTHROPIC_AUTH_TOKEN="your-zai-api-key"
# 可选:指定 API 端点(ZAI 默认使用此端点)
export ANTHROPIC_BASE_URL="https://open.bigmodel.cn/api/anthropic"
Terminal window
# 设置 API Key
export ANTHROPIC_AUTH_TOKEN="your-aliyun-api-key"
# 指定阿里云端点
export ANTHROPIC_BASE_URL="https://coding.dashscope.aliyuncs.com/apps/anthropic"

相比 GLM-5.0,GLM-5.1 有以下显著改进:

根据智谱官方发布信息,GLM-5.1 的改进包括:

  • 更强的代码理解能力:对复杂代码结构的解析更准确
  • 更长的上下文理解:支持更长的对话上下文
  • 工具调用增强:MCP 工具调用的成功率提升
  • 输出稳定性:减少随机性和幻觉

GLM-5.1 覆盖了 Hagicode 支持的所有主流 CLI:

compatiblePrimaryFamilies: [
"claude", // Claude Code CLI
"codebuddy", // Codebuddy CLI
"hermes", // Hermes CLI
"qoder", // Qoder CLI
"kiro" // Kiro CLI
]

确保正确设置 ANTHROPIC_AUTH_TOKEN 环境变量,这是所有 CLI 连接模型的必要凭证。

GLM-5.1 需要在对应的模型提供商处开通:

  • 智谱 AI ZAI 平台默认支持
  • 阿里云 DashScope 可能需要单独申请

使用 provider/model 格式时,确保 provider ID 正确:

  • 智谱 AI:zaizhipuai
  • 阿里云:aliyundashscope
  • 建议使用 high 级别以获得最佳代码生成效果
  • Gemini CLI 不支持 reasoning 参数,会自动忽略该配置

Hagicode 通过统一的抽象层,实现了 GLM-5.1 与多种 CLI 的灵活集成。开发者可以根据自己的偏好和使用场景,选择合适的 CLI 工具,并通过简单的配置使用最新的 GLM-5.1 模型。

GLM-5.1 作为智谱最新的模型版本,相比 GLM-5.0 有明显的改进:

  • 独立的版本标识,无 legacy 包袱
  • 更强的推理能力和代码理解
  • 广泛的多 CLI 兼容性
  • 灵活的推理级别配置

通过正确配置环境变量和 Hero 装备,玩家可以在不同的 CLI 环境中充分发挥 GLM-5.1 的强大能力。

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。

Hagicode.Libs:统一集成多个 AI 编程助手 CLI 的工程实践

Hagicode.Libs:统一集成多个 AI 编程助手 CLI 的工程实践

Section titled “Hagicode.Libs:统一集成多个 AI 编程助手 CLI 的工程实践”

在开发 HagiCode 项目的过程中,我们需要同时集成 Claude Code、Codex、CodeBuddy 等多个 AI 编程助手 CLI。每个 CLI 的接口、参数、输出格式都不一样,重复的集成代码让项目越来越难以维护。本文分享我们如何通过 HagiCode.Libs 库构建统一抽象层,解决这个工程痛点——也算是我们踩过的坑,积累下来的一点经验罢了。

现在的 AI 编程助手市场挺热闹的,除了 Claude Code,还有 OpenAI 的 Codex、智谱的 CodeBuddy 等等。作为一个 AI 代码助手项目,HagiCode 需要在多个子项目(桌面端、后端、Web 等)中集成这些不同的 CLI 工具。

一开始问题还不大,集成一个 CLI 也就是几百行代码的事儿。只是随着要支持的 CLI 越来越多,事情就开始变得麻烦了——

每个 CLI 有不同的命令行参数格式,环境变量的要求也不一样,输出格式更是五花八门——有的输出 JSON,有的流式 JSON,有的就是纯文本。再加上跨平台兼容性问题,Windows 和 Unix 系统的可执行文件发现和进程管理机制完全不同,代码重复度越来越高。其实这也无非就是 Ctrl+C、Ctrl+V 多了一点,但维护起来可就头疼了。

最头疼的是,每次要新增一个 CLI 功能支持,就得在好几个项目里改同样的代码。这种方式显然不是长久之计——代码也是有脾气的,重复太多它也会闹别扭。

本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个开源的 AI 代码助手项目,需要同时维护前端 VSCode 扩展、后端 AI 服务、跨平台桌面客户端等多个子项目。怎么说呢,正是这种多语言、多平台的复杂场景,促成了 HagiCode.Libs 的诞生——算是被逼出来的,也罢。

虽然这些 AI 编程助手 CLI 各有特点,但从技术层面来看,它们存在明显的共同特征:

相似的交互模式:都是启动 CLI 进程,发送提示词,接收流式响应,解析消息,最后会话结束或继续——这一套流程,说到底都是一个模子刻出来的。

相似的配置需求:都需要 API 密钥认证、工作目录设置、模型选择、工具权限控制、会话管理。毕竟大家都是吃 API 这碗饭的,差别无非是口味不同。

跨平台挑战一致:都需要解决可执行文件路径解析(claude vs claude.exe vs /usr/local/bin/claude)、进程启动和环境变量处理、Shell 命令转义和参数构建等问题。这跨平台的事儿,说多了都是泪——Windows 和 Unix 的差异,只有踩过坑的人才知道。

基于这些分析,我们需要一个统一的抽象层来提供一致的接口,封装跨平台的 CLI 发现逻辑,处理流式输出的解析,同时支持依赖注入和非 DI 场景使用。这事儿想想就头大,但还是要面对——毕竟是自己的项目,哭着也要做完。

我们创建了 HagiCode.Libs —— 一个轻量级的 .NET 10 库工作空间,采用 MIT 开源协议,现已发布在 GitHub。虽然不是什么惊天地泣鬼神的大作,但解决实际问题,还是挺香的。

HagiCode.Libs/
├── src/
│ ├── HagiCode.Libs.Core/ # 核心功能
│ │ ├── Discovery/ # CLI 可执行文件发现
│ │ ├── Process/ # 跨平台进程管理
│ │ ├── Transport/ # 流式消息传输
│ │ └── Environment/ # 运行时环境解析
│ ├── HagiCode.Libs.Providers/ # 提供者实现
│ │ ├── ClaudeCode/ # Claude Code 提供者
│ │ ├── Codex/ # Codex 提供者
│ │ └── Codebuddy/ # CodeBuddy 提供者
│ ├── HagiCode.Libs.ConsoleTesting/ # 测试框架
│ ├── HagiCode.Libs.ClaudeCode.Console/
│ ├── HagiCode.Libs.Codex.Console/
│ └── HagiCode.Libs.Codebuddy.Console/
└── tests/ # xUnit 测试

在设计 HagiCode.Libs 时,我们遵循了几个原则——毕竟也都是踩过的坑,总结出来的经验:

零重型框架依赖:不依赖 ABP 或其他大型框架,保持轻量级。这年头,依赖越少,麻烦越少——谁还没被依赖地狱毒打过呢。

跨平台支持:Windows、macOS、Linux 原生支持,不需要针对不同平台写不同的代码。一套代码走天下,也挺好的。

流式处理:使用异步流处理 CLI 输出,更符合现代 .NET 的编程模式。毕竟时代在变,异步才是王道。

灵活集成:既支持依赖注入场景,也允许直接实例化使用。萝卜青菜,各有所爱,怎么方便怎么来。

如果你的项目已经在使用依赖注入(比如 ASP.NET Core 或通用主机),可以直接集成——这也算是个孩子,虽然不大,但挺乖的:

using HagiCode.Libs.Providers;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddHagiCodeLibs();
await using var provider = services.BuildServiceProvider();
var claude = provider.GetRequiredService<ICliProvider<ClaudeCodeOptions>>();
var options = new ClaudeCodeOptions
{
ApiKey = "your-api-key",
Model = "claude-sonnet-4-20250514"
};
await foreach (var message in claude.ExecuteAsync(options, "Hello, Claude!"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}

如果是简单的脚本或者不使用 DI 的场景,直接创建实例也行——说白了就是看个人喜好:

var claude = new ClaudeCodeProvider();
var options = new ClaudeCodeOptions
{
ApiKey = "sk-ant-xxx",
Model = "claude-sonnet-4-20250514"
};
await foreach (var message in claude.ExecuteAsync(options, "帮我写一个快速排序"))
{
// 处理消息
}

两种方式使用的是同一套底层实现,你可以根据项目实际情况选择合适的集成方式。这世界本就没有标准答案,适合自己的才是最好的——虽然这话有点老套,但确实是这么个理儿。

每个提供者都有专用的测试控制台项目,方便独立验证集成效果——怎么说呢,测试这件事,要么不做,要做就做到位:

Terminal window
# Claude Code 测试
dotnet run --project src/HagiCode.Libs.ClaudeCode.Console -- --test-provider
dotnet run --project src/HagiCode.Libs.ClaudeCode.Console -- --test-all claude
# CodeBuddy 测试
dotnet run --project src/HagiCode.Libs.Codebuddy.Console -- --test-provider codebuddy-cli
# Codex 测试
dotnet run --project src/HagiCode.Libs.Codex.Console -- --test-provider codex-cli

测试场景覆盖了几个关键场景:

  • Ping:健康检查,确认 CLI 可用
  • Simple Prompt:基本提示测试
  • Complex Prompt:多轮对话测试
  • Session Restore/Resume:会话恢复测试
  • Repository Analysis:代码库分析测试

这种独立的测试控制台设计在调试时特别有用,可以快速定位问题是在 HagiCode.Libs 层还是 CLI 本身。这调试嘛,说白了就是看问题出在哪儿——方向对了,就成功了一半。

跨平台兼容性是 HagiCode.Libs 的核心目标之一。我们配置了 GitHub Actions 工作流 .github/workflows/cli-discovery-cross-platform.yml,在 ubuntu-latestmacos-latestwindows-latest 三个平台上运行真实的 CLI 发现验证。

这确保了每次代码变更都不会破坏跨平台兼容性。本地开发时也可以通过以下命令复现——总不能让 CI 帮你背所有锅,自己本地也要能跑起来:

Terminal window
npm install --global @anthropic-ai/claude-code@2.1.79
HAGICODE_REAL_CLI_TESTS=1 dotnet test --filter "Category=RealCli"

HagiCode.Libs 使用异步流处理 CLI 输出,这种方式比传统的回调或事件模式更符合现代 .NET 的异步编程风格——说到底,这就是技术的进步,谁也挡不住:

public async IAsyncEnumerable<CliMessage> ExecuteAsync(
TOptions options,
string prompt,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
// 启动 CLI 进程
// 解析流式 JSON 输出
// 生成 CliMessage 序列
}

消息类型包括:

  • user:用户消息
  • assistant:助手响应
  • tool_use:工具调用
  • result:会话结束

这种设计让调用方可以灵活地处理流式输出,比如实时显示、缓冲后处理、或者转发到其他服务。美又何必在乎天晴阴呢?重要的是思路打开了,怎么用都成。

HagiCode.Libs.Exploration 模块提供了 Git 仓库发现和状态检查功能,这在分析代码库场景特别有用——这也是被逼出来的功能,谁让 HagiCode 需要分析代码库呢:

// 发现 Git 仓库
var repositories = await GitRepositoryDiscovery.DiscoverAsync("/path/to/search");
// 获取仓库信息
var info = await GitRepository.GetInfoAsync(repoPath);
Console.WriteLine($"Branch: {info.Branch}, Remote: {info.RemoteUrl}");
Console.WriteLine($"Has uncommitted changes: {info.HasUncommittedChanges}");

HagiCode 的代码分析功能就用到了这个模块来识别项目结构和 Git 状态。算是物尽其用,也算是个孩子,没白养。

基于我们在 HagiCode 项目中的实践,有几个地方需要特别注意——都是事儿,事儿,事儿:

API 密钥安全:不要将 API 密钥硬编码到代码中,使用环境变量或配置管理。HagiCode.Libs 支持通过 Options 对象传递配置,方便集成各种配置源。毕竟安全这件事,怎么小心都不为过。

CLI 版本锁定:CI/CD 中我们锁定了特定版本(如 @anthropic-ai/claude-code@2.1.79)以减少版本漂移带来的不确定性。本地开发时建议也使用固定版本。这版本的事儿,说多了都是泪——不固定版本,分分钟教你做人。

测试分类:默认测试使用假提供者保持确定性和速度,真实 CLI 测试需要显式启用。这样既保证了 CI 的快速反馈,又能在需要时进行真实环境验证。这平衡木走起来,也不容易——快和稳,总是需要取舍。

会话管理:不同 CLI 的会话恢复机制不同,Claude Code 使用 .claude/ 目录存储会话,Codex 和 CodeBuddy 各有自己的方式。使用时要注意查看各自文档,了解会话持久化的具体机制。这也罢了,了解清楚总没坏处。

HagiCode.Libs 是我们在开发 HagiCode 过程中,为了解决多 CLI 集成的重复工程问题而构建的统一抽象层。它通过提供一致的接口、封装跨平台细节、支持灵活的集成方式,大大降低了集成多个 AI 编程助手的工程复杂度。一切都淡了——但经验留下了。

如果你也在项目中需要集成多个 AI CLI 工具,或者对跨平台进程管理、流式消息处理感兴趣,欢迎来 GitHub 看看。项目采用 MIT 开源协议,欢迎贡献和反馈。终究是缘分一场,来都来了,不妨交个朋友。

本文分享的方案是 HagiCode 实际踩坑、实际优化出来的。这又有什么办法呢?踩坑嘛,正常——如果你觉得这套方案有价值,说明我们的工程实力也还算过得去。那么 HagiCode 本身,也值得关注一下,说不定有惊喜呢。


如果本文对你有帮助:

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。

ImgBin CLI 工具设计:HagiCode 图片资产管理方案

ImgBin CLI 工具设计:HagiCode 图片资产管理方案

Section titled “ImgBin CLI 工具设计:HagiCode 图片资产管理方案”

本文介绍如何从零构建一个可自动化执行的图片资产流水线,包括 CLI 工具设计、Provider Adapter 架构、以及元数据管理策略。

其实也没想到,图片资产管理这事儿也能让我们纠结这么久。

在 HagiCode 项目开发过程中,我们遇到了一个看似简单却十分棘手的问题:图片资产的生成和管理。怎么说呢,就像青春期的那些事儿一样——表面上风平浪静,暗地里波澜起伏。

随着项目文档和营销物料的增多,需要大量配图。这些配图有些需要 AI 生成,有些需要从现有素材库中挑选,还有些需要对现有图片进行 AI 识别并自动标注。问题在于,这些工作长期以来都是用零散的脚本加人工操作来完成的——每次生成一张图片,都需要手动执行脚本、手动整理元数据、手动生成缩略图。这也就罢了,关键是这些零散的东西散落在各处,想找的时候找不到,想用的时候用不了。

具体痛点包括:

  1. 缺乏统一入口:图片生成的逻辑分散在不同脚本中,想批量执行根本没门
  2. 元数据缺失:生成后的图片没有统一的 metadata.json,无法检索和追踪
  3. 人工整理成本高:图片的标题、标签都需要人工一一整理,效率低下
  4. 无法自动化:CI/CD 流程中想要自动生成配图?门都没有

也曾想过干脆不管了,可是毕竟还是要做项目的嘛。既然躲不掉,那就想办法解决呗。于是我们决定,将 ImgBin 从「零散脚本」升级为可自动化执行的图片资产流水线。毕竟有些事儿,逃避也不是办法。

本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个 AI 代码助手项目,同时维护着 VSCode 扩展、后端 AI 服务、跨平台桌面客户端等多种组件。在这种多语言、多平台的复杂场景下,图片资产的规范管理成了提升开发效率的关键一环。

怎么说呢,这也算是 HagiCode 成长过程中的一个小小烦恼吧。每个项目都会有这样的时候,看起来不起眼的小问题,却能让人折腾半天。

HagiCode 的构建系统采用 TypeScript + Node.js 生态,因此 ImgBin 也顺理成章地选择了相同的技术栈,确保整个项目的技术一致性。毕竟都用习惯了,换别的也嫌麻烦嘛。


ImgBin 采用分层架构,将 CLI 命令、应用服务、第三方 API 适配器和基础设施层清晰分离:

组件层次结构
├── CLI Entry (cli.ts) 全局参数解析、命令路由
├── Commands (commands/*) generate | batch | annotate | thumbnail
├── Application Services job-runner | metadata | thumbnail | asset-writer
├── Provider Adapters image-api-provider | vision-api-provider
└── Infrastructure Layer config | logger | paths | schema

这种分层设计的好处是:每层的职责清晰,测试时可以方便地 mock 掉外部依赖。其实也就是让各干各的,互不打扰,这样出了问题也容易找原因,不是么?

ImgBin 采用了「一个资产一个目录」的模型,每次生成图片时,都会创建如下结构:

library/
└── 2026-03/
└── orange-dashboard/
├── original.png # 原始图片
├── thumbnail.webp # 512x512 缩略图
└── metadata.json # 结构化元数据

这种模型的优势在于:

  1. 自包含:每个资产的所有文件都在同一个目录,迁移、备份都很方便
  2. 可追溯:通过 metadata.json 可以追溯图片的生成时间、使用的 prompt、模型等信息
  3. 可扩展:未来如果需要添加更多变体(比如不同尺寸的缩略图),只需要在同一目录下新增文件即可

美的事物或人,不一定要占有,只要她还是美的,自己好好看着她的美就好了。这话虽然说得有点远了,但理儿是这么个理儿——图片放在一起了,看起来也舒服,找起来也方便。

metadata.json 是整个系统的核心,它采用分层存储策略,区分了三类字段:

{
"schemaVersion": 2,
"assetId": "orange-dashboard",
"slug": "orange-dashboard",
"title": "Orange Dashboard",
"tags": ["dashboard", "hero", "orange"],
"source": { "type": "generated" },
"paths": {
"assetDir": "library/2026-03/orange-dashboard",
"original": "original.png",
"thumbnail": "thumbnail.webp"
},
"generated": {
"prompt": "orange dashboard for docs hero",
"provider": "azure-openai-image-api",
"model": "gpt-image-1.5"
},
"recognized": {
"title": "Orange Dashboard",
"tags": ["dashboard", "ui", "orange"],
"description": "A modern orange dashboard with charts and metrics"
},
"status": {
"generation": "succeeded",
"recognition": "succeeded",
"thumbnail": "succeeded"
},
"timestamps": {
"createdAt": "2026-03-11T04:01:19.570Z",
"updatedAt": "2026-03-11T04:02:09.132Z"
}
}
  • generated:记录图片生成时的原始信息,如使用的 prompt、提供商、模型等
  • recognized:AI 识别结果,如自动生成的标题、标签、描述
  • manual:人工整理的结果,这个区的数据优先级最高,不会被 AI 识别覆盖

这种分层策略解决了我们之前的一个核心矛盾:AI 识别结果和人工整理结果谁优先?答案是人工优先,AI 识别只是辅助。这事儿也想明白了——有些东西嘛,机器终究是机器,终究还是得人来把关。


ImgBin 的另一个核心设计是 Provider Adapter 模式。我们将外部 API 抽象为统一的接口,这样即使更换 AI 服务商,也不需要修改业务逻辑。

怎么说呢,这就跟感情一样——外表怎么变不重要,重要的是内心那套东西不变。接口定好了,内部的实现怎么换都行。

interface ImageGenerationProvider {
// 生成图片,返回图片的 Buffer
generate(options: GenerateOptions): Promise<Buffer>;
// 获取支持的模型列表
getSupportedModels(): Promise<string[]>;
}
interface GenerateOptions {
prompt: string;
model?: string;
size?: '1024x1024' | '1792x1024' | '1024x1792';
quality?: 'standard' | 'hd';
format?: 'png' | 'webp' | 'jpeg';
}
interface VisionRecognitionProvider {
// 识别图片内容,返回结构化的元数据
recognize(imageBuffer: Buffer): Promise<RecognitionResult>;
// 获取支持的模型列表
getSupportedModels(): Promise<string[]>;
}
interface RecognitionResult {
title?: string;
tags: string[];
description?: string;
confidence: number;
}

这种接口设计的优势在于:

  1. 可测试:单元测试时可以传入 mock provider,不需要真正调用外部 API
  2. 可扩展:新增一个 provider 只需要实现接口,不需要修改调用方代码
  3. 可替换:生产环境用 Azure OpenAI,测试环境用本地模型,只需要切换配置

想笑来伪装自己掉下的泪,想哭来试探自己麻痹了没——有时候做项目就是这样,表面上看是换了个 API,实际上内在的那套逻辑一点没变,也就没什么好怕的了。


ImgBin 提供了四个核心命令,满足不同的使用场景:

Terminal window
# 最简单的用法
imgbin generate --prompt "orange dashboard for docs hero"
# 同时生成缩略图和 AI 标注
imgbin generate --prompt "orange dashboard" --annotate --thumbnail
# 指定输出目录
imgbin generate --prompt "orange dashboard" --output ./library

批量任务通过 YAML 或 JSON manifest 文件定义,适合 CI/CD 流程中使用:

assets/jobs/launch.yaml
defaults:
annotate: true
thumbnail: true
libraryRoot: ./library
jobs:
- prompt: "orange dashboard hero"
slug: orange-dashboard
tags: [dashboard, hero, orange]
- prompt: "pricing grid for docs"
slug: pricing-grid
tags: [pricing, grid, docs]

执行命令:

Terminal window
imgbin batch assets/jobs/launch.yaml

批量任务的设计支持失败隔离:manifest 中逐项处理,单项失败不影响其他任务。可以通过 --dry-run 预览而不实际执行。

这也就罢了,关键是它还能告诉你哪儿成功了哪儿失败了,不像某些事儿,失败了都不知道怎么失败的。

对现有图片执行 AI 识别,自动生成标题、标签、描述:

Terminal window
# 标注单张图片
imgbin annotate ./library/2026-03/orange-dashboard
# 批量标注整个目录
imgbin annotate ./library/2026-03/

为既有图片补生成缩略图:

Terminal window
# 生成缩略图
imgbin thumbnail ./library/2026-03/orange-dashboard

批量任务的 manifest 支持灵活的配置,默认值可以统一设置,单个任务也可以覆盖:

# 全局默认值
defaults:
annotate: true # 默认开启 AI 标注
thumbnail: true # 默认生成缩略图
libraryRoot: ./library
model: gpt-image-1.5
jobs:
# 最小配置,只提供 prompt
- prompt: "first image"
# 完整配置
- prompt: "second image"
slug: custom-slug
tags: [tag1, tag2]
annotate: false # 这个任务不执行 AI 标注
model: dall-e-3 # 这个任务用不同的模型

执行时,ImgBin 会逐个处理任务,每个任务的结果会写入对应的 metadata.json,即使某个任务失败,也不会影响其他任务。任务完成后,会输出汇总报告:

✓ orange-dashboard (succeeded)
✓ pricing-grid (succeeded)
✗ hero-banner (failed: API rate limit exceeded)
2/3 succeeded, 1 failed

有些事儿吧,急也急不来,一个一个来,反而踏实。这,或许就是批量任务的哲学吧。


ImgBin 通过环境变量支持灵活的配置:

Terminal window
# ImgBin 工作目录
IMGBIN_WORKDIR=/path/to/imgbin
# 可执行文件路径(用于脚本中调用)
IMGBIN_EXECUTABLE=/path/to/imgbin/dist/cli.js
# 资产库根目录
IMGBIN_LIBRARY_ROOT=./.imgbin-library
# Azure OpenAI 配置(如果使用 Azure provider)
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
AZURE_OPENAI_API_KEY=your-api-key
AZURE_OPENAI_IMAGE_DEPLOYMENT=gpt-image-1

配置这东西,说重要也重要,说不重要也不重要。毕竟怎么舒服怎么来嘛,适合自己的才是最好的。


在实现过程中,我们总结了以下几个关键点:

接口定义要清晰完整,包括输入参数、返回值、错误处理。建议同时提供同步和异步两种调用方式,方便不同场景使用。

这也算是过来人的一点经验吧,毕竟接口这东西,定好了就不想再改,麻烦。

批量任务中某项失败时,应该:

  1. 记录详细错误信息到单独的日志文件
  2. 继续执行其他任务,不中断整个流程
  3. 最终返回非零退出码,表示有任务失败
  4. 在汇总报告中清晰展示每个任务的执行结果

有些事儿失败了就是失败了,逃避也没用,不如大大方方承认,然后想办法解决。这道理,做项目和做人是一样的。

识别结果默认写入 recognized 区,人工修改的字段有 manual 标记。元数据更新时采用「只增不减」策略:除非显式传入 --force 参数,否则不覆盖已有的人工整理结果。

这事儿也想明白了——有些东西啊,错过了就是错过了,覆盖了也就没了。还是保留着比较好,毕竟记录本身也是一种美。

使用 fs.mkdir({ recursive: true }) 确保目录创建原子性,避免并发场景下的竞态条件。

这大概就是所谓的安全感吧——该稳稳该快快,不拖泥带水,也不瞻前顾后。


ImgBin 作为 HagiCode 项目图片资产管理的核心工具,通过以下设计解决了我们面临的问题:

  1. 统一入口:CLI 命令覆盖了生成、标注、缩略图等全部操作
  2. 元数据驱动:每个资产都有完整的 metadata.json,支持检索和追踪
  3. Provider Adapter:灵活的外部 API 抽象,便于测试和扩展
  4. 批量任务支持:CI/CD 流程中可以自动执行批量图片生成

一切都淡了…可这方案啊,还真是用上了。

这套方案不仅提升了 HagiCode 自身的开发效率,也形成了一个可复用的图片资产管理框架。如果你也在开发类似的多组件项目,相信 ImgBin 的设计思路会给你一些启发。

青春嘛,总是要折腾的。不折腾折腾,怎么知道自个儿几斤几两呢?



感谢您的阅读,如果您觉得本文有用,快点击下方点赞按钮,让更多的人看到本文。

本内容采用人工智能辅助协作,经本人审核,符合本人观点与立场。