LangChain笔记01:Prompt templates,Chat Models,Messages,Output parsers,Structured output
📅 2025-03-19 | 🖱️
概念 #
Prompt template、Chat Model、Messages、Output parser、Structured output是LangChain框架的重要组件和概念。通过有效地组合这些组件,可以构建出简单的LLM应用。
- Prompt template:用于提取模型"提示"中静态部分的组件(通常是一系列消息)。它们对于序列化、版本控制和重用这些静态部分非常有用。
- Chat Model:通过Chat API暴露的大语言模型,处理一系列消息作为输入并输出一条消息。
- Messages:聊天模型中的通信单位,用于表示模型的输入和输出。
- Output parser:负责将模型的输出转换为更适合下游任务的格式。在工具调用(Tool calling)和结构化输出(Structured output)普及之前,输出解析器主要用于此目的。
- Structured output:一种使ChatModel以结构化格式(如符合给定模式的JSON)响应的技术。
可以以通过两种方式组合这些组件:
- 命令式(Imperative):直接调用组件,例如,
model.invoke(...)
- 声明式(Declarative):使用LangChain表达式语言(LCEL, LangChain Expression Language)
关键组件 #
LLM应用程序本质上是一个链式结构,它由以下三个关键组件构成:
提示(Prompt)指令
- 作为模型的输入指令
- 引导模型产生期望的输出
- 对输出质量有决定性影响
大型语言模型(Large Language Model, LLM)
- 作为应用的核心引擎
- 负责进行预测和响应生成
- 可以是GPT、Claude等各类大语言模型
输出解析器(Output Parser)
- 可选但实用的组件
- 将模型的原始输出转换为所需格式
- 例如:JSON转换、结构化数据提取等
组件接口 #
在LangChain框架中,所有组件都实现了统一的接口规范,提供三个核心方法:
- invoke:用于同步调用处理
- stream:用于流式数据处理
- batch:用于批量数据处理
组件的组合方式 #
这些组件的组合主要有两种方式:
1. 命令式(Imperative)组合 #
- 通过直接调用组件方法实现功能
- 适用场景:需要编写大量自定义逻辑时
- 优势:提供更大的编程灵活性和精细控制
2. 声明式(Declarative)组合 #
- 使用LCEL(LangChain Expression Language)
- 适用场景:简单组装现有组件,需求相对固定
- 优势:代码简洁,易于维护,快速开发
选择哪种组合方式主要取决的具体需求:如果需要实现复杂的自定义逻辑,建议使用命令式方法;如果主要是组装现有组件完成基础功能,则声明式方法更为合适。
OutputParser和Structured output #
LCEL声明式+OutputParser #
1from langchain_openai import ChatOpenAI
2from pydantic import BaseModel, Field
3from langchain_core.output_parsers import PydanticOutputParser
4from langchain_core.prompts import ChatPromptTemplate
5
6
7class RestaurantReview(BaseModel):
8 """Restaurant review structure"""
9
10 restaurant_name: str = Field(description="餐厅的名称")
11 food_rating: int = Field(description="菜品口味评分,1-5分")
12 service_rating: int = Field(description="服务质量评分,1-5分")
13 ambiance_rating: int = Field(description="餐厅环境评分,1-5分")
14 recommended_dishes: str = Field(description="推荐的特色菜品")
15 overall_comment: str = Field(description="对餐厅的总体评价和建议")
16
17
18parser = PydanticOutputParser(pydantic_object=RestaurantReview)
19
20prompt_template = ChatPromptTemplate.from_messages(
21 [
22 ("system", "你是一个专业的餐厅评价分析助手,能够从用户描述中提取结构化信息。"),
23 (
24 "human",
25 "请根据用户的描述,生成一个结构化的餐厅评价。\n{format_instructions}\n用户描述: {query}",
26 ),
27 ]
28)
29
30model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
31
32chain = prompt_template | model | parser
33review_result = chain.invoke(
34 {
35 "query": "我昨天去了一家叫'江南小厨'的餐厅,菜品很美味,尤其是红烧肉和清蒸鱼非常好吃。服务员态度一般,有时需要等很久才能叫到人。餐厅装修很有江南风格,环境优雅。总的来说还是值得一去的。",
36 "format_instructions": parser.get_format_instructions(),
37 }
38)
39
40assert isinstance(review_result, RestaurantReview)
41print(review_result)
1restaurant_name='江南小厨' food_rating=5 service_rating=3 ambiance_rating=4 recommended_dishes='红烧肉, 清蒸鱼' overall_comment='总的来说还是值得一去的。'
LCEL声明式+结构化输出(Structured output) #
1from langchain_openai import ChatOpenAI
2from pydantic import BaseModel, Field
3from langchain_core.prompts import ChatPromptTemplate
4
5
6class RestaurantReview(BaseModel):
7 """Restaurant review structure"""
8
9 restaurant_name: str = Field(description="餐厅的名称")
10 food_rating: int = Field(description="菜品口味评分,1-5分")
11 service_rating: int = Field(description="服务质量评分,1-5分")
12 ambiance_rating: int = Field(description="餐厅环境评分,1-5分")
13 recommended_dishes: str = Field(description="推荐的特色菜品")
14 overall_comment: str = Field(description="对餐厅的总体评价和建议")
15
16
17prompt_template = ChatPromptTemplate.from_messages(
18 [
19 ("system", "你是一个专业的餐厅评价分析助手,能够从用户描述中提取结构化信息。"),
20 (
21 "human",
22 "请根据用户的描述,生成一个结构化的餐厅评价。\n用户描述: {query}",
23 ),
24 ]
25)
26
27model = ChatOpenAI(model="gpt-4o-mini", temperature=0).with_structured_output(
28 RestaurantReview
29)
30
31chain = prompt_template | model
32review_result = chain.invoke(
33 {
34 "query": "我昨天去了一家叫'江南小厨'的餐厅,菜品很美味,尤其是红烧肉和清蒸鱼非常好吃。服务员态度一般,有时需要等很久才能叫到人。餐厅装修很有江南风格,环境优雅。总的来说还是值得一去的。",
35 }
36)
37
38assert isinstance(review_result, RestaurantReview)
39print(review_result)
OutputParser和Structured output的区别 #
Structured output #
Structured output是大模型API的原生功能,通过API参数直接要求模型输出符合特定结构的内容。以OpenAI为例,通过/v1/chat/completions
端点的response_format
参数实现,模型会在底层直接生成符合要求的结构化数据。
特点:
- 由模型API直接支持,实现更可靠
- 不需要在提示中描述输出格式
- 目前OpenAI、Google Gemini和Anthropic Claude等主流模型提供商均已支持
- 通过LangChain的
.with_structured_output()
方法可以轻松使用
适用场景:使用支持结构化输出的现代模型时,这是处理结构化数据的首选方法
OutputParser #
OutputParser是一种提示工程技术,通过在提示中明确指定输出格式要求,然后使用解析器将模型输出转换为所需的结构。
特点:
- 适用于所有模型,包括不支持原生结构化输出的旧模型
- 将格式要求作为提示的一部分(通过
format_instructions
) - 需要额外的解析步骤,可能存在解析失败的风险
- 实际格式要求通过提示注入,在
messages
参数中而非API特定参数
使用方式:通过在提示模板中加入格式说明,例如:
1prompt_template = ChatPromptTemplate.from_messages([
2 ("system", "你是一个专业的餐厅评价分析助手,能够从用户描述中提取结构化信息。"),
3 ("human", "请根据用户的描述,生成一个结构化的餐厅评价。\n{format_instructions}\n用户描述: {query}"),
4])
5
6parser = PydanticOutputParser(pydantic_object=RestaurantReview)
7
8review_result = chain.invoke(
9 {
10 "query": "我昨天去了一家叫'江南小厨'的餐厅,菜品很美味,尤其是红烧肉和清蒸鱼非常好吃。服务员态度一般,有时需要等很久才能叫到人。餐厅装修很有江南风格,环境优雅。总的来说还是值得一去的。",
11 "format_instructions": parser.get_format_instructions(),
12 }
13)
选择建议 #
- 对于支持结构化输出的现代模型(如GPT-4o、Claude 3系列等),优先使用Structured output
- 对于需要兼容旧模型或自定义输出格式处理的场景,使用OutputParser
- 在LangChain中,尽可能使用
.with_structured_output()
方法,它会根据模型能力自动选择最佳实现方式
参考链接 #
- https://python.langchain.com/docs/concepts/chat_models/
- https://python.langchain.com/docs/concepts/prompt_templates/
- https://python.langchain.com/docs/concepts/messages/
- https://python.langchain.com/docs/concepts/output_parsers/
- https://python.langchain.com/docs/concepts/structured_outputs/
- https://platform.openai.com/docs/api-reference/chat