使用说明
数据中心气象代理
一种LangGraph代理系统,使用模型上下文协议(MCP)确定数据中心位置的天气预报。
建筑:自定义状态图,具有显式状态管理、模块化节点和符合LangGraph 2026最佳实践的条件路由。
概述
该系统回答了以下问题: “数据中心的天气预报是什么?”
它自主地: 0.检查意图分类,避免回答不应该回答的问题,或对任何问题给出相同的答案
- 发现数据中心的公共IP地址
- 将IP解析为地理坐标
- 获取该位置的当前天气预报
- 合成自然语言响应
为什么是这种架构?
此实现使用LangGraph的 自定义状态图 方法而不是预构建的代理,因为:
- 完全透明:每个决策点都是明确的,可调试的
- 生产就绪:模块化设计支持测试、监控和扩展
- 最佳实践:遵循LangGraph 2026对LangGraph文档中获取的有状态代理的建议:https://docs.langchain.com/oss/python/langgraph/workflows-agents
- 可维护性:与类型化状态模式明确分离关注点
系统架构
┌─────────────────────────────────────────────────────────────────┐
│ Data Center Weather Agent │
│ │
│ ┌─────────────┐ ┌───────────────────────────────────┐ │
│ │ Agent │ HTTP │ MCP Server │ │
│ │ (LangGraph) │◄───────►│ ┌────────┐ ┌─────────┐ ┌───────┐ │ │
│ │ │ SSE │ │ ipify │ │ip_to_geo│ │weather│ │ |
│ │ 5 Nodes │ │ └───┬────┘ └────┬────┘ └──┬────┘ │ │
│ │ 3 Edges │ │ │ │ │ │ │
│ │ 9 State │ │ ▼ ▼ ▼ │ │
│ │ Fields │ │ ipify.org ip-api.com meteo │ │
│ └─────────────┘ └───────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
组件
1.MCP服务器(server/)
- 技术:Python、FastMCP、uvicorn
- 端口:8000(苏格兰和南方能源公司运输)
- 工具:
ipify:获取公共IP地址ip_to_geo:将IP转换为lat/lon(IP-api.com)weather_forecast:获取天气数据(Open Meteo)
- 特性:输入验证、错误处理、结构化日志记录
2.LangGraph代理(agent/)
- 技术:Python、LangGraph、LangChain、谷歌Gemini
- 建筑:自定义状态图
- 状态:跟踪工作流进度的9个键入字段
- 节点:5个模块化计算单元
- 边缘:3个条件路由函数
- 特性:LLM回退、详细跟踪、错误恢复
状态管理
所有数据都通过强类型 AgentState:
class AgentState(TypedDict):
question: str # User's input query
public_ip: str | None # From ipify tool
latitude: float | None # From ip_to_geo tool
longitude: float | None # From ip_to_geo tool
weather_data: str | None # From weather_forecast tool
answer: str | None # Final LLM response
messages: list # Conversation history
error: str | None # Error tracking
current_step: str # Progress indicator
图形结构
START
↓
┌───────────────────────┐
│ intent classification│ → [custom logic]
└──────┬────────────────┘
↓
┌─────────────┐
│ get_ip │ → [ipify tool]
└──────┬──────┘
│ [conditional: success/error]
↓
┌──────────────────┐
│ resolve_location │ → [ip_to_geo tool]
└──────┬───────────┘
│ [conditional: success/error]
↓
┌──────────────┐
│fetch_weather │ → [weather_forecast tool]
└──────┬───────┘
│ [conditional: success/error]
↓
┌────────────────┐
│generate_answer │ → [LLM synthesis]
└───────┬────────┘
↓
END
[error] ← Any failure routes here
节点职责
- get_ip_node:调用ipify工具,使用public_ip更新状态
- resolve_location_node:调用ip_to_geo,提取lat/lon
- fetch_weather_node:使用坐标调用weather_forecast
- generate_answer_node:LLM创建自然语言响应
- 错误节点:集中错误处理和用户消息传递
条件路由
在继续之前,每条边都会验证之前的操作:
def route_after_ip(state: AgentState) -> Literal["resolve_location", "error"]:
"""Route to next node or error based on IP fetch result"""
if state.get("error") or not state.get("public_ip"):
return "error"
return "resolve_location"
设置
先决条件
- Python 3.10或更高版本
- 在3.14.2版本上进行了全面测试
- Google Gemini API密钥(提供免费层)
- 可选:LongCat API密钥(回退)
安装
-
克隆或下载 这个项目
-
安装依赖项:
pip install -r requirements.txt -
配置API密钥:
复制示例环境文件:
cp .env.example .env编辑
.env并添加您的API密钥:GOOGLE_API_KEY=your_gemini_api_key_here LONGCAT_API_KEY=your_longcat_api_key_here # Optional获取API密钥:
- 双子座:https://ai.google.dev/
- 长猫:https://longcat.chat/(可选回退)
用法
启动系统
您需要两个终端窗口:
终端1-启动MCP服务器:
python3 -m server.main
预期产量:
INFO: Started server process
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000
终端2-运行代理:
python3 -m agent.main
示例会话
============================================================
Data Center Weather Agent (Custom StateGraph)
============================================================
Connected to MCP Server
LLM configured with fallback: Gemini -> LongCat
Graph structure built successfully
Agent Ready! (Type 'quit' to exit)
------------------------------------------------------------
Enter your question: What is the weather forecast of the data center?
============================================================
EXECUTION TRACE
============================================================
[Step 1: IP Discovery]
Tool: ipify
Result: 174.162.142.78
[Step 2: Location Resolution]
Tool: ip_to_geo
Input: 174.162.142.78
Result: 40.3495, -111.8998
[Step 3: Weather Retrieval]
Tool: weather_forecast
Input: lat=40.3495, lon=-111.8998
Result: Temperature: 0.2 C, Windspeed: 2.2 km/h
[Step 4: Answer Generation]
Generated answer successfully
============================================================
FINAL ANSWER
============================================================
The data center, located at 40.3495°N, 111.8998°W, currently has a
temperature of 0.2°C and a wind speed of 2.2 km/h.
Enter your question: Where is the data center located?
[... processes IP and location lookup ...]
FINAL ANSWER
The data center is located at coordinates 40.3495°N, 111.8998°W
(approximately in Utah, United States).
Enter your question: quit
文件结构
datacenter_weather_agent/
├── server/
│ ├── main.py # MCP server with FastMCP
│ ├── tools.py # Tool implementations
│ └── __init__.py
├── agent/
│ ├── main.py # Custom StateGraph agent (~570 lines)
│ ├── client.py # MCP client wrapper
│ └── __init__.py
├── README.md # This file
├── ARCHITECTURE.md # Deep technical documentation
├── .env.example # API key template
├── .env # Your API keys (create this)
└── requirements.txt # Python dependencies
主要特点
1.稳健的输入验证
服务器端:
- IP地址格式验证(IPv4/IPv6)
- IPv4八位字节范围检查(0-255)
- 坐标范围验证(纬度:-90至90,经度:-180至180)
- 对所有参数进行类型检查
客户端:
- 响应结构验证
- 非空内容验证
- 运行时错误检测
2.全面的错误处理
每个节点错误处理:
async def get_ip_node(state, tools):
try:
# ... tool execution ...
return success_state
except Exception as e:
logger.error(f"Error in get_ip_node: {e}")
return error_state
条件路由到错误节点:
- 任何节点故障都会路由到集中式错误处理程序
- 用户友好的错误消息
- 代理保持响应(不崩溃)
3.LLM回退策略###->额外功能<-
根据速率限制自动故障切换:
gemini_llm = ChatGoogleGenerativeAI(model="gemini-3-pro-preview")
longcat_llm = ChatOpenAI(model="LongCat-Flash-Chat", ...)
llm = gemini_llm.with_fallbacks([longcat_llm])
4.详细的执行跟踪
每个操作都会被记录:
- 带有输入和输出的工具调用
- 状态转换
- 错误条件
- LLM推理
适合调试和监控。
5.清理执行跟踪
该代理通过以下方式产生干净、集中的输出:
- 抑制详细的库日志(httpx、google_genai)
- 仅显示基本步骤信息
- 自动以静默方式处理LLM回退
面向用户的跟踪只显示重要的内容:
[Step 1: IP Discovery]
Tool: ipify
Result: 174.162.142.78
后端日志仍然可以捕获调试的详细信息。
工具调用策略
代理人执行 严格的顺序工作流程:
-
IP发现 (ipify)
- 无先决条件
- 必须成功才能继续
-
位置分辨率 (ip_to_geo)
- 要求:
public_ip从步骤1 - 调用前验证IP格式
- 从响应解析lat/lon
- 要求:
-
天气检索 (天气预报)
- 要求:
latitude和longitude从步骤2 - 验证坐标范围
- 返回格式化的天气字符串
- 要求:
-
答案生成 LLM
- 要求:所有收集的数据
- 合成自然语言响应
- 维护对话上下文
验证:每个条件边在路由到下一个节点之前验证先决条件是否存在。
生产增强
启用检查点(对话内存)
这是对制作环境的额外意图。
from langgraph.checkpoint.sqlite import SqliteSaver
# In build_graph():
async with SqliteSaver.from_conn_string("./checkpoints.db") as memory:
graph = workflow.compile(checkpointer=memory)
# In main():
config = {"configurable": {"thread_id": "user-123"}}
result = await graph.ainvoke(state, config=config)
在循环中添加人类
from langgraph.checkpoint.sqlite import SqliteSaver
# Compile with interrupt
graph = workflow.compile(
checkpointer=memory,
interrupt_before=["generate_answer"] # Pause before final answer
)
# Resume after approval
graph.invoke(None, config=config) # Continue from interrupt
多代理扩展
创建专门的子代理:
weather_specialist = build_weather_subgraph()
location_specialist = build_location_subgraph()
workflow.add_node("weather", weather_specialist)
workflow.add_node("location", location_specialist)
workflow.add_conditional_edges("start", route_to_specialist, {...})
故障排除
服务器连接失败
症状: connection refused 或 server not found
解决方案:
- 验证服务器是否正在运行:
curl http://localhost:8000/sse - 检查没有其他进程正在使用端口8000
- 查看服务器日志以查找启动错误
LLM速率限制错误
症状: 429 RESOURCE_EXHAUSTED
解决方案:
- 如果配置,回退到LongCat会自动触发
- 等待60秒,然后重试
- 考虑升级到Gemini付费等级
导入错误
症状: ModuleNotFoundError
解决方案:
# Always run from project root:
cd /path/to/datacenter_weather_agent
python3 -m agent.main
工具验证错误
症状: Invalid IP address format 或 Invalid latitude
解决方案:
- 检查服务器日志以了解详细错误
- 验证外部API是否可访问
- 手动测试:
curl https://api.ipify.org?format=json
演出
典型指标:
- 冷启动:1-2秒(库加载)
- 工具执行:3-5秒(3×HTTP请求)
- LLM合成:0.5-1秒
- 总计:每次查询约5-8秒
- 内存:~50MB运行时
瓶颈:
- 外部API潜伏时间(ipify、ip-API、open-metao)
- LLM生成无时间层api密钥的性能明显较慢,请耐心等待
- 网络条件
局限性
- 顺序执行:工具按顺序运行(在某些情况下可以并行运行)
- 仅限公共IP:无法确定内部/私有IP的位置
- 支持VPN:位置反映VPN退出节点(如果活动)
- 无重试逻辑:失败的工具调用立即出错(可以添加指数回退)
- 单一查询:一次处理一个问题(可以添加批量支持)
- 没有坚持:会话之间的状态已清除(除非启用了检查点)
扩展代理
添加新工具
-
实施中
server/tools.py:async def get_timezone(latitude: float, longitude: float) -> str: # Implementation return timezone_data -
注册于
server/main.py:@mcp.tool() async def timezone(latitude: float, longitude: float) -> str: return await get_timezone(latitude, longitude) -
添加节点
agent/main.py:async def get_timezone_node(state, tools): tool = next(t for t in tools if t.name == "timezone") result = await tool.ainvoke({ "latitude": state["latitude"], "longitude": state["longitude"] }) return {**state, "timezone": result} workflow.add_node("get_timezone", get_timezone_node) workflow.add_edge("fetch_weather", "get_timezone") workflow.add_edge("get_timezone", "generate_answer")
修改路由逻辑
更改条件边以支持替代流:
def route_after_ip(state: AgentState):
if state.get("error"):
return "error"
# New: Check if IP is internal/private
ip = state.get("public_ip", "")
if ip.startswith("192.168.") or ip.startswith("10."):
return "handle_private_ip" # New node
return "resolve_location"
测试
单元测试
测试单个节点:
import pytest
from agent.main import get_ip_node
@pytest.mark.asyncio
async def test_get_ip_node():
mock_tools = [MockIPifyTool()]
state = {"question": "test", "messages": []}
result = await get_ip_node(state, mock_tools)
assert result["public_ip"] is not None
assert result["error"] is None
集成测试
测试完整图形执行:
@pytest.mark.asyncio
async def test_full_workflow(mcp_server_running):
graph = await build_graph(client, llm)
initial_state = {...}
final_state = await graph.ainvoke(initial_state)
assert final_state["answer"] is not None
assert "temperature" in final_state["answer"].lower()
LangSmith监控(来源于文档,最后访问时间为2026年1月30日)
启用生产调试跟踪:
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=your_key
export LANGCHAIN_PROJECT="datacenter-weather"
每次执行都会在LangSmith仪表板上进行跟踪。
安全考虑
- API密钥:从不承诺
.env到版本控制 - 服务器暴露:MCP服务器没有身份验证(仅限本地使用)
- 速率限制:外部API可能会禁止滥用
- 输入验证:服务器验证所有工具输入
- 错误消息:避免日志中的敏感数据泄露
依赖项
- httpx:异步HTTP客户端
- 主控程序:模型上下文协议SDK
- 兰格拉夫:基于图的代理框架
- 语言链:LLM抽象层
- 郎链谷歌genai:Gemini集成
- 兰开夏:OpenAI兼容API(LongCat)
- python dotenv:环境变量管理
- 优维康:ASGI服务器
看 requirements.txt 对于特定版本。
了解更多
许可证
这是一个用于个人目的的示范项目。不提供保修。
建于:LangGraph自定义状态图(生产最佳实践,2026年1月)