尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Dify + ECharts 实战:自然语言一键生成饼状图

Dify + ECharts 实战:自然语言一键生成饼状图 之前在业务迭代中遇到一个高频需求用户输入一段业务数据系统自动生成可视化图表。常见的做法是前端先约定好数据结构后端写死几种图表模板一旦遇到字段变化就要改代码整个过程并不“智能”。后来我尝试用 Dify 搭建一个“自然语言生成饼状图”的应用把大语言模型、数据解析、ECharts 配置生成串成一条自动化链路效果非常直接。本文整理的就是这套从零开始的完整实操方案覆盖思路、提示词、工作流编排、代码节点和常见报错处理适合刚接触 Dify 的开发者也适合想快速落地 AI 可视化方案的后端工程师参考。1. Dify 能做什么为什么用它生成饼状图1.1 Dify 是什么Dify 是一个开源的大语言模型应用开发平台主打“LLM App 的可视化编排”。你可以在上面创建对话应用、文本生成应用也可以把多个节点串成工作流节点之间用变量传递数据每个节点可以是大模型调用、代码执行、条件分支、HTTP 请求等。简单理解Dify 把“调用大模型”这件事做成了可视化积木。以前我们要写一套后端服务通过 LangChain 或者直接调 OpenAI SDK 来组织 Prompt、管理上下文、解析输出现在在 Dify 的界面里就能完成大部分工作。它同时提供了应用 API 和 WebApp 页面适合快速验证产品原型也能接进正式业务系统。用 Dify 生成饼状图并不是让 Dify 直接“画图”。更准确的链路是用户输入数据描述 → 大模型理解并整理成结构化数据 → 代码节点把数据转换成 ECharts 可识别的 option JSON → 前端或 WebApp 完成渲染。这样拆开之后Dify 承担的是“数据处理和图表配置生成”这个 AI 能力层。1.2 用 Dify 生成饼状图的两种思路第一种思路是“代码生成方案”。让大模型直接生成一段 Python 绘图代码例如基于 matplotlib 或 pyecharts 的代码然后放到 Python 执行环境里运行运行结果输出为图片或 HTML。优点是定制性强缺点是代码执行环境需要额外搭建并且大模型生成的代码不一定一次通过需要不断调试。第二种思路是“配置生成方案”。让大模型输出结构化的图表配置例如 ECharts 的 option JSON然后前端直接加载这个配置完成渲染。这种方式更稳定因为 ECharts 是纯前端渲染不需要在服务端跑 Python 绘图代码而且大模型生成 JSON 比生成完整可运行代码的成功率高。本文采用第二种思路。Dify 负责生成 ECharts option 配置最后用一个轻量展示页面把饼状图画出来。1.3 本文实战能获得什么读完这篇文章你会掌握下面这些能力在 Dify 中创建“工作流类型”应用。合理编写 Prompt让大模型输出固定 JSON 结构。使用 Dify 的代码节点解析大模型结果。把最终生成的 ECharts option 通过 WebApp 或 API 返回给前端。遇到 JSON 解析失败、字段缺失、渲染空白等问题时的排查思路。整个过程不依赖复杂的前端工程也不需要自建大模型服务。2. 环境准备与版本说明2.1 Dify 部署方式选型Dify 支持云端版和社区版。云端版直接注册账号就能用适合快速体验社区版需要自己部署数据可控适合企业内部项目。社区版最常见的部署方式是通过 Docker Compose 启动。它依赖以下环境组件作用Docker容器运行环境Docker Compose编排 Dify 多个服务浏览器访问 Dify 控制台大模型 API Key驱动 LLM 节点例如 OpenAI、DeepSeek、通义千问等版本方面Dify 迭代速度比较快不同版本的界面细节可能会有差异但核心编排概念基本一致。本文示例基于社区版 Docker Compose 部署思路版本需要根据你的项目实际情况调整。2.2 启动 Dify 社区版首先你需要有一台安装了 Docker 和 Docker Compose 的服务器或本机。拉取 Dify 源码仓库中的 docker 目录在目录内执行启动命令git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env docker compose up -d启动过程会拉取多个镜像包括 API 服务、Worker、PostgreSQL、Redis、Nginx、Sandbox 等。看到所有容器状态为 healthy 或 running 后就可以通过浏览器访问 Dify 控制台。docker compose ps初始化时Dify 默认会监听本机 80 端口或 443 端口。实际端口需要查看.env中NGINX_PORT配置。访问地址一般是http://localhost/install按页面提示创建管理员账号。这里需要提醒一点大模型 API Key 并不是 Dify 自带的需要你提前准备好。在 Dify 控制台“设置 → 模型供应商”里添加 key 之后创建应用时才能选择模型。2.3 创建 Dify 应用登录 Dify 控制台后点击“创建应用”选择“工作流”类型。工作流应用适合“输入一批参数 → 经过多个节点处理 → 输出结果”这种场景正好符合生成图表配置的需求。创建完成后你会进入工作流编排画布。画布左侧是节点列表中间是画布右侧是节点配置面板。这是后面实战的主要操作区域。3. 核心概念Dify 应用编排方式3.1 应用类型与工作流节点Dify 的应用类型主要分为三类聊天助手面向多轮对话场景适合客服、问答类应用。文本生成单次输入输出适合摘要、翻译、文案生成。工作流把多个节点串起来适合有明确业务逻辑的自动化任务。饼状图生成属于典型的“有明确处理流程”的任务所以工作流是最优选择。工作流里常用的节点包括开始节点定义用户输入变量。LLM 节点调用大模型输入 Prompt 和变量输出模型结果。代码节点运行 Python 代码处理变量。条件分支节点根据条件走不同分支。HTTP 请求节点调用外部接口。结束节点定义最终输出内容。3.2 提示词设计的基本原理在 Dify 中LLM 节点的效果很大程度上取决于提示词。写提示词的通用原则是描述清楚角色和任务。给出输入数据格式。明确输出格式。提供示例。对于饼状图场景提示词要解决一个核心问题把用户输入转换成“分类名 数值”的列表。例如用户输入“一季度销售额手机 100 万电脑 80 万耳机 30 万”我们需要模型输出[ {name: 手机, value: 100}, {name: 电脑, value: 80}, {name: 耳机, value: 30} ]为了让模型稳定输出这个结构提示词里一定要写清楚“只能输出 JSON不要输出多余文字”并给出 JSON 示例。3.3 变量与代码节点工作流的开始节点可以为接收用户输入定义变量。例如定义一个input_data变量类型是“段落”用户在发起请求时传入原始数据。代码节点则可以接收上游 LLM 节点的输出变量然后执行 Python 代码把结果返回给下游。需要注意的是Dify 代码节点目前主要支持 Python它的入口是一个main函数函数接收参数返回值需要是 dict 类型。具体支持的参数类型和函数签名会随着版本迭代发生变化建议以官方文档为准。下面给出通用写法示例def main(input_json: str) - dict: # input_json 是上游传过来的原始 JSON 字符串 # 处理逻辑 return {result: processed_data}代码节点的好处是即使大模型偶尔输出格式不完美我们也可以在代码里做容错和清洗保证最终给前端的配置是合法 JSON。3.4 为什么用 ECharts 而不是直接生成图片很多初学者会希望 Dify 直接返回一张饼状图图片。但“生成图片”在工程上成本更高因为需要额外部署绘图环境。大模型生成图片的成功率不稳定。后续修改样式、交互不灵活。ECharts 是前端图表库它的配置是纯 JSON。Dify 生成 JSON前端渲染 JSON天然解耦。而且 ECharts 的饼状图配置结构清晰很容易映射到“分类名 数值”的数据结构。这也是本文选择该方案的原因。4. 完整实战Dify 一键生成饼状图4.1 整体流程设计整个工作流从用户输入到前端展示核心流程如下用户输入一段自然语言描述。开始节点接收输入变量。LLM 节点提取数据输出固定 JSON 数组。代码节点解析 JSON并组装成 ECharts 饼状图 option。结束节点返回 option 给前端。这样设计的好处是“LLM 只负责理解数据代码负责生成配置”各节点职责单一。4.2 创建工作流并配置开始节点在 Dify 中创建“工作流”应用命名为“饼状图生成助手”。进入编排画布后点击“开始”节点添加输入变量变量名input_data类型段落描述用户输入的数据描述例如“各产品销量A 产品 120B 产品 80”这里的变量名会在后续节点中被引用例如{{input_data}}。4.3 添加 LLM 节点并编写提示词从左侧节点列表拖入一个“LLM”节点连接到开始节点之后。LLM 节点的系统提示词System Prompt里我们要明确告诉模型任务和输出格式。下面是一份可以直接使用的提示词模板可以根据自己的业务调整你是一个数据整理助手。用户会输入一段包含分类统计数据的描述你需要提取出“分类名称”和“数值”并输出 JSON 数组。 要求 1. 只输出 JSON不要输出任何解释文字。 2. JSON 格式为[{name: 分类名, value: 数值}] 3. value 必须是数字不要带单位。 4. 如果用户输入中没有明确数值只保留明确的分类和数值。 示例输入 一季度各品类销量手机 100 台电脑 80 台耳机 30 台 示例输出 [{name: 手机, value: 100}, {name: 电脑, value: 80}, {name: 耳机, value: 30}] 用户输入 {{input_data}}在 LLM 节点的用户提示词User Prompt区域填入上面模板模型选择你要用的 LLM。尽量选择支持 JSON 输出稳定的模型例如 GPT-4o、DeepSeek-V3 或者国内云厂商的通用模型。不同模型对“只输出 JSON”的遵循程度不同如果遇到输出带解释文字的情况可以通过代码节点做兼容。4.4 添加代码节点生成 ECharts 配置拖入一个“代码节点”连接到 LLM 节点之后。代码节点的作用有两个处理 LLM 输出的字符串提取 JSON 数组。把数组映射为 ECharts 饼状图的 option。由于 Dify 的代码节点通常以 Python 语法实现下面给出一份通用代码示例import json def main(llm_output: str) - dict: # 1. 清理 LLM 输出去掉可能的 markdown 代码块标记 llm_output llm_output.strip() if llm_output.startswith(): llm_output llm_output.strip() # 去掉可能的 json 标记 if llm_output.startswith(json): llm_output llm_output[4:] llm_output llm_output.strip() # 2. 尝试解析 JSON try: data json.loads(llm_output) except json.JSONDecodeError: # 兼容模型输出前后有解释文字的情况尝试截取第一个 [ 到最后一个 ] start llm_output.find([) end llm_output.rfind(]) if start ! -1 and end ! -1: json_str llm_output[start:end 1] data json.loads(json_str) else: raise ValueError(无法从 LLM 输出中解析出 JSON 数组) # 3. 数据结构校验与清洗 cleaned [] for item in data: name str(item.get(name, )).strip() try: value float(item.get(value, 0)) except (TypeError, ValueError): value 0 if name: cleaned.append({name: name, value: value}) # 4. 构建 ECharts 饼状图 option option { title: { text: 数据分布饼状图, left: center }, tooltip: { trigger: item, formatter: {b}: {c} ({d}%) }, legend: { orient: vertical, left: left }, series: [ { name: 数据分布, type: pie, radius: 60%, data: cleaned, emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: rgba(0, 0, 0, 0.5) } } } ] } return {chart_option: option}这份代码的核心思路是“容错解析 数据清洗 配置组装”。尤其要注意第 2 步大模型输出经常会出现前后带解释文字、Markdown 代码块标记等情况代码里做一层兜底解析可以显著提高成功率。4.5 配置结束节点拖入“结束节点”连接到代码节点之后。结束节点里添加一个输出变量类型选择“JSON”值为代码节点的输出变量chart_option并命名为result。这样工作流运行结束后会直接返回一个 ECharts option JSON。4.6 运行与验证在工作流编辑页右上角点击“运行”输入测试数据各产品线收入企业服务 560 万智能硬件 320 万订阅制软件 180 万技术咨询 90 万运行结束之后结束节点会输出类似下面的 JSON{ result: { title: { text: 数据分布饼状图, left: center }, tooltip: { trigger: item, formatter: {b}: {c} ({d}%) }, legend: { orient: vertical, left: left }, series: [ { name: 数据分布, type: pie, radius: 60%, data: [ {name: 企业服务, value: 560}, {name: 智能硬件, value: 320}, {name: 订阅制软件, value: 180}, {name: 技术咨询, value: 90} ] } ] } }拿到这个 JSON就等于拿到了饼状图的所有配置数据。接下来要做的就是把 JSON 交给前端渲染。4.7 使用 WebApp 或 API 对接前端Dify 工作流应用发布后可以提供 API 调用地址。如果要集成到自己的系统里可以使用 Dify 提供的 API 发送请求请求体示例{ inputs: { input_data: 各产品线收入企业服务 560 万智能硬件 320 万订阅制软件 180 万 }, response_mode: blocking, user: demo-user }接口地址在应用“访问 API”页面可以查看需要在请求头中携带 API Key。拿到返回值后前端用 ECharts 渲染即可。下面是一个极简的 HTML 展示页面用来验证效果。先把上面生成的 option 粘贴到chartOption变量里用浏览器打开即可。!DOCTYPE html html langzh-CN head meta charsetUTF-8 titlePie Chart/title script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script /head body div idchart stylewidth: 800px; height: 500px;/div script const chart echarts.init(document.getElementById(chart)); const chartOption { title: { text: 数据分布饼状图, left: center }, tooltip: { trigger: item, formatter: {b}: {c} ({d}%) }, legend: { orient: vertical, left: left }, series: [{ name: 数据分布, type: pie, radius: 60%, data: [ { name: 企业服务, value: 560 }, { name: 智能硬件, value: 320 }, { name: 订阅制软件, value: 180 } ] }] }; chart.setOption(chartOption); /script /body /html如果页面正常显示饼状图就说明从 Dify 工作流生成的配置可以顺畅衔接前端渲染。实际项目里前端只需要把 Dify API 返回的result字段直接传给chart.setOption()。5. 常见问题与排查5.1 LLM 输出不是合法 JSON问题现象常见原因解决思路代码节点报 JSONDecodeError模型输出了解释文字、Markdown 代码块标记或多余引号在代码节点中做字符串清理和首尾截取输出字段缺失提示词未明确字段名在提示词中增加严格示例并要求“不要添加额外字段”value 含单位提示词未强调数值类型在提示词中明确“value 必须是数字不要带单位”排查时建议先在 LLM 节点单独运行查看模型原始输出。只有先看原始输出才能判断是提示词问题还是代码解析问题。5.2 数据量太大超出模型上下文如果用户输入的数据分类特别多例如 50 个品类大模型可能会遗漏部分分类或者生成结果截断。这时有两种处理思路在进入 Dify 前由业务系统先把数据聚合好只传需要展示的分类。提高模型的 max_tokens 上限给足输出空间。在前端对数据做二次兜底例如按“其他”归类数量过小的分类。从工程实践来说推荐在业务层先做数据清洗Dify 只承担格式转换不要让它处理超大文本。5.3 图表渲染空白问题现象常见原因解决思路页面空白option 中 data 为空数组检查代码节点中 cleaned 是否为空确认 LLM 是否提取到数据图例显示但无饼图series.type 不是 pie检查代码节点中的 type 字段中文乱码HTML 未设置 UTF-8在 HTML head 中声明meta charsetUTF-8ECharts 未加载CDN 地址不可达换成本地 echarts.min.js 文件渲染空白大半是数据层问题建议先在浏览器控制台打印一遍chartOption再确认数据是否完整。5.4 代码节点运行超时Dify 的代码节点有执行时间限制如果处理逻辑太复杂或者 JSON 字符串过大可能超时。处理方式简化代码逻辑不要在代码节点里做复杂循环计算。把清洗逻辑尽量前置到业务系统。如果必须处理大批量数据考虑用 HTTP 请求节点把数据抛给自建服务处理。6. 最佳实践与工程建议6.1 提示词工程建议生成图表配置的场景提示词要追求“确定性”不要追求“创造性”。建议做到让 LLM 只做数据提取不做额外总结。输出格式用 JSON Schema 描述清楚。每次迭代修改提示词后保留一份历史版本方便对比效果。在提示词中用“示例输入 → 示例输出”比长篇解释更有效。可以建立一个提示词版本管理目录把不同业务场景的提示词模板统一维护。后续如果发现模型效果不稳定优先检查是不是提示词被改动了。6.2 数据聚合与预处理饼状图适合展示“分类占比”不适合展示过于细碎的数据。如果原始数据有 100 个分类建议先按业务规则聚合例如只展示 Top 10其余归为“其他”。这一步可以在上游业务系统完成也可以在 Dify 代码节点里完成。在代码节点里做聚合时可以用下面的逻辑# 按 value 降序排序 cleaned.sort(keylambda x: x[value], reverseTrue) # 只保留前 8 个 top cleaned[:8] # 剩余归为其他 rest cleaned[8:] other_value sum(item[value] for item in rest) if other_value 0: top.append({name: 其他, value: round(other_value, 2)})这样的好处是图表更清晰也不会因为分类太多导致提示词截断。6.3 安全性在 Dify 应用中如果允许用户自由输入数据描述需要注意两类安全风险Prompt 注入用户可能在输入中夹带“忽略之前的指令”等恶意内容诱导模型输出异常结果。资源消耗恶意用户通过大量调用消耗 API 额度。应对方式在业务层面对输入长度做限制。对调用 API 的用户做身份认证和频率限制。对 Dify 应用的 API Key 做最小权限隔离不同业务使用不同 Key。不要在前端暴露 Dify API Key应通过后端转发请求。6.4 异常兜底与降级方案完全依赖大模型生成 JSON在极端场景下仍可能失败。生产环境建议增加兜底逻辑如果 LLM 节点解析失败尝试让模型重新生成一次。如果重试仍然失败返回一个固定的“数据解析失败”页面。在接口层设置超时时间避免前端长时间等待。记录每次失败的原始输入和模型输出用于持续优化提示词。6.5 性能与成本优化生成饼状图这类任务对响应时间要求一般不高但成本优化还是值得关注优先选择便宜的模型做数据提取任务不需要用最强模型。如果数据格式固定可以在代码节点直接解析跳过 LLM。对相同输入做缓存避免重复调用模型。在低峰期提前生成一次配置避免用户等待。这些优化顺序从“减少不必要调用”到“控制模型成本”工程上都能直接落地。6.6 日志与监控Dify 应用上线后建议把每次调用的输入、输出、耗时、失败原因记录下来。日志字段可以参考时间戳 用户标识 输入数据 模型输出 最终 chart_option 是否成功 失败原因 耗时有了这些日志后续排查问题和优化提示词会有非常明确的方向。7. 总结与学习路线通过本文的实战你应该已经掌握了 Dify 工作流的核心编排思路也理解了“大模型生成结构化配置前端负责渲染”的通用设计模式。整个过程可以概括为五步Dify 接收输入、LLM 提取数据、代码节点清洗数据、组装 ECharts option、前端渲染饼状图。这套思路不仅适用于饼状图也可以扩展到柱状图、折线图、仪表盘配置生成等场景。如果想继续深入建议从这几个方向入手熟悉 Dify 的更多节点类型例如条件分支、知识库检索、HTTP 请求尝试搭建更复杂的业务工作流。深入学习 ECharts 的配置语法了解不同图表类型对数据格式的要求。研究提示词工程特别是 Few-shot 示例和 JSON Schema 约束方法提高大模型输出的稳定性。尝试把 Dify 工作流集成到现有业务系统通过 API 方式发布并完善监控、限流和降级机制。实际项目中最值得优先关注的是“异常兜底”和“数据清洗”这两块。模型能力再强也无法保证 100% 输出合法 JSON代码节点里的容错解析是最后一道防线。把这层逻辑处理好Dify 生成图表的整体体验会稳定很多。你可以打开 Dify创建一个工作流应用按本文步骤先跑通基础版再根据自己的业务调整提示词和图表样式。亲手试一遍之后你会发现“用 AI 一键生成饼状图”并不是什么复杂的事。
返回列表