从零开始学LangChain(二):Models 模型详解

从零开始学LangChain(二):Models 模型详解

本系列教程将带你从零开始学习LangChain框架,构建强大的AI应用程序。

什么是Models?

在LangChain中,Models是指与大语言模型(LLMs)交互的接口。LangChain提供了统一的API,让你可以轻松切换不同的模型提供商,而无需修改代码。

LangChain支持两种主要的模型类型。LLM是大语言模型,接收文本字符串并返回文本字符串,适用于文本补全、翻译、摘要等场景。Chat Model是聊天模型,接收消息列表并返回消息,专为对话系统和聊天机器人设计。

核心区别在于输入输出的格式。LLM输入字符串输出字符串,而Chat Model输入消息列表输出消息对象。

LLM 使用指南

LangChain提供了多种LLM的集成,包括OpenAI、Anthropic、Hugging Face等。

使用OpenAI LLM

1
2
3
4
5
6
7
8
9
10
11
12
from langchain_openai import OpenAI

# 初始化LLM(使用text-davinci-003等模型)
llm = OpenAI(
model="gpt-3.5-turbo-instruct",
temperature=0.7,
max_tokens=256
)

# 调用模型
response = llm.invoke("解释什么是机器学习")
print(response)

使用Anthropic Claude

1
2
3
4
5
6
7
8
9
from langchain_anthropic import AnthropicLLM

llm = AnthropicLLM(
model="claude-3-opus-20240229",
temperature=0.5,
max_tokens=1024
)

response = llm.invoke("用简单的比喻解释量子计算")

控制生成参数

理解并正确使用这些参数,能显著提升输出质量。temperature控制随机性,范围0-2,创意任务用0.7,精确任务用0。max_tokens限制最大生成token数,通常设置为256-2048。top_p是核采样参数,范围0-1,通常设为0.9,与temperature二选一。frequency_penalty是频率惩罚,范围-2到2,用于减少重复,推荐0-0.5。presence_penalty是存在惩罚,同样范围-2到2,用于鼓励新话题,推荐0-0.5。

让我们看看温度参数的实际效果。

1
2
3
4
5
6
7
8
9
10
11
from langchain_openai import OpenAI

# 低温度:输出确定性和一致性高
llm_cold = OpenAI(temperature=0)
print("低温输出:")
print(llm_cold.invoke("讲一个关于程序员的故事"))

# 高温度:输出更有创意和多样性
llm_hot = OpenAI(temperature=1.2)
print("\n高温输出:")
print(llm_hot.invoke("讲一个关于程序员的故事"))

Chat Model 使用指南

Chat Model专为对话场景设计,支持系统消息、多轮对话等高级功能。

基础用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage, AIMessage

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

# 构建消息列表
messages = [
SystemMessage(content="你是一个友好的Python导师,擅长用比喻解释复杂概念。"),
HumanMessage(content="什么是装饰器?")
]

# 调用模型
response = chat.invoke(messages)
print(response.content)

多轮对话

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, AIMessage

chat = ChatOpenAI(model="gpt-3.5-turbo")

# 模拟对话历史
conversation = [
HumanMessage(content="我叫张三"),
AIMessage(content="你好张三,很高兴认识你!"),
HumanMessage(content="我还叫什么名字?")
]

response = chat.invoke(conversation)
print(response.content)

使用提示词模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate

chat = ChatOpenAI(model="gpt-3.5-turbo")

# 创建提示词模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一位专业的{role}。"),
("human", "请回答:{question}")
])

# 格式化并调用
chain = prompt | chat
response = chain.invoke({
"role": "Python工程师",
"question": "Python中的GIL是什么?"
})

print(response.content)

流式输出

流式输出让用户实时看到生成过程,大幅提升体验。

基础流式输出

1
2
3
4
5
6
7
8
9
from langchain_openai import ChatOpenAI

chat = ChatOpenAI(model="gpt-3.5-turbo")

# 使用stream方法
for chunk in chat.stream("请用3个要点介绍LangChain"):
print(chunk.content, end="", flush=True)

print() # 换行

异步流式输出

1
2
3
4
5
6
7
8
9
10
11
12
13
import asyncio
from langchain_openai import ChatOpenAI

async def stream_chat():
chat = ChatOpenAI(model="gpt-3.5-turbo")

async for chunk in chat.astream("写一首关于编程的诗"):
print(chunk.content, end="", flush=True)

print()

# 运行异步函数
asyncio.run(stream_chat())

流式输出到UI

1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain_openai import ChatOpenAI
from typing import Iterator

def create_streaming_ui(prompt: str) -> Iterator[str]:
"""模拟UI中显示流式输出"""
chat = ChatOpenAI(model="gpt-3.5-turbo")

for chunk in chat.stream(prompt):
yield chunk.content # 返回给UI组件显示

# 使用示例
for text in create_streaming_ui("介绍Python"):
print(text, end="", flush=True)

结构化输出

让LLM按照指定格式输出,便于程序处理。

使用OutputFixerParser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from langchain_openai import ChatOpenAI
from langchain.output_parsers import OutputFixingParser
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

# 定义输出模型
class Recipe(BaseModel):
name: str = Field(description="菜名")
ingredients: list[str] = Field(description="食材列表")
steps: list[str] = Field(description="制作步骤")

# 创建解析器
parser = PydanticOutputParser(pydantic_object=Recipe)

# 创建带有纠错的解析器
fixing_parser = OutputFixingParser.from_llm(
parser=parser,
llm=ChatOpenAI(model="gpt-3.5-turbo")
)

# 使用
chat = ChatOpenAI(model="gpt-3.5-turbo")
prompt = "教我做番茄炒蛋"

response = chat.invoke(prompt + "\n\n" + parser.get_format_instructions())
recipe = fixing_parser.parse(response.content)

print(f"菜名: {recipe.name}")
print(f"食材: {recipe.ingredients}")
print(f"步骤: {recipe.steps}")

JSON模式输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from langchain_openai import ChatOpenAI

chat = ChatOpenAI(model="gpt-3.5-turbo")

prompt = """
请以JSON格式返回以下信息:
- 书名
- 作者
- 出版年份

书籍:《Python编程从入门到实践》
"""

response = chat.invoke(prompt)
print(response.content)

输出会是JSON格式的书名、作者和出版年份信息。

模型切换最佳实践

使用环境变量配置

1
2
3
4
5
6
7
8
9
10
11
12
13
import os
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

# 根据环境变量选择模型
model_provider = os.getenv("MODEL_PROVIDER", "openai")

if model_provider == "openai":
model = ChatOpenAI(model="gpt-4")
elif model_provider == "anthropic":
model = ChatAnthropic(model="claude-3-opus-20240229")
else:
raise ValueError(f"Unknown provider: {model_provider}")

创建模型工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

def create_llm(provider: str = "openai", **kwargs):
"""模型工厂函数"""
providers = {
"openai": ChatOpenAI,
"anthropic": ChatAnthropic,
}

if provider not in providers:
raise ValueError(f"Unknown provider: {provider}")

return providers[provider](**kwargs)

# 使用
model = create_llm(
provider="openai",
model="gpt-4",
temperature=0.7
)

实战示例:智能摘要生成器

让我们创建一个实用的摘要生成工具。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from enum import Enum

class SummaryStyle(str, Enum):
BRIEF = "brief"
DETAILED = "detailed"
BULLET_POINTS = "bullet_points"
TLDR = "tldr"

class ArticleSummarizer:
def __init__(self):
self.chat = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.5)
self.prompt = ChatPromptTemplate.from_messages([
("system", "你是一位专业的文章摘要专家。"),
("human", """请为以下文章生成{style}摘要:

文章标题:{title}
文章内容:{content}

要求:
1. 保留核心信息
2. 语言简洁明了
3. 字数控制在{max_words}字以内""")
])

def summarize(
self,
title: str,
content: str,
style: SummaryStyle = SummaryStyle.BRIEF,
max_words: int = 100
) -> str:
"""生成文章摘要"""

chain = self.prompt | self.chat

style_map = {
SummaryStyle.BRIEF: "简要的",
SummaryStyle.DETAILED: "详细的",
SummaryStyle.BULLET_POINTS: "要点式",
SummaryStyle.TLDR: "一句话"
}

response = chain.invoke({
"title": title,
"content": content,
"style": style_map[style],
"max_words": max_words
})

return response.content

# 使用示例
summarizer = ArticleSummarizer()

article = """
LangChain是一个用于开发由大型语言模型(LLMs)驱动的应用程序的框架。
它提供了标准化的接口来调用不同的LLM,支持链式调用、工具集成、记忆管理等功能。
使用LangChain,开发者可以快速构建聊天机器人、文档问答、代码生成等AI应用。
"""

print("=== 简要摘要 ===")
print(summarizer.summarize(
title="LangChain入门",
content=article,
style=SummaryStyle.BRIEF
))

print("\n=== 要点式摘要 ===")
print(summarizer.summarize(
title="LangChain入门",
content=article,
style=SummaryStyle.BULLET_POINTS
))

print("\n=== 一句话摘要 ===")
print(summarizer.summarize(
title="LangChain入门",
content=article,
style=SummaryStyle.TLDR,
max_words=30
))

常见错误与解决方案

API密钥未设置

症状是出现ValueError: Please set OPENAI_API_KEY environment variable错误。解决方案是加载环境变量并验证密钥是否设置。

1
2
3
4
5
6
7
8
9
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 验证密钥
if not os.getenv("OPENAI_API_KEY"):
raise ValueError("请设置OPENAI_API_KEY环境变量")

模型不支持流式输出

症状是出现NotImplementedError: stream() is not supported错误。解决方案是检查是否支持流式输出,如果不支持则回退到普通调用。

1
2
3
4
5
6
7
8
9
10
chat = ChatOpenAI(model="gpt-3.5-turbo")

# 检查是否支持流式输出
if hasattr(chat, 'stream'):
for chunk in chat.stream("Hello"):
print(chunk.content)
else:
# 回退到普通调用
response = chat.invoke("Hello")
print(response.content)

输出token超限

症状是出现openai.error.InvalidRequestError: This model's maximum context length is 4097 tokens错误。解决方案是限制输出长度或使用更长的上下文模型。

1
2
3
4
5
6
7
8
# 限制输出长度
chat = ChatOpenAI(
model="gpt-3.5-turbo",
max_tokens=1000 # 限制输出token数
)

# 或使用更长的上下文模型
chat_long = ChatOpenAI(model="gpt-3.5-turbo-16k")

系列导航