from langchain_community.chat_message_histories import SQLChatMessageHistory from langchain_core.chat_history import InMemoryChatMessageHistory from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.runnables import RunnableWithMessageHistory, RunnablePassthrough from langchain_openai import ChatOpenAI from env_util import DASHSCOPE_API_KEY, DASHSCOPE_BASE_URL # 0、llm~~ llm = ChatOpenAI( model = "qwen-plus", base_url=DASHSCOPE_BASE_URL, api_key=DASHSCOPE_API_KEY, temperature=0.8, ); # =============================================================================================== # 1、定义专门做聊天的提示词模板 prompt = ChatPromptTemplate.from_messages([ ('system', '你是一个乐于助人的助手。尽你所能回答所有问题。提供的聊天历史包含与你对话用户的相关信息。'), # 系统提示词 MessagesPlaceholder(variable_name='chat_history', optional=True), #消息占位符 ('human', '{input}') #用户提示词,input用户传的问题 ]) chain = prompt | llm; # =============================================================================================== # 2、存储聊天记录: 存的谁?存的第10行的内容(存到哪里?内存、关系型数据库或者redis数据库) store = {} def get_session_history(session_id: str): """从关系型数据库的历史消息列表中 返回当前会话 的所有历史消息""" # SQLChatMessageHistory是langchain提供的 return SQLChatMessageHistory( session_id=session_id, # 这里url换为自己的数据库即可 connection_string='sqlite:///chat_history.db', ) # =============================================================================================== # 3、创建带历史记录功能的处理链,帮我自动存储历史记录 chain_with_message_history = RunnableWithMessageHistory( chain, # 基础执行链 get_session_history, # 指定工厂函数,返回指定session_id的聊天记录 input_messages_key='input', # 指定用户输入的消息的key history_messages_key='chat_history', # 历史消息记录的key ) # =============================================================================================== #4、剪辑和摘要历史上下文消息 # 比如:保留最近的前2条消息(随意指定条数),把之前的所有消息形成摘要 # 定义summarize_messages函数,把当前用户的这次输入传进来 def summarize_messages(current_input): """剪辑和摘要上下午,历史记录""" # 从current_input取出session_id session_id = current_input['config']["configurable"]["session_id"] if not session_id: raise ValueError("必须通过config参数提供session_id") # 获取当前会话ID的所有历史聊天记录 chat_history = get_session_history(session_id) # 从历史聊天记录取出message这个聊天列表(是个数组,里面是一条一条消息,包括AiMessage,toolmessage,humanmessage,systemmessage。。) stored_messages = chat_history.messages # 如果stored_messages长度太短,只有两条以内聊天记录,不需要摘要 if len(stored_messages) <= 2: # 保留最近2条消息的阈值 return False # 超过2条再剪辑 # 剪辑消息列表 last_two_messages = stored_messages[-2:] # 保留的最后2条消息 messages_to_summarize = stored_messages[:-2] # 需要进行摘要的消息列表(最后2条之前的记录) # 构建摘要:就是让大模型去帮你构建摘要,帮你做这件事情,在这里需要再调用大模型 # 所以先构建提示词模版 summarization_prompt = ChatPromptTemplate.from_messages([ ("system", "请将以下对话历史压缩为一条保留关键信息的摘要消息。"), ("placeholder", "{chat_history}"), ("human", "请生成包含上述对话核心内容的摘要,保留重要事实和决策。") ]) # 组成链调用大模型 summarization_chain = summarization_prompt | llm # 大模型会帮你生成摘要(AIMessage) ——》需要生成摘要的是messages_to_summarize,last_two_messages不需要生成摘要 summary_message = summarization_chain.invoke({'chat_history': messages_to_summarize}) # 重建历史记录:清空历史聊天记录 + 添加摘要 + 最后2条原始消息 chat_history.clear() chat_history.add_message(summary_message) for msg in last_two_messages: chat_history.add_message(msg) return True # 最终的链 (需要LCEL完成) # RunnablePassthrough 默认会将输入数据原样传递到下游,通过管道传给下一个组件chain_with_message_history # 同时.assign() 方法允许在保留原始输入的同时,通过指定键值对(如 messages_summarized=summarize_messages)向输入字典中添加新字段 final_chain = (RunnablePassthrough.assign(messages_summarized=summarize_messages) | chain_with_message_history) # =============================================================================================== #5、 测试 result1 = final_chain.invoke({'input': '你好,我是郑金维!', "config": {"configurable": {"session_id": "user123"}}}, config={"configurable": {"session_id": "user123"}}) print(result1) result2 = final_chain.invoke({'input': '我的名字叫什么?', "config": {"configurable": {"session_id": "user123"}}}, config={"configurable": {"session_id": "user123"}}) print(result2) result3 = final_chain.invoke({'input': '历史上,和我同名的人有哪些?', "config": {"configurable": {"session_id": "user123"}}}, config={"configurable": {"session_id": "user123"}}) print(result3)