提示模板与输出解析器

学习如何创建可复用、动态的提示(prompts),并将 AI 的响应解析为结构化数据。这是构建生产级 AI 应用所必备的核心技能。

学习目标

  • 使用变量创建动态且可复用的提示模板
  • 针对不同场景选用合适的提示模板类型
  • 将非结构化的 AI 输出解析为结构化数据(如 JSON、列表等)
  • 通过验证后的输出构建可靠的应用程序

本中级教程的前置知识

本教程假设你已具备以下条件:

  • 已完成第 5 课(LangChain 环境配置)或已安装 LangChain
  • 具备中级 Python 编程能力
  • 对提示工程(prompt engineering)有基本理解
  • 熟悉 JSON 及常用数据结构

什么是 LangChain 提示模板?------ 基础概念

提示模板是一种包含变量的可复用提示,这些变量可以在运行时动态填充。与其将提示硬编码,不如创建一个能根据输入自动调整的模板。

🔑 为什么要使用模板?

  • 可复用性:一次编写,多次使用,适配不同输入
  • 一致性:确保整个应用中提示结构统一
  • 可维护性:只需在一个地方修改提示内容
  • 动态内容:轻松注入用户数据、上下文或变量

如何创建基础的 LangChain 提示模板?------ Python 示例

简单变量替换

最基本的模板会将占位符替换为实际值。下面这个例子展示了一个可用于 LLM 的翻译提示模板:

python 复制代码
from langchain_core.prompts import PromptTemplate

# 创建一个简单模板
template = """你是一个乐于助人的助手,负责将 {input_language} 翻译成 {output_language}。

原文:{text}

译文:"""

# 创建提示模板对象
prompt = PromptTemplate(
    input_variables=["input_language", "output_language", "text"],
    template=template
)

# 使用模板
formatted_prompt = prompt.format(
    input_language="English",
    output_language="Spanish",
    text="Hello, how are you?"
)

print(formatted_prompt)

输出结果:

复制代码
你是一个乐于助人的助手,负责将 English 翻译成 Spanish。

原文:Hello, how are you?

译文:

说明:模板会将 {input_language}、{output_language} 和 {text} 替换为你提供的实际值。注意:这一步仅生成提示文本,并未真正执行翻译。若要获得翻译结果,还需将此提示发送给 LLM。

完整示例:模板 + LLM

下面展示如何将模板与 LLM 结合,真正完成翻译任务:

python 复制代码
from langchain_core.prompts import PromptTemplate
from langchain_google_genai import ChatGoogleGenerativeAI
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 创建模板
template = """你是一个乐于助人的助手,负责将 {input_language} 翻译成 {output_language}。

原文:{text}

译文:"""

prompt = PromptTemplate(
    input_variables=["input_language", "output_language", "text"],
    template=template
)

# 初始化 LLM(需在 .env 文件中设置 GOOGLE_API_KEY)
model = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    google_api_key=os.getenv("GOOGLE_API_KEY")
)

# 构建链:模板 → LLM
chain = prompt | model

# 执行链(这将真正进行翻译!)
response = chain.invoke({
    "input_language": "English",
    "output_language": "Spanish",
    "text": "Hello, how are you?"
})

print(response.content)
# 输出:"Hola, ¿cómo estás?"

聊天提示模板(Chat Prompt Templates)

对于聊天模型(chat models),应使用 ChatPromptTemplate 来处理消息格式。聊天模型要求消息具有特定的角色结构(system、human、assistant),因此 ChatPromptTemplate 是与之正确通信的关键:

python 复制代码
from langchain_core.prompts import ChatPromptTemplate
from langchain_google_genai import ChatGoogleGenerativeAI
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 创建包含 system 和 human 消息的聊天模板
chat_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个{role},负责协助完成{task}。"),
    ("human", "{user_input}"),
])

# 格式化模板
messages = chat_template.format_messages(
    role="编程导师",
    task="Python 编程",
    user_input="如何读取一个 CSV 文件?"
)

# 与模型交互
llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    google_api_key=os.getenv("GOOGLE_API_KEY")  # 显式设置 API 密钥
)
response = llm.invoke(messages)
print(response.content)

📋 消息角色说明:

  • "system":设定 AI 的行为、性格或约束条件,相当于给助手下达指令
  • "human":用户的输入或问题
  • "assistant":AI 的历史回复(用于对话上下文)

✨ ChatPromptTemplate 的优势:

  • 自动为聊天模型格式化消息结构
  • 支持在任意消息类型中使用动态变量
  • 轻松构建对话式应用
  • 在不同聊天模型提供商之间保持一致性

高级模板模式

部分模板(Partial Templates)

预先填充部分变量,其余变量保持动态。适用于某些值固定(如当前日期、系统配置或默认值),而其他值随每次调用变化的场景:

python 复制代码
from langchain_core.prompts import PromptTemplate
from datetime import datetime

# 包含多个变量的模板
template = """日期:{date}
用户:{user_name}
任务:{task}

请完成以下请求:{request}"""

# 创建部分模板,预填日期
prompt = PromptTemplate(
    input_variables=["user_name", "task", "request"],
    template=template,
    partial_variables={"date": datetime.now().strftime("%Y-%m-%d")}
)

# 此时只需提供剩余变量
formatted = prompt.format(
    user_name="Alice",
    task="代码审查",
    request="请根据最佳实践审查以下 Python 函数"
)

print(formatted)
🔑 何时使用部分模板?
  • 时间戳:自动在日志或报告中加入当前日期/时间
  • 系统信息:预填环境、版本或配置详情
  • 用户上下文:一次性设置用户偏好,多次复用
  • 默认值:提供合理的默认选项,同时允许覆盖

💡 专业技巧:部分模板非常适合从通用模板派生专用版本。例如,先创建一个通用邮件模板,再通过部分填充生成支持、销售或通知等不同场景的专用模板。

模板组合(Template Composition)

将多个模板组合成复杂提示。这种模式允许你构建模块化、可复用的提示组件,并根据不同用例灵活搭配:

python 复制代码
from langchain_core.prompts import PromptTemplate

# 定义可复用的模板组件
persona_template = "你是一位拥有{years}年经验的{expertise}专家。"
task_template = "你的任务是{action}以下{content_type}:"
format_template = "请将你的回答格式化为{format}。"

# 组合模板
full_template = f"""
{persona_template}

{task_template}

{format_template}

内容:{{content}}
"""

# 创建完整提示
prompt = PromptTemplate(
    input_variables=["expertise", "years", "action", "content_type", "format", "content"],
    template=full_template
)

# 使用组合模板
result = prompt.format(
    expertise="Python",
    years="10",
    action="优化",
    content_type="代码",
    format="带解释的改进建议列表",
    content="def calculate_sum(numbers): total = 0; for n in numbers: total = total + n; return total"
)

print(result)
🧩 为何使用模板组合?
  • 模块化:为提示的不同部分创建可复用的构建块
  • 一致性:确保应用内所有提示结构统一
  • 灵活性:根据不同场景自由组合组件
  • 可维护性:修改一个组件即可影响所有使用它的提示
💡 真实场景示例:

设想构建一个客服系统,需要不同组合:

  • 技术支持:persona_template + technical_task + detailed_format
  • 销售咨询:persona_template + sales_task + friendly_format
  • 投诉处理:persona_template + empathy_task + solution_format
  • 共享同一"人设"组件,但任务和格式组件各不相同!

LangChain 输出解析器教程:结构化数据的逐步指南

为什么需要输出解析器?

LLM 返回的是非结构化文本,但应用程序通常需要结构化数据。输出解析器能将自由文本转换为以下可用格式:

  • JSON
  • 结构化对象
  • 列表
  • 枚举项
  • 布尔值(是/否决策)
  • 自定义格式

列表输出解析器(List Output Parser)

解析逗号分隔或编号列表。该解析器会自动指示 LLM 以逗号分隔格式返回结果,然后将其拆分为 Python 列表:

python 复制代码
from langchain_core.output_parsers import CommaSeparatedListOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_google_genai import ChatGoogleGenerativeAI
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 初始化解析器
list_parser = CommaSeparatedListOutputParser()

# 创建带格式指令的提示
prompt = PromptTemplate(
    template="列出 5 个{category}。\n{format_instructions}",
    input_variables=["category"],
    partial_variables={"format_instructions": list_parser.get_format_instructions()}
)

# 构建链
llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    google_api_key=os.getenv("GOOGLE_API_KEY")
)
chain = prompt | llm | list_parser

# 获取解析后的列表
result = chain.invoke({"category": "Python Web 框架"})
print(result)  # ['Django', 'Flask', 'FastAPI', 'Pyramid', 'Tornado']
📋 工作原理:
  • 解析器自动向提示中添加格式指令
  • LLM 返回逗号分隔的项
  • 解析器拆分响应并清理空白字符
  • 返回可直接使用的干净 Python 列表
✨ 适用场景:
  • 生成想法或建议列表
  • 从文本中提取多个项目
  • 创建分类或标签
  • 任何需要多个简单输出的任务

结构化输出解析器(Structured Output Parser)

解析带验证的复杂结构化数据。该解析器使用 ResponseSchema 对象定义期望结构,并自动指示 LLM 以 JSON 格式返回数据:

python 复制代码
from pydantic import BaseModel, Field
from langchain_core.output_parsers import PydanticOutputParser  # 注意:这个还在
from langchain_core.prompts import PromptTemplate
from langchain_google_genai import ChatGoogleGenerativeAI
import os
from dotenv import load_dotenv

load_dotenv()

# 1. 用 Pydantic 定义你的输出结构(替代 ResponseSchema)
class ProductInfo(BaseModel):
    name: str = Field(description="产品名称")
    price: float = Field(description="价格,单位为美元")
    features: list[str] = Field(description="主要功能列表")
    in_stock: bool = Field(description="是否有库存")

# 2. 创建解析器
parser = PydanticOutputParser(pydantic_object=ProductInfo)

# 3. 构建提示(自动注入格式指令)
prompt = PromptTemplate(
    template="从以下文本中提取产品信息。\n{format_instructions}\n\n文本:{product_description}",
    input_variables=["product_description"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

# 4. 调用链
llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    google_api_key=os.getenv("GOOGLE_API_KEY")
)
chain = prompt | llm | parser

result = chain.invoke({
    "product_description": "新款 iPhone 15 Pro 售价 999 美元,采用钛金属设计、A17 Pro 芯片和升级版相机系统,目前门店有售。"
})

print(result)  # 返回 ProductInfo 对象,可直接访问属性
# 输出:name='iPhone 15 Pro' price=999.0 features=['钛金属设计', 'A17 Pro 芯片', '升级版相机系统'] in_stock=True

注意: ResponseSchema 和 StructuredOutputParser (0.3版本以前的写法,1.0版本已经弃用,改为更加现代化的方式)。在1.0版本中,推荐使用更加现代化的方式来实现结构化输出解析器。PydanticOutputParser 是一个基于 Pydantic 模型的解析器,它可以将 LLM 的响应解析为符合定义的 Pydantic 模型的实例。

🔑 核心特性:
  • 结构定义:为每个字段指定名称和描述
  • 类型灵活:支持字符串、数字、列表和布尔值
  • 自动指令:解析器明确告诉 LLM 如何格式化响应
  • JSON 输出:返回 Python 字典形式的数据
💡 典型用例:
  • 数据提取:从非结构化文本中抽取结构化信息
  • 表单处理:将自然语言转换为表单字段
  • API 响应:生成可供 API 使用的结构化数据
  • 数据库记录:创建可直接插入数据库的记录

高级:Pydantic 输出解析器(Pydantic Output Parser)

对于生产级应用,推荐使用 Pydantic 实现类型安全与验证。Pydantic 提供最强大的解析能力,包括自动类型转换、验证和清晰的错误信息。

🔍 为何选择 Pydantic 输出解析器?

  • 类型安全:自动类型检查与转换
  • 验证机制:内置字段验证,支持自定义规则
  • 错误处理:解析失败时提供清晰的错误信息
  • IDE 支持:完整的自动补全与类型提示
  • 生产就绪:已在企业级应用中广泛验证

💡 核心组件:

  • BaseModel:用类型定义数据结构
  • Field():添加描述和验证规则
  • PydanticOutputParser:将 LLM 输出转换为类型化对象
  • format_instructions:自动生成提示指令
python 复制代码
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_google_genai import ChatGoogleGenerativeAI
from pydantic import BaseModel, Field
from typing import List
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 定义数据模型
class Recipe(BaseModel):
    name: str = Field(description="食谱名称")
    prep_time: int = Field(description="准备时间(分钟)")
    servings: int = Field(description="可供几人食用")
    ingredients: List[str] = Field(description="所需食材列表")
    difficulty: str = Field(description="难度等级:easy, medium 或 hard")

# 创建解析器
parser = PydanticOutputParser(pydantic_object=Recipe)

# 创建提示
prompt = PromptTemplate(
    template="""从以下文本中提取食谱信息。

{format_instructions}

文本:{recipe_text}""",
    input_variables=["recipe_text"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

# 使用链
llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    temperature=0,  # 降低随机性以提高结构稳定性
    google_api_key=os.getenv("GOOGLE_API_KEY")
)
chain = prompt | llm | parser

# 解析食谱
result = chain.invoke({
    "recipe_text": "这道简单的培根蛋面仅需 20 分钟即可完成,可供 4 人食用。你需要意大利面、鸡蛋、培根、帕玛森奶酪和黑胡椒。"
})

print(f"食谱:{result.name}")
print(f"耗时:{result.prep_time} 分钟")
print(f"份量:{result.servings} 人")
print(f"食材:{', '.join(result.ingredients)}")
print(f"难度:{result.difficulty}")
🎯 高级特性:
  • 自定义验证器:通过 @validator 添加自定义验证逻辑
  • 默认值:为可选字段设置默认值
  • 嵌套模型:支持复杂的嵌套数据结构
  • 枚举(Enums):限制字段只能取特定值
💡 带验证的示例:
python 复制代码
from typing import List
from pydantic import BaseModel, Field, field_validator  # ← 注意这里导入的是 field_validator

class Recipe(BaseModel):
    name: str = Field(description="食谱名称")
    prep_time: int = Field(description="准备时间(分钟)", gt=0, le=480)  # 1~480 分钟
    ingredients: List[str] = Field(description="食材列表", min_length=1)  # ⚠️ 注意:min_items → min_length

    @field_validator('name')
    def name_must_not_be_empty(cls, v: str) -> str:
        if not v.strip():
            raise ValueError('食谱名称不能为空')
        return v.title()  # 自动首字母大写

最佳实践

提示模板(Prompt Templates)

  • 保持模板聚焦单一任务
  • 使用描述性强的变量名
  • 在提示中包含示例
  • 用边界情况测试模板

输出解析器(Output Parsers)

  • 始终包含格式指令
  • 优雅处理解析错误
  • 复杂结构优先使用 Pydantic
  • 使用前务必验证输出

💡常见模式

  • 数据提取:模板 + StructuredOutputParser → 从非结构化文本中提取结构化数据
  • 分类任务:带选项的模板 + EnumOutputParser → 对输入进行分类
  • 多步处理:串联多个模板与解析器 → 构建复杂工作流

🎉下一步:构建复杂工作流

干得漂亮!你已经掌握了 LangChain 的提示模板与输出解析器------这是构建动态、结构化 AI 应用的基石。这些技能将为你学习更复杂的 LangChain 模式打下坚实基础。

准备进阶了吗?在下一课中,你将学习如何使用 LangChain Chains 构建复杂工作流,将多个步骤组合成强大的 AI 流水线。

相关推荐
大模型真好玩17 小时前
大模型训练全流程实战指南工具篇(六)——OCR工具实战指南(以DeepSeek-OCR-2为例)
人工智能·langchain·deepseek
高可用架构19 小时前
LangChain创始人:Agent 连接沙箱的两种模式(附深度架构解析)
架构·langchain
曦云沐21 小时前
第四篇:LangChain 1.0 Community 生态全览:第三方集成与厂商包最佳实践
人工智能·langchain·大模型开发框架
无名修道院1 天前
AI大模型-LangChain
langchain·agent·ai大模型
梧桐1681 天前
基于 LangChain 的Text2SQL 智能体开发实践
人工智能·langchain·大模型·text2sql
Elastic 中国社区官方博客1 天前
从向量到关键词:在 LangChain 中的 Elasticsearch 混合搜索
大数据·开发语言·数据库·elasticsearch·搜索引擎·ai·langchain
JaydenAI1 天前
[拆解LangChain执行引擎] PregelProtocol——定义了"LangChain执行体"最小功能集
python·langchain
明天有专业课1 天前
RAG的基石-数据加载
langchain·aigc