LangChain 的多轮对话,本质不是“模型记住了历史”,而是 Runnable 在每次调用前,把历史消息重新拼进 Prompt,再把新结果写回存储。
这一篇将基于一个完整的多轮对话流程,从零梳理:
多轮对话通常至少要满足:
下面我们用完整代码 + 调用流程,学习 LangChain 的多轮对话机制
python用户输入 ↓ RunnableWithMessageHistory ↓ get_session_history(user_id, conversation_id) ↓ ChatMessageHistory / PostgresChatMessageHistory ↓ Prompt + LLM ↓ 模型输出(并写回历史)
这里以通义千问 ChatTongyi 为例,开启流式 + 思考模式:
pythonfrom langchain_community.chat_models import ChatTongyi
from pydantic import SecretStr
llm = ChatTongyi(
model="qwen3-plush
api_key=SecretStr("sk-xxx"),
streaming=True, # 思考模式必须启用流式输出
model_kwargs={
"enable_thinking": True, # 开启思考模式
"incremental_output": True
}
)
参数说明:
使用 ChatPromptTemplate.from_messages 创建多轮对话模板
pythonfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"你是一个擅长写作的智能聊天助手",
),
MessagesPlaceholder(variable_name="history"), # 历史记录占位符,实现多轮对话关键的一行
("human", "{input}"), # 最新用户输入占位符
]
)
参数说明:
通过 | 操作符可以将 Prompt 输出作为 LLM 输入
pythonrunnable = prompt | llm
pythonimport psycopg
sync_conn = psycopg.connect(
"postgresql://user:password@host:5432/db"
)
pythonfrom langchain_postgres import PostgresChatMessageHistory
PostgresChatMessageHistory.create_tables(
sync_conn,
"message_store"
)
说明:
pythonimport uuid
def get_session_history(user_id: str, conversation_id: str):
# 会话的唯一标识
session_id = str(uuid.uuid5(uuid.NAMESPACE_DNS, f"{user_id}_{conversation_id}"))
return PostgresChatMessageHistory(
"message_store", # table_name
session_id, # session_id
sync_connection=sync_conn
)
这里完成了三件非常重要的事:
pythonfrom langchain_core.runnables import ConfigurableFieldSpec, RunnableWithMessageHistory
with_message_history = RunnableWithMessageHistory(
runnable, # type: ignore
get_session_history,
input_messages_key="input", # 最新输入的 key
history_messages_key="history", # 历史消息的 key
history_factory_config=[
ConfigurableFieldSpec(
id="user_id", # 对应工厂函数参数名
annotation=str,
name="用户 ID",
description="用户的唯一标识符。",
default="",
is_shared=True,
),
ConfigurableFieldSpec(
id="conversation_id", # 对应工厂函数参数名
annotation=str,
name="对话 ID",
description="对话的唯一标识符。",
default="",
is_shared=True,
),
],
)
参数说明:
它在每一次 invoke 时,固定做 4 件事:
python# 第一次调用
result = with_message_history.invoke(
{"input": "你好"},
config={"configurable": {"user_id": "123", "conversation_id": "1"}},
)
print(result)
# 第二次调用(自动带上历史)
result2 = with_message_history.invoke(
{"input": "我刚才说了什么"},
config={"configurable": {"user_id": "123", "conversation_id": "1"}},
)
print(result2)
本文作者:鑫 · Dev
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!