v0.0.11
mcp
This commit is contained in:
parent
eb82b1a174
commit
765201f9ef
6
.env
6
.env
@ -12,4 +12,8 @@ MINIMAX_API_KEY = "sk-cp-wWkzvRP-BiQia-6izxvqgehEsHSz8v4_PtDJAuT3OI0s8QFcEOsxIHc
|
|||||||
MINIMAX_BASE_URL = "https://api.minimaxi.com/v1"
|
MINIMAX_BASE_URL = "https://api.minimaxi.com/v1"
|
||||||
|
|
||||||
BAILIAN_API_KEY = "sk-8c8bec7a613249dbbed08bc3affeef72"
|
BAILIAN_API_KEY = "sk-8c8bec7a613249dbbed08bc3affeef72"
|
||||||
BAILIAN_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
BAILIAN_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||||
|
|
||||||
|
# gemma4:e2b
|
||||||
|
CHERRY_API_KEY = "w6qWTWfnmF5t9OKGDPYpCoLJlga4F7Ezj4OT2XiDtJ3PFCqG"
|
||||||
|
CHERRY_BASE_URL = "https://open.cherryin.cc/v1"
|
||||||
|
|||||||
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Python
|
||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.Python
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Env
|
||||||
|
.env
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.env
|
||||||
@ -1 +1 @@
|
|||||||
3.11
|
3.13
|
||||||
|
|||||||
36
README.md
36
README.md
@ -1,14 +1,16 @@
|
|||||||
# LangChain Learning
|
# LangChain Learning
|
||||||
|
|
||||||
[](https://github.com/your-repo/langchain-learning)
|
[](https://github.com/your-repo/langchain-learning)
|
||||||
[](https://www.python.org/)
|
[](https://www.python.org/)
|
||||||
[](https://www.langchain.com/)
|
[](https://www.langchain.com/)
|
||||||
|
|
||||||
> LangChain 框架学习项目,集成 SiliconFlow & Ollama API
|
> 基于 LangChain 0.3.27 的学习项目,集成 SiliconFlow & Ollama API
|
||||||
|
|
||||||
## 功能特性
|
## 功能特性
|
||||||
|
|
||||||
- **多 LLM 集成**:支持 OpenAI API、SiliconFlow、Ollama 及 LangChain 抽象层
|
- **多 LLM 集成**:支持 OpenAI API、SiliconFlow、Ollama 及 LangChain 抽象层
|
||||||
|
- **MCP 协议支持**:通过 MultiServerMCPClient 连接多个 MCP 服务器
|
||||||
|
- **Agent 智能体**:基于 LangGraph 的 ReAct Agent 实现自主推理与工具调用
|
||||||
- **RAG 检索增强生成**:基于向量库(FAISS)的文档检索与问答
|
- **RAG 检索增强生成**:基于向量库(FAISS)的文档检索与问答
|
||||||
- **流式响应**:实时流式输出,带来更好的使用体验
|
- **流式响应**:实时流式输出,带来更好的使用体验
|
||||||
- **Prompt 工程**:多种 Prompt 模板构建方式
|
- **Prompt 工程**:多种 Prompt 模板构建方式
|
||||||
@ -18,14 +20,13 @@
|
|||||||
- **内存管理**:实现对话历史持久化(ConversationBufferMemory, SummaryMemory)
|
- **内存管理**:实现对话历史持久化(ConversationBufferMemory, SummaryMemory)
|
||||||
- **Rich 终端界面**:支持 Markdown 渲染、多行输入等高级交互
|
- **Rich 终端界面**:支持 Markdown 渲染、多行输入等高级交互
|
||||||
- **模型测速工具**:测试模型的首字延迟 (TTFT) 和每秒生成速度 (TPS)
|
- **模型测速工具**:测试模型的首字延迟 (TTFT) 和每秒生成速度 (TPS)
|
||||||
- **实战示例**:从基础到进阶的使用模式
|
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
### 1. 安装依赖
|
### 1. 安装依赖
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install langchain>=1.2.15 langchain-community>=0.4.1 langchain-siliconflow>=1.0.0 requests>=2.33.1 rich openai pydantic
|
uv sync
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 配置环境变量
|
### 2. 配置环境变量
|
||||||
@ -80,6 +81,21 @@ OLLAMA_API_KEY=ollama
|
|||||||
| 工具定义 | `python tools/tool_definition.py` | 演示 @tool 装饰器和 StructuredTool 定义方式 |
|
| 工具定义 | `python tools/tool_definition.py` | 演示 @tool 装饰器和 StructuredTool 定义方式 |
|
||||||
| 工具调用 | `python tools/tool_demo.py` | 演示模型如何调用工具并获取结果 |
|
| 工具调用 | `python tools/tool_demo.py` | 演示模型如何调用工具并获取结果 |
|
||||||
|
|
||||||
|
**MCP 示例**
|
||||||
|
|
||||||
|
| 示例 | 命令 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| MCP 客户端 | `python mcp/mcp_client.py` | 连接 MCP 服务器并获取工具列表 |
|
||||||
|
| Agent + MCP | `python mcp/mcp_client_with_agent.py` | 使用 ReAct Agent 调用 MCP 工具 |
|
||||||
|
| Agent + MCP (简易版) | `python mcp/mcp_client_with_agent_simple.py` | 简化版的 Agent MCP 调用 |
|
||||||
|
|
||||||
|
**MCP 服务端示例**
|
||||||
|
|
||||||
|
| 示例 | 命令 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 天气服务 | `python mcp/get_weather_server.py` | 提供天气查询的 MCP 服务端 |
|
||||||
|
| 数学服务 | `python mcp/math_server.py` | 提供数学计算的 MCP 服务端 |
|
||||||
|
|
||||||
**Token 用量示例**
|
**Token 用量示例**
|
||||||
|
|
||||||
| 示例 | 命令 | 说明 |
|
| 示例 | 命令 | 说明 |
|
||||||
@ -124,6 +140,12 @@ langchain-learning/
|
|||||||
├── tools/
|
├── tools/
|
||||||
│ ├── tool_definition.py # 工具定义方式演示
|
│ ├── tool_definition.py # 工具定义方式演示
|
||||||
│ └── tool_demo.py # 工具调用完整流程演示
|
│ └── tool_demo.py # 工具调用完整流程演示
|
||||||
|
├── mcp/
|
||||||
|
│ ├── mcp_client.py # MCP 客户端基础用法
|
||||||
|
│ ├── mcp_client_with_agent.py # Agent + MCP 工具调用
|
||||||
|
│ ├── mcp_client_with_agent_simple.py # Agent + MCP 简易版
|
||||||
|
│ ├── get_weather_server.py # 天气查询 MCP 服务端
|
||||||
|
│ └── math_server.py # 数学计算 MCP 服务端
|
||||||
├── token/
|
├── token/
|
||||||
│ └── token_demo.py # Token 用量追踪示例
|
│ └── token_demo.py # Token 用量追踪示例
|
||||||
├── memory/
|
├── memory/
|
||||||
@ -156,8 +178,10 @@ langchain-learning/
|
|||||||
|
|
||||||
| 类别 | 技术 |
|
| 类别 | 技术 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| 框架 | LangChain |
|
| 框架 | LangChain 0.3.27 |
|
||||||
|
| Agent | LangGraph |
|
||||||
| LLM 提供商 | SiliconFlow, Ollama |
|
| LLM 提供商 | SiliconFlow, Ollama |
|
||||||
|
| MCP | langchain-mcp-adapters |
|
||||||
| 向量库 | FAISS |
|
| 向量库 | FAISS |
|
||||||
| 终端美化 | Rich |
|
| 终端美化 | Rich |
|
||||||
| 数据验证 | Pydantic |
|
| 数据验证 | Pydantic |
|
||||||
|
|||||||
20
mcp/get_weather_server.py
Normal file
20
mcp/get_weather_server.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# uv add fastmcp
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from fastmcp import FastMCP
|
||||||
|
|
||||||
|
mcp = FastMCP("mcp demo")
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def get_weather(city: str) -> str:
|
||||||
|
"""获取传入的城市的天气信息"""
|
||||||
|
logging.info(f"调用了查询天气服务,传入的参数为{city}")
|
||||||
|
return f"{city}的天气很好,阳光明媚,晴空万里"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
logging.info("启动一个可以通过MCP调用获取天气的服务")
|
||||||
|
mcp.run(transport="streamable-http", host="127.0.0.1", port=9000)
|
||||||
|
# mcp.run(transport="stdio", host="127.0.0.1", port=9000)
|
||||||
29
mcp/math_server.py
Normal file
29
mcp/math_server.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from fastmcp import FastMCP
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# 配置日志记录器
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO, # 设置日志级别为 INFO
|
||||||
|
format="%(asctime)s - %(levelname)s - %(message)s" # 日志格式
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# 创建 FastMCP 实例
|
||||||
|
mcp = FastMCP("Math")
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def add(a: int, b: int) -> int:
|
||||||
|
"""Add two numbers"""
|
||||||
|
logger.info("The add method is called: a=%d, b=%d", a, b) # 记录加法调用日志
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def multiply(a: int, b: int) -> int:
|
||||||
|
"""Multiply two numbers"""
|
||||||
|
logger.info("The multiply method is called: a=%d, b=%d", a, b) # 记录乘法调用日志
|
||||||
|
return a * b
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logger.info("Start math server through MCP") # 记录服务启动日志
|
||||||
|
# mcp.run(transport="streamable-http",port=8081,path='/mcp') # 启动服务并使用标准输入输出通信
|
||||||
|
mcp.run(transport="stdio") # 启动服务并使用标准输入输出通信(子进程)
|
||||||
12
mcp/mcp_client.py
Normal file
12
mcp/mcp_client.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import asyncio
|
||||||
|
from fastmcp import Client
|
||||||
|
|
||||||
|
client = Client("http://localhost:9000/mcp")
|
||||||
|
|
||||||
|
async def call_tool(city: str):
|
||||||
|
async with client:
|
||||||
|
result = await client.call_tool("get_weather", {"city": city})
|
||||||
|
print(result)
|
||||||
|
## 启动服务端后,再启动客户端进行连接和调用
|
||||||
|
## 这种方式是通过fastmcp的客户端直接调用的
|
||||||
|
asyncio.run(call_tool("北京"))
|
||||||
102
mcp/mcp_client_with_agent.py
Normal file
102
mcp/mcp_client_with_agent.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# from langchain.agents import create_react_agent
|
||||||
|
from langgraph.prebuilt import create_react_agent
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
||||||
|
import os
|
||||||
|
import dotenv
|
||||||
|
|
||||||
|
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:26b")
|
||||||
|
|
||||||
|
|
||||||
|
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}")
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
"args": ["./mcp/math_server.py"],
|
||||||
|
"transport": "stdio"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 2. 通过客户端获取工具列表
|
||||||
|
## 这里是通过服务端获取,所以可能会有异常(比如服务端没有启动,或者网络连接有问题
|
||||||
|
tools = await client.get_tools()
|
||||||
|
|
||||||
|
# 3. 创建一个智能代理,能够完成 思考--> 行动 --> 观察 --> 思考 --> 行动 --> ... --> 最终答案
|
||||||
|
agent = create_react_agent(model=llm, tools=tools)
|
||||||
|
while True:
|
||||||
|
user_input = input("请输入你的问题(输入exit则退出) > ")
|
||||||
|
if user_input == "exit":
|
||||||
|
print("感谢使用,再见👋🏻")
|
||||||
|
break
|
||||||
|
|
||||||
|
agent_response = await agent.ainvoke({"messages": user_input})
|
||||||
|
## agent会自己去调用 tools ,不需要我们去进行调用
|
||||||
|
print_optimized_result(agent_response)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# 资源回收
|
||||||
|
if hasattr(client, 'close'):
|
||||||
|
client.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(execute())
|
||||||
56
mcp/mcp_client_with_agent_simple.py
Normal file
56
mcp/mcp_client_with_agent_simple.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# from langchain.agents import create_react_agent
|
||||||
|
from langgraph.prebuilt import create_react_agent
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
from langchain_mcp_adapters.client import MultiServerMCPClient
|
||||||
|
import os
|
||||||
|
import dotenv
|
||||||
|
|
||||||
|
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:26b")
|
||||||
|
|
||||||
|
|
||||||
|
async def execute():
|
||||||
|
# 1. 创建langchain中的mcp客户端
|
||||||
|
# uv add langchain_mcp_adapters
|
||||||
|
client = MultiServerMCPClient(
|
||||||
|
{
|
||||||
|
# 这里是定义服务端信息的,可以有多个服务端
|
||||||
|
"weather": {
|
||||||
|
"url": "http://localhost:9000/mcp",
|
||||||
|
"transport": "streamable_http",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 2. 通过客户端获取工具列表
|
||||||
|
## 这里是通过服务端获取,所以可能会有异常(比如服务端没有启动,或者网络连接有问题
|
||||||
|
tools = await client.get_tools()
|
||||||
|
|
||||||
|
# 3. 创建一个智能代理,能够完成 思考--> 行动 --> 观察 --> 思考 --> 行动 --> ... --> 最终答案
|
||||||
|
agent = create_react_agent(model=llm, tools=tools)
|
||||||
|
agent_response = await agent.ainvoke({"messages":"北京的天气怎么样?适合出门吗?"})
|
||||||
|
print(agent_response)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# 资源回收
|
||||||
|
if hasattr(client, 'close'):
|
||||||
|
client.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(execute())
|
||||||
@ -6,9 +6,14 @@ readme = "README.md"
|
|||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"faiss-cpu>=1.13.2",
|
"faiss-cpu>=1.13.2",
|
||||||
"langchain==0.3.27",
|
"fastmcp>=3.2.4",
|
||||||
"langchain-community==0.3.31",
|
"langchain>=0.3.27",
|
||||||
"langchain-siliconflow==0.1.3",
|
"langchain-community>=0.3.31",
|
||||||
|
"langchain-core>=0.3.40",
|
||||||
|
"langchain-mcp-adapters>=0.0.1",
|
||||||
|
"langchain-openai>=0.3.35",
|
||||||
|
"langchain-siliconflow>=0.1.3",
|
||||||
|
"langgraph>=1.0.1",
|
||||||
"requests>=2.33.1",
|
"requests>=2.33.1",
|
||||||
"rich>=15.0.0",
|
"rich>=15.0.0",
|
||||||
]
|
]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user