LangChain 多轮对话完全指南

目录


什么是多轮对话

单轮对话 vs 多轮对话

单轮对话:每次独立问答,不记住之前的内容

# 单轮:每次都是全新的开始
response = model.invoke("北京天气如何?")
response = model.invoke("那上海呢?")  # AI不知道"那上海"指的是什么

多轮对话:记住对话历史,上下文关联

# 多轮:记住之前的对话
messages = [
    HumanMessage(content="北京天气如何?"),
    AIMessage(content="北京今天晴天,25度"),
    HumanMessage(content="那上海呢?")  # AI知道"那上海"指的是上海的天气
]
response = model.invoke(messages)

为什么需要多轮对话?

场景 单轮问题 多轮优势
追问 "那上海呢?" 自动理解指代上文
澄清 "不对,是冬天" 记住之前的错误修正
任务延续 "继续写代码" 记得之前写了什么
个性化 "我的名字是小明" 记住用户信息

对话历史管理

最简单的多轮对话

from langchain.chat_models import init_chat_model
from langchain.messages import SystemMessage, HumanMessage, AIMessage
import os
from dotenv import load_dotenv
​
load_dotenv(encoding='utf-8')
​
model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
​
# 构建对话历史
messages = [
    SystemMessage(content="你是一个旅游助手"),
    HumanMessage(content="推荐几个国内旅游城市"),
    AIMessage(content="我推荐:成都、杭州、厦门、丽江"),
    HumanMessage(content="成都有什么好吃的?"),
]
​
response = model.invoke(messages)
print(response.content)

对话历史累积

# 初始化对话历史
history = []
​
# 第1轮对话
messages = history + [
    HumanMessage(content="推荐几个国内旅游城市")
]
response = model.invoke(messages)
print(f"AI: {response.content}")
​
# 更新历史
history.append(HumanMessage(content="推荐几个国内旅游城市"))
history.append(AIMessage(content=response.content))
​
# 第2轮对话(带上历史)
messages = history + [HumanMessage(content="成都有什么好吃的?")]
response = model.invoke(messages)
print(f"AI: {response.content}")
​
# 更新历史
history.append(HumanMessage(content="成都有什么好吃的?"))
history.append(AIMessage(content=response.content))
​
# 第3轮对话
messages = history + [HumanMessage(content="那杭州呢?")]
response = model.invoke(messages)
print(f"AI: {response.content}")

MessagesPlaceholder 占位符

为什么需要占位符?

构建 Prompt 模板时,话历史的长度是动态的,不可能写死:

  • 第1轮:0条历史

  • 第10轮:10条历史

这时候需要 MessagesPlaceholder 占位符,在运行时动态插入历史消息。

显式使用 MessagesPlaceholder

from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
​
# 构建模板,占位符用于插入对话历史
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个资深的Python开发工程师,请认真回答我提出的Python相关的问题"),
    MessagesPlaceholder("memory"),  # 动态插入对话历史
    ("human", "{question}")
])
​
# 调用时传入历史消息
prompt_value = prompt.invoke({
    "memory": [
        HumanMessage(content="我的名字叫亮仔,是一名程序员"),
        AIMessage(content="好的,亮仔你好,很高兴认识你"),
    ],
    "question": "Python的装饰器是什么?"
})

隐式使用占位符

# 隐式写法:("placeholder", "{memory}") 等价于 MessagesPlaceholder("memory")
prompt = ChatPromptTemplate.from_messages([
    ("placeholder", "{memory}"),
    ("system", "你是一个资深的Python开发工程师"),
    ("human", "{question}")
])
​
prompt_value = prompt.invoke({
    "memory": [
        HumanMessage(content="我的名字叫亮仔"),
        AIMessage(content="好的,亮仔你好"),
    ],
    "question": "装饰器是什么?"
})

两种写法对比

# 显式(更清晰,推荐)
MessagesPlaceholder("memory")
​
# 隐式(更简洁)
("placeholder", "{memory}")

对话记忆机制

什么是记忆机制?

记忆机制是 AI 应用记住之前对话内容的能力。常见实现方式:

类型 说明 适用场景
ConversationBufferMemory 完整保存所有历史 对话短、上下文重要
ConversationTokenBufferMemory 按Token数限制 对话长、需要控制成本
ConversationSummaryMemory 自动总结历史 超长对话
VectorStoreRetrieverMemory 向量检索记忆 超长对话、语义检索

ConversationBufferMemory

最简单的记忆方式,保存完整对话历史:

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
​
# 创建记忆对象
memory = ConversationBufferMemory()
​
# 添加对话历史
memory.save_context({"input": "我叫小明"}, {"output": "你好小明!"})
memory.save_context({"input": "我最喜欢的颜色是蓝色"}, {"output": "蓝色是很棒的选择!"})
​
# 加载历史
history = memory.load_memory_variables({})
print(history)
# {'history': 'Human: 我叫小明\nAI: 你好小明!\nHuman: 我最喜欢的颜色是蓝色\nAI: 蓝色是很棒的选择!'}

结合 LangChain 链使用

from langchain.chat_models import init_chat_model
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
from langchain.prompts import PromptTemplate
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 创建记忆链
memory = ConversationBufferMemory()

# 自定义Prompt
template = """你是一个友好的AI助手。
历史对话:
{history}

用户新消息:{input}
你的回复:"""

prompt = PromptTemplate(
    template=template,
    input_variables=["history", "input"]
)

# 创建对话链
chain = ConversationChain(
    llm=model,
    memory=memory,
    prompt=prompt,
    verbose=True
)

# 对话
response = chain.invoke({"input": "我叫小明"})
print(response)

response = chain.invoke({"input": "我叫什么名字?"})
print(response)  # 会记住叫小明

多轮对话实战

基础版本:手动管理历史

from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 构建带记忆的模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个旅游助手,为用户提供旅行建议"),
    MessagesPlaceholder("history"),
    ("human", "{question}")
])

def chat(question, history):
    """对话函数"""
    messages = prompt.format_messages(history=history, question=question)
    response = model.invoke(messages)

    # 更新历史
    history.append(HumanMessage(content=question))
    history.append(AIMessage(content=response.content))

    return response.content, history

# 开始对话
history = []

print("=== 第1轮 ===")
answer1, history = chat("推荐几个国内旅游城市", history)
print(f"AI: {answer1}")

print("\n=== 第2轮 ===")
answer2, history = chat("北京有什么好吃的?", history)
print(f"AI: {answer2}")

print("\n=== 第3轮 ===")
answer3, history = chat("那上海呢?", history)  # "那上海呢"需要结合上文理解
print(f"AI: {answer3}")

进阶版本:支持上下文理解

from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 改进的系统提示词,让AI更好地理解上下文
prompt = ChatPromptTemplate.from_messages([
    ("system", """你是一个专业的旅游顾问。
请根据对话历史,理解用户的上下文。
如果用户用"那...呢"、"还有呢"等指代词,要结合之前的对话来理解。
例如:
- 问"北京之后上海呢?" 要理解这是在问上海的旅游推荐"""),
    MessagesPlaceholder("history"),
    ("human", "{question}")
])

def chat(question, history):
    messages = prompt.format_messages(history=history, question=question)
    response = model.invoke(messages)

    history.append(HumanMessage(content=question))
    history.append(AIMessage(content=response.content))

    return response.content, history

# 对话测试
history = []
answer1, history = chat("北京有什么景点?", history)
print(f"AI: {answer1}")

answer2, history = chat("那上海呢?", history)
print(f"AI: {answer2}")  # 应该理解是在问上海的景点

生产版本:带用户信息记忆

from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 构建带用户信息的模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个私人旅行助手。用户信息:{user_info}"),
    MessagesPlaceholder("history"),
    ("human", "{question}")
])

class TravelChat:
    def __init__(self):
        self.history = []
        self.user_info = {
            "name": "小明",
            "preferences": "喜欢美食和自然风光",
            "budget": "中等预算",
            "travel_style": "自由行"
        }

    def chat(self, question):
        messages = prompt.format_messages(
            user_info=self.user_info,
            history=self.history,
            question=question
        )
        response = model.invoke(messages)

        self.history.append(HumanMessage(content=question))
        self.history.append(AIMessage(content=response.content))

        return response.content

    def reset(self):
        """重置对话历史"""
        self.history = []

# 使用
chat = TravelChat()

print("=== 对话1 ===")
print(chat.chat("我叫小明,喜欢吃辣,帮我推荐一个旅游城市"))

print("\n=== 对话2 ===")
print(chat.chat("那里有什么好吃的辣味美食?"))

进阶用法

Token数限制(控制成本)

对话历史太长会导致 Token 消耗过大,需要限制:

from langchain.memory import ConversationTokenBufferMemory
from langchain.chat_models import init_chat_model
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 限制最大Token数为2000
memory = ConversationTokenBufferMemory(
    llm=model,
    max_token_limit=2000
)

# 添加大量对话
for i in range(20):
    memory.save_context({"input": f"这是第{i}轮对话"}, {"output": f"这是第{i}轮回复"})

# 自动截断旧的历史
history = memory.load_memory_variables({})
print(f"历史长度: {len(history['history'])}")
# 会自动保留最新的对话,删除旧的

自动总结历史(超长对话)

from langchain.memory import ConversationSummaryMemory
from langchain.chat_models import init_chat_model
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

model = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 自动总结历史
memory = ConversationSummaryMemory(llm=model)

# 添加对话
memory.save_context({"input": "我叫小明,是一名程序员"}, {"output": "你好小明!"})
memory.save_context({"input": "我工作5年了"}, {"output": "经验丰富啊!"})
memory.save_context({"input": "我会Python、Java、Go"}, {"output": "技术栈很广!"})

# 获取总结后的历史
history = memory.load_memory_variables({})
print(history['history'])
# 会自动总结为一段话,而不是保留所有对话

向量记忆(语义检索)

from langchain.memory import VectorStoreRetrieverMemory
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.chat_models import init_chat_model
import os
from dotenv import load_dotenv

load_dotenv(encoding='utf-8')

# 创建向量存储
vectorstore = Chroma(embedding_function=OpenAIEmbeddings())
memory = VectorStoreRetrieverMemory(
    vectorstore=vectorstore,
    search_kwargs={"k": 3}  # 返回最相关的3条记忆
)

# 保存记忆(带描述)
memory.save_context(
    {"input": "用户喜欢日料"},
    {"output": "已记录用户的日料偏好"}
)
memory.save_context(
    {"input": "用户下周要去东京"},
    {"output": "已记录用户的东京行程"}
)

# 检索相关记忆
memory.load_memory_variables({"prompt": "用户有什么美食偏好?"})
# 会语义检索返回"喜欢日料"相关记忆

常见问题

1. 对话历史越来越长怎么办?

# 方法1:限制Token数
from langchain.memory import ConversationTokenBufferMemory
memory = ConversationTokenBufferMemory(llm=model, max_token_limit=2000)

# 方法2:自动总结
from langchain.memory import ConversationSummaryMemory
memory = ConversationSummaryMemory(llm=model)

# 方法3:只保留最近N轮
def limit_history(history, max_turns=5):
    return history[-max_turns * 2:]  # 每轮2条消息(问+答)

2. 如何让AI记住用户信息?

# 方法1:放在系统提示词里
prompt = ChatPromptTemplate.from_messages([
    ("system", "用户叫{name},喜欢{preference}"),
    MessagesPlaceholder("history"),
    ("human", "{question}")
])

# 方法2:每次传入用户信息
messages = prompt.format_messages(
    user_info=user_info,
    history=history,
    question=question
)

3. 如何让AI理解指代词?

# 改进系统提示词
system_prompt = """你是一个专业的AI助手。
请注意理解对话中的指代词:
- "那...呢" 通常指代之前提到的事物
- "他/她/它" 指代之前提到的人或物
- "然后呢" 通常继续之前的话题
结合上下文理解用户真实意图。"""

4. 如何持久化对话历史?

import json

# 保存到文件
def save_history(history, filename="history.json"):
    with open(filename, "w", encoding="utf-8") as f:
        json.dump([msg.to_json() for msg in history], f, ensure_ascii=False)

# 从文件加载
def load_history(filename="history.json"):
    with open(filename, "r", encoding="utf-8") as f:
        data = json.load(f)
    return [HumanMessage(**m) if m["type"]=="human" else AIMessage(**m) for m in data]

总结

多轮对话核心概念

概念 作用 代码
对话历史 记住之前的问答 history.append(HumanMessage(...))
MessagesPlaceholder 动态插入历史到模板 MessagesPlaceholder("memory")
ConversationBufferMemory 完整保存历史 memory.load_memory_variables({})
ConversationTokenBufferMemory 限制Token数 max_token_limit=2000
ConversationSummaryMemory 自动总结历史 memory.load_memory_variables({})

选择记忆类型

对话长度短 → ConversationBufferMemory(最简单)
对话长度中等 → ConversationTokenBufferMemory(控制成本)
对话长度长 → ConversationSummaryMemory(自动总结)
对话长度超长 → VectorStoreRetrieverMemory(向量检索)

多轮对话模板

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
​
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个AI助手"),
    MessagesPlaceholder("history"),  # 对话历史
    ("human", "{question}")
])
​
def chat(question, history):
    messages = prompt.format_messages(history=history, question=question)
    response = model.invoke(messages)
    history.append(HumanMessage(content=question))
    history.append(AIMessage(content=response.content))
    return response.content, history
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐