摘要:本文介绍如何在 LangChain 智能代理中通过
after_model注解与RemoveMessage函数自动清理对话历史。核心思路是:在每次模型响应后检查消息总数,若超过阈值则删除最早的消息,从而将上下文控制在可控范围内。文中提供了完整的 Python 示例代码,演示了从环境配置、代理创建到多轮对话验证的完整流程。
内容参考于:图灵AI大模型全栈
模型输出后是通过 after_model 注解来实现,如下图红框
删除消息是通过 RemoveMessage 函数来实现,它是通过消息的id来删除,下图红框是通过for循环得到所有消息的id,然后调用 RemoveMessage 删除所有的消息
代码
fromlangchain.messagesimportRemoveMessagefromlangchain.agentsimportcreate_agent,AgentStatefromlangchain.agents.middlewareimportafter_modelfromlanggraph.checkpoint.memoryimportInMemorySaverfromlanggraph.runtimeimportRuntimefromlangchain_core.runnablesimportRunnableConfigfromlangchain_qwqimportChatQwenfromdotenvimportload_dotenvimportos# 加载环境变量load_dotenv()# 初始化模型llm=ChatQwen(model="qwen3.6-plus",api_key=os.getenv("DASHSCOPE_API_KEY"),base_url=os.getenv("DASHSCOPE_BASE_URL"))# 通过 after_model 注解设置模型输出后执行 delete_old_messages 函数@after_modeldefdelete_old_messages(state:AgentState,runtime:Runtime)->dict|None:""" 删除旧消息以保持对话上下文在可控范围内。 工作原理: 1. 每次模型响应后,检查消息总数 2. 如果超过阈值(2条),删除最早的消息 3. 使用 RemoveMessage 标记删除,LangGraph 会自动处理 参数: state: 当前代理状态,包含所有消息历史 runtime: 运行时上下文,提供额外配置信息 返回: dict | None: 包含要删除的消息列表,或 None(不执行删除) """# 从状态中获取所有消息messages=state["messages"]# 检查消息数量是否超过限制(保留最近2条)iflen(messages)>2:print("----------------------开始删除部分消息---------------------------")# 获取要删除的消息(最早的2条)messages_to_remove=messages[:2]# 创建删除标记列表 10 通过循环删除前8条# RemoveMessage 是一个特殊对象,告诉 LangGraph 要删除哪些消息removal_markers=[RemoveMessage(id=msg.id)formsginmessages_to_remove]# 返回字典,LangGraph 会自动处理删除操作return{"messages":removal_markers}# 如果消息数量未超限,不做任何操作returnNone# ==================== 创建智能代理 ====================# 配置代理agent=create_agent(# 使用的语言模型(此处为示例模型名)model=llm,# 工具列表(示例为空,实际可添加搜索、计算等工具)tools=[],# 系统提示词:定义代理的基本行为准则system_prompt="请保持回答简洁明了,直击要点。",# 注册中间件列表# delete_old_messages 会在每次模型响应后自动执行middleware=[delete_old_messages],# 检查点保存器:用于保存和恢复对话状态# InMemorySaver 在内存中存储,适合开发和测试checkpointer=InMemorySaver(),)# ==================== 配置对话会话 ====================# 配置对象:设置当前对话线程ID# 相同的 thread_id 可以恢复之前的对话历史config:RunnableConfig={"configurable":{"thread_id":"1"# 线程ID,用于标识不同的对话会话}}# ==================== 第一轮对话 ====================print("="*50)print("第一轮对话:自我介绍")print("="*50)stream=agent.stream_events(# 用户输入消息{"messages":[{"role":"user","content":"你好!我叫计算机王"}]},config,version="v3",# 使用 v3 版本的流式事件协议)# 遍历流式响应,打印当前状态快照forsnapshotinstream.values:# 提取并显示消息列表(类型 + 内容)messages_info=[(msg.type,msg.content)formsginsnapshot["messages"]]print(f"当前消息历史 ({len(snapshot['messages'])}条):")formsg_type,contentinmessages_info:print(f" [{msg_type}]:{content[:50]}...")# 截断显示print("-"*30)# ==================== 第二轮对话 ====================print("\n"+"="*50)print("第二轮对话:请求创作内容")print("="*50)stream=agent.stream_events({"messages":[{"role":"user","content":"请写一首关于猫咪的短诗"}]},config,version="v3",)forsnapshotinstream.values:messages_info=[(msg.type,msg.content)formsginsnapshot["messages"]]print(f"当前消息历史 ({len(snapshot['messages'])}条):")formsg_type,contentinmessages_info:print(f" [{msg_type}]:{content[:50]}...")print("-"*30)# ==================== 第三轮对话 ====================print("\n"+"="*50)print("第三轮对话:询问个人信息")print("="*50)stream=agent.stream_events({"messages":[{"role":"user","content":"我叫什么名字?"}]},config,version="v3",)forsnapshotinstream.values:messages_info=[(msg.type,msg.content)formsginsnapshot["messages"]]print(f"当前消息历史 ({len(snapshot['messages'])}条):")formsg_type,contentinmessages_info:print(f" [{msg_type}]:{content[:50]}...")print("-"*30)