Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Triage LangChain 1.0 / LangGraph 1.0 production incidents — LLM-specific SLOs, provider outage runbook, latency spike decision tree, cost-overrun response, agent loop containment. Use during an on-call page, in a post-mortem, or writing the team's first LLM runbook. Trigger with "langchain incident", "llm on-call", "langchain slo", "langchain outage", "langchain cost spike", "langchain agent loop".
.claude/skills/jeremylongshore-langchain-incident-runbook/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-22 | ✗→✓ | ▲ Improved | 157% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 79% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 27% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 184% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 190% | 0% |
3:07am. PagerDuty: "LangChain p95 latency > 10s for 5 minutes." You open LangSmith, filter by service="triage-agent" over the last 15 minutes, and the first trace is 43 seconds long — an agent is on step 24 of 25 iterations, bouncing between the same two tools on a vague user prompt ("help me with my account"). The cost dashboard shows $400 spent in the last 10 minutes, up from a $6/hour baseline. This is P10: create_react_agent defaults to recursion_limit=25 with no cost cap; vague prompts never converge; the spend hits before GraphRecursionError surfaces. First move is not to push a code fix — it is to flip recursion_limit=5 via config reload and add a middleware token-budget cap per session, then deal with the stuck sessions.
Or: same alert, different signature. p95 is healthy at 1.8s, but p99 is 12s and spiky. The spikes correlate with instance starts in Cloud Run. P36: Python + LangChain + embedding preloads = 5–15s cold start; Cloud Run scales to zero by default, so first-request p99 is 10x p95. First move is --min-instances=1 (or a keepalive pinger), not more CPU.
The shape of the page decides the first move. This runbook gives you:
latency <10s, error-rate <0.5%, cost-per-req <$0.05 — with Prometheus burn-rate recording rules that page on user-visible regression.
each with a 3-step diagnostic and first-response action.
.with_fallbacks(backup) so failover is aconfig flip, not a code change.
recursion_limit tuning and middlewaretoken-budget caps so runaway agents stop burning cost before the GraphRecursionError.
langchain-debug-bundle) and write-uptemplate.
Pinned: langchain-core 1.0.x, langgraph 1.0.x, langsmith 0.3+. Primary pain anchors: P10 (agent runaway), P36 (cold start). Adjacent: P29 (per-process rate limiter), P30 (max_retries=6 means 7 attempts), P31 (Anthropic cache RPM).
langchain-observability skill applied — metrics are grounded in what LangSmith callbacks emitbackup model factory from langchain-rate-limits — the failover playbook assumes .with_fallbacks() is already wiredHTTP-style SLOs miss what users actually feel. Define four, publish them, wire burn-rate alerts to the symptom.
| SLO | Threshold | Alert condition | First-response action | |---|---|---|---| | p95 TTFT (time to first streamed token) | <1s | burn-rate > 2% over 5min | Check streaming is enabled; check provider status; check cold start (P36) | | p99 total latency | <10s | burn-rate > 5% over 5min | Check agent loop depth (P10); cold start (P36); provider latency | | Error rate (5xx + uncaught exceptions) | <0.5% | burn-rate > 1% over 5min | Check provider 429/500; auth token; schema drift on structured output | | Cost per request | <$0.05 (tier-dependent) | p95 spend/req > $0.20 over 15min | Check agent recursion (P10); retry rate (P30); token-use per req |
Prometheus recording rule pattern for p99 latency burn-rate (replicate for TTFT, error-rate, and cost):
yamlgroups: - name: langchain_slo interval: 30s rules: - record: langchain:p99_latency_5m expr: histogram_quantile(0.99, sum(rate(langchain_request_duration_seconds_bucket[5m])) by (le, service)) - alert: LangChainP99LatencyBurn expr: langchain:p99_latency_5m > 10 for: 5m labels: { severity: page, team: llm } annotations: summary: "LangChain p99 > 10s for {{ $labels.service }}" runbook: "https://runbooks/langchain-incident-runbook#latency"
See LLM SLOs for the canonical set (free / paid / enterprise tiers), burn-rate recipes (fast + slow), and a TTFT-specific rule that requires streaming to be instrumented.
The alert name tells you the root path. Do not mix diagnostics across paths — the first-response action differs.
Alert fired
├── Latency (p95/p99 breach, TTFT breach)
│ ├── 1. Provider status page (Anthropic, OpenAI) green? → if red, Step 3
│ ├── 2. Cold start pattern? (p99 >> p95, correlates with instance starts) → P36
│ └── 3. Streaming configured? (TTFT only makes sense with .stream/.astream)
│
├── Cost (spend/req or absolute spend/hour breach)
│ ├── 1. Agent recursion depth? (LangSmith: max steps per trace) → P10
│ ├── 2. Retry rate elevated? (callback log: attempt count / logical call) → P30
│ └── 3. Token-use per req regression? (input + output tokens from callbacks)
│
└── Error rate (5xx + uncaught exceptions)
├── 1. Provider 429/500 spike? (distinguish client 4xx from provider 5xx)
├── 2. Auth? (API key rotation, expired token, org quota exhausted)
└── 3. Schema drift on structured output? (Pydantic ValidationError in traces)For each leaf, Latency Triage and Cost Overrun Response give the LangSmith filter query, the exact metric to inspect, and the remediation.
Detection precedes failover. Do not flip fallbacks on an application bug.
provider outage:
status.anthropic.com, status.openai.com) —poll every 30s, surface into Slack
trivial prompt, tracked as a separate SLO
a real outage from your app's bug)
CircuitBreaker middleware (seelangchain-middleware-patterns if available, or a simple aiobreaker-backed runnable) opens after N consecutive APIError / APITimeoutError within a window. Once open, calls skip the primary and go straight to the backup. This bounds the latency cost of a down provider.
.with_fallbacks(backup) — the fallback chain is alreadywired (see langchain-rate-limits). During an outage, either flip a feature flag that swaps the default factory, or temporarily set the primary's max_retries=0 so the chain reaches the fallback immediately.
feature X — monitoring upstream provider") and an internal Slack update with the canary graph attached. Provider Outage Playbook has the full comms template and the circuit-breaker middleware snippet.
P10 is the most common cost-spike cause. create_react_agent defaults to recursion_limit=25, meaning 25 model calls per user turn — with Claude Sonnet at ~$3/MTok input, a 10k-token tool-call loop burns real money per minute.
Three containment layers, applied in order:
recursion_limit per agent depth — interactive chat agents rarelyneed more than 5–8 steps; background research agents can justify 15; never leave the default 25 in production.
python from langgraph.prebuilt import create_react_agent
agent = create_react_agent( llm, tools, recursion_limit=8, # P10 — was default 25 )
cumulative input + output tokens for a session id and raises a custom BudgetExceeded exception once the cap is hit. The agent terminates cleanly; the user sees a polite "I could not finish this task in budget, try rephrasing" instead of a spinning UI until GraphRecursionError.
ENDwhen the same tool has been called with the same args twice in a row. This is a cheap heuristic for "the agent is stuck in a loop."
Cost Overrun Response has the middleware implementation, the repeat-tool edge pattern, and a per-tenant budget enforcement example.
Within 30 minutes of all-clear:
Prometheus dashboard screenshot at the breach window, the agent's config (recursion_limit, model id, max_retries), and the provider's status page state at incident time. Cross-reference langchain-debug-bundle if present.
all-clear), root cause in one sentence with pain-catalog anchor (e.g. "P10: recursion_limit=25 default, vague prompt, no token cap"), permanent fix ticket link, follow-up SLO tuning.
summary (one-paragraph timeline + link to write-up), schedule the post-mortem review in the next weekly SRE sync.
alerted via Prometheus burn-rate rules
cost / error-rate) and first-response actions per leaf
.with_fallbacks(backup)wired to a feature flag for one-flip failover
recursion_limit set per agent depth (never default 25 in prod); middlewaretoken-budget cap per session
on-call workflow
| Symptom | Likely cause | First-response action | |---|---|---| | p95 latency breach, TTFT degraded | Streaming disabled, or provider-side latency | Verify .stream()/.astream() used; check provider status page | | p99 >> p95, correlates with instance starts | Cloud Run cold start (P36) | --min-instances=1, CPU-always-allocated billing, preload imports | | Cost-per-req spike, agent traces show 20+ steps | recursion_limit=25 default + vague prompt (P10) | recursion_limit=5–8, add middleware token-budget cap | | Cost spike, callback log shows 7 attempts per logical call | max_retries=6 inflates cost 7x (P30) | max_retries=2 + circuit breaker; log retries via callbacks | | 429 storm despite requests_per_second=10 on each of N workers | InMemoryRateLimiter is per-process (P29) | Switch to RedisRateLimiter or provider-side quota | | Anthropic 429 while token budget has headroom | Cache RPM throttled separately (P31) | Client-side semaphore on RPM, not token count; monitor cached-read vs uncached separately | | Error-rate spike, all on primary provider | Provider outage | Canary probe confirms; flip failover to .with_fallbacks(backup) via flag | | ValidationError surge on structured output | Schema drift — model added fields | ConfigDict(extra="ignore") on the Pydantic schema (see langchain-sdk-patterns) | | Agent never terminates, no GraphRecursionError yet | Stuck in tool-call loop | Add "repeated tool call" edge routing to END; raise BudgetExceeded from middleware |
PagerDuty: "cost-per-req > $0.20 for 15 minutes." LangSmith filtered to the last 15 minutes shows average trace depth = 22 steps (baseline 4). Single tenant, single conversation pattern — a user who asked an open-ended question the agent cannot resolve. First-response action: flip recursion_limit=5 via config reload (no deploy), add session to the blocklist in middleware, post internal Slack with the trace URL.
See Cost Overrun Response for the middleware token-budget implementation and the per-tenant budget pattern.
p95 healthy at 1.8s, p99 at 12s, spikes correlate with Cloud Run instance starts — classic P36. First-response action: gcloud run services update <svc> --min-instances=1, verify heavy imports are at module top level, schedule follow-up ticket to move embedding preload to a warm-up hook.
See Latency Triage for the cold-start detection recipe and the p95-vs-p99 attribution decision tree.
Anthropic status page goes red. Canary probe error-rate jumps from 0% to 100% on Anthropic, stays at 0% on OpenAI. Flip the failover flag — the .with_fallbacks(backup=ChatOpenAI(...)) chain (already wired via langchain-rate-limits) takes over. Post user-facing status entry, monitor cost (OpenAI pricing differs — watch cost-per-req SLO), revert when upstream recovers.
See Provider Outage Playbook for the circuit-breaker middleware, the canary probe snippet, and the user-comms template.
create_react_agent and recursion_limitdocs/pain-catalog.md (primary: P10, P36; adjacent: P29, P30, P31)langchain-debug-bundle (post-incident capture), langchain-observability (SLO metrics source), langchain-rate-limits (.with_fallbacks chain), langchain-cost-tuning (token budget caps), langchain-deploy-integration (cold-start fix)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-15 | pass→pass | 12,629 | 10,669 | -16% | 1 | 1 | 0% | 1,228 | 4,926 | +301% | 0 | 0 | — |
case-16 | fail→fail | 32,165 | 21,409 | -33% | 1 | 1 | 0% | 3,754 | 7,803 | +108% | 0 | 0 | — |
case-22 | fail→pass | 16,692 | 16,278 | -2% | 1 | 1 | 0% | 2,664 | 6,835 | +157% | 0 | 0 | — |
case-01 | fail→fail | 44,957 | 29,777 | -34% | 1 | 1 | 0% | 6,644 | 8,420 | +27% | 0 | 0 | — |
case-02 | fail→pass | 20,195 | 16,681 | -17% | 1 | 1 | 0% | 4,013 | 7,176 | +79% | 0 | 0 | — |
case-03 | fail→pass | 38,135 | 20,954 | -45% | 1 | 1 | 0% | 6,077 | 7,731 | +27% | 0 | 0 | — |
case-04 | pass→pass | 27,729 | 35,942 | +30% | 1 | 1 | 0% | 3,963 | 9,857 | +149% | 0 | 0 | — |
case-05 | pass→pass | 22,726 | 25,620 | +13% | 1 | 1 | 0% | 3,152 | 7,636 | +142% | 0 | 0 | — |
case-06 | pass→pass | 25,555 | 20,252 | -21% | 1 | 1 | 0% | 3,846 | 7,907 | +106% | 0 | 0 | — |
case-07 | pass→pass | 15,728 | 13,099 | -17% | 1 | 1 | 0% | 2,486 | 6,137 | +147% | 0 | 0 | — |
case-08 | fail→pass | 12,824 | 17,725 | +38% | 1 | 1 | 0% | 2,112 | 6,008 | +184% | 0 | 0 | — |
case-09 | fail→pass | 15,804 | 17,763 | +12% | 1 | 1 | 0% | 2,137 | 6,196 | +190% | 0 | 0 | — |
case-10 | fail→pass | 31,064 | 40,284 | +30% | 1 | 1 | 0% | 2,724 | 6,061 | +123% | 0 | 0 | — |
case-11 | pass→pass | 17,905 | 13,421 | -25% | 1 | 1 | 0% | 1,829 | 5,185 | +183% | 0 | 0 | — |
case-12 | fail→fail | 21,946 | 25,467 | +16% | 1 | 1 | 0% | 2,963 | 7,083 | +139% | 0 | 0 | — |
case-13 | fail→pass | 16,867 | 7,879 | -53% | 1 | 1 | 0% | 1,944 | 5,415 | +179% | 0 | 0 | — |
case-14 | fail→pass | 18,917 | 19,067 | +1% | 1 | 1 | 0% | 2,357 | 6,929 | +194% | 0 | 0 | — |
case-17 | fail→pass | 11,520 | 4,380 | -62% | 1 | 1 | 0% | 1,860 | 4,784 | +157% | 0 | 0 | — |
case-18 | fail→fail | 20,124 | 19,750 | -2% | 1 | 1 | 0% | 2,332 | 6,209 | +166% | 0 | 0 | — |
case-19 | fail→pass | 24,683 | 13,945 | -44% | 1 | 1 | 0% | 2,621 | 6,194 | +136% | 0 | 0 | — |
case-20 | pass→pass | 18,213 | 16,271 | -11% | 1 | 1 | 0% | 3,075 | 6,860 | +123% | 0 | 0 | — |
case-21 | pass→pass | 26,931 | 15,706 | -42% | 1 | 1 | 0% | 3,912 | 5,924 | +51% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +45 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.