Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
OurBuilding Ambient Agents with LangGraph course is now available on LangChain Academy!
Open on GitHub

LangChain Expression Language (LCEL)

Prerequisites

TheLangChainExpressionLanguage (LCEL) takes adeclarative approach to building newRunnables from existing Runnables.

This means that you describe whatshould happen, rather thanhow it should happen, allowing LangChain to optimize the run-time execution of the chains.

We often refer to aRunnable created using LCEL as a "chain". It's important to remember that a "chain" isRunnable and it implements the fullRunnable Interface.

note
  • TheLCEL cheatsheet shows common patterns that involve the Runnable interface and LCEL expressions.
  • Please see the following list ofhow-to guides that cover common tasks with LCEL.
  • A list of built-inRunnables can be found in theLangChain Core API Reference. Many of these Runnables are useful when composing custom "chains" in LangChain using LCEL.

Benefits of LCEL

LangChain optimizes the run-time execution of chains built with LCEL in a number of ways:

  • Optimized parallel execution: Run Runnables in parallel usingRunnableParallel or run multiple inputs through a given chain in parallel using theRunnable Batch API. Parallel execution can significantly reduce the latency as processing can be done in parallel instead of sequentially.
  • Guaranteed Async support: Any chain built with LCEL can be run asynchronously using theRunnable Async API. This can be useful when running chains in a server environment where you want to handle large number of requests concurrently.
  • Simplify streaming: LCEL chains can be streamed, allowing for incremental output as the chain is executed. LangChain can optimize the streaming of the output to minimize the time-to-first-token(time elapsed until the first chunk of output from achat model orllm comes out).

Other benefits include:

  • Seamless LangSmith tracingAs your chains get more and more complex, it becomes increasingly important to understand what exactly is happening at every step.With LCEL,all steps are automatically logged toLangSmith for maximum observability and debuggability.
  • Standard API: Because all chains are built using the Runnable interface, they can be used in the same way as any other Runnable.
  • Deployable with LangServe: Chains built with LCEL can be deployed using for production use.

Should I use LCEL?

LCEL is anorchestration solution -- it allows LangChain to handle run-time execution of chains in an optimized way.

While we have seen users run chains with hundreds of steps in production, we generally recommend using LCEL for simpler orchestration tasks. When the application requires complex state management, branching, cycles or multiple agents, we recommend that users take advantage ofLangGraph.

In LangGraph, users define graphs that specify the application's flow. This allows users to keep using LCEL within individual nodes when LCEL is needed, while making it easy to define complex orchestration logic that is more readable and maintainable.

Here are some guidelines:

  • If you are making a single LLM call, you don't need LCEL; instead call the underlyingchat model directly.
  • If you have a simple chain (e.g., prompt + llm + parser, simple retrieval set up etc.), LCEL is a reasonable fit, if you're taking advantage of the LCEL benefits.
  • If you're building a complex chain (e.g., with branching, cycles, multiple agents, etc.) useLangGraph instead. Remember that you can always use LCEL within individual nodes in LangGraph.

Composition Primitives

LCEL chains are built by composing existingRunnables together. The two main composition primitives areRunnableSequence andRunnableParallel.

Many other composition primitives (e.g.,RunnableAssign) can be thought of as variations of these two primitives.

note

You can find a list of all composition primitives in theLangChain Core API Reference.

RunnableSequence

RunnableSequence is a composition primitive that allows you "chain" multiple runnables sequentially, with the output of one runnable serving as the input to the next.

from langchain_core.runnablesimport RunnableSequence
chain= RunnableSequence([runnable1, runnable2])
API Reference:RunnableSequence

Invoking thechain with some input:

final_output= chain.invoke(some_input)

corresponds to the following:

output1= runnable1.invoke(some_input)
final_output= runnable2.invoke(output1)
note

runnable1 andrunnable2 are placeholders for anyRunnable that you want to chain together.

RunnableParallel

RunnableParallel is a composition primitive that allows you to run multiple runnables concurrently, with the same input provided to each.

from langchain_core.runnablesimport RunnableParallel
chain= RunnableParallel({
"key1": runnable1,
"key2": runnable2,
})
API Reference:RunnableParallel

Invoking thechain with some input:

final_output= chain.invoke(some_input)

Will yield afinal_output dictionary with the same keys as the input dictionary, but with the values replaced by the output of the corresponding runnable.

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

Recall, that the runnables are executed in parallel, so while the result is the same asdictionary comprehension shown above, the execution time is much faster.

note

RunnableParallelsupports both synchronous and asynchronous execution (as allRunnables do).

  • For synchronous execution,RunnableParallel uses aThreadPoolExecutor to run the runnables concurrently.
  • For asynchronous execution,RunnableParallel usesasyncio.gather to run the runnables concurrently.

Composition Syntax

The usage ofRunnableSequence andRunnableParallel is so common that we created a shorthand syntax for using them. This helpsto make the code more readable and concise.

The| operator

We haveoverloaded the| operator to create aRunnableSequence from twoRunnables.

chain= runnable1| runnable2

is Equivalent to:

chain= RunnableSequence([runnable1, runnable2])

The.pipe method

If you have moral qualms with operator overloading, you can use the.pipe method instead. This is equivalent to the| operator.

chain= runnable1.pipe(runnable2)

Coercion

LCEL applies automatic type coercion to make it easier to compose chains.

If you do not understand the type coercion, you can always use theRunnableSequence andRunnableParallel classes directly.

This will make the code more verbose, but it will also make it more explicit.

Dictionary to RunnableParallel

Inside an LCEL expression, a dictionary is automatically converted to aRunnableParallel.

For example, the following code:

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

chain= mapping| runnable3

It gets automatically converted to the following:

chain= RunnableSequence([RunnableParallel(mapping), runnable3])
caution

You have to be careful because themapping dictionary is not aRunnableParallel object, it is just a dictionary. This means that the following code will raise anAttributeError:

mapping.invoke(some_input)

Function to RunnableLambda

Inside an LCEL expression, a function is automatically converted to aRunnableLambda.

def some_func(x):
return x

chain = some_func | runnable1

It gets automatically converted to the following:

chain= RunnableSequence([RunnableLambda(some_func), runnable1])
caution

You have to be careful because the lambda function is not aRunnableLambda object, it is just a function. This means that the following code will raise anAttributeError:

lambda x: x+1.invoke(some_input)

Legacy chains

LCEL aims to provide consistency around behavior and customization over legacy subclassed chains such asLLMChain andConversationalRetrievalChain. Many of these legacy chains hide important details like prompts, and as a wider varietyof viable models emerge, customization has become more and more important.

If you are currently using one of these legacy chains, please seethis guide for guidance on how to migrate.

For guides on how to do specific tasks with LCEL, check outthe relevant how-to guides.


[8]ページ先頭

©2009-2025 Movatter.jp