前面的示例中,每次请求都是独立的,模型只会根据当前提问生成回复,并不会记住之前的聊天内容。
如果希望实现“连续聊天”,就需要把历史对话一起传给模型,也就是多轮对话。
多轮对话的核心原理
LLM 本身并不会“记忆”之前的聊天内容。
所谓多轮对话,本质上是“每次请求时,把历史消息重新发送给模型”。
举一个例子,下面的对话包含两次请求和两次回复:
User:你好
AI:你好,有什么可以帮助你的?
User:我想学习 Python
AI:Python 很适合作为编程入门语言。
第二次请求时,实际上传给模型的是:
messages = [
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好,有什么可以帮助你的?"},
{"role": "user", "content": "我想学习 Python"},
]
模型通过完整上下文,理解当前对话,并生成下一条回复。
核心流程
初始化 client
创建 OpenAI-compatible API 对应的 client。
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com"
)
创建 messages
messages = []
所有历史消息都会存储到 messages 列表中,每条消息都包含:
role:角色
content:消息内容
当前示例涉及两个角色:
user:用户输入
assistant:模型输出
开启聊天循环
使用 while True 持续读取用户输入,实现一个最基础的命令行聊天循环。
print("开始对话(输入 exit 退出)\n")
while True:
user_input = input("User:")
if user_input == "exit":
break
...
保存用户消息
用户输入后,需要先追加到 messages,messages 必须保存完整且有顺序的历史消息,因为模型是按照消息顺序理解对话的。
while True:
...
messages.append({
"role": "user",
"content": user_input
})
发起 API 请求
把完整 messages 发送给模型,stream=True 让模型以流式方式逐步返回内容。
while True:
...
response = client.chat.completions.create(
model="deepseek-v4-flash",
messages=messages,
stream=True
)
流式输出模型回复
先打印 AI 前缀,然后定义一个变量 full_reply,用于拼接完整回复。
接着遍历流式返回的 chunk,拼接到 full_reply,同时实时打印到终端。
while True:
...
print("AI: ", end="", flush=True)
full_reply = ""
for chunk in response:
content = chunk.choices[0].delta.content
if content is not None:
print(content, end="", flush=True)
full_reply += content
保存 assistant 回复
模型输出结束后,需要把完整回复重新追加到 messages,这样下一轮请求时,模型才能看到自己刚才的回复。
while True:
...
messages.append({
"role": "assistant",
"content": full_reply
})