深入LangChain:模型封装与输出解析器
核心知识点讲解
模型封装(Model Wrappers)
LangChain提供了统一的模型封装接口,使开发者能够轻松集成各种语言模型。这些封装不仅提供了一致的API,还添加了一些实用功能,如重试机制、速率限制处理等。
1. 语言模型类型
LangChain支持多种类型的语言模型:
- LLM:基础语言模型,如GPT-3.5、GPT-4等,接收文本输入并返回文本输出
- ChatModel:聊天模型,如ChatGPT,使用消息格式进行交互
- TextEmbeddingModel:文本嵌入模型,将文本转换为向量表示
2. 常见模型封装
LangChain内置了对多种模型提供商的支持:
- OpenAI:GPT系列模型
- Hugging Face:各种开源模型
- Google Vertex AI:PaLM模型
- Anthropic:Claude模型
- Azure OpenAI:Azure上的OpenAI模型
- 国内模型:如智谱AI、百度文心一言、阿里通义千问等
输出解析器(Output Parsers)
输出解析器用于将模型的原始输出转换为更结构化的格式,使后续处理更加容易。
1. 解析器类型
LangChain提供了多种类型的输出解析器:
- 基础解析器:简单的文本处理,如分隔符解析
- 结构化解析器:将输出转换为JSON、字典等结构化格式
- 列表解析器:将输出转换为列表
- Pydantic解析器:使用Pydantic模型进行类型安全的解析
- 多模态解析器:处理文本和其他模态的输出
实用案例分析
案例1:使用不同类型的语言模型
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
# 1. 使用基础LLM
llm = OpenAI(temperature=0.7)
response = llm("什么是人工智能?")
print("LLM响应:", response)
# 2. 使用ChatModel
chat_model = ChatOpenAI(temperature=0.7)
from langchain.schema import HumanMessage, SystemMessage
messages = [
SystemMessage(content="你是一个专业的AI助手"),
HumanMessage(content="什么是人工智能?")
]
chat_response = chat_model(messages)
print("ChatModel响应:", chat_response.content)
# 3. 使用嵌入模型
embedding_model = OpenAIEmbeddings()
embedding = embedding_model.embed_query("什么是人工智能?")
print("嵌入向量长度:", len(embedding))
print("前5个值:", embedding[:5])案例2:自定义语言模型封装
from langchain.llms.base import LLM
from typing import Optional, List, Mapping, Any
import requests
class CustomLLM(LLM):
api_url: str
api_key: str
@property
def _llm_type(self) -> str:
return "custom"
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
data = {
"prompt": prompt,
"max_tokens": 1000
}
if stop:
data["stop"] = stop
response = requests.post(self.api_url, headers=headers, json=data)
response.raise_for_status()
return response.json()["text"]
@property
def _identifying_params(self) -> Mapping[str, Any]:
return {
"api_url": self.api_url
}
# 使用自定义模型
custom_llm = CustomLLM(
api_url="https://api.example.com/llm",
api_key="your-api-key"
)
response = custom_llm("什么是人工智能?")
print(response)案例3:使用不同类型的输出解析器
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
# 1. 基础解析器:使用分隔符
from langchain.output_parsers import DelimitedListOutputParser
output_parser = DelimitedListOutputParser(separator=",")
prompt = PromptTemplate(
template="列出5个{topic}相关的概念,用逗号分隔。\n{format_instructions}",
input_variables=["topic"],
partial_variables={"format_instructions": output_parser.get_format_instructions()}
)
llm = OpenAI(temperature=0)
chain = prompt | llm | output_parser
result = chain.invoke({"topic": "人工智能"})
print("分隔符解析器结果:", result)
# 2. 结构化解析器:JSON格式
from langchain.output_parsers import ResponseSchema, StructuredOutputParser
response_schemas = [
ResponseSchema(name="definition", description="术语的定义"),
ResponseSchema(name="applications", description="应用领域列表"),
ResponseSchema(name="advantages", description="优点列表"),
ResponseSchema(name="disadvantages", description="缺点列表")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
prompt = PromptTemplate(
template="请提供{term}的详细信息,包括定义、应用领域、优点和缺点。\n{format_instructions}",
input_variables=["term"],
partial_variables={"format_instructions": output_parser.get_format_instructions()}
)
chain = prompt | llm | output_parser
result = chain.invoke({"term": "人工智能"})
print("JSON解析器结果:")
print("定义:", result["definition"])
print("应用领域:", result["applications"])
print("优点:", result["advantages"])
print("缺点:", result["disadvantages"])
# 3. Pydantic解析器:类型安全
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from typing import List
class AIInfo(BaseModel):
definition: str = Field(description="术语的定义")
applications: List[str] = Field(description="应用领域列表")
advantages: List[str] = Field(description="优点列表")
disadvantages: List[str] = Field(description="缺点列表")
output_parser = PydanticOutputParser(pydantic_object=AIInfo)
prompt = PromptTemplate(
template="请提供{term}的详细信息,包括定义、应用领域、优点和缺点。\n{format_instructions}",
input_variables=["term"],
partial_variables={"format_instructions": output_parser.get_format_instructions()}
)
chain = prompt | llm | output_parser
result = chain.invoke({"term": "人工智能"})
print("Pydantic解析器结果:")
print("类型:", type(result))
print("定义:", result.definition)
print("应用领域:", result.applications)
print("优点:", result.advantages)
print("缺点:", result.disadvantages)代码解析
模型封装
基础LLM:
OpenAI类封装了OpenAI的文本补全API,提供了简单的文本输入输出接口。ChatModel:
ChatOpenAI类封装了OpenAI的聊天API,使用消息格式进行交互,更适合多轮对话场景。嵌入模型:
OpenAIEmbeddings类封装了OpenAI的嵌入API,用于将文本转换为向量表示,常用于检索和相似度计算。自定义模型:通过继承
LLM基类并实现_call方法,可以创建自定义的模型封装,集成任何语言模型API。
输出解析器
分隔符解析器:
DelimitedListOutputParser使用指定的分隔符将模型输出分割成列表,适用于需要多个项目的场景。结构化解析器:
StructuredOutputParser将模型输出解析为JSON格式,需要定义响应模式来指导模型生成结构化输出。Pydantic解析器:
PydanticOutputParser使用Pydantic模型进行解析,提供类型安全的输出,自动处理类型转换和验证。LCEL语法:使用
|操作符可以简洁地构建处理链,将提示词模板、模型和解析器连接在一起。
高级技巧
1. 自定义输出解析器
对于复杂的输出格式,可以创建自定义的输出解析器:
from langchain.output_parsers import BaseOutputParser
from typing import List
class CustomOutputParser(BaseOutputParser[dict]):
def parse(self, text: str) -> dict:
# 自定义解析逻辑
lines = text.strip().split('\n')
result = {}
for line in lines:
if ':' in line:
key, value = line.split(':', 1)
result[key.strip()] = value.strip()
return result
def get_format_instructions(self) -> str:
return "请按照'键: 值'的格式输出,每行一个键值对。"
# 使用自定义解析器
parser = CustomOutputParser()
prompt = PromptTemplate(
template="请提供{term}的信息。\n{format_instructions}",
input_variables=["term"],
partial_variables={"format_instructions": parser.get_format_instructions()}
)
chain = prompt | llm | parser
result = chain.invoke({"term": "人工智能"})
print("自定义解析器结果:", result)2. 模型配置优化
可以通过配置模型参数来优化性能和成本:
# 配置模型参数
llm = OpenAI(
temperature=0.7, # 创造性
max_tokens=1000, # 最大输出 tokens
top_p=0.95, # 采样阈值
frequency_penalty=0, # 频率惩罚
presence_penalty=0, # 存在惩罚
model_name="gpt-3.5-turbo-instruct", # 模型名称
request_timeout=30, # 请求超时
max_retries=3 # 最大重试次数
)
# 配置聊天模型
chat_model = ChatOpenAI(
temperature=0.7,
model_name="gpt-4",
max_tokens=2000,
request_timeout=60,
max_retries=3
)3. 批量处理
对于多个输入,可以使用批量处理提高效率:
# 批量处理多个输入
inputs = ["什么是人工智能?", "什么是机器学习?", "什么是深度学习?"]
responses = llm.generate(inputs)
for i, generation in enumerate(responses.generations):
print(f"输入: {inputs[i]}")
print(f"输出: {generation[0].text}")
print()总结
LangChain的模型封装和输出解析器提供了强大的工具,使开发者能够:
- 轻松集成各种语言模型:统一的接口和内置的封装使集成不同模型变得简单
- 自定义模型集成:通过继承基类可以集成任何语言模型API
- 结构化输出:使用各种解析器将模型输出转换为结构化格式
- 类型安全:Pydantic解析器提供类型安全的输出处理
- 灵活的处理链:LCEL语法使构建处理流程变得简洁明了
这些功能为我们构建复杂的AI智能体系统提供了坚实的基础。在接下来的几集中,我们将学习如何使用这些组件构建更复杂的应用,如问答系统、对话机器人等。
课后思考
- 如何选择合适的语言模型类型(LLM vs ChatModel)?
- 什么时候应该创建自定义的输出解析器?
- 如何优化模型配置以平衡性能、成本和质量?
- 如何处理模型输出的不确定性和错误?
在下一集中,我们将学习如何构建第一条链:简单的问答链,将模型封装和输出解析器应用到实际场景中。