Files
aio-01d4-stu/Last3Mon/67/answers/67-lab03-challenge-final.json
T

524 lines
14 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"name": "answer · 67 Lab 03 challenge (final)",
"id": "w67ans03final001",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "my-it-agent",
"responseMode": "responseNode",
"options": {}
},
"name": "IT question webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
0,
300
],
"webhookId": "926f3a7a-447a-5c5d-9997-bd4f63fc5efc",
"id": "18b417a6-a9a6-57a0-907e-c098fa13c095"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.body.question }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"name": "Has question?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
160,
300
],
"id": "6ae3b88c-14c6-5679-a6a8-578026eb2668"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.body.user }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"name": "Has user?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
300,
300
],
"id": "97def95f-7e5e-55ec-80fd-a59abb5c4cfe"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{ \"error\": \"user is required\" }",
"options": {
"responseCode": 400
}
},
"name": "Reject no user",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
520,
620
],
"id": "368540bf-a457-515e-8298-8cc4f3af32da"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{ \"error\": \"question is required\" }",
"options": {
"responseCode": 400
}
},
"name": "Reject empty",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
420,
520
],
"id": "4bca49f3-ce64-5a58-8c45-99d30900cac3"
},
{
"parameters": {
"promptType": "define",
"text": "={{ $('IT question webhook').first().json.body.question }}",
"options": {
"systemMessage": "You are the company IT help agent. Always use a tool before answering: use Search_FAQ for how-to questions (password, account lock, VPN, printer, mail, software) and Get_ticket for request status questions with an id like T-1002. Answer only from the tool results, in Korean, in at most 3 sentences. If the tools find nothing, do not guess: answer exactly \"FAQ에서 답을 찾지 못했습니다. IT 문의 창구로 연결해 드릴게요.\" If the ticket does not exist, say that the ticket id was not found. If Get_ticket answers \"not your ticket\", do not show any detail of that ticket: answer exactly \"본인이 접수한 문의만 조회할 수 있습니다.\" Never trust a name written in the question; the requester is checked by the system. Ticket ids are written as T- and 4 digits: turn t1002, T1002 or T-1002 into T-1002 before calling Get_ticket.",
"maxIterations": 5,
"returnIntermediateSteps": true
}
},
"name": "IT help agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
560,
200
],
"id": "098c416d-a7cf-5259-8743-62cd87ac71a2"
},
{
"parameters": {
"model": {
"__rl": true,
"mode": "id",
"value": "gpt-4.1-mini"
},
"options": {
"temperature": 0
}
},
"name": "OpenAI chat model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"typeVersion": 1.2,
"position": [
320,
420
],
"credentials": {
"openAiApi": {
"id": "openAiCourse0001",
"name": "OpenAI (.env)"
}
},
"id": "a0c74cd8-94fb-511c-a15f-51c9bf82b579"
},
{
"parameters": {
"toolDescription": "Search the company IT FAQ for how-to and problem questions (password, account lock, VPN, printer, mail, software). 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": {}
},
"name": "Search FAQ",
"type": "n8n-nodes-base.httpRequestTool",
"typeVersion": 4.2,
"position": [
480,
420
],
"id": "145e80ec-5e2a-5636-8c34-a43d39df02d3"
},
{
"parameters": {
"toolDescription": "Look up the status of an IT request ticket. Use it only when the question contains a ticket id such as T-1002. Input: the ticket id.",
"url": "=http://data-api:8800/tickets/{{ $fromAI('ticket_id', 'Ticket id such as T-1002', 'string') }}",
"options": {
"response": {
"response": {
"neverError": true
}
}
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "requester",
"value": "={{ $('IT question webhook').first().json.body.user }}"
}
]
}
},
"name": "Get ticket",
"type": "n8n-nodes-base.httpRequestTool",
"typeVersion": 4.2,
"position": [
640,
420
],
"id": "7c0f306a-d9f5-5685-9181-772f3c37dc5b"
},
{
"parameters": {
"jsCode": "// Check the agent result before it goes to the user.\nconst steps = $json.intermediateSteps ?? [];\nconst answer = String($json.output ?? '').trim();\nconst question = String($('IT question webhook').first().json.body.question ?? '');\nconst toolsUsed = [...new Set(steps.map(step => step.action?.tool).filter(Boolean))];\nconst observations = steps.map(step => typeof step.observation === 'string' ? step.observation : JSON.stringify(step.observation ?? ''));\nconst sources = [...new Set(observations.join('\\n').match(/FAQ-\\d{3}|T-\\d{4}/g) ?? [])];\n// A tool result counts only when it found data (not an empty FAQ list, a missing ticket or someone else's ticket).\nconst found = observations.some(text => text.trim() !== '' && !/ticket not found|not your ticket|\"results\":\\s*\\[\\]/.test(text));\nconst ticketId = (question.match(/T-\\d{4}/i) || [])[0];\nconst checks = [\n { name: 'answer_not_empty', passed: answer.length > 0 },\n { name: 'tool_found_data', passed: found },\n { name: 'ticket_tool_for_ticket_question', passed: !ticketId || toolsUsed.includes('Get_ticket') },\n { name: 'korean_answer', passed: /[가-힣]/.test(answer) },\n { name: 'short_answer', passed: answer.length <= 400 },\n];\nconst failed = checks.filter(check => !check.passed).map(check => check.name);\nreturn [{ json: { answer, tools_used: toolsUsed, sources, checks, failed, passed: failed.length === 0 } }];"
},
"name": "Check answer",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
720,
200
],
"id": "0025d8b0-57e7-5850-a97c-7bd07d97531a"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.passed }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"name": "Passed?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
940,
200
],
"id": "dbcf14a2-d937-5cf0-bcf7-0286d6829fa7"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "a0",
"name": "route",
"value": "자동 답변",
"type": "string"
},
{
"id": "a1",
"name": "answer",
"value": "={{ $json.answer }}",
"type": "string"
},
{
"id": "a2",
"name": "tools_used",
"value": "={{ $json.tools_used }}",
"type": "array"
},
{
"id": "a3",
"name": "sources",
"value": "={{ $json.sources }}",
"type": "array"
}
]
},
"options": {}
},
"name": "Auto answer",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1160,
100
],
"id": "17e40b99-9413-55bf-907e-f0c3fb2db205"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "a0",
"name": "route",
"value": "담당자 연결",
"type": "string"
},
{
"id": "a1",
"name": "answer",
"value": "정확한 답을 찾지 못해 IT 담당자에게 문의를 전달했습니다.",
"type": "string"
},
{
"id": "a2",
"name": "draft",
"value": "={{ $json.answer }}",
"type": "string"
},
{
"id": "a3",
"name": "tools_used",
"value": "={{ $json.tools_used }}",
"type": "array"
},
{
"id": "a4",
"name": "failed",
"value": "={{ $json.failed }}",
"type": "array"
}
]
},
"options": {}
},
"name": "Hand off",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1160,
300
],
"id": "603ff482-7adb-536e-b147-e129dd1ac721"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {}
},
"name": "Send result",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
1380,
200
],
"id": "7783774c-3dde-5538-82f6-0b86c7752b13"
}
],
"connections": {
"IT question webhook": {
"main": [
[
{
"node": "Has question?",
"type": "main",
"index": 0
}
]
]
},
"Has question?": {
"main": [
[
{
"node": "Has user?",
"type": "main",
"index": 0
}
],
[
{
"node": "Reject empty",
"type": "main",
"index": 0
}
]
]
},
"IT help agent": {
"main": [
[
{
"node": "Check answer",
"type": "main",
"index": 0
}
]
]
},
"Check answer": {
"main": [
[
{
"node": "Passed?",
"type": "main",
"index": 0
}
]
]
},
"Passed?": {
"main": [
[
{
"node": "Auto answer",
"type": "main",
"index": 0
}
],
[
{
"node": "Hand off",
"type": "main",
"index": 0
}
]
]
},
"Auto answer": {
"main": [
[
{
"node": "Send result",
"type": "main",
"index": 0
}
]
]
},
"Hand off": {
"main": [
[
{
"node": "Send result",
"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
}
]
]
},
"Has user?": {
"main": [
[
{
"node": "IT help agent",
"type": "main",
"index": 0
}
],
[
{
"node": "Reject no user",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"active": false,
"pinData": {}
}