Skip to content

消息与提示词模板

分类:LangChain
标签:LangChain
创建时间:2026年10月24日 15:50:30

认识消息 ​

在 LangChain 中,Message(消息)是模型交互的最基本单元。它既代表模型接收到的 输入(Input),也代表模型生成的输出(Output)。

LangChain 在 1.0 中提供了跨模型统一的 Message 标准。无论你使用的是 OpenAI、Anthropic、Gemini 还是本地模型,这一标准都能保持一致的行为。好处:

  • 兼容性强 :不同模型的消息格式自动对齐。
  • 可扩展性高 :方便添加多模态内容或自定义字段。
  • 可追踪性好 :为 LangSmith 等调试工具提供一致的上下文数据结构。

消息的内部结构 ​

LangChain的消息(Message)对象包含三种字段

  • Role:消息所属的角色或类型,如 system 、 user 、 assistant。
  • Content:消息内容。
  • Metadata:(可选)元数据,存储额外信息。如:消息ID、响应时间、token消耗量、消息标签等。

消息类型 ​

LangChain定义了很多消息类型,通过 role 区分。常用的有四种。

  1. 系统消息
python
{"role": "system", "content": "你是个精通编程的软件架构师"}
  1. 用户消息
python
{"role": "user", "content": "你好啊~"}
  1. 助手(AI)消息:代表模型的回复,包括生成的文本、工具调用、元数据等。
python
{"role": "assistant", "content": "我也很高兴认识你"}
python
{
    "role": "assistant",
    "content": "",
    "tool_calls": [{
        "name": "get_weather",
        "args": {"location": "北京"},
        "id": "call_00_nUD2NC9QRN5Cg1GaoIkBJQ4s"
    }]
}
  1. 工具调用消息:工具调用结果匹配的消息类型
python
{"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
python
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)
python
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)

聊天机器人 ​

开发一个简易的对话机器人,需求如下:

  1. 会话上下文最多记忆 n 轮的对话。
  2. 当用户输入特定字符是结束对话。
python
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 += 1

content 和 content_blocks ​

  1. 消息的 content 可以理解为数据内容,它是弱类型的,支持字符串和列表(列表元素通常为字典)。
  2. 此前我们使用时传入的都是字符串类型,传入的值由模型供应商决定,下面以 DeepSeek 官网的 deepseek-v4-flash 模型为例,传入图片+文字的多模态内容。
python
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(输入与输出均为消息列表)
特性PromptTemplateChatPromptTemplate
输出格式纯文本字符串消息列表
角色支持无system/user/assistant
对话历史不支持支持
适用场景简单提示聊天、对话、多轮交互

消息类型:

角色字符串含义用途
system系统消息设定 AI 的行为、角色、规则
user / human用户消息用户的输入/问题
assistant / aiAI 消息AI 的回复(用于对话历史)

定义模板 ​

ChatPromptTemplate 可以通过初始化方法或 from_messages 方法来实例化提示词模板

python
from langchain_core.prompts import ChatPromptTemplate

# 定义模板
chat_prompt_template = ChatPromptTemplate([
    ("system", "你是一个优秀的前端程序员,你的名字是{name}"),
    ("user", "你是谁?"),
    ("ai", "我是一个程序员"),
    ("user", "{user_input}"),
])
python
from langchain_core.prompts import ChatPromptTemplate

# 定义模板
chat_prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个优秀的前端程序员,你的名字是{name}"),
    ("user", "你是谁?"),
    ("ai", "我是一个程序员"),
    ("user", "{user_input}"),
])

使用模板 ​

使用模板有三种方式:invoke、format、format_messages

三种方式返回值均可以传给大模型。

python
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'>
python
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'>
python
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 方法来实例化提示词模板,两种方式的入参都是 列表类型,列表的元素可以有还多种表达方式。

值得注意的是:

  1. 如果是字符串列表,每个元素都是 user 角色,无法设置 system 和 ai 角色。
  2. 消息对象列表无法传入变量。
python
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)
python
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)
python
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)
python
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)
python
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)
python
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() ​

预填充某些固定不变的变量,创建模板的变体。具体场景如下:

  1. 某些变量在所有调用中都相同。
  2. 需要为不同用户/场景创建定制模板
python
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)
python
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 实例。

python
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)
python
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)

封装模板库 ​

在日常开发中,可以把一些常用的模板封装到一个类中。

python
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)

模板组合 ​

python
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)

基于 MIT 许可发布