基于MCP协议与Dify工作流构建智能旅游规划Agent

发布时间:2026/10/5 17:05:04
基于MCP协议与Dify工作流构建智能旅游规划Agent 国庆前朋友拉了个群让我帮忙排一趟西安的行程我一边在高德地图里查景点、查餐厅、查路线一边在Excel里手工整理清单来回切了十几个页面。折腾到后半夜我才意识到这个活儿本质上就是“多源检索 规则排序 结构化输出”完全可以直接交给AI Agent来做。于是我基于高德API把地点搜索、路线规划、周边推荐这几类高频能力通过MCP协议接入Dify工作流搭了一个能自动生成旅游规划清单的Agent输入目的地和偏好输出一份按天、按时段排好的行程表。这个Agent能做到什么程度你只要说一句“北京3日游喜欢胡同和老字号”它会自动把符合条件的景点和餐馆查出来用路线规划接口算好各点之间的通勤时间自动过滤掉评分低、与主题无关的POI最后整理成包含交通方式、建议时长、注意事项的旅行清单。文章会从选型思路、MCP Server编写、Dify工作流编排到实际踩坑排查完整拆解一遍。如果你正在玩Dify或者想入门MCP和Agent开发这篇东西应该能帮你少走不少弯路。1. 项目整体设计与思路拆解1.1 一个旅游清单为什么值得交给Agent来做旅游规划这件事听起来简单真正操作起来信息非常分散。景点要看高德上的位置和评分美食要看榜单和营业时间路线要算点与点之间的通勤距离最后还要把所有内容整合成一份有顺序、有时段、有理由的清单。这一整套流程如果靠人工完成至少半小时起步如果目的地不熟查攻略来回折腾一两个小时都是正常的。拆开来看这个过程本质上就是“检索信息 → 过滤无关项 → 按规则排序 → 生成结构化文本”四个环节都非常适合大模型加上外部工具来执行。传统方案的问题在于地图数据长在高德里模型自己背不出来就算背出来也没有实时路线和评分就算去调API每次返回的JSON格式还不一样写一堆适配代码实在太累。所以我的核心思路是让Agent负责“理解需求和决策”让高德API负责“提供事实数据”两者之间通过MCP协议做一个标准化连接。模型的优势是能听懂“喜欢安静但不想太偏僻”这种模糊表达高德的优势是有准确的POI数据和路径计算能力双方互补之后生成出来的行程清单才是真的可执行、可导航的。1.2 为什么是Dify MCP 高德API这个组合先说为什么不直接写代码。如果不用Dify我需要自己实现会话管理、模型调用、工具注册、Prompt模板、结果渲染还要写一个前端界面给朋友用。这是一整套工程不是一两天能搞定的。Dify把这些现成功能都内置了Agent节点自带工具调用的推理循环我只需要关注业务本身。再说为什么需要MCP。Dify里其实也可以直接用“HTTP请求”节点调高德API但对“旅游规划”这种场景来说高德API不止一个查景点、查美食、算路线、查周边、地理编码少说五六个接口。如果用HTTP节点工作流里要建五六个请求节点每个都要单独处理鉴权、参数、返回解析一旦接口有变动改起来很麻烦。MCP出现之后我可以把高德API封装成一个MCP Server把多个能力统一注册成toolsDify只需要连上这个Server就能自动发现所有工具。后续想加一个天气接口直接在这个Server里加一个函数Dify里同步一下就能用不用动工作流主体。整体选型对比可以看这张表维度纯代码高德SDKDify直接HTTP节点Dify MCP 高德API会话管理自己实现Dify内置Dify内置工具接入成本每个接口写一套每个接口一个节点一个Server统一暴露模型推理循环自己写工作流编排Agent节点自动决策扩展新工具改代码改工作流加一个函数即可维护成本高中低另外选高德而不选其他地图服务主要是两点考虑一是高德的POI数据在城市级的覆盖深度确实够二是Web服务API的个人配额足够支撑日常测试和小规模使用申请流程也比较快不需要商务审核。2. 核心细节解析与实操要点2.1 高德API里真正会用到的那几个接口高德开放平台接口很多但旅游规划Agent核心只需要四类。第一类是地点搜索接口路径是/v3/place/text通过关键词找POI返回结果里有name、location经纬度、rating评分、address、type等字段。比如我想找“北京的胡同”传keywords胡同city北京就能拿到南锣鼓巷、五道营胡同这些结果。这个接口是整个Agent最常用的任何候选POI都从它来。第二类是周边搜索/v3/place/around给定一个经纬度坐标搜索附近指定类型的POI。这个在“晚上到了酒店之后附近有什么可逛”这个场景下很实用模型拿到用户酒店的坐标后可以直接查周边美食和夜间去处。第三类是路径规划/v3/direction/walking、/v3/direction/driving、/v3/direction/transit对应步行、驾车、公交三种方式返回信息里最重要的是distance距离和duration耗时这两个字段是行程排序时的核心依据。第四类是逆地理编码/v3/geocode/regeo把经纬度坐标转成可读的地址描述。这个接口主要用来校验POI坐标的合理性或者在最终清单里给用户一个“位于XX路附近”的参考位置。说句实话旅游规划用不到地图渲染所以不需要引入地图JS SDK只调Web服务API完全够用。申请高德Key的时候注意一个细节在控制台创建应用时服务平台要选“Web服务API”拿到的是一个Key加一个安全密钥。很多教程只让你填Key但新版的签名校验会用到安全密钥建议提前把这两个都拿到后面写MCP Server的时候都配置进去。Key不要直接写进前端代码Agent的调用链里所有请求都走服务端这个习惯能帮你避开不少安全问题。2.2 MCP在项目里到底是什么角色MCPModel Context Protocol本质上是AI应用与外部工具之间的标准化通信协议你可以把它理解为“AI应用界的USB-C接口”。没有USB-C之前每个设备都要配一根专门的数据线接口协议还各不相同MCP出来之后工具发现、工具调用、参数传递、结果返回都定义了统一规范Dify只要连上MCP Server就能像插U盘一样自动识别里边的所有工具。从协议层面看MCP基于JSON-RPC 2.0核心抽象有三类tools可执行的动作、resources可读取的数据资源、prompts可复用的提示模板。在这个项目里我们用到的绝大多数都是tools每个tool对应一个高德API能力。Dify作为MCP客户端会调用MCP Server的tools/list方法获取工具列表然后在Agent的推理循环里根据用户意图选择具体tool执行。当初我也想过不引入MCP直接在Dify里建一堆“HTTP请求”节点。后来对比下来的感受是如果项目只需要接一两个接口HTTP节点足够简单直接但要像旅游规划这样同时接搜索、路线、周边、地理编码四五个接口MCP的收益就非常明显。所有工具在一个Server里统一管理Dify侧只需要接入一次后面就是直接使用的问题。而且MCP Server本身是一个独立进程不依赖Dify我可以单独测试高德API的返回也可以用单元测试来验证参数组装逻辑调试体验比绑在Dify工作流里舒服太多。2.3 Dify侧的准备模型、应用类型、变量在Dify里创建Agent应用之前有几个准备工作要确认。第一个是模型配置Dify本身不提供模型需要接入第三方模型服务。要跑Agent并调用MCP工具模型必须支持工具调用Function Calling能力目前国内的Qwen、DeepSeek、GLM这些主流模型都支持我实际用下来Qwen系列在“按格式输出结构化清单”这件事上表现不错DeepSeek也不错寒暑假高峰期偶尔会慢。选模型时不用盲目追最新最大Agent场景对推理能力有一定要求但对吞吐和成本更敏感中等规模的模型已经够用。第二个关键点是应用类型要选“Agent”而不是“工作流”或“Chatbot”。工作流模式适合固定步骤的确定性流程比如“先查天气再查路线再输出”每步都安排得明明白白Agent模式则让模型自己决定什么时候调用哪个工具、调用几次、返回结果怎么解读。旅游规划这类任务用户输入千变万化有的是“三日游”有的是“亲子游”有的是“只要摄影点”你不可能把所有分支都写进工作流交给Agent自动决策反而更稳。第三个是变量的设计。Dify里有会话变量和系统变量我的做法是会话变量存“目的地”“出行天数”“偏好主题”用户在对话开头填一次后面Agent后续追问的时候做上下文参考系统变量则由Dify自己管理包括聊天历史、工具返回值这些。一定要在Agent节点里勾选“对话轮次中的历史记录”否则模型可能会丢失前面已经确定的行程安排出现“刚定好的第三天下午行程下一轮对话又问一遍”的尴尬情况。3. 实操过程与核心环节实现3.1 Dify本地部署和插件环境准备Dify官方推荐用Docker Compose部署。先去GitHub把dify源代码仓库拉到本地进到docker目录看一眼.env文件把需要的密钥配置好然后直接执行docker compose up -d。首次启动会拉不少镜像网速不好可能会有超时耐心等或者换镜像源就能解决。起来之后打开浏览器访问本地端口创建管理员账号进入工作台。要接入MCP需要在Dify的“插件”市场里安装MCP类型插件。Dify的插件机制支持在线安装和离线安装两种方式在线装的话直接在插件市场搜索MCP就行如果Dify部署在公网受限的环境里可以离线下载插件包再手动导入文件放到插件目录后会提示安装。根据我之前踩坑的经验Dify版本不要太老1.x以上对MCP的支持才算稳定太老的版本连MCP插件都搜不到。3.2 高德MCP Server的实现代码实现高德MCP Server我用的Python生态核心依赖是mcp官方SDK和httpx异步请求库。先安装依赖pip install mcp[cli] httpx然后新建一个amap_mcp_server.py文件代码结构大概是这样的from mcp.server.fastmcp import FastMCP import httpx # 创建MCP Server实例名称为gaode-travel mcp FastMCP(gaode-travel) # 高德Web服务API的Key正式使用时建议从环境变量读取 AMAP_KEY 你的高德Key async def call_amap(api_path: str, params: dict) - dict: 统一的高德API请求封装 params[key] AMAP_KEY async with httpx.AsyncClient() as client: response await client.get( fhttps://restapi.amap.com{api_path}, paramsparams ) return response.json() mcp.tool() async def search_places(city: str, keywords: str, types: str ) - list[dict]: 关键词搜索指定城市的POI适合用来查景点、美食、酒店等。 city: 城市名称如北京 keywords: 搜索关键词如胡同 types: POI类型编码可选如风景名胜、餐饮服务 params {keywords: keywords, city: city, offset: 10} if types: params[types] types result await call_amap(/v3/place/text, params) pois result.get(pois, []) # 裁剪字段只保留Agent真正需要的 cleaned [] for poi in pois: cleaned.append({ name: poi.get(name), location: poi.get(location), address: poi.get(address, ), rating: poi.get(biz_ext, {}).get(rating, ), type: poi.get(type), }) return cleaned mcp.tool() async def plan_route(origin: str, destination: str, mode: str walking) - dict: 计算两个坐标点之间的路线返回里程和预计耗时。 origin: 起点坐标格式为经度,纬度 destination: 终点坐标格式为经度,纬度 mode: 出行方式可选walking/driving/transit api_path f/v3/direction/{mode} result await call_amap(api_path, { origin: origin, destination: destination, strategy: 0 }) paths result.get(route, {}).get(paths, []) if not paths: return {error: 路线规划失败请检查坐标是否合法} path paths[0] return { distance_km: round(int(path.get(distance, 0)) / 1000, 2), duration_min: round(int(path.get(cost, {}).get(duration, 0)) / 60, 1), steps: [step.get(instruction, ) for step in path.get(steps, [])] } if __name__ __main__: mcp.run(transporthttp)运行python amap_mcp_server.pyMCP Server默认监听8000端口。FastMCP这个封装层给开发者省了很多事工具注册就是一个装饰器的事类型标注会自动转成JSON Schema供模型识别这一点非常重要因为Dify的Agent就是靠工具描述来决定“什么时候该调用什么工具的”。如果嫌Python环境麻烦也可以用Dify社区里其他人封装好的现成高德MCP插件但自己写一遍的好处是能完全控制字段裁剪逻辑。比如高德搜索返回的JSON里有很多字段是Agent根本用不到的像pcode、adcode、timezone这些直接一股脑塞给模型既浪费token又可能干扰模型判断。我在MCP层就把返回结果精简成name、location、address、rating、type五个字段模型拿到手就是干净的候选清单。3.3 在Dify里接入MCP并编排Agent应用MCP Server跑起来之后回到Dify工作台进入“插件”页面添加一个MCP类型插件。填写名称gaode-travel类型选“HTTP”URL填http://host.docker.internal:8000/mcp。这里要注意Dify如果是用Docker容器跑的容器内部访问宿主机的localhost是走不通的要用host.docker.internal这个特殊域名来指代宿主机。如果不想依赖这个域名也可以把MCP Server同样跑在Docker里用容器名称互相访问。插件接通之后新建Agent应用选择模型然后在工具面板里应该能看到刚才MCP Server暴露出来的search_places和plan_route两个工具默认是未授权状态点一下授权启用。这一步完成后Agent的推理循环就已经能把“查景点”和“查路线”这两个动作和具体工具关联起来了。接下来是重头戏System Prompt的设计。我实际调了一版比较好用的放在这里供参考你是一位资深旅行规划师。你的任务是根据用户的目的地和偏好生成可执行的每日行程清单。 你必须严格按以下步骤工作 1. 先用 search_places 查询用户提到的核心景点和美食关键词拿到候选POI的名称、坐标和评分。 2. 对候选POI做筛选评分低于4.0的剔除与用户主题无关的类型剔除政府机关、培训机构、公司类POI一律移除。 3. 用 plan_route 计算前一天最后一个地点到当天第一个地点以及相邻安排之间的交通耗时。 4. 优先把相邻地点交通耗时小于40分钟的安排在同一天超时则调整顺序或替换备选POI。 5. 最终输出 Markdown 格式行程清单必须包含日期、时段上午/下午/晚上、地点名称、坐标、交通方式、预估耗时、建议理由。 注意坐标必须保留精度方便用户导航。如果某类信息查不到直接说明不要编造。这段Prompt的核心是把“规则”前置给模型减少模型自由发挥的空间。一开始我让它自由安排结果出现了一个上午塞三个景点最后一段路程要花两小时的情况加了“交通耗时小于40分钟”的硬性约束之后输出明显合理很多。不过这些规则不是死的如果你用户明确说“想去远郊没关系”可以通过对话覆盖掉。3.4 一次实际运行的输入与输出Agent搭好之后我拿“无锡2日游”做了一次完整的测试用户输入是“帮我规划无锡2日游主要想逛古镇和太湖边的自然风光吃得清淡一点。”Agent的执行过程大概是这样的先调用search_places搜索“无锡 古镇”和“无锡 太湖”拿到惠山古镇、荡口古镇、南长街、鼋头渚等一批POI筛选掉评分偏低的再用plan_route计算“鼋头渚到惠山古镇”的驾车时间约32分钟最后输出清单。最终结果经过我简化后是这样的日期时段安排交通方式预估耗时建议理由第一天上午惠山古镇打车/自驾3小时古镇街区保存完整早晨人少适合拍照第一天下午南长街驾车约20分钟2.5小时主打老街和小吃符合“吃清淡”的需求第一天晚上太湖之星摩天轮驾车约15分钟1.5小时太湖边夜景适合饭后散步第二天上午鼋头渚驾车约32分钟4小时太湖核心景点建议早到避开人流第二天下午蠡园驾车约10分钟2小时园林安静与太湖风光形成互补看起来很像样对吧但我要坦白第一次跑出来的结果远没这么顺出现过把“无锡市第一女子中学”选进景点候选的离谱情况。后来在MCP的search_places返回结果里过滤了POI类型把“学校”“政府机构”“公司企业”这类明显不是旅游目的地的类型直接剔除情况才改善。这其实暴露了一个规律Agent能不能稳定产出好结果一半靠模型推理另一半靠你给工具的数据是不是干净。工具侧多做一层过滤模型侧就能少犯一层错。4. 常见问题与排查技巧实录4.1 Dify部署和连接阶段的SSL与凭据校验坑本地跑Dify接入MCP Server时最容易碰到两类报错。第一类是dify ssl error也就是SSL证书错误。原因往往是Dify工具验证默认走HTTPS而本地MCP Server跑的是HTTP两边协议对不上。解决办法是把插件配置里的URL写成http://开头并且确认MCP Server本身没有强制TLS。如果你把MCP Server部署到了远程服务器那反过来要配好HTTPS证书才能接本地开发不建议上证书纯HTTP足够。第二类是an error occurred during credentials validation这个是Dify在验证MCP工具凭据时的通用报错。排查顺序我建议是这样先用浏览器或curl访问一下http://你的地址/mcp/看能不能拿到JSON-RPC响应能拿到说明Server本身没问题问题出在Dify容器到Server之间的网络拿不到检查MCP Server进程是否还活着、端口有没有被防火墙拦截。之前我遇到过一次MCP Server正常运行但Dify容器里host.docker.internal解析失败把URL改成宿主机局域网IP就解决了。这类问题本质是网络拓扑问题和MCP协议本身关系不大但报错提示写得比较吓人容易让人误判。4.2 文档处理场景的unstructured API报错旅游规划Agent如果只是依赖高德API是不需要知识库的但你如果想把小红书攻略、PDF游记这些资料喂给Agent做参考就会碰到这个报错unstructured api url is not configured for doc file processing。原因是Dify处理文档类文件依赖unstructured这个第三方解析服务如果环境变量里没有配置对应的API地址和密钥文档解析就会失败。我踩过一次之后总结了两条路。一是配置环境变量在docker-compose的.env文件里加上UNSTRUCTURED_API_URL和UNSTRUCTURED_API_KEY都指向你实际的解析服务地址重启Dify。二是偷懒方案直接把PDF或Word文件转成纯文本TXT再上传到知识库绕开unstructured解析。对于旅游攻略这种内容转成TXT之后信息损失很小但省掉了一层依赖稳定性和速度反而更好。顺带提一句Dify社区版的离线插件安装也是围绕这套生态做的遇到“插件装了但加载不出来”的问题先检查插件版本和Dify版本是否匹配。4.3 运行期的上下文超长、变量聚合器和工具同步问题Agent运行起来之后最常见的质量问题是上下文超长。高德API返回原始JSON比较大的时候模型一次对话里多次调用工具很快就把上下文窗口挤爆。解决方式是双管齐下第一层在MCP Server里做字段裁剪返回给模型的数据只保留必要信息第二层在Dify里用变量聚合器把多个工具返回值合并成一个精简的最终结构再传给模型的输出阶段。如果还不知道Dify变量聚合器的用法简单说就是它可以把不同来源的数据“攒”成一段文本或结构化对象减少后续步骤重复访问原始数据也能降低token损耗。还有一类问题是“工具找不到”或“新工具不生效”。MCP Server新增了一个工具函数但Dify的工具面板里始终看不到。排查逻辑很简单MCP Server没有重启Dify拿不到新的tools/list结果。要让改动生效必须重启MCP Server进程让Dify重新拉取工具列表。这个坑我也踩过好几次后来我习惯每次改完工具定义就顺手刷一下Dify的工具面板确认数量和描述都对得上再往下走。现象可能原因处理方式Dify连MCP报SSL错误本地Server跑HTTP插件配置成HTTPS把URL改成http开头确认无TLS强制credentials validation失败容器无法访问宿主机MCP用host.docker.internal或局域网IP文档解析报unstructured错误缺环境变量或插件未启用配置解析服务地址或转TXT绕开上下文超长工具返回字段过多MCP层裁剪字段用变量聚合器合并Agent引用了非旅游POI搜索接口返回了无关类型在MCP层过滤学校、机构、公司等类型新增工具不生效MCP Server未重启重启Server并刷新Dify工具列表4.4 并发和配额问题Agent能扛住高频调用吗很多人关心AI Agent怎么扛并发这个问题其实分两层看。Dify应用本身部署好了多个用户同时对话基本没问题真正的瓶颈往往在MCP Server和高德API配额上。高德Web服务API的个人配额并不算高搜索接口每日调用量有限制QPS一般也就几十Agent一个回合里连续调用十几次搜索是很正常的很容易瞬间把配额打满。我的应对策略是在MCP Server上做两层防护。第一层是轻量缓存对相同参数的搜索请求一小时内的结果直接返回缓存不重复调高德。旅游Agent的场景里同一个城市同一个关键词被反复搜索的概率很高缓存效果非常明显。第二层是做限流用一个简单的令牌桶算法限制每秒最多多少次请求超出的请求排队或快速失败。通过缓存和限流双保险实际运行中高德配额消耗速度被压下去好几倍。如果你要承接更大规模的生产并发可以考虑把MCP Server部署成多个副本前面再加一层负载均衡但作为个人项目或小团队项目缓存已经够用。5. 实操心得与后续扩展按我自己做完这个项目的体会来说MCP和Dify这套组合真正适合的场景就是“模型负责思考工具负责查证”的信息检索型Agent。旅游规划只是其中一个不错的方向同样的架构换成查物流、查政策文件、查商品库存逻辑几乎不需要改只要把MCP Server里的工具换成对应的业务API就行。最近社区里大家都在讨论Agent框架与编排经常会提到Agent和Harness的区别——我认为Agent是那个做决策的大脑Harness是承载工具和执行的“工作台”Dify工作流负责编排MCP Server和底层API就是那个执行台。有几个小技巧分享一下。第一MCP Server里不要把所有接口都暴露给Agent暴露得越多模型越容易乱三四张工具刚刚好第二模型的强弱真的影响最终清单质量弱模型不太会遵循“40分钟内”这种约束这时候可以把规则下沉到MCP Server里用代码强行过滤不要让LLM承担它不擅长的计算第三给Agent的输出加一层模板校验很有用我直接在Dify的Agent节点输出前接了一个“格式整理”步骤确保每条清单都包含坐标字段这样用户拿到之后可以直接丢进导航。后续我打算在这个Agent里再接一个天气查询工具让清单自动避开雨天安排户外景点还想加入导出ics日历文件的能力把行程一键同步到手机日历。如果哪天高德API配额不够了可以考虑在MCP层接一个备份地图服务协议不变只换后端实现。最后说句实在话这类项目并不是要证明Agent比人更会旅游而是想说明一套好的工具链条能帮我们把重复劳动压缩到很低的程度——我在这个项目里省下的时间远多于搭它花掉的时间。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询