You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为OpenAI模型配置对话记忆?Django+React聊天机器人开发疑问

解决方案

一、创建对话存储的数据库模型

先定义会话与消息的关联模型,用于存储对话历史:

# models.py
from django.db import models
from django.contrib.auth.models import User  # 无用户系统可删除此关联

class Conversation(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Message(models.Model):
    ROLE_CHOICES = (
        ('user', '用户'),
        ('assistant', 'AI助手'),
    )
    conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='messages')
    role = models.CharField(max_length=10, choices=ROLE_CHOICES)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

执行迁移命令:

python manage.py makemigrations
python manage.py migrate

二、修改APIView集成对话记忆

推荐方案:切换到gpt-3.5-turbo模型(对话适配性更强、token成本更低)

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
import openai
from .models import Conversation, Message

api_key = "你的OpenAI密钥"

class ChatbotView(APIView):
    def post(self, request):
        if not api_key:
            return Response({'errors': {'api_key': ['未配置API密钥']}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        openai.api_key = api_key
        user_input = request.data.get('user_input')
        conversation_id = request.data.get('conversation_id')
        
        if not user_input:
            return Response({'errors': {'user_input': ['输入为空']}}, status=status.HTTP_400_BAD_REQUEST)
        
        # 处理会话:新建或获取已有会话
        if conversation_id:
            try:
                conversation = Conversation.objects.get(id=conversation_id)
            except Conversation.DoesNotExist:
                return Response({'errors': {'conversation_id': ['会话不存在']}}, status=status.HTTP_404_NOT_FOUND)
        else:
            conversation = Conversation.objects.create()  # 有用户系统可改为 Conversation.objects.create(user=request.user)
        
        # 保存用户输入
        Message.objects.create(conversation=conversation, role='user', content=user_input)
        
        # 构建对话历史
        messages = []
        for msg in conversation.messages.all().order_by('created_at'):
            messages.append({"role": msg.role, "content": msg.content})
        
        # 调用OpenAI接口
        try:
            response = openai.ChatCompletion.create(
                model='gpt-3.5-turbo',
                messages=messages,
                max_tokens=250,
                temperature=0.5
            )
            assistant_response = response['choices'][0]['message']['content'].strip()
        except Exception as e:
            return Response({'errors': {'openai': [str(e)]}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        # 保存AI回复
        Message.objects.create(conversation=conversation, role='assistant', content=assistant_response)
        
        return Response({
            "response": assistant_response,
            "conversation_id": conversation.id
        }, status=status.HTTP_200_OK)

兼容原有方案:继续使用text-davinci-003

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
import openai
from .models import Conversation, Message

api_key = "你的OpenAI密钥"

class ChatbotView(APIView):
    def post(self, request):
        if not api_key:
            return Response({'errors': {'api_key': ['未配置API密钥']}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        openai.api_key = api_key
        user_input = request.data.get('user_input')
        conversation_id = request.data.get('conversation_id')
        
        if not user_input:
            return Response({'errors': {'user_input': ['输入为空']}}, status=status.HTTP_400_BAD_REQUEST)
        
        # 处理会话
        if conversation_id:
            try:
                conversation = Conversation.objects.get(id=conversation_id)
            except Conversation.DoesNotExist:
                return Response({'errors': {'conversation_id': ['会话不存在']}}, status=status.HTTP_404_NOT_FOUND)
        else:
            conversation = Conversation.objects.create()
        
        # 保存用户输入
        Message.objects.create(conversation=conversation, role='user', content=user_input)
        
        # 构建prompt
        prompt_parts = []
        for msg in conversation.messages.all().order_by('created_at'):
            role_text = "用户:" if msg.role == 'user' else "AI:"
            prompt_parts.append(f"{role_text}{msg.content}")
        prompt_parts.append("AI:")
        prompt = "\n".join(prompt_parts)
        
        # 调用OpenAI接口
        try:
            response = openai.Completion.create(
                model='text-davinci-003',
                prompt=prompt,
                max_tokens=250,
                temperature=0.5,
                stop=["用户:"]
            )
            assistant_response = response["choices"][0]["text"].strip()
        except Exception as e:
            return Response({'errors': {'openai': [str(e)]}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        # 保存AI回复
        Message.objects.create(conversation=conversation, role='assistant', content=assistant_response)
        
        return Response({
            "response": assistant_response,
            "conversation_id": conversation.id
        }, status=status.HTTP_200_OK)

三、Token消耗优化方案

  1. 切换到gpt-3.5-turbo模型:token成本仅为text-davinci-003的1/10,对话场景适配性更强。
  2. 限制历史对话轮数:只保留最近5-10轮对话,减少上下文长度:
# 示例:只保留最近8条消息(4轮对话)
recent_messages = conversation.messages.all().order_by('created_at')[-8:]
  1. 历史对话总结:当对话超过一定轮数时,调用API总结历史对话,用总结内容替代完整历史:
if conversation.messages.count() > 10:
    # 提取历史对话文本
    history_text = "\n".join([f"{msg.role}: {msg.content}" for msg in conversation.messages.all().order_by('created_at')[:-2]])
    summary_prompt = f"请总结以下对话关键信息:\n{history_text}"
    summary_response = openai.ChatCompletion.create(
        model='gpt-3.5-turbo',
        messages=[{"role": "user", "content": summary_prompt}],
        max_tokens=100
    )
    summary = summary_response['choices'][0]['message']['content']
    
    # 重置会话,保留总结与最新对话
    conversation.messages.all().delete()
    Message.objects.create(conversation=conversation, role='system', content=f"对话总结:{summary}")
    # 重新添加最新的用户输入
    Message.objects.create(conversation=conversation, role='user', content=user_input)
  1. token数量校验:用tiktoken库计算上下文token数,避免超过模型上限:
pip install tiktoken
import tiktoken

def count_tokens(messages, model="gpt-3.5-turbo"):
    encoding = tiktoken.encoding_for_model(model)
    num_tokens = 0
    for message in messages:
        num_tokens += 4
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":
                num_tokens -= 1
    num_tokens += 2
    return num_tokens

# 构建messages后校验,超过限制则移除最早的消息
while count_tokens(messages) > 3500:
    messages.pop(0)

四、前端配合说明

前端首次对话无需传递conversation_id,后端返回新会话ID后,后续所有对话都携带该ID,即可关联同一会话的历史记录。

内容的提问来源于stack exchange,提问作者Salaodxgotico _LAS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 11:58:10