{ "name": "answer · 71 Lab 03 challenge (rewrite query)", "nodes": [ { "name": "Search webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [ 0, 300 ], "parameters": { "httpMethod": "POST", "path": "my-search", "responseMode": "responseNode", "options": {} } }, { "name": "Has question?", "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ 200, 300 ], "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 2 }, "conditions": [ { "id": "c0", "leftValue": "={{ $json.body.question }}", "rightValue": "", "operator": { "type": "string", "operation": "notEmpty", "singleValue": true } } ], "combinator": "and" }, "options": {} } }, { "name": "Reject empty", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [ 420, 560 ], "parameters": { "respondWith": "json", "responseBody": "{ \"error\": \"question is required\" }", "options": { "responseCode": 400 } } }, { "name": "Rewrite query", "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "position": [ 420, 140 ], "parameters": { "promptType": "define", "text": "={{ $('Search webhook').first().json.body.question }}", "options": { "systemMessage": "You rewrite an employee's question into a short search query for company IT policy documents, in Korean. Use the words a policy document would use (for example 암호·비번 → 비밀번호, 와이파이 → 공용 와이파이, 그만두면 → 퇴사, 깔다 → 설치, 챗GPT·제미나이·클로드 → 생성형 AI 서비스, 개인 메일로 보내다 → 외부로 보내다 · 첨부 파일, 폰 → 휴대폰). If the question has two topics, keep the topic about what to do with data or files. Keep numbers and names. Return only the query, one line.", "maxIterations": 2 } } }, { "name": "Rewrite model", "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", "typeVersion": 1.2, "position": [ 380, -60 ], "parameters": { "model": { "__rl": true, "mode": "id", "value": "gpt-4.1-mini" }, "options": { "temperature": 0 } }, "credentials": { "openAiApi": { "id": "openAiCourse0001", "name": "OpenAI (.env)" } } }, { "name": "Search policies", "type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory", "typeVersion": 1.3, "position": [ 640, 300 ], "parameters": { "mode": "load", "memoryKey": { "__rl": true, "mode": "list", "value": "my_policy_docs", "cachedResultName": "my_policy_docs" }, "prompt": "={{ $json.output }}", "topK": "={{ $('Search webhook').first().json.body.top_k ?? 3 }}", "includeDocumentMetadata": true }, "alwaysOutputData": true }, { "name": "Embeddings", "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi", "typeVersion": 1.2, "position": [ 560, 520 ], "parameters": { "model": "text-embedding-3-large", "options": {} }, "credentials": { "openAiApi": { "id": "openAiCourse0001", "name": "OpenAI (.env)" } } }, { "name": "Build hits", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 860, 300 ], "parameters": { "jsCode": "// The search contract: { question, hits: [{ rank, source, title, section, score, text }], top_score, indexed }.\n// Always Output Data is on, so an empty store still gives one empty item: keep only items that have a document.\nconst question = $('Search webhook').first().json.body.question;\nconst hits = $input.all().filter(item => item.json.document).map((item, i) => ({\n rank: i + 1, source: item.json.document.metadata?.source, title: item.json.document.metadata?.title, section: item.json.document.metadata?.section ?? '',\n score: Math.round((item.json.score ?? 0) * 1000) / 1000, text: item.json.document.pageContent ?? '' }));\nreturn [{ json: { question, query: $('Rewrite query').first().json.output, hits, top_score: hits.length ? Math.max(...hits.map(hit => hit.score)) : 0, indexed: hits.length > 0 } }];" } }, { "name": "Send result", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [ 1080, 300 ], "parameters": { "respondWith": "json", "responseBody": "={{ $json }}", "options": {} } } ], "connections": { "Search webhook": { "main": [ [ { "node": "Has question?", "type": "main", "index": 0 } ] ] }, "Has question?": { "main": [ [ { "node": "Rewrite query", "type": "main", "index": 0 } ], [ { "node": "Reject empty", "type": "main", "index": 0 } ] ] }, "Rewrite model": { "ai_languageModel": [ [ { "node": "Rewrite query", "type": "ai_languageModel", "index": 0 } ] ] }, "Rewrite query": { "main": [ [ { "node": "Search policies", "type": "main", "index": 0 } ] ] }, "Embeddings": { "ai_embedding": [ [ { "node": "Search policies", "type": "ai_embedding", "index": 0 } ] ] }, "Search policies": { "main": [ [ { "node": "Build hits", "type": "main", "index": 0 } ] ] }, "Build hits": { "main": [ [ { "node": "Send result", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" } }