LangChain: The Comprehensive LLM Application Framework
LangChain is a framework that simplifies the creation of applications using LLMs. It provides a modular and composable way to build complex LLM workflows by offering various components that can be chained together.
Key Concepts and Components of LangChain:
-
Models:
LLMs: Integrations with various language models (e.g., OpenAI, Hugging Face, Anthropic). These are the core engines that understand and generate human-like text.
Chat Models: Optimized for conversational interactions, often working with a list of messages (e.g., system, human, AI messages).
Embeddings: Converts text into numerical vectors, crucial for tasks like semantic search, retrieval, and similarity comparisons. -
Prompts:
Prompt Templates: Standardized ways to construct prompts for LLMs. They allow you to dynamically insert variables into a predefined structure.
Example:
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate(template="What is a good name for a company that makes {product}?", input_variables=["product"])
print(prompt.format(product="colorful socks"))
# Output: What is a good name for a company that makes colorful socks?
**Output Parsers:** Structure the output from LLMs into a desired format (e.g., JSON, Pydantic objects, lists). This helps make LLM outputs more usable programmatically.
Example (Pydantic Output Parser):
# W.I.P
- Chains:
* Chains are sequences of calls to LLMs or other utilities. They allow you to combine multiple components into a single, cohesive workflow.
**Simple Chains:** A direct call to an LLM with a prompt.
**Sequential Chains:** Execute a series of chains in order, passing the output of one as the input to the next.
**Retrieval Chains:** Combine LLMs with retrieval models to fetch relevant documents and use them to inform the LLM's response (e.g., RAG - Retrieval Augmented Generation).
- Retrieval:
* **Document Loaders:** Load data from various sources (PDFs, websites, databases).
* **Text Splitters:** Break down large documents into smaller, manageable chunks suitable for processing and embedding.
* **Vector Stores:** Databases designed to store and efficiently query embeddings, enabling semantic search. Examples include FAISS, Chroma, Pinecone.
* **Retrievers:** Interface to query a vector store and return relevant documents.
- Agents:
* Agents are a core concept in LangChain. They use an LLM as a "reasoning engine" to decide which **tools** to use and in what order, based on the user's input.
* **Tools:** Functions that an agent can call to interact with the outside world (e.g., search engines, APIs, calculators, databases).
* **Agent Executors:** The runtime that orchestrates the agent's actions, executing tools and feeding the results back to the LLM for further reasoning.
* **Tool Calling:** A modern feature where LLMs can directly output structured calls to tools, often leveraging models fine-tuned for this purpose.
LangGraph: Building Statefule, Multi-Actor LLM Applications with Graphs
LangGraph extends LangChain by allowing you to build stateful, multi-actor applications as a directed acyclic graph (DAG) or even cyclic graphs (for agents with memory and self-correction). It's particularly useful for complex agentic workflows where you need to manage state, define execution paths, and enable features like human-in-the-loop or parallel execution.
Think of it this way: LangChain provides the building blocks; LangGraph provides the blueprint and orchestration engine to connect those blocks in sophisticated ways.
In LangGraph, an application is represented as a graph where:
- Nodes: Represent a step or a component in your application (e.g., an LLM call, a tool invocation, a custom function).
- Edges: Define the transitions between nodes, determining the flow of execution.
- State: A shared object that is passed between nodes, allowing each node to read and update it. This is crucial for maintaining context and memory across multiple steps.
Key Components and Features of LangGraph:
- State and
StateSchema
:
* The **State** is the central concept in LangGraph. It's a mutable object that holds all the relevant information and context for the current execution of the graph. Each node receives the current state, performs its operation, and returns updates to the state.
* `StateSchema`: This is a Pydantic model (or a dictionary) that defines the structure and types of the variables in your graph's state. It ensures type safety and helps manage complex state objects.
- Nodes:
* **Nodes** are the processing units of your graph. They can be any Python callable (function or method).
* Each node takes the current graph state as input and returns a dictionary of updates to that state.
- Edges:
* **Edges** define the flow of control between nodes.
* **Start/End Edges:** Specify where the graph execution begins and ends.
* **Conditional Edges:** Allow for branching logic. Instead of directly specifying the next node, a conditional edge uses a function (a "router" or "decider") that takes the state and returns the name of the next node to execute. This is fundamental for agentic behavior where the LLM decides the next action.
**Fixed Edges:** A direct, unconditional transition from one node to another.
-
HumanInLoop
:
* This feature allows for explicit human intervention at specific points in the graph. You can pause the execution, allow a human to review or modify the state, and then resume. This is crucial for validation, error correction, or supervised learning processes.
* Implemented by designing a node that, when executed, might send a notification to a human and wait for an external signal to update the state or direct the flow. A common pattern is to have a conditional edge check a state variable like `awaiting_human_input`.
-
InMemory
(State Persistence):
* LangGraph's state is mutable and typically lives for the duration of a single `invoke` call. However, for continuous interactions or long-running agents, you often need to persist the state.
* `InMemoryCheckpointSaver`: This is a simple way to store the graph's state in memory between executions. Useful for development and single-session interactions. For production, you'd integrate with databases (e.g., Redis, SQLite).
-
Streaming
:
* LangGraph supports streaming output from LLMs, allowing your application to display tokens as they are generated rather than waiting for the entire response. This improves user experience.
* This is often managed by the underlying LLM integrations (e.g., `model.stream(messages)`) and how nodes are defined to yield intermediate results.
- When invoking the graph, you would iterate over the
stream()
method:for s in graph_executor.stream(input): print(s)
.
-
Breakpoint
:
* Breakpoints allow you to pause the execution of the graph at specific nodes, inspect the current state, and potentially modify it before continuing. This is invaluable for debugging complex graph flows and understanding how the state evolves.
* Enabled during graph compilation with `interrupt_before` or `interrupt_after` parameters.
-
Parallelization
:
* LangGraph can execute multiple nodes concurrently if they don't have dependencies on each other and operate on different parts of the state or perform independent computations. This can significantly speed up complex workflows.
* This is achieved by defining parallel paths in your graph and using appropriate merging strategies for the state. You add multiple conditional routes from a node or define multiple `add_edge` or `add_conditional_edges` that might lead to nodes that run in parallel.
-
Subgraph
:
* You can compose graphs within graphs. A subgraph is essentially a self-contained LangGraph instance that can be treated as a single node within a larger graph. This promotes modularity and reusability, allowing you to build complex systems from smaller, manageable components.
MapReduce
:
* A common pattern in LLM applications, especially for summarization or data processing.
* **Map:** A node processes multiple inputs (e.g., summarizes individual document chunks).
* **Reduce:** Another node combines the outputs from the map phase (e.g., summarizes the individual summaries into a final summary).
* LangGraph facilitates this by allowing you to define a node that iterates over a list in the state and then another node to aggregate the results.
ReAct
(Reasoning and Acting):
* A prominent agentic pattern where an LLM repeatedly performs a cycle of:
* **Reason:** The LLM generates a thought/plan.
* **Act:** The LLM decides which tool to use and its arguments, and the tool is invoked.
* The observation from the tool is then fed back into the LLM for the next reasoning step.
* LangGraph is an ideal framework for implementing ReAct agents due to its ability to model cycles and manage state across turns. A typical ReAct graph would have nodes for LLM reasoning, tool invocation, and conditional edges to loop back to reasoning until a final answer is determined. LangGraph's prebuilt `AgentExecutor` for `tool_calling` agents often uses a ReAct-like pattern under the hood.
Tool Calling
:
* Modern LLMs (like OpenAI's Function Calling or Anthropic's Tool Use) can directly output structured calls to tools in a machine-readable format.
- In LangGraph, a node might receive the LLM's output, parse it to identify tool calls, invoke the specified tools, and then update the state with the tool's results, which can then be fed back to the LLM for further processing. This streamlines agent-tool interactions. LangGraph provides
ToolExecutor
and ToolNode
classes to simplify this.
How LangGraph Connects to LangChain
LangGraph is built on top of LangChain. This means:
- You use LangChain's components (LLMs, chat models, prompt templates, tools, retrievers) within your LangGraph nodes.
- LangGraph provides the orchestration layer, connecting these LangChain components into a structured, stateful, and often cyclical workflow.
This combination allows developers to leverage the extensive toolkit of LangChain while gaining the fine-grained control and state management capabilities of LangGraph for building complex, robust, and interactive LLM applications.
Top comments (0)