{
 "name": "[노드 한 장] Structured Output Parser · 샘플 문의 3건을 고정 JSON으로",
 "nodes": [
  {
   "id": "m",
   "name": "Run manually",
   "type": "n8n-nodes-base.manualTrigger",
   "typeVersion": 1,
   "position": [
    0,
    0
   ],
   "parameters": {}
  },
  {
   "id": "s",
   "name": "Sample inquiries",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    220,
    0
   ],
   "parameters": {
    "jsCode": "// 직접 작성한 실습 샘플. 실제 주문/고객 데이터 아님.\nreturn [{\"text\":\"샘플 주문이에요. 파란 머그컵 두 개를 주문하고 싶어요.\",\"expected\":{\"product\":\"파란 머그컵\",\"quantity\":2,\"topic\":\"order\"}},{\"text\":\"샘플 배송 문의: 접이식 우산 3개, 언제 출발하나요?\",\"expected\":{\"product\":\"접이식 우산\",\"quantity\":3,\"topic\":\"shipping\"}},{\"text\":\"샘플 환불 문의입니다. 노트 한 권을 환불하고 싶어요.\",\"expected\":{\"product\":\"노트\",\"quantity\":1,\"topic\":\"refund\"}}].map((x,i)=>({json:{sample:true,no:i+1,...x}}));"
   }
  },
  {
   "id": "c",
   "name": "Basic LLM Chain",
   "type": "@n8n/n8n-nodes-langchain.chainLlm",
   "typeVersion": 1.7,
   "position": [
    460,
    0
   ],
   "parameters": {
    "promptType": "define",
    "hasOutputParser": true,
    "text": "=다음은 직접 작성한 샘플 주문/문의입니다. product는 원문의 상품명 그대로(수량/조사는 제외), quantity는 개수 숫자, topic은 order(주문), shipping(배송), refund(환불) 중 하나로 추출하세요. 원문에 없는 내용은 만들지 마세요.\n원문: {{ $json.text }}",
    "batching": {
     "batchSize": 1
    }
   }
  },
  {
   "id": "lm",
   "name": "OpenAI Chat Model",
   "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
   "typeVersion": 1.2,
   "position": [
    420,
    240
   ],
   "parameters": {
    "model": {
     "__rl": true,
     "mode": "list",
     "value": "gpt-4.1-mini",
     "cachedResultName": "gpt-4.1-mini"
    },
    "options": {
     "temperature": 0
    }
   }
  },
  {
   "id": "p",
   "name": "Structured Output Parser",
   "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
   "typeVersion": 1.3,
   "position": [
    680,
    240
   ],
   "parameters": {
    "schemaType": "manual",
    "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"product\": {\n      \"type\": \"string\"\n    },\n    \"quantity\": {\n      \"type\": \"number\"\n    },\n    \"topic\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"order\",\n        \"shipping\",\n        \"refund\"\n      ]\n    }\n  },\n  \"required\": [\n    \"product\",\n    \"quantity\",\n    \"topic\"\n  ],\n  \"additionalProperties\": false\n}",
    "autoFix": false
   }
  },
  {
   "id": "v",
   "name": "Verify shape and sample facts separately",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    800,
    0
   ],
   "parameters": {
    "jsCode": "const src=$('Sample inquiries').all(); const input=$input.all(); if(input.length!==3)throw Error('Expected 3 actual outputs'); return input.map((it,i)=>{const s=src[it.pairedItem?.item??i].json; const o=it.json.text??it.json.output??it.json; const shape=typeof o.product==='string'&&typeof o.quantity==='number'&&['order','shipping','refund'].includes(o.topic)&&Object.keys(o).sort().join(',')==='product,quantity,topic'; const match=o.product===s.expected.product&&o.quantity===s.expected.quantity&&o.topic===s.expected.topic; return {json:{sample:true,no:s.no,sourceText:s.text,result:o,schemaValid:shape,sampleFactMatch:match},pairedItem:{item:i}};});"
   }
  }
 ],
 "connections": {
  "Run manually": {
   "main": [
    [
     {
      "node": "Sample inquiries",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Sample inquiries": {
   "main": [
    [
     {
      "node": "Basic LLM Chain",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Basic LLM Chain": {
   "main": [
    [
     {
      "node": "Verify shape and sample facts separately",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "OpenAI Chat Model": {
   "ai_languageModel": [
    [
     {
      "node": "Basic LLM Chain",
      "type": "ai_languageModel",
      "index": 0
     }
    ]
   ]
  },
  "Structured Output Parser": {
   "ai_outputParser": [
    [
     {
      "node": "Basic LLM Chain",
      "type": "ai_outputParser",
      "index": 0
     }
    ]
   ]
  }
 },
 "settings": {
  "timezone": "Asia/Seoul",
  "executionOrder": "v1"
 },
 "meta": {
  "templateCredsSetupCompleted": false,
  "source": "datapopcorn.ai/workflow/nodes"
 }
}