基于NodeJS开发gpt-3.5-turbo聊天应用,能否通过OpenAI API保存对话状态?
可行,实现方案如下
完全可以实现这类需求,核心是自己在Node.js端维护用户的会话状态,并通过对话历史压缩技术减少每次调用OpenAI API时传递的内容体积,既保留对话上下文,又避免每次发送完整历史。
核心实现思路
- 会话状态本地存储:OpenAI API本身不会保存用户的对话上下文,所以需要你自己用数据库(如MongoDB、Redis)或内存存储(仅开发阶段)来保存每个用户的完整对话历史,每条记录包含角色(
user/assistant/system)、消息内容、时间戳等字段。 - 对话历史压缩优化:为了避免每次API调用都发送全部历史,可通过以下方式压缩内容:
- 定期生成对话摘要:调用GPT-3.5-turbo将早期的多轮对话生成简洁摘要,用摘要替代原始的长对话历史,仅保留最新的几轮对话+摘要传递给API。
- 关键信息过滤:手动或通过AI提取对话中的核心指令、用户需求等关键信息,过滤掉无关的闲聊内容。
- API调用优化:每次调用时只传递压缩后的对话上下文+最新的用户消息,而非完整历史,以此维持对话状态并降低token消耗。
Node.js 代码示例
const { OpenAI } = require('openai'); const redis = require('redis'); const client = redis.createClient(); const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); // 获取用户会话历史 async function getSessionHistory(userId) { const historyStr = await client.get(`chat:${userId}`); return historyStr ? JSON.parse(historyStr) : []; } // 保存会话历史到Redis async function saveSessionHistory(userId, history) { await client.set(`chat:${userId}`, JSON.stringify(history)); } // 压缩对话历史:用摘要替换早期对话 async function compressHistory(history) { // 少于5轮对话不压缩 if (history.length <= 5) return history; // 拆分早期历史和最新3轮对话 const earlyHistory = history.slice(0, -3); const latestHistory = history.slice(-3); // 调用GPT生成早期对话的摘要 const summaryCompletion = await openai.chat.completions.create({ model: "gpt-3.5-turbo", messages: [ { role: "system", content: "请将以下对话生成简洁摘要,务必保留用户的核心需求和对话关键上下文:" }, ...earlyHistory ] }); const summary = summaryCompletion.choices[0].message.content; // 返回压缩后的历史:摘要 + 最新对话 return [ { role: "system", content: `对话历史摘要:${summary}` }, ...latestHistory ]; } // 处理用户消息的主函数 async function handleUserMessage(userId, userMessage) { // 获取当前会话历史 let sessionHistory = await getSessionHistory(userId); // 添加用户新消息 sessionHistory.push({ role: "user", content: userMessage }); // 压缩对话历史 const compressedHistory = await compressHistory(sessionHistory); // 调用OpenAI API const chatCompletion = await openai.chat.completions.create({ model: "gpt-3.5-turbo", messages: compressedHistory }); const assistantReply = chatCompletion.choices[0].message.content; // 更新会话历史,保存完整的原始对话(用于后续压缩) sessionHistory.push({ role: "assistant", content: assistantReply }); await saveSessionHistory(userId, sessionHistory); return assistantReply; }
注意事项
- 压缩时机把控:建议每5-10轮对话进行一次压缩,避免过于频繁压缩导致上下文丢失。
- 摘要质量优化:可以调整生成摘要的system prompt,确保摘要准确保留用户的核心需求和对话关键信息。
- 数据安全:如果对话包含敏感信息,务必对存储的会话数据进行加密处理。
- token消耗监控:即使压缩后仍会产生token消耗,需定期监控OpenAI API的token使用情况,避免超出配额。
内容的提问来源于stack exchange,提问作者yoty66
相关产品推荐
相关产品推荐

