💰 点进来就是赚到知识点!本文带你解锁 Chrome 内置大模型,点赞、收藏、评论更能促进消化吸收!
🚀 想解锁更多 Web AI 的技能吗?快来订阅专栏「Web AI 进化录」!
📣 我是 Jax,在畅游 Web 技术海洋的又一年,我仍然是坚定不移的 JavaScript 迷弟,Web 技术带给我太多乐趣。如果你也和我一样,欢迎关注、私聊!
相信你已经知道了,Chrome 浏览器内置了 Gemini Nano 这个大语言模型,这可以算作是 Web 端侧智能的里程碑事件了。在本专栏之前的文章中,我向大家介绍了如何解锁内置模型以及 Prompt API 的初始形态。如今,三个月过去了,内置 AI 又有了什么新动向呢?如果你也对 Web AI 感兴趣,那么这篇文章正是为你而写的,读下去吧。
这一次,我们来了解 Chrome 内置 AI 的最新进展,我会手把手带你解锁 Web 端侧智能,并借助 Prompt API 实现几个小应用,让你切实感受到浏览器级别的智能能力带给开发者和用户的便利性。
先配齐运行环境
一个好消息是,不像之前那样需要额外安装 Chrome Canary,现在我们已经可以在 Chrome 最新的正式版(129.0.6668.59)中使用内置 AI 了。但在开发调试过程中,我发现正式版本的内置模型常常举止怪异,比如不断重复同一句话、答非所问等等。猜测还是有一些微调没做好。但所幸在 Canary 版本中的表现非常正常,所以我们还是用 Canary 来进行本文的实操。
由于内置 AI 仍然是作为实验功能装载进浏览器的,所以还需要手动解锁一下。解锁的方法和之前基本相同,简单来说是以下几步:
-
将系统语言和 Chrome 语言设置为英文。(有兴趣的小伙伴可以实测一下,不设英文是否能成功解锁,欢迎把测试结果留在评论区 🫶🏻)
-
在 chrome://flags 中搜索「optimization guide on device」和「Gemini」,把搜到的设置项通通开启。
-
重启 Chrome
-
在 chrome://components 中找到「Optimization Guide On Device Model 」并点击按钮下载模型
-
最后,在 Console 中打印 ai 这个全局对象,如果一切顺利,你将会看到如下结果:
如果你在操作工程中遇到了问题,没有顺利解锁,没关系,尽管在评论区留言,我会和你一起看看怎么解决。
再看看整体变化
在之前的 Prompt API 中,我们是用 ai.createTextSession()
来开启大模型对话的。但现在再执行这条语句是会报错的,因为 createTextSession
这个方法已经不存在了。
我们刚刚测试解锁时,打印了全局对象 ai
,可以看到,它的成员已经是四个新对象了:
{
assistant,
writer,
rewriter,
summarizer,
}
Chrome 取消了 window.model
这个冗余成员,并且把原有的 createTextSession
等方法整合进了 assistant
子对象的其他方法实现中。可以说,现在的 Prompt API 和三个月前完全不一样了。
这代表着,浏览器内置 AI 目前还在厂商的积极尝试中,远没有达到 W3C 标准的阶段,其功能实现还不稳定,处于频繁变动的状态中。所以我们目前还没办法让内置 AI 功能投产。但这也带给我们一种见证历史的感觉 —— 能目睹内置 AI 的诞生和发展,并且能参与到它的进化过程中去,是可遇不可求的视角和体验。
Prompt,意为提示词,狭义上指的是我们我们用自然语言向大模型传达的指令。而 Prompt API 则是浏览器为 Web 开发者提供的与内置大模型交互的接口。
writer
,rewriter
,summarizer
都是用于文本处理的 API,我们会在后续的专栏文章中详细了解。而 assistant
就是我们本次要重新认识的 Prompt API。
新的助手:assistant 对象
检测可用性
由于 API 还不稳定,所以我们在使用时,应该总是检测可用性。
assistant
对象具有一个 capabilities
方法,可以提供给我们一些内置 AI 的状态信息:
在返回结果中,topK
和 temperature
是用于调控生成结果的参数;而 available
则标识了当前环境下是否可用内置 AI 能力,它的取值范围如下:
no
:当前设备或浏览器不支持after-download
:需要等模型下载完成后才可用readily
:可用
所以我们可以用这样的逻辑来检测可用性:
const capabilities = window.ai?.assistant?.capabilities
if (!capabilities) return false
const { available } = await capabilities()
return available === 'readily'
创建对话
确定可用之后,我们就可以和内置模型来一次对话了。
开启对话的方式沿用了之前的风格:先创建 session
,然后进行 prompt 交互。
const session = await window.ai.assistant.create()
const result = await session.prompt('Who are you and what can you do?')
console.log(result)
执行上面的代码后,你可能会等上一小会儿,才会看见一整段文字被一次性打印出来。其实模型并不是吭哧瘪肚半天才憋出来一段话。文本生成的原理是根据上文递归推断下一个字(或者说 token),所以在我们干等的过程中,模型实际上每秒都在生成一定字数的内容。只不过 prompt()
就是这种不到火候不揭锅的调性,会等全部生成完成才肯吐口。
这世界上没有人喜欢干等,所以 API 提供了另一个方法 promptStreaming
,让模型能够对答如流。
const stream = await session.promptStreaming('Who are you and what can you do?')
for await (const chunk of stream) {
console.log(stream)
}
这一次,你会在浏览器 Console 里看到一座金字塔被搭建起来,行云流水、从上至下:
因为目前返回的 stream
并不真的是流式数据,而是每个 chunk
都是最新的完整回答。但好在我们已经可以在提问后立即得到反馈了。
你一定觉得这样在 Console 运行代码的对话形式太不方便了,肯定想要更流畅地领略端侧 LLM 的魅力。我就猜到你是有品味的程序员,所以写了一个对话界面 —— https://rejax.fun/chrome-ai-ui/#/chat-bot,你可以直接和内置 AI 聊天,而且聊天记录还会保存在 localStorage 里哦~
设置系统提示词
在提示词工程中有这样一个技巧:你可以给大模型设定一个角色,比如「你是一个 Web 开发专家」、「你是一个数据分析师」或者「你是一个乐于点赞、收藏的读者 ❤️」…… 其作用在于让具备通用泛化能力的大模型在生成内容时,专注于某一块特定的领域,以便于更好地处理我们提出的特定问题,忽略无关的信息。这个技巧能够大幅提升生成内容的质量和相关度,从而提高体验和效率。
而 Prompt API 也为这个技巧提供了接口:在创建 session
时,我们可以给 create()
传入配置参数:
const session = await ai.assistant.create({
systemPrompt: 'You are a web development expert……'
})
由此创建出来的 session
,在后续对话中,会牢牢记住自己的使命,按照 systemPrompt
中的指令来推理。
还有一种更通用、更易扩展的配置方法:
const session = await ai.assistant.create({
initialPrompts: [
{
role: 'system',
content: 'You are a web development expert……'
}
]
})
这种 role: 'system'
的方式能起到相同的效果,只不过更符合提示词工程的通用范式,Open AI、LangChain 等提示词的组织形式都是如此。
配置系统提示词的时候,有几点需要注意:
systemPrompt
和role: 'system'
不能混用role: 'system'
只能有一组,且必须放在initialPrompts
的首位
在提示词中附带示例
现在假设要开发一个对联机器人,我们的系统提示词可能会是「你是一个语言学家,你对给定的上联返回下联……」。实测中回可能会发现,大模型不是很能理解「上下联」是什么意思。在这种情况下,你当然可以选择整理一批对联数据集,然后对模型进行训练、微调或者蒸馏。但还有一个更简洁、更经济的方法能迅速带来优化效果,那就是 n-shot 提示词。
N-shot 也是提示词工程中的一个技巧,n 代表非负整数,shot 代表样本或者示例。二者合在一起的意思就是在提示词中带上 n 个示例。比如在上文的几个对话中,提示词只给出了指令,那这就属于 0-shot 提示词。
示例能帮助模型更好地「理解」指令要求中的含义。仍以对联机器人为例,我们把提示词改为「你是一个语言学家,你对给定的上联返回下联。下面是几个例子:上联:大江东流去,下联:小河西淌来。……」,可以以最低的成本获得效果的提升。
回到 Prompt API,initialPrompts
参数是一个数组,除了系统提示词,我们还可以预先传入几轮对话,作为 session
的背景上文,就像这样:
initialPrompts: [
{
role: 'system',
content: '你是一个语言学家,你对给定的上联返回下联'
},
{
role: 'user',
content: '大江东流去'
},
{
role: 'assistant',
content: '小河西淌来',
}
]
其中 role: ‘user’
代表用户输入,role: ‘assistant’
代表用户输出。这样组织提示词,可以让大模型的生成内容更合我们心意。
token 计算
Token 数量一般是商业大模型服务的收费指标之一。用户输入的内容越多,大模型需要处理的 token 就越多。虽说 Chrome 内置的 Gemini Nano 是本地模型,咱们开发者可以不用担心计费问题。但每个大模型都有其上下文窗口极限,具体表现就是如果一次性输入几百万字进去,大模型可能无法全部消化;或者经过几百轮对话后,它无法「回忆」起最初几轮对话里的信息。
这种情况下,就需要开发者进行干预了。比如,我们可以计算每轮对话消耗的 token 数量,预计快要接近极限之前,就把早期内容的关键信息提炼出来,在腾出空间的同时保留一定程度的上文。
内置 AI 也同样为开发者提供了一套计量 token 的工具:
-
session
实例上有一个countPromptTokens
方法,可以计算传入的字符串参数相当于多少 token -
session
还有三个可读属性:maxTokens
:数量上限tokensSoFar
:目前消耗了多少 tokentokensLeft
:还剩多少 token 可用
这样,开发者就能在对话过程中对 token 消耗程度进行把控,从而能够及时处理信息丢失的问题了。
ShowCase:三分钟写一个小玩具
通过上面的介绍,你会发现 Prompt API 是如此简单易用,不知道它有没有激发你的灵感呢?总之先来看看我写的一个:https://rejax.fun/chrome-ai-ui/#/prompt
这个脑洞来自那句歌词「What does the fox say?」
在这个小玩具里,用户输入动物名称,大模型返回这种动物的叫声。如果用户输入的不是动物,就会返回「走开」。
核心代码如下:
const session = await window.ai.assistant.create({
initialPrompts: [
{
role: 'system',
content: 'You are a animal expert, user will give you a name of animal, you return the sound of the animal. If the name is not an animal, you return "go away". Return less than 3 words.'
},
{
role: 'user',
content: 'dog'
},
{
role: 'assistant',
content: 'woof',
},
{
role: 'user',
content: 'table'
},
{
role: 'assistant',
content: 'go away',
}
],
})
const sound = await session.prompt(userPrompt)
写在最后
这次,我们「复习」了全新的 Prompt API,它是我们实践提示词工程的绝佳帮手,能帮我们几乎无成本地落地 AI 应用灵感。
短短三个月,Prompt API 已经进化出了新的形态,来适应新的环境和需求。在我观察到的一些 W3C 标准和社区草稿的编纂过程里,浏览器内置 AI 草稿绝对可以算是更新最积极的一个。相信再过一段时间,它会变得更加强大、更加易用。
如果你也对 Web 端侧智能充满信心和希冀,那就插个眼吧,关注我的专栏,和我一起见证。Witness!