给 LibLLIE 写一个 Skill
LibLLIE 是一个统一的低照度图像增强工具包。它把传统算法、深度学习模型、训练、推理、图像读写和质量评估都放进了同一套接口里。对人来说,这意味着能力完整;对 Agent 来说,却意味着它必须先回答一连串问题:该调用 CLI 还是 Python API?缺少 checkpoint 时能不能继续?生成训练代码后要不要立刻运行?没有参考图时又能计算哪些指标?
所以我给 LibLLIE 写 libllie-cli Skill 时,没有把它做成一份加长版命令手册,而是把它设计成了一层决策系统:先判断任务类型,再加载必要文档,最后选择与风险相匹配的 tool calling 策略。
先把知识拆成可按需读取的三层
整个 Skill 由入口、任务 reference 和脚本模板三层组成:
skills/libllie-cli/
├── SKILL.md
├── references/
│ ├── inference.md
│ ├── training.md
│ └── validation.md
├── assets/
│ ├── train_script.template.py
│ └── validation_script.template.py
└── agents/openai.yamlSKILL.md 只负责所有任务共享的事情:环境契约、必填参数、资源检查、权限边界和失败后的恢复路径。识别出推理、训练或验证意图后,Agent 才会读取对应的 reference;需要生成代码时,再复制并改写相应模板。
reference 也没有重复 LibLLIE 的完整文档,而是充当索引。例如,推理 reference 会把 Agent 导向 predict、图像 I/O 或某个具体模型的文档;训练 reference 才会引入配置和数据集知识。这样,一次简单的 HE 增强不会把训练配置、模型列表和全部指标都塞进上下文。
推理、训练、验证不能使用同一种 tool calling
这是这个 Skill 最重要的设计。三类任务虽然都属于 LibLLIE,但它们的执行成本、参数结构和失败方式完全不同,因此我为它们选择了不同的调用策略:
| 任务 | 调用策略 | 默认是否执行 | 设计原因 |
|---|---|---|---|
| 推理与图像写入 | 直接调用 CLI | 是 | 输入输出明确,命令短,结果可立即检查 |
| 训练 | 生成 Python 脚本 | 否 | 配置复杂、耗时长,可能占用 GPU 或下载权重 |
| 验证 | 生成 Python 脚本 | 否 | 指标依赖不同,需要先检查目录、参考图和自定义注册 |
这种差异化策略比“一律生成 shell 命令”更稳健,因为 tool calling 的形式本身就是安全边界的一部分。
推理:短链路,直接调用 CLI
推理适合直接执行。Agent 先读取 references/inference.md,在不知道可用组件时运行:
"$LIBLLIE_PYTHON" -m libllie.cli list确定目标后,再调用 predict 或 imwrite,并显式传入输入、输出与 checkpoint 路径。这里刻意使用注册环境中的 Python 执行 -m libllie.cli,而不是假设当前 shell 一定能找到 libllie 可执行文件。
但“可以直接执行”不等于“可以猜参数”。传统算法可以直接用算法名;深度学习推理如果只给出模型名,LibLLIE 只能创建模型结构,并不会凭空得到训练权重。因此 Skill 要求 checkpoint 必须是真实存在的 .pt 或 .pth 文件,并检查模型可能额外依赖的预训练路径。缺少 checkpoint 时,它不会编造路径,而是给出两条恢复路线:生成训练脚本得到 best.pt 或 last.pt,或者根据模型文档前往官方来源下载权重。
训练:先生成可审查脚本,再决定是否运行
训练不走 CLI,而是从 train_script.template.py 生成一个调用 llie.train(...) 的 Python 脚本。原因很直接:训练参数多、运行时间长,还可能占用 GPU、下载 VGG 权重或覆盖实验输出。把所有内容塞进一条命令既难审查,也不利于复用和版本控制。
Agent 会先检查用户提供的 YAML 或覆盖参数,优先使用已有配置和 LibLLIE 默认值,只追问文档没有默认值的事实。最低限度要能确定模型和数据集根目录,root_dir、resume、输出目录以及模型特有的预训练路径都保持显式。
生成脚本并不自动获得执行训练的授权。只有用户明确要求运行时,Agent 才会使用已经注册的 $LIBLLIE_PYTHON 执行它。这把“帮我准备训练”与“现在开始消耗计算资源”分成了两个清晰动作。
验证:先编码指标约束,再调用评估 API
验证同样生成 Python 脚本,但它与训练共享的只有“默认不执行”这一条。评估最容易出错的地方不是 API 拼写,而是指标与数据之间的关系:PSNR、SSIM、MSE、MAE、LPIPS 和 LOE 需要参考图,NIQE、MUSIQ 和 PI 则可以进行无参考评估。
因此 validation_script.template.py 会在 llie.evaluate(...) 之前检查增强图目录、可选的参考图目录,以及当前指标是否必须提供参考图:
if REF_IMG_DIR is None and any(
metric.upper() in FULL_REFERENCE_METRICS for metric in METRICS
):
raise ValueError("Full-reference metrics require REF_IMG_DIR.")它还要求批量推理保留文件名,让增强图与参考图能够按 stem 配对;如果使用自定义指标,则先导入对应模块完成注册,再开始评估。这些检查让错误在昂贵的批量计算之前暴露,而不是运行到一半才发现输入不成立。
Makefile:一次安装,让多个 Agent 平台复用
Skill 本体只描述应该怎样使用 LibLLIE,却不应该在每次任务中扫描 Conda、uv 和系统 Python。环境发现被我前移到了安装阶段,并集中放进项目根目录的 Makefile。
安装时,make link-skills 会把 Skill 链接到通用的共享目录:
~/.agents/skills/libllie-cli它没有分别维护 Codex、Claude 等平台的多份副本。支持读取 ~/.agents/skills 这一共享约定的 Agent 平台,可以发现同一个 Skill;SKILL.md 提供通用行为说明,agents/openai.yaml 再补充 OpenAI Agent 所需的展示名称、简介和默认提示。这样做的重点不是“复制到更多目录”,而是让一份源文件成为多个 Agent 的共同事实来源,仓库更新后链接内容也会同步更新。
Makefile 同时会检测三种 Python 环境:
make link-skills # 当前 python
make link-skills env=uv # 项目 .venv
make link-skills env=conda name=<name> # 指定 Conda 环境检测成功后,它把仓库位置和 Python 解释器写入:
export LIBLLIE_ROOT="/path/to/LibLLIE"
export LIBLLIE_PYTHON="/path/to/python"这份环境文件位于 ~/.agents/env/libllie-cli.env。Skill 运行时只消费这两个确定值,不再根据当前终端状态猜测环境。Makefile 还处理了几个容易被忽略的安装细节:目标目录不可写时立即失败,不覆盖同名的普通文件,只替换符号链接;环境文件已经完整存在时会保留原配置;首次写入则通过临时文件和 mv 完成,避免留下半份配置。
安装、运行的职责因此被彻底分开:Makefile 负责发现并登记环境,Skill 负责按照环境契约调用工具。即使切换 Agent 平台,Python 路径也不会随当前 shell 漂移。
示例代码不只是演示,而是标准用法
我没有让 Agent 每次临时拼接训练和验证代码,而是在 assets/ 中提供了两份可复制的标准模板。它们的作用不是展示最短调用,而是给生成结果规定一套稳定结构。
训练模板同时覆盖了 LibLLIE 推荐的两种配置方式:有 YAML 时调用 llie.train(config_path, **overrides),没有 YAML 时传入结构化配置字典。数据集根目录、输出目录和断点路径集中放在顶部,使用 Path 与明确的类型标注,并通过 main() 和 if __name__ == "__main__" 保持脚本可直接执行、也可安全导入。
验证模板则把路径检查、全参考指标判断、保存目录创建、自定义指标导入和 llie.evaluate(...) 调用分开。save_path、return_evaluator 与额外 evaluator 参数都有明确入口,而不是把一组不透明的参数散落在生成代码里。
这类模板比 README 里的一行 quick start 更适合 Agent:它们给出的不是唯一答案,而是一个不容易漏掉关键步骤的代码骨架。Agent 只需要填写顶部的用户数据和配置,就能产出风格一致、可审查、可复用的脚本;用户后续手动修改时,也能快速找到真正需要关注的位置。
鲁棒性来自“知道什么时候停下来”
除了调用策略,我还在 Skill 中加入了明确的参数门禁:
- 推理必须有
target和source,checkpoint 类目标必须真实存在。 - 训练至少要能确定模型与数据集根目录,不替用户虚构数据集或输出路径。
- 验证必须有增强图目录,只有全参考指标才强制要求参考图目录。
- 普通操作只读取 reference 链接到的文档,不随意进入源码、数据集、checkpoint 或 YAML 模板探查。
- 脚本与输出写到用户工作区,Skill 与 LibLLIE 仓库保持只读。
这些限制并不是让 Agent 少做事,而是把无法从工具和文档确认的事实留给用户。与此同时,缺少 checkpoint、数据集或感知损失权重时,Skill 会给出具体的恢复路径,而不是只返回一句“文件不存在”。
最后
给 LibLLIE 写 Skill 的过程,让我更加确定一件事:好的 Skill 不是把文档重新包装成提示词,而是为不同任务设计合适的行动路径。
在 libllie-cli 中,推理走直接 CLI,以缩短调用链;训练走可审查的 Python 脚本,把昂贵执行留给明确授权;验证走带领域约束的脚本,在计算前阻断不成立的指标组合。Makefile 再把共享安装和环境检测前移,标准模板则让 Agent 生成的代码更接近真实项目中的工具用法。
最终形成的是一套清晰分工:SKILL.md 做决策,reference 做导航,LibLLIE 文档提供事实,模板提供标准实现,Makefile 保证不同 Agent 在同一个确定环境里工作。对我来说,这比多记住几条命令更接近 Skill 的真正价值。