跳到主要內容
Open on GitHub

LangChain 運算式語言 (LCEL)

先決條件

LangChain Expression Language (LCEL) 採用宣告式方法,從現有的可執行物件建立新的可執行物件

這表示您描述應該發生什麼,而不是如何發生,讓 LangChain 可以最佳化鏈的執行階段執行。

我們通常將使用 LCEL 建立的 Runnable 稱為「鏈」。請務必記住,「鏈」是 Runnable,並且實作完整的可執行介面

注意
  • LCEL 速查表顯示常見的模式,其中包含可執行介面和 LCEL 運算式。
  • 請參閱下列操作指南清單,其中涵蓋 LCEL 的常見任務。
  • 內建 Runnables 的清單可以在LangChain Core API 參考中找到。當在 LangChain 中使用 LCEL 組成自訂「鏈」時,其中許多可執行物件都很有用。

LCEL 的優點

LangChain 以多種方式最佳化使用 LCEL 建置的鏈的執行階段執行

  • 最佳化平行執行:使用RunnableParallel 平行執行可執行物件,或使用Runnable Batch API 平行執行多個輸入通過給定的鏈。平行執行可以顯著減少延遲,因為可以平行而不是循序完成處理。
  • 保證非同步支援:使用Runnable Async API 可以非同步執行使用 LCEL 建置的任何鏈。當在伺服器環境中執行鏈時,這可能很有用,在伺服器環境中,您想要同時處理大量請求。
  • 簡化串流:可以串流 LCEL 鏈,允許在執行鏈時進行增量輸出。LangChain 可以最佳化輸出的串流,以最大限度地減少首次 Token 時間(從聊天模型llm 輸出第一個區塊所經過的時間)。

其他優點包括

  • 無縫 LangSmith 追蹤 隨著您的鏈變得越來越複雜,了解每個步驟究竟發生什麼變得越來越重要。使用 LCEL,所有步驟都會自動記錄到 LangSmith,以實現最大的可觀察性和可偵錯性。
  • 標準 API:由於所有鏈都是使用可執行介面建置的,因此它們可以像任何其他可執行物件一樣使用。
  • 可使用 LangServe 部署:使用 LCEL 建置的鏈可以使用部署以供生產使用。

我應該使用 LCEL 嗎?

LCEL 是一個協調解決方案——它允許 LangChain 以最佳化的方式處理鏈的執行階段執行。

雖然我們已經看到使用者在生產環境中執行具有數百個步驟的鏈,但我們通常建議將 LCEL 用於更簡單的協調任務。當應用程式需要複雜的狀態管理、分支、循環或多個代理程式時,我們建議使用者利用 LangGraph

在 LangGraph 中,使用者定義指定應用程式流程的圖形。這允許使用者在需要 LCEL 時繼續在個別節點內使用 LCEL,同時輕鬆定義更易讀且可維護的複雜協調邏輯。

以下是一些指南

  • 如果您要進行單次 LLM 呼叫,則不需要 LCEL;而是直接呼叫底層聊天模型
  • 如果您有一個簡單的鏈(例如,提示 + llm + 解析器、簡單的檢索設定等),如果您正在利用 LCEL 的優點,則 LCEL 是合理的選擇。
  • 如果您正在建置複雜的鏈(例如,具有分支、循環、多個代理程式等),請改用 LangGraph。請記住,您始終可以在 LangGraph 中的個別節點內使用 LCEL。

組合基本元件

LCEL 鏈是透過將現有的 Runnables 組合在一起而建置的。兩個主要的組合基本元件是 RunnableSequenceRunnableParallel

許多其他組合基本元件(例如,RunnableAssign)可以視為這兩個基本元件的變體。

注意

您可以在 LangChain Core API 參考中找到所有組合基本元件的清單。

RunnableSequence

RunnableSequence 是一個組合基本元件,可讓您循序「鏈接」多個可執行物件,其中一個可執行物件的輸出作為下一個可執行物件的輸入。

from langchain_core.runnables import RunnableSequence
chain = RunnableSequence([runnable1, runnable2])
API 參考:RunnableSequence

使用某些輸入調用 chain

final_output = chain.invoke(some_input)

對應於以下內容

output1 = runnable1.invoke(some_input)
final_output = runnable2.invoke(output1)
注意

runnable1runnable2 是您想要鏈接在一起的任何 Runnable 的預留位置。

RunnableParallel

RunnableParallel 是一個組合基本元件,可讓您同時執行多個可執行物件,並為每個可執行物件提供相同的輸入。

from langchain_core.runnables import RunnableParallel
chain = RunnableParallel({
"key1": runnable1,
"key2": runnable2,
})
API 參考:RunnableParallel

使用某些輸入調用 chain

final_output = chain.invoke(some_input)

將產生一個 final_output 字典,其索引鍵與輸入字典相同,但值已替換為相應可執行物件的輸出。

{
"key1": runnable1.invoke(some_input),
"key2": runnable2.invoke(some_input),
}

回想一下,可執行物件是平行執行的,因此雖然結果與上面顯示的字典理解相同,但執行時間要快得多。

注意

RunnableParallel 支援同步和非同步執行(所有 Runnables 都是如此)。

  • 對於同步執行,RunnableParallel 使用 ThreadPoolExecutor 同時執行可執行物件。
  • 對於非同步執行,RunnableParallel 使用 asyncio.gather 同時執行可執行物件。

組合語法

RunnableSequenceRunnableParallel 的使用非常普遍,因此我們為使用它們建立了一個簡寫語法。這有助於使程式碼更易讀且更簡潔。

| 運算子

我們多載| 運算子,以從兩個 Runnables 建立 RunnableSequence

chain = runnable1 | runnable2

等效於

chain = RunnableSequence([runnable1, runnable2])

.pipe 方法

如果您對運算子多載有道德上的顧慮,可以使用 .pipe 方法來代替。這與 | 運算子等效。

chain = runnable1.pipe(runnable2)

強制型轉

LCEL 應用自動型別強制型轉,以簡化鏈的組合。

如果您不了解型別強制型轉,您可以隨時直接使用 RunnableSequenceRunnableParallel 類別。

這會使程式碼更冗長,但也會使其更明確。

字典到 RunnableParallel

在 LCEL 運算式中,字典會自動轉換為 RunnableParallel

例如,以下程式碼

mapping = {
"key1": runnable1,
"key2": runnable2,
}

chain = mapping | runnable3

它會自動轉換為以下內容

chain = RunnableSequence([RunnableParallel(mapping), runnable3])
注意

您必須小心,因為 mapping 字典不是 RunnableParallel 物件,它只是一個字典。這表示以下程式碼會引發 AttributeError

mapping.invoke(some_input)

函數到 RunnableLambda

在 LCEL 運算式中,函數會自動轉換為 RunnableLambda

def some_func(x):
return x

chain = some_func | runnable1

它會自動轉換為以下內容

chain = RunnableSequence([RunnableLambda(some_func), runnable1])
注意

您必須小心,因為 lambda 函數不是 RunnableLambda 物件,它只是一個函數。這表示以下程式碼會引發 AttributeError

lambda x: x + 1.invoke(some_input)

舊版鏈

LCEL 旨在圍繞行為和自訂提供與舊版子類別鏈(例如 LLMChainConversationalRetrievalChain)的一致性。許多這些舊版鏈隱藏了重要的詳細資訊,例如提示,並且隨著越來越多可行的模型出現,自訂變得越來越重要。

如果您目前正在使用其中一個舊版鏈,請參閱本指南以取得有關如何遷移的指引

如需有關如何使用 LCEL 執行特定任務的指南,請查看相關的操作指南


此頁面是否對您有幫助?