Prompt Template提示词模板
Prompt是与LLM交互的输入,用于定义任务目标、背景和输出要求,其设计质量直接影响模型效果。在实际业务中,输入具有动态性,固定Prompt难以复用且适配性有限。为此,LangChain引入Prompt Template,将静态字符串抽象为可复用模板,并通过变量填充在运行时生成Prompt,从而提升灵活性与可维护性。有关Prompt的更多内容详见:提示词工程指北。
PromptTemplate(基础文本模板)
PromptTemplate是最基础的模板类型,适用于生成纯文本形式的Prompt,其核心能力是通过变量替换实现动态内容生成。PromptTemplate的具体使用见:LangChain PromptTemplate 全解析。
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate.from_template(
“请生成一段话:{task}”
)
prompt_text = prompt.invoke({
“task”: “介绍良好阅读习惯的重要性”
}).text
response = chat_model.invoke(prompt_text)
print(response.content)
这种方式适用于结构简单的单轮任务。但随着任务复杂度提升,仅使用PromptTemplate会逐渐暴露出结构不清晰、可控性不足的问题。
ChatPromptTemplate(对话模板)
在对话模型场景中,直接拼接文本Prompt往往不够清晰,因此LangChain提供了ChatPromptTemplate,用于按角色组织Prompt结构。
from langchain_core.prompts import ChatPromptTemplate
chat_prompt = ChatPromptTemplate.from_messages([
(“system”, “你是一名文言文写作助手,输出一段自然流畅的文字”),
(“human”, “请完成任务:{task}”)
])
messages = chat_prompt.invoke({
“task”: “介绍良好阅读习惯的重要性”
})
response = chat_model.invoke(messages)
print(response.content)
通过显式区分system和human角色,可以让Prompt结构更加清晰,同时也更贴合对话模型的训练方式。不过,当Prompt进一步复杂化时,这种方式仍然存在复用困难的问题。
https://superml.dev/langchain-prompt-template
MessagePromptTemplate(消息模板组件)
为了支持更复杂的Prompt设计,LangChain提供了MessagePromptTemplate,将Prompt拆分为更细粒度的组件。
from langchain_core.prompts import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
)
chat_prompt = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template(
“你是一个擅长写说明性文字的助手,输出必须为一段完整的表述”
),
HumanMessagePromptTemplate.from_template(
“请生成一段话:{task}”
)
])
messages = chat_prompt.invoke({
“task”: “介绍良好阅读习惯的重要性”
})
response = chat_model.invoke(messages)
print(response.content)
在这种方式下,不同角色的Prompt可以独立定义,并按需组合,适用于复杂系统和团队协作开发。但即使结构清晰,模型在输出格式上的稳定性仍难以完全保证。
FewShotPromptTemplate(少样本提示)
当需要模型稳定输出特定格式或风格时,仅依赖Prompt往往不够。FewShotPromptTemplate通过提供示例引导模型模仿既有格式,以示例替代规则,使输出更加稳定和可预测。关于相关概念及更详细的使用说明,可参考:Langchain学习入门。
简单示例如下:
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
example_template = PromptTemplate.from_template(
“单词:{word}, 英文翻译:{translation}”
)
examples_data = [
{“word”: “苹果”, “translation”: “apple”},
{“word”: “快乐”, “translation”: “happy”}
]
few_shot_template = FewShotPromptTemplate(
example_prompt=example_template,
examples=examples_data,
prefix=“请给出一个单词及其英文翻译,以下是示例:”,
suffix=“单词:{input_word},英文翻译:”,
input_variables=[“input_word”]
)
prompt_text = few_shot_template.invoke(
{“input_word”: “计算机”}
).to_string()
print(prompt_text)
response = chat_model.invoke(prompt_text)
print(response.content)
在对话场景中也可以使用基于消息结构的FewShotChatMessagePromptTemplate:
from langchain_core.prompts import (
ChatPromptTemplate,
FewShotChatMessagePromptTemplate,
)
examples = [
{“input”: “你好”, “output”: “Hello”},
{“input”: “谢谢你的帮助”, “output”: “Thank you for your help”},
]
example_prompt = ChatPromptTemplate.from_messages([
(“human”, “{input}”),
(“ai”, “{output}”),
])
few_shot_prompt = FewShotChatMessagePromptTemplate(
example_prompt=example_prompt,
examples=examples,
)
final_prompt = ChatPromptTemplate.from_messages([
(
“system”,
“你是一个翻译助手,将中文翻译成英文。只输出翻译结果,不要提供额外解释。”
),
few_shot_prompt,
(“human”, “{input}”),
])
chain = final_prompt | chat_model
print(chain.invoke({“input”: “今天天气很好”}).content)
print(chain.invoke({“input”: “请稍等一下”}).content)
partial方法(Prompt部分填充)
通过模板实现动态生成Prompt后,常会遇到固定变量反复传递的问题,如目标语言、角色设定或业务背景,手动处理既繁琐又易出错。此时可用partial方法预先填入这些固定内容,相当于提前构建好一部分Prompt。这样便可通过一个通用模板衍生多个可直接使用的版本,简单又高效。
from langchain_core.prompts import ChatPromptTemplate
template = ChatPromptTemplate.from_messages([
(“system”, “将以下文本翻译为{target_lang},保留原意”),
(“human”, “{text}”)
])
zh_translator = template.partial(target_lang=“中文”)
en_translator = template.partial(target_lang=“英文”)
result_zh = zh_translator.invoke({“text”: “Hello world”})
result_en = en_translator.invoke({“text”: “你好,世界”})
print(result_zh.to_messages())
print(result_en.to_messages())
2.4 Output Parser输出解析器
LLM默认返回的是纯字符串,而实际开发中为了进行后续处理,通常需要结构化数据。为此,必须先对模型的输出结果进行解析,借助解析器将文本转换为特定的数据结构。在LangChain中,这类解析器被定义为Output Parser,并提供了多种实现以适配不同的输出格式。
解析器名称 作用
StrOutputParser 将模型输出直接解析为字符串
JsonOutputParser 将模型输出解析为JSON格式的结构化数据
CommaSeparatedListOutputParser 将逗号分隔的文本解析为Python列表
XMLOutputParser 将模型输出解析为XML格式的结构化数据
关于Output Parser的更多介绍见:How to Master Output Parsers,下面通过一个完整示例,演示不同解析器的使用方式:
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import (
StrOutputParser,
JsonOutputParser,
CommaSeparatedListOutputParser,
XMLOutputParser
)
===============================
1. 字符串解析器StrOutputParser(最基础用法)
===============================
str_prompt = PromptTemplate.from_template(
“用一句话介绍什么是{name}”
)
str_chain = str_prompt | chat_model | StrOutputParser()
print(“StrOutput:”, str_chain.invoke({“name”: “LLM”}))
===============================
2. JSON解析器JsonOutputParser(结构化输出)
===============================
json_parser = JsonOutputParser()
json_prompt = PromptTemplate(
template=“用一句话介绍什么是{name}。\n{format_instructions}”,
input_variables=[“name”],
partial_variables={
“format_instructions”: json_parser.get_format_instructions()
}
)
json_chain = json_prompt | chat_model | json_parser
print(“JSON Output:”, json_chain.invoke({“name”: “LLM”}))
===============================
3. 列表解析器CommaSeparatedListOutputParser(列表结构)
===============================
list_parser = CommaSeparatedListOutputParser()
list_prompt = PromptTemplate(
template=“列出{name}的3个特点。\n{format_instructions}”,
input_variables=[“name”],
partial_variables={
“format_instructions”: list_parser.get_format_instructions()
}
)
list_chain = list_prompt | chat_model | list_parser
print(“List Output:”, list_chain.invoke({“name”: “LLM”}))
===============================
4. XML解析器XMLOutputParser(层级结构)
===============================
xml_parser = XMLOutputParser()
xml_prompt = PromptTemplate(
template=“用XML格式输出什么是{name}。\n{format_instructions}”,
input_variables=[“name”],
partial_variables={
“format_instructions”: xml_parser.get_format_instructions()
}
)
xml_chain = xml_prompt | chat_model | xml_parser
print(“XML Output:”, xml_chain.invoke({“name”: “LLM”}))
2.5 Runnable的调用方式
Runnable是LangChain中的核心执行抽象,代表任何可接收输入并产生输出的可执行单元。可以把它理解为一个标准化的接口,无论LLM、提示词模板、输出解析器、检索器、工具还是LangGraph定义的工作流,只要遵循这一接口规范,就都成为了Runnable。这种统一让不同组件可以像积木一样自由拼接和编排,从而构建复杂的应用。
在LangChain 1.x中,这一抽象被进一步统一,Prompt、Model、Parser、Retriever以及Tool等核心组件,均被明确定义为Runnable。由于遵循相同的输入输出规范,一个组件的输出可以直接成为下一个组件的输入,实现模块间的无缝衔接与灵活组合。更详细的说明可阅读:深入解析Runnable接口的统一、组合与流式处理。
统一的执行抽象建立之后,核心问题便转向调用方式。Runnable为此提供了一组标准方法,以覆盖不同的使用场景:
方法 说明
invoke 同步单次调用
stream 流式输出
batch 批量处理
ainvoke 异步单次调用
astream 异步流式输出
abatch 异步批量处理
下面通过简单示例来介绍这些调用方式的实际用法:
import asyncio
def run_invoke():
response = chat_model.invoke(“你好”)
print(“=== invoke ===”)
print(response.content)
print(response.response_metadata)
def run_stream():
print(“\n=== stream ===”)
for chunk in chat_model.stream(“写一篇500字文章”):
print(chunk.content, end=“”, flush=True)
def run_batch():
print(“\n=== batch ===”)
responses = chat_model.batch([
“翻译:hello”,
“翻译:world”,
“翻译:apple”
])
for r in responses:
print(r.content)
async def run_async():
print(“\n=== ainvoke ===”)
response = await chat_model.ainvoke(“异步调用”)
print(response.content)
print("\n=== astream ===") async for chunk in chat_model.astream("讲一个简短故事"): print(chunk.content, end="", flush=True) print() print("\n=== abatch ===") responses = await chat_model.abatch([ "异步翻译:cat", "异步翻译:dog" ]) for r in responses: print(r.content)ifname== “main”:
run_invoke()
run_stream()
run_batch()
asyncio.run(run_async())
2.6 Bind方法
bind方法解决了一个常见需求:同一个模型,在不同任务中往往需要不同的运行参数。例如,做数学计算时希望输出稳定,写文案时又希望富有变化。如果每次都重新实例化模型来切换参数,既繁琐又低效。
bind的作用,就是在一个模型实例上临时附加一组运行参数,比如temperature、max_tokens或stop等,然后返回一个绑定了这些参数的新对象。该方法不会修改原始模型,而是在其基础上生成一个绑定了特定参数的副本,从而允许在不重新实例化模型的前提下灵活切换调用行为。
这一机制常用于根据任务需求动态调整模型策略,例如:
精确策略:绑定temperature=0.0, max_tokens=200,提升输出稳定性与确定性,适用于信息抽取、数学计算等对准确性要求较高的任务;
创意策略:绑定temperature=0.9, max_tokens=1000,增强随机性与表达空间,适用于写作、对话生成等需要开放创造力的任务。
示例:
bind 生成不同策略的实例,原模型不受影响
precise_strategy = chat_model.bind(temperature=0.3, max_tokens=200)
creative_strategy = chat_model.bind(temperature=0.9, max_tokens=1000)
result_precise = precise_strategy.invoke(“12*9=?”)
result_creative = creative_strategy.invoke(“写一首关于夏天的诗”)
print(“=== 精确策略 ===”)
print(result_precise.content)
print(“\n=== 创意策略 ===”)
print(result_creative.content)
3 核心组件
3.1 Chains与LCEL
在LangChain中,Chain可以理解为一条处理任务的流水线。数据会按照预先设定的步骤,依次经过提示词模板、LLM和输出解析器等组件处理,最终输出结果。关于Chain的详细介绍,可参考:LangChain最详细教程之Chains。
LCEL(LangChain Expression Language)用于以声明式方式描述这一结构,将各组件组合为可执行表达式,而不改变底层执行逻辑。最常见的写法是使用管道符|:
chain = prompt | chat_model | parser
该表达式自左向右执行:prompt生成输入,传递至chat_model进行推理,再由parser完成结构化处理,对应完整的Chain流程。可以理解为,Chain定义执行结构,LCEL负责表达结构,|用于连接各Runnable组件并传递数据流。LangChain中Chains与LCEL的关系可以参考:深度拆解LangChain Chains与LCEL。
在实现层面,参与组合的组件都需要实现Runnable接口。多个组件通过|连接后,新的Chain本身仍然是一个Runnable,因此既可以继续与其他组件组合,也可以通过invoke、stream和batch等方式执行任务。
示例:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.documents import Document
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableLambda
Math Chain
math_prompt = ChatPromptTemplate.from_template(
“请计算下面数学问题:{input}”
)
math_chain = (
math_prompt
| chat_model
| StrOutputParser()
)
print(
math_chain.invoke({
“input”: “25乘以8等于多少?”
})
)
MultiPrompt / Router Chain
translate_prompt = ChatPromptTemplate.from_template(
“请翻译下面内容:\n{input}”
)
summary_prompt = ChatPromptTemplate.from_template(
“请总结下面内容:\n{input}”
)
translate_chain = (
translate_prompt
| chat_model
| StrOutputParser()
)
summary_chain = (
summary_prompt
| chat_model
| StrOutputParser()
)
def router(x):
text = x[“input”]
if “翻译” in text or “translate” in text.lower():
return translate_chain
return summary_chain
router_chain = RunnableLambda(router)
print(
router_chain.invoke({
“input”: “Technology makes life better.”
})
)
StuffDocumentsChain
prompt = ChatPromptTemplate.from_template(
“请总结下面内容:\n{context}”
)
docs = [
Document(page_content=“LangChain是一个LLM开发框架。”),
Document(page_content=“它支持Prompt、Chain和Agent。”)
]
context = “\n”.join([doc.page_content for doc in docs])
stuff_chain = (
prompt
| chat_model
| StrOutputParser()
)
print(
stuff_chain.invoke({
“context”: context
})
)
