基于动态提示与Airtable의AI데이터추출
고급
이것은AI분야의자동화 워크플로우로, 51개의 노드를 포함합니다.주로 Set, Code, Filter, Switch, Webhook 등의 노드를 사용하며인공지능 기술을 결합하여 스마트 자동화를 구현합니다. 통해动态提示与Airtable实现AI데이터추출
사전 요구사항
- •HTTP Webhook 엔드포인트(n8n이 자동으로 생성)
- •Airtable API Key
- •대상 API의 인증 정보가 필요할 수 있음
- •OpenAI API Key
사용된 노드 (51)
카테고리
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
"nodes": [
{
"id": "36816ae7-414a-482e-8a50-021885237273",
"name": "Event Type",
"type": "n8n-nodes-base.switch",
"position": [
-220,
-140
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "row.updated",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2162daf8-d23d-4b8f-8257-bdfc5400a3a8",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.event_type }}",
"rightValue": "row.updated"
}
]
},
"renameOutput": true
},
{
"outputKey": "field.created",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "48e112f6-afe8-40bf-b673-b37446934a62",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.event_type }}",
"rightValue": "field.created"
}
]
},
"renameOutput": true
},
{
"outputKey": "field.updated",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "5aa258cd-15c2-4156-a32d-afeed662a38e",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.event_type }}",
"rightValue": "field.updated"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "920ca6d8-7a6e-4482-b003-fa643f550a85",
"name": "Get Prompt Fields",
"type": "n8n-nodes-base.code",
"position": [
-900,
-140
],
"parameters": {
"jsCode": "const fields = $input.first().json.fields\n .filter(item => item.description)\n .map((item, idx) => ({\n id: item.id,\n order: idx,\n name: item.name,\n type: item.type,\n description: item.description,\n }));\n\nreturn { json: { fields } };"
},
"typeVersion": 2
},
{
"id": "3b73b2f5-9081-4633-911f-ef3041600a00",
"name": "Get File Data",
"type": "n8n-nodes-base.httpRequest",
"position": [
1220,
320
],
"parameters": {
"url": "={{ $json.File[0].url }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "e96edca8-9e8b-4ca4-bef9-dae673d3aba4",
"name": "파일에서 추출",
"type": "n8n-nodes-base.extractFromFile",
"position": [
1380,
320
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "b5c2b87b-5756-4810-84c9-34ea420bdcef",
"name": "Get Result",
"type": "n8n-nodes-base.set",
"position": [
2000,
380
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "63d7c52e-d5bf-4f4c-9e37-1d5feaea20f4",
"name": "id",
"type": "string",
"value": "={{ $('Row Reference').item.json.id }}"
},
{
"id": "3ad72567-1d17-4910-b916-4c34a43b1060",
"name": "={{ $('Event Ref').first().json.field.name }}",
"type": "string",
"value": "={{ $json.text.trim() }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a5cb0510-620b-469d-bf66-26ab64d6f88f",
"name": "항목 반복",
"type": "n8n-nodes-base.splitInBatches",
"position": [
800,
220
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "20e24946-59d8-4b19-bfab-eebb02f7e46d",
"name": "Row Reference",
"type": "n8n-nodes-base.noOp",
"position": [
980,
320
],
"parameters": {},
"typeVersion": 1
},
{
"id": "4090c53e-e635-4421-ab2b-475bfc62cea4",
"name": "Generate Field Value",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1540,
320
],
"parameters": {
"text": "=<file>\n{{ $json.text }}\n</file>\n\nData to extract: {{ $('Event Ref').first().json.field.description }}\noutput format is: {{ $('Event Ref').first().json.field.type }}",
"messages": {
"messageValues": [
{
"message": "=You assist the user in extracting the required data from the given file.\n* Keep you answer short.\n* If you cannot extract the requested data, give you response as \"n/a\"."
}
]
},
"promptType": "define"
},
"typeVersion": 1.5
},
{
"id": "582d4008-4871-4798-bc24-abf774ad29b5",
"name": "Fields to Update",
"type": "n8n-nodes-base.code",
"position": [
1560,
-300
],
"parameters": {
"jsCode": "const row = $('Row Ref').first().json;\nconst fields = $('Get Prompt Fields').first().json.fields;\nconst missingFields = fields\n .filter(field => field.description && !row[field.name]);\n\nreturn missingFields;"
},
"typeVersion": 2
},
{
"id": "051c6a99-cec3-42df-9de7-47cb69b51682",
"name": "항목 반복1",
"type": "n8n-nodes-base.splitInBatches",
"position": [
820,
-420
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "f559c8ff-2ee5-478d-84ee-6b0ca2fe2050",
"name": "Row Ref",
"type": "n8n-nodes-base.noOp",
"position": [
1000,
-300
],
"parameters": {},
"typeVersion": 1
},
{
"id": "7b82cc73-67cb-46d7-a1d4-19712c86890a",
"name": "Get File Data1",
"type": "n8n-nodes-base.httpRequest",
"position": [
1240,
-300
],
"parameters": {
"url": "={{ $('Row Ref').item.json.File[0].url }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "7ef1556c-96a3-4988-982d-ec8c5fba4601",
"name": "파일에서 추출1",
"type": "n8n-nodes-base.extractFromFile",
"position": [
1400,
-300
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1
},
{
"id": "9916f1c1-f413-4996-ad45-380a899b4a88",
"name": "Get Result1",
"type": "n8n-nodes-base.set",
"position": [
2120,
-260
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "e376ba60-8692-4962-9af7-466b6a3f44a2",
"name": "={{ $('Fields to Update').item.json.name }}",
"type": "string",
"value": "={{ $json.text.trim() }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "f62f612d-c288-4062-ab3c-dbc24c9b4b38",
"name": "Generate Field Value1",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1720,
-300
],
"parameters": {
"text": "=<file>\n{{ $('Extract from File1').first().json.text }}\n</file>\n\nData to extract: {{ $json.description }}\noutput format is: {{ $json.type }}",
"messages": {
"messageValues": [
{
"message": "=You assist the user in extracting the required data from the given file.\n* Keep you answer short.\n* If you cannot extract the requested data, give you response as \"n/a\" followed by \"(reason)\" where reason is replaced with reason why data could not be extracted."
}
]
},
"promptType": "define"
},
"typeVersion": 1.5
},
{
"id": "615f7436-f280-4033-8ec8-a34f1bd78075",
"name": "필터 Valid Rows",
"type": "n8n-nodes-base.filter",
"position": [
520,
-420
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "7ad58f0b-0354-49a9-ab2f-557652d7b416",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.File[0].url }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "281b9fb0-305c-4a0c-b73b-82b6ba876d12",
"name": "필터 Valid Fields",
"type": "n8n-nodes-base.filter",
"position": [
340,
220
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "5b4a7393-788c-42dc-ac1f-e76f833f8534",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.field.description }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "dd0fa792-791f-4d31-a7e8-9b72a25b6a07",
"name": "Event Ref",
"type": "n8n-nodes-base.noOp",
"position": [
160,
220
],
"parameters": {},
"typeVersion": 1
},
{
"id": "ca1174b3-da18-4d3c-86ef-3028cd5b12a7",
"name": "Event Ref1",
"type": "n8n-nodes-base.noOp",
"position": [
160,
-420
],
"parameters": {},
"typeVersion": 1
},
{
"id": "8800b355-0fa8-4297-b13b-d3da8a01c3b7",
"name": "메모",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1180,
-340
],
"parameters": {
"color": 7,
"width": 480,
"height": 440,
"content": "### 1. Get Table Schema\n[Learn more about the Airtable node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.airtable/)\n\nFor this operation, we'll use the handy Airtable node. I recommend getting familiar with this node for all your Airtable needs!\n"
},
"typeVersion": 1
},
{
"id": "a90876d3-8a93-4d90-9e2a-f23de452259d",
"name": "메모1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-260,
-440
],
"parameters": {
"color": 5,
"width": 330,
"height": 80,
"content": "### 2a. Updates Minimal Number of Rows\nThis branch updates only the rows impacted."
},
"typeVersion": 1
},
{
"id": "319adf97-8b14-4069-b4cc-594a6ea479c1",
"name": "메모2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-320,
140
],
"parameters": {
"color": 5,
"width": 390,
"height": 120,
"content": "### 2b. Update Every Row under the Field\nThis branch updates all applicable rows under field when the field/column is created or changed. Watch out - if you have 1000s of rows, this could take a while!"
},
"typeVersion": 1
},
{
"id": "42a60c8c-476f-4930-bac5-4d36a7185f4f",
"name": "메모3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2240,
-1000
],
"parameters": {
"width": 520,
"height": 1120,
"content": "## Try It Out!\n### This n8n template powers a \"dynamic\" or \"user-defined\" prompts with PDF workflow pattern for a [Airtable](https://airtable.com/invite/r/cKzxFYVc) table. Simply put, it allows users to populate a spreadsheet using prompts without touching the underlying template.\n\n**Check out the video demo I did for n8n Studio**: https://www.youtube.com/watch?v=_fNAD1u8BZw\n\n**Check out the example Airtable here:** https://airtable.com/appAyH3GCBJ56cfXl/shrXzR1Tj99kuQbyL\n\nThis template is intended to be used as a webhook source for Airtable. **Looking for a Baserow version? [Click here](https://n8n.io/workflows/2780-ai-data-extraction-with-dynamic-prompts-and-baserow)**\n\n## How it works\n* Each Airtable.io tables offers integration feature whereby changes to the table can be sent as events to any accessible webhook. This allows for a reactive trigger pattern which makes this type of workflow possible. For our usecase, we capture the vents of `row_updated`, `field_created` and `field_updated`.\n* Next, we'll need an \"input\" column in our Airtable.io table. This column will be where our context lives for evaluating the prompts against. In this example, our \"input\" column name is \"file\" and it's where we'll upload our PDFs. Note, this \"input\" field is human-controlled and never updated from this template.\n* Now for the columns (aka \"fields\" in Airtable). Each field allows us to define a name, type and description and together form the schema. The first 2 are self-explaintory but the \"description\" will be for users to provide their prompts ie. what data should the field to contain.\n* In this template, a webhook trigger waits for when a row or column is updated. The incoming event comes with lots of details such as the table, row and/or column Ids that were impacted.\n* We use this information to fetch the table's schema in order to get the column's descriptions (aka dynamic prompts).\n* For each triggered event, we download our input ie. the PDF and ready it for our AI/LLM. By iterating through the available columns and feeding the dynamic prompts, our LLM can run those prompts against the PDF and thus generating a value response for each cell.\n* These values are then collected and used to update the Airtable Record.\n\n## How to use\n* You'll need to publish this workflow and make it accessible to our Airtable instance.\n* you must run the \"Create Airtable Webhooks\" mini-flow to link it to your Airtable.\n* This template is reusable for other Airtables but the webhooks need to be created each time for each table.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Flowgramming!"
},
"typeVersion": 1
},
{
"id": "c6d037e9-1bf7-47a7-9c46-940220e0786b",
"name": "메모4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-680,
-340
],
"parameters": {
"color": 7,
"width": 760,
"height": 440,
"content": "### 2. Event Router Pattern\n[Learn more about the Switch node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.switch/)\n\nA simple switch node can be used to determine which event to handle. The difference between our row and field events is that row event affect a single row whereas field events affect all rows. \n"
},
"typeVersion": 1
},
{
"id": "897cec32-3a4c-4a76-bffe-b1456c287b44",
"name": "메모5",
"type": "n8n-nodes-base.stickyNote",
"position": [
100,
-620
],
"parameters": {
"color": 7,
"width": 620,
"height": 400,
"content": "### 3. Filter Only Rows with Valid Input\n[Learn more about the Split Out node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.splitout/)\n\nThis step handles one or more updated rows where \"updated\" means the \"input\" column (ie. \"file\" in our example) for these rows were changed. For each affected row, we'll get the full row to figure out only the columns we need to update - this is an optimisation to avoid redundant work ie. generating values for columns which already have a value."
},
"typeVersion": 1
},
{
"id": "a5999ca3-4418-42c5-aa1c-fbdfb1c04fef",
"name": "메모7",
"type": "n8n-nodes-base.stickyNote",
"position": [
2060,
-480
],
"parameters": {
"color": 7,
"width": 600,
"height": 440,
"content": "### 6. Update the Airtable Record\n[Learn more about the Edit Fields node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.set/)\n\nFinally, we can collect the LLM responses and combine them to build an API request to update our Airtable record - the Id of which we got from initial webhook. After this is done, we can move onto the next row and repeat the process.\n"
},
"typeVersion": 1
},
{
"id": "38192929-a387-4240-8373-290499b40e5a",
"name": "메모8",
"type": "n8n-nodes-base.stickyNote",
"position": [
1180,
-580
],
"parameters": {
"color": 7,
"width": 860,
"height": 580,
"content": "### 5. PDFs, LLMs and Dynamic Prompts? Oh My!\n[Learn more about the Basic LLM node](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.chainllm/)\n\nThis step is where it all comes together! In short, we give our LLM the PDF contents as the context and loop through our dynamic prompts (from the schema we pulled earlier) for our row. At the end, our LLM should have produced a value for each column requested.\n\n**Note**: There's definitely a optimisation which could be done for caching PDFs but it beyond the scope of this demonstration.\n"
},
"typeVersion": 1
},
{
"id": "19a9b93a-d18f-4ffd-ae93-ed41cf398e90",
"name": "메모9",
"type": "n8n-nodes-base.stickyNote",
"position": [
740,
-580
],
"parameters": {
"color": 7,
"width": 420,
"height": 460,
"content": "### 4. Using an Items Loop\n[Learn more about the Split in Batches node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.splitinbatches/)\n\nA split in batches node is used here to update a row at a time however, this is a preference for user experience - changes are seen in the Airtable quicker.\n"
},
"typeVersion": 1
},
{
"id": "5407fead-ee7c-47c8-94ed-5b89e74e50e8",
"name": "메모10",
"type": "n8n-nodes-base.stickyNote",
"position": [
100,
40
],
"parameters": {
"color": 7,
"width": 600,
"height": 360,
"content": "### 7. Listing All Applicable Rows Under The Column\n[Learn more about the Filter node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.filter)\n\nTo keep things performant, we can decide to get only rows with inputfield populated as this is required to perform the extraction. This can easily be achieved with Airtable filters."
},
"typeVersion": 1
},
{
"id": "43b0e330-b79a-4577-b4fc-314e8b790cf7",
"name": "메모11",
"type": "n8n-nodes-base.stickyNote",
"position": [
1160,
140
],
"parameters": {
"color": 7,
"width": 700,
"height": 500,
"content": "### 9. Generating Value using LLM\n[Learn more about the Extract From File node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.extractfromfile/)\n\nPretty much identical to Step 5 but instead of updating every field/column, we only need to generate a value for one. \n"
},
"typeVersion": 1
},
{
"id": "0665fe56-48d2-4215-8d95-d4c01f9266ed",
"name": "OpenAI 채팅 모델",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1720,
-140
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1.1
},
{
"id": "1997fb8b-73eb-4016-bab6-eb8f02fee368",
"name": "메모12",
"type": "n8n-nodes-base.stickyNote",
"position": [
720,
40
],
"parameters": {
"color": 7,
"width": 420,
"height": 460,
"content": "### 8. Using an Items Loop\n[Learn more about the Split in Batches node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.splitinbatches/)\n\nSimilar to Step 4, the Split in Batches node is a preference for user experience - changes are seen in the Airtable quicker.\n"
},
"typeVersion": 1
},
{
"id": "c2799ded-b742-43a2-80ce-7a0c8f1df96e",
"name": "OpenAI 채팅 모델1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1540,
500
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"id": "8gccIjcuf3gvaoEr",
"name": "OpenAi account"
}
},
"typeVersion": 1.1
},
{
"id": "e5b42790-fc86-4134-9d04-e6bcad4a5f20",
"name": "메모13",
"type": "n8n-nodes-base.stickyNote",
"position": [
1880,
140
],
"parameters": {
"color": 7,
"width": 500,
"height": 440,
"content": "### 10. Update the Airtable Record\n[Learn more about the Edit Fields node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.set/)\n\nAs with Step 6, the LLM response is used to update the row however only under the field that was created/changed. Once complete, the loop continues and the next row is processed.\n"
},
"typeVersion": 1
},
{
"id": "b1e98631-a440-4c66-b2d2-8236f6889b65",
"name": "메모6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2240,
-1140
],
"parameters": {
"color": 7,
"width": 300,
"height": 120,
"content": "[](https://airtable.com/invite/r/cKzxFYVc)"
},
"typeVersion": 1
},
{
"id": "9d293b3a-954d-4e3b-8773-b6c3dded9520",
"name": "Get Webhook 트리거 Payload",
"type": "n8n-nodes-base.httpRequest",
"position": [
-580,
-140
],
"parameters": {
"url": "=https://api.airtable.com/v0/bases/{{ $('Airtable Webhook').first().json.body.base.id }}/webhooks/{{ $('Airtable Webhook').first().json.body.webhook.id }}/payloads",
"options": {},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "airtableTokenApi"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 4.2
},
{
"id": "5f8d919b-14cd-4cb4-8604-731e56cc9402",
"name": "Parse Event",
"type": "n8n-nodes-base.code",
"position": [
-400,
-140
],
"parameters": {
"jsCode": "const webhook = $('Airtable Webhook').first().json;\nconst schema = $('Get Prompt Fields').first().json;\nconst { payloads } = $input.first().json;\nif (!payloads.length) return [];\n\nconst event = payloads[payloads.length - 1];\nconst baseId = webhook.body.base.id;\nconst tableId = Object.keys(event.changedTablesById)[0];\nconst table = event.changedTablesById[tableId];\n\nreturn {\n baseId,\n tableId,\n event_type: getEventType(table),\n fieldId: getFieldId(table),\n field: getField(getFieldId(table)),\n rowId: getRecordId(table),\n}\n\nfunction getEventType(changedTableByIdObject) {\n if (changedTableByIdObject['createdFieldsById']) return 'field.created';\n if (changedTableByIdObject['changedFieldsById']) return 'field.updated'\n if (changedTableByIdObject['changedRecordsById']) return 'row.updated';\n return 'unknown';\n}\n\nfunction getFieldId(changedTableByIdObject) {\n const field = changedTableByIdObject.createdFieldsById\n || changedTableByIdObject.changedFieldsById\n || null;\n\n return field ? Object.keys(field)[0] : null;\n}\n\nfunction getField(id) {\n return schema.fields.find(field => field.id === id);\n}\n\nfunction getRecordId(changedTableByIdObject) {\n const record = changedTableByIdObject.changedRecordsById\n || null;\n\n return record ? Object.keys(record)[0] : null;\n}"
},
"typeVersion": 2
},
{
"id": "9b99d939-94d6-4fef-8b73-58c702503221",
"name": "Get Table Schema",
"type": "n8n-nodes-base.airtable",
"position": [
-1080,
-140
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "={{ $('Airtable Webhook').item.json.body.base.id }}"
},
"resource": "base",
"operation": "getSchema"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2.1
},
{
"id": "c29fc911-a852-46f2-bbb1-5092cc1aaa9d",
"name": "Fetch Records",
"type": "n8n-nodes-base.airtable",
"position": [
520,
220
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "={{ $json.baseId }}"
},
"table": {
"__rl": true,
"mode": "id",
"value": "={{ $json.tableId }}"
},
"options": {},
"operation": "search",
"filterByFormula": "NOT({File} = \"\")"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2.1
},
{
"id": "86d3c8d8-709f-4d9d-99bc-5d1b4aeb8603",
"name": "Update Row",
"type": "n8n-nodes-base.airtable",
"position": [
2180,
380
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "={{ $('Event Ref').first().json.baseId }}"
},
"table": {
"__rl": true,
"mode": "id",
"value": "={{ $('Event Ref').first().json.tableId }}"
},
"columns": {
"value": {},
"schema": [
{
"id": "id",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "id",
"defaultMatch": true
},
{
"id": "Name",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "File",
"type": "array",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "File",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Full Name",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Full Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Created",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "Created",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Last Modified",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "Last Modified",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Address",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Address",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [
"id"
]
},
"options": {},
"operation": "update"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2.1
},
{
"id": "95d08439-59a2-4e74-bd5a-b71cf079b621",
"name": "Get Row",
"type": "n8n-nodes-base.airtable",
"position": [
340,
-420
],
"parameters": {
"id": "={{ $json.rowId }}",
"base": {
"__rl": true,
"mode": "id",
"value": "={{ $json.baseId }}"
},
"table": {
"__rl": true,
"mode": "id",
"value": "={{ $json.tableId }}"
},
"options": {}
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2.1
},
{
"id": "50888ac5-30c9-4036-aade-6ccfdf605c3b",
"name": "Add Row ID to Payload",
"type": "n8n-nodes-base.set",
"position": [
2300,
-260
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={{\n{\n id: $('Row Ref').item.json.id,\n ...$input.all()\n .map(item => item.json)\n .reduce((acc, item) => ({\n ...acc,\n ...item,\n }), {})\n}\n}}"
},
"executeOnce": true,
"typeVersion": 3.4
},
{
"id": "e3ebeb45-45d9-44a4-a2e6-bde89f5da125",
"name": "Update Record",
"type": "n8n-nodes-base.airtable",
"position": [
2480,
-260
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "={{ $('Event Ref1').first().json.baseId }}"
},
"table": {
"__rl": true,
"mode": "id",
"value": "={{ $('Event Ref1').first().json.tableId }}"
},
"columns": {
"value": {},
"schema": [
{
"id": "id",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "id",
"defaultMatch": true
},
{
"id": "Name",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "File",
"type": "array",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "File",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Full Name",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Full Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Address",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Address",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Created",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "Created",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Last Modified",
"type": "string",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "Last Modified",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [
"id"
]
},
"options": {},
"operation": "update"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2.1
},
{
"id": "ac01ec4b-e030-4608-af38-64558408832f",
"name": "Airtable Webhook 트리거",
"type": "n8n-nodes-base.webhook",
"position": [
-1400,
-140
],
"webhookId": "a82f0ae7-678e-49d9-8219-7281e8a2a1b2",
"parameters": {
"path": "a82f0ae7-678e-49d9-8219-7281e8a2a1b2",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2
},
{
"id": "90178da9-2000-474e-ba93-a02d03ec6a1d",
"name": "클릭 시 ‘Test workflow’",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1600,
-640
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b8b887ce-f891-4a3c-993b-0aaccadf1b52",
"name": "설정 Airtable Vars",
"type": "n8n-nodes-base.set",
"position": [
-1420,
-640
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "012cb420-1455-4796-a2ac-a31e6abf59ba",
"name": "appId",
"type": "string",
"value": "<MY_BASE_ID>"
},
{
"id": "e863b66c-420f-43c6-aee2-43aa5087a0a5",
"name": "tableId",
"type": "string",
"value": "<MY_TABLE_ID>"
},
{
"id": "e470be1a-5833-47ed-9e2f-988ef5479738",
"name": "notificationUrl",
"type": "string",
"value": "<MY_WEBHOOK_URL>"
},
{
"id": "e4b3213b-e3bd-479b-99ec-d1aa31eaa4c8",
"name": "inputField",
"type": "string",
"value": "File"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a3ef1a4a-fd22-4a37-8edb-48037f44fa4b",
"name": "Get Table Schema1",
"type": "n8n-nodes-base.airtable",
"position": [
-1240,
-820
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "={{ $json.appId }}"
},
"resource": "base",
"operation": "getSchema"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 2.1
},
{
"id": "2490bbc6-2ea1-4146-b0b8-5a406e89ea2c",
"name": "Get \"Input\" Field",
"type": "n8n-nodes-base.set",
"position": [
-1060,
-820
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "={{\n$input.all()\n .map(item => item.json)\n .find(item => item.id === $('Set Airtable Vars').first().json.tableId)\n .fields\n .find(field => field.name === $('Set Airtable Vars').first().json.inputField)\n}}"
},
"executeOnce": true,
"typeVersion": 3.4
},
{
"id": "a3de141f-0ce8-4f8e-ae8e-f10f635d14ec",
"name": "RecordsChanged Webhook 트리거",
"type": "n8n-nodes-base.httpRequest",
"position": [
-880,
-820
],
"parameters": {
"url": "=https://api.airtable.com/v0/bases/{{ $('Set Airtable Vars').first().json.appId }}/webhooks",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"notificationUrl\": $('Set Airtable Vars').first().json.notificationUrl,\n \"specification\": {\n \"options\": {\n \"filters\": {\n \"fromSources\": [ \"client\" ],\n \"dataTypes\": [ \"tableData\" ],\n \"changeTypes\": [ \"update\" ],\n \"recordChangeScope\": $('Set Airtable Vars').first().json.tableId,\n \"watchDataInFieldIds\": [$json.id]\n }\n }\n }\n}\n}}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "airtableTokenApi"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 4.2
},
{
"id": "21b0fae8-2046-4647-83c4-132d1d63503a",
"name": "FieldsChanged Webhook 트리거",
"type": "n8n-nodes-base.httpRequest",
"position": [
-880,
-640
],
"parameters": {
"url": "=https://api.airtable.com/v0/bases/{{ $('Set Airtable Vars').first().json.appId }}/webhooks",
"method": "POST",
"options": {},
"jsonBody": "={{\n{\n \"notificationUrl\": $('Set Airtable Vars').first().json.notificationUrl,\n \"specification\": {\n \"options\": {\n \"filters\": {\n \"fromSources\": [ \"client\" ],\n \"dataTypes\": [ \"tableFields\" ],\n \"changeTypes\": [ \"add\", \"update\" ],\n \"recordChangeScope\": $('Set Airtable Vars').first().json.tableId\n }\n }\n }\n}\n}}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "airtableTokenApi"
},
"credentials": {
"airtableTokenApi": {
"id": "Und0frCQ6SNVX3VV",
"name": "Airtable Personal Access Token account"
}
},
"typeVersion": 4.2
},
{
"id": "f31c36cb-98da-4688-a83a-f06e46d2b8a2",
"name": "메모14",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1680,
-1000
],
"parameters": {
"color": 5,
"width": 1020,
"height": 580,
"content": "## ⭐️ Creating Airtable Webhooks\nTo link this workflow with Airtable, you'll have to create webhooks for the Base.\nYou'll only really need to do this this once but if these webhooks are inactive after 7 days, you'll need to create them again.\n\nCheck out the Airtable Developer documentation for more info: [https://airtable.com/developers/web/api/webhooks-overview](https://airtable.com/developers/web/api/webhooks-overview)"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"95d08439-59a2-4e74-bd5a-b71cf079b621": {
"main": [
[
{
"node": "Filter Valid Rows",
"type": "main",
"index": 0
}
]
]
},
"f559c8ff-2ee5-478d-84ee-6b0ca2fe2050": {
"main": [
[
{
"node": "7b82cc73-67cb-46d7-a1d4-19712c86890a",
"type": "main",
"index": 0
}
]
]
},
"dd0fa792-791f-4d31-a7e8-9b72a25b6a07": {
"main": [
[
{
"node": "Filter Valid Fields",
"type": "main",
"index": 0
}
]
]
},
"ca1174b3-da18-4d3c-86ef-3028cd5b12a7": {
"main": [
[
{
"node": "95d08439-59a2-4e74-bd5a-b71cf079b621",
"type": "main",
"index": 0
}
]
]
},
"36816ae7-414a-482e-8a50-021885237273": {
"main": [
[
{
"node": "ca1174b3-da18-4d3c-86ef-3028cd5b12a7",
"type": "main",
"index": 0
}
],
[
{
"node": "dd0fa792-791f-4d31-a7e8-9b72a25b6a07",
"type": "main",
"index": 0
}
],
[
{
"node": "dd0fa792-791f-4d31-a7e8-9b72a25b6a07",
"type": "main",
"index": 0
}
]
]
},
"b5c2b87b-5756-4810-84c9-34ea420bdcef": {
"main": [
[
{
"node": "86d3c8d8-709f-4d9d-99bc-5d1b4aeb8603",
"type": "main",
"index": 0
}
]
]
},
"86d3c8d8-709f-4d9d-99bc-5d1b4aeb8603": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"9916f1c1-f413-4996-ad45-380a899b4a88": {
"main": [
[
{
"node": "50888ac5-30c9-4036-aade-6ccfdf605c3b",
"type": "main",
"index": 0
}
]
]
},
"5f8d919b-14cd-4cb4-8604-731e56cc9402": {
"main": [
[
{
"node": "36816ae7-414a-482e-8a50-021885237273",
"type": "main",
"index": 0
}
]
]
},
"c29fc911-a852-46f2-bbb1-5092cc1aaa9d": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"3b73b2f5-9081-4633-911f-ef3041600a00": {
"main": [
[
{
"node": "Extract from File",
"type": "main",
"index": 0
}
]
]
},
"20e24946-59d8-4b19-bfab-eebb02f7e46d": {
"main": [
[
{
"node": "3b73b2f5-9081-4633-911f-ef3041600a00",
"type": "main",
"index": 0
}
]
]
},
"e3ebeb45-45d9-44a4-a2e6-bde89f5da125": {
"main": [
[
{
"node": "Loop Over Items1",
"type": "main",
"index": 0
}
]
]
},
"7b82cc73-67cb-46d7-a1d4-19712c86890a": {
"main": [
[
{
"node": "Extract from File1",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "20e24946-59d8-4b19-bfab-eebb02f7e46d",
"type": "main",
"index": 0
}
]
]
},
"Airtable Webhook": {
"main": [
[
{
"node": "9b99d939-94d6-4fef-8b73-58c702503221",
"type": "main",
"index": 0
}
]
]
},
"582d4008-4871-4798-bc24-abf774ad29b5": {
"main": [
[
{
"node": "f62f612d-c288-4062-ab3c-dbc24c9b4b38",
"type": "main",
"index": 0
}
]
]
},
"9b99d939-94d6-4fef-8b73-58c702503221": {
"main": [
[
{
"node": "920ca6d8-7a6e-4482-b003-fa643f550a85",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items1": {
"main": [
[],
[
{
"node": "f559c8ff-2ee5-478d-84ee-6b0ca2fe2050",
"type": "main",
"index": 0
}
]
]
},
"Extract from File": {
"main": [
[
{
"node": "4090c53e-e635-4421-ab2b-475bfc62cea4",
"type": "main",
"index": 0
}
]
]
},
"Filter Valid Rows": {
"main": [
[
{
"node": "Loop Over Items1",
"type": "main",
"index": 0
}
]
]
},
"2490bbc6-2ea1-4146-b0b8-5a406e89ea2c": {
"main": [
[
{
"node": "RecordsChanged Webhook",
"type": "main",
"index": 0
}
]
]
},
"920ca6d8-7a6e-4482-b003-fa643f550a85": {
"main": [
[
{
"node": "Get Webhook Payload",
"type": "main",
"index": 0
}
]
]
},
"a3ef1a4a-fd22-4a37-8edb-48037f44fa4b": {
"main": [
[
{
"node": "2490bbc6-2ea1-4146-b0b8-5a406e89ea2c",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "f62f612d-c288-4062-ab3c-dbc24c9b4b38",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Set Airtable Vars": {
"main": [
[
{
"node": "a3ef1a4a-fd22-4a37-8edb-48037f44fa4b",
"type": "main",
"index": 0
},
{
"node": "FieldsChanged Webhook",
"type": "main",
"index": 0
}
]
]
},
"Extract from File1": {
"main": [
[
{
"node": "582d4008-4871-4798-bc24-abf774ad29b5",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "4090c53e-e635-4421-ab2b-475bfc62cea4",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Filter Valid Fields": {
"main": [
[
{
"node": "c29fc911-a852-46f2-bbb1-5092cc1aaa9d",
"type": "main",
"index": 0
}
]
]
},
"Get Webhook Payload": {
"main": [
[
{
"node": "5f8d919b-14cd-4cb4-8604-731e56cc9402",
"type": "main",
"index": 0
}
]
]
},
"4090c53e-e635-4421-ab2b-475bfc62cea4": {
"main": [
[
{
"node": "b5c2b87b-5756-4810-84c9-34ea420bdcef",
"type": "main",
"index": 0
}
]
]
},
"50888ac5-30c9-4036-aade-6ccfdf605c3b": {
"main": [
[
{
"node": "e3ebeb45-45d9-44a4-a2e6-bde89f5da125",
"type": "main",
"index": 0
}
]
]
},
"FieldsChanged Webhook": {
"main": [
[]
]
},
"f62f612d-c288-4062-ab3c-dbc24c9b4b38": {
"main": [
[
{
"node": "9916f1c1-f413-4996-ad45-380a899b4a88",
"type": "main",
"index": 0
}
]
]
},
"RecordsChanged Webhook": {
"main": [
[]
]
},
"When clicking ‘Test workflow’": {
"main": [
[
{
"node": "Set Airtable Vars",
"type": "main",
"index": 0
}
]
]
}
}
}자주 묻는 질문
이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급 - 인공지능
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
동적 프롬프트와 Baserow를 활용한 AI 데이터 추출
동적 프롬프트와 Baserow를 활용한 AI 데이터 추출
Set
Code
Filter
+
Set
Code
Filter
45 노드Jimleuk
인공지능
n8n, Apify, OpenAI o3 자체托管 AI 깊이 연구 대리자 사용
n8n, Apify, OpenAI o3을 사용하여 자체托管 AI 깊이 연구 대리자
If
Set
Code
+
If
Set
Code
87 노드Jimleuk
인공지능
[템플릿] AI 반려동물 가게 v8
🐶 AI 펫 샵 어시스턴트 - GPT-4o, Google 캘린더 및 WhatsApp/Instagram/Facebook 통합
If
N8n
Set
+
If
N8n
Set
244 노드Amanda Benks
영업
AI 대리인 레스토랑 [템플릿]
🤖 WhatsApp, 인스타그램, 메신저의 AI 레스토랑 도우미
If
N8n
Set
+
If
N8n
Set
239 노드Amanda Benks
기타
Qdrant, Mistral.ai, OpenAI를 사용하여 세금 법률 어시스턴트를 구축합니다.
Qdrant, Mistral.ai, OpenAI를 사용하여 세금 법률 어시스턴트를 구축합니다.
Set
Wait
Filter
+
Set
Wait
Filter
38 노드Jimleuk
금융
반려동물 가게 4
🐶 펫 샵 예약 AI 대리자
If
Set
Code
+
If
Set
Code
187 노드Bruno Dias
인공지능
워크플로우 정보
난이도
고급
노드 수51
카테고리1
노드 유형14
저자
Jimleuk
@jimleukFreelance consultant based in the UK specialising in AI-powered automations. I work with select clients tackling their most challenging projects. For business enquiries, send me an email at hello@jimle.uk LinkedIn: https://www.linkedin.com/in/jimleuk/ X/Twitter: https://x.com/jimle_uk
외부 링크
n8n.io에서 보기 →
이 워크플로우 공유