{ "name": "LLM_wiki", "nodes": [ { "parameters": { "formTitle": "上傳文件", "formDescription": "上傳你的知識文件", "formFields": { "values": [ { "fieldLabel": "文件", "fieldType": "file", "fieldName": "doc", "acceptFileTypes": ".md, .txt" } ] }, "options": {} }, "type": "n8n-nodes-base.formTrigger", "typeVersion": 2.5, "position": [ 0, 112 ], "id": "57e78e69-c698-4fbe-963a-1e43d3e1dc81", "name": "On form submission", "webhookId": "75dd9d9f-182b-44a7-8295-ef33d55aa4d2" }, { "parameters": { "promptType": "define", "text": "=以下是用戶上傳的文件內容,請整理後寫入 Wiki:\n{{ $json.doc }}", "options": { "systemMessage": "你是 Wiki 知識寫入助手。\n你的唯一任務是將收到的文件內容整理後,完整寫入 Wiki 知識庫。\n\n## 工具說明\n\n- get_indexs:讀取 index sheet,回傳所有條目的 topic、doc_id、keywords、summary\n- create_wiki_page:新建 Wiki Doc,輸入 topic 名稱,回傳 doc_id\n- write_wiki:在 Wiki Doc 末尾 Append 新內容,輸入 doc_id + content\n- write_index:在 index sheet 新增一行,用於全新條目,輸入 topic、doc_id、keywords、summary\n- update_wiki:更新 index sheet 既有條目的 keywords 和 summary,輸入 topic + 新值\n\n## 執行流程\n\n### 第一步:讀取 index(必須)\n呼叫 get_indexs,取得所有現有條目。\n在做任何其他動作之前,必須先完成這一步。\n\n### 第二步:分析文件\n將文件內容拆解為一個或多個主題。\n每個主題獨立處理。\n\n### 第三步:對每個主題執行以下判斷\n\n**如果主題已存在於 index:**\n1. 呼叫 write_wiki(帶入既有 doc_id),將新知識 Append 到文件末尾\n2. 呼叫 update_wiki,更新該條目的 keywords 和 summary\n→ update_wiki 是這個分支的最後一步,未呼叫代表此主題尚未完成\n\n**如果主題不存在於 index:**\n1. 呼叫 create_wiki_page(輸入 topic),取得新 doc_id\n2. 呼叫 write_wiki(帶入新 doc_id),寫入初始內容\n3. 呼叫 write_index,將新條目寫入 index sheet\n→ write_index 是這個分支的最後一步,未呼叫代表此主題尚未完成\n\n### 第四步:確認收尾(必須)\n在回報任何結果給用戶之前,檢查每個主題是否都已完成最後一步:\n- 既有主題:update_wiki 已呼叫 ✓\n- 新主題:write_index 已呼叫 ✓\n\n如果有任何主題還沒完成最後一步,必須先補完,才能回報結果。\n\n### 第五步:回報結果\n格式如下:\n\n✅ 已更新的主題:[topic 名稱](doc_id: xxx)\n🆕 已新建的頁面:[topic 名稱](doc_id: xxx)\n\n## 寫入格式規範\n\n- 語言:繁體中文\n- 結構:條列核心概念,每點一行\n- 末尾固定附上:來源:上傳文件|日期:{{$now}}\n- 模式:Append,絕對不刪除或覆蓋舊內容\n\n## 鐵律\n\n- 沒有呼叫 get_indexs 之前,不得執行任何其他工具\n- 沒有更新 index 之前,不得回報任務完成\n- write_wiki 永遠不是最後一步\n你必須透過工具呼叫(function call)執行所有操作。\n絕對不可以用文字描述「我將要呼叫 XXX」或「Calling XXX with input」。\n描述行動不等於執行行動。只有實際呼叫工具才算完成任務。" } }, "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "position": [ 704, 0 ], "id": "1a52474b-dc56-409f-b9f5-76655dd842f5", "name": "AI Agent" }, { "parameters": { "operation": "text", "binaryPropertyName": "doc", "destinationKey": "doc", "options": {} }, "type": "n8n-nodes-base.extractFromFile", "typeVersion": 1.1, "position": [ 224, 112 ], "id": "b35641d7-1830-4951-9007-f1d5870fc223", "name": "Extract from File" }, { "parameters": { "descriptionType": "manual", "toolDescription": "讀取 Wiki index sheet,取得所有現有條目。\n\n回傳每筆條目的:topic、doc_id、keywords、summary、last_updated\n\n這是每次流程的第一步,必須先呼叫才能判斷主題是否已存在。", "authentication": "serviceAccount", "documentId": { "__rl": true, "value": "1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho", "mode": "list", "cachedResultName": "index", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho/edit?usp=drivesdk" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "工作表1", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho/edit#gid=0" }, "options": {} }, "type": "n8n-nodes-base.googleSheetsTool", "typeVersion": 4.7, "position": [ 576, 224 ], "id": "71b93dc0-d918-42dd-88ca-30a75b807130", "name": "get_indexs", "credentials": { "googleApi": { "id": "jiemOwKMFTLhtSli", "name": "Service_Account_Richblack" } } }, { "parameters": { "toolDescription": "=建立一個新的 Google Docs Wiki 頁面。\n\n輸入:\n- doc_title:頁面標題(主題名稱)\n\n回傳:\n- doc_id:新建頁面的 Google Doc ID(後續 write_wiki 和 write_index 都需要這個值)\n\n注意:建立後必須繼續呼叫 write_wiki 寫入內容,再呼叫 write_index 更新索引,任務才算完成。", "method": "POST", "url": "https://YOUR-N8N-HOST/webhook/YOUR-CREATE-WIKI-PAGE-WEBHOOK-ID", "sendBody": true, "bodyParameters": { "parameters": [ { "name": "doc_title", "value": "={{ $fromAI('doc_title') }}" } ] }, "options": {} }, "type": "n8n-nodes-base.httpRequestTool", "typeVersion": 4.4, "position": [ 704, 224 ], "id": "8e9efcaa-e434-444a-98bc-347fc0c9b989", "name": "create_wiki_page" }, { "parameters": { "modelName": "models/gemini-flash-latest", "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini", "typeVersion": 1.1, "position": [ 448, 224 ], "id": "7cb78f89-1c14-435d-90aa-1f2dcb3bd07d", "name": "Gemini", "credentials": { "googlePalmApi": { "id": "kT9HBbdgSzqMyxem", "name": "Google Gemini Leo 自家用" } } }, { "parameters": { "options": {} }, "type": "@n8n/n8n-nodes-langchain.chatTrigger", "typeVersion": 1.4, "position": [ 240, 464 ], "id": "d437ecd9-f215-4e9e-850b-9f041ef9168e", "name": "When chat message received", "webhookId": "2215100f-da5f-4c4d-a25c-c5e480d8c54c" }, { "parameters": { "descriptionType": "manual", "toolDescription": "讀取指定 Wiki Google Doc 的完整內容。\n\n輸入:\n- doc_id:目標 Google Doc 的 ID(從 get_indexs 取得)\n\n回傳:該頁面的全文內容,用於回答用戶問題。", "operation": "get", "documentURL": "={{ $fromAI('doc_id') }}" }, "type": "n8n-nodes-base.googleDocsTool", "typeVersion": 2, "position": [ 720, 688 ], "id": "bc9be3ed-9db6-4efa-b517-ea06c56b0c8d", "name": "read_wiki", "credentials": { "googleDocsOAuth2Api": { "id": "pgd50DD52VYwX6IC", "name": "Leo_personal_n8n_test" } } }, { "parameters": { "options": { "systemMessage": "你是 Wiki 知識查詢助手。\n你的任務是根據用戶的問題,從 Wiki 知識庫找到答案後回答。\n\n工具說明:\n- get_indexs:讀取 index sheet,回傳所有條目的 topic、doc_id、keywords、summary\n- read_wiki:讀取指定 Wiki Doc 的內容,輸入 doc_id,回傳全文\n\n執行順序:\n1. 呼叫 get_indexs,瀏覽所有條目的 keywords 和 summary\n2. 判斷哪個(或哪幾個)doc_id 與問題最相關\n3. 呼叫 read_wiki(帶入 doc_id)讀取內容\n4. 根據讀到的內容回答用戶\n\n注意:\n- 只讀不寫,不要修改任何 Wiki 內容\n- 如果 index 裡找不到相關主題,直接告知用戶「Wiki 尚未收錄此主題」\n- 回答要根據 Wiki 內容,不要自己發明答案" } }, "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "position": [ 592, 464 ], "id": "2b77a40c-e0b7-477f-aac1-50d80fe4deec", "name": "AI Agent1" }, { "parameters": { "modelName": "models/gemma-4-31b-it", "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini", "typeVersion": 1.1, "position": [ 464, 688 ], "id": "e32a353a-adb9-4821-8308-784af0c93129", "name": "Gemini1", "credentials": { "googlePalmApi": { "id": "kT9HBbdgSzqMyxem", "name": "Google Gemini Leo 自家用" } } }, { "parameters": { "descriptionType": "manual", "toolDescription": "在 index sheet 新增或更新一筆條目。這是每次寫入流程的最後一步,沒有呼叫這個工具代表任務尚未完成。\n\n輸入:\n- topic:主題名稱\n- doc_id:對應的 Google Doc ID(從 create_wiki_page 取得,或從 get_indexs 讀出)\n- keywords:逗號分隔的關鍵詞列表\n- summary:這篇 Wiki 目前涵蓋內容的一句話摘要\n- last_updated:今天日期,格式 YYYY-MM-DD\n\n行為:doc_id 已存在則更新該行,不存在則新增一行。", "authentication": "serviceAccount", "operation": "appendOrUpdate", "documentId": { "__rl": true, "value": "1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho", "mode": "list", "cachedResultName": "index", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho/edit?usp=drivesdk" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "工作表1", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho/edit#gid=0" }, "columns": { "mappingMode": "defineBelow", "value": { "doc_id": "={{ $fromAI('doc_id') }}", "topic": "={{ $fromAI('topic') }}", "keywords": "={{ $fromAI('keywords') }}", "summary": "={{ $fromAI('summary') }}", "last_updated": "={{ $fromAI('last_updated') }}" }, "matchingColumns": [ "doc_id" ], "schema": [ { "id": "topic", "displayName": "topic", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "doc_id", "displayName": "doc_id", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "keywords", "displayName": "keywords", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "summary", "displayName": "summary", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true }, { "id": "last_updated", "displayName": "last_updated", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true } ], "attemptToConvertTypes": false, "convertFieldsToString": false }, "options": {} }, "type": "n8n-nodes-base.googleSheetsTool", "typeVersion": 4.7, "position": [ 832, 224 ], "id": "6091001d-c6e3-478d-bdbd-6ab4afededc2", "name": "write_index", "credentials": { "googleApi": { "id": "jiemOwKMFTLhtSli", "name": "Service_Account_Richblack" } } }, { "parameters": { "descriptionType": "manual", "toolDescription": "讀取指定 Wiki Google Doc 的完整內容。\n\n輸入:\n- doc_id:目標 Google Doc 的 ID(從 get_indexs 取得)\n\n回傳:該頁面的全文內容,用於回答用戶問題。", "authentication": "serviceAccount", "documentId": { "__rl": true, "value": "1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho", "mode": "list", "cachedResultName": "index", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho/edit?usp=drivesdk" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "工作表1", "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Zgs3o1sJxzWdpN_JbDHCcPECXvrxlj7QnYZKcu5u0ho/edit#gid=0" }, "options": {} }, "type": "n8n-nodes-base.googleSheetsTool", "typeVersion": 4.7, "position": [ 848, 688 ], "id": "d9edd457-07a4-46d6-810b-c1c988ac9525", "name": "get_indexs1", "credentials": { "googleApi": { "id": "jiemOwKMFTLhtSli", "name": "Service_Account_Richblack" } } }, { "parameters": {}, "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow", "typeVersion": 1.4, "position": [ 592, 688 ], "id": "48c22e61-9260-4c77-b782-cf3cd049e371", "name": "Simple Memory" }, { "parameters": { "descriptionType": "manual", "toolDescription": "取代指定 Wiki Google Doc 中的特定文字段落。用於修改或更正既有頁面中的內容。\n\n輸入:\n- doc_id:目標 Google Doc 的 ID\n- old_text:要被取代的原始文字\n- new_text:取代後的新文字\n\n注意:呼叫完畢後必須繼續呼叫 write_index 更新索引中的 keywords 和 summary。", "operation": "update", "documentURL": "={{ $fromAI('doc_id') }}", "actionsUi": { "actionFields": [ { "action": "replaceAll", "text": "={{ $fromAI('old_text') }}", "replaceText": "={{ $fromAI('new_text') }}" } ] } }, "type": "n8n-nodes-base.googleDocsTool", "typeVersion": 2, "position": [ 960, 224 ], "id": "811d333c-2d32-4238-a03a-bf35e2d7bd82", "name": "update_wiki", "credentials": { "googleDocsOAuth2Api": { "id": "pgd50DD52VYwX6IC", "name": "Leo_personal_n8n_test" } } }, { "parameters": { "descriptionType": "manual", "toolDescription": "將新內容 Append(插入)到指定的 Wiki Google Doc 末尾。用於寫入全新頁面的初始內容,或在既有頁面末尾新增知識。\n\n輸入:\n- doc_id:目標 Google Doc 的 ID\n- text:要寫入的內容\n\n注意:這是新增內容,不會刪除原有內容。呼叫完畢後必須繼續呼叫 write_index 更新索引。", "operation": "update", "documentURL": "={{ $fromAI('doc_id') }}", "actionsUi": { "actionFields": [ { "action": "insert", "text": "={{ $fromAI('text') }}" } ] } }, "type": "n8n-nodes-base.googleDocsTool", "typeVersion": 2, "position": [ 1088, 224 ], "id": "64891a23-95d7-4d9f-a8ff-a0e74798737e", "name": "write_wiki", "credentials": { "googleDocsOAuth2Api": { "id": "pgd50DD52VYwX6IC", "name": "Leo_personal_n8n_test" } } }, { "parameters": { "content": "## 1. 資料入庫", "height": 448, "width": 1328, "color": 2 }, "type": "n8n-nodes-base.stickyNote", "position": [ -96, -80 ], "typeVersion": 1, "id": "e6626b8e-1717-40f1-9094-e95d3455eec8", "name": "Sticky Note" }, { "parameters": { "content": "## 2. 資料查詢", "height": 448, "width": 1328, "color": 4 }, "type": "n8n-nodes-base.stickyNote", "position": [ -96, 384 ], "typeVersion": 1, "id": "35370a11-27e8-4b58-97db-725cf7af1319", "name": "Sticky Note1" } ], "pinData": {}, "connections": { "On form submission": { "main": [ [ { "node": "Extract from File", "type": "main", "index": 0 } ] ] }, "Extract from File": { "main": [ [ { "node": "AI Agent", "type": "main", "index": 0 } ] ] }, "get_indexs": { "ai_tool": [ [ { "node": "AI Agent", "type": "ai_tool", "index": 0 } ] ] }, "create_wiki_page": { "ai_tool": [ [ { "node": "AI Agent", "type": "ai_tool", "index": 0 } ] ] }, "Gemini": { "ai_languageModel": [ [ { "node": "AI Agent", "type": "ai_languageModel", "index": 0 } ] ] }, "When chat message received": { "main": [ [ { "node": "AI Agent1", "type": "main", "index": 0 } ] ] }, "read_wiki": { "ai_tool": [ [ { "node": "AI Agent1", "type": "ai_tool", "index": 0 } ] ] }, "Gemini1": { "ai_languageModel": [ [ { "node": "AI Agent1", "type": "ai_languageModel", "index": 0 } ] ] }, "write_index": { "ai_tool": [ [ { "node": "AI Agent", "type": "ai_tool", "index": 0 } ] ] }, "get_indexs1": { "ai_tool": [ [ { "node": "AI Agent1", "type": "ai_tool", "index": 0 } ] ] }, "Simple Memory": { "ai_memory": [ [ { "node": "AI Agent1", "type": "ai_memory", "index": 0 } ] ] }, "update_wiki": { "ai_tool": [ [ { "node": "AI Agent", "type": "ai_tool", "index": 0 } ] ] }, "write_wiki": { "ai_tool": [ [ { "node": "AI Agent", "type": "ai_tool", "index": 0 } ] ] } }, "active": false, "settings": { "executionOrder": "v1", "binaryMode": "separate" }, "versionId": "e749498e-7a54-4cf8-95da-11b5a53cdd29", "meta": { "templateCredsSetupCompleted": true, "instanceId": "4b0d44081b86641724941387a3a04b51a305f7e1a5c57b8feea64b401216b1f0" }, "id": "eIbQFUBI8Q8bRRPn", "tags": [] }