螢幕錄製可以呈現整個工作,但無法說明其背後邏輯。有人開啟收件匣、檢查寄件者、將某個值複製到客戶記錄、與試算表比對、傳送摘要,然後繼續下一步。

這些工作清晰可見,但自動化仍須通過更嚴苛的測試:系統能否在不遺漏步驟、不接錯動作、不匯入看似正確卻在後續失效的內容下,還原該工作?

我在螢幕分析專案的 n8n 部分,就是為了因應這個問題而建置。產生器不將最終檔案視為一袋文字,而是將發現的自動化轉換為 N8NWorkflowN8NNode 以及連線物件,再輸出 n8n 相容的 JavaScript Object Notation (JSON)。這增加了程式碼的規範,但能捕捉字串組裝容易引入的一類錯誤。

1. 維持平台詞彙範圍狹小

每個輸出的節點類型都來自 n8n_workflow_generator.py 中的 NodeType。此列舉涵蓋產生器知道如何建立的觸發器、語言模型節點,以及應用程式整合。當專案需要另一個 n8n 節點時,我會先在此處新增,再讓產生器使用。

這會犧牲編輯速度。無法透過提示中拼寫新識別字,快速插入一次性節點。換來的優點是更明確的失敗:不支援的平台名稱會在 Python 中失敗,而非隱藏在可匯入的檔案中。

相同的概念也適用於 n8n_agent_templates.py 中的代理設定。AgentTemplate 命名可用的模式;AgentConfig 則承載提示、工具、整合、觸發偏好、模型選擇、temperature 與迭代限制。提示只是一個欄位,而非其他一切的容器。

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import List


class AgentTemplate(Enum):
    EMAIL_TRIAGE = "email_triage"
    CRM_DATA_SYNC = "crm_data_sync"
    CALENDAR_ASSISTANT = "calendar_assistant"
    DOCUMENT_PROCESSOR = "document_processor"
    COMMUNICATION_ROUTER = "communication_router"
    REPORT_GENERATOR = "report_generator"
    LEAD_QUALIFIER = "lead_qualifier"
    TASK_MANAGER = "task_manager"
    VOICE_ASSISTANT = "voice_assistant"
    MULTI_AGENT_ORCHESTRATOR = "multi_agent_orchestrator"


@dataclass
class AgentConfig:
    name: str
    description: str
    template: AgentTemplate
    system_prompt: str
    tools: List[str] = field(default_factory=list)
    integrations: List[str] = field(default_factory=list)
    triggers: List[str] = field(default_factory=list)
    llm_model: str = "gemini-2.5-flash"
    temperature: float = 0.7
    max_iterations: int = 10

Enter fullscreen mode Exit fullscreen mode

此結構同時也是一種限制。若新的自動化需要 AgentConfig 無法表達的概念,我會先擴充模型。這會減緩實驗速度,但能維持匯出路徑的正確性。

2. 先建置物件,再產生 JSON

產生器的結構化形式就是 n8n 圖形本身:節點加上具名連線。它不會維護第二種私有圖形格式。N8NWorkflowN8NNode 與連線記錄,就是分析結果到儲存 JSON 檔案之間的表示方式。

flowchart TD
  analysis[Discovered automation] --> workflow[N8NWorkflow]
  workflow --> nodes[N8NNode objects]
  workflow --> connections[Connection records]
  nodes --> json[n8n JSON export]
  connections --> json
  json --> importer[REST importer]
  importer --> status[Import status]```



這項區分很重要。像是「分類這封郵件」這類偵測到的步驟,只有在產生器有足夠脈絡可選擇觸發器、模型、整合與連線順序時,才會對應到具體的 n8n 節點。定位是與身分分開計算的,因此畫布保持易讀,而不會將佈局綁定到節點 ID。

權衡之下是彈性。確定性放置無法比擬手動排列的畫布,且型別化建構比直接編輯 JSON 檔案更繁重。對於產生的自動化,我偏好可預測的檢視,而非完美的視覺佈局。

核心物件形狀很簡單:

```python from __future__ import annotations from dataclasses import dataclass, field from typing import Any, Dict, List @dataclass class N8NNode: id: str name: str type: str position: List[int] parameters: Dict[str, Any] = field(default_factory=dict) credentials: Dict[str, Any] = field(default_factory=dict) type_version: float = 1.0 def to_dict(self) -> Dict[str, Any]: node_dict = { "id": self.id, "name": self.name, "type": self.type, "position": self.position, "parameters": self.parameters, "typeVersion": self.type_version, } if self.credentials: node_dict["credentials"] = self.credentials return node_dict

Enter fullscreen mode Exit fullscreen mode

這就是讓 JSON 感覺像產生碼的部分。在序列化之前,物件已擁有身分、類型、參數、憑證、版本與位置。等到檔案存在時,重要的決策早已通過可檢視的 Python 結構。

3. 將匯入視為部署狀態

產生以檔案結束;當檔案透過 Representational State Transfer (REST) API 抵達 n8n 時,操作才開始。在 n8n_importer.py 中,匯入失敗有命名的例外,匯入進度有明確的狀態。

from enum import Enum


class N8NError(Exception):
    """Custom exception for n8n API errors."""


class ImportStatus(Enum):
    PENDING = "pending"
    IMPORTING = "importing"
    SUCCESS = "success"
    FAILED = "failed"
    REQUIRES_CREDENTIALS = "requires_credentials"

Enter fullscreen mode Exit fullscreen mode

憑證問題與匯入失敗需要不同的恢復路徑,因此會給予不同的標籤。部署流程可以產生自動化、建立支援的代理檔案、匯入它們,並在處理憑證時保留啟用狀態關閉。

這種分離會移除便利性。一鍵產生、匯入、設定憑證並啟用的做法,雖然在示範時更快,但在正式環境中,將這些動作分開能讓部分失敗可恢復。

4. 我用來測試的對照表

層級 它回答的問題
AgentTemplate 正在建置哪種自動化模式?
AgentConfig 哪個提示、工具、整合、觸發器與模型設定描述了它?
NodeType 哪些 n8n 識別字可以被輸出?
N8NWorkflow / N8NNode 哪個圖形會變成 JSON?
ImportStatus / N8NError 當成品抵達 n8n 時發生了什麼?

這比字串插值成本更高:額外的列舉、資料類別、物件建構、儲存步驟,以及匯入報告。它也讓結構變更更明確。我願意支付這個成本,因為從螢幕錄製推斷出的自動化本就帶有不確定性;匯出路徑應該降低這種不確定性。

當 Workflow JSON 能夠移動資料、呼叫模型並路由工作時,它就是程式碼。將它視為產生的程式碼,是我讓發現的流程不變成匯入意外的方法。


🎧 收聽有聲書Spotify · Google Play · 所有平台
🎬 在 YouTube 觀看視覺總覽
📖 閱讀完整的 13 部分系列