ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【AI大模型】Langchain 多类型对话消息使用实战操作详解

【AI大模型】Langchain 多类型对话消息使用实战操作详解 目录一、前言二、Langchain 多类型消息使用2.1 Langchain 消息说明2.2 Langchain 消息内部结构2.3 LangChain 消息类型2.3.1 系统消息2.3.2 用户消息2.3.3 助手(AI)消息2.3.4 工具调用消息2.4 消息格式2.4.1 格式1JSON格式2.4.2 格式2对象格式2.4 消息对象字段说明2.4.1 SystemMessage 参数列表2.4.2 HumanMessage 参数列表2.4.3 AIMessage 参数列表2.4.4 ToolMessage 参数列表2.5 对话历史管理2.5.1 会话记忆介绍2.5.2 对话历史优化三、Langchain 消息扩展3.1 content 使用四、写在最后一、前言在使用Langchain 与大模型进行对话过程中涉及到不同类型的消息这些不同类型消息的组合使用从而完成多轮复杂的对话任务本文将通过实际案例详细介绍在Langchain 中多种类型的消息使用。二、Langchain 多类型消息使用2.1 Langchain 消息说明大模型没有记忆它的输出只和输入模型的内容有关上下文。很多大模型API服务也没有在服务端维护会话历史是“ 无状态 ”的。因此如果应用需要“记住”对话历史需要在程序中维护消息列表。在 LangChain 中Message消息是模型交互的最基本单元。它既代表模型接收到的 输入Input 也代表模型生成的 输出Output 。每一轮与大模型的对话都由一条或多条 Message 构成。每个 Message 不仅包含 文字内容 还携带描述上下文状态的 元信息metadata 用于保持对话的一致性和可追踪性。比如模型在多轮交互中理解“谁在说话”、“说了什么”、“这条信息属于哪一轮对话”。LangChain 在 1.0 中提供了跨模型统一的 Message 标准。无论你使用的是 OpenAI、Anthropic、Gemini 还是本地模型这一标准都能保持一致的行为。这样的好处是兼容性强 不同模型的消息格式自动对齐。可扩展性高 方便添加多模态内容或自定义字段。可追踪性好 为 LangSmith 等调试工具提供一致的上下文数据结构。2.2 Langchain 消息内部结构LangChain的消息Message对象包含三种字段Role消息所属的角色或类型如 system 、 user 、 assistant 。Content消息内容Metadata可选元数据存储额外信息。如消息ID、响应时间、token消耗量、消息标签等2.3 LangChain 消息类型LangChain定义了很多消息类型通过 role 进行区分常用的有四种。2.3.1 系统消息也称为系统提示词用于在对话开始时为模型设定角色、行为准则和上下文背景。它像是给AI助手的一份工作说明书决定了其回答问题的风格、领域和专业范围。{role: system, content: 你是个精通编程的软件架构师}2.3.2 用户消息也称为用户提示词在多轮对话中它表示用户的一次输入。可以包含简单的文本问题也可以是复杂的多模态内容如图片、音频、文档等。{role: user, content: 你好啊~}2.3.3助手(AI)消息代表模型的回复包括生成的文本、工具调用、元数据等{role: assistant, content: 我也很高兴认识你}或者下面这样{ role: assistant, content: , tool_calls: [{ name: get_weather, args: {location: 北京}, id: call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s }] }2.3.4工具调用消息工具调用结果匹配的消息类型。将此消息返回给模型让模型基于这个结果继续生成回复。在后面分享Tools的时候 详细介绍。{role: tool, content: 今天天气很好, tool_call_id: call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s}问题为什么使用不同的消息类型明确角色 清晰区分系统提示、用户输入和 AI 回复控制行为 通过 SystemMessage 精确控制 AI 的行为对话历史 构建完整的多轮对话上下文调试友好 更容易追踪和调试对话流程2.4 消息格式在具体调用大模型API传递消息的时候不同消息类型传递的格式也不一样LangChain支持两种消息格式。2.4.1 格式1JSON格式系统消息{role: system, content: 你是个善解人意的助手}用户消息{role: user, content: 你好啊~}助手消息{role: assistant, content: 我也很高兴认识你}工具调用消息{role: tool, content: 工具输出, tool_call_id: call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s}如下是Json格式消息调用的完整示例from langchain.chat_models import init_chat_model from dotenv import load_dotenv import os # 1、读取.env配置文件中的信息。相关的环境变量以.env文件中的优先 load_dotenv(overrideTrue) DEEPSEEK_API_KEY os.getenv(DEEPSEEK_API_KEY) DEEPSEEK_BASE_URL os.getenv(DEEPSEEK_BASE_URL) # 2、模型初始化 llm_model init_chat_model( modeldeepseek-v4-pro, api_keyDEEPSEEK_API_KEY, base_urlDEEPSEEK_BASE_URL, ) # 通过JSON初始化 messages [ {role: system, content: 你是一个善于给出通俗易懂解释的AI助手}, {role: user, content: 你好}, {role: assistant, content: 你好我能帮你什么}, {role: user, content: 什么是机器学习} ] response llm_model.invoke(messages) print(response.content)2.4.2 格式2对象格式在一些大型的项目中对象格式是一种比较常见的针对不同的角色也不相同系统消息SystemMessage(content你是个善解人意的助手)用户消息HumanMessage(content你好啊~)助手消息AIMessage(我也很高兴认识你)工具调用消息ToolMessage( content工具输出, tool_call_idcall_00_nUD2NC9QRN5Cg1GaoIkBJQ4s # 一定要和AI消息中的调用ID匹配 )比如下面的示例# 消息列表示例 messages [ SystemMessage(content你是一个助手), HumanMessage(content你好), AIMessage(content你好有什么可以帮你), HumanMessage(content天气怎么样), AIMessage(content让我查询一下...), ToolMessage(content北京晴天, tool_call_idcall_123), AIMessage(content北京今天是晴天) ]下面是对象格式消息调用的完整示例from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage,HumanMessage,AIMessage from dotenv import load_dotenv import os # 1、读取.env配置文件中的信息。相关的环境变量以.env文件中的优先 load_dotenv(overrideTrue) DEEPSEEK_API_KEY os.getenv(DEEPSEEK_API_KEY) DEEPSEEK_BASE_URL os.getenv(DEEPSEEK_BASE_URL) # 2、模型初始化 llm_model init_chat_model( modeldeepseek-v4-pro, api_keyDEEPSEEK_API_KEY, base_urlDEEPSEEK_BASE_URL, ) # 通过JSON初始化 messages [ SystemMessage(你是一个善于给出通俗易懂解释的AI助手), HumanMessage(你好), AIMessage(你好我能帮你什么), HumanMessage(什么是机器学习), ] response llm_model.invoke(messages) print(response.content)小结角色字典格式对象格式用途示例System{role: system, ...}SystemMessage(...)设定 AI 的行 为、角色、规 则你是一个专业的 数学老师User{role: user, ...}HumanMessage(...)用户输入什么是微积分Assistant{role: assistant,...}AIMessage(...)AI 的回复微积分是研究变 化率的数学分支...Tool{role: tool,...}ToolMessage(...)工具执行的结果今天北京天气晴朗万里无云2.4消息对象字段说明接下来对消息对象中的常用字段做深入的说明此处仅说明常用字段完整字段列表可以通过查阅官方手册或阅读源码。2.4.1SystemMessage 参数列表content 消息内容字段名可以省略SystemMessage(你是个善解人意的助手)等同于SystemMessage(content 你是个善解人意的助手)2.4.2HumanMessage 参数列表content 消息内容字段名可以省略HumanMessage(你好啊~)相当于HumanMessage(content 你好啊~)metadata 元数据字段可以有很多自定义举例带有元数据字段HumanMessage( contentHello!, namealice, # 可选用户名 idmsg_123, # 可选message的ID )name 和 id 都属于元数据字段当消息类型相同对消息进行区分。但不是所有模型都支持这一功能是否支持取决于模型供应商需要查看官方手册。比如OpenAI的API手册告诉我们HumanMessage支持 name 作为元数据字段如下图所示。而 DeepSeek的API官方文档明确支持 name 作为元数据但实测发现模型无法识别。如下是使用OpenRouter进行调用的示例代码from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage, AIMessage from dotenv import load_dotenv import os from langchain_openrouter import ChatOpenRouter # 加载配置文件 load_dotenv(overrideTrue) OPENROUTER_API_KEY os.getenv(OPENROUTER_API_KEY) OPENROUTER_API_BASE os.getenv(OPENROUTER_API_BASE) # 2、模型初始化 model ChatOpenRouter( modeldeepseek/deepseek-v3.2, api_keyOPENROUTER_API_KEY, base_urlOPENROUTER_API_BASE, ) messages [ SystemMessage( 你是一个信息抽取器。你会收到多条来自不同发言者的 user 消息。每条消息可能带有 name 字段。你的任务是严格根据每条消息的 name 提取发言者及其观点并输出JSON。 禁止使用“第一个人/第二个人”这种相对称呼。若某条消息没有 name则输出 unknown。输出格式{\speakers\:[{\name\:\...\,\claim\:\...\}]} ), HumanMessage( content我认为 112, nameBob ), HumanMessage( content我认为 112, nameTom ), HumanMessage( content请列出谁说了什么不要判断对错。, nameaudience ) ] response model.invoke(messages) print(response.content)通过执行结果可以看到name 输出为unknown说明OpenRouter不支持2.4.3AIMessage 参数列表content 模型输出的原始内容字段名可以省略AIMessage(你好~)相当于AIMessage(content你好~)response_metadata AIMessage特有属性LLM的响应中附加元数据根据不同模型会有不同如可能会包含本次token使用量等信息。tool_calls AIMessage特有属性表示工具调用信息。当LLM决定调用工具时在AIMessage 中就会包含这个属性没有工具调用则为空。tool_calls属性是一个ToolCall 列表每个ToolCall 是一个字典包含字段见上。结构如下tool_calls[ { name: get_weather, // 应调用的工具名 args: {city: 杭州}, // 调用工具的参数 id: call_00_gIXYOD1Q1OkEXmdDBqXR1578, // 工具调用的唯一标识ID type: tool_call }, { name: get_news, args: {}, id: call_01_jD3phD5PEaIZf0mVLhKt0861, type: tool_call } ]比如下面的代码中展示了如何在AIMessage 中调用工具AIMessage( content, tool_calls[{ name: get_weather, args: {city: 北京}, id: call_xxx }] )下面是一个完整的调用案例from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage, AIMessage from dotenv import load_dotenv import os from langchain_openrouter import ChatOpenRouter # 加载配置文件from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage, AIMessage from dotenv import load_dotenv import os from langchain_openrouter import ChatOpenRouter # 加载配置文件 load_dotenv(overrideTrue) OPENROUTER_API_KEY os.getenv(OPENROUTER_API_KEY) OPENROUTER_API_BASE os.getenv(OPENROUTER_API_BASE) # 2、模型初始化 model ChatOpenRouter( modeldeepseek/deepseek-v3.2, api_keyOPENROUTER_API_KEY, base_urlOPENROUTER_API_BASE, ) messages [ SystemMessage(你叫小智是一名助人为乐的助手。), HumanMessage(你好好久不见请介绍下你自己。) ] response model.invoke(messages) print(response) load_dotenv(overrideTrue) OPENROUTER_API_KEY os.getenv(OPENROUTER_API_KEY) OPENROUTER_API_BASE os.getenv(OPENROUTER_API_BASE) # 2、模型初始化 model ChatOpenRouter( modeldeepseek/deepseek-v3.2, api_keyOPENROUTER_API_KEY, base_urlOPENROUTER_API_BASE, ) messages [ SystemMessage(你叫小智是一名助人为乐的助手。), HumanMessage(你好好久不见请介绍下你自己。) ] response model.invoke(messages) print(response)响应结果如下usage_metadata 模型调用时用量信息AIMessage( content你好呀很高兴再次与你相遇✨\n\n我是小智一个由深度求索公司创造 的AI助手。我的核心使命就是尽我所能为你提供帮助——无论是回答问题、协助思考、解决 实际问题还是陪你聊聊天放松心情我都会用热情和专业来回应你。\n\n简单来说\n **知识范围**涵盖科学、技术、人文、生活等广泛领域但知识截止于2024年7月\n **能力特点**支持长文本处理、文件上传可读取图像/文本/PDF等格式内容、联网搜 索需要你手动开启\n **风格**倾向于细致、耐心且带一点温暖感的交流方式\n **初心**不做价值判断尊重你的视角专注提供实用信息\n\n距离上次聊天可能已经 有一段时间了如果你有任何新的问题或想聊的话题我随时在这里等你开口~ , additional_kwargs{}, response_metadata{ model_name: deepseek/deepseek-v3.2, id: gen-1789000800-SbvYOpJwOKLlQnCAMuxH, created: 1789000800, object: chat.completion, finish_reason: stop, logprobs: None, model_provider: openrouter, cost: 7.794e-05, cost_details: { upstream_inference_completions_cost: 7.144e-05, upstream_inference_prompt_cost: 6.5e-06, upstream_inference_cost: 7.794e-05 } }, idlc_run--01a088c1-d432-7212-8caf-169810195498-0, tool_calls[], invalid_tool_calls[], usage_metadata{ input_tokens: 25, output_tokens: 188, total_tokens: 213, input_token_details: {cache_read: 0, cache_creation: 0}, output_token_details: {reasoning: 0} } )2.4.4ToolMessage 参数列表核心参数content 文件内容name 工具名称tool_call_id 工具调用唯一IDToolMessage必须紧邻匹配的AIMessage和前者tool_calls中的id一致参数消息结构如下ToolMessage( content工具输出, nameget_weather, tool_call_idcall_00_nUD2NC9QRN5Cg1GaoIkBJQ4s )看下面完整示例from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage, AIMessage from dotenv import load_dotenv import os from langchain_openrouter import ChatOpenRouter # 加载配置文件 load_dotenv(overrideTrue) OPENROUTER_API_KEY os.getenv(OPENROUTER_API_KEY) OPENROUTER_API_BASE os.getenv(OPENROUTER_API_BASE) # 2、模型初始化 model ChatOpenRouter( modeldeepseek/deepseek-v3.2, api_keyOPENROUTER_API_KEY, base_urlOPENROUTER_API_BASE, ) def get_weather(city: str) - str: return 天气很好 # 模拟模型绑定工具 model_with_tools model.bind_tools([get_weather]) ai_message { role: assistant, content: , tool_calls: [{ name: get_weather, args: {location: 北京}, id: call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s }] } tool_message { role: tool, content: 今天北京天气晴朗万里无云~, tool_call_id: call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s } messages [ {role: user, content: 北京天气如何}, ai_message, tool_message ] response model.invoke(messages) from rich import print as rprint rprint(response)2.5 对话历史管理2.5.1 会话记忆介绍在学习大模型对话的时候应该还有印象大模型是没有记忆的如果不做记忆管理下一轮对话时大模型就不记得上一轮对话内容了解决这个会话记忆一种最简单的方式就是每次调用必须传递完整的对话历史比如下面这样第 1 轮 [system, user] → AI回复 → 保存回复 第 2 轮 [system, user, assistant, user] → AI回复 → 保存回复 第 3 轮 [system, user, assistant, user, assistant, user] → AI回复注意这种方式下每次对话都要在原有的消息列表中添加新消息 不可重新创建新的列表。下面是几个错误的示例# 第一次 response1 model.invoke(我叫张三) # 第二次没传历史 response2 model.invoke(我叫什么) # AI 不记得conversation [{role: user, content: 问题1}] response1 model.invoke(conversation) conversation [{role: user, content: 问题2}] # 重新创建 response2 model.invoke(conversation) # 丢失了历史conversation [] conversation.append({role: user, content: 问题1}) response1 model.invoke(conversation) # 忘记保存 response1.content conversation.append({role: user, content: 问题2}) response2 model.invoke(conversation) # AI 不知道之前的回答2.5.2 对话历史优化如果使用上面的方式对话历史会越来越长不可避免的会消耗大量 tokens 增加成本。解决方案只保留最近 N 轮对话具体来说总是保留 system 消息定义角色只保留最近 N 轮对话丢弃更早的历史在下面的案例中定义一个保留最近对话轮数的函数后面在多轮对话中调用def keep_recent_messages(messages, max_pairs3): 保留最近的 N 轮对话 max_pairs: 保留的对话轮数每轮 user assistant # 分离 system 和对话 system_msgs [m for m in messages if m.get(role) system] conversation_msgs [m for m in messages if m.get(role) ! system] # 只保留最近的 recent_msgs conversation_msgs[-(max_pairs * 2):] # 返回system 最近对话 return system_msgs recent_msgs完整的示例如下在下面的案例代码中进行了3轮对话通过上面的方式对多轮对话进行优化from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage, AIMessage from dotenv import load_dotenv import os from langchain_openrouter import ChatOpenRouter # 加载配置文件 load_dotenv(overrideTrue) OPENROUTER_API_KEY os.getenv(OPENROUTER_API_KEY) OPENROUTER_API_BASE os.getenv(OPENROUTER_API_BASE) # 2、模型初始化 model ChatOpenRouter( modeldeepseek/deepseek-v3.2, api_keyOPENROUTER_API_KEY, base_urlOPENROUTER_API_BASE, ) def keep_recent_messages(messages, max_pairs3): 保留最近的 N 轮对话 max_pairs: 保留的对话轮数每轮 user assistant # 分离 system 和对话 system_msgs [m for m in messages if m.get(role) system] conversation_msgs [m for m in messages if m.get(role) ! system] # 只保留最近的 recent_msgs conversation_msgs[-(max_pairs * 2):] # 返回system 最近对话 return system_msgs recent_msgs # 初始化 long_conversation [ {role: system, content: 你是 Python 导师} ] # 第 1 轮 long_conversation.append({role: user, content: 什么是列表用一句解释}) r1 model.invoke(long_conversation) long_conversation.append({role: assistant, content: r1.content}) long_conversation.append({role: user, content: 列表和元组有什么区别用一句解释}) r2 model.invoke(long_conversation) long_conversation.append({role: assistant, content: r2.content}) # 第 3 轮 long_conversation.append({role: user, content: 什么是字典呢用一句解释}) r3 model.invoke(long_conversation) long_conversation.append({role: assistant, content: r3.content}) print(f原始消息数: {len(long_conversation)}) # 优化只保留最近 2 轮 optimized keep_recent_messages(long_conversation, max_pairs2) print(f优化后消息数: {len(optimized)}) print(f保留的内容: system 最近2轮对话) # 添加新的用户问题 optimized.append({role: user, content: 我第一个问题问的是什么}) # 使用优化后的历史 response model.invoke(optimized) print(f\nAI 回复: {response.content})通过这种方式可以让大模型在对话时记住前面的对话内容三、Langchain 消息扩展Langchain 除了上文中的几个类型的消息还有一些扩展的属性下面做一些介绍。3.1content 使用消息的 content 可以理解为数据内容它是弱类型的支持字符串和列表列表元素通常为字典1、存储字符串这是比较常见的一种形式如果只是纯文本内容直接传递字符串就好当content内容只有字符串时可以省略参数名称from LangChain.messages import HumanMessage msg1 HumanMessage(content 你好啊) msg2 HumanMessage(你好啊) print(msg1) print(msg2)2、存储字典列表如果需要发送的不只是文本如多模态内容则需要content的 字典列表 形式。字典内容遵循模型供应商的API规范以 openai: gpt-4.1 为例。参考官网文档Create chat completion | OpenAI API Reference如下示例from openai import OpenAI client OpenAI() completion client.chat.completions.create( modelgpt-6-astra, messages[ {role: developer, content: You are a helpful assistant.}, {role: user, content: Hello!} ] ) print(completion.choices[0].message)四、写在最后本文详细介绍了Langchain中各种类型消息的使用希望对看到的同学有帮助本篇到此结束感谢观看。
返回列表