本文深入讲解 LangChain 中的 Prompt 模板系统,探索变量绑定、FewShot 示例构建、格式化策略等关键能力,帮助你构建灵活可控的提示内容生成逻辑。
一、PromptTemplate 是什么?
PromptTemplate
是 LangChain 中用于生成语言模型 输入文本 的标准化模板系统。
它的主要作用是:
- 使用占位变量构造提示内容将动态上下文注入至 prompt 中实现不同输入场景下的统一模板管理与复用
二、基础使用:变量绑定与格式化
PromptTemplate 的核心能力是“模板 + 输入变量 = 生成文本”。
from langchain_core.prompts import PromptTemplateprompt = PromptTemplate.from_template("你是谁?我是{identity}。")print(prompt.format(identity="LangChain"))# 输出:你是谁?我是LangChain。
也可使用 input_variables
与 template
分开定义:
from langchain_core.prompts import PromptTemplateprompt = PromptTemplate( input_variables=["agent", "topic"], template="请 {agent} 用一句话总结关于 {topic} 的内容。")print(prompt.format(agent="LLM", topic="LangChain"))# 输出:请 LLM 用一句话总结关于 LangChain 的内容。
三、进阶功能:FewShotPromptTemplate(示例注入式提示构造)
FewShotPromptTemplate
是 LangChain 中用于构造 带有示例上下文(Few-Shot Examples) 的提示模板系统。它的作用是:在正式提示之前,插入一组“训练样例”,让模型更好地理解输入模式,提高生成准确性,常用于分类、问答、意图识别等任务。
✅ 工作机制
它的生成逻辑等价于三段拼接:
[样例1模板渲染] [样例2模板渲染] ... + [Suffix(真正的Prompt部分)]
从而构造出如下结构:
输入:狗输出:动物输入:苹果输出:水果输入:西瓜输出:
✅ 示例代码解析
from langchain.prompts import FewShotPromptTemplate, PromptTemplate# 定义训练样例examples = [ {"input": "狗", "output": "动物"}, {"input": "苹果", "output": "水果"},]# 定义样例模板:每个样例如何格式化为字符串example_prompt = PromptTemplate.from_template("输入:{input}\n输出:{output}")# 构造 FewShotPromptTemplateprompt = FewShotPromptTemplate( examples=examples, # 样例数据列表 example_prompt=example_prompt, # 样例模板 suffix="输入:{input}\n输出:", # 正式 Prompt(将在样例之后接上) input_variables=["input"] # 最终用户提供的变量(传给 suffix))# 渲染 Promptprint(prompt.format(input="西瓜"))
🧠 核心概念解析
参数名称 | 含义说明 |
---|---|
examples | 提供的示例数据,通常是结构化字典列表 |
example_prompt | 每个样例的渲染模板(可嵌套 PromptTemplate) |
suffix | 实际用户输入部分的 Prompt |
prefix (可选) | 在所有样例之前插入前缀 |
example_separator | 样例之间的分隔符,默认为两个换行 |
📦 FewShotPromptTemplate 的使用场景
- 文本分类:根据几个示例推断目标类别函数映射:输入一个值,模型输出其对应映射意图识别:提供几个句子 → 推断其意图标签少样本 QA/RAG:插入上下文片段作为参考
🧩 进阶用法:动态样例选择器(Selector)
除了手动提供 examples
外,你还可以动态选择最相关的样例:
from langchain_community.embeddings import HuggingFaceEmbeddingsfrom langchain_community.vectorstores import FAISSfrom langchain.prompts.example_selector import SemanticSimilarityExampleSelectorfrom langchain.prompts import FewShotPromptTemplate, PromptTemplate# 1. 定义本地 embedding 模型embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")# 2. 定义示例examples = [ {"input": "狗", "output": "汪汪叫"}, {"input": "苹果", "output": "水果"}, {"input": "猫", "output": "喵喵叫"}, {"input": "钢琴", "output": "乐器"},]# 3. 构建向量相似度选择器 selectorselector = SemanticSimilarityExampleSelector.from_examples( examples=examples, embeddings=embedding_model, vectorstore_cls=FAISS, k=2)# 4. 构建 Prompt 模板example_prompt = PromptTemplate.from_template("输入:{input}\n输出:{output}")prompt = FewShotPromptTemplate( example_selector=selector, example_prompt=example_prompt, suffix="输入:{input}\n输出:", input_variables=["input"])# 5. 格式化并查看实际 Promptprint(prompt.format(input="小提琴"))
这可以实现 基于输入动态检索最相似的示例,大大提升上下文精度。
四、进阶控制:自定义格式逻辑(替代 format_func
)
在 LangChain 新版本中,PromptTemplate
已不再支持传入 format_func
参数。但我们依然可以通过封装、继承等方式实现自定义的 Prompt 格式控制逻辑,特别适用于构建动态 Prompt、多语言切换、对话历史注入等复杂场景。
✅ 1. 封装类实现“自定义格式器”
你可以为 PromptTemplate
写一个包装器,对格式化结果进行二次加工:
from langchain.prompts import PromptTemplateclass UppercasePrompt: def __init__(self, template: PromptTemplate): self.template = template def format(self, **kwargs) -> str: base = self.template.format(**kwargs) return base.upper()# 示例用法template = PromptTemplate.from_template("你好,{name}!")prompt = UppercasePrompt(template)print(prompt.format(name="tom"))# 输出:你好,TOM!
✅ 2. 拼接上下文:封装对话历史逻辑
适用于多轮对话中,把历史问答作为 Prompt 的一部分注入:
from langchain_core.prompts import PromptTemplateclass ChatHistoryPrompt: def __init__(self, prompt_template: PromptTemplate): self.prompt = prompt_template def format(self, user_input: str, history: list[dict]) -> str: history_text = "\n".join(f"用户:{h['q']}\n助手:{h['a']}" for h in history) full_input = f"{history_text}\n用户:{user_input}\n助手:" return self.prompt.format(input=full_input)# 用法prompt_template = PromptTemplate.from_template("{input}")history_prompt = ChatHistoryPrompt(prompt_template)chat_history = [ {"q": "今天天气好吗?", "a": "很晴朗。"}, {"q": "那我适合出门吗?", "a": "当然适合。"}]print(history_prompt.format(user_input="那我还要带伞吗?", history=chat_history))
📤 输出:
✅ 3. 动态模板切换(根据输入结构)
适用于根据不同任务切换 Prompt 模板结构:
from langchain_core.prompts import PromptTemplateclass TaskPrompt: def __init__(self): self.qa = PromptTemplate.from_template("问:{question}\n答:") self.summary = PromptTemplate.from_template("请总结以下内容:{text}") def format(self, task_type: str, **kwargs) -> str: if task_type == "qa": return self.qa.format(**kwargs) elif task_type == "summary": return self.summary.format(**kwargs) else: raise ValueError("未知的任务类型")# 使用示例prompt = TaskPrompt()print(prompt.format(task_type="qa", question="LangChain 是什么?"))# 输出:问:LangChain 是什么?print(prompt.format(task_type="summary", text="PromptTemplate系统本质上是一个可编程的模板引擎," "允许用户在模板注入逻辑中引入复杂行为(如动态示例切换、多语言支持、上下文拼接等)。"))# 输出:请总结以下内容:PromptTemplate系统本质上是一个可编程的模板引擎,允许用户在模板注入逻辑中引入复杂行为(如动态示例切换、多语言支持、上下文拼接等)。
五、与其他模块组合:PromptTemplate 本身是 Runnable
PromptTemplate
在 LangChain 中不仅仅是一个字符串格式化工具,它本身就是一个可执行模块,继承自 RunnableSerializable
,因此你可以像拼积木一样将其与模型、解析器、分支、回退等模块灵活组合。
这也是 LangChain 的核心哲学之一:一切都是 Runnable,一切皆可组合。
✅ 基础用法:PromptTemplate 与 LLM 拼接
import osfrom langchain.prompts import PromptTemplatefrom langchain_openai import ChatOpenAIprompt = PromptTemplate.from_template("请解释一下:{input}")# 或者使用环境变量llm = ChatOpenAI( temperature=0.7, model="glm-4.5", openai_api_key=os.getenv("ZAI_API_KEY"), openai_api_base="https://open.bigmodel.cn/api/paas/v4/")# 组合两个 Runnable,构成一个完整链路chain = prompt | llmprint(chain.invoke({"input": "月亮"}))
📌 说明:
invoke({"input": ...})
会自动传入模板所需字段输出为ChatMessage
对象,通常为AIMessage(content=...)
✅ 输入转换:配合 RunnableLambda 进行字段重构
我们可以通过 RunnableLambda
对输入数据结构进行预处理,例如将外部问答表单结构转换为 Prompt 所需的 {input}
字段:
from langchain_core.runnables import RunnableLambdacontext_injector = RunnableLambda(lambda d: {"input": d["question"]})chain = context_injector | prompt | llm# 原始数据不符合 Prompt 模板格式input_data = {"question": "什么是日照金山?"}print(chain.invoke(input_data))
✅ 常用于从工具接收参数、网页表单输入、数据库字段等“非标准格式”转为 Prompt 所需格式。
✅ 中间加工:组合 Parser、后处理、工具调用等模块
你可以在 Prompt → LLM 之间插入处理模块,例如代码高亮、参数注解、消息格式转换等:
from langchain_core.runnables import RunnableLambdapost_processor = RunnableLambda(lambda msg: msg.content.upper())chain = prompt | llm | post_processorprint(chain.invoke({"input": "用10个英文单词概括一下介绍一下LLM"}))
✅ 与其他模块协同:Retry / Fallback / Tagging / LangSmith
所有 Runnable
都支持:
.with_retry(RetryConfig(...))
.with_fallbacks([...])
.with_config(tags=[...], metadata={...})
你可以构建一个“具备鲁棒性与可观测性”的 Prompt 执行链:
robust_chain = (prompt | llm).with_config(tags=["分类任务"])print(robust_chain.invoke({"input": "苹果"}))
✅ 并行执行多个 Prompt:构造多路提示结构(如对比测试)
from langchain_core.runnables import RunnableParallelprompt1 = PromptTemplate.from_template("请用10到20个中文汉字解释:{input}")prompt2 = PromptTemplate.from_template("请用10到20个英文单词解释:{input}")multi_chain = RunnableParallel({ "中文回答": prompt1 | llm, "英文回答": prompt2 | llm})print(multi_chain.invoke({"input": "黑洞"}))
六、总结与工程价值
PromptTemplate 是提示工程的基础设施,具备以下价值:
- 保证提示格式一致性,降低出错率支持变量化复用,提升 prompt 管理效率支持示例注入与自定义格式化,增强表达能力可作为 Runnable 单元与链路灵活组合
在构建复杂的 Agent、RAG 或多轮对话系统时,PromptTemplate 是最基本的构建砖块。
接下来我们将进入 LangChain 的 Memory 设计体系,理解如何构建支持上下文记忆的链,支持多轮会话与历史引用等高级功能。