1. 浏览器内置大模型到底是个什么东西
1.1 从"调API"到"用浏览器自带能力"的转变
过去两年,给网页加AI能力几乎只有一条路:申请某个云端大模型的API Key,然后在前端或后端发请求。这条路能跑通,但问题也很明显——要花钱、要联网、要处理密钥泄露风险,还得担心请求频率限制。很多个人开发者做个小工具站,光是API费用就劝退了。
浏览器内置大模型是另一条思路。它把模型直接跑在用户的浏览器里,通过一套标准化的JavaScript接口调用。你不需要申请任何密钥,不需要服务器中转,用户打开网页就能用。目前主流浏览器厂商都在推进这件事,比较有代表性的是Chrome内置的Gemini Nano,以及围绕它构建的Prompt API和Summarizer API等。
我第一次接触这个能力是在一个内部工具项目上。当时的需求很简单:让用户粘贴一段网页文案,自动给出优化建议。如果用云端API,每次调用都要计费,用户量一上来成本就失控。换成浏览器内置模型之后,成本直接归零,而且因为模型在本地跑,用户数据不出设备,隐私方面也更好交代。
1.2 它能做什么,不能做什么
先说能做的。浏览器内置模型适合处理短文本的理解与生成任务,比如:
- 对一段文案给出改写建议
- 总结一段用户输入的内容
- 判断文本的语气、情感倾向
- 根据关键词生成简短的描述
再说不能做的。它不适合处理长文档、复杂推理、代码生成这类重任务。模型参数量摆在那里,能力边界是明确的。我实测下来,输入控制在几百字以内效果最稳,超过一千字就开始出现答非所问的情况。
还有一个容易被忽略的点:模型可用性不是100%。不是所有浏览器版本都支持,不是所有设备都能跑。所以你的代码必须做好降级处理,检测不到就给出友好提示,而不是直接报错白屏。
1.3 为什么值得关注这个方向
从工程角度看,浏览器内置模型解决了一个很实际的问题:把AI能力的边际成本压到零。对于个人项目、内部工具、教育类网站来说,这个价值非常大。你不需要为每个用户每次调用付费,也不需要维护后端服务。
从用户体验角度看,本地推理意味着没有网络延迟。云端API一个来回少说几百毫秒,本地模型基本是即时的。用户输入完点一下,结果马上就出来,这种流畅感是云端方案给不了的。
从隐私角度看,用户输入的内容完全留在本地,不经过任何服务器。对于处理敏感文本的场景,这一点是决定性的。
2. 核心接口与能力拆解
2.1 Prompt API的基本调用方式
浏览器内置模型的核心接口是Prompt API。它的调用逻辑和常见的对话式API很像,但有几个关键差异需要注意。
首先是会话(session)的概念。你不能像调云端API那样每次发一个独立请求,而是要先创建一个会话对象,然后在会话里持续对话。这样做的好处是模型能记住上下文,坏处是会话会占用内存,用完要记得销毁。
// 检测能力是否可用 if ('ai' in window && 'languageModel' in window.ai) { const availability = await window.ai.languageModel.availability(); if (availability === 'available') { // 创建会话 const session = await window.ai.languageModel.create({ systemPrompt: '你是一个网页文案优化助手,给出简洁具体的建议。' }); // 发送请求 const result = await session.prompt('帮我优化这句话:我们的产品很好用'); console.log(result); // 用完销毁 session.destroy(); } }这段代码里有几个细节值得展开。availability()返回的值可能是available、downloadable、downloading、unavailable几种状态。如果是downloadable,说明模型还没下载到本地,你需要触发下载流程。如果是unavailable,那就是设备或浏览器不支持,只能走降级方案。
2.2 会话参数怎么调
创建会话时可以传几个关键参数,直接影响输出质量和资源占用。
systemPrompt是最重要的一个。它决定了模型的角色和行为边界。我踩过的坑是:一开始没写systemPrompt,模型什么话题都聊,给网页优化建议的时候经常跑偏去聊别的。后来加了一句明确的角色限定,输出质量立刻稳定了。
temperature控制输出的随机性。给优化建议这种任务,我一般设在0.3到0.5之间。太低会显得死板,每次都给一样的建议;太高会天马行空,给出不切实际的方案。
topK限制每次采样的候选词数量。这个参数一般不用动,默认值就够用。除非你发现输出太发散,可以适当调低。
注意:不同浏览器版本对参数的支持程度不一样。有些参数传了会被忽略,不会报错。所以不要完全依赖参数调优,systemPrompt写清楚才是根本。
2.3 能力检测与降级策略
这是整个方案里最容易被忽视、但最重要的一环。浏览器内置模型的可用性受三个因素影响:浏览器品牌和版本、操作系统、设备硬件。
我的做法是写一个统一的能力检测函数,返回三种状态:完全可用、需要下载、不可用。然后针对每种状态给出不同的UI反馈。
async function checkModelCapability() { if (!('ai' in window) || !('languageModel' in window.ai)) { return { status: 'unsupported', message: '当前浏览器不支持内置模型' }; } const availability = await window.ai.languageModel.availability(); switch (availability) { case 'available': return { status: 'ready' }; case 'downloadable': return { status: 'need-download', message: '首次使用需要下载模型,约需几分钟' }; case 'downloading': return { status: 'downloading', message: '模型下载中,请稍候' }; default: return { status: 'unsupported', message: '当前设备无法运行内置模型' }; } }降级方案我一般准备两套。第一套是纯规则方案:用正则和关键词匹配给出基础建议,比如检测到"很好用"就提示"建议替换为更具体的描述"。第二套是引导方案:提示用户升级浏览器或换设备。两套方案根据实际情况选用。
3. 网页优化建议功能的完整实现
3.1 需求拆解与功能设计
回到标题里的场景:给自己的网页提供优化建议。这个需求可以拆成几个子问题。
第一,优化什么。网页优化是个很宽泛的概念,可能是文案优化、SEO优化、可访问性优化、性能优化。浏览器内置模型擅长的是文本理解,所以聚焦在文案和内容层面的优化最合适。
第二,怎么输入。最自然的方式是让用户直接粘贴文本,或者从当前页面提取文本。我选择的是后者——用户点击按钮,脚本自动抓取页面主要文本内容,然后送给模型分析。
第三,怎么输出。模型返回的是一段文字,直接展示太粗糙。我的做法是让模型按固定格式返回,然后用正则解析成结构化数据,分条展示。
3.2 页面文本提取的实操细节
从页面提取文本看起来简单,其实有不少坑。直接取document.body.innerText会把导航栏、页脚、广告都抓进来,噪音太大。
我的做法是优先找语义化标签。先看有没有<article>或<main>,有就取里面的内容;没有就找<body>里文本密度最高的区块。文本密度的计算方式是:该区块的文本长度除以HTML标签数量,比值越高说明文本越集中。
function extractMainContent() { // 优先语义化标签 const article = document.querySelector('article') || document.querySelector('main'); if (article) return article.innerText.trim(); // 退而求其次,找文本密度最高的div const divs = Array.from(document.querySelectorAll('div')); let best = null; let bestScore = 0; for (const div of divs) { const text = div.innerText || ''; const tagCount = div.querySelectorAll('*').length || 1; const score = text.length / tagCount; if (score > bestScore && text.length > 200) { bestScore = score; best = div; } } return best ? best.innerText.trim() : document.body.innerText.trim(); }提取出来的文本还要做长度控制。前面说过,模型对长文本处理不好。我的策略是分段处理:把长文本按段落切分,每段控制在300字以内,逐段送给模型,最后汇总结果。
3.3 提示词设计的经验
提示词写得好不好,直接决定输出质量。我前后改了七八版,总结出几条经验。
第一,明确输出格式。不要让模型自由发挥,而是规定好返回结构。比如要求它按"问题类型|原文片段|优化建议"的格式返回,每行一条。这样解析起来很方便。
第二,给出具体示例。在systemPrompt里放一两个输入输出示例,模型的表现会稳定很多。这叫few-shot,实测比纯指令效果好。
第三,限定建议数量。不限制的话,模型可能给出一大堆无关痛痒的建议。我一般限定"最多给出5条最重要的建议",逼它做优先级排序。
第四,要求给出理由。只说"改成这样"没有说服力,要求它说明"为什么这样改更好",用户才愿意采纳。
下面是我实际在用的systemPrompt模板:
你是一个网页文案优化助手。用户会给你一段网页文本,你需要给出优化建议。 输出格式要求:每条建议占一行,格式为: [问题类型] 原文片段 -> 优化建议(理由) 问题类型限定为:表达啰嗦、用词模糊、语气不当、结构混乱、缺少重点。 要求: 1. 最多给出5条建议,按重要性排序 2. 原文片段必须是文本中真实存在的 3. 优化建议要具体可执行,不要空泛 4. 理由用一句话说明 示例输入:我们的产品非常好用,功能很多,欢迎大家使用。 示例输出: [用词模糊] 非常好用 -> 操作简单,三步完成配置("非常好用"缺乏具体信息) [表达啰嗦] 功能很多,欢迎大家使用 -> 支持批量处理、自动保存等12项功能(去掉客套话,直接说功能)3.4 结果解析与展示
模型返回的文本需要解析成结构化数据。因为我在提示词里规定了固定格式,解析逻辑就比较简单:按行分割,每行用正则提取问题类型、原文片段、优化建议和理由。
function parseSuggestions(rawText) { const lines = rawText.split('\n').filter(line => line.trim()); const suggestions = []; const pattern = /^\[(.+?)\]\s*(.+?)\s*->\s*(.+?)((.+?))$/; for (const line of lines) { const match = line.match(pattern); if (match) { suggestions.push({ type: match[1], original: match[2], suggestion: match[3], reason: match[4] }); } } return suggestions; }解析失败的情况也要处理。模型偶尔会不按格式返回,这时候我的做法是把原始文本直接展示出来,并加一句"模型返回格式异常,以下为原始输出",让用户自己判断。总比什么都不显示强。
展示层面,我用卡片式布局,每条建议一张卡片,问题类型用不同颜色标签区分。原文片段加删除线,优化建议加粗,理由用小字灰色显示。用户一眼就能看出哪里有问题、怎么改、为什么改。
4. 性能优化与资源管理
4.1 模型加载时机的选择
模型加载是个耗时操作,尤其是首次下载。如果页面一打开就加载模型,用户会感觉页面卡顿。我的策略是延迟加载:页面加载完成后不立即初始化模型,等用户点击"开始分析"按钮时再加载。
这样做的好处是首屏速度不受影响。坏处是用户第一次点击要等几秒。为了缓解等待焦虑,我在按钮点击后立即显示一个加载动画,并配上文字提示"正在准备模型,首次使用可能需要几秒"。
如果用户可能多次使用这个功能,可以在第一次加载完成后把session缓存起来,后续调用直接复用。但要注意,session会占用内存,页面隐藏或用户长时间不操作时应该销毁。
let cachedSession = null; async function getSession() { if (cachedSession) return cachedSession; cachedSession = await window.ai.languageModel.create({ systemPrompt: SYSTEM_PROMPT, temperature: 0.4 }); return cachedSession; } // 页面隐藏时销毁,释放内存 document.addEventListener('visibilitychange', () => { if (document.hidden && cachedSession) { cachedSession.destroy(); cachedSession = null; } });4.2 长文本的分段处理策略
前面提到长文本要分段,具体怎么分有讲究。按固定字数切分是最简单的,但可能把一句话切断,影响模型理解。
我的做法是按段落切分,再合并短段落。先用换行符把文本切成段落,然后从头开始累加,当累加长度接近300字时就切一刀。这样能保证每段语义相对完整。
function splitText(text, maxLength = 300) { const paragraphs = text.split(/\n+/).filter(p => p.trim()); const chunks = []; let current = ''; for (const para of paragraphs) { if ((current + para).length > maxLength && current) { chunks.push(current); current = para; } else { current += (current ? '\n' : '') + para; } } if (current) chunks.push(current); return chunks; }分段处理还有个好处是可以并行请求。多个段落同时送给模型,总耗时比串行快很多。但要注意并发数不能太高,一般控制在3到5个,太高会拖慢浏览器响应。
4.3 内存占用的监控
浏览器内置模型跑在本地,内存占用是实打实的。我在测试机上观察过,一个活跃session大概占用几百MB内存。如果同时开多个session,内存很快就会被吃满。
所以我的原则是:同一时间只保留一个session。如果用户快速连续点击分析按钮,要用防抖处理,避免创建多个session。另外,分析完成后如果用户没有继续操作的迹象,设置一个定时器自动销毁session。
let idleTimer = null; function scheduleCleanup() { if (idleTimer) clearTimeout(idleTimer); idleTimer = setTimeout(() => { if (cachedSession) { cachedSession.destroy(); cachedSession = null; } }, 60000); // 60秒无操作就销毁 }5. 常见问题与排查实录
5.1 模型不可用怎么办
这是最高频的问题。用户反馈"点了没反应",十有八九是模型不可用。排查顺序是这样的:
第一步,确认浏览器版本。打开控制台输入'ai' in window,返回false说明浏览器根本不支持。这种情况只能引导用户升级浏览器。
第二步,确认模型状态。输入await window.ai.languageModel.availability(),看返回值。如果是downloadable,说明需要下载,但可能因为网络原因下载失败。如果是unavailable,说明设备硬件不满足要求。
第三步,检查设备存储空间。模型下载需要几百MB空间,空间不足会导致下载失败。
我把这些排查步骤做成了一个自检页面,用户遇到问题时可以一键检测,直接看到哪一步出了问题。
5.2 输出质量不稳定的应对
模型输出时好时坏,这是本地小模型的通病。我的应对策略有三条。
降低期望值。不要指望它给出专家级的建议,把它当成一个"能帮你发现明显问题"的助手就好。实际使用中,它对"表达啰嗦""用词模糊"这类问题的识别还是挺准的。
增加后处理。模型输出后,用规则做一层过滤。比如过滤掉长度过短的建议、过滤掉原文片段在文本中找不到的建议。这能去掉大部分无效输出。
提供反馈入口。让用户对每条建议点赞或点踩,收集数据后可以优化提示词。我收集了两百多条反馈后发现,用户最认可的是"用词模糊"类建议,最不认可的是"结构混乱"类。于是我在提示词里加强了前者、弱化了后者。
5.3 不同浏览器的兼容处理
目前内置模型的支持情况差异很大。有的浏览器完全支持,有的只支持部分API,有的完全不支持。我的做法是特性检测而非浏览器检测。不要判断navigator.userAgent,而是直接检测API是否存在。
// 好的做法:特性检测 if ('ai' in window && 'languageModel' in window.ai) { /* ... */ } // 坏的做法:浏览器检测 if (navigator.userAgent.includes('Chrome')) { /* ... */ }特性检测的好处是,当其他浏览器后续支持这个能力时,你的代码不用改就能用。浏览器检测则会把路走窄。
对于不支持的浏览器,我准备了一个纯前端规则版作为兜底。虽然效果不如模型,但至少能用。规则版的核心逻辑是维护一个常见问题词表,比如"很好""不错""优秀"这类模糊词,检测到就提示替换为具体描述。
5.4 问题速查表
| 现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 点击按钮无反应 | API不存在 | 控制台输入'ai' in window | 引导升级浏览器 |
| 一直显示加载中 | 模型下载失败 | 检查availability()返回值 | 检查网络和存储空间 |
| 输出乱码或格式错乱 | 提示词格式约束不够 | 查看原始返回文本 | 加强systemPrompt格式要求 |
| 分析速度很慢 | 文本过长或并发过高 | 查看分段数量和并发数 | 减少分段长度,降低并发 |
| 内存占用过高 | session未销毁 | 检查是否有多个session | 加防抖和自动销毁逻辑 |
| 输出内容跑题 | systemPrompt角色限定不清 | 检查提示词 | 明确角色和任务边界 |
6. 实际项目中的经验沉淀
6.1 提示词迭代的笨办法
提示词优化没有捷径,就是改一版、测一批、看结果。我建了一个测试集,包含20段不同类型的网页文本,每次改完提示词就跑一遍,人工评估输出质量。前后改了八版,质量才稳定下来。
这个过程中最大的收获是:示例比指令管用。与其写一堆"你要怎样怎样"的指令,不如直接给两个输入输出示例。模型模仿示例的能力很强,指令理解能力反而一般。
6.2 用户引导的设计细节
功能再好,用户不会用也白搭。我在界面上做了几处引导设计。
按钮文字从"分析"改成"获取优化建议",更直白。加载状态从转圈改成进度提示"正在分析第2段,共5段",让用户知道进展。结果为空时不是显示空白,而是显示"未发现明显问题,你的文案已经很不错了",给正向反馈。
这些细节看起来小,但直接影响用户留存。我对比过改版前后的数据,加了进度提示后,用户在加载过程中的跳出率下降了将近一半。
6.3 这个方案适合什么场景
最后说说适用边界。浏览器内置模型方案最适合低频、短文本、隐私敏感的场景。比如:
- 个人博客的文案自检工具
- 内部文档的用词规范检查
- 教育场景下的写作辅助
- 对隐私要求高的文本处理
不适合高频、长文本、复杂推理的场景。如果你要做的是长文档摘要、代码审查、复杂数据分析,还是老老实实上云端大模型。
我在实际使用中发现,这个方案最大的价值不是替代云端API,而是提供了一个零成本的AI能力入口。很多小需求不值得为它单独接一个API,但用浏览器内置模型就能轻松搞定。这种"顺手就能加个AI功能"的体验,才是它真正吸引人的地方。
后续如果要做扩展,我打算加上历史记录对比功能,让用户看到自己文案的改进过程。技术上就是把每次分析结果存到localStorage,然后做一个时间线视图。这个功能不复杂,但对提升用户粘性应该有帮助。