一、简介

提示词模板(Prompt Templates) 是 LangChain 最核心、最基础的模块之一,专门解决动态生成提示词的问题。它能让你把固定的提示词逻辑封装起来,通过传入变量自动生成高质量、标准化的提示词,告别手动拼接字符串的混乱与错误。

1.1 为什么需要提示词模板?

先看反面案例(手动拼接字符串):

user_name = "小明"
user_question = "Python 是什么?"
# 手动拼接,容易出错、难以维护
prompt = f"你是一个专业编程助手,请回答{user_name}的问题:{user_question}"

这种做法在简单场景下可行,但随着应用复杂度增加,会暴露出以下问题:

  1. 重复代码:相同的提示结构在多处重复出现。
  2. 难以维护:提示结构变更时需要修改多处代码。
  3. 缺少组合能力:无法方便地复用片段或动态组合。
  4. 难以与对话历史、工具调用等结合:纯字符串无法表达消息的角色、工具调用等元数据。

LangChain 的提示词模板通过将提示抽象为模板对象,解决了上述问题,并提供了丰富的扩展能力。让开发者能够实现以下:

  1. 统一抽象:通过 PromptTemplate 和 ChatPromptTemplate 将提示构建与模型调用解耦。
  2. 强大组合:支持变量、部分填充、消息占位符、Few-shot 等。
  3. 可复用与序列化:模板可以保存、加载,实现提示工程的最佳实践。
  4. 与 LCEL 无缝集成:模板作为链的一部分,可以灵活组合。

1.2 核心类型

LangChain 主要提供了两种主要的提示词模板类型:

模板类型 适用场景 输入格式 输出格式
PromptTemplate 简单的文本生成、旧版 LLM 字符串变量 字符串
ChatPromptTemplate 对话模型(推荐) 消息列表(角色+内容) 消息列表

二、PromptTemplate(基础文本模板)

最简单的模板,用于生成纯文本提示词。使用 Python 的 str.format 语法({variable_name})。

2.1 基本用法

from langchain_core.prompts import PromptTemplate

# 1. 定义模板({变量名} 为占位符)
template = PromptTemplate(
    input_variables=["name", "question"],  # 声明变量
    template="你是专业助手,请回答 {name} 的问题:{question}"
)

# 2. 传入变量,生成最终提示词
prompt = template.format(name="小明", question="Python 是什么?")

print(prompt)

简化写法(推荐):

template = PromptTemplate.from_template(
    "你是专业助手,请回答 {name} 的问题:{question}"
)
# 自动识别变量,无需手动写 input_variables

输出:

你是专业助手,请回答 小明 的问题:Python 是什么?

2.2 从文件加载

把 Prompt 从代码里抽离出来,放在 .txt / .yaml / .json 文件中统一管理,方便修改、版本控制、多语言切换。

步骤 1:创建 Prompt 文件

新建文件:prompts/system_prompt.txt

你是一位专业的AI助手,请根据以下上下文回答用户问题。
保持回答简洁、准确、有礼貌。

上下文:{context}
用户问题:{question}

步骤 2:用 LangChain 加载并生成 PromptTemplate

from langchain.prompts import PromptTemplate

# 1. 从文本文件读取内容
with open("prompts/system_prompt.txt", "r", encoding="utf-8") as f:
    prompt_template = f.read()

# 2. 加载为 PromptTemplate
prompt = PromptTemplate(
    template=prompt_template,
    input_variables=["context", "question"]  # 必须和文件里的 {变量} 对应
)

# 测试
print(prompt.format(context="RAG是检索增强生成", question="RAG是什么?"))

三、ChatPromptTemplate(对话模板)

这是现代 LangChain 应用中最常用的模板类型。它将提示词组织为消息列表,每条消息都有明确的角色(system、human、ai)。

3.1 基本用法

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import SystemMessage, HumanMessage

# 定义聊天模板(列表形式,按角色分段)
chat_prompt = ChatPromptTemplate.from_messages([
    # 系统提示(固定角色)
    ("system", "你是 {role},回答语言必须使用 {language}"),
    # 用户消息(动态问题)
    ("user", "{question}")
])

# 生成完整消息列表
messages = chat_prompt.format_messages(
    role="资深Python工程师",
    language="中文",
    question="什么是装饰器?"
)

print(messages)

输出:

[
  SystemMessage(content="你是 资深Python工程师,回答语言必须使用 中文"),
  HumanMessage(content="什么是装饰器?")
]

3.2 支持的消息类型

ChatPromptTemplate.from_messages([
    ("system", "系统指令"),           # SystemMessage
    ("human", "用户消息"),            # HumanMessage
    ("ai", "AI消息"),                 # AIMessage
    ("function", "函数调用结果"),     # FunctionMessage(旧版)
    ("tool", "工具结果"),             # ToolMessage(新版)
])

3.3 角色写法支持 3 种格式

# 1. 元组(最简洁,推荐)
("system", "你是一个助手")

# 2. 消息类(灵活)
SystemMessage(content="你是一个助手")

# 3. 字典(兼容序列化)
{"role": "system", "content": "你是一个助手"}

3.4 链式调用与格式化

prompt = ChatPromptTemplate.from_template("解释:{topic}")  # 快速创建单消息模板
# 等同于:
prompt = ChatPromptTemplate.from_messages([("human", "解释:{topic}")])

# 格式化获取消息列表
messages = prompt.format_messages(topic="量子计算")

# 格式化获取字符串(仅当只有一条消息时可用)
text = prompt.format(topic="量子计算")

四、MessagesPlaceholder(消息占位符)

这是 LangChain 中最强大的特性之一,用于在模板中动态插入任意数量的历史消息或工具结果。

4.1 基本用法

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个乐于助人的助手。"),
    MessagesPlaceholder(variable_name="chat_history"),  # 历史对话占位符
    ("human", "{input}")
])

# 动态插入历史消息
from langchain.memory import ChatMessageHistory

history = ChatMessageHistory()
history.add_user_message("我叫小明")
history.add_ai_message("你好小明!")

# 填充模板
messages = prompt.format_messages(
    chat_history=history.messages,  # 插入整个历史列表
    input="我叫什么名字?"
)

4.2 控制占位符的显示方式

MessagesPlaceholder(
    variable_name="conversation",
    optional=True,          # 是否可选(不提供时忽略)
    separator="\n",         # 消息之间的分隔符(仅字符串输出时)
)

五、模板变量与部分填充

5.1 变量

模板中可以定义任意数量的变量。格式化时必须提供所有变量的值(除非使用部分填充)。

template = "Hello {name}, your score is {score}."
prompt = PromptTemplate.from_template(template)
prompt.format(name="Alice", score=95)  # 必须提供所有变量

5.2 批量生成提示词(Batch)

一次性生成多条提示:

prompts = template.batch([
    {"name": "A", "question": "Q1"},
    {"name": "B", "question": "Q2"}
])

5.3 校验变量

自动检查是否缺少变量:

template = PromptTemplate(
    template="{a} + {b} = {c}",
    input_variables=["a", "b"],
    validate_template=True  # 开启校验,发现缺少 c 会报错
)

5.4 部分填充(Partial)

部分填充允许我们预先固定某些变量的值,生成一个部分模板,稍后再填充剩余变量。

# 使用 partial 方法
partial_prompt = prompt.partial(score=100)
formatted = partial_prompt.format(name="Bob")
print(formatted)  # Hello Bob, your score is 100.

部分填充也可以使用函数,在运行时动态计算:

from datetime import datetime

def _get_datetime():
    return datetime.now().strftime("%Y-%m-%d")

prompt = PromptTemplate(
    template="Today is {date}. Tell me a fact about {topic}.",
    partial_variables={"date": _get_datetime}
)
print(prompt.format(topic="moon"))
# Today is 2025-03-28. Tell me a fact about moon.

5.5 序列化与保存(保存到文件 / 云端)

# 保存为 JSON
chat_prompt.save("prompt.json")

# 从文件加载
from langchain_core.prompts import load_prompt
loaded_prompt = load_prompt("prompt.json")

六、组合与管道

提示词模板可以与模型、输出解析器组合成可运行的链条(Runnable)。

6.1 基础组合

from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("用{language}写一首关于{theme}的诗。")

# 组合成 LCEL 链
chain = prompt | model | StrOutputParser()

# 执行
result = chain.invoke({"language": "中文", "theme": "春天"})

6.2 多输入与字典传递

# 模板可以包含多个变量
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role}。"),
    ("human", "请回答:{question}。参考上下文:{context}")
])

# invoke 时传递字典
chain = prompt | model
response = chain.invoke({
    "role": "历史学家",
    "question": "秦始皇统一六国的时间?",
    "context": "公元前221年"
})

6.3 模板组合

可以将多个模板组合成一个更大的模板。LangChain 提供了 PipelinePromptTemplate,但更常见的是直接使用字符串拼接或利用 ChatPromptTemplate.from_messages 合并消息列表。

base_system = ChatPromptTemplate.from_messages([
    ("system", "You are an AI assistant. Follow the rules: {rules}.")
])

task_specific = ChatPromptTemplate.from_messages([
    ("human", "Solve this math problem: {problem}")
])

combined = ChatPromptTemplate.from_messages(
    base_system.messages + task_specific.messages
)

七、Few-shot 提示模板

Few-shot 学习(少样本学习)需要在提示中提供几个示例,引导模型按示例格式输出。LangChain 提供了 FewShotPromptTemplate 和 FewShotChatMessagePromptTemplate 来简化这一过程。

7.1 基础 Few-shot 模板(文本模型)

from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

# 定义示例格式
example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="Input: {input}\nOutput: {output}"
)

# 示例列表
examples = [
    {"input": "happy", "output": "joyful"},
    {"input": "sad", "output": "unhappy"},
]

# 创建 FewShotPromptTemplate
few_shot = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="Give the antonym for the following words:",
    suffix="Input: {word}\nOutput:",
    input_variables=["word"],
    example_separator="\n\n"
)

print(few_shot.format(word="big"))
# Give the antonym for the following words:
#
# Input: happy
# Output: joyful
#
# Input: sad
# Output: unhappy
#
# Input: big
# Output:

7.2 Few-shot 聊天模板

对于聊天模型,我们可以使用 FewShotChatMessagePromptTemplate,它接受一组聊天消息作为示例。

from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate

# 定义示例:每个示例是一组消息
examples = [
    [
        HumanMessage(content="What is 2+2?"),
        AIMessage(content="4"),
    ],
    [
        HumanMessage(content="What is 3+3?"),
        AIMessage(content="6"),
    ]
]

# 创建 Few-shot 模板
few_shot_template = FewShotChatMessagePromptTemplate(
    examples=examples,
    # 可选:指定每个示例的格式化方式,这里直接使用示例本身
    example_prompt=ChatPromptTemplate.from_messages([("human", "{input}"), ("ai", "{output}")]),
    # 但示例已经是消息,所以 example_prompt 实际上不会应用,而是直接使用 examples
)

# 合并到主模板
final_prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a math assistant."),
    few_shot_template,
    ("human", "{input}"),
])

# 格式化
messages = final_prompt.format_messages(input="What is 5+5?")

八、高级特性

8.1 自定义模板格式

当系统自带的 PromptTemplate / ChatPromptTemplate 不够用时,可以自己写一个完全可控的模板。其主要实现步骤有以下几点:

  1. 继承 StringPromptTemplate 或 BaseChatPromptTemplate
  2. 定义 input_variables
  3. 在 format() 或 format_messages() 里拼提示词

8.1.1 最简单的自定义模板

from langchain.prompts import StringPromptTemplate
from pydantic import BaseModel, Field
from typing import List

# 自定义模板
class MyCustomPrompt(StringPromptTemplate, BaseModel):
    # 定义你需要的变量
    context: str
    question: str

    def format(self, **kwargs) -> str:
        # 在这里自由拼接提示词
        return f"""
你是专业AI助手。

上下文:
{self.context}

用户问题:
{self.question}

请根据上下文回答问题。
"""

# 使用
prompt = MyCustomPrompt(
    context="RAG是检索增强生成",
    question="RAG是什么?"
)

print(prompt.format())

8.1.2 带动态变量的自定义模板

class RAGPrompt(StringPromptTemplate, BaseModel):
    # 允许外部传入
    input_variables: List[str] = ["context", "question"]

    def format(self,** kwargs):
        context = kwargs["context"]
        question = kwargs["question"]
        
        return f"""
请根据下面的文档回答问题,不要编造。

文档:
{context}

问题:{question}
"""

# 使用
prompt = RAGPrompt()
print(prompt.format(context="xxx", question="yyy"))

8.1.3 聊天模型专用自定义模板

适合 Qwen、Llama、ChatGLM、GPT 等。

from langchain.schema import SystemMessage, HumanMessage, AIMessage
from langchain.prompts import BaseChatPromptTemplate
from typing import List, Sequence

class ChatCustomPrompt(BaseChatPromptTemplate, BaseModel):
    def format_messages(self,** kwargs) -> Sequence:
        context = kwargs["context"]
        question = kwargs["question"]
        
        return [
            SystemMessage(content="你是专业RAG助手,根据上下文回答。"),
            HumanMessage(content=f"上下文:{context}\n问题:{question}")
        ]

# 使用
prompt = ChatCustomPrompt(input_variables=["context", "question"])
msgs = prompt.format_messages(context="检索内容", question="什么是RAG?")

8.1.4 带逻辑的高级自定义模板

例如:自动截断上下文、过滤空内容、拼接历史对话

class AdvancedRAGPrompt(StringPromptTemplate, BaseModel):
    input_variables: List[str] = ["context", "question", "history"]

    def format(self, **kwargs):
        context = kwargs["context"]
        question = kwargs["question"]
        history = kwargs.get("history", "")

        # 自定义逻辑1:截断太长的上下文
        if len(context) > 2000:
            context = context[:2000] + "..."

        # 自定义逻辑2:拼接历史
        history_prompt = f"历史对话:{history}" if history else ""

        return f"""
{history_prompt}

上下文:
{context}

问题:{question}

请简洁回答。
"""

8.2 多模态模板(图像+文本)

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage

# 手动构建多模态消息
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个图像识别助手。"),
    ("human", [
        {"type": "text", "text": "描述这张图片:{description_request}"},
        {"type": "image_url", "image_url": {"url": "{image_url}"}}
    ])
])

8.3 与模型链(Chain)结合

提示词模板通常与 LLMChain 或 ChatOpenAI 结合使用,构建完整的链。

from langchain.chains import LLMChain
from langchain_openai import OpenAI

llm = OpenAI()
prompt = PromptTemplate.from_template("Tell me a {adjective} joke about {topic}.")
chain = LLMChain(llm=llm, prompt=prompt)

result = chain.run(adjective="funny", topic="dogs")
print(result)

对于聊天模型,可以使用 ChatOpenAI 和 ChatPromptTemplate:

from langchain_openai import ChatOpenAI

chat_model = ChatOpenAI()
chat_prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a {persona} assistant."),
    ("human", "{input}")
])
chain = chat_prompt | chat_model  # 使用 LCEL(LangChain Expression Language)
response = chain.invoke({"persona": "pirate", "input": "Tell me a joke."})

8.4 动态选择模板

from langchain_core.prompts import PromptTemplate

# 根据条件选择不同模板
def select_template(topic):
    if topic == "代码":
        return PromptTemplate.from_template("用{python}代码实现:{task}")
    else:
        return PromptTemplate.from_template("解释:{task}")

template = select_template("代码")

九、最佳实践与技巧

  1. 使用 ChatPromptTemplate 处理聊天模型:即使是简单场景,也推荐使用聊天模板,因为它天然支持系统消息、历史等扩展。
  2. 利用 MessagesPlaceholder 注入动态内容:如对话历史、工具调用结果,避免硬编码。
  3. 部分填充实现默认值:将不常变的变量(如当前日期、固定指令)通过 partial 固化,减少调用时的参数。
  4. 示例管理:对于 Few-shot,考虑将示例存储在外部文件或数据库中,动态加载。
  5. 模板版本控制:将提示模板保存为独立文件,方便团队协作和 A/B 测试。
  6. 避免在模板中写入敏感信息:使用环境变量或部分填充函数从安全处获取。
  7. 调试:在开发阶段,可以先用 format_messages 查看最终生成的消息,再送入模型。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐