LangChain笔记01:Prompt templates,Chat Models,Messages,Output parsers,Structured output

LangChain笔记01:Prompt templates,Chat Models,Messages,Output parsers,Structured output

📅 2025-03-19 | 🖱️
🔖 langchain

概念 #

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应用程序本质上是一个链式结构,它由以下三个关键组件构成:

  1. 提示(Prompt)指令

    • 作为模型的输入指令
    • 引导模型产生期望的输出
    • 对输出质量有决定性影响
  2. 大型语言模型(Large Language Model, LLM)

    • 作为应用的核心引擎
    • 负责进行预测和响应生成
    • 可以是GPT、Claude等各类大语言模型
  3. 输出解析器(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()方法,它会根据模型能力自动选择最佳实现方式

参考链接 #

© 2025 青蛙小白 | 总访问量 | 总访客数