跳转到主要内容
上下文管理

多轮对话

管理对话上下文

Qwen API 是无状态的,不会保存对话历史。要实现多轮对话,您需要在每次请求中传递对话历史。此外,您还可以使用截断、摘要和检索等策略来高效管理上下文并降低 Token 消耗。
本文介绍如何通过 Responses API、OpenAI 兼容 Chat Completions 或 DashScope API 实现多轮对话,并提供上下文管理策略。

工作原理

要实现多轮对话,您需要维护一个 messages 数组。每轮对话中,将用户的最新提问和模型的回复追加到该数组中,然后将更新后的数组作为下一次请求的输入。 以下示例展示了对话过程中 messages 数组的变化:
1

第一轮

将用户的提问添加到 messages 数组中。
// 使用文本模型
[
  {"role": "user", "content": "推荐一部关于太空探索的科幻电影。"}
]

// 使用多模态模型,例如 Qwen-VL
// {"role": "user",
//       "content": [{"type": "image_url","image_url": {"url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251031/ownrof/f26d201b1e3f4e62ab4a1fc82dd5c9bb.png"}},
//                   {"type": "text", "text": "图片中展示了哪些商品?"}]
// }
2

第二轮

将模型的回复和用户的最新提问添加到 messages 数组中。
// 使用文本模型
[
  {"role": "user", "content": "推荐一部关于太空探索的科幻电影。"},
  {"role": "assistant", "content": "推荐《XXX》,这是一部经典的科幻作品。"},
  {"role": "user", "content": "这部电影的导演是谁?"}
]

// 使用多模态模型,例如 Qwen-VL
//[
//    {"role": "user", "content": [
//                    {"type": "image_url","image_url": {"url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251031/ownrof/f26d201b1e3f4e62ab4a1fc82dd5c9bb.png"}},
//                   {"type": "text", "text": "图片中展示了哪些商品?"}]},
//    {"role": "assistant", "content": "图片中展示了三件商品:一条浅蓝色背带裤、一件蓝白条纹短袖衬衫和一双白色运动鞋。"},
//    {"role": "user", "content": "它们是什么风格的?"}
//]

快速开始

  • Responses API
  • OpenAI 兼容
  • DashScope
Responses API 简化了多轮对话的实现。通过传递 previous_response_id 即可自动关联上下文,无需手动管理消息历史。如需更高级的会话管理,请参见使用 Conversations
请使用响应的 id(UUID 格式,如 f0dbb153-117f-9bbf-8176-5284b47f3xxx)作为 previous_response_id。不要使用 output 数组中消息的 id(如 msg_56c860c4-3ad8-4a96-8553-d2f94c259xxx)。响应 id 的有效期为 7 天。
import os
from openai import OpenAI

client = OpenAI(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

# 第一轮
response1 = client.responses.create(
  model="qwen3.7-plus",
  input="我叫小明,请记住我的名字。"
)
print(f"第一轮回复:{response1.output_text}")

# 第二轮 - 使用 previous_response_id 关联上下文
response2 = client.responses.create(
  model="qwen3.7-plus",
  input="你还记得我的名字吗?",
  previous_response_id=response1.id
)
print(f"第二轮回复:{response2.output_text}")
响应示例(第二轮)
{
  "id": "f0dbb153-117f-9bbf-8176-5284b47f3xxx",
  "model": "qwen3.7-plus",
  "status": "completed",
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "当然记得,小明!有什么我可以帮您的吗?"
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 78,
    "output_tokens": 16,
    "total_tokens": 94
  }
}

多模态模型

  • 本节适用于 Qwen3-VL 和 Qwen3.5 等多模态模型。Qwen-Omni 请参见非实时
  • Qwen3-Omni-Captioner 专为单轮任务设计,不支持多轮对话。
多模态模型的多轮对话与文本模型有以下区别:
  • 用户消息的构造:多模态模型的用户消息除了文本外,还可以包含图像、音频等多模态信息。
  • DashScope SDK 接口:使用 DashScope Python SDK 时,需调用 MultiModalConversation 类;使用 DashScope Java SDK 时,同样调用 MultiModalConversation 类。
  • OpenAI 兼容
  • DashScope
from openai import OpenAI
import os

client = OpenAI(
  # 如果没有配置环境变量,请用 API Key 替换下行: api_key="sk-xxx"
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
messages = [
  {
    "role": "user",
    "content": [
      {
        "type": "image_url",
        "image_url": {
          "url": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20251031/ownrof/f26d201b1e3f4e62ab4a1fc82dd5c9bb.png"
        },
      },
      {"type": "text", "text": "图片中展示了哪些商品?"},
    ],
  }
]
completion = client.chat.completions.create(
  model="qwen3-vl-plus",  # 您可以替换为其他多模态模型,并根据需要修改 messages
  messages=messages,
)
print(f"第一轮输出:{completion.choices[0].message.content}")

assistant_message = completion.choices[0].message
messages.append(assistant_message.model_dump())
messages.append({
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "它们是什么风格的?"
    }
  ]
})
completion = client.chat.completions.create(
  model="qwen3-vl-plus",
  messages=messages,
  )

print(f"第二轮输出:{completion.choices[0].message.content}")

思考模型

思考模型会返回两个字段:reasoning_content(思考过程)和 content(最终回复)。更新 messages 数组时,只需保留 content 字段,忽略 reasoning_content 字段。
[
  {"role": "user", "content": "推荐一部关于太空探索的科幻电影。"},
  {"role": "assistant", "content": "推荐《XXX》,这是一部经典的科幻作品。"},
  {"role": "user", "content": "这部电影的导演是谁?"}
]
将助手消息添加到 messages 数组时,请不要包含 reasoning_content 字段,否则会导致请求报错。
关于思考模型的更多信息,请参见深度思考视觉理解。Qwen3-Omni-Flash(思考模式)的多轮对话请参见非实时
  • OpenAI 兼容
  • DashScope
from openai import OpenAI
import os

# 初始化 OpenAI 客户端
client = OpenAI(
  # 如果没有配置环境变量,请用 API Key 替换下行: api_key="sk-xxx"
  api_key = os.getenv("DASHSCOPE_API_KEY"),
  base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)


messages = []
conversation_idx = 1
while True:
  reasoning_content = ""  # 定义完整思考过程
  answer_content = ""     # 定义完整回复
  is_answering = False   # 判断是否结束思考过程并开始回复
  print("="*20+f"第 {conversation_idx} 轮对话"+"="*20)
  conversation_idx += 1
  user_msg = {"role": "user", "content": input("请输入:")}
  messages.append(user_msg)
  # 创建聊天补全请求
  completion = client.chat.completions.create(
    # 您可以根据需要替换为其他深度思考模型
    model="qwen3.7-plus",
    messages=messages,
    extra_body={"enable_thinking": True},
    stream=True,
    # stream_options={
    #     "include_usage": True
    # }
  )
  print("\n" + "=" * 20 + "思考过程" + "=" * 20 + "\n")
  for chunk in completion:
    # 如果 chunk.choices 为空,打印用量信息
    if not chunk.choices:
      print("\n用量信息:")
      print(chunk.usage)
    else:
      delta = chunk.choices[0].delta
      # 打印思考过程
      if hasattr(delta, 'reasoning_content') and delta.reasoning_content != None:
        print(delta.reasoning_content, end='', flush=True)
        reasoning_content += delta.reasoning_content
      else:
        # 开始回复
        if delta.content != "" and is_answering is False:
          print("\n" + "=" * 20 + "完整回复" + "=" * 20 + "\n")
          is_answering = True
        # 打印回复内容
        print(delta.content, end='', flush=True)
        answer_content += delta.content
  # 将模型回复内容添加到上下文
  messages.append({"role": "assistant", "content": answer_content})
  print("\n")

使用 Conversations

previous_response_id 适用于简单的链式对话。如果需要服务端会话管理、跨设备上下文延续或手动控制消息,可以使用 Conversations API 的 conversation 参数。

创建会话并对话

首先通过 Conversations API 创建一个会话,然后将 conversation 参数和 instructions(系统提示词)传入 responses.create。服务端会自动管理上下文。
import os
from openai import OpenAI

client = OpenAI(
  api_key=os.getenv("DASHSCOPE_API_KEY"),
  base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

# 创建会话
conversation = client.conversations.create()

# 第一轮
response1 = client.responses.create(
  conversation=conversation.id,
  model="qwen3.7-plus",
  instructions="你是一位旅行顾问,擅长推荐旅行目的地。",
  input="推荐一个适合夏季旅行的城市。",
)
print(f"第一轮回复:{response1.output_text}")

# 第二轮 - 服务端自动管理上下文
response2 = client.responses.create(
  conversation=conversation.id,
  model="qwen3.7-plus",
  instructions="你是一位旅行顾问,擅长推荐旅行目的地。",
  input="那里有什么必尝的美食?",
)
print(f"第二轮回复:{response2.output_text}")

向会话中添加消息

您可以手动向会话中添加消息(如补充用户消息或外部知识)。
items = client.conversations.items.create(
  "conv_xxx",  # 替换为您的 conversation id
  items=[
    {
      "type": "message",
      "role": "user",
      "content": [{"type": "input_text", "text": "补充信息:我更喜欢海滨城市。"}],
    }
  ],
)
print(items.data)

查看对话历史

列出会话中的所有消息,查看完整的对话历史。
items = client.conversations.items.list("conv_xxx")  # 替换为您的 conversation id
print(items.data)

注意事项

  • ID 有效期:响应 id 和会话中的消息有效期为 7 天。conversation 本身不过期,可持续使用,但其中过期的消息将不再参与上下文。建议通过 instructions 参数传递系统指令,而非通过创建会话时的 items,以避免系统指令因过期而丢失。
  • 正确的 ID 来源:请使用响应的顶层 id,而非 output 数组中消息的 id
  • 跨轮上下文:每次传入 previous_response_id 时,系统会自动关联从首轮对话到当前轮次的完整上下文。
  • 互斥性previous_response_idconversation 不能同时使用,否则会报错 [400] INVALID_REQUEST: Mutually exclusive parameters: Ensure you are only providing one of: previous_response_id or conversation.

如何选择?

方式适用场景
previous_response_id简单的链式多轮对话,无需创建独立会话
conversation服务端会话管理、跨设备上下文延续、手动增删消息
更多 Conversations API 操作(更新会话、删除会话、删除消息等),请参见 Conversations

正式使用

多轮对话会消耗大量 Token,且可能超出模型的上下文限制。请使用以下策略管理上下文并控制成本。

1. 上下文管理

messages 数组会随着对话轮次增长,可能超出 Token 限制。

1.1. 上下文截断

当对话历史过长时,只保留最近 N 轮对话。这种方法实现简单,但会丢失早期的对话信息。

1.2. 滚动摘要

为了在不丢失核心信息的前提下动态压缩对话历史、控制上下文长度,可以随着对话推进对上下文进行摘要: a. 当对话历史达到一定长度(如最大上下文长度的 70%)时,提取较早的部分(如前半段),单独调用模型生成该部分的"记忆摘要"。 b. 构造下一次请求时,用"记忆摘要"替换冗长的对话历史,并拼接最近几轮对话。

1.3. 向量化检索

滚动摘要可能导致部分信息丢失。为了让模型能从大量对话历史中回忆相关信息,可以从线性传递上下文切换为按需检索: a. 每轮对话结束后,将对话内容存入向量数据库。 b. 用户提问时,基于相似度检索相关的对话记录。 c. 将检索到的对话记录与最新的用户输入合并后发送给模型。

2. 成本控制

每轮对话的输入 Token 都会增加,导致成本上升。

2.1. 减少输入 Token

使用上述上下文管理策略来减少输入 Token,从而降低成本。

2.2. 使用支持上下文缓存的模型

messages 数组会被重复处理和计费。上下文缓存(适用于 Qwen-Max、Qwen-Plus、Qwen-Flash 和 Qwen-Coder 等部分 Qwen 模型)可以降低成本并提升响应速度。
上下文缓存功能自动启用,无需修改代码。

错误码

如果调用失败,请参见错误信息