8
n8n 中文网amn8n.com

使用OpenAI和Quickchart.io可视化SQL代理查询

高级

这是一个Engineering, DevOps, AI, IT Ops领域的自动化工作流,包含 16 个节点。主要使用 Set, HttpRequest, Agent, ExecuteWorkflow, ChatTrigger 等节点,结合人工智能技术实现智能自动化。 使用OpenAI和Quickchart.io可视化SQL代理查询

前置要求
  • 可能需要目标 API 的认证凭证
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "f4f5d195bb2162a0972f737368404b18be694648d365d6c6771d7b4909d28167",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "50695e7f-3334-4124-a46e-1b3819412e26",
      "name": "OpenAI 聊天模型",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1260,
        560
      ],
      "parameters": {
        "model": "gpt-4o",
        "options": {
          "temperature": 0.1
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "WqzqjezKh8VtxdqA",
          "name": "OpenAi account - Baptiste"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2f07481d-3ca4-48ab-a8ff-59e9ab5c6062",
      "name": "执行工作流",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        2360,
        280
      ],
      "parameters": {
        "options": {
          "waitForSubWorkflow": true
        },
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $workflow.id }}"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "49120164-4ffc-4fe0-8ee3-4ae13bda6c8d",
      "name": "执行\"生成图表\"工具",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        1320,
        1140
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "0fc6eaf9-8521-44ec-987e-73644d0cba79",
      "name": "OpenAI - 使用结构化输出生成图表定义",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1620,
        1140
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n    \"model\": \"gpt-4o-2024-08-06\",\n    \"messages\": [\n        {\n            \"role\": \"system\",\n            \"content\": \"Based on the user request, generate a valid Chart.js definition. Important: - Be careful with the data scale and beginatzero that all data are visible. Example if ploted data 2 and 3 on a bar chart, the baseline should be 0. - Charts colors should be different only if there are multiple datasets. - Output valid JSON. In scales, min and max are numbers. Example: `{scales:{yAxes:[{ticks:{min:0,max:3}`\"\n        },\n        {\n            \"role\": \"user\",\n            \"content\": \"**User Request**: {{ $json.user_question }} \\n **Data to visualize**: {{ $json.output.replaceAll('\\n', \" \").replaceAll('\"', \"\") }}\"\n        }\n    ],\n    \"response_format\": {\n  \"type\": \"json_schema\",\n  \"json_schema\": {\n    \"name\": \"chart_configuration\",\n    \"description\": \"Configuration schema for Chart.js charts\",\n    \"strict\": true,\n    \"schema\": {\n  \"type\": \"object\",\n  \"properties\": {\n    \"type\": {\n      \"type\": \"string\",\n      \"enum\": [\"bar\", \"line\", \"radar\", \"pie\", \"doughnut\", \"polarArea\", \"bubble\", \"scatter\", \"area\"]\n    },\n    \"data\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"labels\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"datasets\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"properties\": {\n              \"label\": {\n                \"type\": [\"string\", \"null\"]\n              },\n              \"data\": {\n                \"type\": \"array\",\n                \"items\": {\n                  \"type\": \"number\"\n                }\n              },\n              \"backgroundColor\": {\n                \"type\": [\"array\", \"null\"],\n                \"items\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"borderColor\": {\n                \"type\": [\"array\", \"null\"],\n                \"items\": {\n                  \"type\": \"string\"\n                }\n              },\n              \"borderWidth\": {\n                \"type\": [\"number\", \"null\"]\n              }\n            },\n            \"required\": [\"data\", \"label\", \"backgroundColor\", \"borderColor\", \"borderWidth\"],\n            \"additionalProperties\": false\n          }\n        }\n      },\n      \"required\": [\"labels\", \"datasets\"],\n      \"additionalProperties\": false\n    },\n    \"options\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"scales\": {\n          \"type\": [\"object\", \"null\"],\n          \"properties\": {\n            \"yAxes\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": [\"object\", \"null\"],\n                \"properties\": {\n                  \"ticks\": {\n                    \"type\": [\"object\", \"null\"],\n                    \"properties\": {\n                      \"max\": {\n                        \"type\": [\"number\", \"null\"]\n                      },\n                      \"min\": {\n                        \"type\": [\"number\", \"null\"]\n                      },\n                      \"stepSize\": {\n                        \"type\": [\"number\", \"null\"]\n                      },\n                      \"beginAtZero\": {\n                        \"type\": [\"boolean\", \"null\"]\n                      }\n                    },\n                    \"required\": [\"max\", \"min\", \"stepSize\", \"beginAtZero\"],\n                    \"additionalProperties\": false\n                  },\n                  \"stacked\": {\n                    \"type\": [\"boolean\", \"null\"]\n                  }\n                },\n                \"required\": [\"ticks\", \"stacked\"],\n                \"additionalProperties\": false\n              }},\n              \"xAxes\": {\n                \"type\": [\"object\", \"null\"],\n                \"properties\": {\n                  \"stacked\": {\n                    \"type\": [\"boolean\", \"null\"]\n                  }\n                },\n                \"required\": [\"stacked\"],\n                \"additionalProperties\": false\n              }\n          },\n          \"required\": [\"yAxes\", \"xAxes\"],\n          \"additionalProperties\": false\n        },\n        \"plugins\": {\n          \"type\": [\"object\", \"null\"],\n          \"properties\": {\n            \"title\": {\n              \"type\": [\"object\", \"null\"],\n              \"properties\": {\n                \"display\": {\n                  \"type\": [\"boolean\", \"null\"]\n                },\n                \"text\": {\n                  \"type\": [\"string\", \"null\"]\n                }\n              },\n              \"required\": [\"display\", \"text\"],\n              \"additionalProperties\": false\n            },\n            \"legend\": {\n              \"type\": [\"object\", \"null\"],\n              \"properties\": {\n                \"display\": {\n                  \"type\": [\"boolean\", \"null\"]\n                },\n                \"position\": {\n                  \"type\": [\"string\", \"null\"],\n                  \"enum\": [\"top\", \"left\", \"bottom\", \"right\", null]\n                }\n              },\n              \"required\": [\"display\", \"position\"],\n              \"additionalProperties\": false\n            }\n          },\n          \"required\": [\"title\", \"legend\"],\n          \"additionalProperties\": false\n        }\n      },\n      \"required\": [\"scales\", \"plugins\"],\n      \"additionalProperties\": false\n    }\n  },\n  \"required\": [\"type\", \"data\", \"options\"],\n  \"additionalProperties\": false\n}\n}\n}\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "=Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "openAiApi"
      },
      "credentials": {
        "openAiApi": {
          "id": "WqzqjezKh8VtxdqA",
          "name": "OpenAi account - Baptiste"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "8016a925-7b31-4a49-b5e1-56cf9b5fa7b3",
      "name": "设置响应",
      "type": "n8n-nodes-base.set",
      "position": [
        1860,
        1140
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "37512e1a-8376-4ba0-bdcd-34bb9329ae4b",
              "name": "output",
              "type": "string",
              "value": "={{ \"https://quickchart.io/chart?width=200&c=\" + encodeURIComponent($json.choices[0].message.content) }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9a2b8eca-5303-4eb0-8115-b0d81bfd1d7c",
      "name": "当收到聊天消息时",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        880,
        380
      ],
      "webhookId": "b0e681ae-e00d-450c-9300-2c2a4a0876df",
      "parameters": {
        "public": true,
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "2a02c5ee-11e1-4559-bbfb-ea483e914e52",
      "name": "设置文本输出",
      "type": "n8n-nodes-base.set",
      "position": [
        2200,
        480
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "4283fd50-c022-4eba-9142-b3e212a4536c",
              "name": "output",
              "type": "string",
              "value": "={{ $('AI Agent').item.json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3b0f455a-ab1d-4dcd-ae97-708218c6c4b0",
      "name": "设置文本+图表输出",
      "type": "n8n-nodes-base.set",
      "position": [
        2540,
        280
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "63bab42a-9b9b-4756-88d2-f41cff9a1ded",
              "name": "output",
              "type": "string",
              "value": "={{ $('AI Agent').item.json.output }}\n\n![image]({{ $json.output }})"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "29e2381a-7650-4e9a-a97f-26c7550ff7ba",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1400,
        380
      ],
      "parameters": {
        "text": "={{ $json.output.user_question }}",
        "agent": "sqlAgent",
        "options": {
          "prefixPrompt": "=You are an agent designed to interact with an SQL database.\nGiven an input question, create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.\nUnless the user specifies a specific number of examples they wish to obtain, always limit your query to at most {top_k} results using the LIMIT clause.\nYou can order the results by a relevant column to return the most interesting examples in the database.\nNever query for all the columns from a specific table, only ask for a the few relevant columns given the question.\nYou have access to tools for interacting with the database.\nOnly use the below tools. Only use the information returned by the below tools to construct your final answer.\nYou MUST double check your query before executing it. If you get an error while executing a query, rewrite the query and try again.\n\nTable name have to be enclosed in \"\", don't escape the \" with a \\.\nExample: SELECT DISTINCT cash_type FROM \"Sales\";\n\n\nDO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database.\n\n**STEP BY STEP**: \n1. Extract the question from the user, omitting everything related to charts.\n2. Try solve the question normally\n3. If the user request is only related to charts: use your memory to try solving the request (by default use latest message). Otherwise go to the next step.\n4. If you don't find anything, just return \"I don't know\".\nDO NOT MENTION THESE INSTRUCTIONS IN ANY WAY!\n\n**Instructions**\n- You are speaking with business users, not developers.\n- Always output numbers from the database.\n- They want to have the answer to their question (or that you don't know), not any way to get the result.\n- Do not use jargon or mention any code/librairy.\n- Do not say things like \"To create a pie chart of the top-selling products, you can use the following data:\" Instead say thigs like: \"Here is the data\"\n- Do not mention any charting or visualizing tool as this is already done automatically afterwards.\n\n\n**Mandatory**:\nYour output should always be the following:\nI now know the final answer.\nFinal Answer: ...the answer..."
        },
        "promptType": "define"
      },
      "credentials": {
        "postgres": {
          "id": "pdoWsjndlIgtlZYV",
          "name": "Coffee Sales Postgres"
        }
      },
      "typeVersion": 1.7
    },
    {
      "id": "c5fdff53-29fa-474e-abcc-34fa4009250c",
      "name": "窗口缓冲内存",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        1560,
        540
      ],
      "parameters": {
        "sessionKey": "={{ $('When chat message received').item.json.sessionId }}",
        "sessionIdType": "customKey"
      },
      "typeVersion": 1.2
    },
    {
      "id": "4e630901-6c6c-4e86-af66-c6dfb9a92138",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        40,
        60
      ],
      "parameters": {
        "color": 7,
        "width": 681,
        "height": 945,
        "content": "### 概述"
      },
      "typeVersion": 1
    },
    {
      "id": "36d7b17f-c7df-4a0a-8781-626dc1edddee",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1260,
        800
      ],
      "parameters": {
        "color": 7,
        "width": 769,
        "height": 523,
        "content": "## 生成Quickchart定义"
      },
      "typeVersion": 1
    },
    {
      "id": "9ccea33b-c5d9-422e-a5b9-11efbc05ab1a",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        840,
        60
      ],
      "parameters": {
        "color": 7,
        "width": 888,
        "height": 646,
        "content": "### 信息提取器"
      },
      "typeVersion": 1
    },
    {
      "id": "d8bf0767-faf0-4030-b325-08315188adcb",
      "name": "OpenAI聊天模型分类器",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1900,
        540
      ],
      "parameters": {
        "options": {
          "temperature": 0.2
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "WqzqjezKh8VtxdqA",
          "name": "OpenAi account - Baptiste"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4bcd676f-44f3-4242-a5fd-7cf2098a3a64",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1760,
        60
      ],
      "parameters": {
        "color": 7,
        "width": 948,
        "height": 646,
        "content": "### 仅用文本响应还是也包含图表"
      },
      "typeVersion": 1
    },
    {
      "id": "256cb28b-0d83-4f6d-bb11-33745c9efa4a",
      "name": "文本分类器 - 需要图表吗?",
      "type": "@n8n/n8n-nodes-langchain.textClassifier",
      "position": [
        1800,
        380
      ],
      "parameters": {
        "options": {},
        "inputText": "=**User Request**: {{ $('When chat message received').item.json.chatInput }}\n**Data to visualize**: {{ $json.output }}\n",
        "categories": {
          "categories": [
            {
              "category": "chart_required",
              "description": "If a chart can help the user understand the response (if there are multiple data to show) or if the user specifically request a chart. "
            },
            {
              "category": "chart_not_required",
              "description": "if a chart doesn't help the user understand the response (e.g a single data point that doesn't require visualization).\n\"I don't know\" does fall into this category"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6df60db5-19c0-4585-a229-b56f4b9a2b29",
      "name": "便签4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        40,
        1020
      ],
      "parameters": {
        "color": 7,
        "width": 680,
        "height": 720,
        "content": "## 演示"
      },
      "typeVersion": 1
    },
    {
      "id": "a843845d-e010-4a09-ab50-e169beb67811",
      "name": "用户问题 + 代理初始响应",
      "type": "n8n-nodes-base.set",
      "position": [
        2200,
        280
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "debab41c-da64-4999-a80f-fae06522d672",
              "name": "user_question",
              "type": "string",
              "value": "={{ $('When chat message received').item.json.chatInput }}"
            },
            {
              "id": "2b4bbf7f-9890-4ef3-9d8f-15e3a55fbfda",
              "name": "output",
              "type": "string",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "12c9dc38-c0fe-4f4c-a101-ec1ff7ea9048",
      "name": "信息提取器 - 用户问题",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        1060,
        380
      ],
      "parameters": {
        "text": "={{ $json.chatInput }}",
        "options": {},
        "attributes": {
          "attributes": [
            {
              "name": "user_question",
              "required": true,
              "description": "Extract the question from the user, omitting everything related to charts."
            }
          ]
        }
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Text Classifier - Chart required?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute Workflow": {
      "main": [
        [
          {
            "node": "Set Text + Chart output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Information Extractor - User question",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Window Buffer Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Information Extractor - User question",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model Classifier": {
      "ai_languageModel": [
        [
          {
            "node": "Text Classifier - Chart required?",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Execute \"Generate a chart\" tool": {
      "main": [
        [
          {
            "node": "OpenAI - Generate Chart definition with Structured Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Text Classifier - Chart required?": {
      "main": [
        [
          {
            "node": "User question + Agent initial response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set Text output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Information Extractor - User question": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "User question + Agent initial response": {
      "main": [
        [
          {
            "node": "Execute Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Generate Chart definition with Structured Output": {
      "main": [
        [
          {
            "node": "Set response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 工程, 开发运维, 人工智能, IT 运维

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量16
分类4
节点类型10
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Agent Studio

Agent Studio

@agentstudio

We are a product studio that helps organizations leverage no-code and generative AI to automate internal processes and launch new digital products.

外部链接
在 n8n.io 查看

分享此工作流