大模型智能体与MCP(二) 使用Langchain 1.2实现MCP和智能体调用

张开发
2026/4/16 1:42:16 15 分钟阅读

分享文章

大模型智能体与MCP(二) 使用Langchain 1.2实现MCP和智能体调用
MCP过程MCP 起源于 2024 年 11 月 25 日 Anthropic 发布的文章Introducing the Model Context Protocol定义了应用程序和 AI 模型之间交换上下文信息的方式。这使得开发者能够以一致的方式将各种数据源、工具和功能连接到 AI 模型一个中间协议层就像 USB-C 让不同设备能够通过相同的接口连接一样。MCP 的目标是创建一个通用标准使 AI 应用程序的开发和集成变得更加简单和统一。类似于上一章的工具调用Function CallMCP 就是以更标准的方式让 LLM Chat 使用不同工具,具体实现步骤为:用户提出一个问题客户端将问题发生给在线大模型进行思考由大模型从工具库中分析可用的工具和对应描述由大模型决定使用其中一个或多个工具客户端使用MCP Server 从工具的提供源执行工具工具执行结果返回大模型大模型结合执行结果构造最终的prompt返回自然语言响应结果回复结果给用户MCP大模型LLM 在以下方面存在局限大模型不擅长数值精确计算——通过 Tools 调用计算器或 Excel训练数据有截止日期——通过 Resources 或网络检索获取最新数据无法直接操作本地文件/数据库——通过 Tools 桥接系统 API难以执行特定业务逻辑——通过 Tools 封装业务能力缺乏功能拓展性——通过MCP调用外部 API天气、地图、GitHub浏览器和自动化工具应用示例调用百度地图MCP依赖安装langchain_mcp_adapters准备百度地图MCP key和大模型API key创建MCP客户端和工具集由于百度地图的tools和langchain的tools格式存在差异需要自定义构建工具并使用异步方法asyncdefcreate_bmap_mcp_client():mcp_config{amap-maps-streamableHTTP:{url:fhttps://mcp.map.baidu.com/sse?ak{key},transport:sse,}}clientMultiServerMCPClient(mcp_config)print(client)mcp_toolsawaitclient.get_tools()safe_tools[]fortinmcp_tools:defcreate_wrappers(orig_tool):asyncdefarun_wrapper(**kwargs):try:# 尝试调用原始工具resawaitorig_tool.ainvoke(kwargs)returnstr(res)ifnotisinstance(res,str)elseresexceptExceptionase:# ⚠️ 拦截报错转化为大模型能看懂的自然语言提示error_msgf调用工具失败报错信息:{str(e)}。hint请检查你传入的参数。是否因为你传入了地名而该工具实际需要的是经纬度(lat, lng)如果是请先调用搜索工具获取坐标returnerror_msghintdefrun_wrapper(**kwargs):try:resorig_tool.invoke(kwargs)returnstr(res)ifnotisinstance(res,str)elseresexceptExceptionase:error_msgf调用工具失败报错信息:{str(e)}。hint请检查你传入的参数。是否因为你传入了地名而该工具实际需要的是经纬度(lat, lng)如果是请先调用搜索工具获取坐标returnerror_msghintreturnrun_wrapper,arun_wrapper run_fn,arun_fncreate_wrappers(t)# 构建标准的 LangChain Toolsafe_toolStructuredTool(namet.name,descriptiont.description,args_schemat.args_schema,# 继承原工具的参数模型funcrun_fn,coroutinearun_fn,)safe_tools.append(safe_tool)# print(\n*50)print(️ 可用 MCP 工具列表)print(*50)fori,toolinenumerate(safe_tools,1):# 如果用的是上文的 safe_toolsprint(f[{i}] 工具名称:{tool.name})print(f 描述:{tool.description})# print(f 参数: {tool.args})# print(- * 50)returnclient,safe_tools提示词和智能体构建asyncdefcreate_run_agent():client,toolsawaitcreate_bmap_mcp_client()llmChatOpenAI(modeldeepseek-chat,base_urlhttps://api.deepseek.com,api_keyAPI_KEY,streamingTrue,)system_templateChatMessagePromptTemplate.from_template(template你是一名生活智能助手会调用百度地图MCP工具解决问题,rolesystem,)human_templateChatMessagePromptTemplate.from_template(template用户提问{question},roleuser,# role只有user没有human的值)# 提示词模板导入预设好的系统以及用户模板Dchat_promptChatPromptTemplate.from_messages([system_template,human_template,])messageschat_prompt.format_messages(questionr 目标 - 明天上午9点我要从广州塔到白云机场 - 线路选择公交地铁或者打车 - 考虑出行时间和路线以及天气情况 - 输出一个HTML页面输出到D:\Project-Python\LLMtest\LLM_MCP\02-MCP\.temp 要求 - 制作网页来展示出行线路和位置 - 网页使用简约美观的页面的页面风格以及卡片展示 - 行程规划的结果要能够在百度地图APP中展示并集成到H5页面中 ,)# 创建智能体输入大模型和工具agentcreate_agent(llm,toolstoolsfile_tools)# 控制台调试console_handlerStdOutCallbackHandler()# 使用异步方法respawaitagent.ainvoke({messages:messages},config{callbacks:[console_handler]})# 输出内容print(resp[messages][-1].content)returnresp# 异步调用asyncio.run(create_run_agent())生成的html页面导览内容完整美观MCP的两种传输方式——StdioStreamable HttpStdio(标准输入输出)通过本地进程的标准输入stdin和标准输出stdout进行通信。客户端以子进程的形式启动MCP服务器双方通过管道交换JSON-RPC格式的消息消息以换行符分隔适用于本地进程通信和简单的批处理任务和工具调用极度轻量无网络开销不支持分布式部署。使用Stdio传输代码分为MCP server和client需要开启MCP server由client调用MCP服务frommcp.server.fastmcpimportFastMCP#创建MCP服务mcpFastMCP(Math Tools)#工具定义mcp.tool()defadd(a:int,b:int)-int:add two numbersreturnabmcp.tool()defmul(a:int,b:int)-int:multiply two numbersreturna*bmcp.tool()defdiv(a:int,b:int)-float:divide two numbersreturna/b#使用stdio传输if__name____main__:mcp.run(transportstdio)importasyncioimportosfromdotenvimportload_dotenvfromlangchain.agentsimportcreate_agentfromlangchain_core.callbacksimportStdOutCallbackHandlerfromlangchain_core.messagesimportSystemMessage,HumanMessagefromlangchain_deepseekimportChatDeepSeekfromlangchain_mcp_adapters.toolsimportload_mcp_toolsfrommcpimportStdioServerParameters,ClientSessionfrommcp.client.stdioimportstdio_client load_dotenv()API_KEYos.getenv(deepseek_api_key)asyncdefcreate_client():server_parametersStdioServerParameters(commandpython,args[stdio_server.py],)llmChatDeepSeek(modeldeepseek-chat,api_keyAPI_KEY,streamingTrue,)asyncwithstdio_client(server_parameters)as(read,write):asyncwithClientSession(read,write)assession:awaitsession.initialize()toolsawaitload_mcp_tools(session)print(tools)agentcreate_agent(llm,tools)console_handlerStdOutCallbackHandler()system_msgSystemMessage(你是一个使用已有工具进行运算的助手严禁直接回复答案)human_msgHumanMessage(43*2?)respawaitagent.ainvoke({messages:[system_msg,human_msg]},config{callbacks:[console_handler]})returnresp respasyncio.run(create_client())print(resp[messages][-1].content) Entering new tools chain... content[{type: text, text: 6, id: lc_90e60247-9c7c-4001-a049-aea511dcedfc}] namemul tool_call_idcall_00_CqLDf5WfKzqD8XfQhj0FksU7 artifact{structured_content: {result: 6}} Finished chain. Entering new model chain... Processing request of type CallToolRequest Finished chain. Entering new tools chain... content[{type: text, text: 10, id: lc_09255275-68c5-4fb1-ada7-5dc9df3a8bb3}] nameadd tool_call_idcall_00_8UCKDEwgNfXX9xTPYkvWLIqk artifact{structured_content: {result: 10}} Finished chain. Entering new model chain... Finished chain. Finished chain. 所以 4 3 * 2 10。从输出可发现大模型先使用乘法工具算出6最后使用加法工具算出10Streamable Http2025年3月引入的新传输方式替代了SSE。通过统一的/message端点实现双向通信适用于高并发远程服务调用和需要灵活流式响应的场景如AI助手的动态输出。相比SSE支持连接恢复无需重新开始。无需服务器维持长连接降低资源压力。统一端点/message简化接口设计MCP官方推荐的传输方式在stdio上进行两处修改即可第一处MCP Server 中mcp.run(transportstreamable-http)第二处Client中clientMultiServerMCPClient({math:{url:http://127.0.0.1:8000/mcp,transport:streamable_http,}})toolsawaitclient.get_tools()

更多文章