借助 Prompt API,开发者可以使用 Gemini Nano 直接在浏览器中运行自然语言处理任务。这种内置 AI 方法可确保用户隐私、降低服务器成本并实现离线功能。
1. 使用入门和硬件要求
Prompt API 目前在 Chrome 148(桌面版)及更高版本中提供,适用于 Windows、macOS、Linux 和 Chromebook Plus。
硬件前提条件
- 存储空间:22 GB 可用空间(用于初始配置文件和模型)。
- 内存/CPU:16 GB RAM 和 4 个以上的 CPU 核心。
- GPU:4 GB 或更大 VRAM(音频输入所需)。
- 网络:仅在初始模型下载时需要。
初始化 API
在触发下载之前,请检查模型是否可用:
const availability = await LanguageModel.availability();
// Do not call create() when unavailable — the model cannot run on this device.
if (availability !== 'unavailable') {
const session = await LanguageModel.create({
monitor(m) {
// Inform the user while the model downloads so the UI doesn't appear frozen.
m.addEventListener('downloadprogress', (e) => {
console.log(`Downloaded ${e.loaded * 100}%`);
});
},
});
}
2. 核心提示功能
为简洁起见,本部分中的会话示例省略了 session.destroy()。当不再需要会话时,始终调用 session.destroy() 以释放设备内存(请参阅第 5 节)。
基本输出和流式输出
对于简短回答,请使用 prompt()。对于较长的内容,请使用 promptStreaming() 提供响应速度更快的界面。
强制性:切勿将模型输出分配给 innerHTML。模型输出不可信,可能包含注入的标记。请始终使用 textContent 或排错程序。
const session = await LanguageModel.create();
// prompt() accumulates the full response before resolving — use for short, one-shot output.
const result = await session.prompt('Write a haiku about coding.');
// textContent, not innerHTML — model output is untrusted and must not be parsed as markup.
outputEl.textContent = result;
// promptStreaming() yields independent chunks that must be concatenated;
// use for longer content so each chunk can be rendered progressively.
const stream = session.promptStreaming('Write a long story about a robot.');
let completeResult = '';
for await (const chunk of stream) {
completeResult += chunk;
outputEl.append(chunk);
}
console.log('Full story:', completeResult);
多模态输入
Prompt API 支持文本、音频和视觉输入(图片、画布、视频帧)。
const session = await LanguageModel.create({
// Declaring expected input types lets the browser optimize model loading.
expectedInputs: [{ type: 'text' }, { type: 'image' }],
expectedOutputs: [{ type: 'text' }],
});
const response = await session.prompt([
{
role: 'user',
content: [
{ type: 'text', value: 'What is in this image?' },
{ type: 'image', value: document.querySelector('canvas') },
],
},
]);
3. 高级会话管理
会话可让模型在多次互动中保持上下文。
上下文和配额
每个会话都有一个 token 上限。您可以通过 session.contextUsage 和 session.contextWindow 监控用量。如果窗口溢出,系统会丢弃最早的消息(系统提示除外)。
克隆会话
克隆功能非常高效,可用于启动共享相同初始上下文(例如“系统”角色)的并行对话,而无需重新初始化。
const mainSession = await LanguageModel.create({
initialPrompts: [{ role: 'system', content: 'You speak like a pirate.' }],
});
const branchA = await mainSession.clone();
const branchB = await mainSession.clone();
// Destroy the base after cloning — the clones own their own context from here.
mainSession.destroy();
正在恢复过往会话
虽然原生“恢复”功能正在开发中,但您可以通过将之前的历史记录输入 initialPrompts 来重新创建会话。
注意:localStorage 未加密且具有持久性。存储的对话记录可能包含用户个人身份信息 (PII) - 在保留聊天记录之前,请考虑隐私影响。
// || '[]' ensures JSON.parse never receives null when the key doesn't exist yet.
const history = JSON.parse(localStorage.getItem('chat_history') || '[]');
const session = await LanguageModel.create({
initialPrompts: history, // Array of {role, content} objects
});
4. 使用 JSON 架构的结构化输出
为防止模型添加“闲聊”内容(例如“没问题,这是您的 JSON:”),请通过 responseConstraint 字段使用 JSON 架构。这可确保输出是有效的 JSON,可以立即解析。
示例:情感分类
// Pass the schema as a plain object — do not JSON.stringify() it first.
const schema = {
type: 'object',
properties: {
rating: { type: 'number', minimum: 1, maximum: 5 },
is_positive: { type: 'boolean' },
},
required: ['rating', 'is_positive'],
};
const result = await session.prompt(
"Rate the following feedback: 'The food was great!'",
{ responseConstraint: schema },
);
const data = JSON.parse(result);
console.log(data.rating); // 5
限制条件和前缀
您可以使用 prefix: true 预填充助理的回答,从而进一步引导模型。
const character = await session.prompt([
{ role: 'user', content: 'Create a character sheet' },
{ role: 'assistant', content: '```json\n', prefix: true },
]);
5. 最佳实践和安全
- 资源清理:对话结束时,请务必调用
session.destroy()以释放内存。 - 输出安全性:模型输出不可信。始终将结果写入
textContent,而不是innerHTML,以防止恶意模型输出导致 XSS 注入。 - 如果您需要允许有限的 HTML,请使用原生 Sanitizer API 或 DOMPurify 等清理工具。
- 中止任务:使用
AbortController,让用户能够停止长时间运行的生成任务。将signal传递给prompt()或promptStreaming(),而不是LanguageModel.create()。 - 安全性:使用权限政策控制 iframe 中的访问权限:
<iframe src="..." allow="language-model"></iframe>。 - 设计:查看《人 + AI 指南》,确保以负责任的方式实现 AI。
通过将结构化输出与强大的会话管理相结合,开发者可以构建完全在用户设备上运行的复杂、有状态 AI 应用。
注意事项
如需查看完整的注意事项列表,请参阅 https://developer.chrome.com/docs/ai/built-in-ai-dos-donts.md.txt。以下是其要点:
在合理的时间准备模型
适用对象:所有 API,例如 Summarizer、Translator 和 Writer。
正确做法:在明确确定用户有意使用 AI 功能后,立即初始化会话,例如,当用户进入相关的 AI 工具界面、将鼠标悬停在 AI 工作区上或与该功能周围的界面互动时。通过预热会话,模型可以在用户设置任务时在后台静默加载到内存中,从而消除可避免的冷启动延迟。 尝试领先一步,在开始渲染当前结果时立即启动下一个最可能的 AI 任务,例如,如果该功能专为迭代使用而设计。
不建议:除非必要,否则请勿等待用户点击“生成”才初始化会话。这会导致冷启动延迟,因为模型必须先加载到内存中并准备好执行流水线。
在创建期间设置初始提示
适用范围:Prompt API。
建议:在会话初始化期间提供系统指令,以提高第一个提示的速度。
不建议:从空会话开始,并在第一次 prompt() 调用中发送系统指令。这会增加延迟时间,因为这会迫使模型在最后一刻处理这些指令。
克隆会话以执行重复性任务
适用范围:Prompt API。
对于 Prompt API,每个会话都会跟踪对话的上下文,并考虑之前的所有互动。由于克隆会继承其父级会话的所有内容,包括初始提示和截至克隆时的所有互动记录,因此请合理安排使用方式,仅继承所需内容。
正确做法:
- 创建基础会话:如需高效处理不相关的任务,请创建一个仅包含系统指令且不包含先前对话上下文的基础会话。
- 克隆基准:对新任务使用该基础会话中的
clone(),以节省重新解析系统指令的开销。这样,您就可以创建并行对话,或将任务重置为基准状态。
错误做法:
- 请勿将同一会话重复用于不相关的任务,并避免克隆已包含不必要互动记录的任何会话。这两种模式都可能导致不相关的先前上下文干扰当前任务。
- 请勿使用相同的系统指令重复调用
create()。请改用克隆模式来优化性能。
销毁未使用的会话
适用范围:所有 API。
建议:在不再需要会话时,显式调用 destroy(),以便在不再使用某项功能时释放内存。如果您使用克隆模式,请保留基本会话并销毁不再需要的克隆。
不建议:让多个大型会话保持活跃状态。每个会话都会消耗内存,这会造成不必要的资源使用,并可能成为一个问题。会话将由垃圾回收器自然清理,但调用 destroy() 可以更快地释放内存。
安全高效地呈现流式回答
适用于:所有支持流式传输的 API(Prompt、Summarizer、Writer、Rewriter 和 Translator)。
建议:将所有 LLM 输出视为不可信内容。清理完整的组合输出,而不仅仅是数据块,因为恶意代码可能会分散在不同的更新中。在渲染之前,请使用 Sanitizer API(如果支持)。为避免性能下降,请使用流式 Markdown 解析器,例如 streaming-markdown。
不建议:在每次更新数据块时直接设置 innerHTML。这种方法速度较慢,尤其是在处理语法高亮等复杂格式时,并且容易受到注入攻击。
优化输入以提高速度
适用范围:所有 API。
建议:仅向模型传递绝对必要的信息。去除与手头任务无关的所有内容。对于大型数据集,请提供简短概览和少量相关项。
不建议:向 API 发送未经处理的原始文本、不必要的元数据、HTML 标记或未经筛选的大型列表。延迟时间会随着输入大小的增加而显著增加,这可能会导致 AI 功能在许多设备上看起来无法正常运行。
使用结构化输出获得可预测的结果
适用范围:Prompt API。
建议:如果您需要模型以特定格式返回数据,请使用结构化输出,方法是提供 responseConstraint 字段来提供 JSON 架构。这样可以确保输出可预测,并避免您需要进行复杂的后处理或手动解析。
错误做法:仅依赖自然语言指令(例如“仅输出 JSON”)。模型可能会包含会破坏解析器的对话填充词。
将生成与长度限制解耦
适用范围:Prompt API,因为它是唯一支持结构化输出架构的 API。
建议:让模型自然地生成回答,然后使用客户端逻辑截断文本,使其适合您的界面。
不建议:使用结构化输出架构强制执行严格的字符数限制(例如 maxLength: 125)。如果模型的回答长度超过您设置的上限,模型可能会切换到高密度 token(例如外语或表情符号)来压缩含义,从而导致输出内容毫无意义。
让用户知情
适用范围:所有 API。
建议:根据任务的复杂程度和预期时长,使用动画、视觉提示和进度指示器让用户了解进度。最佳方法取决于您的应用场景和 API 输出的预期长度。例如:
- 长内容流式传输:对于摘要或对话,流式传输默认会创建逐个词元的打字机效果。这会让人感觉很自然,并能提供即时反馈。
- 非流式传输适用于短任务(或长异步任务):对于短输出(例如替代文本),非流式传输可以打造更精致的界面。此外,它还提供了时间,以便在当前 AI 任务渲染时,推测性地准备下一个 AI 任务。这种方法也适用于较长的异步或后台任务。如果用户没有被卡在输出环节,可以继续其流程,那么就没有必要在输出生成时立即显示。在界面中发出信号,表明该过程正在进行中。
- 更新时的视觉过渡:翻译或重写文本时,使用动画(例如文字变形)。
不建议:在没有视觉提示的情况下更新界面。
契合用户对时间和工作的心理模型
适用范围:所有 API。
建议:如果回答几乎是即时生成的,请考虑人为延迟一两秒。矛盾的是,当用户认为生成过程与他们认为的任务难度相符时,他们可能会认为结果更值得信赖。使用动画来表示 AI 处理已完成。
不建议:在用户猝不及防的情况下瞬间替换界面。
允许用户快速浏览和撤消 AI 编辑
适用范围:所有 API。
建议:在界面中提供步进器或导航历史记录,让用户能够放心地探索不同的结果,并快速撤消 AI 编辑。这可确保不同版本仍然随时可用。
不建议:覆盖用户之前的草稿或他们可能喜欢的 AI 结果,而不提供返回、还原或比较版本的方法。
赋予用户控制权和覆盖权
适用范围:所有 API。
建议:让用户成为所有生成内容的最终编辑者。提供直观的覆盖选项,让用户对最终输出拥有完全控制权。这些 API 可能会产生不正确的结果。
不建议:强制将 AI 生成的结果作为唯一选项。
缓存重复性任务的结果
适用范围:所有 API。
建议:针对重复的输入或查询实现本地结果缓存(例如,使用 sessionStorage 或 IndexedDB)。通过剪裁空格和转换为小写来规范化输入,以提高缓存命中率。对于大型输入(例如图片),请生成一个哈希值作为缓存键。为缓存设置保守的存留时间 (TTL)(或在后台更新缓存结果的同时提供缓存结果)。如果结果不令人满意,允许用户触发新的推理。
不建议:针对重复的搜索查询或相同的数据输入重新运行相同的推理,因为这种情况下不希望出现变化,例如用户在搜索结果之间来回浏览。 这能优化响应速度,并高效利用本地计算资源。
6. 后备策略
在使用之前,请检查 LanguageModel 对象在全局范围内是否可用:
if ('LanguageModel' in self) {
// The Prompt API is supported.
} else {
// Execute fallback strategy
}
如果 Prompt API 不受支持,或者可用性检查返回“unavailable”,您必须妥善回退:
- 远程 API 回退:将检测请求重定向到服务器端点或云 API(例如 Vertex AI Gemini API)。
- 本地 API 后备:将检测请求重定向到本地端点,例如使用 Transformers.js。