{
  "id": "SJwkSCPF1an8rsve",
  "meta": {
    "instanceId": "9239289f4ac5af7b996edef620e4bf7d2f9831e5f716593db80b14e930575f8f",
    "templateCredsSetupCompleted": true
  },
  "name": "Auto-Optimize System Prompts using OPRO & DSPy Logic",
  "tags": [],
  "nodes": [
    {
      "id": "0ce67220-10c9-4084-8ec4-aea6df878e63",
      "name": "Sticky Note Main",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2048,
        -432
      ],
      "parameters": {
        "width": 528,
        "height": 660,
        "content": "## Auto-Optimize Prompts (OPRO/DSPy Implementation)\n\nThis workflow implements cutting-edge concepts from **Google DeepMind's OPRO** and **Stanford's DSPy** to automatically refine AI prompts.\n\n## Why it's powerful\nInstead of manual trial-and-error, this workflow uses an **LLM-driven optimization loop**.\nIt mathematically evaluates the output against a ground truth and iteratively rewrites the prompt to maximize accuracy, just like compiling code.\n\n## How it works\n1. **Define**: Set your initial prompt and a \\\"Ground Truth\\\" (expected answer).\n2. **Generate**: The AI generates a response.\n3. **Evaluate**: An Evaluator AI scores the response (0-100).\n4. **Optimize**: An Optimizer AI analyzes the failure and improves the prompt.\n5. **Loop**: Repeats until the score reaches 95+.\n\n## Setup steps\n1. **Configure OpenAI**: Set credentials in `OpenAI Chat Model`.\n2. **Customize**: Edit `Define Initial Prompt & Test Data` with your task.\n3. **Run**: Watch the prompt self-improve!"
      },
      "typeVersion": 1
    },
    {
      "id": "7c651fda-e903-4d5e-b05f-5be23acf49d8",
      "name": "Sticky Note Init",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1504,
        -432
      ],
      "parameters": {
        "color": 7,
        "width": 494,
        "height": 656,
        "content": "## 1. Initialization\nDefine the starting prompt and the test case.\n\nExample: Invoice Data Extraction"
      },
      "typeVersion": 1
    },
    {
      "id": "5d2b7a89-6415-41b6-94a8-3e77f1eb7703",
      "name": "Sticky Note Gen Eval",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        -432
      ],
      "parameters": {
        "color": 7,
        "width": 708,
        "height": 640,
        "content": "## 2. Generation & Evaluation\nGenerate response and score it against ground truth."
      },
      "typeVersion": 1
    },
    {
      "id": "95c31df9-4ffe-46ea-a06c-a53e21b81f82",
      "name": "Sticky Note Opt",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        -432
      ],
      "parameters": {
        "color": 7,
        "width": 516,
        "height": 640,
        "content": "## 3. Optimization Loop\nAnalyze results and improve the prompt if needed."
      },
      "typeVersion": 1
    },
    {
      "id": "167addf3-7815-4c26-8fab-f3e523894bf7",
      "name": "When clicking ‘Execute workflow’",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1440,
        -160
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9519a48a-e021-4552-908e-ef5973b784cd",
      "name": "Define Initial Prompt & Test Data",
      "type": "n8n-nodes-base.set",
      "position": [
        -1216,
        -160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "79bcebc3-01ef-453a-932e-ac4dd23aedb2",
              "name": "initial_prompt",
              "type": "string",
              "value": "Extract invoice data from the text and output as JSON."
            },
            {
              "id": "bfaead23-4eaf-457f-985d-d0a112ddb709",
              "name": "test_input",
              "type": "string",
              "value": "Invoice #INV-9982. Date: 12th of Oct, 2023. Grand Total: $1,100 (includes 10% VAT). Items: 2x Widget A, 1x Widget B."
            },
            {
              "id": "39866c21-a311-45c0-84b7-de73db3c79bd",
              "name": "ground_truth",
              "type": "string",
              "value": "{   \"id\": \"INV-9982\",   \"date\": \"2023-10-12\",   \"subtotal\": 1000,   \"vat\": 100,   \"total\": 1100,   \"items\": [\"Widget A\", \"Widget A\", \"Widget B\"] }"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "55fcf4d8-9209-4c61-8f2c-bfbe070bccc0",
      "name": "AI Prompt Optimizer",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "onError": "continueRegularOutput",
      "position": [
        256,
        -256
      ],
      "parameters": {
        "text": "=You are a world-class prompt engineer.\nYour goal is to optimize the system prompt so that the AI model can output the 'expected correct answer' with 100% accuracy.\n\n## Task\nAnalyze the provided 'Previous Prompt', 'Generated Result', and 'Evaluation Result (Score and Reason)', and rewrite the prompt to achieve a higher score.\n\n## Optimization Strategy\n1. Clarify instructions: Eliminate ambiguity and use specific verbs.\n2. Strengthen constraints: Prioritize affirmative commands over negative ones.\n3. Guide thinking: Add instructions like 'Think step-by-step' if necessary.\n4. Add Few-Shot: Add output examples if there are many format errors.\n\n## Output Format\nOutput ONLY the following JSON format. No Markdown code blocks required.",
        "options": {
          "systemMessage": "=# Goal\nAchieve a score of 100.\n\n# Current Status\n- Current Score: {{ $json.output.score }} / 100\n- Evaluation Comment: {{ $json.output.reason }}\n\n# Previous Prompt\n\"\"\"\n{{ $('Manage Loop & State').item.json.current_prompt }}\n\"\"\"\n\n# Generated Result for Previous Input (Failure)\n\"\"\"\n{{ $('AI Response Generator').item.json.output }}\n\"\"\"\n\n# (Expected) Ground Truth\n\"\"\"\n{{ $('Manage Loop & State').item.json.ground_truth }}\n\"\"\"\n\nBased on the above, improve the previous prompt to increase the score. \n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "b6ac0833-f4fe-4f66-9dbe-77bf99844b6c",
      "name": "AI Response Evaluator",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "onError": "continueRegularOutput",
      "position": [
        -96,
        -256
      ],
      "parameters": {
        "text": "=# Input Data\n{{ $('Manage Loop & State').item.json.test_input }}\n\n# Expected Ground Truth\n{{ $('Manage Loop & State').item.json.ground_truth }}\n\n# Actual Generated Answer\n{{ $json.output }}\n\nStart the evaluation.",
        "options": {
          "systemMessage": "=You are a strict and fair AI evaluator.\nCompare the 'Input Data', 'Expected Ground Truth', and 'Actual Generated Answer' provided by the user, and evaluate the quality.\n\n## Evaluation Criteria\n1. **Accuracy**: Does it contain the information from the ground truth? Are there no lies or errors?\n2. **Format**: Does it follow the requested format (JSON, Markdown, etc.)?\n3. **Tone**: Is it in the instructed tone and style?\n\n## Scoring Tips\n- 100 points if it matches perfectly or is of equivalent quality.\n- 50 points or less if there are fatal errors.\n- Deduct points strictly for format errors."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "98670d2b-e4eb-4181-aa06-5a16aea57ebc",
      "name": "Manage Loop & State",
      "type": "n8n-nodes-base.code",
      "position": [
        -928,
        -368
      ],
      "parameters": {
        "jsCode": "// 1. Get Static Data\nconst staticData = $('Define Initial Prompt & Test Data').first().json;\nconst inputData = items[0].json;\n\n// YOUR_AWS_SECRET_KEY_HERE==\n// 2. Update Loop Count (Adopt AI calculation)\n// YOUR_AWS_SECRET_KEY_HERE==\nlet currentLoopCount = 1;\n\nif (inputData.next_loop_count) {\n    // If AI says \"Next is loop 3\", adopt it\n    currentLoopCount = inputData.next_loop_count;\n} else if (inputData.loop_count) {\n    // Maintain previous value if exists\n    currentLoopCount = inputData.loop_count;\n}\n\n// YOUR_AWS_SECRET_KEY_HERE==\n// 3. Update Prompt\n// YOUR_AWS_SECRET_KEY_HERE==\nlet nextPrompt = staticData.initial_prompt;\nlet currentScore = 0;\n\n// 2nd loop onwards\nif (currentLoopCount > 1) {\n    // First, get and keep previous prompt (prevent reset)\n    try {\n        const prev = $('Manage Loop & State').item.json.current_prompt;\n        if (prev) nextPrompt = prev;\n    } catch(e) {}\n\n    // Get Score\n    try {\n        // Get score from Evaluator output\n        currentScore = $('AI Response Evaluator').item.json.output.score || 0;\n    } catch(e) {}\n\n    // Update if there is an improvement proposal from AI\n    if (inputData.improved_prompt) {\n        nextPrompt = inputData.improved_prompt;\n    }\n}\n\n// YOUR_AWS_SECRET_KEY_HERE==\n// 4. Output\n// YOUR_AWS_SECRET_KEY_HERE==\nreturn [{\n  json: {\n    // Static Data\n    test_input: staticData.test_input,\n    ground_truth: staticData.ground_truth,\n    initial_prompt: staticData.initial_prompt,\n\n    // Updated Data\n    current_prompt: nextPrompt,\n    loop_count: currentLoopCount,\n    current_score: currentScore,\n\n    // Stop Condition (Over 5 loops OR Error prevention limit OR Score >= 95)\n    stop_loop: currentLoopCount > 5 || currentScore >= 95\n  }\n}];"
      },
      "executeOnce": false,
      "typeVersion": 2
    },
    {
      "id": "de205d99-043f-4d91-94b0-64820be376e6",
      "name": "AI Response Generator",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -448,
        -256
      ],
      "parameters": {
        "text": "=Respond to the following input according to the instructions.\n\nInput:\n{{ $json.test_input }}",
        "options": {
          "systemMessage": "={{ $json.current_prompt }}"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "de86fe42-e5f2-4b91-96e0-31d763579b98",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -368,
        -32
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "credential-id",
          "name": "openAiApi Credential"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "9746cbd5-283a-4f3f-ad21-6cb96f1243af",
      "name": "Check Loop Condition",
      "type": "n8n-nodes-base.if",
      "position": [
        -752,
        -368
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1283eac2-81c7-4ade-b3ed-adc4432bb883",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.stop_loop }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "77d542df-3380-4dbe-9f64-a871f3053145",
      "name": "End Loop",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -480,
        -752
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "4f1e33e3-5b62-4262-afc8-45020f92337b",
      "name": "Evaluator Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -16,
        -32
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"score\": 90,\n  \"reason\": \"Reason for deduction and specific pointers on how to get closer to the correct answer (within 100 characters)\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "24716665-625b-4507-8e19-be973cccb81d",
      "name": "Optimizer Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        336,
        -32
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"improved_prompt\": \"Improved Prompt\",\n  \"change_log\": \"Reason for change\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "d83ce8ae-70ed-40ef-b989-bb29a8663b82",
      "name": "Update Prompt & Loop Count",
      "type": "n8n-nodes-base.set",
      "position": [
        592,
        -48
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2cf489f6-d88d-41f6-82c9-95f315e00aee",
              "name": "next_loop_count",
              "type": "number",
              "value": "={{ $('Manage Loop & State').item.json.loop_count + 1 }}"
            },
            {
              "id": "improved_prompt_assignment",
              "name": "improved_prompt",
              "type": "string",
              "value": "={{ $json.output.improved_prompt }}"
            },
            {
              "id": "change_log_assignment",
              "name": "change_log",
              "type": "string",
              "value": "={{ $json.output.change_log }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7092cd5e-c638-4e0f-9a12-bf74bcd24b75",
  "connections": {
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Prompt Optimizer",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "AI Response Evaluator",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "AI Response Generator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "AI Prompt Optimizer": {
      "main": [
        [
          {
            "node": "Update Prompt & Loop Count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manage Loop & State": {
      "main": [
        [
          {
            "node": "Check Loop Condition",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Loop Condition": {
      "main": [
        [
          {
            "node": "End Loop",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "AI Response Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Response Evaluator": {
      "main": [
        [
          {
            "node": "AI Prompt Optimizer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Response Generator": {
      "main": [
        [
          {
            "node": "AI Response Evaluator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluator Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Response Evaluator",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Optimizer Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Prompt Optimizer",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Update Prompt & Loop Count": {
      "main": [
        [
          {
            "node": "Manage Loop & State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Define Initial Prompt & Test Data": {
      "main": [
        [
          {
            "node": "Manage Loop & State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Execute workflow’": {
      "main": [
        [
          {
            "node": "Define Initial Prompt & Test Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}