subtext_url and pasting a prompt, a triage agent does it on every flagged run.
What you need
- Your own LangChain/LangGraph agent, serving real end-users, already threading each end-user’s Subtext session URL into its trace metadata as
subtext_url(see the LangSmith integration — this is the load-bearing step; nosubtext_urlon the trace means no session to review later). - A LangSmith project with tracing enabled for that agent.
- A working Subtext MCP endpoint.
- The official
langsmith-mcp-serverMCP (see the LangSmith integration), or the LangSmith SDK if your triage agent’s runtime doesn’t support MCP. - Somewhere to run a webhook handler — a serverless function or a small backend service reachable from LangSmith.
- Wherever you want the finding to land — Slack, a ticket queue, an internal channel.
Set it up
1
Thread the end-user session into trace metadata
Attach
subtext_url under metadata on the root run for every request your agent serves (covered in the LangSmith integration). Get this in place before anything else — it’s the one step everything downstream depends on.2
(Optional) score runs with an online evaluator
If you want a quality signal beyond errors and explicit end-user feedback, add a LangSmith online evaluator — an LLM-as-judge run against each new trace — that writes a feedback key, e.g.
review_quality, scoring whether the agent’s output actually looks right. Richer signal than error/thumbs-down alone, at the cost of a model call per traced run. Skip it for a first pass if error + thumbs-down is enough.3
Create a LangSmith Automation
In your LangSmith tracing project, click + New in the top right, then New Automation. (Existing rules and their logs live under the project’s Automations tab.)Filter — an FQL query over the condition you care about, e.g.:If you added an evaluator in Step 2, add
has(feedback_key, "review_quality") so the rule waits for the score to land before firing — LangSmith’s docs call out this evaluator/webhook race explicitly; without the wait, the Automation can fire before the async evaluator finishes.Sampling rate — 1.0 to review every matching run; lower it if flagged-run volume is high and you’d rather triage a sample.Action — Webhook, pointed at your handler’s URL. Add a ?secret= query param (or an encrypted custom header) and verify it in the handler before doing anything else — fail closed.4
Stand up the webhook handler
The one hard constraint: LangSmith’s webhook contract requires your endpoint to respond within 5 seconds, or delivery is declared failed (5xx retries twice with backoff; 4xx doesn’t retry; the response body is ignored). A real Subtext review takes 30–60s+, so the handler cannot review inline — acknowledge fast, then do the work asynchronously.The payload LangSmith POSTs:Run dicts in the payload are lightweight — fetch the full run by id via the SDK or Two ways to run the triage agent itself:
langsmith-mcp-server if you need metadata reliably.Handler shape (any runtime that supports “ack now, keep working”):- As a background LangGraph run (LangChain-native) — if your triage agent is itself a LangGraph deployment, start a non-streamed/blocking run from the handler (a
.../runs/waitcall or the SDK equivalent) and read its final output. Keeps the triage agent on the same platform as the agent being reviewed. - As a serverless background job (portable) — a plain agent loop in the handler’s own runtime that holds both MCP connectors directly. No LangGraph dependency; the simpler option if the agent you’re reviewing isn’t itself LangGraph-based.
langsmith-mcp-server (fetch_runs(trace_id=...) — what your agent actually did) and the Subtext MCP (review-open(session_url=subtext_url) — what the end-user actually experienced). It reasons over both and decides: did the agent produce a bad result, or did the end-user hit friction the agent had nothing to do with? That’s the finding worth posting.On-demand vs. cron
Recommended: on-demand, via the webhook above. Timely — the team hears about a bad run in the same window it happened — no polling, and it’s what LangSmith Automations support natively. Fallback: daily cron. A scheduled job that queries LangSmith once a day for flagged traces in the last 24h (list_runs(filter=...), the same filter as the Automation) and batch-reviews them, for teams that would rather get one daily digest than a notification per run. Same triage-agent shape, just invoked on a schedule instead of a webhook.
Test it
1
Force a flagged run
Throw an error in your agent, or manually log a bad feedback score on a real run via the SDK.
2
Confirm the Automation fires
Check its run history in the LangSmith UI, and confirm your webhook receives the POST within the 5s window.
3
Confirm the async review actually ran
Check your handler’s logs for the
fetch_runs / review-open tool calls, and confirm the finding landed in Slack (or your target destination).Related
- LangSmith integration — attach
subtext_urlto your traces and add thelangsmith-mcp-server. - Session Review overview — what your triage agent does once a session is open.

