使用LangChain和DeepSeek调用百度地图MCP服务

我们在上一遍文章中介绍了自己如何开发MCP Server,并通过 LangChain +DeepSeek实现实现多MCP服务的调用。文章地址:https://lowcode.blog.csdn.net/article/details/147035705

本文以调用百度地图接口为示例,介绍如何基于 LangChain +DeepSeek调用第三方的MCP服务,并给出整个示例的 Python 代码。

智能体开发平台在线体验地址:http://www.yunchengxc.com

一、MCP是什么

MCP(Model Context Protocol)是什么、使用MCP有什么好处、MCP的技术架构,这些内容在前面文章中都有介绍,本文不再重复。

二、前提条件

1、Python运行环境安装。建议使用Python3.10以上版本,本示例使用了 Python 3.12.9版本。

2、Python开发工具安装。本人是vue\Java\python多种语言开发,所以使用了 IntelliJ IDEA开发工具。读者可以根据个人习惯选择合适的Python开发工具,比如:PyCharm、VS Code。

3、注册DeepSeek,获得访问deepseek模型服务的api_key。DeepSeek的AI开放平台地址:https://platform.deepseek.com。

4、注册百度地图,获得访问百度地图服务的api_key。Baidu平台地址:https://lbsyun.baidu.com/faq/api?title=mcpserver/prepare。

三、代码实现

1、创建python工程

首先,通过开发工具创建一个python工程。这一步很简单,不再描述。

接着,激活虚拟环境项目目录,并通过以下命令创建并激活虚拟环境:

python -m venv venv   #有的环境下命令是python3或者py

.\venv\Scripts\activate  #windows下的激活命令

注意:如果是通过IDEA工具创建的Python工程,默认会创建并激活venv虚拟环境,就不再需要手动创建

2、pip安装依赖包

本示例使用langchain、LangGraph和DeepSeek,所以需要先安装依赖包。

在虚拟环境命令窗口执行:

pip install -U langchain langgraph

pip install -U langchain-deepseek

3、开发Baidu地图MCP Server

百度官方提供了地图的MCP Server,无需我们自己开发,下载官方源代码文件,导入我们的python工程即可。

百度地图核心API现已全面兼容MCP协议,百度地图提供了多个核心API接口和MCP协议的对接, 涵盖逆地理编码、地点检索、路线规划等。百度地图MCP Server发布后,智能体开发者仅需简单配置,就可以在大模型中快速接入地图服务,实现查找周边地点、 规划出行路线等能力,大幅降低了智能体应用开发过程中调用地图服务相关能力的门槛,显著提升了智能体应用的开发效率。

以下是百度地图MCP Server的源码代码,命名baidu_map.py

import os
import copy
import httpx
from asyncio import sleep

from mcp.server.fastmcp import FastMCP, Context

# 创建MCP服务器实例
mcp = FastMCP("mcp-server-baidu-maps")
# 设置API密钥,请更换为自己申请的密钥,用于调用百度地图API,获取方式请参考:https://lbsyun.baidu.com/apiconsole/key
# api_key = os.getenv('BAIDU_MAPS_API_KEY')
api_key="b6QFwBcBeJSJsUlIIYSxgttpi3v4E0M7"
api_url = "https://api.map.baidu.com"

def filter_result(data) -> dict:
    '''
    过滤路径规划结果,用于剔除冗余字段信息,保证输出给模型的数据更简洁,避免长距离路径规划场景下chat中断
    '''

    # 创建输入数据的深拷贝以避免修改原始数据
    processed_data = copy.deepcopy(data)

    # 检查是否存在'result'键
    if 'result' in processed_data:
        result = processed_data['result']

        # 检查'result'中是否存在'routes'键
        if 'routes' in result:
            for route in result['routes']:
                # 检查每个'route'中是否存在'steps'键
                if 'steps' in route:
                    new_steps = []
                    for step in route['steps']:
                        # 提取'instruction'字段,若不存在则设为空字符串
                        new_step = {
                            'distance': step.get('distance', ''),
                            'duration': step.get('duration', ''),
                            'instruction': step.get('instruction', '')
                        }
                        new_steps.append(new_step)
                    # 替换原steps为仅含instruction的新列表
                    route['steps'] = new_steps

    return processed_data


@mcp.tool()
async def map_geocode(
        address: str,
        ctx: Context
) -> dict:
    """
    Name:
        地理编码服务

    Description:
        将地址解析为对应的位置坐标。地址结构越完整,地址内容越准确,解析的坐标精度越高。

    Args:
        address: 待解析的地址。最多支持84个字节。可以输入两种样式的值,分别是:
        1、标准的结构化地址信息,如北京市海淀区上地十街十号【推荐,地址结构越完整,解析精度越高】
        2、支持“*路与*路交叉口”描述方式,如北一环路和阜阳路的交叉路口
        第二种方式并不总是有返回结果,只有当地址库中存在该地址描述时才有返回。

    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/geocoding/v3/"

        # 设置请求参数
        # 更多参数信息请参考:https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding
        params = {
            "ak": f"{api_key}",
            "output": "json",
            "address": f"{address}",
            "from": "py_mcp"
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e


@mcp.tool()
async def map_reverse_geocode(
        latitude: float,
        longitude: float,
        ctx: Context
) -> dict:
    """
    Name:
        逆地理编码服务

    Description:
        根据经纬度坐标点获取对应位置的行政区划与POI信息

    Args:
        latitude: 纬度 (gcj02ll)
        longitude: 经度 (gcj02ll)

    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("There")

        # 调用百度API
        url = f"{api_url}/reverse_geocoding/v3/"

        # 设置请求参数
        # 更多参数信息请参考:https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-abroad
        params = {
            "ak": f"{api_key}",
            "output": "json",
            "coordtype": "gcj02ll",
            "location": f"{latitude},{longitude}",
            "extensions_poi": "1",
            "from": "py_mcp"
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e


@mcp.tool()
async def map_search_places(
        query: str,
        region: str,
        location: str,
        radius: int,
        ctx: Context
) -> dict:
    """
    Name:
        地点检索服务

    Description:
        城市内检索: 检索某一城市内(目前最细到城市级别)的地点信息。
        周边检索: 设置圆心和半径,检索圆形区域内的地点信息(常用于周边检索场景)。

    Args:
        query: 检索关键字
        region: 检索的行政区划
        location: 圆形区域检索中心点
        radius: 圆形区域检索半径,单位:米

    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/place/v2/search"

        # 设置请求参数
        # 更多参数信息请参考:https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-placeapi
        params = {
            "ak": f"{api_key}",
            "output": "json",
            "query": f"{query}",
            "region": f"{region}",
            "from": "py_mcp"
        }
        if location:
            params["location"] = f"{location}"
            params["radius"] = f"{radius}"

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e

@mcp.tool()
async def map_place_details(
        uid: str,
        ctx: Context
) -> dict:
    """
    Name:
        地点详情检索服务

    Description:
        地点详情检索: 地点详情检索针对指定POI,检索其相关的详情信息。
        开发者可以通地点检索服务获取POI uid。使用“地点详情检索”功能,传入uid,即可检索POI详情信息,如评分、营业时间等(不同类型POI对应不同类别详情数据)。

    Args:
        uid: poi的唯一标识
    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/place/v2/detail"

        # 设置请求参数
        # 更多参数信息请参考:https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-placeapi/detail
        params = {
            "ak": f"{api_key}",
            "output": "json",
            "uid": f"{uid}",
            # Agent入参不可控,这里给定scope为2
            "scope": 2,
            "from": "py_mcp"
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e

@mcp.tool()
async def map_distance_matrix(
        origins: str,
        destinations: str,
        mode: str,
        ctx: Context
) -> dict:
    """
    Name:
        批量算路服务

    Description:
        根据起点和终点坐标计算路线规划距离和行驶时间
        批量算路目前支持驾车、骑行、步行
        步行时任意起终点之间的距离不得超过200KM,超过此限制会返回参数错误
        驾车批量算路一次最多计算100条路线,起终点个数之积不能超过100

    Args:
        origins: 多个起点坐标纬度,经度,按|分隔。示例:40.056878,116.30815|40.063597,116.364973【骑行】【步行】支持传入起点uid提升绑路准确性,格式为:纬度,经度;POI的uid|纬度,经度;POI的uid。示例:40.056878,116.30815;xxxxx|40.063597,116.364973;xxxxx
        destinations: 多个终点坐标纬度,经度,按|分隔。示例:40.056878,116.30815|40.063597,116.364973【【骑行】【步行】支持传入终点uid提升绑路准确性,格式为:纬度,经度;POI的uid|纬度,经度;POI的uid。示例:40.056878,116.30815;xxxxx|40.063597,116.364973;xxxxx
        mode: 批量算路类型(driving, riding, walking)

    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/routematrix/v2/{mode}"

        # 设置请求参数
        # 更多参数信息请参考:https://lbsyun.baidu.com/faq/api?title=webapi/routchtout
        params = {
            "ak": f"{api_key}",
            "output": "json",
            "origins": f"{origins}",
            "destinations": f"{destinations}",
            "from": "py_mcp"
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e

@mcp.tool()
async def map_directions(
        model: str,
        origin: str,
        destination: str,
        ctx: Context
) -> dict:
    """
    Name:
        路线规划服务

    Description:
        驾车路线规划: 根据起终点坐标规划驾车出行路线
        骑行路线规划: 根据起终点坐标规划骑行出行路线
        步行路线规划: 根据起终点坐标规划步行出行路线
        公交路线规划: 根据起终点坐标规划公共交通出行路线

    Args:
        model: 路线规划类型(driving, riding, walking, transit)
        origin: 起点坐标,当用户只有起点名称时,需要先通过地理编码服务或地点地点检索服务确定起点的坐标
        destination: 终点坐标,当用户只有起点名称时,需要先通过地理编码服务或地点检索服务确定起点的坐标

    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/directionlite/v1/{model}"

        # 设置请求参数
        # 更多参数信息请参考:https://lbs.baidu.com/faq/api?title=webapi/direction-api-v2
        params = {
            "ak": f"{api_key}",
            "output": "json",
            "origin": f"{origin}",
            "destination": f"{destination}",
            "from": "py_mcp"
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        '''
        过滤非公交的导航结果,防止返回的结果中包含大量冗余坐标信息,影响大模型的响应速度,或是导致chat崩溃。
        当前只保留导航结果每一步的距离、耗时和语义化信息。
        公交路线规划情况比较多,尽量全部保留。
            
        '''
        if model == 'transit':
            return result
        else:
            return filter_result(result)

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e


@mcp.tool()
async def map_weather(
        location: str,
        district_id: int,
        ctx: Context
) -> dict:
    """
    Name:
        天气查询服务

    Description:
        用户可通过行政区划或是经纬度坐标查询实时天气信息及未来5天天气预报(注意: 使用经纬度坐标需要高级权限)。

    Args:
        location: 经纬度,经度在前纬度在后,逗号分隔 (需要高级权限, 例如: 116.30815,40.056878)
        district_id: 行政区划 (例如: 1101010)
    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/weather/v1/?"

        # 设置请求参数
        # 更多参数信息请参考:https://lbs.baidu.com/faq/api?title=webapi/weather
        params = {
            "ak": f"{api_key}",
            "data_type": "all",
            "from": "py_mcp"
        }

        # 核心入参,二选一
        if not location:
            params["district_id"] = f"{district_id}"
        else :
            params["location"] = f"{location}"

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e


@mcp.tool()
async def map_ip_location(
        # ip: str,
        ctx: Context
) -> dict:
    """
    Name:
        IP定位服务

    Description:
        根据用户请求的IP获取当前的位置,当需要知道用户当前位置、所在城市时可以调用该工具获取

    Args:
    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/location/ip"

        # 设置请求参数
        # 更多参数信息请参考:https://lbs.baidu.com/faq/api?title=webapi/ip-api
        params = {
            "ak": f"{api_key}",
            "from": "py_mcp"
        }

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e


@mcp.tool()
async def map_road_traffic(
        model: str,
        road_name: str,
        city: str,
        bounds: str,
        vertexes: str,
        center: str,
        radius: int,
        ctx: Context
) -> dict:
    """
    Name:
        实时路况查询服务

    Description:
        查询实时交通拥堵情况, 可通过指定道路名和区域形状(矩形, 多边形, 圆形)进行实时路况查询。

        道路实时路况查询: 查询具体道路的实时拥堵评价和拥堵路段、拥堵距离、拥堵趋势等信息
        矩形区域实时路况查询: 查询指定矩形地理范围的实时拥堵情况和各拥堵路段信息
        多边形区域实时路况查询: 查询指定多边形地理范围的实时拥堵情况和各拥堵路段信息
        圆形区域(周边)实时路况查询: 查询某中心点周边半径范围内的实时拥堵情况和各拥堵路段信息


    Args:
        model:      路况查询类型(road, bound, polygon, around)
        road_name:  道路名称和道路方向, model=road时必传 (如:朝阳路南向北)
        city:       城市名称或城市adcode, model=road时必传 (如:北京市)
        bounds:     区域左下角和右上角的经纬度坐标, model=bound时必传 (如:39.912078,116.464303;39.918276,116.475442)
        vertexes:   多边形区域的顶点经纬度, model=polygon时必传 (如:39.910528,116.472926;39.918276,116.475442;39.916671,116.459056;39.912078,116.464303)
        center:     圆形区域的中心点经纬度坐标, model=around时必传 (如:39.912078,116.464303)
        radius:     圆形区域的半径(米), 取值[1,1000], model=around时必传 (如:200)

    """
    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用百度API
        url = f"{api_url}/traffic/v1/{model}?"

        # 设置请求参数
        # 更多参数信息请参考:https://lbs.baidu.com/faq/api?title=webapi/traffic
        params = {
            "ak": f"{api_key}",
            "output": "json",
            "from": "py_mcp"
        }

        # 核心入参,根据model选择
        match model:
            case 'bound':
                params['bounds'] = f'{bounds}'
            case 'polygon':
                params['vertexes'] = f'{vertexes}'
            case 'around':
                params['center'] = f'{center}'
                params['radius'] = f'{radius}'
            case 'road':
                params['road_name'] = f'{road_name}'
                params['city'] = f'{city}'
            case _:
                pass

        async with httpx.AsyncClient() as client:
            response = await client.get(url, params=params)
            response.raise_for_status()
            result = response.json()

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

        return result

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e


@mcp.tool()
async def map_poi_extract(
        text_content: str,
        ctx: Context
) -> dict:
    """
    Name:
        POI智能提取

    Description:
        根据用户提供的文本描述信息, 智能提取出文本中所提及的POI相关信息. (注意: 使用该服务, api_key需要拥有对应的高级权限, 否则会报错)

    Args:
        text_content: 用于提取POI的文本描述信息 (完整的旅游路线,行程规划,景点推荐描述等文本内容, 例如: 新疆独库公路和塔里木湖太美了, 从独山子大峡谷到天山神秘大峡谷也是很不错的体验)
    """

    # 关于高级权限使用的相关问题,请联系我们: https://lbsyun.baidu.com/apiconsole/fankui?typeOne=%E4%BA%A7%E5%93%81%E9%9C%80%E6%B1%82&typeTwo=%E9%AB%98%E7%BA%A7%E6%9C%8D%E5%8A%A1

    try:
        # 获取API密钥
        if not api_key:
            raise Exception("Can not found API key.")

        # 调用POI智能提取的提交接口
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        submit_url = f"{api_url}/api_mark/v1/submit"
        result_url = f"{api_url}/api_mark/v1/result"

        # 设置上传用户描述的请求体
        submit_body = {
            "ak": f"{api_key}",
            "id": 0,
            "msg_type": "text",
            "text_content": f"{text_content}",
            "from": "py_mcp"
        }

        # 异步请求
        async with httpx.AsyncClient() as client:
            # 提交任务
            submit_resp = await client.post(
                submit_url, data=submit_body, headers=headers, timeout=10.0
            )
            submit_resp.raise_for_status()
            submit_result = submit_resp.json()

            if submit_result.get("status") != 0:
                error_msg = submit_result.get("message", "unkown error")
                raise Exception(f"API response error: {error_msg}")


            map_id = submit_result.get("result", {}).get("map_id")
            if not map_id:
                raise Exception("Can not found map_id")

            # 轮询获取结果(最多5次,间隔2秒)
            result_body = {"ak": api_key, "id": 0, "map_id": map_id, "from": "py_mcp"}
            max_retries = 5
            for attempt in range(max_retries):
                result_resp = await client.post(
                    result_url, data=result_body, headers=headers, timeout=10.0
                )
                result_resp.raise_for_status()
                result = result_resp.json()

                if result.get("status") == 0 and result.get("result"):
                    return result
                elif attempt < max_retries - 1:
                    await sleep(2)

            else:
                raise Exception("Timeout to get the result")

        if result.get("status") != 0:
            error_msg = result.get("message", "unkown error")
            raise Exception(f"API response error: {error_msg}")

    except httpx.HTTPError as e:
        raise Exception(f"HTTP request failed: {str(e)}") from e
    except KeyError as e:
        raise Exception(f"Failed to parse reponse: {str(e)}") from e

if __name__ == "__main__":
    print("baidu地图服务,MCP Server启动成功")
    mcp.run(transport="stdio")  # 启动服务并使用标准输入输出通信

注意:该MCP Server中定义了调用百度地图接口的10个方法,分别是:  ['map_geocode', 'map_reverse_geocode', 'map_search_places', 'map_place_details', 'map_distance_matrix', 'map_directions', 'map_weather', 'map_ip_location', 'map_road_traffic', 'map_poi_extract'],

具体这些API接口的用处,请参考百度官方说明文档:https://lbsyun.baidu.com/faq/api?title=mcpserver/base

4、开发调用百度地图的MCP Client

通过Python开发工具,创建一个python文件,命名为baidu_map_client.py。源代码如下:

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from langchain_mcp_adapters.tools import load_mcp_tools
from langgraph.prebuilt import create_react_agent
from langchain_deepseek import ChatDeepSeek

# 初始化 DeepSeek 大模型客户端
llm = ChatDeepSeek(
    model="deepseek-chat",  # 指定 DeepSeek 的模型名称
    api_key="sk-e508ba61639640848060a1a2c1ee7b17"  # 替换为您自己的 DeepSeek API 密钥
)

# 解析并输出结果
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 main():
    # 创建服务器参数
    server_params = StdioServerParameters(
        command="python",
        args=["./baidu_map.py"],
    )

    # 使用 stdio_client 进行连接
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            # 初始化连接
            await session.initialize()
            print("成功连接到MCP Server")

            # 加载工具
            tools = await load_mcp_tools(session)
            print("加载工具完成: ", [tool.name for tool in tools])

            # 创建代理
            agent = create_react_agent(llm, tools)

            # 循环接收用户输入
            while True:
                try:
                    # 提示用户输入问题
                    user_input = input("\n请输入您的问题(或输入 'exit' 退出):")
                    if user_input.lower() == "exit":
                        print("感谢使用!再见!")
                        break

                    # 调用代理处理问题
                    agent_response = await agent.ainvoke({"messages": user_input})

                    # 打印完整响应(调试用)
                   # print("\n完整响应:", agent_response)

                    # 调用抽取的方法处理输出结果
                    print_optimized_result(agent_response)

                except Exception as e:
                    print(f"发生错误:{e}")
                    continue

# 使用 asyncio 运行异步主函数
if __name__ == "__main__":
    asyncio.run(main())

四、运行测试

先运行MCP Server,即baidu_map.py,再运行baidu_map_client.py

,在命令行窗口进行AI对话,观察日志输出结果,确定是否调用了百度地图的MCP Server服务。

提问:

从北京西站到清华大学怎么走,优先考虑地铁?

回答:

一共调用了3次百度地图服务,分别是:

map_geocode({"address": "北京西站"})

map_geocode({"address": "清华大学"})

map_directions(参数)

最后返回了完整结果。

最终答案: 从北京西站到清华大学的地铁路线如下:

1. **步行至北京西站地铁站**  

   - 步行约471米,大约需要6分钟。

2. **乘坐地铁9号线(国家图书馆方向)**  

   - 从北京西站(3西北口)上车,经过4站到达国家图书馆站。

   - 预计时间:约10分钟。

3. **换乘地铁4号线大兴线(安河桥北方向)**  

   - 在国家图书馆站换乘地铁4号线,经过6站到达圆明园站(B东北口)。

   - 预计时间:约13分钟。

4. **步行至清华大学**  

   - 从圆明园站步行约1.9公里,大约需要25分钟。

**总行程**  

- 距离:约14.6公里  

- 时间:约63分钟  

- 费用:5元(地铁票价)

猜你喜欢

转载自blog.csdn.net/wxz258/article/details/147040940
今日推荐