
Langchain Orchestration
- 315 installs
- 61 repo stars
- Updated June 13, 2026
- manutej/luxor-claude-marketplace
Design and implement LangChain chains, retrievers, tool routers, and multi-agent orchestration when building production AI features that need reliable LLM workflow control.
About
Guides Claude Code through LangChain-based orchestration for agents and LLM workflows, covering chain composition, tool integration, retrieval, memory, routing, and operational patterns so AI features are structured, testable, and maintainable in SaaS or API products.
- Multi-step chain design
- Tool and retriever wiring
- Agent coordination patterns
- Memory and state handling
- Production orchestration guardrails
Langchain Orchestration by the numbers
- 315 all-time installs (skills.sh)
- +18 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #2,245 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/manutej/luxor-claude-marketplace --skill langchain-orchestrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 315 |
|---|---|
| repo stars | ★ 61 |
| Last updated | June 13, 2026 |
| Repository | manutej/luxor-claude-marketplace ↗ |
What it does
Design and implement LangChain chains, retrievers, tool routers, and multi-agent orchestration when building production AI features that need reliable LLM workflow control.
Files
LangChain Orchestration Skill
Complete guide for building production-grade LLM applications with LangChain, covering chains, agents, memory, RAG patterns, and advanced orchestration techniques.
Table of Contents
1. Core Concepts 2. Chains 3. Agents 4. Memory Systems 5. RAG Patterns 6. LLM Integrations 7. Callbacks & Monitoring 8. Retrieval Strategies 9. Streaming 10. Error Handling 11. Production Best Practices
Core Concepts
LangChain Expression Language (LCEL)
LCEL is the declarative way to compose chains in LangChain, enabling streaming, async, and parallel execution.
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
# Basic LCEL chain
prompt = ChatPromptTemplate.from_template("Tell me about {topic}")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
output_parser = StrOutputParser()
chain = prompt | llm | output_parser
result = chain.invoke({"topic": "quantum computing"})Runnable Interface
Every component in LangChain implements the Runnable interface with standard methods:
from langchain_core.runnables import RunnablePassthrough
# Key methods: invoke, stream, batch, ainvoke, astream, abatch
chain = prompt | llm | output_parser
# Synchronous invoke
result = chain.invoke({"topic": "AI"})
# Streaming
for chunk in chain.stream({"topic": "AI"}):
print(chunk, end="", flush=True)
# Batch processing
results = chain.batch([{"topic": "AI"}, {"topic": "ML"}])
# Async variants
result = await chain.ainvoke({"topic": "AI"})RunnablePassthrough
Pass inputs directly through or apply transformations:
from langchain_core.runnables import RunnablePassthrough
# Pass through unchanged
chain = RunnablePassthrough() | llm | output_parser
# With transformation
def add_context(x):
return {"text": x["input"], "context": "important"}
chain = RunnablePassthrough.assign(processed=add_context) | llmChains
Sequential Chains
Process data through multiple steps sequentially.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(temperature=0)
# Step 1: Generate ideas
idea_prompt = ChatPromptTemplate.from_template(
"Generate 3 creative ideas for: {topic}"
)
idea_chain = idea_prompt | llm | StrOutputParser()
# Step 2: Evaluate ideas
eval_prompt = ChatPromptTemplate.from_template(
"Evaluate these ideas and pick the best one:\n{ideas}"
)
eval_chain = eval_prompt | llm | StrOutputParser()
# Combine into sequential chain
sequential_chain = (
{"ideas": idea_chain}
| RunnablePassthrough.assign(evaluation=eval_chain)
)
result = sequential_chain.invoke({"topic": "mobile app"})Map-Reduce Chains
Process multiple inputs in parallel and combine results.
from langchain_core.runnables import RunnableParallel
from langchain_core.prompts import ChatPromptTemplate
# Define parallel processing
summary_prompt = ChatPromptTemplate.from_template(
"Summarize this text in one sentence: {text}"
)
keywords_prompt = ChatPromptTemplate.from_template(
"Extract 3 keywords from: {text}"
)
sentiment_prompt = ChatPromptTemplate.from_template(
"Analyze sentiment (positive/negative/neutral): {text}"
)
# Map: Process in parallel
map_chain = RunnableParallel(
summary=summary_prompt | llm | StrOutputParser(),
keywords=keywords_prompt | llm | StrOutputParser(),
sentiment=sentiment_prompt | llm | StrOutputParser()
)
# Reduce: Combine results
reduce_prompt = ChatPromptTemplate.from_template(
"""Combine the analysis:
Summary: {summary}
Keywords: {keywords}
Sentiment: {sentiment}
Provide a comprehensive report:"""
)
map_reduce_chain = map_chain | reduce_prompt | llm | StrOutputParser()
result = map_reduce_chain.invoke({
"text": "LangChain is an amazing framework for building LLM applications."
})Router Chains
Route inputs to different chains based on conditions.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Define specialized chains
technical_prompt = ChatPromptTemplate.from_template(
"Provide a technical explanation of: {query}"
)
simple_prompt = ChatPromptTemplate.from_template(
"Explain in simple terms: {query}"
)
technical_chain = technical_prompt | llm | StrOutputParser()
simple_chain = simple_prompt | llm | StrOutputParser()
# Router function
def route_query(input_dict):
query = input_dict["query"]
complexity = input_dict.get("complexity", "simple")
if complexity == "technical":
return technical_chain
return simple_chain
# Create router chain
from langchain_core.runnables import RunnableLambda
router_chain = RunnableLambda(route_query)
# Use the router
result = router_chain.invoke({
"query": "quantum entanglement",
"complexity": "technical"
})Conditional Chains
Execute chains based on conditions.
from langchain_core.runnables import RunnableBranch
# Define condition-based routing
classification_prompt = ChatPromptTemplate.from_template(
"Classify this as 'question', 'statement', or 'command': {text}"
)
question_handler = ChatPromptTemplate.from_template(
"Answer this question: {text}"
) | llm | StrOutputParser()
statement_handler = ChatPromptTemplate.from_template(
"Acknowledge this statement: {text}"
) | llm | StrOutputParser()
command_handler = ChatPromptTemplate.from_template(
"Execute this command: {text}"
) | llm | StrOutputParser()
# Create conditional branch
branch = RunnableBranch(
(lambda x: "question" in x["type"].lower(), question_handler),
(lambda x: "statement" in x["type"].lower(), statement_handler),
command_handler # default
)
# Full chain with classification
full_chain = (
{"text": RunnablePassthrough(), "type": classification_prompt | llm | StrOutputParser()}
| branch
)LLMChain (Legacy)
Traditional chain format still supported:
from langchain.chains import LLMChain
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate(
input_variables=["product"],
template="What is a good name for a company that makes {product}?"
)
chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(product="eco-friendly water bottles")Stuff Documents Chain
Combine documents into a single context:
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.documents import Document
prompt = ChatPromptTemplate.from_template(
"""Answer based on the following context:
<context>
{context}
</context>
Question: {input}"""
)
document_chain = create_stuff_documents_chain(llm, prompt)
docs = [
Document(page_content="LangChain supports multiple LLM providers."),
Document(page_content="Chains can be composed using LCEL.")
]
result = document_chain.invoke({
"input": "What does LangChain support?",
"context": docs
})Agents
ReAct Agents
Reasoning and Acting agents that use tools iteratively.
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import Tool
from langchain import hub
# Define tools
def search_tool(query: str) -> str:
"""Search for information"""
return f"Search results for: {query}"
def calculator_tool(expression: str) -> str:
"""Calculate mathematical expressions"""
try:
return str(eval(expression))
except:
return "Invalid expression"
tools = [
Tool(
name="Search",
func=search_tool,
description="Useful for searching information"
),
Tool(
name="Calculator",
func=calculator_tool,
description="Useful for math calculations"
)
]
# Create ReAct agent
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=5
)
result = agent_executor.invoke({
"input": "What is 25 * 4, and then search for that number's significance"
})LangGraph ReAct Agent
Modern approach using LangGraph for better control:
from langgraph.prebuilt import create_react_agent
from langchain_core.tools import tool
from langgraph.checkpoint.memory import MemorySaver
@tool
def retrieve(query: str) -> str:
"""Retrieve relevant information from the knowledge base"""
# Your retrieval logic here
return f"Retrieved information for: {query}"
@tool
def analyze(text: str) -> str:
"""Analyze text and provide insights"""
return f"Analysis of: {text}"
# Create agent with memory
memory = MemorySaver()
agent_executor = create_react_agent(
llm,
[retrieve, analyze],
checkpointer=memory
)
# Use with configuration
config = {"configurable": {"thread_id": "abc123"}}
for chunk in agent_executor.stream(
{"messages": [("user", "Find information about LangChain")]},
config=config
):
print(chunk)Conversational ReAct Agent
Agent with built-in conversation memory:
from langchain.agents import create_conversational_retrieval_agent
from langchain_core.tools import Tool
tools = [
Tool(
name="Knowledge Base",
func=lambda q: f"KB result: {q}",
description="Search the knowledge base"
)
]
conversational_agent = create_conversational_retrieval_agent(
llm,
tools,
verbose=True
)
# Maintains conversation context
result1 = conversational_agent.invoke({
"input": "What is LangChain?"
})
result2 = conversational_agent.invoke({
"input": "Tell me more about its features"
})Zero-Shot React Agent
Agent that works without examples:
from langchain.agents import AgentType, initialize_agent, load_tools
# Load pre-built tools
tools = load_tools(["serpapi", "llm-math"], llm=llm)
agent = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=True,
max_iterations=3
)
result = agent.run(
"What is the population of Tokyo and what is that number divided by 2?"
)Structured Chat Agent
Agent that uses structured input/output:
from langchain.agents import create_structured_chat_agent
# Define tools with structured schemas
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(description="The search query")
max_results: int = Field(default=5, description="Maximum results")
@tool(args_schema=SearchInput)
def structured_search(query: str, max_results: int = 5) -> str:
"""Search with structured parameters"""
return f"Found {max_results} results for: {query}"
tools = [structured_search]
prompt = hub.pull("hwchase17/structured-chat-agent")
agent = create_structured_chat_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)Tool Calling Agent
Modern agent using native tool calling:
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers"""
return a * b
@tool
def search_database(query: str, limit: int = 10) -> str:
"""Search the database"""
return f"Found {limit} results for {query}"
# Bind tools to LLM
llm_with_tools = llm.bind_tools([multiply, search_database])
# Create simple tool chain
from operator import itemgetter
tool_chain = llm_with_tools | (lambda x: x.tool_calls[0]["args"]) | multiply
result = tool_chain.invoke("What's four times 23")Memory Systems
ConversationBufferMemory
Store complete conversation history:
from langchain.memory import ConversationBufferMemory
from langchain.chains import LLMChain
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
("placeholder", "{chat_history}"),
("human", "{input}")
])
chain = LLMChain(llm=llm, prompt=prompt, memory=memory)
# Conversation is automatically stored
response1 = chain.run(input="Hi, I'm Alice")
response2 = chain.run(input="What's my name?") # Will remember AliceConversationBufferWindowMemory
Keep only recent K interactions:
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(
k=5, # Keep last 5 interactions
memory_key="chat_history",
return_messages=True
)
chain = LLMChain(llm=llm, prompt=prompt, memory=memory)ConversationSummaryMemory
Summarize conversation history:
from langchain.memory import ConversationSummaryMemory
memory = ConversationSummaryMemory(
llm=llm,
memory_key="chat_history",
return_messages=True
)
chain = LLMChain(llm=llm, prompt=prompt, memory=memory)
# Long conversations are automatically summarized
for i in range(20):
chain.run(input=f"Tell me fact {i} about AI")ConversationSummaryBufferMemory
Hybrid approach: recent messages + summary:
from langchain.memory import ConversationSummaryBufferMemory
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=100, # When to trigger summarization
memory_key="chat_history",
return_messages=True
)Vector Store Memory
Semantic search over conversation history:
from langchain.memory import VectorStoreRetrieverMemory
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_texts([], embeddings)
memory = VectorStoreRetrieverMemory(
retriever=vectorstore.as_retriever(search_kwargs={"k": 5})
)
# Save context
memory.save_context(
{"input": "My favorite color is blue"},
{"output": "That's great!"}
)
# Retrieve relevant context
relevant = memory.load_memory_variables({"input": "What's my favorite color?"})Recall Memories (LangGraph)
Structured memory with save and search:
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_openai import OpenAIEmbeddings
from langchain_core.tools import tool
recall_vector_store = InMemoryVectorStore(OpenAIEmbeddings())
@tool
def save_recall_memory(memory: str) -> str:
"""Save important information to long-term memory"""
recall_vector_store.add_texts([memory])
return f"Saved memory: {memory}"
@tool
def search_recall_memories(query: str) -> str:
"""Search long-term memories"""
docs = recall_vector_store.similarity_search(query, k=3)
return "\n".join([doc.page_content for doc in docs])
# Use with agent
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(
llm,
[save_recall_memory, search_recall_memories]
)Custom Memory with LangGraph State
Define custom state for memory:
from typing import List
from langgraph.graph import MessagesState, StateGraph, START, END
class State(MessagesState):
recall_memories: List[str]
def load_memories(state: State):
"""Load relevant memories before agent processes input"""
messages = state["messages"]
last_message = messages[-1].content if messages else ""
# Search for relevant memories
docs = recall_vector_store.similarity_search(last_message, k=3)
memories = [doc.page_content for doc in docs]
return {"recall_memories": memories}
# Add to graph
builder = StateGraph(State)
builder.add_node(load_memories)
builder.add_edge(START, "load_memories")RAG Patterns
Basic RAG Chain
Fundamental retrieval-augmented generation:
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# Setup vector store
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_texts(
[
"LangChain supports multiple LLM providers including OpenAI, Anthropic, and more.",
"Chains can be composed using LangChain Expression Language (LCEL).",
"Agents can use tools to interact with external systems."
],
embedding=embeddings
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# RAG prompt
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# Build RAG chain
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
result = rag_chain.invoke("What does LangChain support?")RAG with Retrieval Chain
Using built-in retrieval chain constructor:
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
prompt = ChatPromptTemplate.from_template(
"""Answer based on the context:
<context>
{context}
</context>
Question: {input}"""
)
document_chain = create_stuff_documents_chain(llm, prompt)
retrieval_chain = create_retrieval_chain(retriever, document_chain)
response = retrieval_chain.invoke({
"input": "What is LCEL?"
})
# Returns: {"input": "...", "context": [...], "answer": "..."}RAG with Chat History
Conversational RAG with context:
from langchain.chains import create_history_aware_retriever
from langchain_core.prompts import MessagesPlaceholder
contextualize_prompt = ChatPromptTemplate.from_messages([
("system", "Given a chat history and the latest user question, "
"formulate a standalone question which can be understood "
"without the chat history."),
MessagesPlaceholder("chat_history"),
("human", "{input}")
])
history_aware_retriever = create_history_aware_retriever(
llm,
retriever,
contextualize_prompt
)
# Use in RAG chain
qa_chain = create_retrieval_chain(
history_aware_retriever,
document_chain
)
# First question
result1 = qa_chain.invoke({
"input": "What is LangChain?",
"chat_history": []
})
# Follow-up with context
result2 = qa_chain.invoke({
"input": "What are its main features?",
"chat_history": [
("human", "What is LangChain?"),
("ai", result1["answer"])
]
})Multi-Query RAG
Generate multiple search queries for better retrieval:
from langchain.retrievers.multi_query import MultiQueryRetriever
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(),
llm=llm
)
# Automatically generates multiple query variations
rag_chain = (
{"context": multi_query_retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)RAG with Reranking
Improve relevance with reranking:
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import FlashrankRerank
# Setup reranker
compressor = FlashrankRerank()
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=retriever
)
# Use in RAG chain
rag_chain = (
{"context": compression_retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)Parent Document Retrieval
Retrieve larger parent documents for full context:
from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
# Storage for parent documents
store = InMemoryStore()
# Splitters
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000)
parent_retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=store,
child_splitter=child_splitter,
parent_splitter=parent_splitter,
)
# Add documents
parent_retriever.add_documents(documents)Self-Query Retrieval
Natural language to structured queries:
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
metadata_field_info = [
AttributeInfo(
name="source",
description="The document source",
type="string",
),
AttributeInfo(
name="page",
description="The page number",
type="integer",
),
]
document_content_description = "Technical documentation"
self_query_retriever = SelfQueryRetriever.from_llm(
llm,
vectorstore,
document_content_description,
metadata_field_info,
)LLM Integrations
OpenAI Integration
from langchain_openai import ChatOpenAI, OpenAI
# Chat model
chat_model = ChatOpenAI(
model="gpt-4o-mini",
temperature=0.7,
max_tokens=500,
api_key="your-api-key"
)
# Completion model
completion_model = OpenAI(
model="gpt-3.5-turbo-instruct",
temperature=0.9
)Anthropic Claude Integration
from langchain_anthropic import ChatAnthropic
claude = ChatAnthropic(
model="claude-3-5-sonnet-20241022",
temperature=0,
max_tokens=1024,
api_key="your-api-key"
)HuggingFace Integration
from langchain_huggingface import HuggingFaceEndpoint
llm = HuggingFaceEndpoint(
repo_id="meta-llama/Llama-2-7b-chat-hf",
huggingfacehub_api_token="your-token",
task="text-generation",
temperature=0.7
)Google Vertex AI Integration
from langchain_google_vertexai import ChatVertexAI, VertexAI
# Chat model
chat_model = ChatVertexAI(
model_name="chat-bison",
temperature=0
)
# Completion model
completion_model = VertexAI(
model_name="gemini-1.0-pro-002"
)Ollama Local Models
from langchain_community.llms import Ollama
llm = Ollama(
model="llama2",
temperature=0.8
)Binding Tools to LLMs
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers together"""
return a * b
# Bind tools to model
llm_with_tools = llm.bind_tools([multiply])
# Model will return tool calls
response = llm_with_tools.invoke("What is 3 times 4?")
print(response.tool_calls)Callbacks & Monitoring
Standard Callbacks
Track chain execution:
from langchain_core.callbacks import StdOutCallbackHandler
from langchain.callbacks import get_openai_callback
# Standard output callback
callbacks = [StdOutCallbackHandler()]
chain = prompt | llm | StrOutputParser()
result = chain.invoke(
{"topic": "AI"},
config={"callbacks": callbacks}
)
# OpenAI cost tracking
with get_openai_callback() as cb:
result = chain.invoke({"topic": "AI"})
print(f"Total Tokens: {cb.total_tokens}")
print(f"Total Cost: ${cb.total_cost}")Custom Callbacks
Create custom callback handlers:
from langchain_core.callbacks import BaseCallbackHandler
from typing import Any, Dict
class MyCustomCallback(BaseCallbackHandler):
def on_llm_start(self, serialized: Dict[str, Any], prompts: list[str], **kwargs):
print(f"LLM started with prompts: {prompts}")
def on_llm_end(self, response, **kwargs):
print(f"LLM finished with response: {response}")
def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs):
print(f"Chain started with inputs: {inputs}")
def on_chain_end(self, outputs: Dict[str, Any], **kwargs):
print(f"Chain ended with outputs: {outputs}")
def on_tool_start(self, serialized: Dict[str, Any], input_str: str, **kwargs):
print(f"Tool started with input: {input_str}")
def on_tool_end(self, output: str, **kwargs):
print(f"Tool ended with output: {output}")
# Use custom callback
custom_callback = MyCustomCallback()
result = chain.invoke(
{"topic": "AI"},
config={"callbacks": [custom_callback]}
)Argilla Callback
Track and log to Argilla:
from langchain_community.callbacks import ArgillaCallbackHandler
argilla_callback = ArgillaCallbackHandler(
dataset_name="langchain-dataset",
api_url="http://localhost:6900",
api_key="your-api-key"
)
callbacks = [argilla_callback]
agent = initialize_agent(
tools,
llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
callbacks=callbacks
)
agent.run("Who was the first president of the United States?")UpTrain Callback
RAG evaluation and monitoring:
from langchain_community.callbacks import UpTrainCallbackHandler
uptrain_callback = UpTrainCallbackHandler(
key_type="uptrain",
api_key="your-api-key"
)
config = {"callbacks": [uptrain_callback]}
# Automatically evaluates context relevance, factual accuracy, completeness
result = rag_chain.invoke("What is LangChain?", config=config)LangSmith Integration
Production monitoring and debugging:
import os
# Set environment variables
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-key"
os.environ["LANGCHAIN_PROJECT"] = "my-project"
# All chains automatically traced
result = chain.invoke({"topic": "AI"})
# View traces at smith.langchain.comRetrieval Strategies
Vector Store Retrievers
Basic similarity search:
from langchain_community.vectorstores import FAISS, Chroma, Pinecone
# FAISS
faiss_retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 5}
)
# Maximum Marginal Relevance (MMR)
mmr_retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"k": 5, "fetch_k": 20, "lambda_mult": 0.5}
)
# Similarity with threshold
threshold_retriever = vectorstore.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={"score_threshold": 0.8, "k": 5}
)Ensemble Retriever
Combine multiple retrievers:
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
# BM25 for keyword search
bm25_retriever = BM25Retriever.from_texts(texts)
bm25_retriever.k = 5
# Combine with vector search
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever],
weights=[0.5, 0.5]
)
docs = ensemble_retriever.get_relevant_documents("LangChain features")Time-Weighted Retriever
Prioritize recent documents:
from langchain.retrievers import TimeWeightedVectorStoreRetriever
retriever = TimeWeightedVectorStoreRetriever(
vectorstore=vectorstore,
decay_rate=0.01, # Decay factor for older docs
k=5
)Multi-Vector Retriever
Multiple vectors per document:
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.storage import InMemoryByteStore
store = InMemoryByteStore()
retriever = MultiVectorRetriever(
vectorstore=vectorstore,
byte_store=store,
id_key="doc_id"
)
# Add documents with multiple representations
retriever.add_documents(documents)Streaming
Stream Chain Output
Stream tokens as they're generated:
from langchain_core.output_parsers import StrOutputParser
chain = prompt | llm | StrOutputParser()
# Stream method
for chunk in chain.stream({"topic": "AI"}):
print(chunk, end="", flush=True)Stream with Callbacks
Handle streaming events:
from langchain_core.callbacks import StreamingStdOutCallbackHandler
streaming_llm = ChatOpenAI(
streaming=True,
callbacks=[StreamingStdOutCallbackHandler()]
)
chain = prompt | streaming_llm | StrOutputParser()
result = chain.invoke({"topic": "AI"}) # Streams to stdoutAsync Streaming
Stream asynchronously:
async def stream_async():
async for chunk in chain.astream({"topic": "AI"}):
print(chunk, end="", flush=True)
# Run async
import asyncio
asyncio.run(stream_async())Stream Agent Responses
Stream agent execution:
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(llm, tools)
for chunk in agent.stream(
{"messages": [("user", "Search for LangChain information")]},
stream_mode="values"
):
chunk["messages"][-1].pretty_print()Streaming RAG
Stream RAG responses:
retrieval_chain = (
{
"context": retriever.with_config(run_name="Docs"),
"question": RunnablePassthrough(),
}
| prompt
| llm
| StrOutputParser()
)
# Stream the response
for chunk in retrieval_chain.stream("What is LangChain?"):
print(chunk, end="", flush=True)Error Handling
Retry Logic
Automatic retries on failure:
from langchain_core.runnables import RunnableRetry
# Add retry to chain
chain_with_retry = (prompt | llm | StrOutputParser()).with_retry(
stop_after_attempt=3,
wait_exponential_jitter=True
)
result = chain_with_retry.invoke({"topic": "AI"})Fallback Chains
Use fallback on errors:
from langchain_core.runnables import RunnableWithFallbacks
primary_llm = ChatOpenAI(model="gpt-4")
fallback_llm = ChatOpenAI(model="gpt-3.5-turbo")
chain_with_fallback = (prompt | primary_llm).with_fallbacks(
[prompt | fallback_llm]
)
result = chain_with_fallback.invoke({"topic": "AI"})Try-Except Patterns
Manual error handling:
from langchain_core.exceptions import OutputParserException
try:
result = chain.invoke({"topic": "AI"})
except OutputParserException as e:
print(f"Parsing failed: {e}")
result = chain.invoke({"topic": "AI"}) # Retry
except Exception as e:
print(f"Chain execution failed: {e}")
result = NoneTimeout Handling
Set execution timeouts:
from langchain_core.runnables import RunnableConfig
config = RunnableConfig(timeout=10.0) # 10 seconds
try:
result = chain.invoke({"topic": "AI"}, config=config)
except TimeoutError:
print("Chain execution timed out")Validation
Validate inputs and outputs:
from pydantic import BaseModel, Field, validator
class QueryInput(BaseModel):
topic: str = Field(..., min_length=1, max_length=100)
@validator("topic")
def topic_must_be_valid(cls, v):
if not v.strip():
raise ValueError("Topic cannot be empty")
return v.strip()
# Use with chain
def validate_and_invoke(topic: str):
try:
validated = QueryInput(topic=topic)
return chain.invoke({"topic": validated.topic})
except ValueError as e:
return f"Validation error: {e}"Production Best Practices
Environment Configuration
Manage secrets securely:
import os
from dotenv import load_dotenv
load_dotenv()
# Use environment variables
llm = ChatOpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
model=os.getenv("MODEL_NAME", "gpt-4o-mini")
)
# Vector store configuration
VECTOR_STORE_TYPE = os.getenv("VECTOR_STORE", "faiss")
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "text-embedding-3-small")Caching
Cache LLM responses:
from langchain.cache import InMemoryCache, SQLiteCache
from langchain.globals import set_llm_cache
# In-memory cache
set_llm_cache(InMemoryCache())
# Persistent cache
set_llm_cache(SQLiteCache(database_path=".langchain.db"))
# Responses are cached automatically
result1 = llm.invoke("What is AI?") # Calls API
result2 = llm.invoke("What is AI?") # Uses cacheRate Limiting
Control API usage:
from langchain_core.rate_limiters import InMemoryRateLimiter
rate_limiter = InMemoryRateLimiter(
requests_per_second=1,
check_every_n_seconds=0.1,
max_bucket_size=10
)
llm = ChatOpenAI(rate_limiter=rate_limiter)Batch Processing
Process multiple inputs efficiently:
# Batch invoke
inputs = [{"topic": f"Topic {i}"} for i in range(10)]
results = chain.batch(inputs, config={"max_concurrency": 5})
# Async batch
async def batch_process():
results = await chain.abatch(inputs)
return resultsMonitoring and Logging
Production monitoring:
import logging
from langchain_core.callbacks import BaseCallbackHandler
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ProductionCallback(BaseCallbackHandler):
def on_chain_start(self, serialized, inputs, **kwargs):
logger.info(f"Chain started: {serialized.get('name', 'unknown')}")
def on_chain_end(self, outputs, **kwargs):
logger.info(f"Chain completed successfully")
def on_chain_error(self, error, **kwargs):
logger.error(f"Chain error: {error}")
# Use in production
production_callback = ProductionCallback()
config = {"callbacks": [production_callback]}Testing Chains
Unit test your chains:
import pytest
from langchain_core.messages import HumanMessage, AIMessage
def test_basic_chain():
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "testing"})
assert isinstance(result, str)
assert len(result) > 0
def test_rag_chain():
result = rag_chain.invoke("What is LangChain?")
assert "LangChain" in result
assert len(result) > 50
@pytest.mark.asyncio
async def test_async_chain():
result = await chain.ainvoke({"topic": "async"})
assert isinstance(result, str)Performance Optimization
Optimize chain execution:
# Use appropriate chunk sizes for text splitting
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
length_function=len
)
# Limit retrieval results
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# Use smaller, faster models where appropriate
fast_llm = ChatOpenAI(model="gpt-4o-mini")
# Enable streaming for better UX
streaming_chain = prompt | fast_llm.with_streaming() | StrOutputParser()Documentation
Document your chains:
from langchain_core.runnables import RunnableConfig
class DocumentedChain:
"""
Production RAG chain for technical documentation.
Features:
- Multi-query retrieval for better coverage
- Reranking for improved relevance
- Streaming support
- Error handling with fallbacks
Usage:
chain = DocumentedChain()
result = chain.invoke("Your question here")
"""
def __init__(self):
self.llm = ChatOpenAI(model="gpt-4o-mini")
self.retriever = self._setup_retriever()
self.chain = self._build_chain()
def _setup_retriever(self):
# Setup logic
pass
def _build_chain(self):
# Chain construction
pass
def invoke(self, query: str, config: RunnableConfig = None):
"""Execute the chain with error handling"""
try:
return self.chain.invoke(query, config=config)
except Exception as e:
logger.error(f"Chain execution failed: {e}")
raise---
Summary
This skill covers comprehensive LangChain orchestration patterns:
- Chains: Sequential, map-reduce, router, conditional chains
- Agents: ReAct, conversational, zero-shot, structured agents
- Memory: Buffer, window, summary, vector store memory
- RAG: Basic, multi-query, reranking, parent document retrieval
- LLM Integration: OpenAI, Anthropic, HuggingFace, Vertex AI, Ollama
- Callbacks: Standard, custom, Argilla, UpTrain, LangSmith
- Retrieval: Vector store, ensemble, time-weighted, multi-vector
- Streaming: Chain, agent, async streaming
- Error Handling: Retry, fallback, timeout, validation
- Production: Configuration, caching, rate limiting, monitoring, testing
For more examples and patterns, see EXAMPLES.md.
LangChain Orchestration Examples
Production-ready examples covering chains, agents, memory, RAG patterns, and advanced orchestration.
Table of Contents
1. Chain Examples 2. Agent Examples 3. Memory Examples 4. RAG Examples 5. Advanced Patterns
Chain Examples
1. Sequential Analysis Chain
Use Case: Multi-step content analysis pipeline
Description: Process text through sequential steps: summarization, keyword extraction, and sentiment analysis.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# Step 1: Summarize
summarize_prompt = ChatPromptTemplate.from_template(
"Summarize this text in 2-3 sentences:\n\n{text}"
)
summarize_chain = summarize_prompt | llm | StrOutputParser()
# Step 2: Extract keywords
keywords_prompt = ChatPromptTemplate.from_template(
"Extract 5 key topics from this summary:\n\n{summary}"
)
keywords_chain = keywords_prompt | llm | StrOutputParser()
# Step 3: Analyze sentiment
sentiment_prompt = ChatPromptTemplate.from_template(
"Analyze the sentiment (positive/negative/neutral) and explain:\n\n{summary}"
)
sentiment_chain = sentiment_prompt | llm | StrOutputParser()
# Combine into sequential chain
sequential_chain = (
{"summary": {"text": RunnablePassthrough()} | summarize_chain}
| RunnablePassthrough.assign(
keywords=lambda x: keywords_chain.invoke({"summary": x["summary"]}),
sentiment=lambda x: sentiment_chain.invoke({"summary": x["summary"]})
)
)
# Execute
text = """
LangChain is a powerful framework for building LLM applications.
It provides comprehensive tools for chains, agents, and memory systems.
The community is active and the documentation is excellent.
"""
result = sequential_chain.invoke(text)
print(f"Summary: {result['summary']}\n")
print(f"Keywords: {result['keywords']}\n")
print(f"Sentiment: {result['sentiment']}")Explanation: This chain demonstrates sequential processing where each step depends on the previous one. The first step summarizes the input, then parallel steps extract keywords and analyze sentiment from that summary.
---
2. Map-Reduce Document Processing
Use Case: Analyze multiple documents in parallel and combine results
Description: Process multiple documents simultaneously and aggregate findings.
from langchain_core.runnables import RunnableParallel
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(temperature=0)
# Map phase: Process each document
doc_analysis_prompt = ChatPromptTemplate.from_template(
"""Analyze this document and extract:
1. Main topic
2. Key points (3 max)
3. Conclusion
Document: {document}
Provide a structured analysis:"""
)
analysis_chain = doc_analysis_prompt | llm | StrOutputParser()
# Reduce phase: Combine all analyses
combine_prompt = ChatPromptTemplate.from_template(
"""Combine these document analyses into a comprehensive report:
{analyses}
Provide:
1. Overall themes
2. Common patterns
3. Unique insights
4. Final recommendations
"""
)
combine_chain = combine_prompt | llm | StrOutputParser()
# Full map-reduce implementation
def map_reduce_documents(documents):
# Map: Analyze each document in parallel
map_chains = {
f"doc_{i}": (lambda doc: {"document": doc}) | analysis_chain
for i in range(len(documents))
}
parallel_map = RunnableParallel(**map_chains)
# Execute map phase
analyses = parallel_map.invoke({
f"doc_{i}": doc for i, doc in enumerate(documents)
})
# Reduce: Combine results
combined_analyses = "\n\n---\n\n".join(analyses.values())
final_report = combine_chain.invoke({"analyses": combined_analyses})
return final_report
# Example usage
documents = [
"LangChain provides tools for building LLM applications...",
"Vector databases enable semantic search capabilities...",
"RAG patterns combine retrieval with generation..."
]
report = map_reduce_documents(documents)
print(report)Explanation: Map-reduce pattern processes multiple inputs in parallel (map phase) then combines results (reduce phase). This is efficient for analyzing multiple documents or data sources simultaneously.
---
3. Dynamic Router Chain
Use Case: Route queries to specialized handlers
Description: Classify input and route to appropriate processing chain.
from langchain_core.runnables import RunnableBranch, RunnableLambda
# Define specialized chains
technical_prompt = ChatPromptTemplate.from_template(
"""Provide a detailed technical explanation with code examples:
Topic: {query}
Include:
- Technical details
- Code examples
- Best practices
"""
)
beginner_prompt = ChatPromptTemplate.from_template(
"""Explain in simple, beginner-friendly terms:
Topic: {query}
Use:
- Simple language
- Analogies
- Step-by-step breakdown
"""
)
business_prompt = ChatPromptTemplate.from_template(
"""Provide a business-focused explanation:
Topic: {query}
Focus on:
- Business value
- ROI considerations
- Use cases
"""
)
technical_chain = technical_prompt | llm | StrOutputParser()
beginner_chain = beginner_prompt | llm | StrOutputParser()
business_chain = business_prompt | llm | StrOutputParser()
# Classifier chain
classifier_prompt = ChatPromptTemplate.from_template(
"""Classify this query as 'technical', 'beginner', or 'business':
Query: {query}
Respond with only one word: technical, beginner, or business"""
)
classifier = classifier_prompt | llm | StrOutputParser()
# Router implementation
def route_query(input_dict):
query = input_dict["query"]
classification = classifier.invoke({"query": query}).strip().lower()
print(f"Routing to: {classification}")
if "technical" in classification:
return technical_chain.invoke({"query": query})
elif "beginner" in classification:
return beginner_chain.invoke({"query": query})
else:
return business_chain.invoke({"query": query})
router_chain = RunnableLambda(route_query)
# Test different query types
queries = [
"Explain async/await in Python with implementation details",
"What is machine learning?",
"How can AI improve our company's efficiency?"
]
for query in queries:
print(f"\nQuery: {query}")
result = router_chain.invoke({"query": query})
print(f"Response: {result[:200]}...")Explanation: Router chains dynamically select the appropriate processing path based on input classification. This enables specialized handling for different types of queries.
---
4. Conditional Branching Chain
Use Case: Execute different logic based on conditions
Description: Branch execution based on input characteristics.
from langchain_core.runnables import RunnableBranch
# Define handlers for different input types
def handle_question(input_dict):
prompt = ChatPromptTemplate.from_template(
"Provide a comprehensive answer to: {text}"
)
chain = prompt | llm | StrOutputParser()
return chain.invoke(input_dict)
def handle_statement(input_dict):
prompt = ChatPromptTemplate.from_template(
"Acknowledge and expand on this statement: {text}"
)
chain = prompt | llm | StrOutputParser()
return chain.invoke(input_dict)
def handle_command(input_dict):
prompt = ChatPromptTemplate.from_template(
"Explain how to execute this command: {text}"
)
chain = prompt | llm | StrOutputParser()
return chain.invoke(input_dict)
# Classifier
def classify_input(text):
if "?" in text:
return "question"
elif any(word in text.lower() for word in ["create", "build", "make", "generate"]):
return "command"
return "statement"
# Create conditional branch
branch = RunnableBranch(
(lambda x: classify_input(x["text"]) == "question", RunnableLambda(handle_question)),
(lambda x: classify_input(x["text"]) == "command", RunnableLambda(handle_command)),
RunnableLambda(handle_statement) # default
)
# Test inputs
inputs = [
{"text": "What is the capital of France?"},
{"text": "Create a Python function for sorting"},
{"text": "LangChain is an amazing framework"}
]
for inp in inputs:
print(f"\nInput: {inp['text']}")
result = branch.invoke(inp)
print(f"Result: {result[:150]}...")Explanation: Conditional branching allows different processing paths based on input characteristics. This is useful for handling various input types with specialized logic.
---
Agent Examples
5. ReAct Agent with Custom Tools
Use Case: Research assistant with search and calculation tools
Description: Agent that reasons about tool usage and acts accordingly.
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import Tool
from langchain import hub
import json
# Define custom tools
def search_knowledge_base(query: str) -> str:
"""Search internal knowledge base"""
# Simulate knowledge base search
knowledge = {
"langchain": "LangChain is a framework for developing LLM applications",
"rag": "RAG stands for Retrieval Augmented Generation",
"agents": "Agents use tools and reasoning to accomplish tasks"
}
query_lower = query.lower()
for key, value in knowledge.items():
if key in query_lower:
return value
return f"No information found for: {query}"
def calculate(expression: str) -> str:
"""Perform mathematical calculations"""
try:
# Safe evaluation (in production, use a proper math parser)
result = eval(expression, {"__builtins__": {}}, {})
return f"Result: {result}"
except Exception as e:
return f"Calculation error: {str(e)}"
def analyze_data(data_json: str) -> str:
"""Analyze structured data"""
try:
data = json.loads(data_json)
if isinstance(data, list):
return f"List analysis: {len(data)} items, avg={sum(data)/len(data):.2f}"
elif isinstance(data, dict):
return f"Dict analysis: {len(data)} keys: {list(data.keys())}"
return f"Type: {type(data).__name__}"
except Exception as e:
return f"Analysis error: {str(e)}"
# Create tools
tools = [
Tool(
name="Knowledge_Base_Search",
func=search_knowledge_base,
description="Search the internal knowledge base for information about LangChain concepts"
),
Tool(
name="Calculator",
func=calculate,
description="Perform mathematical calculations. Input should be a valid Python expression like '2 + 2' or '10 * 5'"
),
Tool(
name="Data_Analyzer",
func=analyze_data,
description="Analyze structured data in JSON format. Input should be valid JSON."
)
]
# Create ReAct agent
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=5,
handle_parsing_errors=True
)
# Test queries
queries = [
"What is RAG and calculate 15 * 8",
"Analyze this data: [10, 20, 30, 40, 50]",
"Search for information about agents and calculate 100 / 4"
]
for query in queries:
print(f"\n{'='*60}")
print(f"Query: {query}")
print(f"{'='*60}")
result = agent_executor.invoke({"input": query})
print(f"\nFinal Answer: {result['output']}")Explanation: ReAct agents combine reasoning and acting. They think about which tool to use, execute it, observe the result, and continue until the task is complete. This example shows custom tools for search, calculation, and data analysis.
---
6. LangGraph Agent with Memory
Use Case: Conversational agent with persistent memory
Description: Modern agent using LangGraph with conversation history.
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
from langchain_core.tools import tool
# Define tools
@tool
def get_weather(location: str) -> str:
"""Get weather information for a location"""
# Simulate weather API
weather_data = {
"new york": "Sunny, 72°F",
"london": "Rainy, 15°C",
"tokyo": "Cloudy, 20°C"
}
return weather_data.get(location.lower(), "Weather data not available")
@tool
def save_preference(preference: str) -> str:
"""Save user preference to memory"""
return f"Saved preference: {preference}"
@tool
def get_news(topic: str) -> str:
"""Get latest news about a topic"""
return f"Latest news about {topic}: [Simulated news content]"
# Create agent with memory
memory = MemorySaver()
llm = ChatOpenAI(model="gpt-4o-mini")
agent_executor = create_react_agent(
llm,
tools=[get_weather, save_preference, get_news],
checkpointer=memory
)
# Conversation with memory
config = {"configurable": {"thread_id": "user_123"}}
# First interaction
print("Interaction 1:")
for chunk in agent_executor.stream(
{"messages": [("user", "What's the weather in New York?")]},
config=config,
stream_mode="values"
):
chunk["messages"][-1].pretty_print()
# Second interaction (remembers context)
print("\n\nInteraction 2:")
for chunk in agent_executor.stream(
{"messages": [("user", "Save my preference: I prefer metric units")]},
config=config,
stream_mode="values"
):
chunk["messages"][-1].pretty_print()
# Third interaction (uses memory)
print("\n\nInteraction 3:")
for chunk in agent_executor.stream(
{"messages": [("user", "Get news about AI")]},
config=config,
stream_mode="values"
):
chunk["messages"][-1].pretty_print()Explanation: LangGraph agents provide better control over execution flow and built-in memory management. The checkpointer maintains conversation state across interactions, enabling context-aware responses.
---
7. Multi-Step Research Agent
Use Case: Complex research tasks requiring multiple tool calls
Description: Agent that breaks down complex queries into steps.
from langchain_core.tools import tool
from langchain.agents import AgentExecutor, create_react_agent
@tool
def web_search(query: str) -> str:
"""Search the web for information"""
# Simulate web search
results = {
"langchain pricing": "LangChain is open source and free to use",
"python version": "Current Python version is 3.11",
"ai trends": "Top AI trends: LLMs, RAG, Agents, Multimodal AI"
}
for key in results:
if key in query.lower():
return results[key]
return f"Search results for: {query}"
@tool
def summarize_text(text: str) -> str:
"""Summarize long text into key points"""
# Simulate summarization
words = text.split()
if len(words) > 20:
return " ".join(words[:20]) + "... [summarized]"
return text
@tool
def compare_items(items: str) -> str:
"""Compare multiple items and provide analysis"""
return f"Comparison analysis of: {items}"
# Create research agent
tools = [web_search, summarize_text, compare_items]
llm = ChatOpenAI(model="gpt-4", temperature=0)
prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=10
)
# Complex research query
research_query = """
Research the current state of AI agents, find information about LangChain,
summarize the key findings, and compare different approaches to building agents.
"""
result = agent_executor.invoke({"input": research_query})
print(f"\n\nResearch Complete!")
print(f"Final Report: {result['output']}")Explanation: This agent demonstrates multi-step reasoning for complex tasks. It searches for information, processes results, and combines findings to answer complex queries.
---
Memory Examples
8. Conversation Buffer Memory
Use Case: Chatbot with complete conversation history
Description: Store and retrieve full conversation context.
from langchain.memory import ConversationBufferMemory
from langchain.chains import LLMChain
from langchain_core.prompts import ChatPromptTemplate
# Setup memory
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
# Create conversational prompt
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful AI assistant with memory of our conversation."),
("placeholder", "{chat_history}"),
("human", "{input}")
])
# Create chain with memory
llm = ChatOpenAI(model="gpt-4o-mini")
conversation = LLMChain(
llm=llm,
prompt=prompt,
memory=memory,
verbose=True
)
# Simulate conversation
conversations = [
"Hi, my name is Alice and I'm interested in learning Python",
"What programming concepts should I start with?",
"Can you remind me what my name is?",
"What was I interested in learning?"
]
for user_input in conversations:
print(f"\nUser: {user_input}")
response = conversation.run(input=user_input)
print(f"Assistant: {response}")
# Inspect memory
print("\n\nConversation History:")
print(memory.load_memory_variables({}))Explanation: ConversationBufferMemory stores the complete conversation history, enabling the model to reference previous interactions. This is ideal for short to medium conversations where full context is important.
---
9. Conversation Summary Memory
Use Case: Long conversations with automatic summarization
Description: Summarize conversation history to manage token limits.
from langchain.memory import ConversationSummaryMemory
# Create summary memory
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
memory = ConversationSummaryMemory(
llm=llm,
memory_key="chat_history",
return_messages=True
)
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant. Use the conversation summary below:"),
("placeholder", "{chat_history}"),
("human", "{input}")
])
conversation = LLMChain(llm=llm, prompt=prompt, memory=memory)
# Simulate long conversation
topics = [
"Tell me about machine learning",
"How does deep learning differ from traditional ML?",
"What are neural networks?",
"Explain backpropagation",
"What is gradient descent?",
"Tell me about overfitting",
"How do you prevent overfitting?",
"What is regularization?",
"Explain dropout technique",
"What have we discussed so far?" # Should use summary
]
for topic in topics:
print(f"\nUser: {topic}")
response = conversation.run(input=topic)
print(f"Assistant: {response[:150]}...")
# View summary
print("\n\nConversation Summary:")
print(memory.load_memory_variables({}))Explanation: ConversationSummaryMemory automatically summarizes conversation history when it gets too long. This maintains context while managing token limits for extended conversations.
---
10. Vector Store Memory
Use Case: Semantic search over conversation history
Description: Store conversations in vector database for semantic retrieval.
from langchain.memory import VectorStoreRetrieverMemory
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.prompts import PromptTemplate
# Initialize vector store
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_texts(
["Initial memory"], # Start with placeholder
embeddings,
metadatas=[{"timestamp": "initial"}]
)
# Create vector memory
memory = VectorStoreRetrieverMemory(
retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
memory_key="history"
)
# Save various facts
facts = [
("My name is Bob", "Nice to meet you Bob!"),
("I work as a data scientist", "That's interesting!"),
("I'm learning LangChain", "Great choice!"),
("My favorite color is blue", "Blue is a nice color!"),
("I have two cats named Whiskers and Mittens", "Cute names!")
]
for user_msg, ai_msg in facts:
memory.save_context(
{"input": user_msg},
{"output": ai_msg}
)
# Retrieve relevant memories
queries = [
"What's my profession?",
"Do I have any pets?",
"What color do I like?"
]
for query in queries:
print(f"\nQuery: {query}")
relevant_memories = memory.load_memory_variables({"input": query})
print(f"Relevant memories: {relevant_memories['history']}")Explanation: Vector store memory enables semantic search over conversation history. It retrieves relevant past interactions based on similarity, not just recent context.
---
11. Custom Recall Memory with LangGraph
Use Case: Structured long-term memory for agents
Description: Save and recall specific memories using vector search.
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_openai import OpenAIEmbeddings
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
# Initialize recall memory
recall_vector_store = InMemoryVectorStore(OpenAIEmbeddings())
@tool
def save_recall_memory(memory: str) -> str:
"""Save important information to long-term memory for future recall"""
recall_vector_store.add_texts([memory])
return f"Saved to memory: {memory}"
@tool
def search_recall_memories(query: str) -> str:
"""Search long-term memories for relevant information"""
docs = recall_vector_store.similarity_search(query, k=3)
if not docs:
return "No relevant memories found"
memories = "\n".join([f"- {doc.page_content}" for doc in docs])
return f"Relevant memories:\n{memories}"
@tool
def get_current_time() -> str:
"""Get the current time"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Create agent with recall tools
llm = ChatOpenAI(model="gpt-4o-mini")
agent = create_react_agent(llm, [save_recall_memory, search_recall_memories, get_current_time])
# Test conversation with memory
config = {"configurable": {"thread_id": "memory_test"}}
# Save memories
print("Saving memories...")
agent.invoke(
{"messages": [("user", "Remember that my birthday is on July 15th")]},
config=config
)
agent.invoke(
{"messages": [("user", "Save this: I prefer vegetarian food")]},
config=config
)
agent.invoke(
{"messages": [("user", "Remember my favorite programming language is Python")]},
config=config
)
# Recall memories
print("\n\nRecalling memories...")
result = agent.invoke(
{"messages": [("user", "What do you know about my preferences?")]},
config=config
)
print(result)Explanation: Custom recall memory provides structured long-term storage. Agents can explicitly save important information and search for it later using semantic similarity.
---
RAG Examples
12. Basic RAG Chain
Use Case: Question answering over documents
Description: Retrieve relevant documents and generate answers.
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.documents import Document
# Create sample documents
documents = [
Document(page_content="LangChain is a framework for developing applications powered by language models."),
Document(page_content="Chains allow you to combine multiple components together to create a single, coherent application."),
Document(page_content="Agents use language models to choose a sequence of actions to take."),
Document(page_content="Memory systems allow you to persist state between calls of a chain/agent."),
Document(page_content="RAG (Retrieval Augmented Generation) combines retrieval with generation for better answers."),
]
# Setup vector store
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# Create RAG prompt
prompt = ChatPromptTemplate.from_template("""
Answer the question based only on the following context:
Context:
{context}
Question: {question}
Provide a clear and concise answer:
""")
# Helper function
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# Build RAG chain
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# Test questions
questions = [
"What is LangChain?",
"How do agents work?",
"What is RAG?",
"Explain memory systems"
]
for question in questions:
print(f"\nQuestion: {question}")
answer = rag_chain.invoke(question)
print(f"Answer: {answer}")Explanation: Basic RAG retrieves relevant documents from a vector store and uses them as context for the LLM to generate accurate answers. This grounds responses in your data.
---
13. Conversational RAG
Use Case: Multi-turn Q&A with conversation history
Description: RAG that maintains conversation context for follow-up questions.
from langchain.chains import create_history_aware_retriever, create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import MessagesPlaceholder
# Setup (reuse vectorstore from previous example)
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# Contextualize question prompt
contextualize_prompt = ChatPromptTemplate.from_messages([
("system", "Given a chat history and the latest user question "
"which might reference context in the chat history, "
"formulate a standalone question which can be understood "
"without the chat history. Do NOT answer the question, "
"just reformulate it if needed and otherwise return it as is."),
MessagesPlaceholder("chat_history"),
("human", "{input}")
])
# Create history-aware retriever
history_aware_retriever = create_history_aware_retriever(
llm,
retriever,
contextualize_prompt
)
# QA prompt
qa_prompt = ChatPromptTemplate.from_messages([
("system", "Answer the question based on the following context:\n\n{context}"),
MessagesPlaceholder("chat_history"),
("human", "{input}")
])
# Create document chain
document_chain = create_stuff_documents_chain(llm, qa_prompt)
# Create full conversational RAG chain
conversational_rag_chain = create_retrieval_chain(
history_aware_retriever,
document_chain
)
# Simulate conversation
chat_history = []
questions = [
"What is LangChain?",
"What are its main components?", # Follow-up
"Tell me more about agents", # Another follow-up
]
for question in questions:
print(f"\nUser: {question}")
result = conversational_rag_chain.invoke({
"input": question,
"chat_history": chat_history
})
print(f"Assistant: {result['answer']}")
# Update chat history
chat_history.extend([
("human", question),
("ai", result['answer'])
])
print("\n\nFinal chat history length:", len(chat_history))Explanation: Conversational RAG reformulates follow-up questions using conversation history, enabling natural multi-turn conversations while maintaining retrieval accuracy.
---
14. Multi-Query RAG
Use Case: Improve retrieval coverage with multiple query variants
Description: Generate multiple search queries for comprehensive retrieval.
from langchain.retrievers.multi_query import MultiQueryRetriever
# Create multi-query retriever
llm = ChatOpenAI(temperature=0)
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=vectorstore.as_retriever(),
llm=llm
)
# Setup RAG chain with multi-query retriever
prompt = ChatPromptTemplate.from_template("""
Answer based on the context below. Be comprehensive.
Context:
{context}
Question: {question}
Answer:
""")
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
multi_query_rag = (
{"context": multi_query_retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# Test with ambiguous queries
queries = [
"How can I build applications?", # Could match chains, agents, etc.
"Tell me about memory",
"What features are available?"
]
for query in queries:
print(f"\n{'='*60}")
print(f"Query: {query}")
print(f"{'='*60}")
answer = multi_query_rag.invoke(query)
print(f"Answer: {answer}")Explanation: Multi-query RAG automatically generates multiple variations of the user's question, retrieves documents for each, and combines them. This improves coverage and handles ambiguous queries better.
---
15. RAG with Reranking
Use Case: Improve retrieval relevance with reranking
Description: Retrieve more documents initially, then rerank for relevance.
from langchain.retrievers import ContextualCompressionRetriever
from langchain_community.document_compressors import FlashrankRerank
# Create base retriever (retrieve more docs initially)
base_retriever = vectorstore.as_retriever(search_kwargs={"k": 10})
# Setup reranker
compressor = FlashrankRerank(top_n=3) # Rerank and keep top 3
# Create compression retriever
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever
)
# RAG chain with reranking
rerank_rag_chain = (
{"context": compression_retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# Compare with and without reranking
test_query = "How do I build intelligent applications?"
print("Without reranking:")
basic_docs = base_retriever.get_relevant_documents(test_query)
print(f"Retrieved {len(basic_docs)} documents")
for i, doc in enumerate(basic_docs[:3], 1):
print(f"{i}. {doc.page_content[:100]}...")
print("\n\nWith reranking:")
reranked_docs = compression_retriever.get_relevant_documents(test_query)
print(f"Reranked to {len(reranked_docs)} documents")
for i, doc in enumerate(reranked_docs, 1):
print(f"{i}. {doc.page_content[:100]}...")
print("\n\nFinal answer with reranking:")
answer = rerank_rag_chain.invoke(test_query)
print(answer)Explanation: Reranking retrieves more documents initially then uses a specialized model to reorder them by relevance. This two-stage approach improves answer quality.
---
16. RAG with Source Citations
Use Case: Provide answers with source attribution
Description: Track and cite source documents in responses.
from langchain_core.documents import Document
# Create documents with metadata
docs_with_metadata = [
Document(
page_content="LangChain is a framework for developing applications powered by language models.",
metadata={"source": "LangChain Documentation", "page": 1}
),
Document(
page_content="Chains combine multiple components together to create coherent applications.",
metadata={"source": "LangChain Guide", "page": 15}
),
Document(
page_content="Agents use LLMs to choose sequences of actions to take.",
metadata={"source": "Agent Tutorial", "page": 3}
),
]
# Create vector store with metadata
embeddings = OpenAIEmbeddings()
vectorstore_with_metadata = FAISS.from_documents(docs_with_metadata, embeddings)
retriever_with_metadata = vectorstore_with_metadata.as_retriever(search_kwargs={"k": 2})
# Citation prompt
citation_prompt = ChatPromptTemplate.from_template("""
Answer the question based on the context below. After your answer, cite the sources used.
Context:
{context}
Question: {question}
Answer (include citations in format [Source, Page]):
""")
# Helper to format docs with metadata
def format_docs_with_citations(docs):
formatted = []
for doc in docs:
content = doc.page_content
source = doc.metadata.get("source", "Unknown")
page = doc.metadata.get("page", "N/A")
formatted.append(f"{content}\n[Source: {source}, Page: {page}]")
return "\n\n".join(formatted)
# RAG chain with citations
citation_rag = (
{"context": retriever_with_metadata | format_docs_with_citations, "question": RunnablePassthrough()}
| citation_prompt
| llm
| StrOutputParser()
)
# Test
question = "What is LangChain and how do chains work?"
answer_with_citations = citation_rag.invoke(question)
print(f"Question: {question}")
print(f"\nAnswer with citations:\n{answer_with_citations}")Explanation: Including metadata with documents enables source attribution. This builds trust and allows users to verify information sources.
---
Advanced Patterns
17. Hybrid Agent-RAG System
Use Case: Agent with RAG capabilities and other tools
Description: Combine agent reasoning with RAG retrieval and tools.
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
# RAG tool
@tool
def search_knowledge_base(query: str) -> str:
"""Search the knowledge base for relevant information"""
# Reuse retriever from previous examples
docs = retriever.get_relevant_documents(query)
return format_docs(docs)
@tool
def calculate(expression: str) -> str:
"""Calculate mathematical expressions"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return f"Result: {result}"
except Exception as e:
return f"Error: {str(e)}"
@tool
def generate_summary(text: str) -> str:
"""Generate a summary of the provided text"""
summary_prompt = ChatPromptTemplate.from_template(
"Summarize this text concisely:\n\n{text}"
)
summary_chain = summary_prompt | llm | StrOutputParser()
return summary_chain.invoke({"text": text})
# Create hybrid agent
hybrid_agent = create_react_agent(
llm,
tools=[search_knowledge_base, calculate, generate_summary]
)
# Test complex queries that require multiple capabilities
complex_queries = [
"Search the knowledge base for information about agents and summarize it",
"Find information about chains and calculate how many components were mentioned",
"What is RAG? Then summarize your findings in one sentence"
]
for query in complex_queries:
print(f"\n{'='*60}")
print(f"Query: {query}")
print(f"{'='*60}")
for chunk in hybrid_agent.stream(
{"messages": [("user", query)]},
stream_mode="values"
):
chunk["messages"][-1].pretty_print()Explanation: Hybrid systems combine RAG retrieval with agent reasoning and tools. Agents decide when to retrieve information versus using other capabilities.
---
18. Streaming RAG with Callbacks
Use Case: Real-time RAG responses with progress tracking
Description: Stream responses and track execution stages.
from langchain_core.callbacks import BaseCallbackHandler
from typing import Any, Dict
class StreamingRAGCallback(BaseCallbackHandler):
"""Custom callback for tracking RAG execution"""
def __init__(self):
self.retrieval_count = 0
self.generation_started = False
def on_retriever_start(self, serialized: Dict[str, Any], query: str, **kwargs):
print(f"\n[Retrieval] Searching for: {query}")
self.retrieval_count += 1
def on_retriever_end(self, documents, **kwargs):
print(f"[Retrieval] Found {len(documents)} documents")
def on_llm_start(self, serialized: Dict[str, Any], prompts: list, **kwargs):
if not self.generation_started:
print("[Generation] Starting response generation...")
self.generation_started = True
def on_llm_new_token(self, token: str, **kwargs):
print(token, end="", flush=True)
def on_chain_end(self, outputs: Dict[str, Any], **kwargs):
print(f"\n\n[Complete] Total retrievals: {self.retrieval_count}")
# Setup streaming LLM
streaming_llm = ChatOpenAI(
model="gpt-4o-mini",
streaming=True,
temperature=0
)
# Create streaming RAG chain
streaming_rag = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| streaming_llm
| StrOutputParser()
)
# Execute with callback
callback = StreamingRAGCallback()
print("Question: What is LangChain?")
result = streaming_rag.invoke(
"What is LangChain?",
config={"callbacks": [callback]}
)Explanation: Streaming with callbacks provides real-time feedback on RAG execution. Users see retrieval progress and response generation as it happens.
---
19. Multi-Index RAG
Use Case: Search across multiple knowledge bases
Description: Route queries to appropriate vector stores.
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
# Create multiple specialized vector stores
technical_docs = [
Document(page_content="Python uses dynamic typing and garbage collection."),
Document(page_content="Async/await enables concurrent programming in Python."),
]
business_docs = [
Document(page_content="ROI measures the profitability of investments."),
Document(page_content="Agile methodology emphasizes iterative development."),
]
product_docs = [
Document(page_content="Our API supports REST and GraphQL."),
Document(page_content="Enterprise plan includes 24/7 support."),
]
# Create separate vector stores
embeddings = OpenAIEmbeddings()
technical_store = FAISS.from_documents(technical_docs, embeddings)
business_store = FAISS.from_documents(business_docs, embeddings)
product_store = FAISS.from_documents(product_docs, embeddings)
# Router function
def route_query(query: str) -> FAISS:
"""Route query to appropriate vector store"""
query_lower = query.lower()
if any(word in query_lower for word in ["python", "code", "programming", "technical"]):
print("[Router] -> Technical docs")
return technical_store
elif any(word in query_lower for word in ["business", "roi", "profit", "agile"]):
print("[Router] -> Business docs")
return business_store
else:
print("[Router] -> Product docs")
return product_store
# Multi-index RAG
def multi_index_rag(query: str) -> str:
# Route to appropriate store
vectorstore = route_query(query)
retriever = vectorstore.as_retriever()
# Build RAG chain
chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
return chain.invoke(query)
# Test routing
queries = [
"How does Python handle memory?",
"What is ROI?",
"What support options are available?"
]
for query in queries:
print(f"\n{'='*60}")
print(f"Query: {query}")
answer = multi_index_rag(query)
print(f"Answer: {answer}")Explanation: Multi-index RAG routes queries to specialized knowledge bases. This improves relevance by searching domain-specific collections.
---
20. Evaluation Pipeline
Use Case: Automated RAG evaluation and quality metrics
Description: Measure RAG performance with automated evaluation.
from langchain.evaluation import load_evaluator
from typing import List, Dict
# Evaluation metrics
def evaluate_rag_response(
question: str,
answer: str,
contexts: List[str],
ground_truth: str = None
) -> Dict[str, float]:
"""Evaluate RAG response quality"""
results = {}
# 1. Context relevance
relevance_evaluator = load_evaluator("criteria", criteria="relevance")
relevance_score = relevance_evaluator.evaluate_strings(
prediction=answer,
input=question,
reference="\n".join(contexts)
)
results["context_relevance"] = relevance_score
# 2. Answer completeness
if ground_truth:
accuracy_evaluator = load_evaluator("labeled_criteria", criteria="correctness")
accuracy = accuracy_evaluator.evaluate_strings(
prediction=answer,
input=question,
reference=ground_truth
)
results["accuracy"] = accuracy
# 3. Response length appropriateness
word_count = len(answer.split())
results["word_count"] = word_count
results["conciseness_score"] = 1.0 if 50 <= word_count <= 200 else 0.5
return results
# Test cases with ground truth
test_cases = [
{
"question": "What is LangChain?",
"ground_truth": "LangChain is a framework for developing applications powered by language models"
},
{
"question": "How do agents work?",
"ground_truth": "Agents use language models to choose sequences of actions to take"
}
]
# Evaluate RAG system
print("Evaluating RAG System...\n")
for i, test in enumerate(test_cases, 1):
print(f"Test Case {i}:")
print(f"Question: {test['question']}")
# Get RAG response
answer = rag_chain.invoke(test["question"])
print(f"Answer: {answer[:100]}...")
# Get retrieved contexts
docs = retriever.get_relevant_documents(test["question"])
contexts = [doc.page_content for doc in docs]
# Evaluate
scores = evaluate_rag_response(
question=test["question"],
answer=answer,
contexts=contexts,
ground_truth=test["ground_truth"]
)
print(f"Evaluation Scores: {scores}\n")
print(f"{'='*60}\n")Explanation: Automated evaluation measures RAG quality using metrics like context relevance, answer accuracy, and conciseness. This enables systematic optimization.
---
Summary
This examples collection demonstrates:
Chains (4 examples):
- Sequential processing with dependencies
- Parallel map-reduce patterns
- Dynamic routing and classification
- Conditional branching
Agents (3 examples):
- ReAct agents with custom tools
- LangGraph agents with memory
- Multi-step research workflows
Memory (4 examples):
- Complete conversation history
- Automatic summarization
- Semantic memory search
- Custom recall systems
RAG (5 examples):
- Basic retrieval-augmented generation
- Conversational RAG with history
- Multi-query retrieval
- Reranking for relevance
- Source citations
Advanced Patterns (4 examples):
- Hybrid agent-RAG systems
- Streaming with callbacks
- Multi-index routing
- Automated evaluation
Each example includes:
- Clear use case description
- Complete, runnable code
- Detailed explanation
- Production considerations
For comprehensive API reference, see SKILL.md. For architecture and learning path, see README.md.
LangChain Orchestration
Production-grade guide for building LLM applications with LangChain's chains, agents, memory systems, and RAG patterns.
Quick Start
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# Basic chain
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_template("Tell me about {topic}")
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "LangChain"})
print(result)Installation
# Core packages
pip install langchain langchain-core langchain-community
# LLM providers
pip install langchain-openai langchain-anthropic langchain-huggingface
# Vector stores
pip install faiss-cpu chromadb pinecone-client
# Additional utilities
pip install langgraph langsmith python-dotenvArchitecture Overview
LangChain orchestration consists of five main components:
1. Chains
Compose multiple operations into pipelines using LCEL (LangChain Expression Language).
# Sequential processing
chain = prompt | llm | output_parser
# Parallel processing
from langchain_core.runnables import RunnableParallel
parallel_chain = RunnableParallel(
summary=summary_chain,
keywords=keywords_chain,
sentiment=sentiment_chain
)Key patterns:
- Sequential chains: Process data step-by-step
- Map-reduce chains: Parallel processing with aggregation
- Router chains: Dynamic routing based on input
- Conditional chains: Branch execution based on conditions
2. Agents
Autonomous systems that use tools and reasoning to accomplish tasks.
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(llm, tools=[search_tool, calculator_tool])
result = agent.invoke({
"messages": [("user", "What is 25 * 4?")]
})Agent types:
- ReAct agents: Reasoning + Acting with iterative tool use
- Conversational agents: Context-aware dialogue systems
- Zero-shot agents: Work without examples
- Structured agents: Use defined input/output schemas
3. Memory Systems
Maintain conversation context and user preferences.
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
# Automatically stores and retrieves context
chain = LLMChain(llm=llm, prompt=prompt, memory=memory)Memory types:
- Buffer memory: Store complete history
- Window memory: Keep last K interactions
- Summary memory: Summarize long conversations
- Vector memory: Semantic search over history
4. RAG (Retrieval-Augmented Generation)
Enhance LLM responses with external knowledge.
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
# Setup retriever from vector store
retriever = vectorstore.as_retriever()
# Build RAG chain
document_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, document_chain)
result = rag_chain.invoke({"input": "Your question"})RAG patterns:
- Basic RAG: Simple retrieval + generation
- Multi-query RAG: Multiple search queries
- RAG with reranking: Improve relevance
- Conversational RAG: Context-aware retrieval
5. Streaming
Real-time token generation for better UX.
for chunk in chain.stream({"topic": "AI"}):
print(chunk, end="", flush=True)Common Use Cases
1. Question Answering System
Build a QA system over your documents:
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# Load and embed documents
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)
# Create QA chain
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vectorstore.as_retriever()
)
answer = qa_chain.run("What is the main topic of the documents?")2. Conversational AI
Create a chatbot with memory:
from langchain.memory import ConversationBufferWindowMemory
memory = ConversationBufferWindowMemory(k=5, return_messages=True)
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
("placeholder", "{chat_history}"),
("human", "{input}")
])
chain = LLMChain(llm=llm, prompt=prompt, memory=memory)
# Maintains conversation context
response1 = chain.run("Hi, I'm Alice")
response2 = chain.run("What's my name?") # Remembers Alice3. Research Assistant
Agent that can search and analyze information:
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import Tool
def search_web(query: str) -> str:
# Your search implementation
return f"Results for: {query}"
def analyze_data(data: str) -> str:
# Your analysis implementation
return f"Analysis of: {data}"
tools = [
Tool(name="Search", func=search_web, description="Search the web"),
Tool(name="Analyze", func=analyze_data, description="Analyze data")
]
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = agent_executor.invoke({
"input": "Research LangChain and analyze its key features"
})4. Document Summarization
Summarize long documents efficiently:
from langchain.chains.summarize import load_summarize_chain
# Map-reduce summarization
chain = load_summarize_chain(
llm,
chain_type="map_reduce",
verbose=True
)
summary = chain.run(documents)5. Data Extraction
Extract structured information:
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
class Person(BaseModel):
name: str = Field(description="Person's name")
age: int = Field(description="Person's age")
occupation: str = Field(description="Person's occupation")
parser = PydanticOutputParser(pydantic_object=Person)
prompt = ChatPromptTemplate.from_template(
"""Extract person information:
{format_instructions}
Text: {text}"""
).partial(format_instructions=parser.get_format_instructions())
chain = prompt | llm | parser
result = chain.invoke({"text": "John Doe is a 30-year-old engineer"})
# Returns Person objectLearning Path
Beginner (Week 1-2)
1. Basic Chains
- Understand LCEL syntax
- Build simple prompt | llm | parser chains
- Practice with sequential operations
2. Prompts & Outputs
- Create effective prompt templates
- Use output parsers
- Handle structured outputs
3. Simple RAG
- Setup vector stores
- Build basic retrieval chains
- Test with small document sets
Intermediate (Week 3-4)
1. Advanced Chains
- Implement map-reduce patterns
- Build router chains
- Use conditional logic
2. Memory Systems
- Add conversation memory
- Implement different memory types
- Manage context windows
3. Agent Basics
- Create simple ReAct agents
- Define custom tools
- Handle agent errors
Advanced (Week 5-6)
1. Complex RAG
- Multi-query retrieval
- Reranking strategies
- Parent document retrieval
- Conversational RAG
2. Production Agents
- LangGraph integration
- Structured memory
- Tool calling patterns
- Agent orchestration
3. Monitoring & Optimization
- Implement callbacks
- Setup LangSmith tracing
- Optimize performance
- Handle errors gracefully
Expert (Week 7+)
1. Custom Components
- Build custom retrievers
- Create specialized chains
- Implement custom memory
2. Production Deployment
- Caching strategies
- Rate limiting
- Batch processing
- Testing frameworks
3. Advanced Patterns
- Multi-agent systems
- Complex orchestration
- Hybrid retrieval
- Custom evaluation
Configuration Best Practices
Environment Setup
# .env file
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=ls__...
LANGCHAIN_PROJECT=my-project
# Vector store
VECTOR_STORE_TYPE=faiss
EMBEDDING_MODEL=text-embedding-3-small
# Model configuration
DEFAULT_MODEL=gpt-4o-mini
DEFAULT_TEMPERATURE=0.7
MAX_TOKENS=500Loading Configuration
import os
from dotenv import load_dotenv
load_dotenv()
# Initialize with environment variables
llm = ChatOpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
model=os.getenv("DEFAULT_MODEL", "gpt-4o-mini"),
temperature=float(os.getenv("DEFAULT_TEMPERATURE", "0.7")),
max_tokens=int(os.getenv("MAX_TOKENS", "500"))
)Error Handling Patterns
Retry with Exponential Backoff
chain_with_retry = chain.with_retry(
stop_after_attempt=3,
wait_exponential_jitter=True
)Fallback Chains
primary_chain = prompt | expensive_llm
fallback_chain = prompt | cheap_llm
chain_with_fallback = primary_chain.with_fallbacks([fallback_chain])Timeout Protection
from langchain_core.runnables import RunnableConfig
config = RunnableConfig(timeout=10.0)
result = chain.invoke({"topic": "AI"}, config=config)Performance Tips
1. Use smaller models for simple tasks
- gpt-4o-mini for basic tasks
- gpt-4 for complex reasoning
2. Implement caching
- Cache LLM responses
- Cache embeddings
- Cache retrieval results
3. Batch operations
- Use chain.batch() for multiple inputs
- Set max_concurrency appropriately
4. Optimize retrieval
- Limit k parameter
- Use appropriate chunk sizes
- Implement reranking
5. Stream when possible
- Better user experience
- Lower perceived latency
- Easier to cancel
Testing Your Chains
import pytest
def test_basic_chain():
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "testing"})
assert isinstance(result, str)
assert len(result) > 0
def test_rag_chain():
result = rag_chain.invoke("What is LangChain?")
assert "LangChain" in result.lower()
@pytest.mark.asyncio
async def test_async_chain():
result = await chain.ainvoke({"topic": "async"})
assert isinstance(result, str)Monitoring in Production
LangSmith Integration
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-key"
os.environ["LANGCHAIN_PROJECT"] = "production"
# All chains automatically traced
result = chain.invoke({"topic": "AI"})Custom Callbacks
from langchain_core.callbacks import BaseCallbackHandler
class MetricsCallback(BaseCallbackHandler):
def __init__(self):
self.metrics = {
"llm_calls": 0,
"total_tokens": 0,
"errors": 0
}
def on_llm_start(self, serialized, prompts, **kwargs):
self.metrics["llm_calls"] += 1
def on_llm_end(self, response, **kwargs):
# Track token usage
pass
def on_chain_error(self, error, **kwargs):
self.metrics["errors"] += 1Resources
Official Documentation
Community
Examples
- See EXAMPLES.md for 18+ production-ready patterns
- Check SKILL.md for comprehensive API reference
File Structure
langchain-orchestration/
├── SKILL.md # Comprehensive guide with 60+ examples
├── README.md # Quick start and learning path
└── EXAMPLES.md # 18+ production-ready examplesContributing
This skill is designed to be comprehensive and production-ready. For improvements or additions:
1. Ensure examples are tested and working 2. Follow the existing structure and style 3. Include both basic and advanced use cases 4. Add production best practices
License
This skill documentation is provided as-is for educational and production use.
---
Next Steps: 1. Review SKILL.md for comprehensive API coverage 2. Explore EXAMPLES.md for production patterns 3. Start with Basic Chains in the Learning Path 4. Build your first RAG application 5. Deploy with monitoring and error handling
Happy orchestrating!