跳到主要內容

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

其他優點包括

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

我應該使用 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 執行特定任務的指南,請查看相關的操作指南


此頁面是否有所幫助?