easy-langent Task02
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()调用 - 能说出
FewShotPromptTemplate和ExampleSelector各自解决什么问题 - 能默写三种 OutputParser 的名称、输出类型、是否校验
- 能解释为什么 LangGraph 中必须用
StrOutputParser - 能用管道符
|写出prompt | llm | parser链式调用 - 能说明
PydanticOutputParser中Field(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任务
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)