上一篇講了概念和選型,這篇捲起袖子來寫 code。

n8n:5 分鐘跑起來

Docker 部署

最快的方式:

# docker-compose.yml
services:
  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=changeme
      - GENERIC_TIMEZONE=Asia/Taipei
    volumes:
      - n8n-data:/home/node/.n8n
volumes:
  n8n-data:
docker compose up -d
# 打開 http://localhost:5678 就能用了

正式環境?加 PostgreSQL 存 workflow 資料、Nginx 反代、HTTPS:

# docker-compose.prod.yml
services:
  n8n:
    image: n8nio/n8n
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=${POSTGRES_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - WEBHOOK_URL=https://n8n.yourdomain.com/
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168
    depends_on:
      - postgres
 
  postgres:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=n8n
    volumes:
      - postgres-data:/var/lib/postgresql/data

n8n + AI 節點實戰

範例 1:智能客服分流

[Webhook] 收到客戶訊息
    → [AI Agent] 分類意圖
    → FAQ      → RAG 搜尋 → 生成回答 → 回覆
    → 技術問題  → 建 Jira ticket → 通知工程師
    → 投訴     → 記錄 → 通知主管

AI Agent 節點設定概念:

{
  "model": "gpt-4o-mini",
  "systemPrompt": "你是客服意圖分類器。回傳:FAQ、TECH_ISSUE、COMPLAINT。只回傳分類名稱。",
  "inputText": "={{ $json.message }}"
}

gpt-4o-mini 做分類就夠了。不需要 GPT-4o。分類三個選項不需要最強大腦。

範例 2:RSS 新聞摘要

[RSS Feed Trigger] 抓取新聞
    → [AI] 分類(技術/商業/其他)
    → [IF] 只留技術和商業
    → [AI] 生成 300 字中文摘要
    → [Notion] 儲存
    → [Slack] 發送每日彙整

範例 3:PR 自動摘要

[GitHub Webhook] 新 PR 開啟
    → [GitHub] 取得 diff
    → [AI] 分析:改了什麼、潛在風險、review 重點
    → [GitHub] 貼為 PR comment
    → [Slack] 通知 reviewer

這種固定流程的事,n8n 最拿手。不需要 Agent「自己決定要不要看其他檔案」——拿 diff、分析、貼回去,三步搞定。


LangChain:RAG Chain 實作

基本 Chain

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
 
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
 
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是技術文件撰寫者。用繁體中文、3 個重點說明。"),
    ("user", "請解釋什麼是 {topic}")
])
 
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "微服務架構"})

RAG Chain

from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
 
# 設定
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma(persist_directory="./chroma_db", embedding_function=embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
 
prompt = ChatPromptTemplate.from_messages([
    ("system", "根據參考資料回答。沒有相關資訊請說明。\n\n參考資料:{context}"),
    ("user", "{question}")
])
 
def format_docs(docs):
    return "\n\n---\n\n".join(
        f"[{doc.metadata.get('source', '未知')}]\n{doc.page_content}"
        for doc in docs
    )
 
rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt | llm | StrOutputParser()
)
 
answer = rag_chain.invoke("n8n 怎麼設定 webhook?")

Agent(帶工具)

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.tools import tool
 
@tool
def get_weather(city: str) -> str:
    """取得指定城市的天氣"""
    import requests
    r = requests.get(f"https://wttr.in/{city}?format=j1")
    if r.ok:
        c = r.json()["current_condition"][0]
        return f"{city}: {c['temp_C']}°C, {c['weatherDesc'][0]['value']}"
    return f"查詢 {city} 失敗"
 
llm = ChatOpenAI(model="gpt-4o", temperature=0)
agent = create_openai_tools_agent(llm, [get_weather], prompt)
executor = AgentExecutor(
    agent=agent, tools=[get_weather],
    max_iterations=10,        # 防止無限迴圈
    max_execution_time=60,    # 60 秒超時
)

注意 max_iterationsmax_execution_time——沒設這兩個,Agent 可能會無限迴圈然後吃光你的 API 額度。別問我怎麼知道的。


安全與成本控制

API Key 管理

❌ 寫在 docker-compose.yml commit 到 git
✅ .env 檔(加入 .gitignore)
✅ n8n 的 Credential 功能(加密儲存)
✅ AWS Secrets Manager / Vault

成本追蹤

from langchain_community.callbacks import get_openai_callback
 
with get_openai_callback() as cb:
    result = chain.invoke({"question": "..."})
    print(f"Cost: ${cb.total_cost:.4f}")

模型選用策略

  • 分類 / 摘要 / 翻譯 → gpt-4o-mini(便宜 16 倍)
  • 複雜推理 / code review → gpt-4oclaude-sonnet
  • 先全用 mini,哪個不夠好再升級

隱私考量

用 API 代表你的資料會傳到第三方。高敏感度場景用 n8n + Ollama 完全私有:

services:
  ollama:
    image: ollama/ollama
    volumes:
      - ollama-data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

資料完全不出你的伺服器。代價是模型能力弱一些,但對分類和摘要來說通常夠用。


常踩的 5 個坑

  1. 什麼都想用 AI — 資料同步、格式轉換不需要 AI。AI 適合非結構化資料處理
  2. Agent 成本失控 — 沒設 max_iterations,一天 50,000 次 API call,月底帳單 $2,000+
  3. Chain 太長 — 每增加一步都增加失敗點。先用最簡單的 chain,不夠再加
  4. 忽略錯誤處理 — AI 失敗了使用者收不到回覆。必須有 Retry + Fallback + Error Log
  5. 沒有監控 — 至少追蹤:成功率、延遲、API 成本、錯誤類型

系列回顧

  1. n8n、LangChain、Agent 怎麼選?
  2. → 你在這裡:實作指南

接下來可以看 Prompt Engineering 實戰,學更多讓 AI 聽話的技巧。


自動化的第一步不是選工具,而是把流程畫出來。畫得出來的,八成 n8n 就搞定了。