首页
/ Electron LanguageModelMessageContent 对象详解:Prompt API 多模态输入的内容载体

Electron LanguageModelMessageContent 对象详解:Prompt API 多模态输入的内容载体

2026-09-06 13:33:11作者:戚魁泉Nursing

Electron 的实验性 Prompt API 让 Web 内容可以像调用 Chromium 标准 LanguageModel 接口一样,把请求路由到开发者自己实现的本地 AI 处理器;而 LanguageModelMessageContent 对象正是这套机制中每一条消息的"内容单元",用于承载 textimageaudio 三类多模态输入。读完本文,你将掌握该对象两个字段的完整定义与取值组合规则、它与 LanguageModelMessage 的嵌套关系、从渲染进程 LanguageModel API 到 utility 进程处理器的底层数据转换链路,以及在实际代码中构造合法内容对象的实操方式。

对象结构:type 与 value 两个字段

LanguageModelMessageContent 对象(结构文档)只有两个字段:

字段 类型 说明
type string 内容类型,取值为 textimageaudio 之一
value ArrayBuffer | string 内容的实际数据

utility 进程的 gin 转换器源码 可以确认两种字段的配合关系:

  • type: 'text'valuestring,直接携带文本内容。源码中对应 dict.Set("type", "text"); dict.Set("value", val->get_text())
  • type: 'image'valueArrayBuffer,承载位图的原始像素数据。源码先将 Chromium 内部的 SkBitmap 转换为 N32 预乘(premultiplied)RGBA 格式再写入 ArrayBuffer,若像素读取失败会抛出 TypeError: Invalid bitmap content in prompt
  • type: 'audio'valueArrayBuffer,承载 float32 音频采样序列(源码中按 sizeof(float) * raw_data.size() 计算缓冲区大小并拷贝原始 std::vector<float> 数据)。

需要注意:虽然类型签名写作 ArrayBuffer | string,但按 typevalue 的组合约束,实际应为"text 用 string、image/audio 用 ArrayBuffer"。转换器源码中还留有 TODO 注释,说明图像像素与音频采样的具体数据布局(形状、采样率等)目前没有正式承诺,自定义处理器在解析二进制数据时应以防御式处理为前提。

该对象是 LanguageModelMessage结构文档)的组成部分:每条消息由 rolesystem / user / assistant)、contentLanguageModelMessageContent[] 数组)以及可选的 prefix 布尔字段构成。prompt() 等 API 允许传入多个内容项,因此一条消息中可以混排文本、图像与音频,这是多模态输入能力的直接来源。

渲染进程侧:LanguageModel API 如何消费该对象

LanguageModelMessageContent 面向的是 Web 内容一侧。要启用这套 API,渲染进程需要打开 Blink 实验特性,官方教程 local-ai-handler 给出了标准配置:

const win = new BrowserWindow({
  webPreferences: {
    enableBlinkFeatures: 'AIPromptAPI,AIPromptAPIMultimodalInput'
  }
});

其中 AIPromptAPI 启用 LanguageModel 全局接口,AIPromptAPIMultimodalInput 启用图像/音频等多模态输入支持。窗口启用后,页面内即可使用标准 API:

// 文本消息会被规范化为 { role: 'user', content: [{ type: 'text', value: '...' }] }
const model = await LanguageModel.create();
const reply = await model.prompt('hello world');

一个值得注意的规范化行为:当 prompt() 接收字符串简写输入时,Electron 会把它转换为标准的消息数组。测试用例 明确验证了处理器最终收到的输入形态:

// spec/api-local-ai-handler-spec.ts 中的断言
expect(message.input).to.deep.equal([
  { role: 'user', content: [{ type: 'text', value: 'hello world' }], prefix: false }
]);

同时该测试文件验证了直接传 LanguageModelMessage[] 的用法——content 数组中每项就是本文主角 LanguageModelMessageContent 对象:

const input = [
  { role: 'user', content: [{ type: 'text', value: 'hello' }] },
  { role: 'assistant', content: [{ type: 'text', value: 'hi' }] }
];
// model.prompt(input)
// 测试断言:每条消息的 prefix 都会被补为 false

此外 LanguageModel.create()initialPrompts 选项也接受同样的消息结构(测试中有 { role: 'system', content: [{ type: 'text', value: 'You are Electron AI' }] } 的实例),因此 LanguageModelMessageContent 同样适用于系统提示词的定义。

底层链路:mojo 结构如何转换成 JS 对象

从源码结构看,整个 Prompt API 的调用链是:渲染进程页面调用 LanguageModel 接口 → Blink 通过 mojo 把 AILanguageModelPrompt 结构发到浏览器进程 → ProxyingAIManager 将请求代理转发到通过 session.registerLocalAIHandler() 注册的 utility 进程 → utility 进程的转换器 把 mojo 结构转成 JS 字典,交给开发者代码。

其中 Converter<blink::mojom::AILanguageModelPromptContentPtr> 就是 LanguageModelMessageContent 的生成点:mojo 侧的 oneof 结构(text / bitmap / audio)被逐一映射为 { type, value } 字典,外层 Converter<blink::mojom::AILanguageModelPromptPtr> 再组装出 rolecontentprefix 三个字段。也就是说,你在 utility 进程处理器里拿到的每个 content 对象,其字段名和取值('text' / 'image' / 'audio')都由这层转换器固定下来。

浏览器进程侧还有一个可用性兜底:ProxyingAIManager::CanCreateLanguageModel 使用 WrapCallbackWithDefaultInvokeIfNotRun 把未响应的检查默认置为不可用。对应的测试行为是:utility 进程崩溃或未注册处理器时,LanguageModel.availability() 一律返回 'unavailable',页面侧不会挂起。

utility 进程侧:LanguageModelUtility 中的使用

在主进程侧,LanguageModelUtility 类是本地 AI 模型的 JS 实现载体,它的三个接受消息数组的方法都以 LanguageModelMessage[] 为输入,即间接消费 LanguageModelMessageContent

languageModelUtility.prompt(input, options)        // Promise<string> | Promise<ReadableStream<string>>
languageModelUtility.append(input, options)        // Promise<undefined>
languageModelUtility.measureContextUsage(input, options) // Promise<number>
  • prompt(input, options):对模型发起提示并获取响应;
  • append(input, options):仅追加消息到上下文,不产生响应;
  • measureContextUsage(input, options):计算输入将占用的 token 数。

因此,在 utility 进程的处理器脚本中,你可以按 item.type 分支处理不同内容项——text 直接读取字符串,image / audio 则通过 item.value(ArrayBuffer)拿到原始字节,交由自建的本地模型推理引擎消费。

适用前提与注意事项

  1. 实验特性LanguageModelUtility 的全部方法与渲染进程 LanguageModel API 均标注为 Experimental(见 LanguageModelUtility 文档),接口仍可能调整;
  2. 双端启用:完整链路需要渲染进程开启 AIPromptAPI 等 Blink 特性、utility 进程实现并注册 handler(session.registerLocalAIHandler(aiHandler)),缺一不可;
  3. 二进制格式未定型:image 与 audio 的 ArrayBuffer 数据布局目前以源码实现为准(N32 预乘像素 / float32 采样),源码中的 TODO 表明官方尚未承诺稳定格式,跨版本使用二进制内容时建议做兼容性校验;
  4. 默认值行为:消息的 prefix 字段在从 API 传入后被统一补为 false测试断言可验证),处理器实现无需自己补全该字段。

相关资源

登录后查看全文
热门项目推荐
相关项目推荐