# 1、最基础的提示词模板 PromptTemplate
最早期、面向单轮纯文本 的提示模板(对应老的 LLM 接口),主要生成 一个字符串 prompt。
导入方式
from langchain_core.prompts import PromptTemplate
使用示例
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
llm = ChatOpenAI(
base_url=os.getenv('OPENAI_BASE_URL'),
api_key=os.getenv('OPENAI_API_KEY'),
model=os.getenv('OPENAI_MODEL'),
temperature=0.5
)
template = '''
我想去{location}旅行,给我一些建议!
'''
prompt = PromptTemplate(
input_variables=["location"],
template=template
)
final_prompt = prompt.format(location='邢台')
print(f'最终提示词:{final_prompt}')
print(llm.invoke(final_prompt))
完整输出
最终提示词:
我想去邢台旅行,给我一些建议!
落:感受古老的民居建筑和传统村落风貌。\n - 赵氏孤儿纪念馆:了解中国古代著名的忠义故事。\n - 司马台长城:如果喜欢户外和历史,可以登长城,俯瞰壮丽的景色。\n - 南和县的天河山:适合登山和自然爱好者,风景优美。\n2. 美食推荐:\n - 邢台特色小吃:如羊肉泡馍、面食、豆腐乳等。\n - 品尝当地的农家菜,体验地道的河北风味。\n3. 交通建议:\n - 邢台有火车站,方便乘坐火车到达。\n - 市内交通可以选择公交或打车,方便前往各大景点。\n4. 最佳旅行时间:\n - 春秋季(3-5月、9-11月)天气宜人,适合旅游。\n - 避开夏季的高温和冬季的寒冷。\n5. 其他建议:\n - 提前安排住宿,选择市中心或景点附近的酒店。\n - 尊重当地习俗,注意环境保护。\n - 可以提前查阅一些旅游攻略或联系当地导游,获得更丰富的体验。\n\n希望这些建议对你的邢台之旅有所帮助!祝你旅途愉快!' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 390, 'prompt_tokens': 22, 'total_tokens': 412, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'gpt-4.1-nano-2025-04-14', 'system_fingerprint': 'fp_1a97b5aa6c', 'id': 'chatcmpl-CiHFbdC8Ep3sTlPMt1fpPcJJToOBN', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--dd8ecfe0-2979-4fe1-9f3f-a7cb2351bba8-0' usage_metadata={'input_tokens': 22, 'output_tokens': 390, 'total_tokens': 412, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}
# 2、ChatPromptTemplate
面向 聊天模型(ChatModel / ChatOpenAI) 的模板,生成的是 一串消息对象列表(System / Human / AI / Tool 等 message),可以更好地表达多轮对话结构。
# 一、ChatPromptTemplate 是什么?
官方定义(翻译一下精简版):
“用于聊天模型的提示模板,用来为聊天模型创建灵活的模板化 prompt。”
它继承自 BaseChatPromptTemplate,本身就是一个 Runnable,可以直接 prompt | model 这样接在链上。
# 二、基本用法:最常见的 3 种构造方式
# 1. 直接用构造函数传入 messages 列表(最原始写法)
官方示例:
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate(
[
("system", "You are a helpful AI bot. Your name is {name}."),
("human", "Hello, how are you doing?"),
("ai", "I'm doing well, thanks!"),
("human", "{user_input}"),
]
)
prompt_value = template.invoke(
{
"name": "Bob",
"user_input": "What is your name?",
}
)
# prompt_value 是 ChatPromptValue,里面有 messages 列表
要点:
messages列表中的每一项都可以是:- 元组形式:
("system" | "human" | "ai" | "tool" | "placeholder", 模板字符串) - 或者更底层的
SystemMessagePromptTemplate、HumanMessagePromptTemplate等实例
- 元组形式:
{name}、{user_input}是变量,调用invoke()/format_messages()时用参数填充。
# 2. 使用 from_messages(推荐)
from_messages 是官方推荐的构造方式之一,用法跟构造函数几乎一样,只是更清晰:
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
llm = ChatOpenAI(
base_url=os.getenv('OPENAI_BASE_URL'),
api_key=os.getenv('OPENAI_API_KEY'),
model=os.getenv('OPENAI_MODEL'),
temperature=0.5
)
prompt = ChatPromptTemplate.from_messages([
('system', '你是一个专业的旅游顾问,你的名字叫{name}'),
('human', '我要去{city}'),
('human', '偏好:{preference}')
])
prompt_value = prompt.invoke({
'name': '小旅',
'city': '青岛',
'preference': '喜欢看海'
})
print(prompt_value)
print(llm.invoke(prompt_value))
适用场景:
多条消息、多角色 的结构化 prompt(system + 多条 human/ai/tool)。
# 3. 使用 from_template(只有一条 human 消息时很方便)
from_template 用来把一个字符串模板直接包成 单条 human 消息 的 chat prompt:
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_template(
"请用中文介绍一下{city}的必去景点和特色美食。"
)
# 等价于:messages = [("human", "请用中文介绍一下{city}的必去景点和特色美食。")]
prompt_value = prompt.invoke({"city": "邢台"})
适合快速把“原来写给文本模型的 PromptTemplate”迁移到 chat 模式:
原来:
PromptTemplate.from_template("...{city}...")
现在:ChatPromptTemplate.from_template("...{city}...")
# 三、调用方式:invoke / format_messages / format
ChatPromptTemplate 是 Runnable,有一整套 runnable 接口。官方接口说明里列了:invoke / ainvoke / batch / abatch / stream / astream
一般会用这几个:
# 1. invoke():直接得到 ChatPromptValue(最常用)
prompt_value = prompt.invoke({"city": "邢台"})
messages = prompt_value.to_messages() # list[BaseMessage]
- 结果是
ChatPromptValue,里面包装了最终的messages。
# 2. format_messages():直接拿消息列表
官方说明:”Format the chat template into a list of finalized messages.“
接收的是关键字参数,不是字典。
messages = prompt.format_messages(city="邢台")
# -> [SystemMessage(...), HumanMessage(...), ...]
常用场景:自己有模型调用逻辑,想直接传 messages 给模型。
# 3. format():把 chat prompt 展开成单个字符串(调试或兼容老逻辑)
官方说明:Format the chat template into a string.
text = prompt.format(city="邢台")
print(text)
- 实际项目里:给 chat 模型用不太常用,更多是用来打印/调试。
# 四、单变量快捷调用(Single-variable template)
如果模板中只存在 一个变量,文档里说你可以直接传非 dict 参数,自动映射到那个变量:
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate(
[
("system", "You are a helpful AI bot. Your name is Carl."),
("human", "{user_input}"),
]
)
prompt_value = template.invoke("Hello, there!")
# 等价于 template.invoke({"user_input": "Hello, there!"})
这个在做简单包装时很好用,比如“把用户输入直接塞到 {input} 里”。
# 五、MessagesPlaceholder:注入历史对话 / scratchpad
文档里专门有一节 Messages Placeholder 示例:
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate(
[
("system", "You are a helpful AI bot."),
# 这个 placeholder 会从变量 "conversation" 里一串消息
("placeholder", "{conversation}"),
# 等价于:MessagesPlaceholder(variable_name="conversation", optional=True)
]
)
prompt_value = template.invoke(
{
"conversation": [
("human", "Hi!"),
("ai", "How can I assist you today?"),
("human", "Can you make me an ice cream sundae?"),
("ai", "No."),
]
}
)
结果会把 system + 传入的对话历史拼在一起,变成一串 SystemMessage / HumanMessage / AIMessage。
打印prompt_value输出如下:
messages=[SystemMessage(content='You are a helpful AI bot.', additional_kwargs={}, response_metadata={}), HumanMessage(content='Hi!', additional_kwargs={}, response_metadata={}), AIMessage(content='How can I assist you today?', additional_kwargs={}, response_metadata={}), HumanMessage(content='Can you make me an ice cream sundae?', additional_kwargs={}, response_metadata={}), AIMessage(content='No.', additional_kwargs={}, response_metadata={})]
在 1.0 风格里,常见用法有两个:
-
注入 chat_history(检索问答、多轮对话)
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_openai import ChatOpenAI from dotenv import load_dotenv import os load_dotenv() llm = ChatOpenAI( base_url=os.getenv('OPENAI_BASE_URL'), api_key=os.getenv('OPENAI_API_KEY'), model=os.getenv('OPENAI_MODEL'), temperature=0.5 ) template = ChatPromptTemplate( [ ("system", "You are a helpful AI bot."), MessagesPlaceholder('history'), ('human', '{input}') ] ) prompt_value = template.invoke( { "history": [ ("human", "Hi!"), ("ai", "How can I assist you today?"), ("human", "Can you make me an ice cream sundae?"), ("ai", "No."), ], "input": "What about a milkshake?" } ) print(prompt_value) print(llm.invoke(prompt_value))messages=[SystemMessage(content='You are a helpful AI bot.', additional_kwargs={}, response_metadata={}), HumanMessage(content='Hi!', additional_kwargs={}, response_metadata={}), AIMessage(content='How can I assist you today?', additional_kwargs={}, response_metadata={}), HumanMessage(content='Can you make me an ice cream sundae?', additional_kwargs={}, response_metadata={}), AIMessage(content='No.', additional_kwargs={}, response_metadata={}), HumanMessage(content='What about a milkshake?', additional_kwargs={}, response_metadata={})] content="I can't make a milkshake for you, but I can definitely help you with a great recipe! Would you like a classic vanilla, chocolate, or something more adventurous?" additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 34, 'prompt_tokens': 61, 'total_tokens': 95, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'gpt-4.1-mini-2025-04-14', 'system_fingerprint': 'fp_9766e549b2', 'id': 'chatcmpl-Cj2DQzKI4Bl1F7ewM96JgXcVVNJ4k', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--aab2463c-53f0-44f5-aca4-693cf53426ce-0' usage_metadata={'input_tokens': 61, 'output_tokens': 34, 'total_tokens': 95, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}} -
Agent 的
agent_scratchpad:工具调用的 action / observation 会作为消息列表注入,这在 Agent 相关文档里一堆例子都有。
# 六、和 Chat 模型拼在一起用(链式写法)
结合 1.0 的 Runnable 风格,你真正落地时通常会这么写:
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from dotenv import load_dotenv
import os
load_dotenv()
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业、简洁的旅游顾问。"),
MessagesPlaceholder("history", optional=True),
("human", "{input}"),
])
model = ChatOpenAI(
base_url=os.getenv('OPENAI_BASE_URL'),
api_key=os.getenv('OPENAI_API_KEY'),
model=os.getenv('OPENAI_MODEL'),
temperature=0.5
)
parser = StrOutputParser()
# 组装成链:输入 dict -> prompt -> model -> 文本
chain = prompt | model | parser
# 首轮对话
res1 = chain.invoke({
"input": "帮我规划一下在邢台的一日游。",
"history": [],
})
# 第二轮,把历史塞回去
history = [
("human", "帮我规划一下在邢台的一日游。"),
("ai", res1),
]
res2 = chain.invoke({
"input": "顺便推荐几样当地特色美食。",
"history": history,
})
print("第一轮回复:", res1)
print("\n第二轮回复:", res2)
第一轮回复: 当然可以!以下是邢台一日游的推荐行程:
**上午:**
1. **广府古城**
- 参观时间:约2小时
- 特色:保存完好的明清古建筑群,感受古城风貌和历史文化。
- 建议:漫步古城街巷,品尝当地小吃。
2. **天河山国家森林公园**
- 参观时间:约2小时
- 特色:自然风光优美,有登山步道和瀑布景观,适合轻松徒步。
**中午:**
- 在广府古城附近品尝邢台特色美食,如驴肉火烧、豆腐脑等。
**下午:**
3. **邢台博物馆**
- 参观时间:约1.5小时
- 特色:了解邢台的历史、文化和民俗,馆内展品丰富。
4. **清风峡景区**
- 参观时间:约2小时
- 特色:峡谷风光秀丽,有溪流、奇石和古刹,适合拍照和放松。
**晚上:**
- 可选择在市区用晚餐,推荐尝试当地特色菜肴。
- 若时间允许,可逛逛邢台市中心的商业街区,感受当地夜生活。
如果有特别兴趣或需求,也可以告诉我,我帮你调整行程!
第二轮回复: 当然,邢台的特色美食有很多,以下几样非常值得尝试:
1. **驴肉火烧**
- 特色:酥脆的火烧夹着鲜嫩的驴肉,香气浓郁,是邢台著名小吃。
2. **邢台豆腐脑**
- 特色:口感细腻,配以特制调料,咸鲜开胃。
3. **烧鸡**
- 特色:邢台烧鸡色泽金黄,肉质鲜嫩多汁,风味独特。
4. **杂粮煎饼**
- 特色:用多种杂粮制作,口感丰富,常搭配辣酱或蔬菜。
5. **羊汤**
- 特色:汤汁浓郁,肉质鲜美,适合冬季食用。
这些美食在广府古城及市区的餐馆都能找到,建议品尝地道小吃,体验地道风味。祝你旅途愉快!
这里完全利用了:
ChatPromptTemplate作为 Runnable 的invoke能力MessagesPlaceholder做多轮历史注入
# 七、进阶:partial / append / extend 等 API
这些在文档的 method 列表里都有:
# 1. partial():预先固定部分变量
“Get a new ChatPromptTemplate with some input variables already filled in.”
base_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个风格为「{style}」的旅游顾问。"),
("human", "{input}"),
])
# 先固定 style
concise_prompt = base_prompt.partial(style="简洁")
detailed_prompt = base_prompt.partial(style="详细、有条理")
# 调用时就只传 input 就行
pv1 = concise_prompt.invoke({"input": "帮我规划邢台一日游"})
pv2 = detailed_prompt.invoke({"input": "帮我规划邢台一日游"})
适合做:同一套逻辑,不同人格 / 不同语气 的版本。
# 2. append() / extend():在代码里动态加消息
官方说明:
append:Append a message to the end of the chat template.extend:Extend the chat template with a sequence of messages.
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个旅游顾问。"),
("human", "{input}"),
])
# 动态追加一条 system 说明
prompt = prompt.append(("system", "回答时请控制在 200 字以内。"))
# 或者追加多条
prompt = prompt.extend([
("human", "如果涉及到邢台,请重点介绍历史景点。")
])
这个在你需要根据配置/环境动态拼 prompt 时很有用,例如 feature flag 控制。
# 3. 其它可能会用到的能力(简单点名)
pretty_print():打印一个人类可读的 prompt 结构(调试用)save():把 prompt 保存到文件get_input_schema()/get_output_schema():以 Pydantic 模型形式暴露输入/输出 schema(类型系统 / UI 集成会用到)__or__/pipe()/map()/with_retry()/with_config():这些都是 Runnable 的组合工具,玩链子玩熟了会经常用。
# 八、一个“从 0 到 1”完整示例
目标:
做一个简单的“旅游问答助手”链,带历史记忆、可复用风格。
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from dotenv import load_dotenv
import os
load_dotenv()
# 1. 定义基础 prompt(可复用)
base_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个风格为「{style}」的中国城市旅游顾问。回答使用简体中文。"),
MessagesPlaceholder("history", optional=True),
("human", "{input}"),
])
# 2. 固定 style = "简洁、分点"
prompt = base_prompt.partial(style="简洁、分点")
# 3. 绑定模型与输出解析
model = ChatOpenAI(
base_url=os.getenv('OPENAI_BASE_URL'),
api_key=os.getenv('OPENAI_API_KEY'),
model=os.getenv('OPENAI_MODEL'),
temperature=0.5
)
parser = StrOutputParser()
chain = prompt | model | parser
# ========== 第 1 轮 ==========
history = []
answer1 = chain.invoke({
"input": "我要去邢台玩一天,帮我规划路线,最好包含古城和山景。",
"history": history,
})
print("A1:", answer1)
history.extend([
("human", "我要去邢台玩一天,帮我规划路线,最好包含古城和山景。"),
("ai", answer1),
])
# ========== 第 2 轮 ==========
answer2 = chain.invoke({
"input": "再推荐几样邢台当地特色美食。",
"history": history,
})
print("A2:", answer2)
history.extend([
("human", "再推荐几样邢台当地特色美食。"),
("ai", answer2),
])
# ========== 第 3 轮 ==========
answer3 = chain.invoke({
"input": "这些景点之间交通怎么安排最合理?",
"history": history,
})
print("A3:", answer3)
history.extend([
("human", "这些景点之间交通怎么安排最合理?"),
("ai", answer3),
])
# ========== 第 4 轮 ==========
answer4 = chain.invoke({
"input": "如果我带父母一起去,有什么需要注意的?",
"history": history,
})
print("A4:", answer4)
history.extend([
("human", "如果我带父母一起去,有什么需要注意的?"),
("ai", answer4),
])
# ========== 第 5 轮 ==========
answer5 = chain.invoke({
"input": "最后帮我按时间顺序整理成一份简洁的一日游行程单。",
"history": history,
})
print("A5:", answer5)
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from dotenv import load_dotenv
import os
load_dotenv()
# 1. 定义基础 prompt(可复用)
base_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个风格为「{style}」的中国城市旅游顾问。回答使用简体中文。"),
MessagesPlaceholder("history", optional=True),
("human", "{input}"),
])
# 2. 固定 style = "简洁、分点"
prompt = base_prompt.partial(style="简洁、分点")
# 3. 绑定模型与输出解析
model = ChatOpenAI(
base_url=os.getenv('OPENAI_BASE_URL'),
api_key=os.getenv('OPENAI_API_KEY'),
model=os.getenv('OPENAI_MODEL'),
temperature=0.5
)
parser = StrOutputParser()
chain = prompt | model | parser
# 关键函数:自动用上一轮的 history + 本轮输入,得到输出并写回 history
def ask(user_input: str, history: list, chain) -> str:
"""
- 使用当前 history 和本轮 user_input 调用链
- 得到 ai_answer
- 自动把 (user_input, ai_answer) 追加到 history
- 返回 ai_answer
"""
ai_answer = chain.invoke({
"input": user_input,
"history": history,
})
# 自动记录上一轮「输入 + 输出」
history.extend([
("human", user_input),
("ai", ai_answer),
])
return ai_answer
if __name__ == "__main__":
history: list[tuple[str, str]] = []
# 第 1 轮
a1 = ask("我要去邢台玩一天,帮我规划路线,最好包含古城和山景。", history, chain)
print("A1:", a1)
# 第 2 轮
a2 = ask("再推荐几样邢台当地特色美食。", history, chain)
print("A2:", a2)
# 第 3 轮
a3 = ask("这些景点之间交通怎么安排最合理?", history, chain)
print("A3:", a3)
# 第 4 轮
a4 = ask("如果我带父母一起去,有什么需要注意的?", history, chain)
print("A4:", a4)
# 第 5 轮
a5 = ask("最后帮我按时间顺序整理成一份简洁的一日游行程单。", history, chain)
print("A5:", a5)