8
n8n 中文网amn8n.com

无需结构化输出解析器即可从AI代理获得可靠的结构化输出 - 使用OpenAI和Switch节点

高级

这是一个Engineering, AI领域的自动化工作流,包含 16 个节点。主要使用 Set, Switch, Agent, ChatTrigger, LmChatOpenAi 等节点,结合人工智能技术实现智能自动化。 无需结构化输出解析器即可从AI代理获得可靠的结构化输出 - 使用OpenAI和Switch节点

前置要求
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移

无法加载工作流预览

导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "",
  "meta": {
    "instanceId": ""
  },
  "name": "无需结构化输出解析器即可从 AI Agent 获得可靠的结构化输出 - 使用 OpenAI 和 Switch 节点",
  "tags": [],
  "nodes": [
    {
      "id": "",
      "name": "AI 代理",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -400,
        760
      ],
      "parameters": {
        "text": "={{ $json.chatInput }}",
        "options": {
          "maxIterations": 10,
          "systemMessage": "=You are a helpful assistant specialized in nutrition.  \nYour task is to provide accurate nutritional information for a given food item.  \nYou must return your answer strictly in the form of a JSON object matching the following schema:\n\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"alimentName\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the food item, in English\"\n    },\n    \"averageCalories\": {\n      \"type\": \"number\",\n      \"description\": \"Average calories per 100g or standard portion (kcal)\"\n    },\n    \"proteins\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of protein per 100g or portion (grams)\"\n    },\n    \"carbohydrates\": {\n      \"type\": \"number\",\n      \"description\": \"Total amount of carbohydrates per 100g or portion (grams), including fiber and sugars\"\n    },\n    \"sugar\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of total sugars (subset of carbohydrates) per 100g or portion (grams)\"\n    },\n    \"fiber\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of dietary fiber (subset of carbohydrates) per 100g or portion (grams)\"\n    },\n    \"fat\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of fat per 100g or portion (grams)\"\n    },\n    \"sodium\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of sodium per 100g or portion (milligrams)\"\n    },\n    \"healthyScore\": {\n      \"type\": \"number\",\n      \"minimum\": 0,\n      \"maximum\": 10,\n      \"description\": \"A healthiness score from 0 (very unhealthy) to 10 (very healthy), based on nutritional guidelines\"\n    }\n  },\n  \"required\": [\n    \"alimentName\",\n    \"averageCalories\",\n    \"proteins\",\n    \"carbohydrates\",\n    \"sugar\",\n    \"fiber\",\n    \"fat\",\n    \"sodium\",\n    \"healthyScore\"\n  ]\n}\n\n\nIf the user input is not a valid food item, or if you are unsure whether it is a real food, then instead return:\n\n{\n  \"error\": \"invalid_input\",\n  \"message\": \"The provided input does not appear to be a valid food item.\"\n}\n\n----\n\n⚠️ If you fail to produce output in the correct schema, the Schema Error Prompt below will contain an error message. You will need to follow the instructions it provides:\n\n## Schema Error Prompt:\n\n{{ $json.schemaErrorPrompt }}\n\n",
          "returnIntermediateSteps": true
        },
        "promptType": "define"
      },
      "executeOnce": false,
      "typeVersion": 1.8
    },
    {
      "id": "",
      "name": "当收到聊天消息时",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -800,
        760
      ],
      "webhookId": "",
      "parameters": {
        "mode": "webhook",
        "public": true,
        "options": {
          "responseMode": "responseNode"
        },
        "authentication": "basicAuth"
      },
      "credentials": {
        "httpBasicAuth": {
          "id": "",
          "name": ""
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -400,
        920
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "id",
          "value": "=gpt-4.1-nano"
        },
        "options": {
          "temperature": 0.8,
          "responseFormat": "json_object"
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "",
          "name": "OpenAi Connection"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "",
      "name": "简单记忆",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -260,
        920
      ],
      "parameters": {},
      "typeVersion": 1.3
    },
    {
      "id": "",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        860,
        760
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "invalidSchema",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.output.error !== undefined && $json.aiRunIndex < 3 }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "validSchema",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $json.output.alimentName }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "",
      "name": "验证输出 + 设置 `aiRunIndex`",
      "type": "n8n-nodes-base.set",
      "onError": "continueRegularOutput",
      "position": [
        260,
        760
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "",
              "name": "output",
              "type": "object",
              "value": "={{ \n(() => {\n\tlet raw = $json.output;\n\n\tif (typeof raw === 'string') {\n\t\traw = raw\n\t\t\t.replace(/^\\s*```json/i, '')\n\t\t\t.replace(/```$/i, '')\n\t\t\t.trim();\n\t\ttry { raw = JSON.parse(raw); }\n\t\tcatch { return { error: 'invalid_json' }; }\n\t}\n\n\t// Allow alternative valid response when input is not a valid food item\n\tif (\n\t\traw.error === 'invalid_input' &&\n\t\traw.message === 'The provided input does not appear to be a valid food item.'\n\t) {\n\t\treturn JSON.stringify(raw, null, 2);\n\t}\n\n\t// Check required keys\n\tconst requiredKeys = [\n\t\t'alimentName',\n\t\t'averageCalories',\n\t\t'proteins',\n\t\t'carbohydrates',\n\t\t'sugar',\n\t\t'fiber',\n\t\t'fat',\n\t\t'sodium',\n\t\t'healthyScore'\n\t];\n\n\tfor (const key of requiredKeys) {\n\t\tif (!(key in raw)) {\n\t\t\treturn { error: 'missing_key', key };\n\t\t}\n\t}\n\n\t// Type checks\n\tif (typeof raw.alimentName !== 'string')\n\t\treturn { error: 'invalid_type', key: 'alimentName', expected: 'string' };\n\n\tif (typeof raw.averageCalories !== 'number')\n\t\treturn { error: 'invalid_type', key: 'averageCalories', expected: 'number' };\n\n\tif (typeof raw.proteins !== 'number')\n\t\treturn { error: 'invalid_type', key: 'proteins', expected: 'number' };\n\n\tif (typeof raw.carbohydrates !== 'number')\n\t\treturn { error: 'invalid_type', key: 'carbohydrates', expected: 'number' };\n\n\tif (typeof raw.sugar !== 'number')\n\t\treturn { error: 'invalid_type', key: 'sugar', expected: 'number' };\n\n\tif (typeof raw.fiber !== 'number')\n\t\treturn { error: 'invalid_type', key: 'fiber', expected: 'number' };\n\n\tif (typeof raw.fat !== 'number')\n\t\treturn { error: 'invalid_type', key: 'fat', expected: 'number' };\n\n\tif (typeof raw.sodium !== 'number')\n\t\treturn { error: 'invalid_type', key: 'sodium', expected: 'number' };\n\n\tif (typeof raw.healthyScore !== 'number')\n\t\treturn { error: 'invalid_type', key: 'healthyScore', expected: 'number' };\n\n\tif (raw.healthyScore < 0 || raw.healthyScore > 10)\n\t\treturn { error: 'invalid_range', key: 'healthyScore', expected: 'number between 0 and 10' };\n\n\t// If all checks pass, return the parsed and formatted JSON\n\treturn JSON.stringify(raw, null, 2);\n})() \n}}"
            },
            {
              "id": "",
              "name": "=aiRunIndex",
              "type": "number",
              "value": "={{ $node[\"AI Agent\"].runIndex }} "
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "",
      "name": "格式化模式错误提示",
      "type": "n8n-nodes-base.set",
      "position": [
        920,
        1020
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "",
              "name": "schemaErrorPrompt",
              "type": "string",
              "value": "=If you're seeing this message, it means your previous response did not follow the required output schema defined in your prompt:\n\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"alimentName\": {\n      \"type\": \"string\",\n      \"description\": \"The name of the food item, in English\"\n    },\n    \"averageCalories\": {\n      \"type\": \"number\",\n      \"description\": \"Average calories per 100g or standard portion (kcal)\"\n    },\n    \"proteins\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of protein per 100g or portion (grams)\"\n    },\n    \"carbohydrates\": {\n      \"type\": \"number\",\n      \"description\": \"Total amount of carbohydrates per 100g or portion (grams), including fiber and sugars\"\n    },\n    \"sugar\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of total sugars (subset of carbohydrates) per 100g or portion (grams)\"\n    },\n    \"fiber\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of dietary fiber (subset of carbohydrates) per 100g or portion (grams)\"\n    },\n    \"fat\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of fat per 100g or portion (grams)\"\n    },\n    \"sodium\": {\n      \"type\": \"number\",\n      \"description\": \"Amount of sodium per 100g or portion (milligrams)\"\n    },\n    \"healthyScore\": {\n      \"type\": \"number\",\n      \"minimum\": 0,\n      \"maximum\": 10,\n      \"description\": \"A healthiness score from 0 (very unhealthy) to 10 (very healthy), based on nutritional guidelines\"\n    }\n  },\n  \"required\": [\n    \"alimentName\",\n    \"averageCalories\",\n    \"proteins\",\n    \"carbohydrates\",\n    \"sugar\",\n    \"fiber\",\n    \"fat\",\n    \"sodium\",\n    \"healthyScore\"\n  ]\n}\n\n\nPlease revise your output to strictly match this structure.\n\nFor reference, the last user message was:\n{{ $('When chat message received').item.json.chatInput }}\n\nAnd your response was:\n{{ $('AI Agent').item.json.output }}\n\nThis does not conform to the expected schema. Please correct your output accordingly."
            },
            {
              "id": "",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $('When chat message received').item.json.sessionId }}"
            },
            {
              "id": "",
              "name": "chatInput",
              "type": "string",
              "value": "={{ $('When chat message received').item.json.chatInput }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "",
      "name": "有效模式输出",
      "type": "n8n-nodes-base.set",
      "position": [
        1460,
        760
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "",
              "name": "nutritionalValues",
              "type": "object",
              "value": "={{ $json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        600,
        -260
      ],
      "parameters": {
        "color": 7,
        "width": 520,
        "height": 1140,
        "content": "## Switch"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 1040,
        "content": "## AI Agent"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "便签 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        60,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 1040,
        "content": "## 验证输出 + 设置 `aiRunIndex`"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "便签 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1160,
        360
      ],
      "parameters": {
        "color": 7,
        "width": 700,
        "height": 520,
        "content": "## 有效模式输出"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "便签 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1160,
        940
      ],
      "parameters": {
        "color": 7,
        "width": 700,
        "height": 600,
        "content": "## 输出处理(有效与无效模式)"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "设置 schemaValidationError 和 lastAgentOutput",
      "type": "n8n-nodes-base.set",
      "position": [
        1280,
        1020
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "",
              "name": "schemaValidationError",
              "type": "string",
              "value": "={{ $('Validate Output + Set `aiRunIndex`').item.json.output }}"
            },
            {
              "id": "",
              "name": "lastAgentOutput",
              "type": "string",
              "value": "={{ $('AI Agent').item.json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "",
      "name": "设置聊天输出",
      "type": "n8n-nodes-base.set",
      "position": [
        1640,
        1020
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "",
              "name": "output",
              "type": "string",
              "value": "=This output was sent because a schema validation error occurred:\n\n{{ $json.schemaValidationError }}\n\nHowever, here is the last AI agent response:\n\n{{ $json.lastAgentOutput }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "",
      "name": "便签 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1580,
        -60
      ],
      "parameters": {
        "color": 5,
        "width": 720,
        "height": 940,
        "content": "## 无需结构化输出解析器即可从 AI Agent 获得可靠的结构化输出 - 使用 OpenAI 和 Switch 节点"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "callerPolicy": "",
    "executionOrder": "v1",
    "executionTimeout": 60
  },
  "versionId": "",
  "connections": {
    "Switch": {
      "main": [
        [
          {
            "node": "Format Schema Error Prompt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Valid Schema Output",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set schemaValidationError & lastAgentOutput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Validate Output + Set `aiRunIndex`",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Format Schema Error Prompt": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Output + Set `aiRunIndex`": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set schemaValidationError & lastAgentOutput": {
      "main": [
        [
          {
            "node": "Set chat Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

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

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

高级 - 工程, 人工智能

需要付费吗?

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

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

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

作者
Dataki

Dataki

@dataki

I am passionate about transforming complex processes into seamless automations with n8n. My expertise spans across creating ETL pipelines, sales automations, and data & AI-driven workflows. As an avid problem solver, I thrive on optimizing workflows to drive efficiency and innovation.

外部链接
在 n8n.io 查看

分享此工作流