目录
[2.1. PromptTemplate:字符串模板的基石](#2.1. PromptTemplate:字符串模板的基石)
[2.2. FewShotPromptTemplate:面向文本模型的少样本提示模板](#2.2. FewShotPromptTemplate:面向文本模型的少样本提示模板)
[2.3. ChatPromptTemplate:面向聊天模型](#2.3. ChatPromptTemplate:面向聊天模型)
[MessagesPlaceholder 补充说明](#MessagesPlaceholder 补充说明)
[2.4. FewShotChatMessagePromptTemplate:面向聊天模型的少样本提示模板](#2.4. FewShotChatMessagePromptTemplate:面向聊天模型的少样本提示模板)
[PromptTemplate 系列模板详细对比](#PromptTemplate 系列模板详细对比)
[3.少样本提示(Few-Shot Prompting)](#3.少样本提示(Few-Shot Prompting))
[tool_example_to_messages 函数](#tool_example_to_messages 函数)
[4. LangChain Hub:提示词的"GitHub"](#4. LangChain Hub:提示词的“GitHub”)
1.为什么需要提示词模板
在构建 LLM 应用时,我们经常面临这样的场景:需要向模型发送大量结构相似但内容不同的请求 (如介绍{xxxx}的历史)。如果每次都手动拼接字符串,代码将变得臃肿且难以维护。
提示词模板本质上是一个可复用的提示词蓝图------它类似于Python中的字符串格式化功能。你创建一个带有"占位符"的模板,然后在运行时用具体的值填充这些占位符,从而生成最终发送给 LLM 的完整提示词
核心价值
- 可复用性:只需定义一个模板,即可用于无数个类似的查询
- 关注点分离:将提示词的结构逻辑与具体数据分离开来
- 一致性:确保发送给 LLM 的提示词结构统一,获得更稳定、可预测的输出
- 可维护性:修改提示词风格或结构时,只需修改一处模板文件
2.提示词相关接口
2.1. PromptTemplate:字符串模板的基石
PromptTemplate 是 LangChain 中最基础的模板类,适用于传统的文本补全模型场景
它通过模板化的方式,将提示词中的固定文本 与动态变量(如用户输入、业务数据)分离,解决了硬编码提示词导致的维护困难、复用性差等问题
class PromptTemplate(BasePromptTemplate):
def __init__(
self,
template: str,
input_variables: Optional[List[str]] = None,
template_format: str = "f-string",
partial_variables: Optional[Dict[str, Any]] = None,
validate_template: bool = True,
**kwargs: Any,
) -> None:
...
- 参数详解
| 参数名 | 类型 | 是否必需 | 说明 |
| input_variables | List[str] | 是 | 模板中使用的动态变量名列表 。 PromptTemplate 在格式化时会校验这些变量是否都被提供了值。 |
| template | str | 是 | 模板字符串 本身, 其中用 {变量名} 的格式来标记需要动态替换的部分。 |
| template_format | str | 否 | 指定模板的语法格式 ,默认为 "f-string"。 也支持 "jinja2" 和 "mustache"。 |
| validate_template | bool | 否 | 是否在初始化时校验模板的有效性 (如变量是否匹配), 默认为 True。 |
| partial_variables | List[str] |
否 | 模板中可选的变量名列表,通常用于更高级的占位符场景。 |
|---|
核心原理
PromptTemplate 本质上是 Python f-string 的高级封装。它接收一个包含 {variable} 占位符的模板字符串,在调用时用传入的变量值进行替换,最终输出一个单一的字符串。
该类实现了标准的 Runnable 接口,这意味着它可以与 LangChain 表达式语言(LCEL)无缝集成,通过 | 操作符与其他组件(如模型、输出解析器)组成处理链
- 核心方法与使用方式
| 方法 | 返回类型 | 说明 |
|---|---|---|
from_template(template) |
PromptTemplate |
最推荐的创建方式 。从参数 template 中自动解析出 input_variables,代码更简洁 |
format(**kwargs) |
str |
核心方法 。传入具体的变量值, 将模板格式化为最终的字符串提示词 |
invoke(**kwargs) |
str |
核心方法 。与 format() 功能相同,是 LangChain 标准化的可运行接口(Runnable),传入字典参数 |
partial(**kwargs) |
PromptTemplate |
用于部分填充 模板变量,生成一个新的模板。可以用于设置一些变量的默认值(支持静态值或动态函数) |
format_prompt(**kwargs) |
PromptValue |
类似于 format(),但返回的是一个 PromptValue 对象,该对象能根据下游模型类型自动转换: • 普通 LLM :通过 to_string() 转为字符串 • ChatModel :通过 to_messages() 转为消息列表(包含单个 HumanMessage 对象的列表) |
from langchain_core.prompts import PromptTemplate
from datetime import datetime
import time
# 1. 直接实例化对象
prompt1 = PromptTemplate(
template="用户{user}在{date}登录系统,IP地址为{ip}。",
input_variables=["user", "date", "ip"],
template_format="f-string"
)
print(prompt1.format(user="张三", date="2026-07-12", ip="192.168.1.100"))
# 2. from_template 自动推断变量
prompt2 = PromptTemplate.from_template("尊敬的{title}{name},您的订单{order_id}已发货。")
# format 填充模板
print(prompt2.format(title="先生", name="李明", order_id="ORD-2026-001"))
# 3. invoke 填充模板(标准化接口)
prompt4 = PromptTemplate.from_template("将以下句子翻译成{lang}:{sentence}")
result4 = prompt4.invoke({"lang": "英文", "sentence": "今天天气真好"})
print(result4)
# 4. partial 预填充部分变量
prompt5 = PromptTemplate.from_template("日期:{date},用户:{user},操作:{action},状态:{status}")
partial_prompt = prompt5.partial(date="2026-07-12", status="成功")
print(partial_prompt.format(user="王芳", action="修改密码"))
# 5. format_prompt 返回 PromptValue 对象
prompt7 = PromptTemplate.from_template("请用{adj}的方式描述{subject}。")
prompt_value = prompt7.format_prompt(adj="诗意", subject="秋天")
print(f"类型: {type(prompt_value)}")
print(f"转为字符串: {prompt_value.to_string()}")
print(f"转为消息列表: {prompt_value.to_messages()}")
# 6. 实例化时使用 partial_variables
prompt8 = PromptTemplate(
template="系统版本:{version},环境:{env},请求ID:{request_id},耗时:{cost}ms",
input_variables=["request_id", "cost"],
partial_variables={"version": "v3.2.1", "env": "生产环境"}
)
print(prompt8.format(request_id="REQ-20260712-001", cost=45))
- **变量名必须完全匹配:**format() 传入的 key 必须与模板中的 {variable} 一致
- 预填充变量不再需要传入:partial() 固定后,format() 时不能重复传入
- **invoke 输入必须是字典:**与 format(**kwargs) 不同,invoke 接收一个字典参数
- **模板格式支持:**默认 f-string,也支持 jinja2、mustache(通过 template_format 指定)
2.2. FewShotPromptTemplate:面向文本模型的少样本提示模板
FewShotPromptTemplate 适用于传统的文本生成任务 ,生成字符串
它将示例、前缀指令和动态输入按固定结构组合为完整的提示词
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
class FewShotPromptTemplate(BasePromptTemplate):
def __init__(
self,
examples: Optional[List[Dict[str, Any]]] = None,
example_prompt: Optional[PromptTemplate] = None,
prefix: Optional[str] = "",
suffix: Optional[str] = "",
input_variables: Optional[List[str]] = None,
example_separator: str = "\n\n",
prefix_variables: Optional[List[str]] = None,
suffix_variables: Optional[List[str]] = None,
template_format: str = "f-string",
validate_template: bool = True,
**kwargs: Any,
) -> None:
...
- 参数详细说明
| 参数名称 | 类型 | 是否必需 | 说明 |
|---|---|---|---|
examples |
Optional[List[Dict[str, Any]]] |
二选一 | 静态示例数据列表。每个字典代表一个示例,其键需与 example_prompt 中的变量对应。与 example_selector 二选一 |
example_selector |
Optional[BaseExampleSelector] |
二选一 | 动态示例选择器。当示例众多时,可根据输入智能选择最相关的示例,以节省 Token 并提高准确性。与 examples 二选一 |
example_prompt |
PromptTemplate |
必需 | 用于格式化单个示例的模板。定义了每个示例字典如何被渲染成字符串 |
input_variables |
List[str] |
必需 | 最终提示词模板所期望的输入变量名称列表。这些变量通常在 suffix 或 prefix 中被使用 |
prefix |
str |
可选 | 所有示例之前的引导文本,用于设定角色或任务背景,默认空字符串 |
suffix |
str |
函数签名可选(默认 ""),但功能上通常必需 |
示例列表之后的结束文本,通常包含用户实际提问 和等待模型补全的提示(如 "问:{question}\n答:")。如果不提供,请确保 prefix 中包含所有 input_variables,但这会导致提示词格式不自然 |
example_separator |
str |
可选 | 用于连接各个示例以及 prefix、suffix 的字符串分隔符,默认为 "\n\n" |
prefix_variables |
Optional[List[str]] |
可选 | prefix 中的变量列表,通常自动推断,无需手动指定 |
suffix_variables |
Optional[List[str]] |
可选 | suffix 中的变量列表,通常自动推断,无需手动指定 |
template_format |
str |
可选 | 模板格式,支持 "f-string"(默认)、"jinja2" 等 |
validate_template |
bool |
可选 | 是否在初始化时验证模板语法,默认 True |
- 核心方法
| 方法 | 返回类型 | 说明 |
|---|---|---|
format(**kwargs) |
str |
格式化完整模板(前缀 + 示例 + 后缀)返回字符串 |
invoke(input) |
str |
同 format,标准化 Runnable 接口 |
partial(**kwargs) |
FewShotPromptTemplate |
预填充部分变量,返回新模板 |
format_prompt(**kwargs) |
PromptValue |
返回 PromptValue 对象 |
from_examples() |
FewShotPromptTemplate |
类方法,从示例列表和示例分隔符快捷创建 |
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
# 示例数据
examples = [
{"word": "高兴", "antonym": "悲伤"},
{"word": "快速", "antonym": "缓慢"},
{"word": "明亮", "antonym": "暗淡"},
]
example_prompt = PromptTemplate(
template="原词: {word}\n反义词: {antonym}",
input_variables=["word", "antonym"]
)
#1. format(**kwargs) - 返回字符串
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="请为以下词语生成反义词:",
suffix="原词: {input_word}\n反义词:",
input_variables=["input_word"],
example_separator="\n\n"
)
result = few_shot_prompt.format(input_word="炎热")
print(f"结果:\n{result}")
# 2. invoke(input) - 返回字符串
result_invoke = few_shot_prompt.invoke({"input_word": "寒冷"})
print(f"结果:\n{result_invoke}")
# 3. partial(**kwargs) - 返回 FewShotPromptTemplate
partial_prompt = few_shot_prompt.partial(prefix="【新前缀】请生成反义词:")
result_partial = partial_prompt.format(input_word="温暖")
print(f"结果:\n{result_partial}")
# 4. format_prompt(**kwargs) - 返回 PromptValue
prompt_value = few_shot_prompt.format_prompt(input_word="湿润")
print(f"to_string():\n{prompt_value.to_string()}")
print(f"to_messages(): {prompt_value.to_messages()}")
# 5. from_examples() - 类方法快捷创建
few_shot_from_examples = FewShotPromptTemplate.from_examples(
examples=examples,
example_prompt=example_prompt,
prefix="从例子中学习反义词:",
suffix="原词: {input_word}\n反义词:",
input_variables=["input_word"],
example_separator="\n---\n"
)
result_from_examples = few_shot_from_examples.format(input_word="干燥")
print(f"结果:\n{result_from_examples}")
工作原理
-
获取示例 :通过静态
examples或动态example_selector获得示例列表。 -
格式化示例 :使用
example_prompt将每个示例字典渲染成字符串。 -
拼接最终提示词 :将
prefix、所有格式化后的示例字符串、suffix用example_separator连接起来,形成最终提示词。
2.3. ChatPromptTemplate:面向聊天模型
随着 ChatGPT 等对话模型的普及,LLM 的输入从单一字符串演变为结构化的消息列表ChatPromptTemplate 应运而生,专为聊天模型设计
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import BaseMessagePromptTemplate
from typing import Sequence, Optional, Dict, Any, Union
class ChatPromptTemplate(BaseChatPromptTemplate):
def __init__(
self,
messages: Sequence[BaseMessagePromptTemplate],
input_variables: Optional[List[str]] = None,
partial_variables: Optional[Dict[str, Any]] = None,
template_format: str = "f-string",
validate_template: bool = True,
**kwargs: Any,
) -> None:
...
- 核心参数详解
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
messages |
Sequence[BaseMessagePromptTemplate] |
必需 | 消息模板列表,定义对话中的每一条消息(系统、人类、AI等) |
input_variables |
Optional[List[str]] |
可选 | 模板中所有变量名列表。若不提供,会自动从所有消息模板中提取 |
partial_variables |
Optional[Dict[str, Any]] |
可选 | 预填充的变量(静态值或动态函数) |
template_format |
str |
可选 | 模板格式,支持 "f-string"(默认)、"jinja2" |
validate_template |
bool |
可选 | 是否在初始化时校验模板语法,默认 True |
- 核心方法
| 方法 | 返回类型 | 说明 |
|---|---|---|
format_messages(**kwargs) |
List[BaseMessage] |
核心方法 。填充模板并返回消息列表([HumanMessage, AIMessage, ...]),用于 ChatModel 输入 |
format_prompt(**kwargs) |
PromptValue |
返回 PromptValue 对象,可通过 to_messages() 或 to_string() 转换 |
invoke(input) |
PromptValue |
标准化 Runnable 接口,返回 PromptValue(注意:不是 str) |
partial(**kwargs) |
ChatPromptTemplate |
预填充部分变量,返回新模板 |
format(**kwargs) |
str |
将整个对话序列化为单个字符串(不推荐,仅用于兼容) |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
# 基础模板
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一位专业的{role}顾问。"),
("human", "请帮我分析{issue}的问题。"),
])
# 1. format_messages(**kwargs) - 返回 List[BaseMessage]
messages = chat_prompt.format_messages(role="财务", issue="税务筹划")
for msg in messages:
print(f" {type(msg).__name__}: {msg.content}")
# 2. format_prompt(**kwargs) - 返回 PromptValue
prompt_value = chat_prompt.format_prompt(role="法律", issue="合同审查")
print(f"to_messages(): {prompt_value.to_messages()}")
print(f"to_string():\n{prompt_value.to_string()}")
# 3. invoke(input) - 返回 PromptValue
result = chat_prompt.invoke({"role": "医疗", "issue": "健康管理"})
print(f"to_messages(): {result.to_messages()}")
# 4. partial(**kwargs) - 返回 ChatPromptTemplate
partial_prompt = chat_prompt.partial(role="教育")
# 现在只需填充 issue
partial_messages = partial_prompt.format_messages(issue="在线教学")
print(f"部分填充后的消息:\n{partial_messages}")
# 5. format(**kwargs) - 返回 str(不推荐)
result_str = chat_prompt.format(role="科技", issue="AI伦理")
print(f"字符串结果:\n{result_str}")
# 6. 使用 MessagesPlaceholder
chat_prompt_with_history = ChatPromptTemplate.from_messages([
("system", "你是有用的助手。"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
history = [
HumanMessage(content="你好,我想了解LangChain"),
AIMessage(content="LangChain是一个开发LLM应用的框架。"),
]
# 使用 format_messages
full_messages = chat_prompt_with_history.format_messages(
history=history,
input="它支持哪些特性?"
)
for msg in full_messages:
print(f" {type(msg).__name__}: {msg.content[:30]}...")
- 消息角色简写对照
| 元组简写 | 等价类 | 说明 |
|---|---|---|
("system", "内容") |
SystemMessagePromptTemplate |
系统指令 |
("human", "内容") |
HumanMessagePromptTemplate |
用户输入 |
("ai", "内容") |
AIMessagePromptTemplate |
AI 回复示例 |
("placeholder", "{变量名}") |
MessagesPlaceholder |
动态插入历史消息列表 |
核心原理
ChatPromptTemplate 构建的是一个由 BaseMessage 对象组成的列表,每个消息都带有角色标识------system、human/user、ai------这恰好对应了现代聊天模型 API 的输入格式
在 LangChain 0.2.24 版本之后,可以直接使用 ChatPromptTemplate() 构造函数初始化模板;在此版本之前,需要使用 ChatPromptTemplate.from_messages() 方法
MessagesPlaceholder 补充说明
MessagesPlaceholder 是 ChatPromptTemplate 中用于动态插入消息列表的特殊消息模板。它是一个占位符类,用于在对话中注入历史消息或动态生成的消息序列
from langchain_core.prompts import MessagesPlaceholder
class MessagesPlaceholder:
def __init__(
self,
variable_name: str,
optional: bool = False,
):
...
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
variable_name |
str |
必需 | 变量名,在 format_messages() 或 invoke() 中需传入对应名称的消息列表 |
optional |
bool |
可选 | 是否允许该占位符为空(不传入对应变量),默认 False |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
# 1. 基础用法:插入对话历史
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个有帮助的助手。"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{user_input}"),
])
history = [
HumanMessage(content="你好,我想学Python"),
AIMessage(content="太好了!Python是一门非常实用的编程语言。")
]
# format_messages 填充
messages = chat_prompt.format_messages(
chat_history=history,
user_input="我应该从哪里开始?"
)
for msg in messages:
print(f" {type(msg).__name__}: {msg.content}")
print("=" * 70)
# 2. 多个占位符
chat_prompt_multi = ChatPromptTemplate.from_messages([
("system", "你是AI助手。"),
MessagesPlaceholder(variable_name="context"), # 上下文消息(如检索结果)
MessagesPlaceholder(variable_name="history"), # 对话历史
("human", "{question}"),
])
context_msgs = [
AIMessage(content="相关文档:LangChain是一个框架..."),
]
history_msgs = [
HumanMessage(content="什么是LangChain?"),
AIMessage(content="LangChain是一个用于构建LLM应用的框架。")
]
result = chat_prompt_multi.format_messages(
context=context_msgs,
history=history_msgs,
question="它有哪些核心组件?"
)
for msg in result:
print(f" {type(msg).__name__}: {msg.content[:40]}...")
print("=" * 70)
# 3. optional=True 允许不传入
chat_prompt_optional = ChatPromptTemplate.from_messages([
("system", "你是助手。"),
MessagesPlaceholder(variable_name="optional_history", optional=True),
("human", "{input}"),
])
# 不传入 optional_history 也不会报错
messages_optional = chat_prompt_optional.format_messages(input="你好")
print("【optional=True 允许为空】")
for msg in messages_optional:
print(f" {type(msg).__name__}: {msg.content}")
2.4. FewShotChatMessagePromptTemplate:面向聊天模型的少样本提示模板
它的核心作用是,通过在提示词中嵌入一组结构化的对话示例(Examples),来引导模型理解并模仿特定的对话模式或任务逻辑
from langchain_core.prompts import FewShotChatMessagePromptTemplate, ChatPromptTemplate
from langchain_core.example_selectors import BaseExampleSelector
from typing import Optional, List, Dict, Any, Union
from langchain_core.prompts.chat import BaseMessagePromptTemplate
class FewShotChatMessagePromptTemplate(BaseChatPromptTemplate):
def __init__(
self,
examples: Optional[List[Dict[str, Any]]] = None,
example_selector: Optional[BaseExampleSelector] = None,
example_prompt: Union[BaseMessagePromptTemplate, ChatPromptTemplate] = None,
input_variables: Optional[List[str]] = None,
partial_variables: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> None:
...
- 核心参数详解
| 参数名称 | 类型 | 是否必需 | 说明 |
|---|---|---|---|
examples |
Optional[List[Dict[str, Any]]] |
二选一 | 静态示例列表,每个示例是字典,键对应 example_prompt 中的变量。 与 example_selector 二选一 |
example_selector |
Optional[BaseExampleSelector] |
二选一 | 动态示例选择器,根据输入智能选择相关示例。与 examples 二选一 |
example_prompt |
Union[BaseMessagePromptTemplate, ChatPromptTemplate] |
必需 | 用于格式化单个示例的消息模板 (可以是 ChatPromptTemplate 或 BaseMessagePromptTemplate),将示例字典转换为消息列表 |
input_variables |
Optional[List[str]] |
必需 | 最终模板中所有变量名 (包括 example_prompt 和任何前缀/后缀中的变量) |
partial_variables |
Optional[Dict[str, Any]] |
可选 | 预填充的变量(静态值或动态函数) |
**kwargs |
Any |
可选 | 其他参数(如 template_format、validate_template 等,但通常无需关心) |
与 FewShotPromptTemplate 不同,FewShotChatMessagePromptTemplate 没有 prefix 和 suffix 参数,因为消息序列化更灵活。如需添加系统提示或用户问题,应将其作为独立的消息模板与 FewShotChatMessagePromptTemplate 组合使用(例如通过 ChatPromptTemplate.from_messages(system_msg, few_shot, user_msg))
- 核心方法
| 方法 | 返回类型 | 说明 |
|---|---|---|
format_messages(**kwargs) |
List[BaseMessage] |
核心方法。填充模板并返回消息列表,包含示例消息(可能包含多条消息,因为示例可以包含多个角色) |
format_prompt(**kwargs) |
PromptValue |
返回 PromptValue 对象(ChatPromptValue),可通过 to_messages() 或 to_string() 转换 |
invoke(input) |
PromptValue |
标准化 Runnable 接口,返回 PromptValue |
partial(**kwargs) |
FewShotChatMessagePromptTemplate |
预填充部分变量,返回新模板 |
format(**kwargs) |
str |
不推荐,仅为兼容而存在(会序列化为字符串) |
from_examples() |
FewShotChatMessagePromptTemplate |
类方法 ,从示例列表、示例分隔符等快捷创建(类似于 FewShotPromptTemplate.from_examples) |
from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate
from langchain_core.messages import HumanMessage, AIMessage
# 示例数据
examples = [
{"english": "Hello", "chinese": "你好"},
{"english": "How are you", "chinese": "你好吗"},
{"english": "Good morning", "chinese": "早上好"},
]
# 示例模板:每个示例包含一条 HumanMessage 和一条 AIMessage
example_prompt = ChatPromptTemplate.from_messages([
("human", "英文:{english}"),
("ai", "中文:{chinese}"),
])
# 1. from_examples() - 类方法快捷创建
few_shot = FewShotChatMessagePromptTemplate.from_examples(
examples=examples,
example_prompt=example_prompt,
input_variables=[], # 示例中没有额外变量
)
# 组合到完整提示(加入系统指令和用户问题)
final_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个翻译助手,请将英文翻译成中文。"),
few_shot,
("human", "英文:{user_input}"),
])
# 2. format_messages(**kwargs) - 返回 List[BaseMessage]
messages = final_prompt.format_messages(user_input="Goodbye")
for idx, msg in enumerate(messages):
print(f" {idx+1}. {type(msg).__name__}: {msg.content}")
# 3. format_prompt(**kwargs) - 返回 PromptValue
prompt_value = final_prompt.format_prompt(user_input="Thank you")
print(f"to_messages(): {prompt_value.to_messages()}")
print(f"to_string():\n{prompt_value.to_string()}")
# 4. invoke(input) - 返回 PromptValue
result = final_prompt.invoke({"user_input": "Good night"})
print(f"to_messages(): {result.to_messages()}")
# 5. partial(**kwargs) - 返回 FewShotChatMessagePromptTemplate
examples_with_lang = [
{"source": "Hello", "target": "你好"},
{"source": "How are you", "target": "你好吗"},
]
example_prompt_with_lang = ChatPromptTemplate.from_messages([
("human", "{source_lang}:{source}"),
("ai", "{target_lang}:{target}"),
])
few_shot_with_lang = FewShotChatMessagePromptTemplate(
examples=examples_with_lang,
example_prompt=example_prompt_with_lang,
input_variables=["source", "target", "source_lang", "target_lang"] # 注意变量
)
# 使用 partial 预填充语言名称
partial_few_shot = few_shot_with_lang.partial(source_lang="英文", target_lang="中文")
# 现在只需填充 source 和 target(target 在示例中已固定,但我们仍可传入)
# 组合使用
partial_final = ChatPromptTemplate.from_messages([
partial_few_shot,
("human", "{source_lang}:{user_input}"),
])
# 注意:partial_final 中仍有 source_lang 变量,但我们已预填充,所以无需传
result_partial = partial_final.format_messages(user_input="Goodbye", source="Goodbye", target="再见")
for msg in result_partial:
print(f" {type(msg).__name__}: {msg.content}")
核心原理
定义时(组合阶段):final_prompt 只是持有一个引用 ,将 few_shot 作为其消息列表中的一个元素(类型为 FewShotChatMessagePromptTemplate)。此时不会生成任何具体的消息对象。
调用时(渲染阶段):当你调用 final_prompt.format_messages(user_input="...") 时,系统会遍历 final_prompt 中的所有元素:遇到普通的 ("system", "...") 或 ("human", "..."),直接渲染为单条消息;遇到 few_shot 对象时,会调用它的 format_messages() 方法,该方法会遍历所有示例,将每个示例通过 example_prompt 渲染成多条消息(如 HumanMessage + AIMessage),然后将这些消息全部"铺平"展开,合并到最终的消息列表中
PromptTemplate 系列模板详细对比
| 对比维度 | PromptTemplate | FewShot PromptTemplate | Chat PromptTemplate | FewShotChatMessage PromptTemplate |
|---|---|---|---|---|
| 适用场景 | 单条文本提示词 | 少样本文本提示词(给示例后提问) | 多轮对话提示词(ChatModel) | 少样本对话提示词 (给示例后提问,用于 ChatModel) |
| 输出格式 | 纯字符串(str) |
纯字符串(str) |
消息列表 | 消息列表 |
input_variables 要求 |
必须包含模板中的所有变量 | 必须包含 prefix/suffix 中的所有变量(示例中变量由 example_prompt 自行管理) |
可选(自动从所有消息模板中提取) | 可选(自动从所有消息模板中提取) |
invoke 返回类型 |
str |
str |
PromptValue(具体为 ChatPromptValue) |
PromptValue(具体为 ChatPromptValue) |
format方法 |
核心,返回 str |
核心,返回 str |
可用,返回 str(不推荐) |
可用,返回 str (不推荐) |
| 常见组合方式 | 独立使用或作为链的一部分 | 独立使用或作为链的一部分 | 通常与 ChatModel 配合 |
通常作为 ChatPromptTemplate.messages 列表中的一个元素 |
- 简单单轮问答 → PromptTemplate
- 需要少量示例指导 → FewShotPromptTemplate
- 多轮对话或需要角色区分 → ChatPromptTemplate
- 需要在对话中嵌入示例 → FewShotChatMessagePromptTemplate(通常与 ChatPromptTemplate 组合使用)
3.少样本提示(Few-Shot Prompting)
少样本提示是一种通过向 LLM 提供少量输入-输出示例,引导模型按照示例的格式、风格或推理逻辑来回答新问题的技术。它让模型"照猫画虎",显著提升输出的一致性和准确性
- 对于文本模型,FewShotPromptTemplate 将示例、前缀指令和动态输入按固定结构组合为完整的提示词
- 对于聊天模型, FewShotChatMessagePromptTemplate 将示例集中的每个样本格式化为 HumanMessage → AIMessage 的消息对
tool_example_to_messages 函数
tool_example_to_messages 是 LangChain 中一个用于将工具调用示例转换为标准消息列表 的工具函数。它的主要用途是为支持工具调用的模型(如 OpenAI、Claude 等)创建少样本(Few-shot)提示词。
- 示范作用:向模型清晰展示了"何时调用工具、如何组织调用参数、如何关联结果"的完整模式
- 强制关联:通过自动生成并传递 tool_call_id,确保模型学习到正确的 ID 绑定规则,避免推理时消息错位
- 简化输入:允许直接传入 Pydantic 模型,无需手动构造字典,提升代码可读性和类型安全性
from langchain_core.messages import tool_example_to_messages
from typing import List, Dict, Any, Optional
def tool_example_to_messages(
input: str,
tool_calls: Optional[List[Dict[str, Any]]] = None,
tool_outputs: Optional[List[Dict[str, Any]]] = None,
*,
tool_call_id: Optional[str] = None,
**kwargs: Any,
) -> List[BaseMessage]:
...
- 参数详细说明
| 参数 | 类型 | 必填性 | 说明 |
|---|---|---|---|
input |
str |
必需 | 用户的原始输入文本(即用户说了什么), 将包装为 HumanMessage |
tool_calls |
List[BaseModel] 或 List[Dict[str, Any]] |
通常必需 | 期望模型执行的工具调用列表。每个调用可表示为 Pydantic BaseModel(含 name、args、id 字段)或字典(含 "name"、"args"、"id")。将包装为 AIMessage(带 tool_calls 属性) 。如不提供,则不会生成 AIMessage 和后续 ToolMessage |
tool_outputs |
Optional[List[str] 或 List[Dict]] |
可选 | 工具调用的结果列表,与 tool_calls 一一对应。若提供字符串列表,则每个字符串将作为 ToolMessage 的 content;若提供字典列表,可额外指定 "tool_call_id" 以匹配具体调用。若不提供,会插入占位符(如 "placeholder")或直接跳过(取决于实现) |
ai_response |
Optional[str] |
可选 | (部分版本支持) 如果提供,会在消息列表末尾附加一条 AIMessage,其 content 为该字符串,可用于展示模型最终回复(例如在工具调用后) |
tool_call_id |
Optional[str] |
可选 | (兼容旧版本) 当只有一个工具调用且未在 tool_calls 中指定 ID 时,可为所有 ToolMessage 指定统一的 ID;若 tool_outputs 中亦未提供 ID,则自动生成 |
**kwargs |
Any |
可选 | 其他传递给消息构造时的额外参数(如 additional_kwargs、response_metadata 等),会附加到生成的消息上 |
返回值类型:ListBaseMessage
生成的消息序列会按以下顺序生成消息:
-
HumanMessage: 包含用户的输入 input
-
AIMessage: 包含工具调用信息 tool_calls
-
ToolMessage (每个工具调用一个): 包含对应工具的执行结果 tool_outputs 或占位符
-
AIMessage (可选): 如果提供了 ai_response,则作为最终的回答
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.utils.function_calling import tool_example_to_messages
from langchain_openai import ChatOpenAI
from typing import Optional, List
from pydantic import BaseModel, Field1.定义模型
model = ChatOpenAI(model="gpt-4o-mini")
2.定义结构化输出对象
class Person(BaseModel):
"""⼀个⼈的信息。"""
# 注意:
# 1. 每个字段都是 Optional "可选的" ------ 允许 LLM 在不知道答案时输出 None。
# 2. 每个字段都有⼀个 description "描述" ------ LLM使⽤这个描述。
# 有⼀个好的描述可以帮助提⾼提取结果。
name: Optional[str] = Field(default=None, description="这个⼈的名字")
hair_color: Optional[str] = Field(default=None, description="如果知道这个⼈头发的颜⾊")
skin_color: Optional[str] = Field(default=None, description="如果知道这个⼈的肤⾊")
height_in_meters: Optional[str] = Field(default=None, description="以⽶为单位的⾼度")class Data(BaseModel):
people : List[Person] = Field(description="人员列表")3.模型包装
structured_model = model.with_structured_output(Data)
4.定义示例
examples =[
(
"海洋是广阔的、蓝色的。它有两万多英尺深",
Data(people=[])
),
(
"小明在跳舞,1米78的身高看起来很灵活",
Data(people=[Person(name='小明',hair_color=None, skin_color=None, height_in_meters='1.78')])
)
]5.定义提示词模板
prompt_template = ChatPromptTemplate(
[
SystemMessage(content="你是⼀个提取信息的专家,只从⽂本中提取相关信息。如果您不知道要提取的属性的值,属性值返回null"),
MessagesPlaceholder("example_message"),
("human", "{new_message}")
]
)6.将示例转换为消息
example_messages = []
for txt, tool_call in examples:
if tool_call.people:
ai_message = "检测到人"
else:
ai_message = "未检测到人"
example_messages.extend(
tool_example_to_messages(
txt,
[tool_call],
ai_response=ai_message,
)
)
#[HumanMessage(content='海洋是广阔的、蓝色的。它有两万多英尺深', additional_kwargs={}, response_metadata={}),
AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'bf438cc1-ae03-4ba0-be6d-f88badc2e5ed', 'type': 'function', 'function': {'name': 'Data', 'arguments': '{"people":[]}'}}]}, response_metadata={}, tool_calls=[{'name': 'Data', 'args': {'people': []}, 'id': 'bf438cc1-ae03-4ba0-be6d-f88badc2e5ed', 'type': 'tool_call'}], invalid_tool_calls=[]),
ToolMessage(content='You have correctly called this tool.', tool_call_id='bf438cc1-ae03-4ba0-be6d-f88badc2e5ed'),
AIMessage(content='未检测到人', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[]),
HumanMessage(content='小明在跳舞,1米78的身高看起来很灵活', additional_kwargs={}, response_metadata={}),
AIMessage(content='', additional_kwargs={'tool_calls': [{'id': '3373f260-4655-46b3-afb6-da9cfbb52810', 'type': 'function', 'function': {'name': 'Data', 'arguments': '{"people":[{"name":"小明","hair_color":null,"skin_color":null,"height_in_meters":"1.78"}]}'}}]}, response_metadata={}, tool_calls=[{'name': 'Data', 'args': {'people': [{'name': '小明', 'hair_color': None, 'skin_color': None, 'height_in_meters': '1.78'}]}, 'id': '3373f260-4655-46b3-afb6-da9cfbb52810', 'type': 'tool_call'}], invalid_tool_calls=[]),
ToolMessage(content='You have correctly called this tool.', tool_call_id='3373f260-4655-46b3-afb6-da9cfbb52810'),
AIMessage(content='检测到人', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[])
]
print(example_messages)
# 7.定义并执行链 deepseek不支持with_structured_output
chain = prompt_template | structured_model
print(chain.invoke(
{
"example_message": example_messages,
"new_message": "篮球场上,⾝⾼两⽶的中锋王伟默契地将球传给⼀⽶七的后卫挚友李明,完成⼀记绝杀"
}
))
tool_example_to_messages 将静态的 Pydantic 示例数据,转化为模型在原生工具调用场景中能够直接理解并模仿的完整对话消息序列。它通过模拟"用户提问 → 模型决策(携带精确参数的 tool_calls)→ 工具执行反馈 → 最终自然语言回复"的闭环,不仅精准教会了模型如何按 Data 和 Person 的格式填写结构化参数,更利用"检测到人/未检测到人"的正反例结尾,为模型建立了清晰的决策边界(即什么情况该输出空列表,什么情况该填充数据),从而在保障输出格式绝对正确的同时,极大地抑制了模型在信息缺失时随意编造内容(幻觉)的风险,将少样本提示从"文字描述"升级为了"可执行的交互式范式"
核心原理
(1)强制建立"工具调用 ID"绑定关系,使模型在推理时不会混淆不同调用的结果
当你在 tool_calls 中未指定每个调用的 id 时,函数会自动为每个调用生成一个随机 UUID(如 "call_8f7d3a")。
生成的 AIMessage 会携带这些 id,并填充到其 tool_calls 字段中。
对于 tool_outputs,函数会将每个输出构造为 ToolMessage,并强制其 tool_call_id 与对应的 AIMessage 中的 id 相匹配(若 tool_outputs 中未提供 tool_call_id,则按顺序自动关联)。
这样,示例消息序列明确展示了"请求-响应"的配对规则,模型在后续真实推理中才会严格遵循这个 ID 关联逻辑。
(2)Pydantic 对象的"序列化解构"
当你传入 tool_calls 参数时,支持两种格式:
- Pydantic 模型实例(如 GetWeather(city="上海"))
- 字典(如 {"name": "get_weather", "args": {"city": "上海"}})
若传入的是 Pydantic 实例,函数内部会进行以下转换:
| 步骤 | 操作 | 结果 |
|---|---|---|
| 1. 提取类名 | 调用 instance.__class__.__name__ |
"GetWeather"(作为工具名称) |
| 2. 提取参数 | 调用 instance.model_dump()(或旧版 .dict()) |
{"city": "上海"} |
| 3. 生成 ID | 调用 uuid.uuid4().hex 或类似方式 |
如 "call_8f7d3a" |
| 4. 构造调用项 | 组装为字典 | {"name": "GetWeather", "args": {"city": "上海"}, "id": "call_8f7d3a", "type": "tool_call"} |
最终,这些调用项会被放入 AIMessage 的 tool_calls 字段中
4. LangChain Hub:提示词的"GitHub"
LangChain Hub 是一个用于上传、浏览、拉取和管理提示词 的平台。它类似于 GitHub 之于代码------开发者可以分享和发现优质的提示模板,加速应用开发