本文 AI 產出,尚未審核

LangChain 教學:Callbacks 與 Log – Tracing 與觀測鏈路

簡介

在 LLM(大型語言模型)應用日益普及的今天,可觀測性 成為開發者必備的能力。當一段對話、搜尋或資料處理流程在 LangChain 中被串成多個 Chain、Agent、Tool 時,若沒有適當的追蹤與記錄,除錯、效能優化、以及合規審計都會變得相當困難。

LangChain 內建的 Callbacks 機制讓我們能在每個節點(如 LLM 呼叫、Prompt 製作、Tool 執行)前後插入自訂程式碼,配合 LogTracing 功能即可完整繪製執行鏈路。本文將從概念說明、實作範例、常見陷阱與最佳實踐,帶領初學者到中級開發者快速上手,並展示在真實專案中的應用方式。


核心概念

1. Callback 基礎

LangChain 的 CallbackManager 是一個事件分發中心,支援以下常見事件:

事件名稱 觸發時機 常見用途
on_chain_start Chain 開始執行前 記錄輸入、開始時間
on_chain_end Chain 執行完畢後 計算耗時、記錄輸出
on_llm_start LLM 呼叫前 捕捉 Prompt、Token 數
on_llm_end LLM 回傳後 取得回覆、統計成本
on_tool_start / on_tool_end Tool 執行前後 觀測外部 API 呼叫

重點:所有 Callback 皆接受 **kwargs,可自行擴充自訂資訊。

2. Tracing 與 Log 的差異

  • Log:單向記錄,通常寫入檔案或 console,僅供事後檢視。
  • Tracing:結合時間序列與層級關係,形成「樹狀」或「流程圖」視覺化,常與外部平台(如 LangSmith、ELK)整合,支援即時查詢與分析。

LangChain 內建的 ConsoleCallbackHandler 只負責 Log;若需要完整 Tracing,則可使用 LangChainTracer 或自行實作 BaseCallbackHandler

3. 建立自訂 Callback

自訂 Callback 只要繼承 BaseCallbackHandler,實作想要的事件方法即可。以下範例示範將每次 LLM 呼叫寫入 MongoDB,以便日後分析。

# custom_callback.py
from langchain.callbacks.base import BaseCallbackHandler
from datetime import datetime
import pymongo

class MongoTracer(BaseCallbackHandler):
    def __init__(self, uri: str, db_name: str = "langchain_traces"):
        client = pymongo.MongoClient(uri)
        self.collection = client[db_name]["llm_calls"]

    def on_llm_start(self, serialized, prompts, **kwargs):
        self._current = {
            "timestamp": datetime.utcnow(),
            "prompts": prompts,
            "metadata": serialized,
        }

    def on_llm_end(self, response, **kwargs):
        self._current["response"] = response
        self.collection.insert_one(self._current)

4. 使用內建 Tracer(LangSmith)

LangSmith 是 LangChain 官方提供的雲端 Tracing 平台,只要把 LangChainTracer 加入 CallbackManager,即可自動捕捉所有事件。

from langchain.callbacks.tracers.langchain import LangChainTracer
from langchain import LLMChain, PromptTemplate, OpenAI

tracer = LangChainTracer(project_name="MyChatbot")
callback_mgr = CallbackManager([tracer])

prompt = PromptTemplate.from_template("請把以下文字翻成繁體中文:\n{input}")
chain = LLMChain(
    llm=OpenAI(),
    prompt=prompt,
    callback_manager=callback_mgr,
)

result = chain.run({"input": "Hello, world!"})
print(result)  # 觀測結果已於 LangSmith 介面呈現

5. 結合多層級 Chain 的觀測

在實務中,常會把多個 Chain 組成一個大流程(如 RetrievalQA → Summarizer → Formatter)。只要在最外層傳入同一個 CallbackManager,所有子 Chain 會自動共享同一條追蹤線索,形成 層級關係,便於在 UI 上展開/摺疊。

from langchain.chains import RetrievalQA, SummarizationChain
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings

# 建立向量資料庫
vectorstore = FAISS.from_texts(
    ["文件1內容", "文件2內容"], embedding=OpenAIEmbeddings()
)

# 子 Chain
qa_chain = RetrievalQA.from_chain_type(
    llm=OpenAI(),
    retriever=vectorstore.as_retriever(),
    callback_manager=callback_mgr,
)

summarizer = SummarizationChain(
    llm=OpenAI(),
    callback_manager=callback_mgr,
)

# 主流程
def answer_question(query: str):
    answer = qa_chain.run(query)
    summary = summarizer.run(answer)
    return summary

print(answer_question("什麼是 LangChain?"))

在上述程式碼中,qa_chainsummarizer 的每一次 LLM 呼叫、向量檢索都會被同一個 Tracer 捕捉,最終在 LangSmith 中呈現為一條完整的 執行樹


常見陷阱與最佳實踐

陷阱 說明 解法/最佳實踐
忘記傳遞 callback_manager 若只在最外層設定,內部子 Chain 仍會使用預設的 ConsoleCallbackHandler,導致資料斷層。 在每個自訂 Chain、Agent、Tool 建構時都顯式傳入同一個 CallbackManager
大量 Log 造成效能瓶頸 寫入磁碟或遠端 DB 時若同步執行,會拖慢整體回應時間。 使用非同步寫入(asyncio)或批次寫入;在開發環境可只開啟 ConsoleCallbackHandler,正式環境再切換至 Tracer。
敏感資訊外洩 Prompt、回覆可能包含個人資料或商業機密,直接寫入外部服務會有風險。 on_llm_start / on_llm_end 中過濾或加密關鍵欄位;或只在測試環境啟用完整 Tracing。
錯誤未被捕捉 Callback 本身拋出例外會中斷主流程。 在自訂 Callback 中使用 try/except 包住所有程式碼,並在 on_error 事件中記錄。
過度追蹤導致噪聲 記錄每個 token 的細節會產生大量資料,難以分析。 只在需要的層級(如 Chain、Tool)啟用細粒度 Tracing,對 LLM 呼叫僅保留 Prompt/Response。

最佳實踐小結

  1. 統一管理:建立單例 CallbackManager,在整個應用程式的入口處初始化。
  2. 分層紀錄:根據環境(dev / staging / prod)切換不同的 Handler(Console / File / LangSmith)。
  3. 安全第一:在寫入前先過濾或脫敏,尤其是涉及 PII(個人可識別資訊)時。
  4. 效能優化:使用非同步或批次寫入,避免同步 I/O 成為瓶頸。
  5. 可視化:盡量利用 LangSmith 或自建 Grafana Dashboard,讓非技術夥伴也能快速了解流程。

實際應用場景

場景 為何需要 Tracing 典型實作方式
客服聊天機器人 需要追蹤用戶問題、模型回覆、以及使用的工具(如資料庫查詢)以做品質分析。 在每個 on_chain_endon_tool_end 中寫入 MongoDB,並利用 Kibana 產生問題熱點圖。
金融報告自動生成 合規要求必須保留所有模型輸入/輸出的完整紀錄,且要能追溯到特定交易。 使用 LangSmith + 自訂 on_llm_end 加密儲存敏感欄位,並將 trace_id 與交易編號關聯。
資料搜尋 + 摘要 向量檢索結果與摘要模型的串接容易產生資訊遺失,需要檢查每一步的輸入輸出。 CallbackManager 包裹 RetrievalQASummarizationChain,在 UI 上展示「檢索 → 摘要」的階段圖。
A/B 測試多模型 同時跑不同 LLM(例如 GPT‑4 與 Claude)比較表現,必須分辨每筆請求屬於哪個模型。 on_llm_start 中加入 metadata={"model": llm_name},並在分析時依此過濾。
長期監控與成本預算 LLM 使用成本與 token 數是關鍵指標,需即時通知超出預算的情況。 on_llm_end 取得 response["usage"]["total_tokens"],累加至 Redis,若超過門檻即觸發 Slack 通知。

總結

TracingLog 是讓 LangChain 應用從 黑箱 變成 可觀測 的關鍵。透過 CallbackManager 我們可以在每個執行節點插入自訂程式碼,無論是簡單的 console log,還是完整的雲端 Tracing(LangSmith)或自建資料庫,都能輕鬆實現。

本文從概念、實作範例、常見陷阱與最佳實踐,最後列出多種真實場景,提供了一條 從入門到上線 的完整路徑。只要在專案初始化時規劃好 Callback 的使用方式,未來不論是除錯、效能優化、合規審計或是業務分析,都能即時取得清晰的執行鏈路圖,讓開發與運維團隊更有信心面對 LLM 驅動的複雜系統。

祝你在 LangChain 的旅程中,觀測每一步,掌握每一次成功! 🚀