目录
一、前言
你是否曾梦想过像科幻电影里那样,用说话就能指挥机械臂干活?现在这个梦想在VREP仿真环境里成真啦!今天要给大家分享一个超酷的项目——基于MCP协议的uArm机械臂自然语言控制系统,让你只需动口就能玩转三轴机械臂,完全不用写复杂代码,小白也能轻松上手!
接着上篇,这篇来好好唠唠怎么手动实现一个大模型MCP客户端。咱就对着这段代码一步步拆解,把它搞明白。
直接上代码:
二、代码开头部分
import asyncio
from typing import Optional
from contextlib import AsyncExitStack
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from mcp.client.sse import sse_client
#from anthropic import Anthropic
from dotenv import load_dotenv
from openai import OpenAI
import json
这部分就是导入各种需要用的库。asyncio
是用来处理异步操作的,这在和服务器通信的时候特别有用,能提高效率。OpenAI
这个库让我们能方便地调用大模型API。dotenv
可以帮我们加载环境变量,保证代码的安全性。
三、 大模型配置
#阿里百炼
LLM = OpenAI(
api_key="sk-206236c9bc694c94a8f根据申请8b93",
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
load_dotenv()
这里配置了大模型,用的是阿里百炼的模型。你得把 api_key
换成你自己申请的,这样才能正常调用模型。load_dotenv()
会把 .env
文件里的环境变量加载进来。
四、 MCPClient 类
class MCPClient:
def __init__(self):
self.session: Optional[ClientSession] = None
self.exit_stack = AsyncExitStack()
self.llm=LLM
MCPClient
类是整个客户端的核心。在初始化方法里,我们设置了会话 session
初始为 None
,exit_stack
用来管理异步上下文,llm
就是我们前面配置好的大模型。
连接服务器方法
async def connect_to_sse_server(self, server_url: str):
self._streams_context = sse_client(url=server_url)
streams = await self._streams_context.__aenter__()
self._session_context = ClientSession(*streams)
self.session: ClientSession = await self._session_context.__aenter__()
await self.session.initialize()
async def connect_to_server(self, server_script_path: str):
is_python = server_script_path.endswith('.py')
is_js = server_script_path.endswith('.js')
if not (is_python or is_js):
raise ValueError("Server script must be a .py or .js file")
command = "python" if is_python else "node"
server_params = StdioServerParameters(
command=command,
args=[server_script_path],
env=None
)
stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
self.stdio, self.write = stdio_transport
self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))
await self.session.initialize()
response = await self.session.list_tools()
tools = response.tools
print("\nConnected to server with tools:", [tool.name for tool in tools])
这里有两个连接服务器的方法。connect_to_sse_server
是用SSE(Server-Sent Events)协议连接服务器,能实现服务器向客户端实时推送消息。connect_to_server
则是根据服务器脚本的类型(Python 或者 JavaScript)来启动服务器,然后连接上去,还会列出服务器上可用的工具。
处理查询方法
async def process_query(self, query: str) -> str:
messages = [
{
"role": "user",
"content": query
}
]
response = await self.session.list_tools()
available_tools = [
{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters":tool.inputSchema
}
} for tool in response.tools]
qwen_response = self.llm.chat.completions.create(
model="qwen-turbo",
messages=messages,
temperature=0.6,
top_p=0.7,
max_tokens=4096,
tools=available_tools,
)
assistant_output = qwen_response.choices[0].message
if assistant_output.content is None:
assistant_output.content = ""
return "llm no respones\n".join(final_text)
else:
if assistant_output.tool_calls == None:
print(f"无需调用工具")
final_text.append(assistant_output.content)
messages.append({
"role": "assistant",
"content": assistant_output.content
})
else:
tool_name = assistant_output.tool_calls[0].function.name
tool_args = json.loads(assistant_output.tool_calls[0].function.arguments)
print(f"call mcp server tool:\n tool_name:{tool_name}\n tool_args:{tool_args}")
result = await self.session.call_tool(tool_name, tool_args)
final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")
messages.append({
"role": "user",
"content": result.content
})
messages.append({
"role": "system",
"content": "请只回答与当前任务直接相关的内容,不要输出任何其他信息。直接给出对工具调用结果的分析。"
})
qwen_response = self.llm.chat.completions.create(
model="qwen-turbo",
max_tokens=1000,
messages=messages,
)
final_text.append(qwen_response.choices[0].message.content)
return "\n".join(final_text)
process_query
方法用来处理用户的查询。首先把用户的查询封装成消息,然后列出服务器上可用的工具。接着调用大模型 qwen-turbo
来处理查询。如果模型返回的结果不需要调用工具,就直接把结果返回;如果需要调用工具,就调用服务器上的工具,把工具调用结果再传给模型,让模型继续处理,最后把所有结果拼接起来返回。
聊天循环方法
async def chat_loop(self):
print("\nMCP Client Started!")
print("Type your queries or 'quit' to exit.")
while True:
try:
query = input("\nQuery: ").strip()
if query.lower() == 'quit':
break
response = await self.process_query(query)
print("\n" + response)
except Exception as e:
print(f"\nError: {str(e)}")
chat_loop
方法实现了一个交互式的聊天循环。程序启动后,会提示你输入查询内容,你输入 quit
就可以退出。每次输入查询后,程序会调用 process_query
方法处理查询,并把结果打印出来。
清理资源方法
async def cleanup(self):
await self.exit_stack.aclose()
cleanup
方法用来清理资源,关闭异步上下文。
五、主函数
async def main():
if len(sys.argv) < 2:
print("Usage: python client.py <path_to_server_script> or <sse url such as :http://localhost:9900/sse>")
sys.exit(1)
client = MCPClient()
try:
await client.connect_to_sse_server(sys.argv[1])
await client.chat_loop()
finally:
await client.cleanup()
if __name__ == "__main__":
import sys
asyncio.run(main())
主函数 main
会检查命令行参数,如果参数不够,会提示你正确的使用方法。然后创建 MCPClient
实例,连接服务器,启动聊天循环,最后在程序结束时清理资源。
好啦,到这里整个大模型MCP客户端的核心代码就拆解完了。大家要是有兴趣,可以自己动手试试,搞出一个属于自己的客户端!
大模型+MCP服务让机械臂听懂人话
最后
这个项目把大模型的“智能”和机械臂的“精准”结合得恰到好处,真正实现了“自然语言控制硬件”的轻量化方案。不管你是机械臂爱好者、AI开发者,还是单纯觉得好玩的极客,都可以试试——毕竟,用说话就能指挥机械臂的感觉,真的太酷了!
赶紧下载项目源代码,启动你的“LLM智能机械臂之旅”吧~
下载相关资源
(项目版权归FEI PANFENG所有,欢迎垂询!)
-----------------本篇完------------------
PS.扩展阅读
————————————————————————————————————————
对于python机器人编程感兴趣的小伙伴,可以进入如下链接阅读相关咨询
ps1.六自由度机器人相关文章资源
(1) 对六自由度机械臂的运动控制及python实现(附源码)
ps2.四轴机器相关文章资源
(1) 文章:python机器人编程——用python实现一个写字机器人
(2)python机器人实战——0到1创建一个自动是色块机器人项目-CSDN直播
(3)博文《我从0开始搭建了一个色块自动抓取机器人,并实现了大模型的接入和语音控制-(上基础篇)》的vrep基础环境
(3)博文《我从0开始搭建了一个色块自动抓取机器人,并实现了大模型的接入和语音控制-(上基础篇)》的vrep基础环境
(4)实现了语音输入+大模型指令解析+机器视觉+机械臂流程打通
ps3.移动小车相关文章资源
(1)python做了一个极简的栅格地图行走机器人,到底能干啥?[第五弹]——解锁蒙特卡洛定位功能-CSDN博客
(2) 对应python资源:源码地址
(3)python机器人编程——差速AGV机器、基于视觉和预测控制的循迹、自动行驶(上篇)_agv编程-CSDN博客
(4)python机器人编程——差速AGV机器、基于视觉和预测控制的循迹、自动行驶(下篇)_agv路线规划原则python-CSDN博客
对应python及仿真环境资源:源码链接
ps3.wifi小车控制相关文章资源
web端配套资源源代码已经上传(竖屏版),下载地址
仿真配套资源已经上传:下载地址
web端配套资源源代码已经上传(横屏版),下载地址