LangChain in Production: Patterns That Work and Anti-Patterns That Don't
Lessons from running LangChain in production: the anti-patterns that cause failures, the patterns that work, with code examples and cost optimization strategies.
The Production Gap#
Moving LangChain applications from prototype to production reveals a gap between documentation examples and real-world requirements. What works perfectly in development can become costly, slow, or unreliable under production load.
Prototype workloads hide failure modes that only surface at scale: agents that loop on ambiguous inputs, token spend that climbs with every conversation turn, and silent failures that reach you as user complaints. The framework’s abstractions accelerate prototyping but obscure the cost, latency, and reliability levers you need under production load.
The default that holds up: bound every resource explicitly (memory tokens, agent iterations, execution time, output length), wire tracing in before the first chain runs, and drop to the provider SDK wherever the abstraction buys you nothing.
Understanding the Framework Trade-off#
LangChain solved early LLM integration complexity by providing standard abstractions for prompts, chains, agents, and memory management. This made prototyping significantly faster. What might take weeks with direct API calls could be done in days.
However, these abstractions introduce their own challenges:
The velocity-control trade-off: Rapid prototyping comes at the cost of transparency. When something goes wrong in production, debugging through multiple abstraction layers becomes significantly harder than debugging a direct API call.
Hidden behaviors: Framework internals make decisions that aren’t always visible: memory trimming strategies, automatic retries, callback execution order. These work fine until they don’t, and diagnosing why requires deep-diving into source code.
Performance overhead: Each abstraction layer adds latency. Memory wrappers, callback systems, and automatic processing all run on every request. Profile them before assuming the LLM call dominates; on short prompts the framework’s own work can rival it.
The framework inflection point occurs when your team spends more time debugging framework behavior than building features. Some teams hit this quickly, others never do.
The 7 Deadly Anti-Patterns#
1. Unbounded Memory Accumulation#
The default ConversationBufferMemory stores unlimited conversation history:
from langchain.memory import ConversationBufferMemory
# Anti-pattern: This accumulates unbounded history
# Note: ConversationBufferMemory is deprecated - use LangGraph persistence
# or RunnableWithMessageHistory for new projects
memory = ConversationBufferMemory()
# After 50 exchanges: massive context, slow responses, high costs
Every request resends the full history, so cost and latency both grow with conversation length. Eventually the context window overflows and requests start failing outright. Track token usage trends over time and flag conversations whose response times keep growing.
The fix is ConversationSummaryBufferMemory with explicit limits, or a migration to LangGraph persistence:
from langchain.memory import ConversationSummaryBufferMemory
# Note: ConversationSummaryBufferMemory is deprecated
# For new projects, use LangGraph persistence or RunnableWithMessageHistory
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=500, # Keep recent context compact
return_messages=True
)
# Older turns collapse into a summary, so tokens per request stay bounded
2. Agent Without Guardrails#
Creating agents without execution controls:
from langchain.agents import AgentExecutor
# Anti-pattern: No limits on execution
executor = AgentExecutor(agent=agent, tools=tools)
# Nothing here stops the agent bouncing between search and summarize forever
A ReAct loop that never satisfies its stop condition keeps calling tools until something external kills it. Every iteration is a paid LLM call, and the user is staring at a spinner the whole time. Cost alerts and execution time monitoring need to exist before this reaches production.
Explicit controls in configuration put a hard stop on it:
from langchain.agents import AgentExecutor
from langchain.callbacks import get_openai_callback
executor = AgentExecutor(
agent=agent,
tools=tools,
max_iterations=5, # Prevent infinite loops
max_execution_time=30, # Timeout after 30 seconds
early_stopping_method="generate"
)
# Note: get_openai_callback may not capture costs for newer agent types
# Consider using LangSmith for comprehensive cost tracking
with get_openai_callback() as cb:
result = executor.run(query)
print(f"Tokens: {cb.total_tokens}, Cost: ${cb.total_cost}")
3. Over-Abstraction for Simple Tasks#
Using full LangChain abstractions for straightforward operations:
// Anti-pattern: 5 layers of abstraction for simple completion
import { ChatOpenAI } from "langchain/chat_models/openai";
import { ChatPromptTemplate } from "langchain/prompts";
import { StringOutputParser } from "langchain/schema/output_parser";
const chatModel = new ChatOpenAI();
const outputParser = new StringOutputParser();
const prompt = ChatPromptTemplate.fromMessages([
["system", "You are a helpful translator."],
["user", "Translate {text} to {language}"]
]);
const chain = prompt.pipe(chatModel).pipe(outputParser);
// Direct API: Same result, no framework overhead
import OpenAI from "openai";
const openai = new OpenAI();
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [
{ role: "system", content: "You are a helpful translator." },
{ role: "user", content: `Translate ${text} to ${language}` }
]
});
Unnecessary complexity, harder debugging, and team cognitive load pile up for tasks that don’t benefit from the abstraction. Count the layers during code review: importing four or more modules for a basic completion is the signal to reach for the direct API instead.
4. Hidden Latency Overhead#
Framework components can add significant latency:
from langchain.memory import ConversationBufferWindowMemory
# Anti-pattern: wrapper work on every call, never measured
memory = ConversationBufferWindowMemory(k=5)
# Worth profiling: serialisation and callback dispatch happen per invocation
Poor user experience and difficulty scaling to higher request volumes follow close behind. Profile with and without the framework components, and measure end-to-end latency against direct API call time to see the actual gap.
For performance-critical paths, a custom lightweight alternative removes the overhead:
# Custom trimmed memory - keeps last N messages efficiently
class LightweightMemory:
def __init__(self, max_messages=10):
self.messages = []
self.max_messages = max_messages
def add_message(self, message):
self.messages.append(message)
if len(self.messages) > self.max_messages:
self.messages = self.messages[-self.max_messages:]
def get_context(self):
return self.messages
# No callback dispatch, no serialisation round-trip on the hot path
5. Shipping Development Defaults#
Production deployments with development defaults:
# Anti-pattern: Development defaults in production
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI()
# No caching, no output limits, no cost controls
High operational costs, slow responses, and verbose logging filling disk space stay invisible until you baseline cost and latency metrics before the production launch.
Explicit production configuration puts a floor under all three:
from langchain.chat_models import ChatOpenAI
from langchain.cache import RedisCache
from langchain.globals import set_llm_cache
import redis
# Production-ready configuration
set_llm_cache(RedisCache(
redis_=redis.Redis(host="localhost", port=6379)
))
llm = ChatOpenAI(
model="gpt-4",
temperature=0.7,
max_tokens=512, # Limit output length
request_timeout=30, # Timeout for API calls
max_retries=2 # Controlled retry behavior
)
6. Black-Box Agent Behavior#
Deploying agents without observability:
# Anti-pattern: No visibility into agent decisions
executor = AgentExecutor(agent=agent, tools=tools)
result = executor.run(query)
# When this fails silently, you have no idea why
Silent failures, impossible debugging, and discovering issues only through user complaints follow. There is nothing to detect until traces exist, which is precisely the problem.
LangSmith tracing from day one changes that:
import os
from langchain.callbacks.tracers import LangChainTracer
# Enable tracing in environment
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-api-key"
# Automatic tracing of all chains, agents, tools
# Track: latency, costs, tokens, failures, decision paths
executor = AgentExecutor(agent=agent, tools=tools)
result = executor.run(query)
# All execution details now visible in LangSmith dashboard
7. Underestimating Data Ingestion#
Underestimating RAG pipeline complexity:
# Anti-pattern: Assuming document loading "just works"
from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("document.pdf")
documents = loader.load()
# Parser choice, encoding and chunking are where RAG projects actually stall
Wrong PDF parser for your document types, encoding issues with international text, and chunking problems that degrade retrieval quality show up as high failure rates in document processing and poor retrieval results.
Thorough testing of data loaders across multiple strategies catches this early:
from langchain.document_loaders import PyPDFLoader, PDFMinerLoader, UnstructuredPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Try multiple parsers, test with real documents
parsers = [
PyPDFLoader,
PDFMinerLoader,
UnstructuredPDFLoader
]
for ParserClass in parsers:
try:
loader = ParserClass("document.pdf")
docs = loader.load()
# Validate output quality
if validate_extraction(docs):
break
except Exception as e:
print(f"{ParserClass.__name__} failed: {e}")
# Thoughtful chunking strategy
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200, # Maintain context across chunks
length_function=len
)
chunks = splitter.split_documents(docs)
Production-Ready Patterns#
LCEL-First Architecture#
Modern LangChain applications use LCEL (LangChain Expression Language) for better composability:
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
# LCEL: Readable pipe syntax with built-in streaming
chain = (
ChatPromptTemplate.from_template("Analyze: {input}")
| ChatOpenAI(model="gpt-4", streaming=True)
| StrOutputParser()
)
# Supports streaming, batching, async out of the box
for chunk in chain.stream({"input": query}):
print(chunk, end="", flush=True)
LCEL gives clear composition, built-in async support, and easier debugging than legacy chains, and it pays off most in complex workflows that chain multiple LLM calls, transformations, or conditional logic.
Explicit Resource Controls#
Production configuration should make limits explicit:
from langchain.agents import AgentExecutor
from langchain.callbacks import get_openai_callback
# All limits explicit and documented
executor = AgentExecutor(
agent=agent,
tools=tools,
max_iterations=5, # Stop after 5 tool calls
max_execution_time=30, # Hard timeout at 30 seconds
early_stopping_method="generate", # Graceful degradation
verbose=False # Disable debug logging in production
)
# Cost tracking on every request
with get_openai_callback() as cb:
result = executor.run(query)
# Alert if costs exceed threshold
if cb.total_cost > 0.10:
send_alert(f"High cost request: ${cb.total_cost}")
Implementation checklist:
- Token limits on memory and outputs
- Agent iteration caps and timeouts
- Cost budgets and alerts
- Retry limits and exponential backoff
Multi-Tier Caching Strategy#
Caching dramatically reduces costs and latency:
from langchain.cache import InMemoryCache, SQLiteCache, RedisCache
from langchain.globals import set_llm_cache
import redis
# Development: In-memory cache
# set_llm_cache(InMemoryCache())
# Local persistence: SQLite
# set_llm_cache(SQLiteCache(database_path=".langchain.db"))
# Production: Distributed Redis cache
set_llm_cache(RedisCache(
redis_=redis.Redis(
host="redis.production.internal",
port=6379,
db=0
)
))
# Cache configuration
# TTL: 1 year for static content, 1 day for dynamic
# Invalidation: Manual or event-driven for updated content
A cache hit skips the API call entirely, so the payoff tracks how repetitive your traffic actually is. Measure the hit rate before you count the savings.
Observability-First Development#
Set up tracing before writing your first chain:
import os
from langchain.callbacks.base import BaseCallbackHandler
# LangSmith tracing configuration
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-api-key"
os.environ["LANGCHAIN_PROJECT"] = "production-app"
# Custom callback for business metrics
class ProductionMetricsCallback(BaseCallbackHandler):
def on_llm_start(self, serialized, prompts, **kwargs):
self.start_time = time.time()
def on_llm_end(self, response, **kwargs):
latency = time.time() - self.start_time
tokens = response.llm_output.get("token_usage", {})
# Send to your monitoring system
metrics.record("llm.latency", latency)
metrics.record("llm.tokens", tokens.get("total_tokens", 0))
metrics.record("llm.cost", calculate_cost(tokens))
# Use in all chain executions
callbacks = [ProductionMetricsCallback()]
result = chain.invoke({"input": query}, config={"callbacks": callbacks})
Metrics worth tracking:
- Performance: QPS, latency percentiles (p50, p95, p99), time-to-first-token
- Cost: Total tokens, cost per request, daily burn rate
- Quality: Error rates, retry counts, user feedback
- Agent behavior: Tool selections, iteration counts, decision paths
Smart Model Routing#
Route requests to appropriate models based on complexity:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
# Define models with cost/capability trade-offs
cheap_model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
premium_model = ChatOpenAI(model="gpt-4", temperature=0.7)
def route_to_model(query: str):
"""Route based on query complexity"""
complexity_score = analyze_complexity(query)
if complexity_score < 0.3:
return cheap_model # GPT-3.5-turbo: $0.0005/1K input, $0.0015/1K output
else:
return premium_model # GPT-4: $0.03/1K input, $0.06/1K output
# Consider GPT-4o mini for cost-effective option: $0.00015/1K input, $0.0006/1K output
# Dynamic routing in chain
def create_chain(query: str):
model = route_to_model(query)
prompt = ChatPromptTemplate.from_template("{input}")
return prompt | model
# Example complexity analysis
def analyze_complexity(query: str) -> float:
"""Simple heuristic-based complexity scoring"""
score = 0.0
# Length-based scoring
if len(query.split()) > 50:
score += 0.3
# Technical term detection
technical_terms = ["architecture", "algorithm", "performance", "optimization"]
if any(term in query.lower() for term in technical_terms):
score += 0.4
# Multi-step reasoning indicators
if any(word in query.lower() for word in ["compare", "analyze", "explain why"]):
score += 0.3
return min(score, 1.0)
Savings scale with the share of traffic the cheap model can absorb, and every misroute buys that saving with a worse answer. Score the router against a labelled sample before trusting it.
Structured Outputs with Pydantic#
Type-safe outputs reduce post-processing bugs:
from langchain.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
# Define output schema
class ProductAnalysis(BaseModel):
sentiment: str = Field(description="positive, negative, or neutral")
key_features: list[str] = Field(description="list of mentioned features")
price_mentioned: bool = Field(description="whether price was discussed")
confidence_score: float = Field(description="confidence from 0 to 1")
# Parser with schema validation
parser = PydanticOutputParser(pydantic_object=ProductAnalysis)
# Prompt includes format instructions
prompt = PromptTemplate(
template="Analyze this product review:\n{review}\n{format_instructions}",
input_variables=["review"],
partial_variables={"format_instructions": parser.get_format_instructions()}
)
chain = prompt | ChatOpenAI(model="gpt-4") | parser
# Type-safe output
result: ProductAnalysis = chain.invoke({"review": review_text})
print(f"Sentiment: {result.sentiment}, Confidence: {result.confidence_score}")
Type safety, automatic validation, and clear contracts between the LLM and downstream code are the payoff.
The Migration Decision Matrix#
Choosing the right approach depends on your specific requirements:
When to Use LangChain#
- Complex multi-agent systems requiring orchestration
- RAG with multiple retrievers and re-ranking
- Teams needing standard abstractions for collaboration
- Rapid prototyping phase with plans for production hardening
- Heavy reliance on LangSmith observability ecosystem
Example: LinkedIn’s SQL Bot uses LangChain chains wrapped in LangGraph nodes for production-grade multi-agent coordination.
The LlamaIndex Alternative#
- Primary focus on search and retrieval
- Large dataset indexing requirements
- Need for efficient semantic similarity search
- Simpler, more focused use case than general orchestration
Skipping the Framework Entirely#
- Simple chatbot or completion tasks
- Clear, unchanging requirements
- Performance-critical applications where latency matters
- Small team wanting full control
- Minimal external dependencies desired
Example implementation:
from openai import OpenAI
client = OpenAI()
# Clear, explicit, fast
response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": prompt}
],
max_tokens=512,
temperature=0.7
)
answer = response.choices[0].message.content
Signs It’s Time to Migrate#
Consider migration when:
- Team spends more time debugging framework behavior than building features
- Performance profiling puts framework overhead ahead of the LLM call on the critical path
- Requirements don’t fit LangChain’s patterns and you’re fighting the framework
- Dependency management becomes a maintenance burden
Migration approach: Incremental replacement, starting with highest-impact components. Keep what works, replace what doesn’t.
LangGraph: Production Evolution#
LangGraph emerged in 2024 as a production-focused evolution, designed from lessons learned deploying LangChain agents:
Key differences:
- Low-level, controllable framework without hidden behaviors
- No hidden prompts or automatic cognitive architecture
- Durable execution for complex agentic systems
- State management across long-running workflows
Hybrid pattern:
from langgraph.graph import StateGraph, END
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
# Define state
class AgentState(dict):
messages: list[str]
current_step: str
# Use LangChain for LLM interactions
analysis_chain = (
ChatPromptTemplate.from_template("Analyze: {input}")
| ChatOpenAI(model="gpt-4")
)
# Wrap in LangGraph nodes for orchestration
workflow = StateGraph(AgentState)
def analyze_node(state: AgentState):
result = analysis_chain.invoke({"input": state["messages"][-1]})
state["messages"].append(result)
return state
workflow.add_node("analyze", analyze_node)
workflow.add_edge("analyze", END)
workflow.set_entry_point("analyze")
# Best of both: LangChain composability + LangGraph control
app = workflow.compile()
When to upgrade: Moving from AgentExecutor to LangGraph, need for multi-agent coordination, state management across long-running workflows, production reliability requirements.
Companies using LangGraph in production: Uber, LinkedIn, Replit, Elastic.
Cost Optimization Strategies#
Token Management#
Track and control token usage aggressively:
from langchain.callbacks import get_openai_callback
# 1. Track everything
# Note: get_openai_callback has limitations with newer agent implementations
# Use LangSmith for comprehensive tracking across all agent types
with get_openai_callback() as cb:
result = chain.invoke({"input": query})
print(f"Tokens: {cb.total_tokens}, Cost: ${cb.total_cost:.4f}")
# 2. Trim context to last N exchanges
from langchain.memory import ConversationBufferWindowMemory
# Note: ConversationBufferWindowMemory is deprecated
# For new projects, use LangGraph persistence or RunnableWithMessageHistory
memory = ConversationBufferWindowMemory(
k=5, # Keep only last 5 exchanges
return_messages=True
)
# 3. Smart summarization for older context
from langchain.memory import ConversationSummaryBufferMemory
# Note: ConversationSummaryBufferMemory is deprecated
# Migrate to LangGraph persistence for production applications
memory = ConversationSummaryBufferMemory(
llm=llm,
max_token_limit=500,
return_messages=True
)
# 4. Explicit output limits
llm = ChatOpenAI(
model="gpt-4",
max_tokens=512 # Concise responses
)
Where the Savings Come From#
The four levers compound, and they compound in a specific order. Routing changes the price per token, so apply it first; it has the largest effect and the largest quality risk. Memory trimming and output limits change the token count per request, which multiplies against whatever price the router picked. Caching removes requests entirely, so it sits on top of all three.
Model your own numbers before promising anything: take the published per-token prices for the models you route between, multiply by your measured tokens per request, and only then apply your observed cache hit rate.
Monitoring and Observability#
Essential Production Metrics#
import time
from langchain.callbacks.base import BaseCallbackHandler
class ProductionMetrics(BaseCallbackHandler):
"""Comprehensive production monitoring"""
def on_chain_start(self, serialized, inputs, **kwargs):
self.chain_start = time.time()
def on_chain_end(self, outputs, **kwargs):
duration = time.time() - self.chain_start
metrics.gauge("chain.duration", duration)
def on_llm_start(self, serialized, prompts, **kwargs):
self.llm_start = time.time()
metrics.increment("llm.requests")
def on_llm_end(self, response, **kwargs):
# Performance metrics
latency = time.time() - self.llm_start
metrics.gauge("llm.latency", latency)
# Cost metrics
usage = response.llm_output.get("token_usage", {})
total_tokens = usage.get("total_tokens", 0)
cost = calculate_cost(usage)
metrics.gauge("llm.tokens", total_tokens)
metrics.gauge("llm.cost", cost)
def on_llm_error(self, error, **kwargs):
metrics.increment("llm.errors")
logger.error(f"LLM error: {error}")
def on_tool_start(self, serialized, input_str, **kwargs):
tool_name = serialized.get("name", "unknown")
metrics.increment(f"tool.{tool_name}.calls")
def on_agent_action(self, action, **kwargs):
metrics.increment("agent.actions")
LangSmith Integration#
LangSmith provides automatic tracing without code changes:
import os
# Environment configuration
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-api-key"
os.environ["LANGCHAIN_PROJECT"] = "production-app"
# Optional: Add metadata for filtering
from langchain.callbacks.tracers import LangChainTracer
tracer = LangChainTracer(
project_name="production-app",
tags=["prod", "version-2.1"]
)
# All chain executions automatically traced
result = chain.invoke(
{"input": query},
config={"callbacks": [tracer]}
)
What LangSmith tracks:
- Execution traces with timing for each step
- Token usage and costs per request
- Agent decision paths and tool selections
- Error rates and failure patterns
- A/B test comparisons with metadata tags
Migration Patterns#
From LangChain to Custom Code#
Incremental approach minimizes risk:
# Week 1: Profile to find the component with the worst cost/latency ratio
# Week 2: Create custom replacement
class EfficientMemory:
def __init__(self, max_messages=10):
self.messages = []
self.max_messages = max_messages
def add(self, message):
self.messages.append(message)
if len(self.messages) > self.max_messages:
self.messages = self.messages[-self.max_messages:]
def get_context(self):
return "\n".join(self.messages)
# Week 3: A/B test implementations
# Group A: LangChain memory (baseline)
# Group B: Custom memory (test)
# Week 4: Compare on p95 latency, tokens per request, answer quality
# Week 5+: Gradual rollout
# 10% → 50% → 100% over 2 weeks
From Legacy Chains to LCEL#
LangChain provides migration tooling:
# Automated migration assistance
langchain migrate --legacy-to-lcel chain.py
Manual migration example:
# Legacy: initialize_agent pattern (deprecated)
from langchain.agents import initialize_agent, AgentType
agent = initialize_agent(
tools=tools,
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION
)
# Modern: LangGraph prebuilt (recommended)
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(
model=llm,
tools=tools
)
Better composability, built-in streaming, clearer debugging, and full control over agent behavior round out the case for making the switch.
Failure Modes in Practice#
The Prototype-to-Production Trap#
A prototype running on defaults looks fine in development, then production reveals high costs, slow responses, and silent failures. Design for production from day one: set resource limits, add caching, and wire in observability before the first deployment.
Framework Lock-In#
Starting with LangChain for rapid prototyping is the easy call. Six months into a deeply coupled architecture, migrating away becomes months of work, unless framework usage stayed at the boundaries with core business logic kept framework-agnostic.
Observability Left for Later#
Launching without tracing or monitoring means production issues surface as user complaints, with no way to debug what actually happened, until LangSmith or an equivalent gets wired in from the start.
Agent Autonomy Without Guardrails#
Trusting an agent to “figure it out” without controls lets the tool-calling loop run until the budget or the user’s patience gives out. Max iterations, timeouts, and cost budgets belong in required configuration, not optional tuning.
Where This Default Holds#
This covers most LangChain deployments: RAG services, internal assistants, and agent workflows with a handful of tools. The price of the discipline is a few dozen lines of configuration and one observability dependency, paid once.
Override it in two directions. Below the line, a single-prompt service with stable requirements does not need the framework at all; the provider SDK plus a cache is less code to write and less code to debug. Above the line, multi-agent systems with long-running state outgrow AgentExecutor well before they outgrow LangChain itself, and that is the moment to move orchestration into LangGraph while keeping LCEL chains for the LLM calls.
References#
- LangChain Documentation (opens in new tab) - Official LangChain overview covering chains, agents, memory, and retrieval abstractions
- LangSmith Observability (opens in new tab) - Official guide to tracing, monitoring, and evaluating LangChain applications in production
- LangGraph Overview (opens in new tab) - The orchestration framework behind durable execution, persistence, and state management for long-running agents
- GitHub - langchain-ai/langchain (opens in new tab) - Main LangChain repository with source, examples, and community integrations
- LangChain Python API Reference (opens in new tab) - Full API reference for LangChain Python classes, callbacks, and LCEL expressions
- LangChain Models (opens in new tab) - Model initialization, timeouts, retries, token limits, and structured output settings
Related posts
A technical guide to production-grade prompt engineering: systematic design, security, observability, and cost optimization for enterprise LLM apps.
prompt-engineering · llm · ai-tools +6
When a coding agent underperforms, the reflex is a stronger model. On bounded tasks the harness moves the score at least as much; a rule for which lever to pull.
ai-agents · ai-tools · llm +3
An implementation-focused glossary for developers navigating the AI/LLM landscape - from tokens to agents, RAG to fine-tuning, with code examples.
llm · ai-agents · rag +6
Prompt caching, model routing, token budgets, and semantic caching: how to keep production LLM spend predictable without giving up answer quality.
aws · cost-optimization · llm +3
Systematic profiling for PostgreSQL and MongoDB: how to find the queries driving latency and infrastructure cost, and which fixes actually move them.
data-storage-orm · postgresql · performance +4