Sometimes, you need to trace a request across multiple services.LangSmith supports distributed tracing out of the box, linking runs within a trace across services using context propagation headers (langsmith-trace and optional baggage for metadata/tags).Example client-server setup:
Trace starts on client
Continues on server
Only accept distributed-tracing headers from trusted services. The langsmith-trace and baggage headers are consumed as trusted tracing context. Do not add TracingMiddleware (or pass inbound request headers as the tracing parent) on a service that receives requests directly from untrusted third parties or the public internet. Keep distributed tracing to internal, service-to-service calls, and strip these headers from untrusted inbound requests at your gateway or proxy. Trusting baggage from an external caller lets them influence how your runs are recorded.
# client.pyfrom langsmith.run_helpers import get_current_run_tree, traceableimport httpx@traceableasync def my_client_function(): headers = {} async with httpx.AsyncClient(base_url="...") as client: if run_tree := get_current_run_tree(): # add langsmith-id to headers headers.update(run_tree.to_headers()) return await client.post("/my-route", headers=headers)
Then the server (or other service) can continue the trace by handling the headers appropriately. If you are using an asgi app Starlette or FastAPI, you can connect the distributed trace using LangSmith’s TracingMiddleware.
The TracingMiddleware class was added in langsmith==0.1.133.
Example using FastAPI:
from langsmith import traceablefrom langsmith.middleware import TracingMiddlewarefrom fastapi import FastAPI, Requestapp = FastAPI() # Or Flask, Django, or any other frameworkapp.add_middleware(TracingMiddleware)@traceableasync def some_function(): ...@app.post("/my-route")async def fake_route(request: Request): return await some_function()
If you are using other server frameworks, you can always “receive” the distributed trace by passing the headers in through langsmith_extra:
# server.pyimport langsmith as lsfrom fastapi import FastAPI, Request@ls.traceableasync def my_application(): ...app = FastAPI() # Or Flask, Django, or any other framework@app.post("/my-route")async def fake_route(request: Request): # request.headers: {"langsmith-trace": "..."} # as well as optional metadata/tags in `baggage` with ls.tracing_context(parent=request.headers): return await my_application()
The example above uses the tracing_context context manager. You can also directly specify the parent run context in the langsmith_extra parameter of a method wrapped with @traceable.
# ... same as above@app.post("/my-route")async def fake_route(request: Request): # request.headers: {"langsmith-trace": "..."} my_application(langsmith_extra={"parent": request.headers})
Then, the server converts the headers back to a run tree, which it uses to further continue the tracing.To pass the newly created run tree to a traceable function, we can use the withRunTree helper, which will ensure the run tree is propagated within traceable invocations.
// server.mtsimport { RunTree } from "langsmith";import { traceable, withRunTree } from "langsmith/traceable";import express from "express";import bodyParser from "body-parser"; const server = traceable( (text: string) => `Hello from the server! Received "${text}"`, { name: "server" } ); const app = express(); app.use(bodyParser.text());app.post("/", async (req, res) => { const runTree = RunTree.fromHeaders(req.headers); const result = await withRunTree(runTree, () => server(req.body)); res.send(result);});
// server.mtsimport { RunTree } from "langsmith";import { traceable, withRunTree } from "langsmith/traceable";import { Hono } from "hono"; const server = traceable( (text: string) => `Hello from the server! Received "${text}"`, { name: "server" } ); const app = new Hono();app.post("/", async (c) => { const body = await c.req.text(); const runTree = RunTree.fromHeaders(c.req.raw.headers); const result = await withRunTree(runTree, () => server(body)); return c.body(result);});
Connect these docs to your agent of choice via MCP for real-time answers.