共计 2582 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点
直接调用 ChatGPT 接口存在几个明显问题:

- API 调用频率限制严格,容易触发速率限制
- 长对话场景下上下文管理困难
- 缺乏本地历史记录和持久化存储
- 无法针对特定场景做定制化交互
这些痛点使得开发专门的浏览器扩展成为必要解决方案。通过扩展可以实现:
- 本地缓存和上下文管理
- 请求队列和自动重试
- 定制化 UI 交互
- 数据持久化存储
技术选型
对比两种主流方案:
浏览器插件方案
- 优点:
- 直接与浏览器交互
- 低延迟响应
- 可访问页面 DOM
- 缺点:
- 受浏览器安全策略限制
- 功能扩展性有限
独立服务端方案
- 优点:
- 功能扩展性强
- 不受浏览器限制
- 可做复杂计算
- 缺点:
- 需要额外部署
- 网络延迟较高
推荐采用混合架构:核心逻辑放在 background service worker,复杂功能通过调用云函数实现。
graph TD
A[Content Script] --> B[Background Worker]
B --> C[OpenAI API]
B --> D[IndexedDB]
C --> E[Cloud Functions]
核心实现
Chrome Extension MV3 架构
manifest.json 关键配置:
{
"manifest_version": 3,
"background": {
"service_worker": "background.js",
"type": "module"
},
"permissions": [
"storage",
"scripting"
]
}
API 调用封装
// 带重试机制的 API 调用
async function callChatGPT(prompt: string, retry = 3): Promise<string> {
try {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify({
model: "gpt-3.5-turbo",
messages: [{role: "user", content: prompt}]
})
});
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
return data.choices[0].message.content;
} catch (error) {if (retry > 0) {await new Promise(resolve => setTimeout(resolve, 1000));
return callChatGPT(prompt, retry - 1);
}
throw error;
}
}
上下文持久化方案
推荐使用 IndexedDB 存储对话历史:
// 初始化数据库
const dbPromise = idb.openDB('chatHistory', 1, {upgrade(db) {
db.createObjectStore('conversations', {
keyPath: 'id',
autoIncrement: true
});
}
});
// 保存对话记录
async function saveConversation(prompt: string, response: string) {
const db = await dbPromise;
await db.add('conversations', {
prompt,
response,
timestamp: Date.now()});
}
性能优化
消息压缩策略
- 移除多余空格和换行
- 使用缩写替换常见短语
- 对长文本进行分段处理
测试数据显示可减少 15-20% 的 token 使用量。
流式响应实现
// 流式处理 API 响应
async function* streamChatGPT(prompt: string) {
const response = await fetch(API_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify({
model: "gpt-3.5-turbo",
messages: [{role: "user", content: prompt}],
stream: true
})
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
if (!reader) throw new Error('No reader available');
while (true) {const {done, value} = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.trim());
for (const line of lines) {if (line.includes('[DONE]')) break;
try {const data = JSON.parse(line.replace('data:', ''));
yield data.choices[0]?.delta?.content || '';
} catch (e) {console.error('Error parsing stream data:', e);
}
}
}
}
避坑指南
常见问题解决方案
- CSP 限制 :在 manifest.json 中添加必要的白名单
- Token 计数误差 :使用官方 tiktoken 库精确计算
- API 限速 :实现请求队列和指数退避重试
- 上下文丢失 :定期自动保存对话状态
- 内存泄漏 :注意清理不再使用的消息缓存
安全考量
API Key 保护措施
- 永远不要在前端代码中硬编码 API Key
- 建议使用临时 token 或代理服务
- 实现按用户配额限制
- 监控异常调用模式
延伸思考
- 如何实现多轮对话的上下文智能压缩?
- 在插件中集成自定义知识库的最佳实践是什么?
- 如何平衡本地处理和云端计算的资源分配?
正文完
发表至: 未分类
近三天内
