Task 2 · LangChain 核心组件实操

Easy-Langent × DataWhale 智能体开发教程
任务笔记 · 第2章


本任务学什么

层级 内容
第2章 模型调用(ChatOpenAI)、提示词模板(PromptTemplate)、输出解析(OutputParser)
学完目标 掌握"输入可控制、输出可预期"的组件化开发能力,能组合三大组件构建简单应用

一、本章知识全景图

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│ PromptTemplate│ → │  ChatOpenAI  │ → │ OutputParser │
│ 提示词模板    │    │   模型调用    │    │   输出解析    │
└──────────────┘    └──────────────┘    └──────────────┘
        ↓                   ↓                   ↓
     规范输入            屏蔽差异            结构化输出

本章核心:用管道符 | 把三个组件串起来,形成 prompt | llm | parser 的完整数据处理链。


二、组件一:ChatOpenAI(模型调用)

2.1 LLM vs ChatModel

LLM(文本生成模型) ChatModel(对话模型)
输入 一段文本 消息列表(带角色)
输出 一段文本 一条对话消息
代表模型 Llama、Qwen(开源) GPT-4o、DeepSeek-Chat
适合场景 简单文本生成、翻译 多轮对话、上下文理解

⚠️ 实际开发几乎只用 ChatModel。DeepSeek-Chat 只支持 Chat Completions 接口,不支持传统 Completions 接口。


2.2 三种消息角色(本质是约束层级)

💡 角色不是用来区分"谁在说话",而是表达不同层级的约束关系

角色 本质 类比
system 全局行为规则,全程生效,优先级最高 老师在黑板上写的教学要求
user 当前轮次的具体任务 学生举手提问
assistant 对话历史,维持连续性 老师刚讲过的内容

优先级system > user > assistant


2.3 代码模板:ChatOpenAI 初始化 + 多轮对话

from langchain_openai import ChatOpenAI

# 初始化(四个关键参数)
chat_model = ChatOpenAI(
    api_key=API_KEY,
    base_url=BASE_URL,
    model="deepseek-chat",
    temperature=0.3,   # 越小越严谨,越大越有创造力
    max_tokens=200     # 避免生成过长内容,控制成本
)

# 多轮对话:手动维护 history
history = [
    {"role": "system", "content": "你是一个耐心的AI学习助手。"}
]

# 第一轮
history.append({"role": "user", "content": "什么是LangChain?"})
result = chat_model.invoke(history)
print(result.content)

# 把 assistant 回复加入历史
history.append({"role": "assistant", "content": result.content})

# 第二轮
history.append({"role": "user", "content": "它的核心组件有哪些?"})
result = chat_model.invoke(history)

关键点:模型本身是无状态的,每次调用都是"从零开始"。必须手动把 assistant 消息追加到 history,模型才能理解上下文。


三、组件二:PromptTemplate(提示词模板)

3.1 解决什么问题

每次写完整提示词太麻烦?把"固定文本"和"动态参数"分离开,模板可复用。


3.2 PromptTemplate 基础用法

from langchain_core.prompts import PromptTemplate

# 定义模板({} 内是动态参数)
prompt_template = PromptTemplate(
    input_variables=["user_role", "subject"],
    template="请给{user_role}写一段50字左右的{subject}学习建议,语言简洁实用,分2个小要点。"
)

# 格式化
formatted = prompt_template.format(user_role="高校学生", subject="LangChain")
result = chat_model.invoke([{"role": "user", "content": formatted}])

3.3 FewShotPromptTemplate(少样本提示)

适用场景:需要模型按特定格式输出时,给几个示例让模型照着做。

from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

examples = [
    {"subject": "Python编程", "method": "核心目标:掌握基础语法..."},
    {"subject": "机器学习", "method": "核心目标:理解算法原理..."}
]

example_prompt = PromptTemplate(
    input_variables=["subject", "method"],
    template="\n学科:{subject}\n学习方法:{method}\n"
)

few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    suffix="学科:{new_subject}\n学习方法:",
    input_variables=["new_subject"]
)

核心逻辑:给模型看示例,它就会照着做。


3.4 ExampleSelector(工程化进阶)

问题 解决方案
示例过多,提示词冗长 ExampleSelector 动态筛选
示例维护困难 存 JSON/CSV,不硬编码
不同场景需要不同示例 按输入特征匹配

工程化最佳实践

  • 示例存 JSON/CSV
  • LengthBasedExampleSelector 按长度筛选
  • 自定义 Selector 按业务特征筛选(如难度)
  • 控制总长度,避免触发 token 限制

四、组件三:OutputParser(输出解析)

将非结构化文本 → 程序可直接处理的结构化数据

4.1 三种解析器对比

解析器 输出类型 适用场景 是否校验类型
StrOutputParser str 纯文本场景,LangGraph 中防止 AIMessage 污染 State
JsonOutputParser dict 快速 Demo,简单键值对
PydanticOutputParser BaseModel 工程化系统,强类型校验

选型原则:Demo → JsonOutputParser | 生产系统 → PydanticOutputParser | LangGraph → StrOutputParser


4.2 PydanticOutputParser(工程主线方案)

from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

class ToolInfo(BaseModel):
    tool_name: str = Field(description="工具名称")
    difficulty: str = Field(description="难度,仅可选:简单/中等/复杂")

parser = PydanticOutputParser(pydantic_object=ToolInfo)

prompt = PromptTemplate(
    template="{user_input},严格按照要求输出。\n{format_instructions}",
    input_variables=["user_input"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

chain = prompt | chat_model | parser
result = chain.invoke({"user_input": "请介绍1个 LangChain 工具"})
print(result.difficulty)        # 直接访问字段
print(result.model_dump())      # 转为字典

Field(description=...) 既是给开发者的文档,也是给模型的格式说明。字段不符合直接报错,提前规避风险


五、链式调用语法(| 管道符)⭐

LangChain 1.0+ 的核心语法,后续章节满屏都是。

# 链式调用:一行串联 prompt → llm → parser
chain = prompt | chat_model | parser
result = chain.invoke({"user_input": "..."})

# 对比传统写法(繁琐)
formatted = prompt.format(user_input="...")
response = chat_model.invoke(formatted)
result = parser.parse(response.content)

借鉴 Unix 管道哲学:左侧输出作为右侧输入。


六、本章小结表

组件 解决的问题 核心价值
ChatOpenAI 不同厂商模型接口不统一 统一接口,切换模型零感知
PromptTemplate 提示词重复编写、难维护 参数化设计,规范复用
FewShotPromptTemplate 模型不理解输出格式要求 示例引导,格式可控
ExampleSelector 示例过多、维护困难 动态筛选,工程化管理
StrOutputParser AIMessage 对象污染 State 统一转为纯字符串
JsonOutputParser 需要简单键值对结构 自动引导输出 JSON
PydanticOutputParser 需要强类型校验 字段不符直接报错

七、自检清单

学完 Task 2,用这个清单判断是否真正掌握:

  • 能说出 LLM 和 ChatModel 的区别,知道实际开发主要用哪个
  • 能解释三种消息角色的本质(不是身份区分,是约束层级)
  • 能默写 ChatOpenAI 四个关键参数
  • 能写出 PromptTemplate 定义 + format() 调用
  • 能说出 FewShotPromptTemplateExampleSelector 各自解决什么问题
  • 能默写三种 OutputParser 的名称、输出类型、是否校验
  • 能解释为什么 LangGraph 中必须用 StrOutputParser
  • 能用管道符 | 写出 prompt | llm | parser 链式调用
  • 能说明 PydanticOutputParserField(description=...) 的双重作用

八、你可能没想到的几个点

1. 为什么多轮对话要手动维护 history?
模型本身是无状态的(stateless),每次调用都是"从零开始"。只有把之前的 assistant 回复重新放进消息列表,模型才能"记住"上下文。这正是下一章 Memory 组件要解决的核心痛点。

2. StrOutputParser 看起来什么都没做,为什么这么重要?
因为在 LangGraph 中,如果 AIMessage 对象混进 State,后续节点处理会出错。StrOutputParser 不是在解析文本,是在统一数据类型

3. temperature 和 max_tokens 的实战意义?

  • temperature=0.3(严谨)→ 代码生成、事实问答
  • temperature=0.8(创造)→ 写作、创意、头脑风暴
  • max_tokens → 控制成本,防止模型"说太多",生产环境必设

4. 为什么工程化必须用 ExampleSelector 而不是硬编码示例?
示例数量多了之后:(1) 浪费 token (2) 超出上下文限制 (3) 不相关示例反而干扰输出。ExampleSelector 按需筛选,既省 token 又提高输出质量。

5. 第二章是"承上启下"的关键章

  • 承上:第一章的 llm.invoke() 在本章扩展为 prompt | llm | parser
  • 启下:本章手动维护 history 的痛点 → 第三章 Memory;ChatOpenAI 是第三章 Tool 组件的基础

九、连接三个底层核心

前言核心 本章关联
工具调用逻辑 ChatOpenAI 统一接口是工具调用的基础,下一章学 Tool 组件
状态机设计 输出解析器的结构化输出,是 LangGraph State 管理的前置知识
多智能体协作 StrOutputParser 让多 Agent 的输出统一为字符串,便于在 State 中流转

笔记整理:Easy-Langent × DataWhale · task2任务

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐