LangChain-Learning_new/agent/langchain_agent_tool_mcp.py
2026-04-16 01:02:24 +08:00

137 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import asyncio
import logging
import sys
from docutils.nodes import description
from langchain_community.agent_toolkits.load_tools import load_tools
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain_mcp_adapters.client import MultiServerMCPClient
import os
import dotenv
from langgraph.checkpoint.memory import InMemorySaver
from pydantic import BaseModel, Field
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
dotenv.load_dotenv()
## 设置环境变量
os.environ['OPENAI_API_KEY'] = os.getenv("OLLAMA_API_KEY")
os.environ['OPENAI_BASE_URL'] = os.getenv("OLLAMA_BASE_URL")
# 默认的 'model_name': 'deepseek-ai/DeepSeek-V3.1',
llm = ChatOpenAI(model="gemma4:e2b")
def print_optimized_result(agent_response):
"""
解析代理响应并输出优化后的结果。
:param agent_response: 代理返回的完整响应
"""
messages = agent_response.get("messages", [])
steps = [] # 用于记录计算步骤
final_answer = None # 最终答案
for message in messages:
if hasattr(message, "additional_kwargs") and "tool_calls" in message.additional_kwargs:
# 提取工具调用信息
tool_calls = message.additional_kwargs["tool_calls"]
for tool_call in tool_calls:
tool_name = tool_call["function"]["name"]
tool_args = tool_call["function"]["arguments"]
steps.append(f"调用工具: {tool_name}({tool_args})")
elif message.type == "tool":
# 提取工具执行结果
tool_name = message.name
tool_result = message.content
steps.append(f"{tool_name} 的结果是: {tool_result}")
elif message.type == "ai":
# 提取最终答案
final_answer = message.content
# 打印优化后的结果
print("\n计算过程:")
for step in steps:
print(f"- {step}")
if final_answer:
print(f"\n最终答案: {final_answer}")
def greet(name: str) -> str:
"""用于打招呼的函数"""
return f"你好呀,{name}"
class greetInput(BaseModel):
name: str = Field(description="打招呼的对象")
async def execute():
# 1. 创建langchain中的mcp客户端 —— uv add langchain_mcp_adapters
client = MultiServerMCPClient(
# mcp.run(transport="streamable-http", host="127.0.0.1", port=9000)
{
# 这里是定义服务端信息的,可以有多个服务端
# 这里是定义服务端信息的,可以有多个服务端
"weather": {
"url": "http://localhost:9000/mcp",
"transport": "streamable_http",
},
"math": {
# "command": "python", # npx uvx
"command": sys.executable,
"args": ["./mcp/math_server.py"],
"transport": "stdio"
}
}
)
try:
# 2. 通过客户端获取工具列表
## 这里是通过服务端获取,所以可能会有异常(比如服务端没有启动,或者网络连接有问题
tools_mcp = await client.get_tools()
tools = tools_mcp + tools_internal + [tools_custom]
# 3. 创建一个智能代理,能够完成 思考--> 行动 --> 观察 --> 思考 --> 行动 --> ... --> 最终答案
from langchain.agents import create_agent
## 创建一个带记忆和工具的agent
agent = create_agent(
model=llm,
tools=tools,
# 配置记忆后必须增加thread_id, checkpoint_ns, checkpoint_id参数之一用于区分会话
checkpointer=InMemorySaver()
)
while True:
user_input = input("请输入你的问题输入exit则退出 > ")
if user_input == "exit":
print("感谢使用,再见👋🏻")
break
agent_response = await agent.ainvoke(
{"messages": [{"role": "user", "content": user_input}]},
{"configurable": {"thread_id": "1"}},
)
## agent会自己去调用 tools ,不需要我们去进行调用
print_optimized_result(agent_response)
finally:
# 资源回收
if hasattr(client, 'close'):
client.close()
if __name__ == '__main__':
tools_internal = load_tools(["arxiv", "wikipedia"], llm=llm, allow_dangerous_tools=True)
tools_custom = tool(
name_or_callable="greet",
runnable=greet,
description="用于打招呼的函数",
args_schema=greetInput
)
asyncio.run(execute())