一、起因:调色不该这么复杂
图像调色虽然看似只是微调一些滑块,实际上涉及多个关联参数:色温、亮度、对比度、饱和度、阴影、高光等等。对于普通用户来说,这些名词本身就不够直观,更别说理解它们之间的相互影响。即便是熟悉图像处理的用户,调出理想效果也往往需要多次尝试与回退。
我在开发图像编辑器 Monica(github.com/fengzhizi71...) 的过程中,一直希望降低调色门槛。于是,我开始尝试一个思路:能否用自然语言来驱动参数,让用户说一句话,比如"让肤色冷一点",系统就能自动完成一系列合理的参数调整?
随着近年来大模型(LLM)在语言理解和结构化输出方面的能力逐渐成熟,这个目标不再只是想象。我尝试接入一个 LLM 模型,为 Monica 增加一个「自然语言调色助手」。
二、我的方案:LLM + 参数结构
为了让大模型具备调色能力,我使用了 DeepSeek 提供的 API 接口。它支持中文自然语言输入,并且能够输出结构化 JSON 格式,便于程序直接解析使用。
用户每次输入一句自然语言指令,比如"肤色偏黄,冷一点",我会将当前的调色参数作为上下文信息,一起发送给模型。模型返回的结果是一组结构化的参数调整结果,例如:
json
{
"temperature": 200,
"status": 5
}
其中各项参数值直接对应 Monica 的定义好的调色参数结构 ColorCorrectionSettings:
kotlin
data class ColorCorrectionSettings(
val contrast:Int = 255, // 对比度,范围 0-510
val hue:Int = 180, // 色调,范围 0-360
val saturation:Int = 255, // 饱和度,范围 0-510
val lightness:Int = 255, // 亮度,范围 0-510
val temperature:Int = 255, // 色温,范围 0-510
val highlight:Int = 255, // 高光,范围 0-510
val shadow:Int = 255, // 阴影,范围 0-510
val sharpen:Int = 0, // 锐化,范围 0-255
val corner:Int = 0, // 暗角,范围 0-255
val status:Int = 0 // 1 contrast, 2 hue, 3 saturation, 4 lightness, 5 temperature, 6 highlight, 7 shadow, 8 sharpen, 9 corner
)
所以每次调用后,模型会返回完整参数对象,我只需用返回的调色参数来更新图像效果。为了便于 UI 提示用户「这次改了什么」,ColorCorrectionSettings 恰好有一个辅助字段 status,用来标识当前轮被重点修改的参数,例如 status=5 表示"色温"发生了变化。
这套机制简单、稳定,并且可以自然支持"多轮会话",是后续构建交互式调色系统的基础。
三、关键实现点
3.1 Prompt 设计:构造有上下文的对话输入
为了让大模型理解并正确生成调色参数,我构造了一个包含当前参数上下文的 prompt。请求结构分为两部分:
- system 消息:定义模型角色。例如:
swift
"你是一个图像调色助手。用户会输入一句话,你需要将这句话转换为一组 JSON 格式的调色参数,字段说明如下:\\n\\n- contrast: 对比度,整数,范围 0 - 510,默认值 255。\\n- hue: 色调,整数,范围 0 - 360,默认值 180。\\n- saturation: 饱和度,整数,范围 0 - 510,默认值 255。\\n- lightness: 亮度,整数,范围 0 - 510,默认值 255。\\n- temperature: 色温,整数,范围 0 - 510,默认值 255。\\n- highlight: 高光,整数,范围 0 - 510,默认值 255。\\n- shadow: 阴影,整数,范围 0 - 510,默认值 255。\\n- sharpen: 锐化,整数,范围 0 - 255,默认值 0。\\n- corner: 暗角,整数,范围 0 - 255,默认值 0。\\n- status: 表示用户意图主要修改了哪一项(用于前端高亮显示),值如下:\\n - 1 表示 contrast\\n - 2 表示 hue\\n - 3 表示 saturation\\n - 4 表示 lightness\\n - 5 表示 temperature\\n - 6 表示 highlight\\n - 7 表示 shadow\\n - 8 表示 sharpen\\n - 9 表示 corner\\n\\n要求:\\n- 不要输出解释。\\n- 严格输出 JSON 格式,字段顺序与上方一致。\\n- 如果用户输入不涉及某些参数,请保留默认值。\\n- 请根据语义合理推测用户意图。"
- user 消息:拼接当前调色参数 + 用户输入的自然语言指令,格式如下:
makefile
当前调色参数如下:
contrast: 255
hue: 180
...
用户指令:"让肤色冷一点"
这种组合方式可以让模型理解当前状态,并生成"增量式"的调整结果,避免从头生成。
3.2 多轮对话:基于当前参数持续调整
每次用户提交一句新指令,我会把上一次生成的参数作为"当前状态"传入下一轮请求中,实现连续调色。例如用户可以连续说:
- "再亮一点"
- "肤色更自然一点"
- "暗角加重一些"
每轮模型输出的结果都会被解析为新的 ColorCorrectionSettings,并作为下一轮上下文继续参与交互。这种机制模拟了"连续对话中的状态记忆",用户无需重复说明所有内容。
我在客户端维护了一个 DialogSession 会话状态对象,这种方式避免了用户重复描述,也使模型具备了"记忆能力",调色过程更加连贯自然。
kotlin
data class DialogSession(
val systemPrompt: String,
var currentSettings: ColorCorrectionSettings,
val history: MutableList<Pair<String, ColorCorrectionSettings>> = mutableListOf()
)
3.3 Compose 弹窗组件:对话式调色界面
在 UI 层,我基于 Kotlin Compose 实现了一个轻量级的弹出对话框组件。主要功能包括:
- 输入自然语言指令;
- 调用 DeepSeek API 并异步等待响应;
- 显示当前会话的历史记录(用户输入 + 模型响应);
- 将参数更新实时传回图像处理模块,触发图像调整。
用户只需和"调色助手"对话,不再需要直接操作一堆滑块。
下面的代码展示了如何通过跟 DeepSeek 的 API 进行多轮对话,获取对应的调色参数,并把用户指令和调色参数保存。(省略了网络请求和解析 json 对象)
替换成其他的大模型也是类似的,比如换成 OpenAI 的 API 只要改少许代码即可。
kotlin
/**
* 每次根据当前参数和新指令拼 prompt, 支持多轮对话
*/
@Throws(MonicaException::class)
suspend fun applyInstructionWithLLM(
session: DialogSession,
instruction: String,
apiKey: String
): ColorCorrectionSettings? {
val prompt = buildString {
append("当前图像的参数如下:\n")
append(GsonUtils.toJson(session.currentSettings))
append("\n\n")
append("用户指令:$instruction")
}
val messages = mutableListOf<DeepSeekMessage>().apply {
this.add(DeepSeekMessage(role = "system", content = systemPromptForColorCorrection))
this.add(DeepSeekMessage(role = "user", content = prompt))
}
val deepSeekRequest = DeepSeekRequest("deepseek-chat", messages, false)
val payload = GsonUtils.toJson(deepSeekRequest)
val responseJson = sendPostJson(
url = "https://api.deepseek.com/chat/completions",
headers = mapOf("Content-Type" to "application/json",
"Authorization" to "Bearer $apiKey"),
body = payload
)
try {
val json = extractJson(responseJson)
val responseObj = GsonUtils.fromJson<ColorCorrectionSettings>(json, ColorCorrectionSettings::class.java)
session.currentSettings = responseObj
session.history.add(Pair(instruction, responseObj)) // 保存用户指令、调色参数
return responseObj
} catch (e: Exception) {
logger.error("responseJson = $responseJson")
logger.error(e.message, e)
throw MonicaException("无法获取调色的参数")
}
}
效果演示:






四、小结与展望
这次尝试只是一个起点,我用最简单的方式让 Monica 图像编辑器具备了自然语言调色的能力。借助大模型对中文语义的理解能力,用户无需理解"色温"、"对比度"等专业术语,只需要一句话就能驱动参数调整。
从技术实现上看,结构化参数 + prompt 工程 + 多轮上下文状态,是搭建语言驱动交互的关键几个要素。它也证明了传统图像处理工具完全可以与 LLM 接轨,提升交互体验,而不一定非要端到端"全自动"。
下一步,我可能会尝试接入更丰富的视觉模型,实现更多的功能,继续探索「自然语言 × 图像编辑」的边界。我也可能会考虑在本地部署 LLM,以提升响应速度和可控性。
图像编辑器 Monica 的地址:github.com/fengzhizi71...