大模型API请求超时怎么办?连接、首字节与总时长的分层排查指南
大模型API超时不一定是同一种故障。应先区分连接超时、读取超时、总时长限制和HTTP网关错误,再结合请求耗时、错误码、流式状态及请求标识逐层定位。本文给出最小复现、代理检查和安全重试方法。
小睿AI导航 ARTICLE DETAIL
本教程使用独立FastMCP项目,将内部产品编号查询函数封装成只读MCP工具,并给出服务端代码和客户端测试方法。你可以依次验证工具发现、参数传入、正常返回与错误处理,同时了解stdio与HTTP的配置
样式 7 内容详情排版
独立FastMCP项目与MCP Python SDK都提供名为FastMCP的实现,但安装包、导入路径和API不能随意混用。本文统一采用独立FastMCP项目:安装fastmcp,从fastmcp导入FastMCP和Client;不使用MCP Python SDK的mcp.server.fastmcp导入路径。后续查阅资料也应对应独立项目的官方文档。
在支持该包的Python环境中创建虚拟环境,激活后安装依赖:
python -m venv .venv
python -m pip install fastmcp
第二条命令应在虚拟环境激活后执行。首次验证成功后,记录依赖版本,便于复现。
新建server.py,逐行写入以下代码。代码行以段落分隔,函数体和条件块需保留缩进。示例使用内存数据,不连接真实业务系统,也不修改产品状态。
import logging
from fastmcp import FastMCP
from fastmcp.exceptions import ToolError
logging.basicConfig(level=logging.INFO)
mcp = FastMCP("ProductLookup")
PRODUCTS = {"P1001": {"name": "演示产品", "status": "active"}}
def lookup_product(product_id: str) -> dict[str, str]:
"""按产品编号只读查询,返回product_id、name和status。"""
key = product_id.strip().upper()
if not key:
raise ToolError("产品编号不能为空")
if key not in PRODUCTS:
raise ToolError("未找到该产品编号")
return {"product_id": key, **PRODUCTS[key]}
mcp.tool()(lookup_product)
if __name__ == "__main__":
mcp.run(transport="stdio")
mcp.tool()(lookup_product)负责注册工具,与装饰器写法作用相同。参数类型让客户端获得输入约束,函数说明用于工具发现,返回类型描述结果结构。未知编号和空字符串会产生明确的工具错误;接入真实数据库后,还应捕获查询异常,记录服务端日志,避免把连接信息或完整堆栈返回给客户端。
支持stdio的客户端需要配置启动命令和参数。例如command填写虚拟环境中Python解释器的绝对路径,args填写server.py的绝对路径。客户端通过进程的标准输入、标准输出交换MCP消息,通常不需要提前手动启动服务。
不要用print输出调试日志。stdio的标准输出用于协议通信,普通日志应写入标准错误或文件。上面的logging默认使用标准错误;也要检查第三方库是否向标准输出打印内容。
在server.py所在目录运行:
python -c "from server import mcp; mcp.run(transport='http', host='127.0.0.1', port=8000)"
客户端改为连接http://127.0.0.1:8000/mcp,不再配置启动该服务的本地命令。这里的HTTP使用Streamable HTTP传输;客户端是否支持这种传输及其配置字段,需要查对应客户端文档。127.0.0.1仅供本机连接。
新建test_client.py,放在同一目录并使用同一环境运行。下面的Client是支持MCP的程序化客户端,适合先排除桌面客户端配置因素。
import asyncio
from fastmcp import Client
async def main():
async with Client("server.py") as client:
print(await client.list_tools())
for args in [{"product_id": "P1001"}, {"product_id": "P9999"}, {}]:
try:
result = await client.call_tool("lookup_product", args)
print(result.content)
except Exception as exc:
print(type(exc).__name__, str(exc))
asyncio.run(main())
执行python test_client.py。工具列表应包含lookup_product;P1001应返回包含product_id、name、status的数据;P9999应报告未找到;空参数对象应触发必填参数校验。测试客户端不承载stdio服务端协议,因此这里可以print结果。宽泛捕获异常仅用于让测试继续执行。
验证HTTP时,先保持HTTP服务运行,再把Client("server.py")替换为Client("http://127.0.0.1:8000/mcp"),重复相同测试。
若查询依赖外部API,密钥由服务端通过os.environ["PRODUCT_API_KEY"]等方式读取,不放入工具参数、源码或返回结果。stdio子进程是否继承环境变量取决于客户端配置,需要实际确认。
远程部署还需处理认证、TLS、网络访问范围和工具权限。只读查询同样可能暴露内部数据,应在服务端按调用者身份限制可查询范围。连接成功只说明通信链路可用,不能证明权限与数据安全已得到保障。