LangChain 设计原理分析⁵ | PromptTemplate 模板系统与上下文注入机制

本文深入讲解 LangChain 中的 Prompt 模板系统,探索变量绑定、FewShot 示例构建、格式化策略等关键能力,帮助你构建灵活可控的提示内容生成逻辑。


一、PromptTemplate 是什么?

PromptTemplate 是 LangChain 中用于生成语言模型 输入文本 的标准化模板系统。

它的主要作用是:

  • 使用占位变量构造提示内容
  • 将动态上下文注入至 prompt 中
  • 实现不同输入场景下的统一模板管理与复用

二、基础使用:变量绑定与格式化

PromptTemplate 的核心能力是"模板 + 输入变量 = 生成文本"。

python 复制代码
from langchain_core.prompts import PromptTemplate

prompt = PromptTemplate.from_template("你是谁?我是{identity}。")
print(prompt.format(identity="LangChain"))
# 输出:你是谁?我是LangChain。

也可使用 input_variablestemplate 分开定义:

python 复制代码
from langchain_core.prompts import PromptTemplate

prompt = PromptTemplate(
    input_variables=["agent", "topic"],
    template="请 {agent} 用一句话总结关于 {topic} 的内容。"
)
print(prompt.format(agent="LLM", topic="LangChain"))
# 输出:请 LLM 用一句话总结关于 LangChain 的内容。

三、进阶功能:FewShotPromptTemplate(示例注入式提示构造)

FewShotPromptTemplate 是 LangChain 中用于构造 带有示例上下文(Few-Shot Examples) 的提示模板系统。它的作用是:在正式提示之前,插入一组"训练样例",让模型更好地理解输入模式,提高生成准确性,常用于分类、问答、意图识别等任务。


✅ 工作机制

它的生成逻辑等价于三段拼接:

css 复制代码
[样例1模板渲染]  
[样例2模板渲染]  
...  
+  
[Suffix(真正的Prompt部分)]

从而构造出如下结构:

复制代码
输入:狗
输出:动物

输入:苹果
输出:水果

输入:西瓜
输出:

✅ 示例代码解析

python 复制代码
from langchain.prompts import FewShotPromptTemplate, PromptTemplate

# 定义训练样例
examples = [
    {"input": "狗", "output": "动物"},
    {"input": "苹果", "output": "水果"},
]

# 定义样例模板:每个样例如何格式化为字符串
example_prompt = PromptTemplate.from_template("输入:{input}\n输出:{output}")

# 构造 FewShotPromptTemplate
prompt = FewShotPromptTemplate(
    examples=examples,  # 样例数据列表
    example_prompt=example_prompt,  # 样例模板
    suffix="输入:{input}\n输出:",  # 正式 Prompt(将在样例之后接上)
    input_variables=["input"]  # 最终用户提供的变量(传给 suffix)
)

# 渲染 Prompt
print(prompt.format(input="西瓜"))

🧠 核心概念解析

参数名称 含义说明
examples 提供的示例数据,通常是结构化字典列表
example_prompt 每个样例的渲染模板(可嵌套 PromptTemplate)
suffix 实际用户输入部分的 Prompt
prefix(可选) 在所有样例之前插入前缀
example_separator 样例之间的分隔符,默认为两个换行

📦 FewShotPromptTemplate 的使用场景

  • 文本分类:根据几个示例推断目标类别
  • 函数映射:输入一个值,模型输出其对应映射
  • 意图识别:提供几个句子 → 推断其意图标签
  • 少样本 QA/RAG:插入上下文片段作为参考

🧩 进阶用法:动态样例选择器(Selector)

除了手动提供 examples 外,你还可以动态选择最相关的样例:

python 复制代码
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from 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. 构建向量相似度选择器 selector
selector = 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. 格式化并查看实际 Prompt
print(prompt.format(input="小提琴"))

这可以实现 基于输入动态检索最相似的示例,大大提升上下文精度。


四、进阶控制:自定义格式逻辑(替代 format_func

在 LangChain 新版本中,PromptTemplate 已不再支持传入 format_func 参数。但我们依然可以通过封装、继承等方式实现自定义的 Prompt 格式控制逻辑,特别适用于构建动态 Prompt、多语言切换、对话历史注入等复杂场景。


✅ 1. 封装类实现"自定义格式器"

你可以为 PromptTemplate 写一个包装器,对格式化结果进行二次加工:

python 复制代码
from langchain.prompts import PromptTemplate

class 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 的一部分注入:

python 复制代码
from langchain_core.prompts import PromptTemplate

class 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 模板结构:

python 复制代码
from langchain_core.prompts import PromptTemplate

class 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 拼接

python 复制代码
import os

from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

prompt = 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 | llm

print(chain.invoke({"input": "月亮"}))

📌 说明:

  • invoke({"input": ...}) 会自动传入模板所需字段
  • 输出为 ChatMessage 对象,通常为 AIMessage(content=...)

✅ 输入转换:配合 RunnableLambda 进行字段重构

我们可以通过 RunnableLambda 对输入数据结构进行预处理,例如将外部问答表单结构转换为 Prompt 所需的 {input} 字段:

python 复制代码
from langchain_core.runnables import RunnableLambda

context_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 之间插入处理模块,例如代码高亮、参数注解、消息格式转换等:

python 复制代码
from langchain_core.runnables import RunnableLambda

post_processor = RunnableLambda(lambda msg: msg.content.upper())

chain = prompt | llm | post_processor

print(chain.invoke({"input": "用10个英文单词概括一下介绍一下LLM"}))

✅ 与其他模块协同:Retry / Fallback / Tagging / LangSmith

所有 Runnable 都支持:

  • .with_retry(RetryConfig(...))
  • .with_fallbacks([...])
  • .with_config(tags=[...], metadata={...})

你可以构建一个"具备鲁棒性与可观测性"的 Prompt 执行链:

python 复制代码
robust_chain = (prompt | llm).with_config(tags=["分类任务"])

print(robust_chain.invoke({"input": "苹果"}))

✅ 并行执行多个 Prompt:构造多路提示结构(如对比测试)

python 复制代码
from langchain_core.runnables import RunnableParallel

prompt1 = 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 设计体系,理解如何构建支持上下文记忆的链,支持多轮会话与历史引用等高级功能。

相关推荐
Chasing__Dreams1 小时前
langchain--1--prompt、output格式、LCEL示例
langchain
都叫我大帅哥1 天前
当AI遇上话痨:LangGraph的`trim_messages`裁剪艺术完全指南
python·langchain·ai编程
青衫客361 天前
LLM——使用 LangGraph 构建 ReAct 智能体:多轮对话 + 工具调用 + 可视化流程图
langchain·大模型·llm·agent·langgraph
王国强20092 天前
LangChain 设计原理分析⁴ | BaseLanguageModel 接口解构:多模型适配的设计模式
langchain
AI Echoes2 天前
ChatGPT、Playground手动模拟Agent摘要缓冲混合记忆功能
人工智能·python·langchain
AIGC包拥它2 天前
检索召回率优化探究二:基于 LangChain 0.3集成 Milvus 2.5向量数据库构建的智能问答系统
人工智能·python·langchain·软件工程·个人开发·milvus
王国强20092 天前
LangChain 设计原理分析³ | 从零实现一个自定义 Runnable 模块
langchain
喵王叭2 天前
【大模型核心技术】Agent 理论与实战
人工智能·langchain
Nero2 天前
SpringBoot对接LangChain4J四件套
langchain