This workflow corresponds to n8n.io template #11495 — we link there as the canonical source.
This workflow follows the Agent → OpenAI Chat recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "SJwkSCPF1an8rsve",
"meta": {
"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 \u2018Execute workflow\u2019",
"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": {
"name": "<your 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,
"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 \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Define Initial Prompt & Test Data",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow implements cutting-edge concepts from Google DeepMind's OPRO (Optimization by PROmpting) and Stanford's DSPy to automatically refine AI prompts. It iteratively generates, evaluates, and optimizes responses against a ground truth, allowing you to "compile" your…
Source: https://n8n.io/workflows/11495/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.
Generate AI viral videos with NanoBanana & VEO3, shared on socials via Blotato 2. Uses @blotato/n8n-nodes-blotato, googleSheets, lmChatOpenAi, toolThink. Event-driven trigger; 94 nodes.
RAG CHATBOT Main. Uses telegram, telegramTrigger, lmChatOpenAi, n8n-nodes-mcp. Event-driven trigger; 87 nodes.
The best content automation template in the market is now even better—with “deep research” on time-sensitive topics\! Unlike most n8n content automation templates that are mainly for “demo purposes,”
Digital marketers, content creators, social media managers, and businesses who want to use AI marketing automation for YouTube Shorts without spending hours on production. This AI workflow helps anyon