首页
/ Electron LanguageModelUtility 完全解析:在 Utility 进程中构建本地 AI 语言模型能力

Electron LanguageModelUtility 完全解析:在 Utility 进程中构建本地 AI 语言模型能力

2026-09-06 11:39:53作者:舒璇辛Bertina

Electron 通过实验性的 Prompt API 让渲染进程可以调用本地大语言模型(LLM),而 LanguageModelUtility 是这条链路上运行在 Utility 进程中的核心类。本文基于当前仓库中 docs/api/language-model-utility.md 的完整 API 定义展开,逐一讲清构造器、静态方法、实例属性与实例方法的语义,结合 结构类型文档lib/utility/api/language-model-utility.ts 的实现源码,说明它如何与 localAIHandler 协作,帮助你在 Electron 应用中落地本地 AI 推理能力。

一、类定位:Utility 进程中的本地 AI 语言模型实现

LanguageModelUtility 的官方定位是 “Implement local AI language models”(实现本地 AI 语言模型),其所属进程为 Utility 进程(见 glossary 中对 Utility 进程的定义)。

这个设计符合 Electron 的多进程模型:重计算、可能崩溃的模型推理被隔离在主进程与渲染进程之外的独立 Utility 进程中运行,主进程通过 session 注册本地 AI 处理器,渲染进程通过 Prompt API 发起请求,三者通过 IPC/Mojo 边界解耦。从源码结构看,该类的 JavaScript 侧实现由以下文件组织:

二、构造器:new LanguageModelUtility(initialState)

构造器接收一个 initialState 对象,包含两个数字字段:

字段 类型 说明
contextUsage number 当前上下文窗口中已占用的 token 数
contextWindow number 上下文窗口总容量(token 数)

对应源码(language-model-utility.ts#L10-L13)中,构造器只是把这两个值直接赋给实例属性:

interface LanguageModelConstructorValues {
  contextUsage: number;
  contextWindow: number;
}

export default class LanguageModelUtility implements Electron.LanguageModelUtility {
  contextUsage: number;
  contextWindow: number;

  constructor(values: LanguageModelConstructorValues) {
    this.contextUsage = values.contextUsage;
    this.contextWindow = values.contextWindow;
  }
  // ...
}

文档中有一条明确的注意事项(NOTE):不要在类之外直接调用该构造器,因为这样创建的实例不会与 localAIHandler 正确建立连接。创建实例的正确方式是下一节的静态方法 LanguageModelUtility.create()

三、静态方法

3.1 LanguageModelUtility.create(options)(实验性)

使用提供的 options 创建一个新的 LanguageModelUtility 实例。

LanguageModelCreateOptions 结构继承自 LanguageModelCreateCoreOptions,完整字段如下(结合 language-model-create-options.mdlanguage-model-create-core-options.md):

字段 类型 是否可选 说明
signal AbortSignal 取消信号,用于中止创建过程
initialPrompts LanguageModelMessage[] 创建时注入的初始提示消息列表
expectedInputs LanguageModelExpected[] 声明模型预期接收的输入模态
expectedOutputs LanguageModelExpected[] 声明模型预期产生的输出模态

其中 LanguageModelExpected 的字段为:

  • type(string):text / image / audio 三者之一;
  • languages(string[],可选):语言列表。

从当前仓库的 JS 侧实现看,create() 目前是一个占位实现,返回 contextUsage: 0, contextWindow: 0 的空上下文实例(language-model-utility.ts#L15-L20):

static async create(): Promise<LanguageModelUtility> {
  return new LanguageModelUtility({
    contextUsage: 0,
    contextWindow: 0
  });
}

这说明 JS 层只是整个调用链的端点之一,真正的模型装载发生在 C++ 侧的 Prompt API 基础设施中,JavaScript 实现负责承载上下文状态并暴露 API 形状。

3.2 LanguageModelUtility.availability([options])(实验性)

探测语言模型的可用性,返回以下四个字符串之一:

返回值 含义
available 模型已就绪,可立即使用
downloadable 模型尚未下载,可以下载
downloading 模型正在下载中
unavailable 当前环境下模型不可用

该状态机对应用端做 UI 引导非常关键:在展示“开始对话”之前,先调用 availability() 判断是否需要先触发模型下载流程。当前 JS 侧实现同样为占位逻辑,固定返回 'available'language-model-utility.ts#L22-L24),真实判定逻辑在底层实现中完成。

四、实例属性

languageModelUtility.contextUsage(实验性)

number,表示当前上下文窗口中已使用的 token 数量。

languageModelUtility.contextWindow(实验性)

number,表示上下文窗口总大小(token 数)。

这两个属性与构造器参数一一对应,是衡量“还能再塞多少上下文”的直接依据:可用余量约为 contextWindow - contextUsage

五、实例方法

5.1 languageModelUtility.prompt(input, options)(实验性)

向模型发起提示并获取响应。返回值是 Promise<string>Promise<ReadableStream<string>> 的联合类型,即调用方既可以拿到完整的字符串响应,也可以消费一个文本流(适合逐字渲染的对话界面)。

LanguageModelPromptOptions 的字段(见 language-model-prompt-options.md):

字段 类型 是否可选 说明
responseConstraint Object | RegExp JSON Schema 对象或正则表达式,用于约束响应必须匹配指定结构(结构化输出)
signal AbortSignal 取消信号

LanguageModelMessage 的结构(见 language-model-message.md):

字段 类型 是否可选 说明
role string 取值 system / user / assistant
content LanguageModelMessageContent[] 消息内容数组
prefix boolean 标记是否为前缀消息

LanguageModelMessageContent 则支持多模态(见 language-model-message-content.md):

字段 类型 说明
type string 取值 text / image / audio
value ArrayBuffer | string 文本内容用 string,二进制内容用 ArrayBuffer

一个符合上述结构的调用示例(参数形状以文档为准):

const response = await lm.prompt(
  [
    { role: 'system', content: [{ type: 'text', value: 'You are a helpful assistant.' }] },
    { role: 'user', content: [{ type: 'text', value: '总结这段话的核心观点。' }] }
  ],
  {
    signal: new AbortController().signal,
    responseConstraint: { type: 'object', properties: { summary: { type: 'string' } } }
  }
);

5.2 languageModelUtility.append(input, options)(实验性)

向模型追加消息但触发响应生成,用于多轮对话中维护上下文(例如把上一轮的 assistant 回复回填进会话历史)。对应 JS 实现为空的 async 方法(language-model-utility.ts#L30)。

5.3 languageModelUtility.measureContextUsage(input, options)(实验性)

测量给定输入会占用多少 token,但不实际发起推理。这是实现“输入框剩余 token 提示”“上下文超限预警”的配套 API:先 measureContextUsage,再决定是否 prompt。JS 侧占位实现返回 0language-model-utility.ts#L32-L34)。

5.4 languageModelUtility.clone(options)(实验性)

克隆一个 LanguageModelUtility,克隆出的实例保留原有的上下文与初始提示。从源码实现看,克隆即把当前的 contextUsagecontextWindow 复制到新实例(language-model-utility.ts#L36-L41):

async clone() {
  return new LanguageModelUtility({
    contextUsage: this.contextUsage,
    contextWindow: this.contextWindow
  });
}

典型场景是从一个已预热上下文的会话派生出独立分支(如并行探索多个问题),分支之间互不污染。

5.5 languageModelUtility.destroy()(实验性)

销毁模型,同时中止所有正在进行中的执行。JS 侧实现为空操作(language-model-utility.ts#L43),资源释放由底层完成。调用方应在会话结束、窗口关闭时显式调用,避免遗留模型状态占用 Utility 进程资源。

六、与 localAIHandler 的协作关系

LanguageModelUtility 不是孤立使用的。文档对构造器的 NOTE 提示它必须与 localAIHandler 正确连接,而 docs/api/local-ai-handler.md 说明了这条链路的另一半:

  1. 主进程侧:通过 ses.registerLocalAIHandler(handler) 把一个脚本注册到指定 session,该脚本即运行在 Utility 进程中;
  2. Utility 进程侧:脚本调用 localAIHandler.setPromptAPIHandler(promptAPIHandler) 注册 Prompt API 绑定处理器,处理器签名为 Function<typeof LanguageModelUtility | null>,接收 details 对象,包含:
    • webContentsId:发起 Prompt API 调用的 WebContents 唯一 id;
    • securityOrigin:调用页面的 origin;
    • frameToken:发起调用 frame 的 frame token;
    • renderProcessId:承载该 frame 的渲染进程 id。
  3. 请求路由:每对 webContentsIdsecurityOrigin 触发一次绑定请求。处理器返回 null 即拒绝该渲染进程创建新的 Prompt API 会话;若要使既有 Prompt API 会话失效,则用 ses.registerLocalAIHandler(null) 清除 handler。
  4. 排队语义:若渲染进程在 setPromptAPIHandler() 调用之前就调用了 Prompt API,请求会被排队,handler 设置后统一冲刷;排队过多时会丢弃最旧的待处理请求并拒绝渲染进程中的 pending promise。文档因此建议尽早调用 setPromptAPIHandler()

从源码结构看,Utility 进程中的 localAIHandler 模块直接是 C++ 绑定 electron_utility_local_ai_handler 的 JS 包装(lib/utility/api/local-ai-handler.ts),而 lib/utility/init.ts 中注册的 isLanguageModel / isLanguageModelClass 隐藏值,则是框架在跨进程传递 LanguageModelUtility 实例时进行类型识别的机制。仓库中的功能测试 spec/api-local-ai-handler-spec.ts 也表明,localAIHandler 模块的行为受 Prompt API 特性开关控制(features.isPromptAPIEnabled() 为真时才执行)。

七、API 使用小结

将文档定义的 API 汇总为速查表:

成员 签名 返回值 用途
new LanguageModelUtility(initialState) initialState: { contextUsage, contextWindow } 实例 仅限框架内部使用,勿直接构造
LanguageModelUtility.create(options) options: LanguageModelCreateOptions Promise<LanguageModelUtility> 创建实例(推荐入口)
LanguageModelUtility.availability([options]) options?: LanguageModelCreateCoreOptions Promise<string> 返回 available / downloadable / downloading / unavailable
instance.contextUsage number 当前已用 token 数
instance.contextWindow number 上下文窗口容量(token)
instance.prompt(input, options) 消息数组 + Prompt 选项 Promise<string> | Promise<ReadableStream<string>> 发起推理,支持结构化响应约束
instance.append(input, options) 消息数组 + signal Promise<undefined> 仅追加上下文,不触发响应
instance.measureContextUsage(input, options) 消息数组 + Prompt 选项 Promise<number> 预估算力/上下文占用
instance.clone(options) LanguageModelCloneOptions Promise<LanguageModelUtility> 保留上下文与初始提示地克隆
instance.destroy() 销毁模型并中止进行中的执行

需要说明的是:该 API 族整体标注为 Experimental,当前仓库的 JavaScript 实现(lib/utility/api/language-model-utility.ts)对 createavailabilitypromptmeasureContextUsage 等均为形状正确的占位实现,真实的模型装载与推理由 C++ 侧 Prompt API 基础设施承担,且相关功能受 Prompt API 特性开关控制。在应用层使用这些 API 时,应以 availability() 的结果驱动 UI 流程,用 contextUsage / contextWindow 监控上下文水位,并在会话结束时调用 destroy() 释放资源。

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