第 1 课
← 返回系列列表

模型调用与提示词管理

LangChain for LLM App Dev — LangChain 应用开发

LangChain 的 Model I/O 模块,管理 LLM 调用与提示词模板。

模型调用与提示词管理

课程简介

LangChain 的 Model I/O 模块,管理 LLM 调用与提示词模板。

🎬 本课程视频:LangChain for LLM App Dev — LangChain 应用开发


LangChain Model I/O:统一模型调用与提示词管理

一、LangChain 概览

LangChain 是目前最流行的 LLM 应用开发框架。它解决的核心问题是:将 LLM 应用开发的通用模式抽象为可复用的组件

LangChain 的架构分为六个核心模块:
- Model I/O:模型调用、提示词管理、输出解析
- Retrieval:文档加载、向量存储、检索
- Chains:链式调用组合
- Memory:对话记忆管理
- Agents:智能体框架
- Callbacks:回调与监控

今天我们重点学习 Model I/O 模块。

二、ChatModel 和 LLM 的统一抽象

2.1 多模型适配问题

不同的 LLM 提供商(OpenAI、Anthropic、Google、开源模型)有不同的 API 接口:
- OpenAI:使用 openai.ChatCompletion.create()
- Anthropic:使用 anthropic.Anthropic().messages.create()
- 接口参数不同、返回值格式不同、错误处理方式不同

如果直接在代码中调用模型 API,切换模型需要修改大量代码。

2.2 LangChain 的抽象层

LangChain 提供一个统一的接口层:

from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

# OpenAI
llm = ChatOpenAI(model="gpt-4", temperature=0)

# 切换到 Anthropic——只需改这一行
# llm = ChatAnthropic(model="claude-3-5-sonnet-20240620", temperature=0)

# 使用方式完全相同
response = llm.invoke("请用中文介绍一下机器学习")

2.3 关键参数

llm = ChatOpenAI(
    model="gpt-4",          # 模型名称
    temperature=0.7,        # 随机性(0=确定,1=随机)
    max_tokens=1024,        # 最大输出长度
    timeout=30,             # 超时时间
    max_retries=2,          # 最大重试次数
    streaming=True           # 是否流式输出
)

三、PromptTemplate:提示词模板管理

3.1 为什么需要模板?

在复杂应用中,同一个提示词结构需要重复使用,只是填充不同的变量。硬编码提示词会导致:
- 重复代码:同样的提示词结构到处复制
- 难以维护:修改提示词需要修改多处代码
- 版本混乱:不同地方的提示词版本可能不同步

3.2 PromptTemplate 基础

from langchain.prompts import PromptTemplate

# 定义模板
template = PromptTemplate.from_template(
    "请用{language}帮我写一个{function_name}函数,"
    "要求实现{requirement}。"
)

# 填充变量
prompt = template.invoke({
    "language": "Python",
    "function_name": "二分查找",
    "requirement": "输入一个有序数组和目标值,返回目标值的索引"
})

print(prompt.text)
# 输出:请用Python帮我写一个二分查找函数,要求实现输入一个有序数组和目标值,返回目标值的索引。

3.3 ChatPromptTemplate 对话模板

对于对话模型,我们需要管理多轮消息,而不是单段文本。

from langchain.prompts import ChatPromptTemplate
from langchain.prompts.chat import SystemMessagePromptTemplate, HumanMessagePromptTemplate

# 构建对话模板
chat_template = ChatPromptTemplate.from_messages([
    ("system", "你是一位{role}专家。你的回答应该{style}。"),
    ("human", "{question}"),
    ("ai", "让我思考一下{question}这个问题。"),
    ("human", "请给出最终答案。")
])

messages = chat_template.invoke({
    "role": "Python编程",
    "style": "简洁明了,附带代码示例",
    "question": "如何在Python中读取CSV文件"
})

3.4 FewShotPromptTemplate 少样本模板

from langchain.prompts import FewShotPromptTemplate, PromptTemplate

# 定义示例
examples = [
    {"input": "苹果", "output": "水果/公司"},
    {"input": "银行", "output": "金融机构/河岸"},
]

# 示例模板
example_prompt = PromptTemplate.from_template(
    "输入:{input}
输出:{output}"
)

# 少样本提示模板
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="请判断以下词语的常见含义:",
    suffix="输入:{input}
输出:",
    input_variables=["input"]
)

print(few_shot_prompt.invoke({"input": "Java"}))

# 输出:
# 请判断以下词语的常见含义:
# 输入:苹果
# 输出:水果/公司
# 输入:银行
# 输出:金融机构/河岸
# 输入:Java
# 输出:

四、OutputParser:输出解析器

4.1 输出结构化的必要性

LLM 的输出是自然语言,但在工程场景中我们需要:
- JSON 对象供程序解析
- 特定格式的数据供下游系统消费
- 错误时优雅处理而非崩溃

4.2 常用输出解析器

StructuredOutputParser——根据 JSON Schema 约束输出:

from langchain.output_parsers import StructuredOutputParser, ResponseSchema

# 定义期望的输出结构
response_schemas = [
    ResponseSchema(name="summary", description="文章的一句话摘要"),
    ResponseSchema(name="key_points", description="文章的3-5个核心要点"),
    ResponseSchema(name="sentiment", description="文章的情感倾向:正面/负面/中性")
]

parser = StructuredOutputParser.from_response_schemas(response_schemas)

# 在提示词中加入格式说明
format_instructions = parser.get_format_instructions()

prompt = PromptTemplate.from_template(
    "分析以下文章:
{article}

{format_instructions}"
)

# 执行
input_data = prompt.invoke({
    "article": "...",
    "format_instructions": format_instructions
})
output = llm.invoke(input_data)

# 解析输出
parsed = parser.parse(output.content)
print(parsed["summary"])
print(parsed["key_points"])
print(parsed["sentiment"])

PydanticOutputParser——基于 Pydantic 模型的类型安全解析:

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

class ArticleAnalysis(BaseModel):
    summary: str = Field(description="一句话摘要")
    key_points: list[str] = Field(description="3-5个核心要点")
    sentiment: str = Field(description="情感倾向")

parser = PydanticOutputParser(pydantic_object=ArticleAnalysis)

# 解析时自动校验类型
result: ArticleAnalysis = parser.parse(output.content)
print(result.summary)
print(result.key_points[0])

4.3 错误处理

try:
    parsed = parser.parse(output.content)
except Exception as e:
    # 解析失败时,尝试修复
    print(f"解析失败:{e}")
    print(f"原始输出:{output.content}")

    # 尝试让模型重新生成符合格式的输出
    fix_prompt = f"请确保你的输出符合以下格式:
{format_instructions}"
    fixed_output = llm.invoke(fix_prompt + output.content)
    parsed = parser.parse(fixed_output.content)

五、管道运算符

LangChain 支持使用 | 运算符将组件串联起来:

# 管道:prompt → model → parser
chain = prompt | llm | parser

# 执行
result = chain.invoke({
    "article": article_text
})

这种方式让代码非常简洁:prompt | model | parser,每个组件只负责一件事,组合起来就是完整的处理流程。

六、完整示例

from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.output_parsers import CommaSeparatedListOutputParser

# 初始化
llm = ChatOpenAI(model="gpt-4", temperature=0.7)

# 构建管道
prompt = ChatPromptTemplate.from_template(
    "为{product}生成5个吸引人的营销口号,用逗号分隔。"
)
parser = CommaSeparatedListOutputParser()
chain = prompt | llm | parser

# 执行
slogans = chain.invoke({"product": "一款AI笔记应用"})
for i, slogan in enumerate(slogans, 1):
    print(f"{i}. {slogan}")

七、总结

LangChain 的 Model I/O 模块通过统一的模型抽象层、灵活的提示词模板系统和强大的输出解析器,极大地简化了 LLM 应用的开发过程。开发者只需切换模型名称即可在不同模型间迁移,模板系统让提示词的管理和维护变得清晰,输出解析器确保模型输出可以被程序精确消费。管道运算符 | 让组件组合变得简洁优雅。

七、Output Parser 详解

7.1 为什么需要 Output Parser?

LLM 输出的是字符串,但应用往往需要结构化数据。Output Parser 是连接 LLM 和应用之间的桥梁。

7.2 常用 Parser 类型

from langchain.output_parsers import (
    CommaSeparatedListOutputParser,
    PydanticOutputParser,
    StructuredOutputParser,
    JsonOutputParser,
)

# 逗号分隔列表解析器
parser = CommaSeparatedListOutputParser()

# 结构化输出解析器
parser = StructuredOutputParser.from_response_schemas([
    ResponseSchema(name="name", description="人名"),
    ResponseSchema(name="age", description="年龄"),
])

# JSON 解析器
parser = JsonOutputParser()

7.3 自定义 Parser

from langchain.schema import BaseOutputParser

class MyParser(BaseOutputParser):
    def parse(self, text: str):
        # 自定义解析逻辑
        return text.strip().split('\n')

八、三者的协作流程

完整的 Model I/O 流程:

用户输入 → PromptTemplate(格式化) → LLM(推理) → OutputParser(解析) → 结构化输出

九、总结

关键要点回顾:
- ChatModel 和 CompletionModel 的区别
- PromptTemplate 的参数化和最佳实践
- ChatPromptTemplate 的多消息支持
- Output Parser 将字符串转为结构化数据
- Model I/O 是 LangChain 应用的基础层

七、Output Parser 详解

7.1 为什么需要 Output Parser?

LLM 输出的是字符串,但应用往往需要结构化数据。Output Parser 是连接 LLM 和应用之间的桥梁。

7.2 常用 Parser 类型

from langchain.output_parsers import (
    CommaSeparatedListOutputParser,
    PydanticOutputParser,
    StructuredOutputParser,
    JsonOutputParser,
)

# 逗号分隔列表解析器
parser = CommaSeparatedListOutputParser()

# 结构化输出解析器
parser = StructuredOutputParser.from_response_schemas([
    ResponseSchema(name="name", description="人名"),
    ResponseSchema(name="age", description="年龄"),
])

# JSON 解析器
parser = JsonOutputParser()

7.3 自定义 Parser

from langchain.schema import BaseOutputParser

class MyParser(BaseOutputParser):
    def parse(self, text: str):
        # 自定义解析逻辑
        return text.strip().split('\n')

八、三者的协作流程

完整的 Model I/O 流程:

用户输入 → PromptTemplate(格式化) → LLM(推理) → OutputParser(解析) → 结构化输出

九、总结

关键要点回顾:
- ChatModel 和 CompletionModel 的区别
- PromptTemplate 的参数化和最佳实践
- ChatPromptTemplate 的多消息支持
- Output Parser 将字符串转为结构化数据
- Model I/O 是 LangChain 应用的基础层

七、Output Parser 详解

7.1 为什么需要 Output Parser?

LLM 输出的是字符串,但应用往往需要结构化数据。Output Parser 是连接 LLM 和应用之间的桥梁。

7.2 常用 Parser 类型

from langchain.output_parsers import (
    CommaSeparatedListOutputParser,
    PydanticOutputParser,
    StructuredOutputParser,
    JsonOutputParser,
)

# 逗号分隔列表解析器
parser = CommaSeparatedListOutputParser()

# 结构化输出解析器
parser = StructuredOutputParser.from_response_schemas([
    ResponseSchema(name="name", description="人名"),
    ResponseSchema(name="age", description="年龄"),
])

# JSON 解析器
parser = JsonOutputParser()

7.3 自定义 Parser

from langchain.schema import BaseOutputParser

class MyParser(BaseOutputParser):
    def parse(self, text: str):
        # 自定义解析逻辑
        return text.strip().split('\n')

八、三者的协作流程

完整的 Model I/O 流程:

用户输入 → PromptTemplate(格式化) → LLM(推理) → OutputParser(解析) → 结构化输出

九、总结

关键要点回顾:
- ChatModel 和 CompletionModel 的区别
- PromptTemplate 的参数化和最佳实践
- ChatPromptTemplate 的多消息支持
- Output Parser 将字符串转为结构化数据
- Model I/O 是 LangChain 应用的基础层

延伸阅读

链式调用与记忆系统 →