前端仔轉型 AI 應用開發的 思維轉變

前言

作為一個寫了 5 年 Vue + React 的前端,我用 Python + LangGraph 做了一个企業級 AIOps 排障 Agent。過程中最大的感悟是:真正難的不是調大模型,而是讓大模型少干活。


這篇文章講什麼

我不會從頭教你代碼怎麼寫,因為這個年代工程思維才是價值。我要分享的是一個前端工程師做 AI Agent 專案的完整心路歷程——從「LLM 是萬能的」到「LLM 只在刀刃上用」的認知轉變,以及這個過程中我踩的坑和總結的方法論。

如果你也是前端,也在考慮往 AI/全端方向轉,這篇文章可能對你有用。

文章結構:

  1. 為什麼一個前端要做 Agent
  2. 架構設計:9 個節點只有 1 個用 LLM
  3. 最值錢的不是 LLM,是收斂窗口和限流器
  4. Redis 不是加分項,是必需品
  5. 前端思維在 Agent 開發中的意外優勢
  6. 給想轉型的前端小夥伴的建議

一、為什麼一個前端要做 Agent

先說背景:我寫了 5 年前端,技術棧以 Vue + React + TypeScript 為主,做的是 B 端企業級工具平台——從零搭建過元件庫、主導過多個複雜中後台系統的架構設計,日常處理的就是大資料量表格虛擬滾動、複雜表單聯動、權限路由體系、微前端接入這些硬骨頭。隨著 AI 浪潮發展,這幾年也不是只寫前端,因為做的是內部工具平台,經常需要自己寫 Node.js 的 BFF 層對接後端微服務介面,所以對後端的 API 設計、資料庫查詢、中間件這些概念並不陌生。因此絕對不是後端零基礎。

去年做了我的第一個 Agent 專案——AI 智能客服。那個專案讓我入了門:學會了 Prompt 工程、RAG 檢索增強、對話狀態管理。後端部分用的是 Python + FastAPI,也是那個專案讓我正式從 Node.js 過渡到了 Python 技術棧。但說實話,智能客服的 Agent 邏輯相對簡單——使用者提問 → 檢索知識庫 → LLM 生成回答,基本是單輪或多輪對話,工程複雜度不高。

做完客服 Agent 後我一直在想:有沒有更複雜的場景,能把 Agent 的工程化能力真正體現出來?

機會來了——一場普通的會議中:「每天 86 個服務的告警,光是看一遍就要 1 小時,分析根因又要半小時。」

我一聽就知道,這個場景比客服複雜太多了:多資料來源(指標 + 日誌 + 機器狀態)、多步推理(收斂 → 分類 → 採集 → 診斷)、成本敏感(每天幾百次 LLM 調用)。正好是我想要的「第二個 Agent 專案」。

於是我主動請纓做了這個 AIOps 排障 Agent。第一版 MVP 花了兩週跑通核心流程(收斂 → 分類 → 採集 → 診斷),先在 5 個核心服務上灰度驗證。之後又用了 1 個多月做工程化優化(Redis 快取層、事件驅動改造、限流和成本控制),逐步擴到全量 86 個微服務、2100 台伺服器。最終 MTTR(平均修復時間)從 45 分鐘降到 12 分鐘。

下面我把第二個 Agent 專案中最核心的設計思路分享出來——很多是從第一個客服 Agent 踩坑後總結的教訓。


二、架構設計:9 個節點只有 1 個用 LLM

第一版:全靠 LLM(客服 Agent 的慣性思維)

做客服 Agent 時,流程就是「使用者問什麼 → LLM 答什麼」,LLM 承擔了幾乎所有智能決策。我一開始做排障 Agent 時延續了這個思路:

告警進來 → 丟給 LLM → LLM 告訴我根因是什麼 → 完事

一跑起來就出問題了——客服場景一天幾百次對話還 hold 得住,運維場景一天幾千條告警直接炸了

  • 太貴:一條告警要消耗 4000+ token,86 個服務每天幾百條告警,一天 ¥85
  • 太慢:每次 LLM 調用 3–5 秒,所有環節都調 LLM 的話要 30 秒
  • 不可控:LLM 偶爾「抽風」給個完全離譜的分類,後面的診斷全跑偏

第二版:規則優先,LLM 只做規則做不了的事

客服 Agent 教會了我怎麼跟 LLM 打交道,但排障 Agent 教會了我什麼時候不該用 LLM

我重新審視了整個流程,發現一個關鍵事實:

80% 的決策是確定性的,不需要 LLM。

比如告警分類——如果 3 條告警裡 2 條是 latency 類型,那事件類型就是「延遲異常」,這用 Python 的 Counter.most_common 一行程式碼就能搞定,為什麼要花錢讓 LLM 來選?

最終架構是 LangGraph 狀態機,9 個節點這樣分工:

  • correlate → 純規則(按服務 + 依賴鏈收斂告警)
  • parse_input → 純規則(擷取欄位)
  • classify → 80% 規則 + 20% LLM 兜底
  • build_plan → LLM 建議 + 規則強校驗
  • run_tools → 純工具呼叫(查 Prometheus / ES / CMDB)
  • diagnose → ⭐ 100% LLM(唯一核心)
  • risk_check → 純規則(關鍵字匹配 "重啟" / "回滾")
  • finalize → 純規則(置信度校準)
  • settle_case → 純規則(高置信度自動沉澱案例)

LLM 只在 diagnose 節點真正不可替代——因為從「錯誤率飆升 + ConnectionRefused 日誌 + 剛部署新版本」這些線索推導出「新版本連接池配置錯誤」,需要跨領域關聯推理,規則寫不了。

分類節點的程式碼,簡單到讓我意外

from collections import Counter

TYPE_MAP = {"error_rate": "error_rate", "latency": "latency",
            "cpu": "resource", "memory": "resource"}

def classify_incident(state):
    # 投票:統計每種告警類型出現次數,取最多的
    counter = Counter(state["alert_types"])
    dominant = counter.most_common(1)[0][0]  # 比如 "latency"

    result = TYPE_MAP.get(dominant)  # 查規則表
    if result:
        return {"incident_type": result}  # 命中,不調 LLM

    return {"incident_type": _llm_classify(state)}  # 兜底

前端小夥伴應該覺得很眼熟——這跟條件渲染是一樣的邏輯:

if (type === 'error') return <ErrorIcon />;     // 規則命中
if (type === 'warning') return <WarningIcon />; // 規則命中
return <DefaultIcon />;                         // 兜底

效果對比

指標 全 LLM 方案 規則 + LLM 混合
LLM 調用次數 / 每次診斷 5–9 次 1–2 次
Token 消耗 ~10,000 ~2,500
延遲 15–30 秒 3–5 秒
日均成本 ¥85 ¥32

一句話總結:不是 LLM 不好,是你不該讓它做它不擅長的事。


三、最值錢的不是 LLM,是收斂窗口和限流器

告警風暴問題

上線第一天就出事了。

凌晨 2 點,一個服務掛了,5 分鐘內產生了 47 條告警(error_rate、latency、cpu 同時飆)。按原來的設計,每條告警觸發一次診斷,47 次 LLM 調用,一算要 ¥15——就這一個故障。

而且 47 次診斷結論都是一樣的,因為根因就一個。

解決方案:2 分鐘收斂窗口

我做了一個 AlertBuffer——同一個服務的告警先攢著,2 分鐘後一起診斷:

def add(self, alert):
    key = (alert["project_id"], alert["service_name"])

    # 追加到 Redis 列表
    r.rpush(buffer_key, json.dumps(alert))

    # SETNX:只有第一條告警才啟動定時器
    is_first = r.set(timer_key, "1", nx=True, ex=120)
    if is_first:
        # 120 秒後自動 flush
        Timer(120, self._flush, args=[key]).start()

前端小夥伴應該秒懂——這就是 debounce 的伺服器端版本

// 前端 debounce:停止輸入 300ms 後才搜尋
const debouncedSearch = debounce(search, 300);

// 後端 AlertBuffer:同服務告警 120s 後才診斷
alert_buffer.add(alert)  // 不立即診斷,等窗口到期

區別是前端 debounce 每次按鍵會重置計時器,而告警緩衝是固定窗口——第一條告警啟動 120 秒倒數,後續告警只追加不重置。更像是 throttle + batch

47 條告警 → 1 次 LLM 調用。省了 46 次。

限流器:滑動窗口

LLM API 有 rate limit(每分鐘 30 次),我用 Redis Sorted Set 做了滑動窗口限流:

def acquire(self, r):
    now = time.time()

    # ① 清理 60 秒前的紀錄
    r.zremrangebyscore(key, "-inf", now - 60)
    # ② 看當前窗口有多少次
    count = r.zcard(key)
    # ③ 沒超限就放行
    if count < 30:
        r.zadd(key, {f"{now}:{thread_id}": now})
        return True
    return False

為什麼不用簡單計數器?因為固定窗口有邊界突發問題:第 59 秒來 30 個請求 + 第 61 秒又來 30 個 = 2 秒內 60 個請求,但兩個窗口各自都沒超限。Sorted Set 滑動窗口保證任意連續 60 秒內不超過 30 次


四、Redis 不是加分項,是必需品

一開始我什麼都存在記憶體裡——緩衝佇列用 dict,快取用 dict,限流用 deque。

看起來能跑,直到我問自己:

「服務重啟了,正在收斂的告警怎麼辦?」 「多部署一個實例,限流計數器各算各的,總量不就超了?」

答案是:必須用 Redis

但我做了一個關鍵設計——Redis 優先,自動降級到記憶體

def add(self, alert):
    r = get_redis()          # 嘗試取得 Redis 連線
    if r is not None:
        self._add_to_redis(r, alert)   # Redis 可用 → 用 Redis
    else:
        self._add_to_memory(alert)     # Redis 掛了 → 降級到記憶體

為什麼不直接強依賴 Redis?

AIOps 排障場景,可用性比一致性重要。 Redis 掛了,寧可用記憶體頂著(可能重啟丟資料),也不能因為快取不可用就不診斷。

最終 Redis 用了 4 個場景:

  • 告警緩衝隊列:List(RPUSH)——重啟不丟、多實例共享
  • LLM 結果快取:String + TTL——相同告警不重複調 LLM
  • 調用限流:Sorted Set——多實例共享計數
  • 每日 Token 預算:INCRBY——原子累加、次日自動清零

五、前端思維在 Agent 開發中的意外優勢

做完這個專案,我發現前端經驗給了我幾個別人沒有的優勢:

1. 狀態管理思維 → Agent 狀態機

LangGraph 的 AgentState 本質就是一棵全域狀態樹,9 個節點像 reducer 一樣處理狀態:

# Agent 的 state 流轉
{"alert_messages": [...], "incident_type": None}
    → correlate → {"alert_messages": [...更多], ...}
    → classify  → {"incident_type": "latency", ...}
    → diagnose  → {"root_causes": [...], ...}

這跟 Redux 一模一樣:

// Redux 的 state 流轉
{alerts: [], type: null}
    → FETCH_ALERTS → {alerts: [...], ...}
    → CLASSIFY     → {type: 'latency', ...}
    → DIAGNOSE     → {rootCauses: [...], ...}

2. 元件化思維 → 節點解耦

前端寫元件講究「單一職責、props 進 events 出」。Agent 節點也一樣——每個節點只從 state 裡取自己需要的欄位,處理完回傳新欄位,不關心其他節點。

這讓我天然就把節點寫得很解耦,後來加新功能(比如 risk_check)只需要新增一個節點檔案 + 在圖裡加一條邊。

3. 降級思維 → 容錯設計

前端天天跟「介面掛了怎麼辦」打交道(loading → error → empty 三態)。寫 Agent 時我本能地給每個節點都加了降級:

  • LLM 掛了 → 返回保守結論(confidence: 0.3)
  • Redis 掛了 → 降級到記憶體
  • 工具查詢失敗 → 跳過,用已有證據繼續

有些純後端/AI 背景的人會忽略這些,因為他們習慣「調不通就報錯退出」。

4. Debounce/Throttle → 收斂窗口

上面講的告警收斂,本質就是 debounce。前端經常寫這個,我看到「告警風暴」的問題第一反應就是「加個 debounce」,而後端同事可能會想到 Kafka 之類的重方案。


六、給想轉型的前端小夥伴的建議

1. 不要從零學 Python,從「翻譯」開始

我學 Python 的方式不是看教程,而是把我熟悉的 JS 邏輯翻譯成 Python

// JS: 陣列去重
const unique = [...new Set(arr)];

// JS: 條件渲染
const icon = type === 'error' ? <ErrorIcon /> : <DefaultIcon />;

// JS: debounce
const debounced = debounce(fn, 300);

翻成 Python:

# Python: 列表去重
unique = list(set(arr))

# Python: 條件分支
icon = ErrorIcon if type == 'error' else DefaultIcon

# Python: Timer(類似 setTimeout)
Timer(120, fn).start()

語法不同,但程式設計思維是通用的

2. Agent 的核心不是 LLM,是工程化

很多人覺得做 AI Agent 就是「調 LLM API」。不是的。

我這個專案裡 LLM 相關程式碼大概佔 15%。另外 85% 是:

  • 告警收斂邏輯(狀態管理)
  • Redis 快取和限流(中間件)
  • 資料源抽象層(設計模式)
  • 並發調度(執行緒池)
  • 錯誤處理和降級(容錯)

這些全是工程能力,跟 LLM 無關,跟前端經驗高度相關。

3. 選一個你熟悉的業務場景做 Agent

不要憑空造需求。找一個你日常工作中有的痛點:

  • 做運維平台的 → AIOps 排障 Agent(就是我做的這個)
  • 做客服系統的 → 智能客服 Agent
  • 做資料平台的 → 自動化資料分析 Agent
  • 做文件系統的 → RAG 知識庫 Agent

業務理解 + 工程能力 + AI 能力 = 你的不可替代性。


小結

做完這個專案,我最大的感悟是:

AI Agent 開發 = 10% 的 LLM + 90% 的工程化。

LLM 是那個做「最後一哩」推理的天才,但天才需要一個靠譜的團隊幫他準備好資料、控制好成本、兜住錯誤。這個「團隊」就是你寫的工程程式碼。

而前端工程師天生擅長這些——狀態管理、元件化、降級容錯、效能優化——只是以前這些能力用在了瀏覽器裡,現在換到了伺服器端而已。

如果你也是前端,也想往 AI 方向試試,別猶豫。工程能力比純寫程式能力值錢得多,因為你永遠沒有 AI 會寫系統工程的那套東西。


原文出處:https://juejin.cn/post/7620595472269836322


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝14   💬10   ❤️2
416
🥈
我愛JS
📝2   💬9   ❤️2
92
🥉
💬1  
4
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登