標籤: LangGraph

  • Langflow:用畫流程圖做自己的 AI Agent

    Langflow:用畫流程圖做自己的 AI Agent

    📌 本文重點

    • Langflow 用拖拉節點設計 AI Agent 工作流
    • 支援記憶、工具調用與 Webhook,讓 Agent 真正能做事
    • 30 分鐘內即可做出第一個可用的內部 Bot 或自動化流程
    • 開源、可自行部署,適合技術團隊掌控環境

    一句話先講清楚:Langflow 就是把「寫 Agent 程式」變成「畫流程圖」,讓你用拖拉方塊的方式,搭出自己的 AI 工作流。

    Langflow GitHub 專案連結


    核心功能:用方塊和線組出一個會動的 AI

    1. 節點(Nodes):把複雜任務拆成小方塊

    在 Langflow 裡,你看到的是一塊畫布,左邊是各種「節點」,右邊是你畫好的流程圖。

    常用節點類型:

    • LLM 節點:呼叫大語言模型(例如 OpenAI、Anthropic、Ollama 等)
    • Prompt 節點:管理提示詞模板,支援變數(如 {{question}}
    • Memory 節點:儲存上下文,例如聊天紀錄或任務狀態
    • Tool / API 節點:呼叫外部服務,像 HTTP RequestWebhook

    你可以做的動作:

    • 打開 Langflow,先拖一個 Chat Model 節點 到畫布上
    • 再拖一個 Prompt 節點,將使用者輸入包裝成模型指令
    • 把 Prompt 的輸出線接到 Chat Model 的輸入,就完成最基本的「問答 bot」骨架

    💡 關鍵: 把任務拆成節點後,你可以像搭積木一樣重組、調整工作流,而不必重寫整段程式。

    2. 連線(Edges):定義資料怎麼流動

    每個節點都有輸入/輸出接口,透過連線把它們接起來,就形成一個 Agent 工作流。

    常見連線方式:

    • 使用者輸入 → Prompt 節點 → LLM 節點 → 回傳結果
    • 文件載入節點 → 向量資料庫節點(檢索)→ LLM 節點(基於文件回答)
    • Webhook 節點 → LLM 節點 → 再呼叫另一個 API 節點回寫結果

    你可以做的動作:

    • 在畫布上嘗試把「使用者輸入」節點接到兩個不同的 Prompt 節點,再接到兩個 LLM 節點,做 A/B 測試不同指令效果

    3. 記憶(Memory):讓 Agent 不只回一題就忘記

    如果只接一個 LLM 節點,你得到的是單輪對話。要做「會記得之前說過什麼」的 Agent,就要加上 Memory 節點

    在 Langflow 裡常見記憶用法:

    • 把歷史對話存入記憶,讓下一輪 LLM 接收到完整上下文
    • 在流程中保存一些關鍵變數(例如工單號碼、用戶角色),下游節點可以讀取

    你可以做的動作:

    • 新增一個 Conversation Memory 節點,接在「使用者輸入」和「LLM」中間
    • 測試多輪提問,同一個 Agent 能接續前面的內容

    4. 工具調用與 Webhook:讓 Agent 真的「能做事」

    Langflow 不只是聊天,它可以讓 LLM 透過節點呼叫各種工具:

    • HTTP Request / Webhook 節點:連到你的 CRM、工單系統、Google Sheets 或任意 REST API
    • 資料處理節點:對 JSON、文字做轉換,讓輸入輸出更乾淨

    你可以做的動作:

    • 在畫布上加一個 HTTP 節點,設定你公司內部 API URL
    • 讓 LLM 的輸出(例如「請查詢這個訂單狀態:#12345」)轉成 API 查詢,再把結果回傳給使用者

    適合誰用:三個實戰場景

    場景 1:客服自動回覆流程(半自動客服)

    目標:讓客服人員不用自己寫回覆,改成「點選建議」或讓 Agent 先草擬。

    基本流程可以這樣畫:

    1. 使用者訊息輸入節點(接 Web / 聊天介面)
    2. 記憶節點:保存同一位客戶的歷史對話
    3. FAQ 文件載入 + 向量資料庫節點:把常見問題和答案餵給系統
    4. LLM 節點:基於 FAQ 檢索結果產生回覆草稿
    5. Webhook / 前端節點:把草稿送到客服後台,讓人類按「同意 / 修改 / 拒絕」

    你可以採取的行動(30 分鐘內可完成雛形):

    • 匯入一份公司 FAQ PDFMarkdown
    • 建一個簡單的「文件檢索 + LLM 回覆」流程
    • 先在 Langflow 介面測試問答,確認準確率,再決定要不要跟正式客服系統串接

    💡 關鍵: 只要一份 FAQ 和一個基本檢索流程,半自動客服雛形在 30 分鐘內就能跑起來。

    場景 2:文件問答 Bot(內部知識庫助理)

    這是最多人用 Langflow 起手式:做一個「問公司內部文件」的 Bot。

    流程示意:

    1. File Loader 節點:載入 PDFDOCXMarkdown
    2. Text Splitter 節點:把長文件切成小片段
    3. Embedding + Vector Store 節點:建立向量索引,支援語意搜尋
    4. Query 節點:根據提問在向量庫中檢索相關片段
    5. LLM 節點:拿檢索到的內容,組合成清楚答案

    你可以採取的行動:

    • 先用幾份內部文件(例如員工手冊、產品說明)做一個小型知識庫
    • 在 Langflow 介面用「如果我請假怎麼申請?」這類問題測試
    • 看輸出是否有文件來源,確認 Agent 沒亂掰(可在 Prompt 裡要求標註來源)

    場景 3:簡單內部自動化任務(通知 / 報表 / 小流程)

    你不一定要做複雜 Agent,很多公司會先從「AI + 小自動化」開始:

    可能流程:

    1. 定時觸發(或外部 Webhook)節點:例如每天早上 9 點跑一次
    2. API 節點:從系統拉出昨日訂單或工單資料
    3. LLM 節點:請模型整理成「今日重點三點」或「需要注意的異常」
    4. Webhook / Email 節點:把結果發到 Slack / Teams / Email

    你可以採取的行動:

    • 選一個你每天手動整理的報表,先用 Langflow 做一個「拉資料 → LLM 整理 → 發通知」的簡化版
    • 先用測試環境 API,確認沒有誤發給正式頻道,再上線

    怎麼開始:從安裝到第一個 Agent

    1. 部署方式:本機 vs 雲端

    Langflow 是開源專案(Python),你有兩種常見用法:

    • 本機部署:適合開發者、內網環境
    • 需要:Python 環境、基本命令列操作
    • 在本機跑,方便串內部服務,不用把資料丟到外部 SaaS

    • 雲端部署:適合團隊協作、多人共用

    • 可用 Docker 或自行丟到雲端 VM
    • 好處:同事可以一起進到同一個 Langflow 介面,共用工作流模板

    你可以採取的行動:

    • 先在自己電腦用 Docker 跑起 Langflow,熟悉介面
    • 等你有第一個可用流程,再考慮搬到公司雲端或內網伺服器

    2. 快速安裝步驟(以本機為例)

    以最常見的方式示意(實際請以官方 README 為準):

    # 建議用虛擬環境或 Docker,這裡以 pip 為例
    pip install langflow
    
    # 安裝完成後啟動服務
    langflow run
    
    # 預設會在 http://localhost:7860 開一個 Web 介面
    

    你可以採取的行動:

    • 安裝後打開瀏覽器進入 http://localhost:7860
    • 新建一個 Flow,拖一個 Chat Model 節點,接一個 Prompt 節點,測試一輪聊天

    3. 接不同 LLM:商用 API 和本地模型

    Langflow 支援多種模型來源:

    • 商用 API
    • OpenAI、Anthropic 等,只要在設定中填上 API Key
    • 適合需要好的語言品質,又不介意雲端的情境

    • 本地模型

    • 可透過像 Ollama 之類的本地推論服務來接
    • 適合零信任、不能把程式碼或資料送出公司網路的團隊

    你可以採取的行動:

    • 先在 Langflow 裡設好一組「雲端模型」作為開發時使用
    • 如果公司有安全需求,再加一組「指向 Ollama / 本地推論」的 LLM 節點,測試兩種效果差異

    4. 串第三方服務:Webhook / API 節點配置

    要讓 Agent 動起來,最重要是「能跟外部世界互動」。在 Langflow 裡,你通常會:

    1. 新增一個 HTTP / Webhook 節點
    2. 設定 URLHTTP 方法(GET / POST)、HeadersBody 模板
    3. 把 LLM 節點的輸出接到這個 HTTP 節點,讓模型決定要送什麼資料

    你可以採取的行動:

    • 先串一個你熟悉的服務(例如測試用的 webhook.site 或公司內的 sandbox API
    • 用很簡單的 payload(例如只送一行文字),確認連線和驗證沒問題

    範例與社群模板:照著做就有第一個 Agent

    Langflow 社群已經累積不少現成 Flow,可以直接匯入再改。

    常見範例類型:

    • FAQ 問答 Bot:已經幫你設好「文件載入 → 檢索 → LLM 回覆」
    • Email 助理:模型幫你改寫、翻譯、整理郵件內容
    • 簡易客訴處理 Agent:先分類情緒,再產出回覆草稿

    你可以採取的行動:

    • 在 Langflow 社群或 GitHub issue / discussions 中搜尋 templatesexamples
    • 選一個 Flow 匯入,改掉其中的 API Key、文件路徑,就變成你自己的版本

    延伸:跟其他 Agent 工具的差異

    市面上也有不少 Agent / 工作流工具,若你同時在看其它方案,可以用下面的表格快速比較定位:

    名稱 核心功能 免費方案 適合誰
    Langflow 視覺化設計 AI Agent 工作流,支援 LLM、記憶、工具調用 開源,自行部署 想自己畫流程、控管部署環境的開發者與技術團隊
    LangGraph 用程式碼定義 Agent 圖結構與狀態機,偏工程師導向 開源 Python 套件 喜歡用程式精細控制 Agent 狀態的後端工程師
    Graphify 把程式碼與文件變成知識圖譜,配合 AI 助理檢索 開源,自行部署 想整理程式碼資產、做跨檔案查詢的開發者

    如果你想要「看得見的流程圖 + 自己部署」,Langflow 是目前上手成本相對低的一條路:從拖第一個節點到完成一個能用的 Agent,控制在 30 分鐘內完全合理。

    💡 關鍵: 視覺化流程加開源部署,讓技術團隊既能快速試錯,又能保有環境與資料的掌控權。


    結論很簡單:先用 Langflow 畫出一個最小可行的 AI 工作流,把你手上最煩的一件重複工作丟給它。等你真正看到 Agent 每天幫你省下的時間,再來慢慢加節點、加工具,把流程做厚,這樣學習成本最低、成效也最明顯。

    🚀 你現在可以做的事

    • pip install langflowDocker 在本機跑起 Langflow,打開 http://localhost:7860 熟悉介面
    • 匯入一份公司 FAQ 或內部文件,照文中的「文件檢索 + LLM 回覆」流程畫出第一個 Bot
    • 在 Langflow 社群 / GitHub 上搜尋並匯入一個現成 Flow 範例,改成符合你公司 API 和文件路徑的版本
  • 把整個 Google 變成你的 AI Agent

    把整個 Google 變成你的 AI Agent

    📌 本文重點

    • google/skills 是 Google 產品專用的 AI Agent 工具箱
    • 透過現成 skills,LLM 可直接操作 Gmail / Calendar / Drive
    • 幾十行 Python 就能做出實用的 Workspace 自動化 Agent
    • 重視權限、安全與流程設計,才能放心在公司環境使用

    用一句話說清楚:google/skills 是一個專門替 Google 產品包好的「AI Agent 工具箱」,讓 LLM 不只會聊天,還能直接幫你操作 Gmail、Calendar、Drive 等服務。

    專案連結:https://github.com/google/skills


    google/skills 是什麼?可以幹嘛?

    用開發者的語言講:

    • 這是一組 Python 套件 + 一堆已實作好的「工具(skills)」
    • 每個 skill 就是一個可被 LLM 呼叫的函式,背後已幫你處理好 Google API 認證、資料結構、錯誤處理
    • 你只要把這些 skills 接到你熟悉的 Agent 框架(或自己寫個 loop),LLM 就能:
    • Gmail 搜尋、讀取、回覆郵件
    • Google Calendar 建立、更新、刪除行程
    • Google Drive 找檔案、讀內容
    • 以及其他 Google 產品(例如 Docs / Sheets / Tasks 等)

    💡 關鍵: 把繁瑣的 Google API 細節封裝成 skills,讓你專注在設計 Agent 流程,而不是處理認證與資料結構。

    目前常見支援的產品與典型技能

    以 GitHub 專案內容與官方範例為主,目前重點集中在 Workspace 產品:

    • Gmail:搜尋郵件、讀取內容、標記已讀、建立草稿、送出郵件
    • Calendar:建立事件、更新時間/地點、取消會議、查詢空檔
    • Drive:列出檔案、搜尋、下載內容、讀取檔案文字(搭配 API 或其他工具)
    • Tasks / Docs / Sheets:視版本與模組更新擴充,作為實驗性 skills 提供

    你可以把它想成:「Google 幫你寫好一堆『LLM 可安全使用的 Google API wrapper』,你只要負責接到自己的 Agent。」


    核心功能:讓 LLM 真的「動手做事」

    下面用三個代表性技能,拆開來看它怎麼組成一條完整工作流。

    1. Gmail:搜尋 + 回覆郵件

    能做的事

    • 根據條件(發信人、標題關鍵字、時間)搜尋郵件
    • 讀取郵件主旨、內容、附件資訊
    • 由 LLM 生成人性化回覆,再用 skill 建草稿或直接寄出

    你可以怎麼用

    • 自動整理每日「待回覆」郵件清單
    • 給 Agent 一句自然語言指令:
    • 「幫我找這週所有含『報價』的客戶信,產出一封統一回覆草稿」

    2. Calendar:建立 / 修改行程

    能做的事

    • 建立新事件(時間、地點、參與者、線上會議)
    • 更新時間或加入備註
    • 查詢某段時間的空檔

    你可以怎麼用

    • 讓 LLM 從郵件裡抓出「時間 + 地點 + 主題」,自動變成 Calendar 事件
    • 用一句話:
    • 「把明天 3–5 點標成『專注工作』,不要排會議」

    3. Drive:從檔案抓資料

    能做的事

    • 依檔名、類型、擁有者搜尋檔案
    • 下載或讀取檔案(再交給 LLM 摘要)

    你可以怎麼用

    • 找到昨天產出的報表,請 LLM 摘要要點後寄給主管
    • 自動從會議紀錄整理 action items,寫回 Google Docs

    把它們串起來:一條完整工作流範例

    例子:自動從郵件抓會議資訊 → 建行程 → 建備忘錄

    1. Agent 用 Gmail skill 搜尋主題含「Meeting」「邀請」的未讀信
    2. LLM 解析郵件內容,抽出:會議主題、時間、地點、參與者
    3. 用 Calendar skill 建立事件,寫入摘要與會議連結
    4. 用 Drive/Docs skill 建一份「Meeting Notes」文件,寫入議程、預先問題

    你只要負責描述「整體目標」,LLM 會自己決定何時呼叫哪個 skill。你的程式碼變得像是在描述流程,而不是在寫一堆 API 呼叫細節。

    💡 關鍵: 一旦 workflow 串起來,同一套 skills 可以重複組裝出不同的自動化場景,大幅降低開發新 Agent 的成本。


    實戰場景:把散落在 Workspace 的動作串起來

    下面是幾個可以立即實作的場景,每一個都對應到你可以「今天就試做」的腳本。

    1. 個人行程助理

    需求:每天早上想知道今天有哪些會議、重要信件、待辦。

    可以怎麼做

    • Gmail:抓「星號」或加標籤的關鍵郵件
    • Calendar:列出今天所有會議與空檔
    • Tasks / Drive:列出今日到期的任務與文件
    • LLM 整理成一封「每日簡報」,寄到 Gmail 或 Slack

    👉 可行動:用本文後面的「每日早上報告 Agent」最小範例修改即可。

    2. 客服工單整理

    需求:客服信都在 Gmail,手工整理太慢。

    技能組合

    • Gmail:抓取特定 label(例如 support)的所有新信
    • LLM:
    • 自動分類(bug、退款、帳號問題)
    • 抽出關鍵欄位(客戶、產品、影響範圍)
    • Drive/Sheets skill:寫入 Google 試算表,讓團隊追蹤

    3. 銷售線索追蹤

    需求:商務開發信散落在 Gmail、會議安排在 Calendar、紀錄在 Drive。

    技能組合

    • Gmail:搜尋含「報價」「demo」關鍵字的信
    • Calendar:對應已有 / 尚未安排會議的線索
    • Drive:讀取對應的提案文件
    • LLM:產出「Sales pipeline 摘要」,再寄給業務團隊

    4. 團隊報表自動彙總

    需求:每週要整理多份 Google Sheets / Docs 的數據與摘要。

    技能組合

    • Drive:搜尋指定資料夾裡的所有報表
    • Sheets/Docs skill:抓出指定欄位/段落
    • LLM:彙整成一份「本週關鍵指標 + 亮點 + 風險」
    • Gmail:寄給管理層

    每個場景本質上都是:用 skills 拉資料 → LLM 處理 → 再用 skills 寫回 Google 生態

    💡 關鍵: 只要 Workspace 流程是「讀資料 → 分類/摘要 → 回寫」,幾乎都能用同一套模式快速自動化。


    怎麼開始:從零到一的小 Agent(Python)

    這段寫給已經會基本 Python 的讀者。目標是做一個:

    「每日早上 9 點,整理今天的會議與重要郵件,寄一封報告給自己」

    步驟一:安裝套件與專案結構

    pip install google-skills openai  # 或你要用的 LLM 客戶端
    

    一個最小專案結構可以是:

    project/
      main.py          # 主程式,Agent 邏輯
      skills_config.py # Google skills 初始化
      .env             # 儲存 API Key 等環境變數
    

    步驟二:設定 Google API 憑證與權限

    1. 前往 https://console.cloud.google.com/
    2. 建立專案,啟用:
    3. Gmail API
    4. Calendar API
    5. (若需 Drive,就再開啟 Drive API)
    6. 建立 OAuth 用戶端 / Service Account 憑證
    7. 下載憑證 JSON,放進你的專案中,路徑寫在環境變數(例如 GOOGLE_APPLICATION_CREDENTIALS

    google/skills 會讀這些設定,幫你處理 OAuth 流程。第一次執行會要你開瀏覽器認證,通過後就可以長期使用。

    步驟三:初始化 skills

    # skills_config.py
    from google.skills import GmailSkill, CalendarSkill
    
    gmail_skill = GmailSkill(scopes=[
        "https://www.googleapis.com/auth/gmail.readonly",
        "https://www.googleapis.com/auth/gmail.send",
    ])
    
    calendar_skill = CalendarSkill(scopes=[
        "https://www.googleapis.com/auth/calendar",
    ])
    
    TOOLS = {
        "gmail": gmail_skill,
        "calendar": calendar_skill,
    }
    

    (實際類名與參數以官方 GitHub 為準,這裡是示意寫法。)

    步驟四:寫一個最小「每日報告」 Agent

    下面示意一個 純 Python + LLM + skills 的簡易 loop:

    # main.py
    import datetime as dt
    from skills_config import TOOLS
    from openai import OpenAI
    
    client = OpenAI()
    
    
    def get_today_summary():
        today = dt.date.today().isoformat()
    
        # 1) 用 Gmail skill 抓今天重要信件(實際用法依官方 API)
        important_emails = TOOLS["gmail"].search_messages(
            query="label:STARRED newer_than:1d"
        )
    
        # 2) 用 Calendar skill 抓今天所有事件
        events = TOOLS["calendar"].list_events(
            time_min=today + "T00:00:00Z",
            time_max=today + "T23:59:59Z",
        )
    
        prompt = f"""
    你是一個助理,請用條列整理以下資訊:
    1. 今日重要郵件(寄件人 + 主題)
    2. 今日會議(時間 + 標題)
    
    重要郵件:{important_emails}
    今日行程:{events}
    """
    
        resp = client.chat.completions.create(
            model="gpt-4o-mini",  # 或你使用的其他 LLM
            messages=[{"role": "user", "content": prompt}],
        )
        return resp.choices[0].message.content
    
    
    def send_daily_report():
        summary = get_today_summary()
        TOOLS["gmail"].send_message(
            to="your_email@example.com",
            subject="今日工作總覽",
            body=summary,
        )
    
    
    if __name__ == "__main__":
        send_daily_report()
    

    接下來只要用 crontab 或任一排程工具,每天早上 9 點跑一次 python main.py,你就有一個真正會「用 Gmail + Calendar 幫你工作」的小 Agent 了。


    延伸玩法:接到 LangGraph / MCP / 自建 loop

    google/skills 本身只是一組工具,你可以自由接到任何 Agent 框架。

    常見接法比較

    名稱 核心功能 免費方案 適合誰
    LangGraph 圖形化定義 Agent workflow、狀態機 開源 要做複雜流程 / 多工具協作
    MCP 標準化「工具伺服器」協議 規格開源 想讓多個模型共用同一組工具
    Simple loop(自建) while-loop + tool call + LLM 只要有 LLM 即可 想快速測試、腳本導向

    怎麼接 google/skills?

    • LangGraph:把 Gmail/Calendar skill 包成「tool node」,用 graph 描繪整條流程(例如:先讀 mail → 判斷 → 建行程)。
    • MCP:把 google/skills 包成 MCP 工具伺服器,就像 Reddit 上有人把產品目錄接到 Claude 一樣,任何支援 MCP 的 Agent 都能呼叫這組 Google 工具。
    • 自建 loop:如前面的 send_daily_report(),自己在程式裡控制什麼時候 call 哪個 skill。

    實務注意事項:安全、權限與 rate limit

    在公司環境用 google/skills,這幾點非常重要:

    1. 最小權限原則
    2. 只開啟必要的 scopes,例如只讀 Gmail 就不要給 send 權限
    3. 針對不同 Agent 建不同憑證,避免權限過大
    4. 審計與日誌
    5. 記錄每次工具呼叫(誰、什麼時候、對哪個帳號)
    6. 公司內部可用 SIEM / 日誌系統統一管理
    7. Rate limit 與配額
    8. Google API 有配額,批次任務要加上 sleep / retry
    9. 測試環境與正式環境要分開憑證,避免測試爆掉正式配額
    10. LLM 安全邏輯
    11. 對「寫入」類操作(寄信、刪除事件)加上確認步驟
    12. 可用 rule-based filter:例如禁止刪除某些標籤信件

    總結:把「會聊天的 LLM」變成「會用 Google 的助理」

    如果你已經每天活在 Gmail、Calendar、Drive 裡,google/skills 的價值很單純:

    • 你不用再對著 Google API 文件苦讀,只要調用現成的 skills
    • LLM 能真的幫你「按按鈕、拉資料、寫回去」,而不是只給你建議
    • 從個人行程助理,到團隊報表自動化,都可以在幾十行 Python 內完成第一個版本

    先從一個小腳本開始:「每日早上發報告」,跑通一次之後,你就會自然開始想把更多 Workspace 工作交給你的 Agent。

    🚀 你現在可以做的事

    • 打開 google/skills GitHub 專案,瀏覽支援的 skills 清單與範例程式
    • 依照文中的「每日報告 Agent」範例,在本機建立一個最小 Python 專案跑通一次
    • 在你的 Workspace 工作流中,挑一個「讀資料 → 整理 → 寄出」流程,試著用 google/skills + LLM 自動化它
  • 用狀態機把 13GB 小模型變成工程實習生

    用狀態機把 13GB 小模型變成工程實習生

    📌 本文重點

    • 小模型別當全能 Agent,要當被流程管控的小工
    • 用顯式狀態機拆任務,大幅提升穩定性與可回滾性
    • 每步輸出 JSON + schema 驗證,讓小模型也能穩定改碼

    只靠 prompt 堆疊,13GB 本地模型在中大型改碼任務幾乎必翻車:上下文飄掉、一次回錯一堆檔、改到一半忘記需求。把模型包進顯式狀態機,把「一次大任務」拆成可恢復的子任務,可以在不改模型的前提下,大幅提升穩定性、可觀測性與可測試性——正是那篇 13.8GB 模型從 2/10 變成 10/10 的核心做法。

    💡 關鍵: 只改調用方式與流程設計,就能把同一顆 13.8GB 小模型的表現從 2/10 拉到 10/10。


    重點說明

    1. 小模型為什麼在長對話裡特別容易翻車?

    從工程視角,有三個根本原因:

    1. token 預算太小 + 資訊密度太高
      13GB 級(多是 7B〜13B 參數)在 4k–16k context 內要同時塞:需求、專案結構、幾個檔案內容、測試結果、對話歷史,關鍵訊息會被截斷或壓縮到模型抓不到

    2. 上下文漂移(context drift)
      多輪長對話時,你不可能每次都重貼完整需求與檔案。模型只能靠「語意回憶」之前說過什麼,多輪後任務邊界就開始模糊:忘記原本的 constraint、改到不該動的檔案、把舊 bug 當新需求。

    3. 一次性決策成本過高
      傳統「一條大 prompt + chain-of-thought」會在單輪裡要求:理解需求 → 找檔 → 設計改動 → 寫碼 → 自我檢查。這在 token 限制與小模型推理能力下,極易在中間任一步 hallucinate,之後又沒有明確的 rollback 機制。

    關鍵結論: 小模型不適合當「一次性全能 Agent」,更適合當「被嚴格流程控制的小工」,讓狀態機負責 long-term 記憶與決策邊界。

    💡 關鍵: 把 long-term 記憶與流程決策交給狀態機,小模型只做局部推理,能顯著降低翻車率。


    2. 用顯式狀態機拆解大任務:核心設計

    把「改造一個中小型專案」拆成明確的 State + Transition

    常見狀態設計可以是:

    1. DISCOVER_PROJECT:掃描 repo、建立檔案索引
    2. PLAN_CHANGE:根據需求與索引產生修改計畫(檔案清單、步驟)
    3. EDIT_FILE:逐檔案修改(step-by-step)
    4. RUN_TESTS:執行測試、收集結果
    5. ROLLBACK_OR_FIX:測試失敗→嘗試修復或回滾
    6. DONE / FAILED:終止狀態

    每個狀態都只給模型 極簡上下文 + 明確輸入/輸出 schema,例如在 EDIT_FILE

    • 輸入:
    • 需求摘要(短)
    • 該檔案目前內容(或片段)
    • 計畫中對此檔案的變更描述
    • 輸出:
    • 結構化 JSON:{"status": "ok|skip|abort", "patch": "...diff..."}

    轉移條件示例:

    • DISCOVER_PROJECTPLAN_CHANGE:索引成功建立
    • PLAN_CHANGEEDIT_FILE:生成的計畫通過 schema 檢查
    • EDIT_FILERUN_TESTS:所有目標檔案處理完
    • RUN_TESTS
    • 全綠 → DONE
    • 有失敗 + 可定位 → EDIT_FILE (targeted fix)
    • 多次失敗 → ROLLBACK_OR_FIX

    失敗重試策略與超時機制

    • 每個狀態設定 max_retries,例如 2–3 次,超過則標記為 FAILED 或轉 ROLLBACK_OR_FIX
    • 每次 LLM 回應必經:
    • JSON schema 驗證
    • domain guard(例如禁止刪除大量無關 code)
    • 超時機制
    • 單次呼叫 timeout(例如 60s),保障工作流不被卡死
    • 整個工作流 wall-clock timeout(例如 30 分鐘),方便在 CI 或自動化工具中運行

    💡 關鍵: 把重試、超時、回滾寫死在狀態機邏輯裡,比指望 prompt 提醒模型「要小心」可靠太多。


    3. 實作範例:13GB 本地模型改造專案(Python)

    以下是精簡版 pseudo-code,示範如何把本地模型包在狀態機裡,跑 step-by-step 編碼、測試與回滾。假設:

    • 使用 vLLM / llama.cpp server 暴露出 OpenAI-compatible API
    • GPU:3060 12GB,模型用 Q4 / Q5 量化
    import enum
    import json
    import subprocess
    from dataclasses import dataclass
    from typing import Dict, Any, List
    import requests
    
    OPENAI_BASE = "http://localhost:8000/v1"
    MODEL_NAME = "local-13b-q4"
    
    class State(enum.Enum):
        DISCOVER_PROJECT = "DISCOVER_PROJECT"
        PLAN_CHANGE = "PLAN_CHANGE"
        EDIT_FILE = "EDIT_FILE"
        RUN_TESTS = "RUN_TESTS"
        ROLLBACK_OR_FIX = "ROLLBACK_OR_FIX"
        DONE = "DONE"
        FAILED = "FAILED"
    
    @dataclass
    class Context:
        repo_path: str
        requirement: str
        file_index: Dict[str, Any] = None
        plan: List[Dict[str, Any]] = None
        current_file_idx: int = 0
        test_result: str = ""
    
    
    def call_llm(system_prompt: str, user_prompt: str, max_tokens: int = 1024) -> str:
        resp = requests.post(
            f"{OPENAI_BASE}/chat/completions",
            json={
                "model": MODEL_NAME,
                "messages": [
                    {"role": "system", "content": system_prompt},
                    {"role": "user", "content": user_prompt},
                ],
                "temperature": 0.2,
                "max_tokens": max_tokens,
            },
            timeout=60,
        )
        resp.raise_for_status()
        return resp.json()["choices"][0]["message"]["content"]
    
    
    def discover_project(ctx: Context) -> Context:
        # 這裡可以用 ripgrep / fd 產生檔案清單,略
        ctx.file_index = {"files": ["src/a.py", "src/b.py"], "tests": ["tests/test_a.py"]}
        return ctx
    
    
    def plan_change(ctx: Context) -> Context:
        system = """你是資深工程師,輸出 JSON,字段: steps: [{file, description}]。"""
        user = f"需求: {ctx.requirement}\n可修改檔案: {ctx.file_index['files']}\n請產生最多 10 個步驟。"
        raw = call_llm(system, user)
        try:
            plan = json.loads(raw)
        except Exception:
            raise ValueError("PLAN_CHANGE: model output not JSON")
        ctx.plan = plan["steps"]
        ctx.current_file_idx = 0
        return ctx
    
    
    def apply_patch(repo_path: str, file: str, patch: str):
        # 建議用 unified diff + `patch` 指令,這裡簡化處理
        with open(f"{repo_path}/{file}", "w", encoding="utf-8") as f:
            f.write(patch)
    
    
    def edit_file(ctx: Context) -> Context:
        step = ctx.plan[ctx.current_file_idx]
        file_path = step["file"]
        with open(f"{ctx.repo_path}/{file_path}", encoding="utf-8") as f:
            content = f.read()
    
        system = """你只負責修改單一檔案。輸出 JSON: {status, patch}。
        - status: ok | skip | abort
        - patch: 完整檔案內容,不要解釋文字。"""
    
        user = f"需求: {ctx.requirement}\n此步驟: {step['description']}\n原始內容:\n{content[:4000]}"
        raw = call_llm(system, user, max_tokens=2048)
        try:
            out = json.loads(raw)
        except Exception:
            raise ValueError("EDIT_FILE: invalid JSON")
    
        if out["status"] == "ok":
            apply_patch(ctx.repo_path, file_path, out["patch"])
        elif out["status"] == "abort":
            raise RuntimeError("Model aborted edit")
    
        ctx.current_file_idx += 1
        return ctx
    
    
    def run_tests(ctx: Context) -> Context:
        proc = subprocess.run(["pytest"], cwd=ctx.repo_path, capture_output=True, text=True)
        ctx.test_result = proc.stdout + "\n" + proc.stderr
        return ctx
    
    
    def rollback_or_fix(ctx: Context) -> Context:
        # 真實情況應該搭配 git: reset --hard HEAD~1 或建立 branch
        # 這裡示意:交給模型看測試輸出,決定要修哪個檔案
        system = "請從測試輸出中找出最可能需要修改的單一檔案,輸出 JSON: {file, reason}"
        user = ctx.test_result[:4000]
        raw = call_llm(system, user)
        try:
            out = json.loads(raw)
        except Exception:
            raise ValueError("ROLLBACK_OR_FIX: invalid JSON")
    
        # 根據 out['file'] 重新插入 plan
        ctx.plan.insert(ctx.current_file_idx, {"file": out["file"], "description": out["reason"]})
        return ctx
    
    
    def run_state_machine(ctx: Context):
        state = State.DISCOVER_PROJECT
        retries: Dict[State, int] = {s: 0 for s in State}
        MAX_RETRIES = 2
    
        while True:
            try:
                if state == State.DISCOVER_PROJECT:
                    ctx = discover_project(ctx)
                    state = State.PLAN_CHANGE
    
                elif state == State.PLAN_CHANGE:
                    ctx = plan_change(ctx)
                    state = State.EDIT_FILE
    
                elif state == State.EDIT_FILE:
                    if ctx.current_file_idx >= len(ctx.plan):
                        state = State.RUN_TESTS
                    else:
                        ctx = edit_file(ctx)
    
                elif state == State.RUN_TESTS:
                    ctx = run_tests(ctx)
                    if "failed" in ctx.test_result:
                        state = State.ROLLBACK_OR_FIX
                    else:
                        state = State.DONE
    
                elif state == State.ROLLBACK_OR_FIX:
                    ctx = rollback_or_fix(ctx)
                    state = State.EDIT_FILE
    
                elif state in (State.DONE, State.FAILED):
                    return state, ctx
    
            except Exception as e:
                print(f"State {state} error: {e}")
                retries[state] += 1
                if retries[state] > MAX_RETRIES:
                    return State.FAILED, ctx
    
    
    if __name__ == "__main__":
        ctx = Context(repo_path="/path/to/repo", requirement="把 API v1 換成 v2 並修正測試")
        final_state, final_ctx = run_state_machine(ctx)
        print("Final state:", final_state)
    

    重點:

    • 模型只做 局部、可回滾的決策(例如一次只改一檔)。
    • 工作流邏輯(狀態、重試、回滾)都在 可測試的 Python 函式 中,而不是藏在 prompt 裡。

    若用 TypeScript + LangGraph / 自行寫狀態機,模式相同:每個 Node 是一個狀態,Edge 由測試結果與 JSON 輸出決定。


    4. 與「prompt + chain-of-thought」相比的實際好處

    1. 穩定性
    2. CoT 依賴模型「自己監督自己」,小模型的推理錯誤會被往後 propagate,沒有硬性 checkpoint。
    3. 狀態機把流程切成多個 可檢查的邏輯節點,每步都能強制過 schema、判斷失敗與回滾。

    4. 成本與資源

    5. 單輪 prompt 巨大 → token 費用高,且在本地 GPU 上速度慢。
    6. 狀態機讓每輪上下文更短、更聚焦,在 3060 12GB + Q4 模型上可以穩定跑 多輪短對話,總延遲往往比一輪巨 prompt 更好控制。

    7. 觀測性(logging / trace)

    8. 把每個狀態轉移、LLM input/output、git diff 全記錄(例如存到 SQLite / OpenTelemetry trace),可以:

      • 後覽失敗案例
      • 做離線分析:哪個狀態最常出錯?哪種需求最難?
    9. 可測試性

    10. 傳統做法難以單元測試 Agent:prompt 無法 deterministic。
    11. 狀態機可以用 fake LLM 或 replay 真實輸出,對每個 state handler 寫 unit test,例如:當測試結果是某種錯誤訊息時,ROLLBACK_OR_FIX 應插入哪個 plan。

    建議與注意事項

    1. 避免狀態爆炸

    • 限制狀態數量在 5–10 個,複雜度放在狀態內部的子函式,而不是新增一堆細碎狀態。
    • 優先建立 通用狀態模板PLAN / EXECUTE / VERIFY / RECOVER 四類,大部分工程任務都能套這個骨架。

    2. 處理 hallucination 與非法狀態

    • 所有 LLM 輸出一律要求 JSON + schema 驗證,非法就走重試邏輯。
    • EDIT_FILE 等關鍵步驟設計 domain guard
    • 檢查 patch 是否刪除超過 X% 行數;
    • 檢查是否涉及黑名單檔案(例如 config、CI YAML)。

    3. 設計「保守模式」避免改壞檔案

    建議預設開啟:

    1. 所有改動先走分支 / 工作目錄拷貝
    2. 狀態機只在 temp branch/dir 上動手,最後才由人類 review + merge。

    3. 只允許白名單檔案被修改

    4. PLAN_CHANGE 事先產出可修改清單,EDIT_FILE 收到不在清單內的檔案時直接拒絕。

    5. 必備 diff 檢查

    6. 每次改檔後,log 一份 git diff。
    7. 可以加一個 HUMAN_APPROVAL 狀態,在 CI 或 IDE 裡讓人按「Approve」才繼續。

    4. 3060 12GB 本地 GPU 的實務建議

    • 模型:選 Q4_K_M / Q5 量化的 7B–13B 開源模型(如 Llama 系家族、Qwen 等),在 Agentic coding 任務上實測延遲可接受。
    • 推理引擎:
    • llama.cpp / ollama:部署簡單,適合單機開發。
    • vLLM:若你需要高併發與更細緻的 batching,可考慮,但對記憶體稍敏感。
    • 參數建議:
    • max_tokens 控制在 512–2048,依狀態不同調整。
    • temperature 低於 0.3,減少 hallucination。
    • 避免在單輪塞完整檔案,改成 片段 + 明確上下文(例如「你只看這個 function」)。

    5. 映射到現有 Agent framework 的模式

    這套思路可以直接映射到:

    • LangChain / LangGraph
    • 每個狀態 = 一個 Node(通常是 Tool + LLM)。
    • 轉移條件透過 conditional edges 判斷 JSON output 中的 status / next_state
    • 用 LangGraph 的 checkpointingContext 存到外部 store,可做恢復與可視化。

    • LangMCP(可檢視狀態的 Agent framework)

    • Context 中的 file_index / plan / test_result 全部納入 inspectable state
    • 除錯時可以直接在 UI 裡看到「Agent 在哪一步做錯決策」,而不是只看 tokens trace。

    • Claude Code / goal-workflow 類工具

    • 把這裡的狀態機當作後端 orchestrator,前端 IDE 只負責:設定 goal → 顯示 plan → 顯示每步 diff / 測試 → 提供人類 approve。

    總結工程模式:

    LLM 做局部推理 + 生成,狀態機做長期決策 + 記憶 + 恢復。
    把「智慧」從模型本體,搬到你可控、可測、可觀測的工作流程式碼中,13GB 小模型也能在工程任務裡穩定交付 10/10 的結果。


    🚀 你現在可以做的事

    • 在本地架一個 llama.cppvLLM 的 OpenAI-compatible 服務,載入一顆 7B–13B Q4/Q5 模型試跑上文的狀態機範例
    • 把你現有的「一條大 prompt 改碼流程」改寫成 5–10 個明確狀態,並為每步定義 JSON schema 與 max_retries
    • 在 CI 或開發機中為這套狀態機加上 logging / trace(例如 SQLite 或 OpenTelemetry),實際分析哪個 state 最常出錯