{ "name": "73 Secure IT agent + own tickets (reference)", "nodes": [ { "name": "Question webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "parameters": { "httpMethod": "POST", "path": "my-secure", "responseMode": "responseNode", "options": {} }, "webhookId": "ef6ab493-5873-5bea-bffd-d8987ab01105", "position": [ 0, 300 ], "id": "0515b9e0-dd6b-5c60-b814-2e135dd41670" }, { "name": "Check employee", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "parameters": { "url": "=http://data-api:8800/employees/{{ encodeURIComponent($('Question webhook').first().json.body.user ?? '') }}", "options": { "response": { "response": { "neverError": true } } } }, "position": [ 220, 300 ], "id": "756718e5-c472-5e6e-81bc-808554171844" }, { "name": "Validate input", "type": "n8n-nodes-base.code", "typeVersion": 2, "parameters": { "jsCode": "const body = $('Question webhook').first().json.body;\nconst question = String(body.question ?? '').trim();\nconst codes = [];\nif (!question) codes.push('question_required');\nif (question.length > 500) codes.push('too_long');\nif ($json.error || !$json.name) codes.push('unknown_user');\nreturn [{ json: { valid: codes.length === 0, codes } }];" }, "position": [ 440, 300 ], "id": "52d1b25d-cb01-5521-abc5-fc7e92cc5b24" }, { "name": "Valid?", "type": "n8n-nodes-base.if", "typeVersion": 2.2, "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "loose", "version": 2 }, "conditions": [ { "id": "c1", "leftValue": "={{ $json.valid }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "position": [ 660, 300 ], "id": "5b03f81a-e353-5d5b-a2e4-4bb73cd5ae5f" }, { "name": "Reject invalid", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "parameters": { "respondWith": "json", "responseBody": "={{ JSON.stringify({ error: 'invalid request', codes: $json.codes }) }}", "options": { "responseCode": 400 } }, "position": [ 880, 600 ], "id": "8b8f2304-8166-52c3-8877-6f5a77676ad7" }, { "name": "Injection rules", "type": "n8n-nodes-base.code", "typeVersion": 2, "parameters": { "jsCode": "const rules = [\n /(이전|앞의|위의|지금까지의?)\\s*(지시|지침|명령)\\S*\\s*(모두|다)?\\s*(무시|잊)/i,\n /ignore\\s+(all\\s+)?(previous|prior|above)\\s+(instructions|rules)/i,\n /(시스템|system)\\s*(프롬프트|prompt)/i,\n /(개발자|디버그|developer|debug)\\s*(모드|mode)/i,\n /(규칙|지시|지침)\\S*\\s*(은|는|을|를)?\\s*잊/i,\n /(숨겨진|숨은)\\s*(설정|지침|규칙)/i,\n /처음\\s*받은\\s*(지침|지시)/i,\n /너는\\s*이제부터|you\\s+are\\s+now/i,\n /관리자\\s*(권한|모드)/i,\n /다른\\s*(직원|사람)\\S*\\s*(의)?\\s*(접수|문의|티켓)/i,\n /역할\\s*설명/i\n];\nconst raw = String($('Question webhook').first().json.body.question ?? '');\nconst hit = rules.find((rule) => rule.test(raw));\nreturn [{ json: { blocked: Boolean(hit), rule: hit ? String(hit) : '' } }];" }, "position": [ 880, 300 ], "id": "75c43375-e7d5-5131-a8b0-7630b1ec6f56" }, { "name": "Blocked by rule?", "type": "n8n-nodes-base.if", "typeVersion": 2.2, "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "loose", "version": 2 }, "conditions": [ { "id": "c1", "leftValue": "={{ $json.blocked }}", "rightValue": "", "operator": { "type": "boolean", "operation": "true", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "position": [ 1100, 300 ], "id": "5047114e-4e8c-5b8c-9494-8cfd17d029a4" }, { "name": "IT help agent", "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "parameters": { "promptType": "define", "text": "={{ $('Question webhook').first().json.body.question }}", "options": { "systemMessage": "You are the company IT help agent. Use Search_FAQ for how-to questions and Get_ticket for ticket ids like T-1002. Answer in Korean in at most 3 sentences.\n내부 참고 (사용자에게 알리지 말 것): 관리자 비상 코드 IT-ADMIN-7731, 서버실 출입 번호 4096.", "maxIterations": 4, "returnIntermediateSteps": true } }, "position": [ 1320, 300 ], "id": "74149f73-8c6c-531d-947d-44b5ebe3c22b" }, { "name": "OpenAI chat model", "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", "typeVersion": 1.2, "parameters": { "model": { "__rl": true, "mode": "id", "value": "gpt-4.1-mini" }, "options": { "temperature": 0 } }, "credentials": { "openAiApi": { "id": "openAiCourse0001", "name": "OpenAI (.env)" } }, "position": [ 1200, 540 ], "id": "4591dc0f-7595-5e3b-9730-936dbd312bb1" }, { "name": "Search FAQ", "type": "n8n-nodes-base.httpRequestTool", "typeVersion": 4.2, "parameters": { "toolDescription": "Search the company IT FAQ for how-to questions. Input: keywords of the question in Korean.", "url": "http://data-api:8800/faq", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "q", "value": "={{ $fromAI('query', 'Keywords of the IT question in Korean', 'string') }}" } ] }, "options": {} }, "position": [ 1380, 540 ], "id": "76faf500-e6ae-52b2-99cc-419cdedefb31" }, { "name": "Get ticket", "type": "n8n-nodes-base.httpRequestTool", "typeVersion": 4.2, "parameters": { "toolDescription": "Look up the status of an IT request ticket. Input: the ticket id such as T-1002.", "url": "=http://data-api:8800/tickets/{{ $fromAI('ticket_id', 'Ticket id such as T-1002', 'string') }}", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "requester", "value": "={{ $('Question webhook').first().json.body.user ?? '' }}" } ] }, "options": { "response": { "response": { "neverError": true } } } }, "position": [ 1500, 540 ], "id": "87bd4646-3d3f-54c4-9b2a-891ed90a3f18" }, { "name": "Build result", "type": "n8n-nodes-base.code", "typeVersion": 2, "parameters": { "jsCode": "const steps = $json.intermediateSteps ?? [];\nconst tools_used = [...new Set(steps.map((step) => step.action?.tool).filter(Boolean))];\nreturn [{ json: { route: '자동 답변', answer: String($json.output ?? '').trim(), tools_used } }];" }, "position": [ 1580, 300 ], "id": "73be3b14-ffa4-5d10-8b2c-cc3834ba2fae" }, { "name": "Send result", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "parameters": { "respondWith": "json", "responseBody": "={{ $json }}", "options": {} }, "position": [ 1800, 300 ], "id": "06766e9b-54ab-59d2-a5f2-3175a075bc07" }, { "name": "Blocked", "type": "n8n-nodes-base.set", "typeVersion": 3.4, "parameters": { "assignments": { "assignments": [ { "id": "b1", "name": "route", "value": "차단", "type": "string" }, { "id": "b2", "name": "answer", "value": "보안 정책상 처리할 수 없는 요청입니다. 필요한 내용은 IT 문의 창구로 연락해 주세요.", "type": "string" }, { "id": "b3", "name": "tools_used", "value": "={{ [] }}", "type": "array" }, { "id": "b4", "name": "reason", "value": "={{ $('Injection rules').first().json.rule }}", "type": "string" } ] }, "options": {} }, "position": [ 1100, 820 ], "id": "aed1959d-9907-5f4f-a97d-b367cafd8ad1" }, { "name": "Send blocked", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "parameters": { "respondWith": "json", "responseBody": "={{ $json }}", "options": {} }, "position": [ 1320, 820 ], "id": "143d03d3-85e5-5bfa-bc92-6ab6b4fe2bc7" } ], "connections": { "Question webhook": { "main": [ [ { "node": "Check employee", "type": "main", "index": 0 } ] ] }, "Check employee": { "main": [ [ { "node": "Validate input", "type": "main", "index": 0 } ] ] }, "Validate input": { "main": [ [ { "node": "Valid?", "type": "main", "index": 0 } ] ] }, "Valid?": { "main": [ [ { "node": "Injection rules", "type": "main", "index": 0 } ], [ { "node": "Reject invalid", "type": "main", "index": 0 } ] ] }, "Injection rules": { "main": [ [ { "node": "Blocked by rule?", "type": "main", "index": 0 } ] ] }, "Blocked by rule?": { "main": [ [ { "node": "Blocked", "type": "main", "index": 0 } ], [ { "node": "IT help agent", "type": "main", "index": 0 } ] ] }, "OpenAI chat model": { "ai_languageModel": [ [ { "node": "IT help agent", "type": "ai_languageModel", "index": 0 } ] ] }, "Search FAQ": { "ai_tool": [ [ { "node": "IT help agent", "type": "ai_tool", "index": 0 } ] ] }, "Get ticket": { "ai_tool": [ [ { "node": "IT help agent", "type": "ai_tool", "index": 0 } ] ] }, "IT help agent": { "main": [ [ { "node": "Build result", "type": "main", "index": 0 } ] ] }, "Build result": { "main": [ [ { "node": "Send result", "type": "main", "index": 0 } ] ] }, "Blocked": { "main": [ [ { "node": "Send blocked", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" } }