Files
gjm 1afcc10a61 add
测试mcp基座
2026-10-06 23:10:38 +08:00

163 lines
6.6 KiB
Python

import socket
import json
import time
from openai import OpenAI
# 初始化 DeepSeek 客户端
client = OpenAI(
api_key="sk-420190f448fe41158c4e2ccff90e35ce",
base_url="https://api.deepseek.com"
)
MODEL_NAME = "deepseek-chat"
def fetch_and_translate_tools():
"""向 CAD 基座发送 tools/list,并转换为大模型认识的格式"""
try:
cad_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cad_socket.connect(("127.0.0.1", 8080))
# 1. 向 MCP Server 发送标准的 tools/list 请求
req = {
"jsonrpc": "2.0",
"id": 100,
"method": "tools/list"
}
cad_socket.sendall(json.dumps(req).encode('utf-8'))
response_data = cad_socket.recv(8192)
cad_socket.close()
mcp_response = json.loads(response_data.decode('utf-8'))
if "result" not in mcp_response or "tools" not in mcp_response["result"]:
print("[Error] 无法从 CAD 获取工具列表")
return []
llm_tools = []
# 2. 遍历 CAD 返回的工具,将其翻译为 DeepSeek/OpenAI 格式
for mcp_tool in mcp_response["result"]["tools"]:
llm_tools.append({
"type": "function",
"function": {
"name": mcp_tool["name"],
"description": mcp_tool["description"],
# 核心转换:MCP 的 inputSchema 等价于 LLM 的 parameters
"parameters": mcp_tool["inputSchema"]
}
})
print(f"[Init] 成功从 CAD 动态加载了 {len(llm_tools)} 个工具!")
return llm_tools
except Exception as e:
print(f"[Error] 获取工具列表失败: {e}")
return []
def call_cad_mcp_server(tool_name, arguments):
"""底层 TCP 通信保持不变"""
try:
cad_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cad_socket.connect(("127.0.0.1", 8080))
req = {
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": { "name": tool_name, "arguments": arguments }
}
cad_socket.sendall(json.dumps(req).encode('utf-8'))
response_data = b""
while True:
chunk = cad_socket.recv(8192)
response_data += chunk
if len(chunk) < 8192: break
cad_socket.close()
return json.loads(response_data.decode('utf-8'))
except Exception as e:
print(f"[Error] 连接 CAD 基座失败: {e}")
return None
def run_agent(user_prompt):
print("=== 🚀 CAD 具身智能 Agent 启动 ===")
# 动态向 CAD 请求可用工具,彻底解耦!
tools = fetch_and_translate_tools()
if not tools:
print("没有可用的工具,Agent 退出。")
return
# 核心心智设定:教它怎么形成视觉闭环
system_prompt = """你是一个高阶 AutoCAD 视觉检查专家。
请严格遵循以下工作流:
1. 第一步永远是调用 `get_viewport_screenshot` 观察当前画面。
2. 仔细评估图像。如果目标物体(如图元、文字)太小导致无法确信细节,请调用 `zoom_window_normalized` 放大该局部区域。
3. 【关键指令】:每次执行缩放操作(zoom)后,你必须在下一回合再次调用 `get_viewport_screenshot` 获取放大后的新截图!
4. 反复观察和放大,直到你 100% 看清细节,再用自然语言向用户输出最终结论。"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
MAX_TURNS = 8 # 熔断机制:最多允许思考 8 个回合,防止无限套娃
for turn in range(MAX_TURNS):
print(f"\n--- [第 {turn + 1} 回合] 思考中 ---")
response = client.chat.completions.create(
model=MODEL_NAME,
messages=messages,
tools=tools
)
assistant_message = response.choices[0].message
messages.append(assistant_message) # 记录思维路径
# 1. 检查是否需要执行物理动作
if assistant_message.tool_calls:
for tool_call in assistant_message.tool_calls:
tool_name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
print(f"[动作决定] ⚡ 调用工具: {tool_name}")
if args: print(f" 参数: {args}")
# 执行 CAD 通信
cad_res = call_cad_mcp_server(tool_name, args)
time.sleep(0.5) # 给予 CAD 渲染刷新窗口的时间缓冲
# 处理执行结果,并准备发回给 LLM 的观测报告
tool_result_content = []
if cad_res and "result" in cad_res:
for item in cad_res["result"]["content"]:
if item["type"] == "text":
tool_result_content.append({"type": "text", "text": item["text"]})
elif item["type"] == "image":
base64_img = item["data"]
mime = item.get("mimeType", "image/png")
tool_result_content.append({
"type": "image_url",
"image_url": {"url": f"data:{mime};base64,{base64_img}"}
})
print("[观测反馈] 📸 已将最新 CAD 屏幕画面传回视觉中枢。")
else:
tool_result_content.append({"type": "text", "text": "CAD 工具执行失败或无响应。"})
# 必须向大模型提交 Tool 返回结果
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": tool_result_content
})
# 2. 如果不调工具,说明任务已完成,输出最终自然语言结论
else:
print("\n==================================")
print(f"🎯 [最终结论]:\n{assistant_message.content}")
print("==================================")
break
else:
print("\n[警告] 达到最大思考回合数限制,Agent 强行中止。")
if __name__ == "__main__":
run_agent("请仔细检查当前图纸,告诉我图纸中心那些小圆的内部,是否还包含了更小的同心圆?如果看不清,请务必放大确认。")