搜索文档
认识消息
在 LangChain 中,Message(消息)是模型交互的最基本单元。它既代表模型接收到的 输入(Input),也代表模型生成的输出(Output)。
LangChain 在 1.0 中提供了跨模型统一的 Message 标准。无论你使用的是 OpenAI、Anthropic、Gemini 还是本地模型,这一标准都能保持一致的行为。好处:
- 兼容性强 :不同模型的消息格式自动对齐。
- 可扩展性高 :方便添加多模态内容或自定义字段。
- 可追踪性好 :为 LangSmith 等调试工具提供一致的上下文数据结构。
消息的内部结构
LangChain的消息(Message)对象包含三种字段
- Role:消息所属的角色或类型,如 system 、 user 、 assistant。
- Content:消息内容。
- Metadata:(可选)元数据,存储额外信息。如:消息ID、响应时间、token消耗量、消息标签等。
消息类型
LangChain定义了很多消息类型,通过 role 区分。常用的有四种。
- 系统消息
{"role": "system", "content": "你是个精通编程的软件架构师"}- 用户消息
{"role": "user", "content": "你好啊~"}- 助手(AI)消息:代表模型的回复,包括生成的文本、工具调用、元数据等。
{"role": "assistant", "content": "我也很高兴认识你"}{
"role": "assistant",
"content": "",
"tool_calls": [{
"name": "get_weather",
"args": {"location": "北京"},
"id": "call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s"
}]
}- 工具调用消息:工具调用结果匹配的消息类型
{"role": "tool", "content": "今天天气很好", "tool_call_id": "call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s"}面试题:为什么使用不同的消息类型?
- 明确角色 :清晰区分系统提示、用户输入和 AI 回复。
- 控制行为 :通过 SystemMessage 精确控制 AI 的行为。
- 对话历史 :构建完整的多轮对话上下文。
- 调试友好 :更容易追踪和调试对话流程
消息格式
LangChain支持 JSON 和对象两种消息格式。上面的几处代码块均为 JSON 格式消息。
对应关系如下:
| JSON 格式 | 对象格式 |
|---|---|
| "role": "system" | SystemMessage |
| "role": "user" | HumanMessage |
| "role": "assistant" | AIMessage |
| "role": "tool" | ToolMessage |
from langchain.chat_models import init_chat_model
model = init_chat_model(
model = "ollama:deepseek-coder",
)
message = [
{"role": "system", "content": "你是一个非常优秀的前端程序员"},
{"role": "user", "content": "请问什么是防抖"},
]
res = model.invoke(message)
message.append({"role": "assistant", "content": res.content})
message.append({"role": "tool", "content": "<工具输出>", "tool_call_id": "call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s"})
message.append({"role": "user", "content": "上一个问题是什么?"})
res = model.invoke(message)
message.append({"role": "assistant", "content": res.content})
print(message)from langchain.chat_models import init_chat_model
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
model = init_chat_model(
model = "ollama:deepseek-coder",
)
message = [
SystemMessage("你是一个非常优秀的前端程序员"),
HumanMessage("请问什么是防抖")
]
res = model.invoke(message)
message.append(AIMessage(res.content))
message.append(ToolMessage(content = "<工具输出>", tool_call_id = "call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s"))
message.append(HumanMessage("上一个问题是什么?"))
res = model.invoke(message)
message.append(AIMessage(res.content))
print(message)聊天机器人
开发一个简易的对话机器人,需求如下:
- 会话上下文最多记忆 n 轮的对话。
- 当用户输入特定字符是结束对话。
from langchain.chat_models import init_chat_model
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
MAX_WHEEL = 1
END_KEYWORD = "end"
model = init_chat_model(
model = "ollama:deepseek-coder"
)
messages = [SystemMessage("你是一个全栈工程师,你的名字是 iGmaCode")]
i = 1
def optimizeMessage(arr):
systemList = []
messageList = []
for item in arr:
if type(item) == SystemMessage:
systemList.append(item)
else:
messageList.append(item)
return systemList + messageList[-(MAX_WHEEL * 2):]
while True:
print("\n", "="*10, f"第 {i} 轮提问开始", "="*10, "\n")
user_input = input("请输入您的问题:")
if user_input == END_KEYWORD:
print("会话结束~", messages)
break
messages.append(HumanMessage(user_input))
resJoin = ""
for res in model.stream(optimizeMessage(messages)):
print(res.content, end="", flush=True)
resJoin += res.content
messages.append(AIMessage(resJoin))
i += 1content 和 content_blocks
- 消息的 content 可以理解为数据内容,它是弱类型的,支持字符串和列表(列表元素通常为字典)。
- 此前我们使用时传入的都是字符串类型,传入的值由模型供应商决定,下面以 DeepSeek 官网的 deepseek-v4-flash 模型为例,传入图片+文字的多模态内容。
import base64
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage
load_dotenv(verbose=True)
def image_to_base64_data_uri(file_path: str) -> str:
with open(file_path, "rb") as f:
data = f.read()
b64_str = base64.b64encode(data).decode("utf-8")
return f"data:image/png;base64,{b64_str}"
model = init_chat_model(
model="deepseek:deepseek-v4-flash",
api_key = os.getenv("DEEPSEEK_API_KEY"),
base_url = os.getenv("DEEPSEEK_API_BASE")
)
res = model.invoke([
HumanMessage(
content = [
{"type": "text", "text": "这张图片是什么?"},
{"type": "image_url", "image_url": {"url": image_to_base64_data_uri("a.png")}},
]
)
])
print(res)提示词模板
在 LangChain 开发中,构造提示词既可以直接使用 Python 字符串拼接,也可以使用 LangChain 提供的 PromptTemplate 或 ChatPromptTemplate 。
提示词模板的优势在于:
- 结构清晰(变量占位)
- 易维护、可复用
- 自动变量校验(更安全)
- 支持复杂场景(对话 / RAG / Agent)
- 可与 LangChain 生态无缝集成
- 便于调试与日志追踪
LangChain 1.0的架构变革中,核心的演进之一体现在 Prompt 机制上:一个结构化的、富含元数据的消息列表已经取代单一字符串,成为与模型交互的标准数据格式。
- 旧时代:LLM + PromptTemplate(输入与输出均为字符串)
- 新时代:ChatModel+ChatPromptTemplate(输入与输出均为消息列表)
| 特性 | PromptTemplate | ChatPromptTemplate |
|---|---|---|
| 输出格式 | 纯文本字符串 | 消息列表 |
| 角色支持 | 无 | system/user/assistant |
| 对话历史 | 不支持 | 支持 |
| 适用场景 | 简单提示 | 聊天、对话、多轮交互 |
消息类型:
| 角色字符串 | 含义 | 用途 |
|---|---|---|
| system | 系统消息 | 设定 AI 的行为、角色、规则 |
| user / human | 用户消息 | 用户的输入/问题 |
| assistant / ai | AI 消息 | AI 的回复(用于对话历史) |
定义模板
ChatPromptTemplate 可以通过初始化方法或 from_messages 方法来实例化提示词模板
from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
("user", "你是谁?"),
("ai", "我是一个程序员"),
("user", "{user_input}"),
])from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
("user", "你是谁?"),
("ai", "我是一个程序员"),
("user", "{user_input}"),
])使用模板
使用模板有三种方式:invoke、format、format_messages
三种方式返回值均可以传给大模型。
from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
("user", "你是谁?"),
("ai", "我是一个程序员"),
("user", "{user_input}"),
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({"name": "iGma", "user_input": "说一下 Vue2 和 Vue3 的区别"})
print(type(chat_prompt)) # 输出 <class 'langchain_core.prompt_values.ChatPromptValue'>from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
("user", "你是谁?"),
("ai", "我是一个程序员"),
("user", "{user_input}"),
])
# 使用模板
chat_prompt = chat_prompt_template.format(name="iGma", user_input="说一下 Vue2 和 Vue3 的区别")
print(type(chat_prompt)) # 输出 <class 'str'>from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
("user", "你是谁?"),
("ai", "我是一个程序员"),
("user", "{user_input}"),
])
# 使用模板
chat_prompt = chat_prompt_template.format_messages(name="iGma", user_input="说一下 Vue2 和 Vue3 的区别")
print(type(chat_prompt)) # 输出 <class 'list'>定义模板的参数类型
在定义模板时可以通过初始化方法或 from_messages 方法来实例化提示词模板,两种方式的入参都是 列表类型,列表的元素可以有还多种表达方式。
值得注意的是:
- 如果是字符串列表,每个元素都是
user角色,无法设置system和ai角色。 - 消息对象列表无法传入变量。
from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
"你是谁?",
"{user_input}"
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({"user_input": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
("user", "{user_input}")
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({"name": "iGma", "user_input": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
{"role": "system", "content": "你是一个优秀的前端程序员,你的名字是{name}"},
("user", "{user_input}")
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({"name": "iGma", "user_input": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)from langchain_core.messages import SystemMessage, HumanMessage
from langchain_core.prompts import ChatPromptTemplate
# 定义模板(这里的 name 和 user_input 不会视为变量,即便在使用时传入对应值也无效)
chat_prompt_template = ChatPromptTemplate.from_messages([
SystemMessage("你是一个优秀的前端程序员,你的名字是{name}"),
HumanMessage("{user_input}")
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({"name": "iGma", "user_input": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
# 定义模板(这种写法 name 和 user_input 会被视为变量处理)
chat_prompt_template = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template("你是一个优秀的前端程序员,你的名字是{name}"),
HumanMessagePromptTemplate.from_template("{user_input}")
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({"name": "iGma", "user_input": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)from langchain_core.prompts import ChatPromptTemplate
# 定义模板 1
t1 = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
])
# 定义模板 2
t2 = ChatPromptTemplate.from_messages([
("user", "{user_input}")
])
# 定义模板 3
chat_prompt_template = ChatPromptTemplate.from_messages([
t1, t2
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({"name": "iGma", "user_input": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)部分变量预填充 partial()
预填充某些固定不变的变量,创建模板的变体。具体场景如下:
- 某些变量在所有调用中都相同。
- 需要为不同用户/场景创建定制模板
from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是{dept}的{role}"),
("user", "{task}")
])
user_template = chat_prompt_template.partial(dept="IT研发部", role="前端工程师")
# 使用模板
chat_prompt = user_template.invoke({"task": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是{dept}的{role}"),
("user", "{task}")
])
# IT 部门模板
it_template = chat_prompt_template.partial(dept="IT研发部", role="前端工程师")
# 销售部门模板
sale_template = chat_prompt_template.partial(dept="销售部门", role="销售顾问")
# 使用模板
chat_prompt = it_template.invoke({"task": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)消息占位符
当你不确定消息提示模板使用什么角色,或者希望在格式化过程中插入消息列表时使用。
使用场景:多轮对话系统存储历史消息以及Agent的中间步骤处理此功能非常有用。
具体表现形式有两种:JSON 形式和 MessagesPlaceholder 实例。
from langchain_core.prompts import ChatPromptTemplate
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个 AI 编程助手"),
("placeholder", "{ms}")
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({
"ms": [
("user", "你是谁"),
("ai", "我是 AI 编程助手")
]
})
print(chat_prompt)from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
("system", "你是一个 AI 编程助手"),
MessagesPlaceholder("history")
])
# 使用模板
chat_prompt = chat_prompt_template.invoke({
"history": [
("user", "你是谁"),
("ai", "我是 AI 编程助手")
]
})
print(chat_prompt)封装模板库
在日常开发中,可以把一些常用的模板封装到一个类中。
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
class TemplatePrompt:
TRANSLATOR = ChatPromptTemplate.from_messages([
("system", "你是专业翻译,精通{source_lang}和{target_lang}"),
("user", "翻译以下文本:\n{text}")
])
CODE_REVIEWER = ChatPromptTemplate.from_messages([
("system", "你是{language}代码审查专家,重点关注{focus}"),
("user", "审查代码:\n```{language}\n{code}\n```")
])
SUMMARIZER = ChatPromptTemplate.from_messages([
("system", "你是内容摘要专家"),
("user", "将以下内容总结为{num}个要点:\n{content}")
])
TUTOR = ChatPromptTemplate.from_messages([
("system", "你是{subject}导师,学生水平:{level}"),
("user", "{question}")
])
messages = TemplatePrompt.TRANSLATOR.format_messages(
source_lang="英语",
target_lang="中文",
text="Hello World"
)
print(messages)模板组合
from langchain_core.prompts import ChatPromptTemplate
# 定义模板 1
t1 = ChatPromptTemplate.from_messages([
("system", "你是一个优秀的前端程序员,你的名字是{name}"),
])
# 定义模板 2
t2 = ChatPromptTemplate.from_messages([
("user", "{user_input}")
])
# 定义模板 3
chat_prompt_template = t1 + t2
# 使用模板
chat_prompt = chat_prompt_template.invoke({"name": "iGma", "user_input": "说一下 Vue2 和 Vue3 的区别"})
print(chat_prompt)