今日内容
---------------重点核心部分---------------
# 1 LangChain核心组件之 Agents智能体
# 2 LangChain核心组件之 Models模型
# 3 LangChain核心组件之 Messages消息
# 4 LangChain核心组件之 Tools工具
# 5 LangChain核心组件之 Short-term memory短期记忆
# 6 LangChain核心组件之 Streaming流式传输
# 7 LangChain核心组件之Structured output 结构化输出
---------------高级应用部分---------------
# 8 LangChain高级之Middleware 中间件
# 9 LangChain高级之Guardrails 护栏
# 10 LangChain高级之runtime运行时
# 11 LangChain高级之Context engineering上下文工程
# 12 LangChain高级之Model Context Protocol (MCP)模型上下文协议
# 13 LangChain高级之 Human-in-the-loop 人机交互
# 14 LangChain高级之 Multi-agent 多智能体
# 15 LangChain高级之 Retrieval 检索
# 16 LangChain高级之 Long-term memory 长期记忆
--------------使用LangSmith-需要付费---------------------
# 17 LangSmith Studio
# 18 Test 测试
# 19 Agent 聊天用户界面
# 20 Deployment 部署
# 21 Observability 可观测性
1 LangChain 核心组件之流式传输(Streaming)
# 1 定义
## LangChain 实现了一个流式传输系统来提供实时更新。
## 流式传输对于增强基于 LLM(大型语言模型)构建的应用程序的响应能力至关重要。通过渐进式地显示输出,即使在完整的响应准备好之前,流式传输也能显著改善用户体验,尤其是在处理 LLM 的延迟时。
# 2 概述 (Overview)
## LangChain 的流式传输系统允许您将代理运行的实时反馈展示给您的应用程序。
## LangChain 流式传输可能实现的功能:
流式传输代理进度 — 在每个代理步骤后获取状态更新。
流式传输 LLM 令牌 — 在语言模型生成令牌时进行流式传输。
流式传输自定义更新 — 发出用户定义的信号(例如,"Fetched 10/100 records")。
流式传输多种模式 — 可选择 updates(代理进度)、messages(LLM 令牌 + 元数据)或 custom(任意用户数据)。
# 3 代理进度 (Agent progress)
要流式传输代理进度,请使用 stream_mode="updates" 的 stream 或 astream 方法。这会在每个代理步骤后发出一个事件。
例如,如果您有一个调用工具一次的代理,您应该会看到以下更新:
LLM 节点: 带有工具调用请求的 AIMessage
工具节点: 带有执行结果的 ToolMessage
LLM 节点: 最终的 AI 响应
agent---》问问题---》大模型解决不了--》调用工具--》返回给大模型--》输出给我们
# 回顾一下
models 调用工具麻烦--》bind工具--》自己执行tool--》执行的结果,手动给 models--》大模型返回
agent 调用工具非常简单--》@tool装饰去---》创建agent时---》传入可用工具【会自动读取工具的doc文档】--》LangChain会自己调用工具--》并返回给大模型---》最终输出
# 4 LLM 令牌 (LLM tokens):要在 LLM 生成令牌时流式传输它们,请使用 stream_mode="messages"。您可以在下面看到agent流式传输工具调用和最终响应的输出
# 5 自定义更新 (Custom updates):要流式传输工具在执行过程中发出的更新,您可以使用 get_stream_writer-->langgraph中的工具
# 6 自定义更新多种模式
-stream_mode=【messages,updates】
# 7 禁用流式传输 (Disable streaming):在某些应用程序中,您可能需要为给定的模型禁用单个令牌的流式传输。这对于像多代理系统这样的场景很有用,以便控制哪些代理流式传输它们的输出
1.1 Agent进度
要流式传输代理进度,请使用 `stream_mode="updates"` 的 [`stream`]方法。这会在**每个代理步骤**后发出一个事件
from typing import Literal
from typing_extensions import TypedDict
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain.tools import tool
from langgraph.config import get_stream_writer
# 1 连接model大模型
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 2 编写一个工具
@tool
def get_weather(city: str) -> str:
"""获取给定城市的天气。"""
return f"It's always sunny in {city}!"
# 3 创建agent
agent = create_agent(
model=model,
tools=[get_weather], # 有一个工具供model使用
)
# 4 流式传输
for chunk in agent.stream(
{"messages": [{"role": "user", "content": "上海的天气怎么样?"}]},
stream_mode="updates"
):
for step, data in chunk.items():
print(f"step: {step}")
print(f"content: {data['messages'][-1].content_blocks}")
step: model
content: [{'type': 'tool_call', 'name': 'get_weather', 'args': {'city': '上海'}, 'id': 'call_c389f4a1c2a04ff697d8e4'}]
step: tools
content: [{'type': 'text', 'text': "It's always sunny in 上海!"}]
step: model
content: [{'type': 'text', 'text': '上海的天气总是晴朗的!'}]
1.2 LLM令牌token
# 要在 LLM 生成token时流式传输它们,请使用 `stream_mode="messages"`。您可以在下面看到代理流式传输工具调用和最终响应的输出
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain.tools import tool
# 1 连接model大模型
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 2 编写一个工具
@tool
def get_weather(city: str) -> str:
"""获取给定城市的天气。"""
return f"It's always sunny in {city}!"
# 3 创建agent
agent = create_agent(
model=model,
tools=[get_weather], # 有一个工具供model使用
)
# 4 流式传输
for token, metadata in agent.stream(
{"messages": [{"role": "user", "content": "上海的天气怎么样?"}]},
stream_mode="messages"
):
print(f"node: {metadata['langgraph_node']}")
print(f"content: {token.content_blocks}")
print("\n")
node: model
content: [{'type': 'tool_call_chunk', 'id': 'call_46da6ef34fb24f62a04d66', 'name': 'get_weather', 'args': '', 'index': 0}]
node: model
content: [{'type': 'tool_call_chunk', 'id': 'call_46da6ef34fb24f62a04d66', 'name': '', 'args': '{"city": "', 'index': 0}]
node: model
content: [{'type': 'tool_call_chunk', 'id': '', 'name': None, 'args': '上海"}', 'index': 0}]
node: model
content: []
node: model
content: []
node: tools
content: [{'type': 'text', 'text': "It's always sunny in 上海!"}]
node: model
content: []
node: model
content: [{'type': 'text', 'text': '上海'}]
node: model
content: [{'type': 'text', 'text': '的天气总是'}]
node: model
content: [{'type': 'text', 'text': '晴'}]
node: model
content: [{'type': 'text', 'text': '朗的'}]
node: model
content: [{'type': 'text', 'text': '!'}]
node: model
content: []
node: model
content: []
1.3 自定义更新
# 要流式传输工具在执行过程中发出的更新,可以使用 [`get_stream_writer`]
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain.tools import tool
# pip install langgraph
from langgraph.config import get_stream_writer
# 1 连接model大模型
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 2 编写一个工具
@tool
def get_weather(city: str) -> str:
"""获取给定城市的天气。"""
# 使用 langgraph的get_stream_writer
writer = get_stream_writer()
# 流式传输任何任意数据
writer(f"Looking up data for city: {city}")
writer(f"Acquired data for city: {city}")
return f"It's always sunny in {city}!"
# 3 创建agent
agent = create_agent(
model=model,
tools=[get_weather], # 有一个工具供model使用
)
# 4 流式传输
for chunk in agent.stream(
{"messages": [{"role": "user", "content": "上海天气怎么样?"}]},
stream_mode="custom"
):
print(chunk)
Looking up data for city: 上海
Acquired data for city: 上海
1.4 自定义更新多种模式[多种模式组合]
可以通过将流模式作为列表传递来指定多种流式传输模式:`stream_mode=["updates", "custom"]`
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain.tools import tool
# pip install langgraph
from langgraph.config import get_stream_writer
# 1 连接model大模型
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 2 编写一个工具
@tool
def get_weather(city: str) -> str:
"""获取给定城市的天气。"""
# 使用 langgraph的get_stream_writer
writer = get_stream_writer()
# 流式传输任何任意数据
writer(f"Looking up data for city: {city}")
writer(f"Acquired data for city: {city}")
return f"It's always sunny in {city}!"
# 3 创建agent
agent = create_agent(
model=model,
tools=[get_weather], # 有一个工具供model使用
)
# 4 流式传输
for stream_mode, chunk in agent.stream(
{"messages": [{"role": "user", "content": "上海天气怎么样?"}]},
stream_mode=["updates", "custom"]
):
print(f"stream_mode: {stream_mode}")
print(f"content: {chunk}")
print("\n")
stream_mode: updates
content: {'model': {'messages': [AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 19, 'prompt_tokens': 150, 'total_tokens': 169, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-9331be53-ba66-9f67-a4cc-7c9676dc714d', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--019cb8dd-2714-7f91-80e6-8dccf38b4071-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '上海'}, 'id': 'call_00677a024ca540c5a30a54', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 150, 'output_tokens': 19, 'total_tokens': 169, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]}}
stream_mode: custom
content: Looking up data for city: 上海
stream_mode: custom
content: Acquired data for city: 上海
stream_mode: updates
content: {'tools': {'messages': [ToolMessage(content="It's always sunny in 上海!", name='get_weather', id='d522c05f-b896-4fd1-a6ef-a1bb945919eb', tool_call_id='call_00677a024ca540c5a30a54')]}}
stream_mode: updates
content: {'model': {'messages': [AIMessage(content='上海的天气总是晴朗的!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 8, 'prompt_tokens': 190, 'total_tokens': 198, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-6800de1c-ef4d-98d0-8a1b-2d5da68163bd', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019cb8dd-2bd1-75a0-ab5d-e8e5fa87fd49-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 190, 'output_tokens': 8, 'total_tokens': 198, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]}}
1.5 禁用流式传输
# 1 多Model使用
agent.stream() 都会流式传输
# 创建DeepSeek的model时--》streaming=False
# 创建千问的model时--》不指定
# 某种条件下到了 DeepSeek 回答的时候,就没有流式传输,即便 agent.steam()
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model=model,
streaming=False
)
2 LangChain核心组件之结构化输出
# 1 概念:之前学过--》规定大模型给我们返回的数据格式符合我们的要求
# 1 Pydantic 方式 :返回对象形式
# 2 TypedDict方式:字典形式
# 3 JSON Schema :字典形式--我们可以自己转json格式
# 2 介绍 盗梦空间--》非常多数据--》我们只要我们关注的:Movie对象形式,字典形式{}
-名字
-导演
-评分
# 3 今天研究:Pydantic 返回对象的详细形式
# 4 结构化输出允许 智能体(agents) 以特定的、可预测的格式返回数据。这样,您无需解析自然语言响应,即可获得 JSON 对象、Pydantic 模型 或 数据类(dataclasses) 形式的结构化数据,供您的应用程序直接使用。
# 5 LangChain 的 create_agent 会自动处理结构化输出。用户设置所需的结构化输出 模式(schema),当模型生成结构化数据时,它会被捕获、验证,并作为智能体状态中 'structured_response' 键的值返回
def create_agent(
model=model,
....
response_format: Union[
ToolStrategy[StructuredResponseT],
ProviderStrategy[StructuredResponseT],
type[StructuredResponseT],
None,
]
# 1 response_format 参数有哪些
-ToolStrategy[StructuredResponseT]: 使用 工具调用(tool calling) 实现结构化输出。
-ProviderStrategy[StructuredResponseT]: 使用 提供商原生(provider-native) 的结构化输出功能。
-type[StructuredResponseT]: 模式类型(Schema type) - 会根据模型功能自动选择最佳策略。
-None: 不进行结构化输出。
# 2 当直接提供模式类型时,LangChain 会自动选择:
-ProviderStrategy: 适用于支持原生结构化输出的模型(例如 OpenAI、Grok)。
-ToolStrategy: 适用于所有其他模型。
# 3 结构化响应将在智能体最终状态的 structured_response 键中返回


### 响应格式-之ToolStrategy
from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.agents.structured_output import ProviderStrategy,ToolStrategy
from langchain_openai import ChatOpenAI
# 1 连接model
model = ChatOpenAI(
model="deepseek-chat",
api_key="sk-f360d39d84354ac58a15ddbc9eb81023",
base_url="https://api.deepseek.com",
)
# 2 创建一个类,继承 BaseModel --》使用pydantic 格式
class ContactInfo(BaseModel):
name: str
email: str
QQ: str
# 3 创建agent
agent = create_agent(
model=model,
# 会比大模型直接支持,耗费资源--》因为内部调用了工具
response_format=ToolStrategy(ContactInfo) # 大模型不支持我们要求的格式--》使用ToolStrategy 意思是,langchain内置了一个tool,能够把大模型返回的字符串,处理成我们要的格式
)
# 4 agent交互
result = agent.invoke({
"messages": [{"role": "user", "content": "从以下内容提取联系信息: LiuQingzheng, liuqingzheng2020@163.com.com, 306334678"}]
})
print(type(result["structured_response"]))
### 响应格式-之ProviderStrategy
from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.agents.structured_output import ProviderStrategy,ToolStrategy
from langchain_openai import ChatOpenAI
# 1 连接model
##### 报错:this response_format type is unavailable now---》DeepSeek大模型不支持格式化输出
# model = ChatOpenAI(
# model="deepseek-chat",
# api_key="sk-f360d39d84354ac58a15ddbc9eb81023",
# base_url="https://api.deepseek.com",
# )
### 千问支持--》不报错
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 2 创建一个类,继承 BaseModel --》使用pydantic 格式
class ContactInfo(BaseModel):
name: str
email: str
QQ: str
# 3 创建agent
agent = create_agent(
model=model,
# 大模型支持直接返回这种格式--》直接就返回
# 大模型不支持返回格式---》报错
response_format=ProviderStrategy(ContactInfo)
)
# 4 agent交互
result = agent.invoke({
"messages": [{"role": "user", "content": "从以下内容提取联系信息: LiuQingzheng, liuqingzheng2020@163.com.com, 306334678"}]
})
print(type(result["structured_response"]))
2.2 模型提供商策略
# 1 一些模型提供商通过其 API 原生支持结构化输出(目前仅限 OpenAI)。在可用时,这是最可靠的方法。
# 2 要使用此策略,请配置 ProviderStrategy:
class ProviderStrategy(Generic[SchemaT]):
schema: type[SchemaT]
# 3 schema (必需) 定义结构化输出格式的模式。
# 支持:
Pydantic 模型: 带有字段验证的 BaseModel 子类。
数据类 (Dataclasses): 带有类型注解的 Python 数据类。
TypedDict: 类型化字典类。
JSON Schema: 带有 JSON 模式规范的字典。
# 4 当您将模式类型直接传递给 create_agent.response_format 并且模型支持原生结构化输出时,LangChain 会自动使用 ProviderStrategy:
# 1 模型提供商策略之Pydantic
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
class ContactInfo(BaseModel):
"""一个人的联系信息。"""
name: str = Field(description="该人的姓名")
email: str = Field(description="该人的电子邮件地址")
QQ: str = Field(description="该人的QQ号码")
agent = create_agent(
model=model,
response_format=ContactInfo # 自动选择 ProviderStrategy
)
result = agent.invoke({
"messages": [{"role": "user", "content": "从以下内容提取联系信息: LiuQingzheng, liuqingzheng2020@163.com.com, 306334678"}]
})
print(result["structured_response"])
# 2 模型提供商策略之Dataclass
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from dataclasses import dataclass # python 原生的,不需要额外安装
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
@dataclass
class ContactInfo:
"""一个人的联系信息。"""
name: str # 该人的姓名
email: str # 该人的电子邮件地址
QQ: str # 该人的QQ号码
agent = create_agent(
model=model,
response_format=ContactInfo # 自动选择 ProviderStrategy
)
result = agent.invoke({
"messages": [{"role": "user", "content": "从以下内容提取联系信息: LiuQingzheng, liuqingzheng2020@163.com.com, 306334678"}]
})
print(result["structured_response"])
# 3 模型提供商策略之TypedDict
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from typing_extensions import TypedDict
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
class ContactInfo(TypedDict):
"""一个人的联系信息。"""
name: str # 该人的姓名
email: str # 该人的电子邮件地址
QQ: str # 该人的QQ号码
agent = create_agent(
model=model,
response_format=ContactInfo # 自动选择 ProviderStrategy
)
result = agent.invoke({
"messages": [{"role": "user", "content": "从以下内容提取联系信息: LiuQingzheng, liuqingzheng2020@163.com.com, 306334678"}]
})
print(type(result["structured_response"]))
print(result["structured_response"].get('name'))
# 4 模型提供商策略之JSON Schema
#### JSON Schema 示例
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from typing_extensions import TypedDict
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
contact_info_schema = {
"type": "object",
"description": "一个人的联系信息。",
"properties": {
"name": {"type": "string", "description": "该人的姓名"},
"email": {"type": "string", "description": "该人的电子邮件地址"},
"QQ": {"type": "string", "description": "该人的QQ号码"}
},
"required": ["name", "email", "phone"]
}
agent = create_agent(
model=model,
response_format=contact_info_schema # 自动选择 ProviderStrategy
)
result = agent.invoke({
"messages": [{"role": "user", "content": "从以下内容提取联系信息: LiuQingzheng, liuqingzheng2020@163.com.com, 306334678"}]
})
print(result["structured_response"]['QQ'])
### 注意:
如果提供商对您选择的模型原生支持结构化输出,那么编写 response_format=ProductReview 和 response_format=ToolStrategy(ProductReview) 在功能上是等效的。无论哪种情况,如果不支持结构化输出,智能体都将退回到工具调用策略。
2.3 工具调用策略
2.3.1 基本使用
# 1 对于不支持原生结构化输出的模型,LangChain 使用 工具调用(tool calling) 来达到相同的效果。这适用于所有支持工具调用的模型,即大多数现代模型。
# 2 要使用此策略,请配置 ToolStrategy
class ToolStrategy(Generic[SchemaT]):
schema: type[SchemaT]
tool_message_content: str | None
handle_errors: Union[
bool,
str,
type[Exception],
tuple[type[Exception], ...],
Callable[[Exception], str],
]
# 3 schema (必需) 定义结构化输出格式的模式。
支持:
Pydantic 模型: 带有字段验证的 BaseModel 子类。
数据类 (Dataclasses): 带有类型注解的 Python 数据类。
TypedDict: 类型化字典类。
JSON Schema: 带有 JSON 模式规范的字典。
联合类型 (Union types): 多个模式选项。模型将根据上下文选择最合适的模式。
# 4 tool_message_content (可选)
生成结构化输出时,返回的工具消息的自定义内容。
如果未提供,默认为显示结构化响应数据的消息。
# 5 handle_errors (可选) 结构化输出验证失败的错误处理策略。默认为 True。
True: 捕获所有错误并使用默认错误模板。
str: 捕获所有错误并使用此自定义消息。
type[Exception]: 仅捕获此异常类型并使用默认消息。
tuple[type[Exception], ...]: 仅捕获这些异常类型并使用默认消息。
Callable[[Exception], str]: 返回错误消息的自定义函数。
False: 不重试,让异常传播。
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from typing import Literal
from typing_extensions import TypedDict
from langchain.agents.structured_output import ToolStrategy
from pydantic import BaseModel, Field
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# Pydantic Model 示例:
# 为简洁起见,省略了 Dataclass、TypedDict、JSON Schema 和 Union Types 的 ToolStrategy 示例,它们的结构与 Provider Strategy 类似
class ProductReview(BaseModel):
"""对产品评论的分析。"""
rating: int | None = Field(description="产品的评分", ge=1, le=5)
sentiment: Literal["positive", "negative"] = Field(description="评论的情感倾向") # 枚举:只能从 某几个中选
key_points: list[str] = Field(description="评论的要点。小写,每条 1-3 个词。")
agent = create_agent(
model=model,
response_format=ToolStrategy(ProductReview)
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Analyze this review: 'Great product: 5 out of 5 stars. Fast shipping, but expensive'"}]
})
print(result["structured_response"])
2.3.2 自定义工具消息内容
# tool_message_content 参数允许您自定义生成结构化输出,供给工具调用
# 1 tool_message_content 参数允许您自定义生成结构化输出,供给工具调用
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from typing import Literal
from typing_extensions import TypedDict
from langchain.tools import tool
from langchain.agents.structured_output import ToolStrategy
from pydantic import BaseModel, Field
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
class MeetingAction(BaseModel):
"""从会议记录中提取的行动事项。"""
task: str = Field(description="需要完成的具体任务")
assignee: str = Field(description="负责该任务的人员")
priority: Literal["low", "medium", "high"] = Field(description="优先级")
@tool
def save_meeting(name: str,action:str):
"""把会议行动人和行动内容记录."""
print(name)
print(action)
agent = create_agent(
model=model,
tools=[save_meeting],
response_format=ToolStrategy(
schema=MeetingAction,
tool_message_content="行动事项已捕获并添加到会议记录中!"
)
)
result = agent.invoke({
"messages": [{"role": "user", "content": "From our meeting: Sarah needs to update the project timeline as soon as possible"}]
})
print(result["structured_response"])
'''
不加:tool_message_content
返回:task='Update the project timeline' assignee='Sarah' priority='high'
加:tool_message_content="行动事项已捕获并添加到会议记录中!"
返回:
Sarah
update the project timeline
'''
'''
2.3.3 错误处理
# 模型在通过工具调用生成结构化输出时可能会出错。LangChain 提供了智能的重试机制来自动处理这些错误
-多个结构化输出错误 (Multiple structured outputs error):当模型错误地调用了多个结构化输出工具时,智能体会通过 ToolMessage 提供错误反馈,并提示模型重试
-模式验证错误 (Schema validation error):当结构化输出与预期模式不匹配时,智能体会提供具体的错误反馈
-错误处理策略 (Error handling strategies):可以使用 handle_errors 参数来自定义错误处理方式:
# 1 多个结构化输出错误 (Multiple structured outputs error):当模型错误地调用了多个结构化输出工具时,
# 智能体会通过 ToolMessage 提供错误反馈,并提示模型重试
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from langchain.agents.structured_output import ToolStrategy
from pydantic import BaseModel, Field
from typing import Union
model = ChatOpenAI(
model="qwen-plus",
api_key="sk-6459007b813946289da12857950c955b",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# model = ChatOpenAI(
# model="deepseek-chat",
# api_key="sk-eb2163f3e26d4a008d1f739bc018c568",
# base_url="https://api.deepseek.com",
# )
class ContactInfo(BaseModel):
name: str = Field(description="Person's name")
email: str = Field(description="Email address")
class EventDetails(BaseModel):
event_name: str = Field(description="Name of the event")
date: str = Field(description="Event date")
agent = create_agent(
model=model,
response_format=ToolStrategy(Union[ContactInfo, EventDetails]) # Default: handle_errors=True
)
result=agent.invoke({
"messages": [{"role": "user", "content": "Extract info: John Doe (john@email.com) is organizing Tech Conference on March 15th"}]
})
print(result["structured_response"])
'''
================================ Human Message =================================
Extract info: John Doe (john@email.com) is organizing Tech Conference on March 15th
None
================================== Ai Message ==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: John Doe
email: john@email.com
EventDetails (call_2)
Call ID: call_2
Args:
event_name: Tech Conference
date: March 15th
================================= Tool Message =================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventDetails) when only one is expected.
Please fix your mistakes.
================================= Tool Message =================================
Name: EventDetails
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventDetails) when only one is expected.
Please fix your mistakes.
================================== Ai Message ==================================
Tool Calls:
ContactInfo (call_3)
Call ID: call_3
Args:
name: John Doe
email: john@email.com
================================= Tool Message =================================
Name: ContactInfo
Returning structured response: {'name': 'John Doe', 'email': 'john@email.com'}
'''
# 2 模式验证错误 (Schema validation error):当结构化输出与预期模式不匹配时,智能体会提供具体的错误反馈
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
from typing import Literal
from typing_extensions import TypedDict
from langchain.tools import tool
from langchain.agents.structured_output import ToolStrategy
from pydantic import BaseModel, Field
from typing import Union
# model = ChatOpenAI(
# model="qwen-plus",
# api_key="sk-6459007b813946289da12857950c955b",
# base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
# )
model = ChatOpenAI(
model="deepseek-chat",
api_key="sk-eb2163f3e26d4a008d1f739bc018c568",
base_url="https://api.deepseek.com",
)
class ProductRating(BaseModel):
rating: int | None = Field(description="Rating from 1-5", ge=1, le=5)
comment: str = Field(description="Review comment")
agent = create_agent(
model=model,
response_format=ToolStrategy(ProductRating), # Default: handle_errors=True
system_prompt="You are a helpful assistant that parses product reviews. Do not make any field or value up."
)
result=agent.invoke({
"messages": [{"role": "user", "content": "Parse this: Amazing product, 10/10!"}]
})
print(result["structured_response"])
'''
================================ Human Message =================================
Parse this: Amazing product, 10/10!
================================== Ai Message ==================================
Tool Calls:
ProductRating (call_1)
Call ID: call_1
Args:
rating: 10
comment: Amazing product
================================= Tool Message =================================
Name: ProductRating
Error: Failed to parse structured output for tool 'ProductRating': 1 validation error for ProductRating.rating
Input should be less than or equal to 5 [type=less_than_equal, input_value=10, input_type=int].
Please fix your mistakes.
================================== Ai Message ==================================
Tool Calls:
ProductRating (call_2)
Call ID: call_2
Args:
rating: 5
comment: Amazing product
================================= Tool Message =================================
Name: ProductRating
Returning structured response: {'rating': 5, 'comment': 'Amazing product'}
'''
# 3 错误处理策略 (Error handling strategies):可以使用 handle_errors 参数来自定义错误处理方式:
# ZeroDivisionError
# ZeroDivisionError,ValueError ,TypeError# python 内置的错误
class F(TypeError):
pass
'''
1 自定义错误消息:
ToolStrategy(
schema=ProductRating,
handle_errors="请提供 1-5 之间的有效评分并包含评论。"
)
(如果 handle_errors 是一个字符串,智能体将始终使用固定的工具消息提示模型重试。)
2 仅处理特定异常:
ToolStrategy(
schema=ProductRating,
handle_errors=ValueError # 仅在 ValueError 时重试,否则抛出
)
3 处理多个异常类型:
ToolStrategy(
schema=ProductRating,
handle_errors=(ValueError, TypeError) # 在 ValueError 和 TypeError 时重试
)
4 自定义错误处理函数:如果出了错误,都会执行这个函数--》在函数中,我们写自己的逻辑
def custom_error_handler(error: Exception) -> str:
if isinstance(error, StructuredOutputValidationError):
return "格式存在问题。请重试。"
elif isinstance(error, MultipleStructuredOutputsError):
return "返回了多个结构化输出。请选择最相关的一个。"
elif isinstance(error, ValueError):
return "类型错误"
else:
return f"错误: {str(error)}"
ToolStrategy(
schema=ToolStrategy(Union[ContactInfo, EventDetails]),
handle_errors=custom_error_handler
)
5 不进行错误处理:
response_format = ToolStrategy(
schema=ProductRating,
handle_errors=False # 所有错误都抛出
)
'''