内置中间件(上):调用限制与模型回退
3、其它内置中间件
这里为大部分中间件提供测试代码和输出,感兴趣的同学自行研究。
3.1 ModelCallLimitMiddleware中间件
限制模型调用次数,避免无限循环,控制调用成本。
举例1:整个会话限制-优雅退出
python
from langchain.chat_models import init_chat_model
from dotenv import load_dotenv
import os
# 从.env文件中加载环境变量
load_dotenv(override=True)
CLOSEAI_API_KEY = os.getenv("CLOSEAI_API_KEY")
CLOSEAI_BASE_URL = os.getenv("CLOSEAI_BASE_URL")
model = init_chat_model(
model="gpt-5.4-mini",
model_provider="openai",
api_key=CLOSEAI_API_KEY,
base_url=CLOSEAI_BASE_URL
)python
from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from typing import List
agent = create_agent(
model=model,
checkpointer=InMemorySaver(), # Required for thread limiting
tools=[],
middleware=[
ModelCallLimitMiddleware(
thread_limit=2, # 每个线程最多2次模型调用
# run_limit=5, # 每次运行最多5次
exit_behavior="end", # 达到限制后退出
),
],
)
def pretty_iterate_msg(messages: List[SystemMessage | HumanMessage | AIMessage | ToolMessage]):
for msg in messages:
msg.pretty_print()
config = {"configurable": {"thread_id": "1"}}
response_first = agent.invoke({
"messages": [HumanMessage("你好")]},
config=config
)
print("=" * 30, "> first <", "=" * 30)
pretty_iterate_msg(response_first["messages"])
response_second = agent.invoke({
"messages": [HumanMessage("你是谁?")]},
config=config
)
print("=" * 30, "> second <", "=" * 30)
pretty_iterate_msg(response_second["messages"])
response_third = agent.invoke({
"messages": [HumanMessage("你能帮我做什么?")]},
config=config
)
print("=" * 30, "> third <", "=" * 30)
pretty_iterate_msg(response_third["messages"])输出
text
============================== > first < ==============================
================================ Human Message =================================
你好
================================== Ai Message ==================================
你好!有什么我可以帮你的吗?
============================== > second < ==============================
================================ Human Message =================================
你好
================================== Ai Message ==================================
你好!有什么我可以帮你的吗?
================================ Human Message =================================
你是谁?
================================== Ai Message ==================================
我是 ChatGPT,一个由 OpenAI 训练的 AI 助手。
我可以帮你回答问题、写作、翻译、总结、编程、头脑风暴等。
如果你愿意,也可以直接告诉我你现在想做什么。
============================== > third < ==============================
================================ Human Message =================================
你好
================================== Ai Message ==================================
你好!有什么我可以帮你的吗?
================================ Human Message =================================
你是谁?
================================== Ai Message ==================================
我是 ChatGPT,一个由 OpenAI 训练的 AI 助手。
我可以帮你回答问题、写作、翻译、总结、编程、头脑风暴等。
如果你愿意,也可以直接告诉我你现在想做什么。
================================ Human Message =================================
你能帮我做什么?
================================== Ai Message ==================================
Model call limits exceeded: thread limit (2/2)举例2:整个会话限制-抛异常
python
from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from typing import List
agent = create_agent(
model=model,
checkpointer=InMemorySaver(), # Required for thread limiting
tools=[],
middleware=[
ModelCallLimitMiddleware(
thread_limit=2,
# run_limit=5,
exit_behavior="error",
),
],
)
def pretty_iterate_msg(messages: List[SystemMessage | HumanMessage | AIMessage | ToolMessage]):
for msg in messages:
msg.pretty_print()
config = {"configurable": {"thread_id": "1"}}
response_first = agent.invoke({
"messages": [HumanMessage("你好")]},
config=config
)
print("=" * 30, "> first <", "=" * 30)
pretty_iterate_msg(response_first["messages"])
response_second = agent.invoke({
"messages": [HumanMessage("你是谁?")]},
config=config
)
print("=" * 30, "> second <", "=" * 30)
pretty_iterate_msg(response_second["messages"])
response_third = agent.invoke({
"messages": [HumanMessage("你能帮我做什么?")]},
config=config
)
print("=" * 30, "> third <", "=" * 30)
pretty_iterate_msg(response_third["messages"])输出
text
============================== > first < ==============================
================================ Human Message =================================
你好
================================== Ai Message ==================================
你好!有什么我可以帮你的吗?
============================== > second < ==============================
================================ Human Message =================================
你好
================================== Ai Message ==================================
你好!有什么我可以帮你的吗?
================================ Human Message =================================
你是谁?
================================== Ai Message ==================================
我是 ChatGPT,一个由 OpenAI 训练的 AI 助手。
我可以帮你回答问题、写作润色、翻译、总结、编程、头脑风暴等。
你想聊点什么?
Traceback...
ModelCallLimitExceededError: Model call limits exceeded: thread limit (2/2)
During task with name 'ModelCallLimitMiddleware.before_model' and id '42468735-c5e0-c935-6c91-26d7d4f04f95'举例3:单次调用限制-优雅退出
需要fake-server重复触发工具调用,代码如下
python
import json
import random
import time
from http.server import BaseHTTPRequestHandler, HTTPServer
class FakeDeepSeekHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers.get("Content-Length", 0))
raw_body = self.rfile.read(content_length).decode("utf-8")
print("\n" + "=" * 100)
json_body = None
try:
json_body = json.loads(raw_body)
print("[JSON BODY]")
print(json.dumps(json_body, ensure_ascii=False, indent=2))
except Exception as e:
print("[JSON PARSE ERROR]")
print(repr(e))
response = {
"id": "chatcmpl-test",
"object": "chat.completion",
"created": int(time.time()),
"model": "any",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_1",
"type": "function",
"function": {
"name": json_body["tools"][0] ["function"]["name"],
"arguments": json.dumps(
{'name': '康师傅', 'email': 'songhongkang@atguigu.cn', 'phone': '12345678912'},
ensure_ascii=False
)
}
}
]
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1,
"completion_tokens": 1,
"total_tokens": 2
}
}
append_val = {
"id": "call_2",
"type": "function",
"function": {
"name": json_body["tools"][1]["function"]["name"],
"arguments": json.dumps(
{'event_name': '问数项目启动会', 'date': '2026-03-27'},
ensure_ascii=False
)
}
}
if random.randint(1, 10) > 2:
response["choices"][0]["message"] ["tool_calls"].append(append_val)
# response["choices"][0]["message"]["tool_calls"][0]["function"] ["arguments"] = json.dumps(
# {'name1': '康师傅', 'email2': 'songhongkang@atguigu.cn', 'phone': '12345678912'},
# ensure_ascii=False
# )
print("\n" + "=" * 100)
print("[RESPONSE]")
print(json.dumps(response, ensure_ascii=False, indent=2))
body = json.dumps(response, ensure_ascii=False).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, format, *args):
pass
def main():
server = HTTPServer(("127.0.0.1", 8889), FakeDeepSeekHandler)
print("Fake DeepSeek server running at http://127.0.0.1:8889")
server.serve_forever()
if __name__ == "__main__":
main()注意:服务端代码逻辑是80%概率输出非法响应,所以不一定会导致单次请求的工具调用超过限制,尝试几次即可看到效果。
客户端代码
python
from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from langchain_deepseek import ChatDeepSeek
from pydantic import BaseModel, Field, SecretStr
from typing import List, Union
from dotenv import load_dotenv
load_dotenv()
model = ChatDeepSeek(
model="any",
api_base="http://localhost:8889",
api_key=SecretStr("<KEY>")
)
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
class EventInfo(BaseModel):
event_name: str = Field(description="事件名称")
date: str = Field(description="事件发生日期")
agent = create_agent(
model=model,
checkpointer=InMemorySaver(), # Required for thread limiting
tools=[],
middleware=[
ModelCallLimitMiddleware(
# thread_limit=2,
run_limit=3,
exit_behavior="end",
),
],
response_format=Union[ContactInfo, EventInfo]
)
config = {"configurable": {"thread_id": "1"}}
response = agent.invoke({
"messages": [HumanMessage("你好")]},
config=config
)
for msg in response["messages"]:
msg.pretty_print()输出
text
================================•[1m Human Message •[0m=================================
你好
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
==================================•[1m Ai Message •[0m==================================
Model call limits exceeded: run limit (3/3)举例4:单次调用限制-抛异常
python
from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from langchain_deepseek import ChatDeepSeek
from pydantic import BaseModel, Field, SecretStr
from typing import List, Union
from dotenv import load_dotenv
load_dotenv(override=True)
model = ChatDeepSeek(
model="any",
api_base="http://localhost:8889",
api_key=SecretStr("<KEY>")
)
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
class EventInfo(BaseModel):
event_name: str = Field(description="事件名称")
date: str = Field(description="事件发生日期")
agent = create_agent(
model=model,
checkpointer=InMemorySaver(), # Required for thread limiting
tools=[],
middleware=[
ModelCallLimitMiddleware(
# thread_limit=2,
run_limit=3,
exit_behavior="error",
),
],
response_format=Union[ContactInfo, EventInfo]
)
config = {"configurable": {"thread_id": "1"}}
response = agent.invoke({
"messages": [HumanMessage("你好")]},
config=config
)
for msg in response["messages"]:
msg.pretty_print()输出
text
Traceback...
ModelCallLimitExceededError: Model call limits exceeded: run limit (3/3)
During task with name 'ModelCallLimitMiddleware.before_model' and id 'e731473b-d9c6-d07d-2392-40d38f0f7219'3.2 ToolCallLimitMiddleware中间件
限制工具调用次数,可以限制所有工具调用的总次数,也可以限制特定工具的调用次数。
作用如下:
- 避免过多调用某些昂贵的外部API
- 限制网络爬虫或数据库查询请求的数量
- 避免Agent陷入无限循环
退出行为有三种模式:
- error:直接抛异常
- end:结束整个会话
- continue:继续运行Agent,这是默认行为,此时Agent会将工具调用超出限制的信息传递给模型,后者自主决定后续行为,如果模型能力不足,可能导致死循环,为了避免这种情况,我们实现的fake server会以20%的概率输出正确响应,从而能终止循环。
举例1:整个会话限制-优雅结束
python
from langchain.agents import create_agent
from langchain.agents.middleware import ToolCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from langchain_deepseek import ChatDeepSeek
from pydantic import BaseModel, Field, SecretStr
from typing import List, Union
from dotenv import load_dotenv
load_dotenv(override=True)
model = ChatDeepSeek(
model="any",
api_base="http://localhost:8889",
api_key=SecretStr("<KEY>")
)
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
class EventInfo(BaseModel):
event_name: str = Field(description="事件名称")
date: str = Field(description="事件发生日期")
agent = create_agent(
model=model,
checkpointer=InMemorySaver(), # Required for thread limiting
tools=[],
middleware=[
ToolCallLimitMiddleware(
# thread_limit=2, # 每个线程最多2次工具调用
run_limit=2, # 每次运行最多2次
exit_behavior="end",
),
],
response_format=Union[ContactInfo, EventInfo]
)
def pretty_iterate_msg(messages: List[SystemMessage | HumanMessage | AIMessage | ToolMessage]):
for msg in messages:
msg.pretty_print()
config = {"configurable": {"thread_id": "1"}}
response = agent.invoke({
"messages": [HumanMessage("你好")]},
config=config
)
pretty_iterate_msg(response["messages"])输出
text
================================•[1m Human Message •[0m=================================
你好
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Tool call limit exceeded. Do not make additional tool calls.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Tool call limit exceeded. Do not make additional tool calls.
==================================•[1m Ai Message •[0m==================================
Tool call limit reached: run limit exceeded (4/2 calls).举例2:整个会话限制-抛异常
python
from langchain.agents import create_agent
from langchain.agents.middleware import ToolCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from langchain_deepseek import ChatDeepSeek
from pydantic import BaseModel, Field, SecretStr
from typing import List, Union
from dotenv import load_dotenv
load_dotenv(override=True)
model = ChatDeepSeek(
model="any",
api_base="http://localhost:8889",
api_key=SecretStr("<KEY>")
)
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
class EventInfo(BaseModel):
event_name: str = Field(description="事件名称")
date: str = Field(description="事件发生日期")
agent = create_agent(
model=model,
checkpointer=InMemorySaver(), # Required for thread limiting
tools=[],
middleware=[
ToolCallLimitMiddleware(
# thread_limit=2,
run_limit=2,
exit_behavior="error",
),
],
response_format=Union[ContactInfo, EventInfo]
)
def pretty_iterate_msg(messages: List[SystemMessage | HumanMessage | AIMessage | ToolMessage]):
for msg in messages:
msg.pretty_print()
config = {"configurable": {"thread_id": "1"}}
response = agent.invoke({
"messages": [HumanMessage("你好")]},
config=config
)
pretty_iterate_msg(response["messages"])输出
text
Traceback...
ToolCallLimitExceededError: Tool call limit reached: run limit exceeded (4/2 calls).
During task with name 'ToolCallLimitMiddleware.after_model' and id '065d5983-8a8a-2c1c-0b6f-d9f365c122ba'案例3:单次调用限制-继续运行
python
from langchain.agents import create_agent
from langchain.agents.middleware import ToolCallLimitMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langchain.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from langchain_deepseek import ChatDeepSeek
from pydantic import BaseModel, Field, SecretStr
from typing import List, Union
from dotenv import load_dotenv
load_dotenv(override=True)
model = ChatDeepSeek(
model="any",
api_base="http://localhost:8889",
api_key=SecretStr("<KEY>")
)
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
class EventInfo(BaseModel):
event_name: str = Field(description="事件名称")
date: str = Field(description="事件发生日期")
agent = create_agent(
model=model,
checkpointer=InMemorySaver(), # Required for thread limiting
tools=[],
middleware=[
ToolCallLimitMiddleware(
# thread_limit=2,
run_limit=2,
exit_behavior="continue",
),
],
response_format=Union[ContactInfo, EventInfo]
)
def pretty_iterate_msg(messages: List[SystemMessage | HumanMessage | AIMessage | ToolMessage]):
for msg in messages:
msg.pretty_print()
config = {"configurable": {"thread_id": "1"}}
# seen = set()
response = agent.invoke({
"messages": [HumanMessage("你好")]},
config=config
)
pretty_iterate_msg(response["messages"])输出
text
================================•[1m Human Message •[0m=================================
你好
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Tool call limit exceeded. Do not make additional tool calls.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Tool call limit exceeded. Do not make additional tool calls.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Tool call limit exceeded. Do not make additional tool calls.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Tool call limit exceeded. Do not make additional tool calls.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Tool call limit exceeded. Do not make additional tool calls.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Tool call limit exceeded. Do not make additional tool calls.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Tool call limit exceeded. Do not make additional tool calls.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Tool call limit exceeded. Do not make additional tool calls.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
EventInfo (call_2)
Call ID: call_2
Args:
event_name: 问数项目启动会
date: 2026-03-27
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Error: Model incorrectly returned multiple structured responses (ContactInfo, EventInfo) when only one is expected.
Please fix your mistakes.
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Tool call limit exceeded. Do not make additional tool calls.
=================================•[1m Tool Message •[0m=================================
Name: EventInfo
Tool call limit exceeded. Do not make additional tool calls.
==================================•[1m Ai Message •[0m==================================
Tool Calls:
ContactInfo (call_1)
Call ID: call_1
Args:
name: 康师傅
email: songhongkang@atguigu.cn
phone: 12345678912
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Returning structured response: name='康师傅' email='songhongkang@atguigu.cn' phone='12345678912'
=================================•[1m Tool Message •[0m=================================
Name: ContactInfo
Tool call limit exceeded. Do not make additional tool calls.3.3 ModelFallbackMiddleware中间件
用于故障转移,当主模型无法访问时,启用备用模型。
举例1:
python
from langchain.agents.middleware import ModelFallbackMiddleware
from langchain.chat_models import init_chat_model
# 定义主模型和备用模型
primary_model = init_chat_model("openai:gpt-5.4-mini")
fallback = ModelFallbackMiddleware(
fallback_models=[
init_chat_model("openai:gpt-4o-mini"),
init_chat_model("anthropic:claude-3-haiku")
]
)
agent = create_agent(
model=primary_model,
tools=[],
middleware=[fallback],
)举例2:
python
from langchain.agents import create_agent
from langchain.agents.middleware import ModelFallbackMiddleware
from langchain.messages import HumanMessage
from dotenv import load_dotenv
load_dotenv(override=True)
agent = create_agent(
model="deepseek:fake_model",
tools=[],
middleware=[
ModelFallbackMiddleware(
"deepseek-v4-flash",
"deepseek-v4-pro",
),
],
)
response = agent.invoke({
"messages": [HumanMessage("你是谁?")]
})
last_msg = response["messages"][-1]
print(last_msg)
print('=' * 30, '-> model_name <-', '=' * 30)
print(last_msg.response_metadata.get("model_name"))输出
text
content='你好呀!我是DeepSeek,由深度求索公司创造的AI助手。😊\n\n我的主要特点包
括:\n- **免费使用**:随时为你提供帮助,不收费\n- **强大的上下文能力**:拥有1M的上下 文窗口,可以一次性处理像《三体》三部曲那样的长篇内容\n- **文件处理**:支持上传图片、 PDF、Word、Excel、PPT等文件,我能读取其中的文字信息\n- **联网搜索**:虽然需要你手 动开启,但我可以帮你搜索最新信息\n- **语音交互**:在App端支持语音输入\n\n我的知识截 止于2025年5月,会尽我所能用热情、细腻的方式回答你的问题。无论是学习、工作还是日常闲 聊,我都很乐意陪伴你!\n\n有什么我可以帮你的吗?🌟' additional_kwargs= {'refusal': None, 'reasoning_content': '好的,用户问了一个非常基础的自我介绍问 题:“你是谁?”。这是一个新对话的典型开场,用户可能想确认我的身份和能力,以便后续提出更 具体的问题。\n\n我需要给出一个清晰、全面的自我介绍,说明我的身份、创造者、核心功能和一 些关键特点(比如免费、长上下文、文件处理等),让用户快速了解我能提供什么帮助。最后应该 以开放式的邀请结束,引导用户提出进一步的需求。\n\n想到了用热情友好的语气开头,然后分点 (虽然回复里是段落形式,但思考时是分块想)介绍核心信息,最后表达乐于助人的态度。'} response_metadata={'token_usage': {'completion_tokens': 296, 'prompt_tokens': 6, 'total_tokens': 302, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 126, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 6}, 'model_provider': 'deepseek', 'model_name': 'deepseek-v4-flash', 'system_fingerprint': 'fp_8b330d02d0_prod0820_fp8_kvcache_20260402', 'id': '618d4649-1de7-439d-b1cc-fe2bafb06afe', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019eac53-2db9-75c2-8493-b351c34ae7ae-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 6, 'output_tokens': 296, 'total_tokens': 302, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 126}}
============================== -> model_name <- ==============================
deepseek-v4-flash