简介这份PDF资料面向具备一定Python基础、希望深入AI智能体开发的金融科技从业者围绕Dify与MCP协议讲解如何构建可执行金融操作的理财助手打通行情分析、策略生成到微信端自动推送的全链路。内容涵盖金融助手核心能力架构、MCP智能体协议配置、Dify工作流搭建、微信消息路由服务与RAG知识库集成并给出关键代码片段同时深入实时行情获取、资产组合分析引擎与微信模板消息生成等实现细节还分享部署压测结果与一键部署指南。资源包为单个PDF文件共1个文件约248KB便于集中阅读与对照实践。目前已有262人学习。读者可借此掌握各模块交互逻辑理解意图识别、工具链调用与消息格式化的具体做法并获得高并发稳定性与合规性方面的排错思路适合边读边动手复现。1. 金融理财助手为什么需要 Dify 加 MCP 这套组合微信群里每天都有客户问“今天有什么稳健的配置建议”靠人工一条条回既慢又容易漏。我去年帮一个做投顾的朋友搭过一套自动化推送系统核心思路就是用 Dify 做策略编排和话术生成用 MCP 把行情数据、组合计算、微信推送这几个外部能力接进来最后跑成一个能定时触发、按客户标签分发的闭环。这套方案解决的不是“AI 能不能写理财文案”而是“策略从哪来、数据怎么进、消息怎么出”这三个工程问题。适合有基础 Python 能力、手头有 Dify 环境、想给现有理财业务加一层自动化推送的开发者。读完你能自己搭出一条从行情拉取到微信端送达的最小链路也能看清哪些参数必须调、哪些坑一定会踩。2. Dify 工作流与 MCP 协议的分工边界2.1 为什么不让 Dify 直接调微信接口很多人第一反应是在 Dify 的代码节点里直接写 requests 调微信 API我一开始也这么干过结果翻车了。Dify 的代码节点运行在沙箱里出网策略、超时时间、依赖库版本都不受你控制一旦微信侧要求签名校验或者需要维护 access_token 缓存代码节点就会变得又长又脆。更关键的是Dify 工作流本身是“无状态编排”它擅长的是把 LLM 调用、条件分支、变量赋值串起来而不是做长连接和凭证管理。MCP 的定位正好补上这一块。MCP 是 Model Context Protocol你可以把它理解成一套标准化的“工具插座”Dify 作为客户端通过 MCP 协议去调用外部 MCP Server 暴露的工具。行情查询、组合计算、微信消息发送各自封装成独立的 MCP ServerDify 只负责在合适的节点调用合适的工具。这样职责清晰微信侧的 token 刷新、重试、限流都放在 MCP Server 里Dify 工作流保持干净。常见做法是Dify 工作流负责“决策”MCP Server 负责“执行”。决策包括判断今天是否交易日、客户风险等级是否匹配、推送话术用哪套模板执行包括拉取实时行情、计算组合权重、调用微信接口发送。两者通过 MCP 的 tools/call 请求通信Dify 侧只需要配置好 MCP Server 的地址和工具名。2.2 用 Docker 把 Dify 和 MCP Server 跑在同一台机器上本地验证阶段我一般用 Docker Compose 把 Dify 社区版和一个自写的 MCP Server 放在同一网络里。Dify 的安装用官方 docker-compose.yamlMCP Server 单独写一个 Dockerfile。这样 Dify 容器里配置 MCP Server 地址时直接用服务名而不是 localhost避免容器网络不通的玄学问题。# 目录结构 # dify/ 官方 docker-compose.yaml 所在目录 # mcp-finance/ 自写 MCP Server # Dockerfile # server.py # requirements.txt # 在 dify 目录下启动 Dify cd dify docker compose up -d # 在 mcp-finance 目录下构建并启动 MCP Server cd ../mcp-finance docker build -t mcp-finance:latest . docker run -d --name mcp-finance \ --network dify_default \ -p 8765:8765 \ -e WECHAT_APPIDyour_appid \ -e WECHAT_SECRETyour_secret \ mcp-finance:latest逻辑说明--network dify_default让 MCP Server 加入 Dify 创建的默认网络Dify 容器内就能用http://mcp-finance:8765访问它。端口映射到宿主机是为了方便你用 curl 单独调试 MCP Server正式环境可以去掉-p。环境变量传微信凭证避免硬编码在代码里。参数说明WECHAT_APPID和WECHAT_SECRET来自微信公众平台用于获取 access_token。MCP Server 启动后监听 8765Dify 侧配置 MCP 连接时填http://mcp-finance:8765/sse或对应的 streamable HTTP 端点具体路径取决于你用的 MCP SDK 版本。提示Dify 社区版 1.10 之后对多租户和 MCP 连接的支持有调整如果你用的是更早版本MCP 配置入口可能在“工具”而不是“外部知识库”里先确认版本再动手。3. 把行情、组合计算、微信推送封装成 MCP Server3.1 MCP Server 的最小实现三个工具函数MCP Server 的核心是暴露工具。我用 Python 的 mcp 库写一个最小版本包含三个工具get_market_data拉取行情calc_portfolio计算组合权重send_wechat_message发送微信模板消息。每个工具用装饰器注册参数用 Pydantic 模型定义这样 Dify 侧调用时能自动拿到参数 schema。# server.py from mcp.server.fastmcp import FastMCP from pydantic import BaseModel import requests import time mcp FastMCP(finance-assistant) class MarketQuery(BaseModel): symbols: list[str] period: str 1d class PortfolioInput(BaseModel): symbols: list[str] weights: list[float] capital: float class WeChatMessage(BaseModel): openid: str template_id: str data: dict mcp.tool() def get_market_data(query: MarketQuery) - dict: 拉取指定标的的行情数据 # 这里替换成你实际使用的行情源 result {} for sym in query.symbols: result[sym] {price: 100.0, change_pct: 0.5} return result mcp.tool() def calc_portfolio(inp: PortfolioInput) - dict: 按权重计算组合预期收益和波动 total sum(inp.weights) if abs(total - 1.0) 1e-6: return {error: weights must sum to 1} expected sum(w * 0.05 for w in inp.weights) return {expected_return: expected, capital: inp.capital} mcp.tool() def send_wechat_message(msg: WeChatMessage) - dict: 发送微信模板消息 token get_access_token() url fhttps://api.weixin.qq.com/cgi-bin/message/template/send?access_token{token} payload { touser: msg.openid, template_id: msg.template_id, data: msg.data } resp requests.post(url, jsonpayload, timeout5) return resp.json() def get_access_token() - str: # 实际项目里要做缓存这里简化 appid os.environ[WECHAT_APPID] secret os.environ[WECHAT_SECRET] url fhttps://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credentialappid{appid}secret{secret} return requests.get(url, timeout5).json()[access_token] if __name__ __main__: mcp.run(transportsse, host0.0.0.0, port8765)逻辑说明FastMCP自动把函数签名转成 MCP 工具定义Dify 侧连接后能看到get_market_data、calc_portfolio、send_wechat_message三个工具。get_market_data里我用了占位数据实际要接你的行情源注意加超时和异常捕获否则行情源抖动会拖垮整个工作流。参数说明symbols是标的代码列表period控制周期weights必须归一化我在函数里做了校验不满足直接返回 errorDify 侧可以根据这个分支走兜底话术openid是微信用户标识template_id是模板消息 IDdata是模板占位符内容。3.2 在 Dify 工作流里挂载 MCP 工具并做变量赋值Dify 工作流里先加一个“工具调用”节点选择 MCP 类型填入 MCP Server 地址。连接成功后节点里会出现三个工具。我一般把get_market_data放在工作流前段calc_portfolio放中段send_wechat_message放末段。中间用“变量赋值”节点把上一步的输出映射到下一步的输入。# Dify 工作流关键节点配置示意非完整 YAML仅说明字段 nodes: - id: start type: start variables: - name: customer_openid type: string - name: risk_level type: string - id: fetch_market type: tool provider: mcp tool: get_market_data inputs: symbols: [000001, 000300, 511880] period: 1d outputs: - name: market_data - id: calc type: tool provider: mcp tool: calc_portfolio inputs: symbols: [000001, 000300, 511880] weights: [0.4, 0.4, 0.2] capital: 100000 outputs: - name: portfolio_result - id: llm_generate type: llm prompt: | 根据以下行情和组合计算结果生成一段适合微信推送的理财建议 行情{{market_data}} 组合{{portfolio_result}} 客户风险等级{{risk_level}} - id: send type: tool provider: mcp tool: send_wechat_message inputs: openid: {{customer_openid}} template_id: your_template_id data: first: 今日组合建议 keyword1: {{portfolio_result.expected_return}} remark: {{llm_generate.text}}逻辑说明fetch_market和calc两个工具节点的输出通过变量名传给 LLM 节点LLM 生成话术后再传给send节点。risk_level从 start 节点传入可以在 LLM prompt 里做条件话术比如低风险客户只推货币基金建议。参数说明weights我写死在配置里实际项目应该根据客户风险等级动态计算可以在前面加一个代码节点生成权重数组。template_id要换成你微信公众平台里实际创建的模板 IDdata里的字段名必须和模板占位符完全一致否则微信侧会报 47003 错误。注意Dify 工作流里变量引用用{{}}但 MCP 工具输入如果是数组或对象要确认 Dify 版本是否支持直接传 JSON部分版本需要先序列化成字符串再在 MCP Server 里反序列化。4. 微信端推送链路的避坑与排查4.1 现象Dify 调用 MCP 工具超时工作流卡在工具节点原因MCP Server 默认没有设置请求超时Dify 侧工具节点默认超时可能是 30 秒但行情源响应慢或者微信接口限流时MCP Server 内部 requests 调用没有超时导致整个链路挂住。解决在 MCP Server 的每个 requests 调用里显式加timeout5并且在 Dify 工具节点配置里把超时调到 10 秒。如果行情源本身不稳定加一层本地缓存比如用functools.lru_cache缓存 60 秒内的行情结果。4.2 现象微信模板消息发送成功但用户没收到原因微信模板消息有“防骚扰”限制同一用户短时间内收到多条会静默丢弃或者用户已经取关。另外openid如果来自不同公众号也会发送失败。解决在 MCP Server 里记录每个 openid 的发送时间做频率控制比如同一用户 24 小时内最多推 3 条。发送前先调微信的“获取用户信息”接口确认关注状态取关的直接跳过。openid必须和template_id属于同一个公众号。4.3 现象Dify 工作流里 LLM 生成的话术包含未替换的变量原因LLM 节点的 prompt 里用了{{market_data}}但上一步工具节点的输出变量名不是market_data或者输出是嵌套对象LLM 拿到的是[object Object]。解决在 Dify 的变量赋值节点里把工具输出显式映射成扁平字符串。比如market_data是 dict用代码节点转成 JSON 字符串再传给 LLM。我一般会在 LLM prompt 里加一句“如果变量为空输出默认话术”避免空值导致生成中断。4.4 现象Docker 网络里 Dify 容器访问 MCP Server 报 connection refused原因MCP Server 容器启动时没有加入 Dify 的网络或者 MCP Server 监听的是 127.0.0.1 而不是 0.0.0.0。解决docker run时加--network dify_defaultMCP Server 代码里mcp.run(host0.0.0.0)。用docker exec -it dify-api curl http://mcp-finance:8765/sse在 Dify 容器内测试连通性能通再配到工作流里。4.5 现象Dify 升级后 MCP 连接配置丢失原因Dify 社区版升级时数据库迁移可能重置部分插件配置MCP 连接信息如果存在环境变量里而不是数据库里升级后需要重新配。解决把 MCP Server 地址和工具名写进 Dify 的环境变量文件.env升级后检查docker compose config确认变量还在。更稳妥的做法是 MCP Server 用固定域名或固定容器名Dify 侧配置一次就不用改。5. 让推送策略可验证回测与灰度发布的具体做法5.1 用历史数据回测组合策略再上线直接让 LLM 生成策略就推给客户风险太大。我一般会在 MCP Server 里加一个backtest_portfolio工具输入历史区间和权重输出累计收益和最大回撤。Dify 工作流在正式推送前先调这个工具跑一遍最近 30 个交易日如果最大回撤超过客户风险等级对应的阈值就降级成货币基金建议。mcp.tool() def backtest_portfolio(inp: PortfolioInput, start: str, end: str) - dict: 用历史数据回测组合表现 # 拉取历史净值计算累计收益和最大回撤 nav_series fetch_history(inp.symbols, start, end) portfolio_nav sum(w * nav for w, nav in zip(inp.weights, nav_series)) cum_return portfolio_nav[-1] / portfolio_nav[0] - 1 peak max(portfolio_nav) max_drawdown min(nav / peak - 1 for nav in portfolio_nav) return {cum_return: cum_return, max_drawdown: max_drawdown}逻辑说明fetch_history是你接的历史行情函数返回每个标的的净值序列。组合净值按权重加权再算累计收益和最大回撤。Dify 侧拿到max_drawdown后用条件分支判断是否超过阈值。参数说明start和end用YYYY-MM-DD格式建议至少取 30 个交易日样本太少回撤指标不可信。阈值我一般设低风险客户 -3%中风险 -8%高风险 -15%超过就触发降级。5.2 灰度发布先推给自己再推给客户新策略上线前我会在 Dify 工作流里加一个“测试模式”开关。开启时send_wechat_message的openid固定成我自己的模板消息里加“[测试]”前缀。跑一周确认话术、数据、送达都正常后再按客户标签分批放开。Dify 的变量赋值节点可以读一个test_mode变量从 start 节点传入这样不用改工作流结构。灰度期间重点看三个指标MCP 工具调用成功率、微信模板消息送达率、LLM 生成话术的变量替换完整率。成功率低于 95% 就回滚别硬撑。我自己的习惯是每次改完工作流先用 curl 直接调 MCP Server 的三个工具各一次确认底层没问题再去 Dify 里跑完整链路。这样排查问题时能快速定位是 MCP 层还是 Dify 层。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
KCW 12.24作业信息拆解:从一行简报到可执行计划 1. 从一行简报到一份可执行计划:KCW 12.24作业的信息拆解实战我接手过太多类似"XX项目 XX日作业"这样的任务条目。乍一看,这行字几乎等于什么都没说——没有需求文档、没有验收标准、没有目标定义,甚至没有明确的交付物清单。但正是… · 2026/9/26 17:22:10
学生信息管理系统实战:Python+MySQL+tkinter完整设计与实现 1. 项目整体设计:学生信息管理系统到底该怎么拆1.1 先做需求分析,而不是先写代码我经常帮同学修改学生信息管理系统的课程设计代码,发现最高频的问题不是“不会写代码”,而是“拿到题目就直接打开IDE开写”。最后交上来的东西要么… · 2026/9/26 17:22:10
Selenium环境配置安装全指南:从Python到ChromeDriver一次搞定 先聊个现象:很多人第一次装 Selenium,卡住的往往不是 Selenium 本身,而是 Python、pip、浏览器驱动、环境变量这一连串“周边配置”。明明照着教程敲了pip install selenium,一运行却报一堆错,什么ModuleNotFoundError… · 2026/9/26 17:22:10
Java大富翁源码:面向对象设计与Swing实战工程 简介:这是一份面向Java初学者与移动开发入门者的经典游戏项目源码,完整实现J2ME平台下的大富翁手机游戏逻辑,涵盖地图渲染、角色移动、地产买卖、骰子判定等核心机制。资源包共89个文件,含16个Java源文件(含详细中文注… · 2026/9/26 17:53:58
全新UI简易漂流瓶系统源码:PHP+Vue+Element UI实战解析 前阵子收到一个很有意思的需求:给一个内部兴趣社群做一个独立的漂流瓶模块。用户丢个瓶子到海里,过一会儿捞一个别人的瓶子起来,看完之后可以回复,也可以让它继续漂。功能听起来很简单,但产品提了一个额外要求… · 2026/9/26 17:53:52
JavaScript Object 全解:从属性描述符到原型链,彻底搞懂对象方法 你列这个标题的时候,大概率以为把这些 API 背下来就够了:Object.keys、Object.assign、Object.entries……但真到排查问题的时候会发现,卡你的往往不是“这个方法怎么用”,而是“这个属性为什么没被拷贝过来”“为什么 freeze 之后… · 2026/9/26 17:53:52
2026推理引擎产业全景:从选型到优化的实战指南 先说个背景。我在2025年下半年参与了好几个推理基础设施相关的项目,从几十人的创业团队到几千台GPU的集群都接触了一遍。印象最深的一件事是:几乎所有团队在聊到下一阶段规划时,都默认“推理优化”已经不是加分项,而是及格线。到了… · 2026/9/26 17:53:52
Python小数点精度问题全解析:7个实战技巧与避坑指南 说个可能让你意外的事实:我接手过的Python项目里,因为小数点精度翻车的概率,比内存泄漏、死循环这些“大问题”高得多。尤其是订单、折扣、评分、费率这类需求,0.1 0.2不等于0.3的讨论一出现,轻则报表对不上ÿ… · 2026/9/26 17:53:52
TensorFlow与MATLAB协同实战:环境配置、模型桥接与工程避坑 为什么非要折腾“协同使用”这件事?我这些年接过不少项目,数据预处理、信号分析、控制仿真全部历史沉淀在 MATLAB 里,结果一个深度学习需求砸过来——LSTM 不收敛、Transformer 想试没把握、预训练模型一堆开源权重全是 TensorFlow 的。反过来… · 2026/9/26 17:53:52
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46