AI 工程從零開始|Phase 13 Part 2:AI 工作流程編排 — LangChain、LlamaIndex 與生產管線

大多數人第一次接觸 LLM 應用,寫的是一個 openai.chat() 呼叫。 但到了生產環境,你需要的是:步驟間傳遞上下文、錯誤自動重試、中間結果快取、非同步平行執行。 單次呼叫處理不了這些;你需要的是一條管線,而不是一個函式。 本文從框架比較到生產監控,完整解析 AI 工作流程編排的每一個決策點。


面試情境:你的團隊要上線一個 RAG 客服機器人,需要:查詢改寫 → 向量檢索 → 文件重排序 → 生成答案 → 品質過濾。QA 反映目前有 15% 的查詢因為某一步失敗而整條管線崩潰。架構師問你:如何設計這個管線的錯誤處理策略,以及你會選哪個編排框架?請解釋你的技術決策。


一、核心問題:單次 LLM 呼叫為什麼不夠

1.1 真實 AI 應用的複雜度

想像你在構建一個智慧文件問答系統。用戶問:「上個季度我們在亞太區的收入是多少?」

一個 openai.chat() 能回答嗎?不行。你需要:

  1. 查詢理解:識別出「上個季度」和「亞太區」是關鍵限定詞
  2. 查詢改寫:展開成「Q3 2025 Asia Pacific revenue」等多個搜尋變體
  3. 向量檢索:從數千份財報文件中找出相關段落
  4. 重排序:用 Cross-Encoder 重新對候選段落評分
  5. 上下文組裝:把最相關的段落和對話歷史組成 Prompt
  6. 生成:呼叫 LLM 生成答案
  7. 品質驗證:確認答案有引用來源,沒有幻覺

這是 7 個步驟、至少 4 個外部服務呼叫、數個狀態轉換。這就是工作流程編排要解決的問題。

1.2 沒有編排框架時的痛點

痛點具體表現影響
錯誤傳播步驟 3 失敗 → 整條管線崩潰15–30% 請求失敗率
重複程式碼每個專案重寫 retry / logging開發速度 -40%
測試困難無法對單一步驟做單元測試Bug 定位時間 3×
無可觀測性不知道哪個步驟慢P95 延遲難以優化
狀態管理中間結果存在記憶體,重啟即失長任務無法恢復

1.3 編排框架的核心價值

編排框架提供三個關鍵抽象:

  • 步驟(Step):單一可測試、可替換的執行單元
  • 管線(Pipeline):步驟的組合,定義執行順序和資料流
  • 執行引擎(Runtime):處理並行、重試、狀態持久化

二、三個演進階段(POC → MVP → Scale)

Phase 1:POC(< 1K 用戶,< 100 QPS)

目標:驗證想法,2 週內有 demo。可接受的妥協:無狀態、無重試、同步執行。

╔══════════════════════════════════════════════════════╗
║  Phase 1:線性 Chain(同步,無持久化)                ║
╚══════════════════════════════════════════════════════╝

用戶請求
    │
    ▼
┌───────────────┐
│  Query Rewrite │  ← LLM 呼叫 ~500ms
└───────┬───────┘
        │
        ▼
┌───────────────┐
│  Vector Search │  ← Pinecone/FAISS ~100ms
└───────┬───────┘
        │
        ▼
┌───────────────┐
│  LLM Generate  │  ← LLM 呼叫 ~1500ms
└───────┬───────┘
        │
        ▼
    回傳結果

總延遲:~2.1s(串行)
錯誤處理:無(任一步驟失敗即 500)
狀態:無持久化
框架:LangChain 基礎 Chain

Phase 1 技術選型

  • 框架:LangChain(社群最大,範例最多)
  • 向量庫:Chroma(本地,零配置)
  • 部署:單一 FastAPI 服務
  • 監控:Python logging

成本/複雜度:開發 3 天,月成本 < $50,0 個 SRE 負擔。


Phase 2:MVP(10K–200K 用戶,100–1K QPS)

目標:生產安全,團隊能操作,不需要常駐救火。

╔══════════════════════════════════════════════════════════════╗
║  Phase 2:DAG 管線(非同步,部分持久化,基礎重試)           ║
╚══════════════════════════════════════════════════════════════╝

                    用戶請求
                        │
                        ▼
              ┌─────────────────┐
              │   API Gateway   │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │  Task Queue     │  ← Redis/Celery
              └────────┬────────┘
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
  ┌──────────┐  ┌──────────┐  ┌──────────┐
  │  Query   │  │  Query   │  │  Query   │  ← 並行 3 個改寫
  │ Rewrite 1│  │ Rewrite 2│  │ Rewrite 3│
  └────┬─────┘  └────┬─────┘  └────┬─────┘
       └──────────────┴─────────────┘
                       │ merge
                       ▼
              ┌─────────────────┐
              │  Vector Search  │  ← 並行搜尋
              │  (3 queries)    │
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │   Re-ranking    │  ← Cross-Encoder
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │  LLM Generate   │  ← 含 retry(3)
              └────────┬────────┘
                       │
                       ▼
              ┌─────────────────┐
              │ Quality Filter  │  ← 幻覺檢測
              └────────┬────────┘
                       │
                       ▼
                   回傳結果

總延遲:~1.4s(並行 query rewrite)
錯誤處理:步驟級重試,降級策略
狀態:Redis 快取中間結果(TTL 1h)
框架:LangChain LCEL + LangSmith

Phase 2 新增組件

  • 非同步執行:asyncio + aiohttp
  • 中間結果快取:Redis(TTL 1 小時)
  • 重試機制:指數退避,最多 3 次
  • 可觀測性:LangSmith tracing
  • 降級策略:reranker 失敗時跳過,直接用向量搜尋結果

成本/複雜度:開發 2 週,月成本 $200–$800,需 1 名工程師維護。


Phase 3:Scale(200K–1M+ 用戶,1K–10K QPS)

目標:企業級,自動擴縮,成本優化,SLA 99.9%。

╔═══════════════════════════════════════════════════════════════════╗
║  Phase 3:分散式工作流程(有狀態,多 Worker,全面可觀測)         ║
╚═══════════════════════════════════════════════════════════════════╝

用戶請求
    │
    ▼
┌──────────────────────────────────────────────────────────┐
│  API Layer (Kubernetes, HPA)                             │
│  Rate Limiting │ Auth │ Request Validation               │
└───────────────────────────┬──────────────────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────┐
│  Workflow Orchestrator (Temporal / Prefect)              │
│                                                          │
│  WorkflowID: wf-{uuid}  ← 持久化,可恢復                │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐          │
│  │Step 1│→│Step 2│→│Step 3│→│Step 4│→│Step 5│          │
│  └──────┘ └──────┘ └──────┘ └──────┘ └──────┘          │
│     ↑ checkpoint 每步驟完成後寫入                         │
└───────────────────────────┬──────────────────────────────┘
                            │
            ┌───────────────┼───────────────┐
            ▼               ▼               ▼
    ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
    │  LLM Worker  │ │ Search Worker│ │ Rank Worker  │
    │  Pool (Auto) │ │  Pool (Auto) │ │  Pool (Auto) │
    └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
           │                │                │
           └────────────────┴────────────────┘
                            │
                            ▼
┌──────────────────────────────────────────────────────────┐
│  Observability Stack                                     │
│  Prometheus │ Grafana │ Jaeger │ LangSmith               │
│  Step 延遲 │ 錯誤率 │ LLM Token 用量 │ 答案品質指標      │
└──────────────────────────────────────────────────────────┘

可靠性:每步驟完成後持久化,Worker 崩潰後自動恢復
成本優化:LLM 呼叫結果快取(Semantic Cache,命中率 ~30%)
SLA:99.9%(<8.7h 停機/年)

Phase 3 新增組件

  • 工作流程引擎:Temporal(金融級持久化)或 Prefect
  • Semantic Cache:相似查詢命中快取,節省 LLM 成本 ~30%
  • 多 Worker 池:依步驟類型分別擴縮
  • 成本追蹤:每請求 Token 用量計費到功能

成本/複雜度:開發 6–8 週,月成本 $2K–$10K,需 2–3 名工程師維護。


三、Chain vs DAG:工作流程的兩種思維

3.1 Chain(鏈式)

步驟按固定順序串行執行,前一步的輸出是後一步的輸入。

┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐
│  A   │───▶│  B   │───▶│  C   │───▶│  D   │
└──────┘    └──────┘    └──────┘    └──────┘

優點:簡單、易除錯、資料流清晰
缺點:無法並行、單點失敗影響全鏈
適用:步驟間有嚴格依賴關係

3.2 DAG(有向無環圖)

步驟間的依賴關係明確定義,無依賴的步驟可以並行執行。

         ┌──────────────────────────┐
         │                          │
    ┌────┴───┐                 ┌────┴───┐
    │Query 1 │                 │Query 2 │  ← 並行
    └────┬───┘                 └────┬───┘
         │                          │
         └──────────┬───────────────┘
                    │ merge
                    ▼
              ┌──────────┐
              │  Search  │
              └────┬─────┘
                   │
         ┌─────────┼─────────┐
         ▼         ▼         ▼
    ┌─────────┐ ┌──────┐ ┌──────┐  ← 並行後處理
    │ Rerank  │ │Filter│ │Score │
    └────┬────┘ └──┬───┘ └──┬───┘
         └─────────┴────────┘
                   │ merge
                   ▼
             ┌──────────┐
             │ Generate │
             └──────────┘

優點:並行執行,延遲低;步驟可獨立替換
缺點:依賴關係複雜時難以 debug
適用:有可並行步驟的生產管線

3.3 何時選 Chain,何時選 DAG

情境選 Chain選 DAG
步驟數≤ 5≥ 6
並行需求有(延遲敏感)
團隊規模1–2 人3+ 人
生產 SLA無嚴格要求> 99%
調試頻率需要詳細 tracing

四、LangChain 架構解析:LCEL 表達式語言

4.1 LCEL 的核心設計

LangChain Expression Language(LCEL)是 LangChain v0.2+ 的核心抽象。一切組件都實現 Runnable 介面,可以用 | 運算子組合。

 1from langchain_core.runnables import RunnablePassthrough, RunnableLambda
 2from langchain_core.prompts import ChatPromptTemplate
 3from langchain_openai import ChatOpenAI
 4
 5# 定義各步驟
 6rewrite_prompt = ChatPromptTemplate.from_template(
 7    "Rewrite this query for vector search: {query}"
 8)
 9llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
10
11# LCEL 管線:| 運算子組合
12rewrite_chain = rewrite_prompt | llm | StrOutputParser()
13
14# 並行執行:RunnableParallel
15parallel_searches = RunnableParallel(
16    original=RunnablePassthrough(),
17    rewritten=rewrite_chain,
18)
19
20# 完整管線
21full_pipeline = (
22    parallel_searches
23    | retriever
24    | reranker
25    | answer_prompt
26    | llm
27    | StrOutputParser()
28)

4.2 LCEL 的關鍵特性

自動串流(Streaming):管線中任何一步都可以串流輸出,無需額外配置。

非同步支援:每個 Runnable 都有 .ainvoke() / .astream() 非同步版本。

內建重試

1from langchain_core.runnables import RunnableRetry
2
3resilient_llm = llm.with_retry(
4    retry_if_exception_type=(RateLimitError, TimeoutError),
5    stop_after_attempt=3,
6    wait_exponential_jitter=True,
7)

Fallback 降級

1# 主要模型失敗時自動切換
2robust_llm = ChatOpenAI(model="gpt-4o").with_fallbacks(
3    [ChatOpenAI(model="gpt-4o-mini")]
4)

4.3 LangSmith 可觀測性

LangSmith 是 LangChain 的官方 tracing 平台。設定環境變數後自動捕獲所有步驟:

1LANGCHAIN_TRACING_V2=true
2LANGCHAIN_API_KEY=your_key
3LANGCHAIN_PROJECT=your_project

每次管線執行會記錄:

  • 各步驟輸入/輸出
  • Token 用量(prompt / completion)
  • 延遲分解(哪個步驟最慢)
  • 錯誤堆疊追蹤

實際數字:接入 LangSmith 後,P95 延遲的問題步驟定位時間從 2 小時縮短到 15 分鐘。


五、LlamaIndex:以資料為中心的編排哲學

5.1 LlamaIndex 的差異化定位

LlamaIndex 的核心假設是:AI 應用的瓶頸在資料連接,不在 LLM 呼叫本身。

它提供三個 LangChain 沒有的一流抽象:

  • Connector:70+ 資料來源(Confluence、Notion、S3、資料庫…)
  • Index:VectorStoreIndex、KnowledgeGraphIndex、SummaryIndex 等 8 種
  • Query Engine:針對不同查詢模式優化的引擎

5.2 LlamaIndex Workflow(v0.10+)

新版 LlamaIndex 引入 Workflow 類,支援事件驅動的有狀態執行:

 1from llama_index.core.workflow import (
 2    Workflow, step, Event, StartEvent, StopEvent
 3)
 4
 5class QueryRewriteEvent(Event):
 6    queries: list[str]
 7
 8class SearchResultEvent(Event):
 9    results: list[NodeWithScore]
10
11class RAGWorkflow(Workflow):
12    @step
13    async def rewrite_query(self, ev: StartEvent) -> QueryRewriteEvent:
14        # 查詢改寫邏輯
15        queries = await self._rewrite(ev.query)
16        return QueryRewriteEvent(queries=queries)
17
18    @step
19    async def search(self, ev: QueryRewriteEvent) -> SearchResultEvent:
20        # 並行向量搜尋
21        results = await asyncio.gather(*[
22            self.index.aretrieve(q) for q in ev.queries
23        ])
24        return SearchResultEvent(results=self._merge(results))
25
26    @step
27    async def generate(self, ev: SearchResultEvent) -> StopEvent:
28        answer = await self._generate(ev.results)
29        return StopEvent(result=answer)

5.3 LlamaIndex 的獨特優勢

知識圖譜整合KnowledgeGraphIndex 自動從文件提取實體關係,支援多跳查詢。對「誰是 A 公司 CEO 的前任老闆?」這類問題,準確率比純向量搜尋高 35%。

多模態支援:ImageIndex 處理圖片,TableIndex 處理結構化資料。混合內容文件(PDF 含表格)的解析準確率比 LangChain 高 ~20%。

Sub-Question 引擎:自動把複雜問題分解成多個子問題,分別查詢後合併答案。對複雜分析型問題的 recall 提升 ~25%。


六、有狀態工作流程:中間結果持久化與斷點續跑

6.1 為什麼需要狀態持久化

對於需要 10–60 秒的長任務(如分析 100 頁 PDF),無狀態設計有致命缺陷:

  • Worker 崩潰:任務從頭重跑,成本浪費
  • 用戶關閉頁面:無法在後台繼續
  • LLM 超時(Step 5/10):前 4 步的結果付之一炬

6.2 Redis 作為中間狀態快取

 1import redis
 2import json
 3import hashlib
 4
 5class PipelineStateCache:
 6    def __init__(self, redis_client: redis.Redis, ttl: int = 3600):
 7        self.r = redis_client
 8        self.ttl = ttl
 9
10    def get_step_result(self, workflow_id: str, step_name: str):
11        key = f"wf:{workflow_id}:step:{step_name}"
12        data = self.r.get(key)
13        return json.loads(data) if data else None
14
15    def set_step_result(self, workflow_id: str, step_name: str, result):
16        key = f"wf:{workflow_id}:step:{step_name}"
17        self.r.setex(key, self.ttl, json.dumps(result))
18
19# 管線執行時檢查快取
20async def run_pipeline_with_resume(workflow_id: str, query: str):
21    cache = PipelineStateCache(redis_client)
22
23    # Step 1:查詢改寫(有快取則跳過)
24    rewritten = cache.get_step_result(workflow_id, "rewrite")
25    if not rewritten:
26        rewritten = await rewrite_query(query)
27        cache.set_step_result(workflow_id, "rewrite", rewritten)
28
29    # Step 2:向量搜尋
30    results = cache.get_step_result(workflow_id, "search")
31    if not results:
32        results = await vector_search(rewritten)
33        cache.set_step_result(workflow_id, "search", results)
34
35    # ... 以此類推

6.3 Temporal:金融級工作流程持久化

當可靠性要求達到 99.9%+ 時,Redis 快取不夠用。Temporal 提供事件溯源(Event Sourcing)級別的持久化:

  • Worker 崩潰後,工作流程從最後一個 checkpoint 自動恢復
  • 支援「等待人工審核」的長暫停(Pause/Resume)
  • 工作流程歷史可回放,便於 debug

適用臨界點:任務平均執行時間 > 30 秒,或需要人工介入步驟。


七、錯誤處理:重試、回退與人工介入設計

7.1 錯誤分類與應對策略

錯誤類型範例策略最大重試
暫時性網路錯誤ConnectionTimeout指數退避重試3 次
Rate Limit429 Too Many Requests退避 + Jitter5 次
LLM 內容過濾ContentFilterError重寫 Prompt 後重試2 次
向量庫不可用PineconeUnavailable切換備用索引1 次
答案品質不足Hallucination detected降低 temperature 重生成2 次
超出 Token 限制ContextLengthExceeded截斷輸入後重試1 次

7.2 指數退避實作

 1import asyncio
 2import random
 3from functools import wraps
 4
 5def async_retry(
 6    max_attempts: int = 3,
 7    base_delay: float = 1.0,
 8    max_delay: float = 60.0,
 9    exceptions: tuple = (Exception,),
10):
11    def decorator(func):
12        @wraps(func)
13        async def wrapper(*args, **kwargs):
14            for attempt in range(max_attempts):
15                try:
16                    return await func(*args, **kwargs)
17                except exceptions as e:
18                    if attempt == max_attempts - 1:
19                        raise
20                    # 指數退避 + Jitter(避免驚群效應)
21                    delay = min(base_delay * (2 ** attempt), max_delay)
22                    jitter = random.uniform(0, delay * 0.1)
23                    await asyncio.sleep(delay + jitter)
24        return wrapper
25    return decorator
26
27@async_retry(max_attempts=3, exceptions=(RateLimitError, TimeoutError))
28async def call_llm(prompt: str) -> str:
29    return await llm.ainvoke(prompt)

7.3 人工介入(Human-in-the-Loop)

某些情境下,自動重試不夠,需要人工決策:

 1from enum import Enum
 2
 3class EscalationLevel(Enum):
 4    AUTO_RETRY = "auto_retry"
 5    HUMAN_REVIEW = "human_review"
 6    IMMEDIATE_ALERT = "immediate_alert"
 7
 8def classify_error(error: Exception, attempt: int) -> EscalationLevel:
 9    # 法律/合規相關的回應需要人工審核
10    if "compliance" in str(error).lower():
11        return EscalationLevel.HUMAN_REVIEW
12
13    # 連續 3 次失敗且是關鍵路徑
14    if attempt >= 3 and is_critical_path():
15        return EscalationLevel.IMMEDIATE_ALERT
16
17    return EscalationLevel.AUTO_RETRY

實際效果:引入分層錯誤處理後,生產環境管線失敗率從 15% 降到 2.3%,P99 延遲從 12s 降到 4.2s。

7.4 Circuit Breaker(熔斷器)

當下游服務持續失敗時,快速失敗而非繼續重試浪費資源:

 1class CircuitBreaker:
 2    def __init__(self, failure_threshold=5, timeout=60):
 3        self.failures = 0
 4        self.threshold = failure_threshold
 5        self.timeout = timeout
 6        self.state = "closed"  # closed / open / half-open
 7        self.last_failure_time = None
 8
 9    async def call(self, func, *args, **kwargs):
10        if self.state == "open":
11            if time.time() - self.last_failure_time > self.timeout:
12                self.state = "half-open"
13            else:
14                raise CircuitOpenError("Circuit breaker is open")
15
16        try:
17            result = await func(*args, **kwargs)
18            self._on_success()
19            return result
20        except Exception as e:
21            self._on_failure()
22            raise

八、為什麼選 X 不選 Y

8.1 LangChain vs LlamaIndex vs 自建

選擇          選 X 的理由                      不選 Y 的理由
─────────────────────────────────────────────────────────────────
LangChain     社群最大(GitHub 90K+ stars)      LlamaIndex:資料連接場景較弱
              LCEL 表達式簡潔,串流原生支援       自建:重複造輪子,缺乏 tracing
              LangSmith 整合,可觀測性一流        Haystack:文件較少,社群較小

LlamaIndex    資料連接器 70+,開箱即用            LangChain:Document Loader 較基礎
              知識圖譜、多模態原生支援             自建:多模態處理複雜度高
              Sub-Question 引擎複雜查詢強          Haystack:知識圖譜無原生支援

自建管線      完全控制,無框架升級風險            LangChain/LlamaIndex:功能重複開發
              無抽象層開銷(延遲 -5–15%)         2 人以下團隊:維護成本過高
              框架 API 不穩定時避免遷移痛苦        無標準化 tracing,可觀測性差

翻轉條件

  • 當 QPS > 5K 且需要極致延遲優化時,考慮自建核心路徑(但保留 LangSmith tracing)
  • 當資料來源 > 10 種異質系統時,LlamaIndex 的 Connector 生態優勢顯著

8.2 Redis 快取 vs 資料庫持久化

選擇       選 X 的理由                       不選 Y 的理由
────────────────────────────────────────────────────────────
Redis      < 1ms 讀寫延遲,原生 TTL 支援      PostgreSQL:連接池開銷,寫入 ~5ms
           Pipeline / Lua 腳本原子操作        SQLite:不支援多 Worker 並發寫入
           Cluster 模式線性擴容               無持久化(RDB/AOF 可選)

PostgreSQL 永久持久化,ACID 保證             Redis:重啟後資料可能遺失
           複雜查詢(工作流程歷史統計)        記憶體限制,大 blob 不適合
           已有 PG 實例時零增加成本           延遲比 Redis 高 5–10×

翻轉條件:中間結果需要永久審計(如金融合規場景)→ 改用 PostgreSQL + pg_partman 按時間分區。


8.3 同步 vs 非同步執行

選擇       選 X 的理由                        不選 Y 的理由
─────────────────────────────────────────────────────────────
同步       程式碼簡單,除錯容易               非同步:asyncio 學習曲線
           步驟間強依賴,無並行空間            無法利用 IO 等待時間
           POC/原型階段首選                   高 QPS 下線程阻塞

非同步     並行 IO:3 個搜尋查詢同時進行       同步:QPS 高時阻塞所有請求
           同等硬體,吞吐量提升 3–5×          錯誤追蹤比同步複雜
           asyncio + uvloop 原生支援          共享狀態需要 Lock

實際測試數字:相同硬體(8 core)下,非同步 RAG 管線 QPS = 450,同步版本 QPS = 95。


8.4 Temporal vs Celery vs Prefect

選擇       選 X 的理由                        不選 Y 的理由
─────────────────────────────────────────────────────────────
Temporal   事件溯源,Worker 崩潰自動恢復       Celery:無原生工作流程狀態持久化
           支援任意長時間暫停(等人工審核)     Prefect:雲端依賴,自建成本高
           強一致性保證,金融/醫療合規適用      學習曲線陡峭(Go 背景優先)

Celery     成熟生態,Redis/RabbitMQ 後端       Temporal:部署複雜,需要額外服務
           Python 原生,Django 整合佳           無 workflow 級持久化
           10 分鐘設定完成,適合快速迭代        Prefect:較 Celery 更重

Prefect    現代化 UI,本地 + 雲端混合           Temporal:可觀測性較弱
           Python 裝飾器風格,學習曲線低        Celery:無結構化 DAG 定義
           Prefect Cloud 託管,零運維           雲端版有費用,自建版功能受限

翻轉條件

  • 任務 < 5 分鐘 + 簡單隊列 → Celery
  • 複雜 DAG + 現代 UI + 小團隊 → Prefect
  • 金融/醫療 + 長任務 + 人工介入 → Temporal

8.5 Streaming vs Batch 管線

選擇       選 X 的理由                        不選 Y 的理由
─────────────────────────────────────────────────────────────
Streaming  用戶感知延遲低(首 token < 500ms)  Batch:無法即時呈現生成進度
(LCEL)    錯誤早期可見,用戶可中斷            記憶體占用:大量並發時 SSE 連接多
           LangChain LCEL 原生支援 .astream()  除錯複雜度比 batch 高

Batch      簡單,結果完整後一次性回傳           Streaming:用戶等待體驗差
           易於快取(完整結果 hash)            長生成(> 5s)用戶流失率高
           測試和比較容易(固定輸出)           無法中途取消節省成本

8.6 向量資料庫選型

選擇          選 X 的理由                      不選 Y 的理由
─────────────────────────────────────────────────────────────
Pinecone      全託管,零運維,P95 < 50ms        Weaviate:自建運維複雜
              Hybrid Search(稀疏+密集)原生    Chroma:不支援生產級規模
              Namespace 多租戶開箱即用           FAISS:需要自建 ANN 服務層

Weaviate      GraphQL 介面,多模態原生          Pinecone:費用高($70+/月起)
              自建可完全控制資料主權             無托管版需要自運維
              BM25 + 向量混合搜尋               社群較 Pinecone 小

Chroma        本地開發零配置,Python 原生        Pinecone:POC 階段殺雞用牛刀
              開源免費                          生產規模(> 1M vectors)效能下降
              LangChain/LlamaIndex 完美整合      無持久化集群模式

九、系統效應:編排框架引入前後

9.1 量化對比

指標無框架(直接呼叫)引入 LangChain LCEL引入完整編排(Phase 3)
管線開發時間2 週3 天1 週(含監控)
P50 延遲2,100ms1,400ms(並行)900ms(快取+並行)
P95 延遲8,500ms3,200ms2,100ms
管線失敗率15.2%4.8%1.9%
LLM 成本/1K 請求$12.50$11.80$8.70(快取命中 30%)
Bug 定位時間(均值)4.2 小時35 分鐘12 分鐘
可測試步驟比例20%80%95%

9.2 開發速度影響

引入 LangChain LCEL 後,新功能迭代速度提升約 2.4×,主要來源:

  1. 步驟可以獨立開發、測試、替換(不需要整條管線跑)
  2. LangSmith 讓 Prompt 調優從「猜測」變成「資料驅動」
  3. 標準化錯誤處理消除了大量重複的 try/except 程式碼

9.3 成本優化路徑

成本優化層級(由低到高複雜度):

Level 1:Semantic Cache(難度:低)
  實作:GPTCache + Redis
  效果:相似查詢命中率 25–40%,節省 $3–5/1K 請求
  注意:快取失效策略不當會導致答案過時

Level 2:模型路由(難度:中)
  實作:簡單查詢 → gpt-4o-mini,複雜查詢 → gpt-4o
  效果:平均每請求成本降低 40–60%
  注意:路由判斷本身需要 LLM 呼叫(約 $0.0002)

Level 3:批次處理(難度:中)
  實作:非即時查詢累積後批次送出
  效果:OpenAI Batch API 成本 -50%
  注意:延遲增加,不適合即時場景

Level 4:蒸餾/微調(難度:高)
  實作:用 GPT-4o 生成訓練資料,微調小模型
  效果:特定任務成本降低 80–95%
  注意:需要 1K+ 標記樣本,品質評估複雜

十、面試答題要點(RKK)

「針對這個 RAG 客服管線,我的設計是:把 5 個步驟建模成 DAG,而不是線性 Chain,這樣查詢改寫的 3 個變體可以並行執行,P50 延遲從 2.1s 降到 1.4s。框架選 LangChain LCEL,因為它的 .with_retry().with_fallbacks() 可以在步驟層級定義錯誤策略,而不是在管線層級做全局 try/catch。對於 15% 的失敗率,我的分析是:大部分來自 Rate Limit 和向量庫偶發超時,用指數退避重試(最多 3 次)可以把失敗率降到 2% 以下;剩下的來自答案品質問題,需要品質過濾步驟輸出低信心答案並走人工審核佇列。中間結果用 Redis 快取(TTL 1 小時),Worker 崩潰時可以從上次 checkpoint 恢復。引入 LangSmith tracing 後,P95 延遲問題的定位時間從 4 小時降到 35 分鐘。」

關鍵得分點

  1. DAG 並行化:說出具體哪些步驟可以並行,量化延遲改善
  2. 步驟級錯誤處理:區分不同錯誤類型的應對策略(重試 vs 降級 vs 人工介入)
  3. 具體數字:失敗率從 15% 降到 2%,延遲從 2.1s 降到 1.4s
  4. 框架選型理由:不是「因為流行」,而是具體的技術優勢(LCEL 表達式、LangSmith)
  5. 狀態持久化意識:Redis checkpoint + TTL 設計

十一、系列導航

Phase 13 Part 1RAG 系統設計:向量搜尋、重排序與上下文壓縮

Phase 14 Part 1AI Agent 設計:工具呼叫、規劃循環與多 Agent 協作


本文為「AI 工程從零開始」系列第 Phase 13 Part 2 篇,聚焦生產級 AI 工作流程編排的完整決策體系。

Yen

Yen

Yen