
1. 浏览器 Tab 自动分组插件到底解决什么问题浏览器 Tab 自动分组插件说白了就是让浏览器自己把同一域名的标签页收进一个带颜色和名字的组里省得你手动一个个拖。它适合每天开几十个标签页、又懒得整理的人也适合想用 Cursor 练手浏览器扩展开发的同学。我平时查资料会同时开 GitHub、文档站、几个技术博客标签栏挤成一条缝找东西全靠肉眼扫后来干脆用 Cursor 写了个插件把域名和分组规则交给模型做聚类再让扩展自动执行分组。这个场景的核心链路其实分两段一段是浏览器扩展本身的能力用chrome.tabs.group、chrome.tabGroups这些 API 完成分组和上色另一段是“怎么决定哪些域名该归到一组”这一步如果纯靠手写规则遇到新域名就得手动加很烦。所以我把模型接口接进来让模型根据域名和标题给出分组建议再由扩展落地。模型调用需要一个稳定的 Base URL 和统一 Key这里我用 TaoToken 做接入层把模型请求统一走一个入口Cursor 里写代码时也不用到处换配置。先明确一下这个插件最终要做什么配置页填写域名、分组名称、分组颜色保存后对已打开的标签页立即分组。编辑页展示已有分组规则支持修改和删除。后台自动分组打开已配置域名的链接时自动并入对应分组。模型聚类对未配置的域名调用模型接口给出分组建议减少手动维护。这四件事里前三件是扩展 API 的活第四件是模型接口的活。很多人卡在第四件不是因为模型不会用而是因为 Base URL、Key、Model ID 三件套没对齐请求发出去报 401 或者local proxy failed。下面我按“先跑通扩展再接模型”的顺序写每一步都能复制。2. TaoToken 前置准备统一 Key 与 Base URL 怎么配在 Cursor 里写调用模型的代码之前先把接入层准备好。TaoToken 的作用是给你一个统一的 API 入口Base URL 固定为https://taotoken.net/apiKey 在控制台生成。这样你在扩展里发请求时不用关心后面具体是哪个模型厂商换模型只改 Model ID 就行。第一步打开控制台创建 API Key。地址是https://taotoken.net/console登录后在 API Keys 页面新建一个 Key复制出来先存到本地临时文件里后面要填进扩展的配置。注意 Key 只显示一次丢了就重新建。第二步确认你要用的 Model ID。不同模型 ID 不一样比如做文本聚类可以用通用的对话模型。你可以在模型对话页面先试一下请求能不能通地址是https://taotoken.net/models选一个模型发一句“你好”能返回就说明 Key 和 Base URL 没问题。第三步把三件套记下来后面 Cursor 生成的代码里要填配置项值说明Base URLhttps://taotoken.net/api所有请求的前缀不要加多余路径API Key控制台生成的sk-开头字符串放在扩展的 storage 里不要硬编码进源码Model ID例如gpt-4o-mini这类对话模型按控制台可用列表填这里有个容易踩的坑Base URL 末尾不要自己加/v1或者/chat/completions很多 SDK 会自动拼路径你手动加了就变成双份请求直接 404。我试过在 Cursor 生成的代码里看到它把 Base URL 写成https://taotoken.net/api/v1结果一直报路径错误改回https://taotoken.net/api就好了。另外Key 不要写进manifest.json或者提交到 Git。扩展里正确做法是存在chrome.storage.local配置页让用户自己填或者你在本地调试时用chrome.storage.local.set临时写进去。生产环境更推荐让用户自己填 Key避免你的 Key 泄露。如果你打算长期用这个插件做编码类任务比如让模型帮你生成分组规则甚至改代码可以了解下 Coding Plan地址是https://taotoken.net/coding-plan它更适合高频调用场景。不过我们这个插件只是偶尔调一次聚类用普通 API Key 就够了。准备好这三件套之后回到 Cursor 项目里把.cursorrules和 Composer 提示词写清楚让生成的代码直接按这个 Base URL 来发请求省得后面手动改。3. 可复制配置Cursor 工程初始化与模型调用片段这一节给你能直接复制的配置。先在 Cursor 里新建项目目录比如auto-tab-plugin然后在根目录建.cursorrules文件把项目约束写进去。.cursorrules的作用是让 Cursor 生成的代码符合你的技术栈和接口规范尤其是 Base URL 和 Key 的读取方式。.cursorrules内容如下你是浏览器扩展开发专家使用 Manifest V3。 项目使用原生 JS HTML不引入框架。 所有模型请求统一走 Base URL: https://taotoken.net/api API Key 从 chrome.storage.local 读取字段名 taotoken_key。 Model ID 从 chrome.storage.local 读取字段名 taotoken_model。 请求路径使用 /chat/completions不要重复拼接 /v1。 分组逻辑使用 chrome.tabs.group 和 chrome.tabGroups。接着用CmdI唤起 Composer输入需求提示词。提示词里把模型调用部分写明确避免 Cursor 自己编一个 Base URL帮我实现一个浏览器扩展Manifest V3功能是对标签页按域名分组。 要求 1. 配置页输入域名、分组名称、颜色保存后对已打开标签页分组。 2. 编辑页展示分组规则列表支持编辑和删除。 3. 后台 service worker打开已配置域名时自动并入分组。 4. 对未配置域名调用模型接口获取分组建议。 模型请求配置 - Base URL: https://taotoken.net/api - 路径: /chat/completions - Key 从 chrome.storage.local 的 taotoken_key 读取 - Model 从 chrome.storage.local 的 taotoken_model 读取 - 请求体使用 OpenAI 兼容格式生成项目后Cursor 可能会给一个生成 icon 的脚本依赖 canvas。按它提示装依赖npm i canvas -g node convert_icons.js然后重点看模型调用那段代码。如果 Cursor 生成的callModel函数里 Base URL 不对直接改成下面这个版本。这是一个可以复制进background.js的请求片段async function callModel(domains) { const { taotoken_key, taotoken_model } await chrome.storage.local.get([ taotoken_key, taotoken_model, ]); const resp await fetch(https://taotoken.net/api/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${taotoken_key}, }, body: JSON.stringify({ model: taotoken_model || gpt-4o-mini, messages: [ { role: system, content: 你是标签分组助手。根据域名列表给出分组建议返回 JSON 数组每项包含 domain、group、color。, }, { role: user, content: JSON.stringify(domains), }, ], temperature: 0.2, }), }); if (!resp.ok) { const errText await resp.text(); throw new Error(model request failed: ${resp.status} ${errText}); } const data await resp.json(); return data.choices[0].message.content; }注意Authorization是Bearer加空格再加 Key少一个空格就是 401。model字段填你在控制台确认过的 Model ID不要留空。请求体里messages是标准 OpenAI 兼容格式TaoToken 的接口按这个格式收。配置页里加两个输入框让用户填 Key 和 Model保存时写进 storageawait chrome.storage.local.set({ taotoken_key: keyInput.value.trim(), taotoken_model: modelInput.value.trim(), });这样三件套就齐了Base URL 写死在请求里Key 和 Model ID 从 storage 读。后面验证请求时如果报错先检查这三个值。4. 验证请求与分组准确率本地加载与实测清单代码写完后先在浏览器里加载本地插件。打开chrome://extensions右上角开启开发者模式点“加载已解压的扩展程序”选项目根目录。加载后看扩展卡片有没有红色报错有的话点“错误”看详情通常是manifest.json字段写错或者 service worker 语法错误。加载成功后点扩展图标打开配置页填入 TaoToken 的 Key 和 Model ID再新建一条分组规则比如域名github.com、分组名Dev、颜色blue点保存。这时候已打开的 GitHub 标签页应该被收进一个蓝色分组。如果分组成功但颜色没生效是chrome.tabGroups.update没调用或者颜色值不在允许列表里允许值包括grey、blue、red、yellow、green、pink、purple、cyan、orange。验证模型请求是否通可以在配置页加一个“测试模型”按钮点击后调用callModel([example.com])看返回内容。如果返回正常说明 Base URL、Key、Model ID 三件套没问题。如果报 401检查 Key 有没有多余空格如果报local proxy failed检查 Base URL 是不是被改成了本地地址如果报reading choices相关错误说明返回结构不是预期的choices[0].message.content打印完整响应看看。分组准确率的验证可以这样操作准备 10 个不同域名的标签页其中 6 个属于你配置过的分组4 个未配置。触发自动分组看已配置的 6 个是否全部进组颜色是否正确。对未配置的 4 个调用模型聚类看建议分组是否合理。手动改一条规则看已分组标签页是否同步更新。删除一条规则看对应分组是否解散。我实测下来模型聚类对技术类域名的建议基本可用但偶尔会把docs.xxx.com和xxx.com分成两组因为模型只看域名字符串。解决办法是在提示词里加一句“子域名归入主域名分组”或者在代码里先做一次域名归一化把docs.前缀去掉再发给模型。还有一个坑是已打开标签页多次分组。如果同域名标签页在分组后又被打开后台脚本会再次调用分组可能导致分组重复或者标签页跳动。处理方式是在分组前先查chrome.tabGroups.query看该分组是否已存在存在就只把新标签页加进去不重建分组。5. 常见报错排查401、local proxy failed、reading choices这一节把几个高频报错对照着说都是我在调试时真实遇到的。401 Unauthorized。最常见原因是 Key 不对或者格式不对。检查Authorization头是不是Bearer sk-xxx中间一个空格。如果 Key 是从控制台复制的注意有没有把前后空格带进去。还有一种情况是 Key 被禁用或者额度用完去控制台看下状态。local proxy failed。这个报错通常出现在你把 Base URL 改成了本地地址比如http://localhost:xxxx但本地服务没起来。我们这个插件里 Base URL 应该是https://taotoken.net/api不要改成任何本地地址。如果你在 Cursor 生成的代码里看到它自动填了http://127.0.0.1直接替换掉。Cannot read properties of undefined (reading choices)。这说明返回的 JSON 里没有choices字段。可能原因有三个一是请求路径不对比如拼成了/api/v1/chat/completions实际应该是/api/chat/completions二是 Model ID 填错接口返回了错误对象三是响应被拦截或者返回了 HTML。排查方法是把resp.text()打印出来看原始返回是什么。OAuth 相关报错。如果你在 Cursor 里配置了某些需要 OAuth 的模型接入方式可能会看到 token 过期或者回调失败。我们这个插件用的是 API Key 方式不涉及 OAuth所以如果你看到 OAuth 报错说明代码里混入了别的接入逻辑检查callModel函数是不是被 Cursor 改成了别的认证方式。分组颜色不生效。前面提过颜色值必须在允许列表里。另外chrome.tabGroups.update要在分组创建之后调用顺序反了颜色不会应用。规则列表加载不出来。编辑页读 storage 时字段名要对上配置页写的是rules编辑页就得读rules。如果 Cursor 生成的代码里一个用groupRules一个用rules就会读不到。统一字段名即可。自动分组不触发。Manifest V3 的 service worker 是事件驱动的chrome.tabs.onUpdated监听要注册在顶层不能放在异步回调里。检查background.js里监听器是不是直接写在最外层。6. 继续用 Cursor 迭代这个插件的建议插件跑通之后你可以继续用 Cursor 加功能。比如把分组规则同步到云端或者加一个“一键整理所有窗口”的按钮。每次改需求时把.cursorrules里的 Base URL 和 Key 读取方式保留Cursor 就不会乱改接口配置。如果你后面要接更多模型能力比如让模型直接读标签页标题做语义聚类记得 Model ID 换成支持长文本的模型请求体里把标题拼进messages。TaoToken 的 API Key 和 Base URL 不用变只改 Model ID 就行。需要看接口细节可以去接入文档地址是https://taotoken.net/doc。如果你更习惯在 Claude Code 这类工具里写代码也可以参考https://taotoken.net/claude-code-anthropic的接入方式思路是一样的Base URL 加 Key 加 Model ID。最后提醒一句扩展里调用模型接口是异步的分组操作也是异步的注意用await串起来不然会出现规则还没保存就去分组的情况。把这两段异步逻辑理清楚这个插件的稳定性就差不多了。