LangChain Refresher
Quick refresher on LangChain fundamentals: LLMs, prompts, chains, output parsers, and how they integrate with LangGraph.
LangChain Refresher
LangGraph is built on top of LangChain. Before diving deeper into graphs, let's review the core LangChain components you'll use in every LangGraph application.
LLMs (Language Models)
LangChain provides a unified interface for hundreds of LLMs from OpenAI, Anthropic, Google, Cohere, Hugging Face, and more.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o", temperature=0.7)
response = llm.invoke("What is the capital of France?")
print(response.content) # The capital of France is Paris.Key LLM Parameters
| Parameter | Description | Typical Range |
|---|---|---|
model | Model identifier | "gpt-4o", "claude-3-opus" |
temperature | Randomness of output | 0.0 (deterministic) to 2.0 (creative) |
max_tokens | Maximum output length | 128 to 4096+ |
top_p | Nucleus sampling threshold | 0.0 to 1.0 |
timeout | Request timeout | 10 to 60 seconds |
Chat models use invoke() with messages, not strings. The base LLM class uses strings directly. For LangGraph agents, you'll almost always use ChatOpenAI or similar chat models.
from langchain_core.messages import HumanMessage, SystemMessage
messages = [
SystemMessage("You are a helpful assistant."),
HumanMessage("What is LangGraph?")
]
response = llm.invoke(messages)Prompts
Prompts are templates that structure the input to an LLM. LangChain's ChatPromptTemplate is the standard approach.
from langchain.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "You are an expert in {topic}."),
("human", "Answer this question: {question}")
])
formatted = prompt.format(topic="Python", question="What is a decorator?")Prompt with Few-Shot Examples
examples = [
("human", "What is 2+2?"),
("assistant", "4"),
("human", "What is 5+3?"),
("assistant", "8"),
]
prompt = ChatPromptTemplate.from_messages([
("system", "You are a math tutor. Answer concisely."),
*examples,
("human", "{question}")
])In LangGraph, you typically put prompt construction inside a node function rather than chaining it externally. This keeps the prompt logic close to where it's used.
Chains
Chains connect components together. The modern approach uses the pipe operator (|):
from langchain_core.output_parsers import StrOutputParser
# Chain: prompt → LLM → string output
chain = prompt | llm | StrOutputParser()
result = chain.invoke({
"topic": "AI",
"question": "What is an agent?"
})RunnablePassthrough for Intermediate Values
from langchain_core.runnables import RunnablePassthrough
chain = {
"response": prompt | llm | StrOutputParser(),
"original_question": RunnablePassthrough()
} | RunnablePassthrough()
result = chain.invoke({"topic": "AI", "question": "What is RAG?"})
print(result["response"])
print(result["original_question"])In LangGraph, you should not use the pipe operator to build large chains. Instead, put chain logic inside node functions. This gives you better control over state updates and error handling.
Output Parsers
Output parsers transform LLM text output into structured formats.
StrOutputParser
The simplest parser — converts LLM output to a plain string:
from langchain_core.output_parsers import StrOutputParser
parser = StrOutputParser()
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "AI", "question": "Hi"})
# result is a plain stringPydanticOutputParser
Parses JSON output into a Pydantic model:
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
class Recipe(BaseModel):
name: str = Field(description="Recipe name")
ingredients: list[str] = Field(description="List of ingredients")
steps: list[str] = Field(description="Cooking steps")
cook_time_minutes: int = Field(description="Total cooking time")
parser = PydanticOutputParser(pydantic_object=Recipe)
prompt = ChatPromptTemplate.from_messages([
("system", "Extract recipe info. {format_instructions}"),
("human", "{input_text}")
]).partial(format_instructions=parser.get_format_instructions())
chain = prompt | llm | parser
recipe = chain.invoke({"input_text": "To make pasta, boil water..."})
print(recipe.name, recipe.cook_time_minutes)JsonOutputParser
For simpler cases where you don't need full Pydantic validation:
from langchain_core.output_parsers import JsonOutputParser
chain = prompt | llm | JsonOutputParser()
result = chain.invoke({"input_text": "Extract name and age from: John is 30"})
# result is a dict: {"name": "John", "age": 30}Output parsers are essential in LangGraph for converting LLM responses into structured state updates that downstream nodes can process reliably.
How LangChain Components Fit into LangGraph
In LangGraph, LangChain components become building blocks inside nodes:
from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict, List
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.messages import HumanMessage, AIMessage
llm = ChatOpenAI(model="gpt-4o")
class AgentState(TypedDict):
messages: List[dict]
response: str
def generate_response(state: AgentState) -> dict:
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
("human", "{input}")
])
chain = prompt | llm | StrOutputParser()
response = chain.invoke({"input": state["messages"][-1]["content"]})
return {"response": response}
# Graph construction
builder = StateGraph(AgentState)
builder.add_node("generate", generate_response)
builder.add_edge(START, "generate")
builder.add_edge("generate", END)
app = builder.compile()LangChain components work inside LangGraph nodes, not as replacements for nodes. Each node is a function that uses LangChain tools internally to process state and return updates.
Key Differences When Using LangChain in LangGraph
| Aspect | Pure LangChain | LangGraph with LangChain |
|---|---|---|
| Flow control | Pipe operators (|) | Graph edges and conditions |
| State management | Passed through chain | Shared State object |
| Looping | Not possible | Add edge back to earlier node |
| Tool use | Via ToolChain | Inside node functions |
| Error handling | Chain breaks on error | Per-node try/except |
RunnableConfig in LangGraph
You can pass configuration through LangChain's RunnableConfig when invoking nodes:
from langchain_core.runnables import RunnableConfig
def configurable_node(state: AgentState, config: RunnableConfig) -> dict:
# Access configurable parameters
model_name = config.get("configurable", {}).get("model", "gpt-4o")
temperature = config.get("configurable", {}).get("temperature", 0.7)
llm = ChatOpenAI(model=model_name, temperature=temperature)
response = llm.invoke(state["messages"])
return {"response": response.content}
# Pass config during invocation
app.invoke(
{"messages": [HumanMessage("Hello")]},
config={"configurable": {"model": "gpt-3.5-turbo", "temperature": 0.0}}
)The config parameter in node functions is optional. Only add it when you need runtime configuration like model selection or user-specific settings.
Common Patterns for LangGraph Nodes
Direct LLM Call
def node(state: State) -> dict:
response = llm.invoke(state["input"])
return {"output": response.content}Prompt + LLM + Parser
def node(state: State) -> dict:
chain = prompt | llm | parser
result = chain.invoke({"input": state["input"]})
return {"structured_output": result}Tool-Enabled LLM
def node(state: State) -> dict:
llm_with_tools = llm.bind_tools([search_tool, calculator_tool])
response = llm_with_tools.invoke(state["messages"])
return {"messages": state["messages"] + [response]}Practice Questions
Which LangChain component is used to convert LLM text output into a Pydantic model?
How do LangChain components integrate with LangGraph?
What does the pipe operator (|) do in LangChain?
What is the purpose of the SystemMessage in LangChain?
Which parameter controls the randomness of LLM output?
How do you pass runtime configuration like model selection to a LangGraph node?
What is the output type of ChatOpenAI.invoke()?
What does StrOutputParser do?
Which of the following is NOT a LangChain component commonly used inside LangGraph nodes?
How should you build prompt chains in LangGraph?
Key Takeaways
- LangChain provides LLMs, prompts, chains, and parsers used inside LangGraph nodes
- ChatOpenAI is the standard LLM class; use .invoke() with message lists
- Output parsers (StrOutputParser, PydanticOutputParser) convert LLM text to structured data
- In LangGraph, LangChain components go inside node functions, not outside the graph
- The config parameter allows runtime configuration of LLM parameters
- Avoid the pipe operator for large chains inside LangGraph — prefer explicit function calls