腾讯云服务器

拍了 200 张照片,5 分钟发了朋友圈 —— 我搭建了一个会全自动修图的小龙虾

周末踏春拍了 200 多张照片,回家一看,选片头疼,修图劝退,又是熟悉的"拍完不修、修完不发"剧本。这次我决定换个活法:花一个下午,在腾讯轻量云上用 OpenClaw 搭了一只会全自动修图的"摄影虾"🦞。照片丢进去,选片、调色、排版一条龙,5 分钟直接发朋友圈。硬盘吃灰?不存在的!


一、困境:200 张照片的选片噩梦

三月的西安春意正浓,许久未拿起相机的我终于出门踏春赏花了。

快门咔咔响了一下午,回家往电脑上一导,200 多张 RAW 文件。

满意地合上相机包,打开朋友圈,正准备来一组九宫格 ——

然后我卡住了。

200 张照片,选哪 9 张?

打开 Lightroom,面对几十个滑块,哪个该动?网上教程千千万,跟着调了半小时,出来的效果总差那么点意思。好不容易调完一张,还剩 199 张等着我。

算了,先吃饭吧。

饭后再打开电脑,对着那个文件夹叹口气。算了,明天再说。

明天变后天,后天变下周。一个月后,那个叫「踏春」的文件夹依然安静地躺在硬盘里,和旁边的「元宵」「过年」「跨年」们默默作伴。

这大概是 90% 摄影爱好者的真实写照。

快门按下的那一刻是快乐的。之后的一切 —— 选片、修图、排版、发布 —— 全是摩擦力。

不是不想做,是门槛太高、太耗时间。


二、灵感:让 OpenClaw 做后期助手

正当我躺下,准备用短视频来消除因懒惰而产生的内疚时 ——

手机屏幕亮了。

是 QQbot 发来的消息提醒:「Boss,你今天还没有告诉我有没有运动呢 😊」。

我盯着那条消息愣了几秒,然后猛地坐起来。

对啊!我在腾讯轻量云上还部署了一个"小龙虾"(OpenClaw)!

前阵子 OpenClaw 火爆全网,我第一时间在轻量云上部署了一套,把它当私人健康助手用:提醒运动、记录饮食、分析睡眠质量。没想到今天还能派上别的用场。

忽然一个念头闪过:能不能让这个"小龙虾"帮我做后期?

它有多模态能力,能看懂照片内容;它能写代码,能调用脚本;最重要的是,它就在云端,不用我自己折腾环境。

我重新打开电脑,看着那个叫「踏春」的文件夹。这次,眼神不一样了。


三、构建:武装我的小龙虾

3.1 调研:这事儿能不能干?

想法归想法,能不能实现是另一回事。我赶紧打开元宝,把脑子里的问号一股脑丢了过去:

「Python 能直接读相机 RAW 格式文件吗?比如尼康的 NEF?」

元宝告诉我:有个叫 rawpy 的库,底层封装了 LibRaw,几乎支持所有主流相机品牌的 RAW 格式,尼康 NEF、佳能 CR2/CR3、索尼 ARW、富士 RAF……甚至哈苏的 3FR 和飞思的 IIQ 也没问题。几行代码就能把 RAW 解码成 numpy 数组,再用 Pillow 转成 JPG。

「那怎么用代码给照片修图?能像 Lightroom 那样调曝光、对比度、色温吗?」

元宝说可以。rawpy 负责 RAW 解码,Pillow 和 numpy 负责像素级运算:曝光用 2^x 乘法、对比度用 S 曲线、白平衡用通道增益。再配上 scipy 的样条插值,连参数化色调曲线都能实现。虽然效果不如 Lightroom 的专业算法,但对于社交媒体发图来说足够了。

「200 张照片怎么快速筛选?有没有什么模型能批量给照片打分?」

这个问题的答案让我眼前一亮:OpenAI 开源的 CLIP 模型可以做「美学评分」,配合 LAION 的美学评分头,还能直接输出 1-10 分的美学分数。再加上余弦相似度去重,连拍的重复照片也能自动过滤。

但是 CLIP 模型有很多,我该选择哪个呢?这些模型在我的 4C8G 的轻量云服务器上跑得起来吗?

一翻搜索之后,我挑选了 4 个候选模型,以其中最大的模型(ViT-L/14)为基准,在我这台轻量云服务器上跑了 4 轮实测取均值(每轮内部 3 次编码取中位数,子进程隔离):

模型
编码速度
耗时百分比
Top-10 重合度
模型大小
ViT-L/14(基准)
1477ms/张
100%
10/10
890M
ViT-B/32
109ms/张
7.4%
7/10
338M
MobileCLIP2-S0108ms/张7.3%8/10300MB
MobileCLIP2-S2
226ms/张
15.3%
9/10
398M

最后选了苹果的 MobileCLIP2-S0,因为它:

  1. 速度够快
    :108ms/张,只有基准 ViT-L/14 耗时的 7.3%。4C8G 的 CPU 上处理 200 张照片只要 22 秒,而 ViT-L/14 要将近 5 分钟。
  2. 选片质量有保障
    :Top-10 选片和基准模型有 80% 重合(4 轮测试结果完全一致),意味着同一批照片里它选出的"最好的 10 张"和全尺寸模型只差 2 张。对于预筛来说,这个精度绰绰有余,反正最终选片还要多模态大模型来把关。
  3. 模型最小
    : 最轻量,最适合轻量云的部署环境。

唯一需要处理的兼容性问题是:MobileCLIP 的 embedding 维度是 512,而 LAION 美学评分头要求 768 维输入。解决方案很简单:零填充补齐,256 维的零向量不影响线性层的有效权重。实测下来,皮尔逊相关系数 0.66,排序一致性完全够用。

一连串问答和实测下来,我心里有底了:每一步都有成熟的开源方案,而且跑得飞快。

接着我把这些技术方案交给 CodeBuddy,让它帮我开发了三个独立的 Skill(技能模块),装备给我的小龙虾:

Skill
干什么
核心依赖
photo-converter
RAW → JPG 缩略图,按拍摄日期筛选照片,生成排版预览
rawpy
 + Pillow + numpy(系统依赖 LibRaw)
photo-screener
CLIP 智能预筛:美学评分、连拍去重、场景分类
torch
 + open-clip-torch(模型:MobileCLIP2-S0,约 300MB)
photo-grader
13 步 Lightroom 风格修图:曝光 → 白平衡 → 色调映射 → 对比度 →HSL→ 色彩分级 → 锐化 → 降噪 → 胶片颗粒…
rawpy
 + Pillow + numpy + scipy

每个 Skill 都是自包含的目录,里面有 Python 脚本、配置文件、依赖清单和安装脚本。OpenClaw 能自动读取 Skill 的说明文档,知道什么时候该调用哪个模块、怎么传参数。

有了这三把"武器",接下来就是设计怎么把它们串起来。

但仔细捋一遍流程,我发现少了关键一环:CLIP 只能打分和分类,看不懂一张照片该怎么修。我需要一个真正能理解画面内容的多模态大模型,看完照片后告诉我:"这张曝光欠了,高光该压一点,色温偏暖 200K……"

我又打开元宝,丢了一张阴天拍摄的秦岭山脚下的紫叶李照片过去,问它:「你能根据这张照片给我一组修图参数吗?用 JSON 格式输出,包括曝光、对比度、白平衡、HSL 这些。」

元宝还真给了。不仅给了参数,还附带了每个参数的理由:"紫叶李花瓣偏白,建议高光 -0.15 防止过曝"、"背景绿叶可以通过 HSL 绿色色相偏移增加层次感"。。。

能看图、能输出结构化 JSON、能解释审美判断 —— 这不就是我需要的「修图顾问」吗?

但问题来了:元宝的多模态能力没法在外部脚本里直接调用。我没有可以直接 curl 的多模态 API Key。怎么把这个能力接进我的小龙虾?

这时我想到了 OpenClaw 的 Coding Plan,它是 OpenClaw 管理 API 配额的机制,我的 plan 里已经绑了支持多模态的大模型。而且 OpenClaw 支持多个 Agent 协作,每个 Agent 都能继承 plan 里的模型能力……

等等,这不就全串起来了吗?

我只需要注册一个专门负责"看图 + 出参数"的 Agent,它天然就能用 plan 里的多模态模型看照片、做审美判断、输出 JSON 参数,不用我自己申请 API Key,不用管鉴权,OpenClaw 会自动处理。

3.2 设计:双 Agent 协作架构

于是,我设计了一套双 Agent 协作系统,就像一个摄影工作室里的两个角色:

🦀 PhotoGrapher Agent —— 任务调度 + 脚本执行

负责理解我的意图、编排整个流程、执行所有脚本、汇报结果。它手里握着三个 Skill:photo-converter(格式转换)、photo-screener(CLIP 预筛)、photo-grader(批量修图)。

📸 PhotoCurator Agent —— 摄影审美专家 + 修图顾问

负责"看"照片:分析每张照片的内容和构图、决定选哪些不选哪些、为每张照片生成独立的 JSON 修图参数、规划九宫格排版方案。它通过 OpenClaw 的 Coding Plan 获得多模态能力,天然能看懂图片。

两者通过 OpenClaw 的消息机制协作:我只需要说一句「帮我处理今天的照片」,PhotoGrapher 接住需求、拆解任务、跑脚本;需要"看图做判断"的部分,委派给 PhotoCurator 来完成。

为什么要拆成两个 Agent?

原因有三:

  1. 模型能力不同。 编排 Agent 不需要多模态能力,用通用文本模型就够了,跑起来更快更省 token。审美 Agent 必须用视觉模型看图,但视觉模型 token 消耗更大、推理更慢。拆开之后,各用各的模型,谁也不拖累谁。

  2. 上下文隔离。 200 张缩略图发给视觉模型分析,光图片就要吃掉大量上下文窗口。如果编排和审美混在一个 Agent 里,脚本执行的日志、文件路径、错误信息会和图片分析互相争抢 token 空间。拆成两个 Agent,各自的上下文窗口只装自己需要的信息。

  3. 可独立迭代。 修图方案不满意?只改 PhotoCurator 的 prompt 就行,不影响执行逻辑。脚本要换?只改 PhotoGrapher 的 Skill,不影响审美判断。两个角色解耦,改一个不会炸另一个。

Image

3.3 踩坑:第一张照片过曝成白板

架构设计得再漂亮,真跑起来还是会翻车。

第一次让 AI 修图,我满怀期待地打开成品 —— 一张白花花的照片。

Image

怎么回事?

原来,AI 大模型的修图经验来自海量 Lightroom 教程。它给出的曝光参数是 +1.5,在 Lightroom 里这是个温和的值,但我的 Python 脚本用的是 2^x 算法,+1.5 意味着 2.83 倍亮度,直接过曝成白板。

同样的参数名,同样的数值,在两个系统里效果天差地别。

这就好比你跟一个只用过华氏度的美国人说"今天 30 度",他会以为要穿羽绒服。单位不同,数值就没有意义。

我花了几十轮迭代,才摸清每个参数在脚本里的"安全范围"。这里面的水比想象中深,几乎每个参数都需要重新校准:

参数
Lightroom 里的常用范围
Skill 脚本的安全范围
差了多少
曝光
-2.0 ~ +2.0
-0.3 ~ +0.3
6.7 倍
锐化
0 ~ 150
10 ~ 40
3.8 倍
色彩分级饱和度
0 ~ 100
0 ~ 15
6.7 倍
对比度
-100 ~ +100
-30 ~ +40
~3 倍

每个参数都是这样:AI 按 Lightroom 的经验给值,我的算法用完全不同的数学公式算,最后出来的效果南辕北辙。曝光用的是 2^x 指数乘法、对比度用的是中间值 0.5 基准乘法、高光和阴影用的是乘法式色调映射,全都和 Lightroom 的加法逻辑不一样。

这不是用法不对,而是自研算法和商业软件之间本质的差距。Lightroom 有几十年的色调映射和感知模型积累,我的脚本用的是教科书级别的数学公式:指数、线性、高斯模糊。这个差异是不可消除的。

3.4 尝试:给参数加安全围栏

最直观的方案:既然 AI 给的值太大,那就强制限制范围呗。于是我做了一套"参数约束"机制:

  • 在 AI 的 prompt 里嵌入参数安全范围表,让它按算法而非 Lightroom 出参数
  • 脚本执行前逐参数约束,超出范围的值自动压回安全区间

跑了几轮,过曝问题确实解决了。但很快我发现了新的问题 ——

约束会打破参数之间的比例关系。

还是这张紫叶李山景照,AI 给了一组精心搭配的参数,曝光 +0.7、对比度 +30、高光 -65、阴影 +50。阴天灰暗的场景,提曝光 + 压高光 + 拉阴影是标准的 Lightroom 手法,四个参数相互协调。但算法的曝光安全范围只有 ±0.3,约束机制直接把 +0.7 砍到 +0.3,高光和阴影却原封不动 —— 比例关系被打破了,曝光不够但阴影还在猛拉 +50,对比度 +30 又在加反差。

预览成片,约束方案的问题一目了然:右图天空出现诡异的色彩伪影,暗部被阴影 +50 强行拉起后噪点暴露,整体色调怪异。参数比例一乱,欠曝像素从原图的 3.9% 飙到了 8.9%:

Image

问题出在哪?

3.5 破局:参数映射而非约束

约束砍了曝光(+0.7→+0.3),高光只微调(-65→-60),但阴影 +50 和对比度 +30 原封不动 —— AI 精心搭配的参数组合,被粗暴的约束拆散了。 我突然意识到方向搞反了:大模型天然就是按 Lightroom 的逻辑思考的,它的训练数据里有几百万篇 Lightroom 教程。强迫它学一套全新的算法安全范围,不仅反直觉,还容易出错。

真正该做的不是约束 AI 的输出,而是在 AI 和算法之间加一层翻译。

让 AI 继续用它最擅长的 Lightroom 参数,算法自动把 Lightroom 值"翻译"成等效的算法值。就像同声传译,你说中文,我说英文,意思不变。

于是我给修图脚本加了一个 map_lr_to_engine() 映射函数。每个参数都有独立的缩放系数,比如曝光 ×0.15、对比度 ×0.35、高光 ×0.45、锐化 = 10 + LR 值 ×0.20……而且关键参数(曝光、对比度、高光、阴影)还会根据图片的直方图自适应调整:暗片多缩一点曝光,高动态范围照片多保留一点对比度。

我用上面的照片对比了下这两种方案生成参数的区别:

参数
AI 原始值
约束方案(硬砍)
映射方案(等比缩放)
曝光
+0.7
→ +0.3 ⚠️ 被截断
→ +0.105(×0.15)
对比度
+30
→ +30(未触发)
→ +10.5(×0.35)
高光
-65
→ -60 ⚠️ 微调
→ -29.2(×0.45)
阴影
+50
→ +50(未触发)
→ +22.5(×0.45)

约束方案只砍了曝光和高光,对比度和阴影纹丝不动,四个参数的比例关系全乱了。映射方案则是所有参数同步缩小,+0.7 : +30 : -65 : +50 的比例关系完整保留。

对比测试的指标也很直观:

指标
约束方案
映射方案
欠曝像素比例
8.9%
6.5%
参数比例保持
❌ 被打破
✅ 完整保留
AI 需要学习算法知识
需要
不需要

回头把原图、约束方案、映射方案放在一起看,差距一目了然:

Image

最右边的映射方案,天空自然、紫叶李粉嫩、山体层次保留,和左边的原图相比微微提亮暖调刚好。映射方案完胜。它保留了 AI 的"创作意图",所有参数按比例缩放,相对关系不变。约束只作为映射后的最后一道保险,防止极端值。

同时我又对比了一下另外一张晴天拍摄的照片,发现还是映射方案生成的效果更好。

Image

最终方案变成了三层防御:

第一层,让 AI 自由表达。 Prompt 里不再有算法安全范围表,AI 直接用 Lightroom 标准参数输出修图方案。配上真实验证过的 few-shot 案例和场景分类策略,让 AI 专注于审美判断。

第二层,算法自动映射。map_lr_to_engine() 将 Lightroom 参数逐一翻译为算法等效值,直方图自适应调整关键缩放系数。AI 的创作意图被完整保留。

第三层,安全约束兜底。 映射后再经过 clamp_params() 逐参数约束,防止极端情况下的伪影。这是最后一道保险,不是主要策略。

Image

AI 负责「想」,算法负责「翻译 + 执行」,两者之间用 JSON 传递意图。 修图参数全程可审查、可复现、可手动微调。这不是黑盒魔法,而是一条透明的工作链路。


四、实战:从终端到手机

到目前为止,核心能力已经跑通了,接下来要做的,就是把这些 Skill 和 Agent 正式"装"进 OpenClaw。让我可以通过 QQBot 来指挥我的"摄影虾"干活。

之前的"健康助手"也是 QQ Bot,但是我并不想混用,因为会"污染"上下文和历史记录。所以,我新建了一个 QQ Bot,专门用来控制小爪。

4.1 配置:把 Skill 和 Agent 装进 OpenClaw

我需要做四件事:注册两个 Agent、给 Agent 设置"灵魂"、配置专属 Skill、绑定 QQ Bot。

第一步:注册 Agent。

在 openclaw.json 的 agents.list 里加两条:

{
"agents":{
"list":[
{
"id":"photographer",
"name":"photographer",
"workspace":"/root/.openclaw/workspace-photographer",
"subagents":{
"allowAgents":["photocurator"]
}
},
{
"id":"photocurator",
"name":"photocurator",
"workspace":"/root/.openclaw/workspace-photocurator",
"thinkingDefault":"high"
}
]
}
}

photographer(小爪 🦀)是编排师,负责接活、拆任务、跑脚本;photocurator(小策 📸)是审美专家,负责看图、选片、出修图参数。小爪可以调用小策(allowAgents),但小策不能反过来调小爪,职责单向,不会循环。

thinkingDefault: "high" 让小策默认启用深度思考,审美判断不能图快,得想清楚。

第二步:给 Agent 设置"灵魂"。

每个 Agent 的 workspace 里放一个 IDENTITY.md,定义它是谁、怎么干活:

# 小爪 🦀 — 摄影工作流编排师

- 端到端照片处理流程(RAW → 缩略图 → 预筛 → 选片 → 修图 → 排版)
- 需要审美判断时委派给 PhotoCurator 📸
- 修图参数由引擎自动映射(Lightroom 参数 → 引擎值)
# 小策 📸 — AI 摄影后期专家

- 分析照片内容、构图、光影,挑选最佳作品
- 生成 Lightroom 标准参数的修图方案 JSON
- 参数保守主义:首次偏保守,微调优于推翻重来

再放一个 SOUL.md 定义行为准则,什么该做什么不该做,什么时候该问我什么时候自己决定。这些文件 OpenClaw 启动时会自动加载,Agent 天然就"知道"自己是谁。

第三步:给小爪配置专属 Skill。

把之前开发的三个 Skill 扔进 workspace-photographer/skills/ 目录:

workspace-photographer/
└── skills/
    ├── photo-converter/    # RAW 转缩略图
    │   ├── SKILL.md        # 技能文档(OpenClaw 自动读取)
    │   ├── config.json     # 默认参数
    │   └── scripts/
    │       ├── convert.py
    │       ├── find_by_date.py
    │       └── layout_preview.py
    ├── photo-screener/     # CLIP 预筛
    │   ├── SKILL.md
    │   ├── config.json
    │   └── scripts/
    │       └── screen.py
    └── photo-grader/       # 批量修图
        ├── SKILL.md
        ├── config.json
        └── scripts/
            └── grade.py

每个 Skill 里的 SKILL.md 是给 Agent 看的说明书,输入什么格式、输出到哪里、参数怎么传。小爪读完 SKILL.md 就知道该怎么调这个模块,不用我每次手动指定。

第四步:绑定 QQ Bot。

修改 openclaw.json,把新建的 QQ Bot 绑定到 photographer Agent 上:

{
"channels":{
"qqbot":{
"enabled":true,
"allowFrom":["*"],
"accounts":{
"main":{
"appId":"",
"clientSecret":""
},
"photographer":{
"appId":"",
"clientSecret":""
}
}
}
},
"bindings":[
{
"agentId":"photographer",
"match":{"channel":"qqbot","accountId":"photographer"}
}
]
}

这样,我在 QQ 里跟"摄影虾"聊天,消息就会直接路由给 photographer Agent 处理。

重启 OpenClaw,看到日志里两个 Agent 都上线了。配置搞定。

4.2 实战:QQ 里的一句话修图

掏出手机打开 QQ,找到"摄影虾"。

帮我整理下 3 月 15 日的照片,我想发一个 9 宫格朋友圈

发送。

然后我就去泡了杯茶。

几分钟后,手机震了。小爪发来一张九宫格预览图,紧接着是一段执行报告:

✅ 3 月 15 日的 9 宫格朋友圈照片已经处理完成啦!采用了春日通透柔焦风格...

Image

点开九宫格预览图,9 张照片排列整齐,色调统一柔和,三月的春光全在里面了:

Image

这次效果不错,但仔细看发现第二排第一张照片横着躺了——相机方向传感器没识别对。这种自动旋转校正,后续也得让小爪学会自己处理。

于是我又补了一句:

把 9 张成品也发给我

很快,9 张修好的照片依次发了过来。我长按保存,打开朋友圈,选 9 张图,写一句"三月的花开了",发送。

那个在硬盘里吃了一个月灰的「踏春」文件夹,终于完成了它的使命。

4.3 扩展:手机照片也能调

发完朋友圈后我想到,不是每次拍照都会掏相机。更多时候是路上随手一拍,手机里躺着几十张 JPG 和 HEIC,同样懒得修。

之前的 Skill 是按相机 RAW 文件设计的,手机照片没有 RAW 解码这一步,HEIC 格式也需要额外处理。于是我又花了点时间优化流程:

  • photo-converter
     加了 HEIC/JPG 支持,自动识别输入格式,手机照片直接走 Pillow 解码,不再强制依赖 rawpy
  • photo-screener
     的 CLIP 预筛对手机照片同样有效,MobileCLIP 不挑输入来源,分辨率自适应
  • photo-grader
     的修图引擎区分了 RAW 模式和 JPG 模式:RAW 从线性空间开始调,JPG 从已有色彩空间微调,两条路径参数范围不同

改完之后,在 QQ 里随手发了几张手机拍的花:

Image
效果不输相机,花瓣颜色鲜艳通透,背景柔和干净,修图参数依然全是 JSON,想微调随时可以。

从相机 RAW 到手机随手拍,摄影虾终于可以覆盖我日常拍照的所有场景。


五、展望:让 AI 记住我的审美

这套系统用了几次之后,我有一个更大的念头。

目前每次选片,PhotoCurator 都是从零开始判断,它不知道我偏爱暖调、喜欢柔和的光线、每次都会给风景照加一点点暗角。

我想让它记住我。

每次选片、每次我对修图结果做的微调("高光再压一点""绿色再淡一些"),都写入一份「审美档案」。跑个几十次之后,它就不再是一个通用的审美专家,而是懂我的私人策展人。

甚至可以更进一步,把滨田英明的日系通透、何藩的光影戏剧感整理成「风格知识库」。修图时我说一句"这组用何藩的光影感来调",系统就知道该怎么做。

这些想法有的已经在做了,有的还在脑子里发酵。但这就是自己造工具的乐趣 —— 它不是固定的产品,而是随我成长的系统。


六、尾声:摄影的意义

写到这里,想聊一个更大的话题。

摄影到底意味着什么?

摄影的意义,从来不在器材多贵、参数多精准,而在于那个「我想记录」的冲动。

春天路边一树樱花、傍晚天边烧红的云、孩子们第一次骑自行车的瞬间 —— 这些画面如果不拍下来,就只能存在于越来越模糊的记忆里。

按下快门的那一刻,我们在对抗遗忘。

但记录不应该止步于快门。

一张未经处理的 RAW 文件,灰蒙蒙、暗沉沉,远不如肉眼看到的那一刻动人。后期不是造假,而是还原 —— 还原当时看到的光线、感受到的色彩、心里涌起的那股情绪。

问题在于,这份「还原」的能力,过去一直被锁在专业技能的高墙后面。

我知道自己喜欢暖调、喜欢柔和、喜欢天空有层次感,但不知道滑块该往哪拉。

审美和执行之间,隔着一道鸿沟。

AI 的作用,就是填上这道鸿沟。

我说出想要的感觉,AI 帮我翻译成技术参数,帮我执行。它不是取代我的审美,而是让我的审美得以表达。

摄影的快乐,不应该止步于按下快门的那一刻。

从快门到朋友圈,这条路本来可以很短。

现在,它真的很短了。