This workflow corresponds to n8n.io template #11116 — we link there as the canonical source.
This workflow follows the Chainllm → Form Trigger 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": "OtwtSFJ7MgNL33lT",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AGENTIC AI",
"tags": [
{
"id": "oPwjXlckTdNT4rp6",
"name": "template",
"createdAt": "2025-11-17T08:27:25.890Z",
"updatedAt": "2025-11-17T08:27:25.890Z"
}
],
"nodes": [
{
"id": "38e7d8a0-9378-4550-9baa-70c2feeeb909",
"name": "Form Trigger",
"type": "n8n-nodes-base.formTrigger",
"position": [
-80,
310
],
"parameters": {
"path": "f7978098-4fb4-4419-9c92-a6fd5f8d33cd",
"options": {},
"formTitle": "AI Research Team",
"formFields": {
"values": [
{
"fieldLabel": "Research Topic",
"requiredField": true
},
{
"fieldType": "dropdown",
"fieldLabel": "Research Depth",
"fieldOptions": {
"values": [
{
"option": "Quick (5 min)"
},
{
"option": "Standard (10 min)"
},
{
"option": "Deep (15 min)"
}
]
},
"requiredField": true
},
{
"fieldType": "dropdown",
"fieldLabel": "Output Format",
"fieldOptions": {
"values": [
{
"option": "Executive Summary"
},
{
"option": "Detailed Report"
},
{
"option": "Blog Article"
}
]
},
"requiredField": true
},
{
"fieldType": "textarea",
"fieldLabel": "Additional Context (Optional)"
}
]
},
"responseMode": "responseNode",
"formDescription": "Submit your research topic and let our AI agents work together"
},
"typeVersion": 2
},
{
"id": "d71ffa02-9aa7-434f-b2e0-7c84f284a7f2",
"name": "Parse Form Input",
"type": "n8n-nodes-base.code",
"position": [
140,
310
],
"parameters": {
"jsCode": "// Parse form data and prepare for agents\nconst formData = $input.item.json;\n\nreturn [{\n json: {\n query: formData['Research Topic'],\n depth: formData['Research Depth'],\n format: formData['Output Format'],\n context: formData['Additional Context (Optional)'] || '',\n timestamp: new Date().toISOString(),\n sessionId: $workflow.id + '_' + Date.now()\n }\n}];"
},
"typeVersion": 2
},
{
"id": "2f8432e1-5e92-4c1f-8fd3-d9999bd75199",
"name": "Research Agent - Plan",
"type": "n8n-nodes-base.httpRequest",
"position": [
380,
240
],
"parameters": {
"url": "https://api.groq.com/openai/v1/chat/completions",
"method": "POST",
"options": {},
"jsonBody": "={\n \"model\": \"llama-3.3-70b-versatile\",\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a research specialist. Your task is to create a comprehensive research plan and identify key search queries for the topic. List 5-7 specific search queries that would gather the most relevant information. Format as JSON array of queries.\"\n },\n {\n \"role\": \"user\",\n \"content\": \"{{ $json.query }}{{ $json.context ? '\\\\n\\\\nAdditional context: ' + $json.context : '' }}\"\n }\n ],\n \"temperature\": 0.7,\n \"max_tokens\": 4096\n}\n",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "groqApi"
},
"credentials": {
"groqApi": {
"name": "<your credential>"
}
},
"typeVersion": 4.1
},
{
"id": "3a5be3ee-bd09-4c33-b998-7ee956ba78f7",
"name": "Extract Search Queries",
"type": "n8n-nodes-base.code",
"position": [
640,
220
],
"parameters": {
"jsCode": "// Extract search queries from research plan\nconst response = $input.item.json.choices[0].message.content;\nlet queries = [];\n\n// Try to parse JSON first\ntry {\n queries = JSON.parse(response);\n} catch (e) {\n // Fallback: extract queries from text\n const lines = response.split('\\n');\n queries = lines\n .filter(line => line.trim().length > 10)\n .map(line => line.replace(/^[\\d\\-\\.\\*]\\s*/, '').trim())\n .filter(q => q.length > 0)\n .slice(0, 5);\n}\n\n// Return array of queries for batch processing\nreturn queries.map(query => ({\n json: {\n searchQuery: query,\n originalTopic: $input.item.json.query || $('Parse Form Input').item.json.query,\n sessionId: $input.item.json.sessionId || $('Parse Form Input').item.json.sessionId\n }\n}));"
},
"typeVersion": 2
},
{
"id": "5fcb3f72-4b3b-4e6c-a99d-ab2021b31399",
"name": "SERP Search",
"type": "n8n-nodes-base.httpRequest",
"position": [
800,
235
],
"parameters": {
"url": "https://serpapi.com/search.json",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "q",
"value": "={{ $json.searchQuery }}"
},
{
"name": "num",
"value": "5"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "serpApi"
},
"credentials": {
"serpApi": {
"name": "<your credential>"
}
},
"typeVersion": 4.1
},
{
"id": "906a3e0c-5c8d-4f23-8345-b13d6f1b5add",
"name": "Merge Research",
"type": "n8n-nodes-base.merge",
"position": [
1020,
310
],
"parameters": {
"mode": "combine",
"options": {},
"combinationMode": "multiplex"
},
"typeVersion": 2.1
},
{
"id": "da016204-312e-4192-9c75-f216e3e65ff2",
"name": "Aggregate Research",
"type": "n8n-nodes-base.code",
"position": [
1240,
310
],
"parameters": {
"jsCode": "// Combine all search results\nconst allResults = $input.all();\nconst formData = $('Parse Form Input').first().json;\n\nlet researchData = {\n topic: formData.query,\n context: formData.context,\n sources: []\n};\n\nallResults.forEach(item => {\n if (item.json.organic) {\n item.json.organic.forEach(result => {\n researchData.sources.push({\n title: result.title,\n snippet: result.snippet,\n link: result.link\n });\n });\n }\n});\n\nreturn [{\n json: {\n ...formData,\n research: researchData,\n sourceCount: researchData.sources.length\n }\n}];"
},
"typeVersion": 2
},
{
"id": "5d8ee0ec-12db-4b0c-97c1-5d7d6c0a9a63",
"name": "Merge All Agents",
"type": "n8n-nodes-base.merge",
"position": [
2212,
310
],
"parameters": {
"mode": "combine",
"options": {},
"combinationMode": "multiplex"
},
"typeVersion": 2.1
},
{
"id": "6e00b2c3-5429-4832-b428-98de2942b253",
"name": "Return Results",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2808,
310
],
"parameters": {
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "text/html"
}
]
}
},
"respondWith": "allIncomingItems"
},
"typeVersion": 1.1
},
{
"id": "82d17fe2-2ae2-4141-bc8a-ef1f4a5b8da9",
"name": "Groq Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
2320,
520
],
"parameters": {
"model": "llama-3.3-70b-versatile",
"options": {}
},
"credentials": {
"groqApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "4c7f292a-c0d3-4193-aee4-be3026be67e3",
"name": "Fact-Checker Agent",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1840,
240
],
"parameters": {
"text": "=Content to verify:\\n{{ $json.text }}\\n\\nSource material:\\n{{ $('Aggregate Research').item.json.research.sources.map((s, i) => (i+1) + '. ' + s.title + ': ' + s.snippet).join('\\n\\n') }}\\n\\nProvide fact-check report with any corrections needed.",
"messages": {
"messageValues": [
{
"message": "You are a fact-checker. Verify claims against source material and flag any inaccuracies or unsupported statements."
}
]
},
"promptType": "define"
},
"typeVersion": 1.6
},
{
"id": "15c0884b-e3d3-4e36-b286-8b7df8868d4a",
"name": "Editor Agent",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1840,
360
],
"parameters": {
"text": "=Edit this content:\\n{{ $json.text }}\\n\\nReturn improved version.",
"messages": {
"messageValues": [
{
"message": "You are an editor. Improve clarity, fix grammar, enhance readability, and ensure professional tone."
}
]
},
"promptType": "define"
},
"typeVersion": 1.6
},
{
"id": "0b7812ba-eb64-4a7f-8f0b-5f131c9e652d",
"name": "PM Agent - Final Review1",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
2432,
310
],
"parameters": {
"text": "=ORIGINAL TOPIC: {{ $('Aggregate Research').item.json.research.topic }}\\n\\nWRITTEN CONTENT:\\n{{ $('Writer Agent').item.json.text }}\\n\\nFACT-CHECK REPORT:\\n{{ $('Fact-Checker Agent').item.json.text }}\\n\\nEDITED VERSION:\\n{{ $('Editor Agent').item.json.text }}\\n\\nSOURCES:\\n{{ $('Aggregate Research').item.json.research.sources.map((s, i) => (i+1) + '. ' + s.title + ' - ' + s.link).join('\\\\n') }}\\n\\nCreate final consolidated output with citations.",
"messages": {
"messageValues": [
{
"message": "You are a Project Manager reviewing team outputs. Merge insights from all agents into one cohesive, accurate, well-written final deliverable. Include source citations."
}
]
},
"promptType": "define"
},
"typeVersion": 1.6
},
{
"id": "9807e86a-f35e-4a02-81b5-f36769bcf5e9",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
3028,
310
],
"parameters": {
"jsCode": "// n8n Function node code\n// Input: items where items[i].json.text contains the markdown-ish string\n// Output: items with .json.html and .binary.data (base64 HTML) ready for HTML->PDF nodes\n\nconst sanitizeForHtml = (md) => {\n if (!md) return '';\n // Basic conversion: bold (**text**) -> <strong>text</strong>\n // This is intentionally simple \u2014 for complex markdown use a markdown library.\n let html = md.replace(/\\*\\*(.+?)\\*\\*/gs, '<strong>$1</strong>');\n // Convert two or more newlines to paragraph separators\n html = html.replace(/\\r\\n/g, '\\n');\n html = html.split('\\n\\n').map(p => p.trim()).filter(p => p !== '').map(p => {\n // inside a paragraph convert single newlines to <br>\n const withBr = p.replace(/\\n/g, '<br>');\n return `<p>${withBr}</p>`;\n }).join('\\n');\n return html;\n};\n\nconst wrapFullHtml = (bodyHtml, title = 'Report') => {\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\"/>\n <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>\n <title>${title}</title>\n <style>\n body { font-family: Arial, Helvetica, sans-serif; font-size: 12pt; line-height:1.4; padding: 28px; color: #222; }\n h1 { font-size: 20pt; margin-bottom: 6px; }\n p { margin: 8px 0; }\n strong { font-weight: 700; }\n .footer { margin-top: 24px; font-size: 9pt; color: #666; }\n pre { white-space: pre-wrap; word-wrap: break-word; }\n </style>\n</head>\n<body>\n <h1>${title}</h1>\n ${bodyHtml}\n <div class=\"footer\">Generated by n8n \u2022 ${new Date().toLocaleString()}</div>\n</body>\n</html>`;\n};\n\n// process all items\nconst output = [];\n\nfor (let i = 0; i < items.length; i++) {\n const item = items[i];\n const rawText = item.json && (item.json.text || item.json.body || item.json.content) ? (item.json.text || item.json.body || item.json.content) : '';\n const title = (item.json && item.json.title) ? item.json.title : 'Report';\n const bodyHtml = sanitizeForHtml(rawText);\n const fullHtml = wrapFullHtml(bodyHtml, title);\n\n // place HTML in json for nodes that read html from json\n const newItem = {\n json: {\n ...item.json,\n html: fullHtml,\n _generatedTitle: title,\n },\n binary: {}\n };\n\n // attach binary (base64) \u2014 many HTML->PDF nodes accept binary input\n const buffer = Buffer.from(fullHtml, 'utf8');\n newItem.binary.data = {\n fileName: `${title.replace(/[^a-z0-9]+/gi, '_').toLowerCase() || 'report'}.html`,\n mimeType: 'text/html',\n fileExtension: 'html',\n data: buffer.toString('base64'),\n };\n\n output.push(newItem);\n}\n\nreturn output;\n"
},
"typeVersion": 2
},
{
"id": "924fa486-8dda-48c5-b882-ed12567cf132",
"name": "Writer Agent",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1460,
310
],
"parameters": {
"text": "={{ $json.query }}\\n\\nResearch Sources:\\n{{ $json.research.sources.map((s, i) => (i+1) + '. ' + s.title + ': ' + s.snippet).join('\\\\n\\\\n') }}\\n\\nWrite comprehensive content covering all key findings.",
"messages": {
"messageValues": [
{
"message": "=You are a professional content writer. Create engaging, well-structured content based on research findings. Format: {{ $json.format }}"
}
]
},
"promptType": "define"
},
"typeVersion": 1.6
},
{
"id": "0a7774e0-c5f4-49df-b83c-0979f5cc6477",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
1380,
120
],
"parameters": {
"color": 3,
"width": 1360,
"height": 520,
"content": "## AI AGENTS"
},
"typeVersion": 1
},
{
"id": "39f31e11-6ec4-4af3-978f-9d1e139e140f",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
300,
120
],
"parameters": {
"color": 3,
"width": 300,
"height": 520,
"content": "## RESEARCH AGENT\n"
},
"typeVersion": 1
},
{
"id": "b64b2f2c-a687-4805-9488-5578a7c7fa02",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
620,
120
],
"parameters": {
"color": 4,
"width": 740,
"height": 520,
"content": "## FINALIZING RESEARCH"
},
"typeVersion": 1
},
{
"id": "adf8837f-503f-4e4e-9f1d-5ca9af2cfcf2",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-100,
120
],
"parameters": {
"color": 6,
"width": 380,
"height": 520,
"content": "## INPUT"
},
"typeVersion": 1
},
{
"id": "cebfb2b3-3697-493e-9c15-73f719803293",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2760,
120
],
"parameters": {
"color": 6,
"width": 400,
"height": 520,
"content": "## OUTPUT"
},
"typeVersion": 1
},
{
"id": "c12bdca2-4610-4243-a680-55c1da2941aa",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-140,
-40
],
"parameters": {
"color": 7,
"width": 3400,
"height": 780,
"content": "# AGENTIC AI"
},
"typeVersion": 1
},
{
"id": "78c1b410-1ea5-425a-98f3-62c69098cb6c",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-720,
-260
],
"parameters": {
"width": 560,
"height": 1380,
"content": "# \ud83e\udde0 Agentic AI Research System\n\n# \ud83c\udfa5 **Watch the Tutorial** \n[](https://youtu.be/GUfUzls_9yI?si=XgjiMw9tysyNb6TQ)\n\n\nBuild a complete autonomous research engine inside n8n that behaves like a small AI research team.\nThis workflow uses Groq (Llama 3.3), LangChain Agents, and SerpAPI to collect information, analyze data, fact-check content, and generate a polished, citation-backed report.\n\n\u2699\ufe0f How It Works\n\nA form collects the research topic, depth, and output format.\n\nA Research Agent generates targeted search queries.\n\nSerpAPI fetches real-time results from the web.\n\nAll findings are aggregated and structured for processing.\n\nA Writer Agent creates the first draft based on collected data.\n\nA Fact-Checker Agent verifies statements against the source material.\n\nAn Editor Agent improves tone, structure, and clarity.\n\nA PM Agent consolidates everything into a final research report.\n\n\ud83d\udcbc Use Cases\n\nResearch automation for teams and freelancers\n\nLong-form content creation with verified sources\n\nKnowledge gathering for business, academic, and technical projects\n\nSetup takes less than 10 minutes. Add your Groq API key, SerpAPI key, and run your first research request directly from the form.\n\n\ud83d\udd17 Created by: Muhammad Shaheer\n\ud83d\udca1 YouTube Channel: https://www.youtube.com/@ShaheerAutomation\n\n\ud83d\udce7 For collaborations: shaheerawan001@gmail.com\n\n\ud83d\udd17 LinkedIn: www.linkedin.com/in/muhammad-shaheer-898513192"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "ae9f79cb-7558-4487-97fa-5fbef8907600",
"connections": {
"Code": {
"main": [
[]
]
},
"SERP Search": {
"main": [
[
{
"node": "Merge Research",
"type": "main",
"index": 0
}
]
]
},
"Editor Agent": {
"main": [
[
{
"node": "Merge All Agents",
"type": "main",
"index": 1
}
]
]
},
"Form Trigger": {
"main": [
[
{
"node": "Parse Form Input",
"type": "main",
"index": 0
}
]
]
},
"Writer Agent": {
"main": [
[
{
"node": "Fact-Checker Agent",
"type": "main",
"index": 0
},
{
"node": "Editor Agent",
"type": "main",
"index": 0
}
]
]
},
"Merge Research": {
"main": [
[
{
"node": "Aggregate Research",
"type": "main",
"index": 0
}
]
]
},
"Return Results": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Groq Chat Model": {
"ai_languageModel": [
[
{
"node": "Fact-Checker Agent",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Editor Agent",
"type": "ai_languageModel",
"index": 0
},
{
"node": "PM Agent - Final Review1",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Writer Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Merge All Agents": {
"main": [
[
{
"node": "PM Agent - Final Review1",
"type": "main",
"index": 0
}
]
]
},
"Parse Form Input": {
"main": [
[
{
"node": "Merge Research",
"type": "main",
"index": 1
},
{
"node": "Research Agent - Plan",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Research": {
"main": [
[
{
"node": "Writer Agent",
"type": "main",
"index": 0
}
]
]
},
"Fact-Checker Agent": {
"main": [
[
{
"node": "Merge All Agents",
"type": "main",
"index": 0
}
]
]
},
"Research Agent - Plan": {
"main": [
[
{
"node": "Extract Search Queries",
"type": "main",
"index": 0
}
]
]
},
"Extract Search Queries": {
"main": [
[
{
"node": "SERP Search",
"type": "main",
"index": 0
}
]
]
},
"PM Agent - Final Review1": {
"main": [
[
{
"node": "Return Results",
"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.
groqApiserpApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This template is designed for creators, researchers, freelance writers, founders, and automation professionals who want a reliable way to generate structured, citation-backed research content without doing manual data collection. Anyone creating blog posts, reports, briefs, or…
Source: https://n8n.io/workflows/11116/ — 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.
My workflow 53. Uses formTrigger, httpRequest, lmChatOpenAi, form. Event-driven trigger; 74 nodes.
Episode 23: UGC with nanobanana. Uses lmChatOpenAi, lmChatOllama, lmChatDeepSeek, lmChatOpenRouter. Event-driven trigger; 74 nodes.
Content - Newsletter Agent. Uses formTrigger, chainLlm, outputParserStructured, httpRequest. Event-driven trigger; 91 nodes.
Content - Newsletter Agent. Uses formTrigger, chainLlm, outputParserStructured, httpRequest. Event-driven trigger; 87 nodes.
This template attempts to replicate OpenAI's DeepResearch feature which, at time of writing, is only available to their pro subscribers.