or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced.mdannotation-queues.mdanonymizer.mdclient-api.mddatasets.mdevaluation.mdfeedback.mdgetting-started.mdindex.mdjest.mdlangchain.mdopentelemetry.mdprompts.mdrun-trees.mdschemas.mdtesting.mdtracing.mdvercel.mdvitest.mdworkflows.mdwrappers.md
tile.json

tracing.mddocs/

Tracing and Observability

Comprehensive tracing capabilities for LLM applications, from simple function decorators to manual run tree construction and distributed tracing across services.

Overview

LangSmith tracing captures execution details of your LLM applications, enabling debugging, performance monitoring, and quality analysis. Traces are organized hierarchically, allowing you to see the complete execution flow from high-level operations down to individual LLM calls.

When to use tracing:

  • Debug LLM application behavior and outputs
  • Monitor performance and token usage
  • Understand execution flow in complex chains
  • Track errors and exceptions
  • Analyze production behavior

Core Imports

import { traceable, getCurrentRunTree, withRunTree, isTraceableFunction, ROOT } from "langsmith/traceable";
import { RunTree } from "langsmith";

Quick Start

Basic Tracing with Decorator

The traceable() decorator is the simplest way to add tracing:

import { traceable } from "langsmith/traceable";

const myFunction = traceable(
  async (input: string) => {
    return `Processed: ${input}`;
  },
  { name: "my-function", run_type: "chain" }
);

await myFunction("test"); // Automatically traced

Traceable Decorator

Wrap any function with automatic tracing to LangSmith.

/**
 * Wrap a function with automatic tracing
 * @param wrappedFunc - Function to wrap
 * @param config - Tracing configuration
 * @returns Traceable function with added methods
 */
function traceable<Func>(
  wrappedFunc: Func,
  config?: TraceableConfig<Func>
): TraceableFunction<Func>;

interface TraceableConfig<Func> {
  /** Run name override (defaults to function name) */
  name?: string;
  /** Run type: "llm" | "chain" | "tool" | "retriever" | "embedding" | "prompt" | "parser" */
  run_type?: string;
  /** Additional metadata */
  metadata?: KVMap;
  /** Tags for filtering */
  tags?: string[];
  /** Custom client instance */
  client?: Client;
  /** Project name override */
  project_name?: string;
  /** Aggregator function for reducing batched inputs */
  aggregator?: (args: any[]) => any;
  /** Path to extract config from arguments: [argIndex] or [argIndex, propertyName] */
  argsConfigPath?: [number] | [number, string];
  /** Extract attachments from arguments */
  extractAttachments?: (...args: any[]) => [Attachments?, KVMap];
  /** Extract LLM invocation parameters */
  getInvocationParams?: (...args: any[]) => InvocationParamsSchema?;
  /** Transform inputs before logging */
  processInputs?: (inputs: any) => KVMap;
  /** Transform outputs before logging */
  processOutputs?: (outputs: any) => KVMap;
}

type TraceableFunction<Func> = Func;

type KVMap = Record<string, any>;

interface InvocationParamsSchema {
  ls_provider?: string;
  ls_model_name?: string;
  ls_model_type?: "chat" | "llm";
  ls_temperature?: number;
  ls_max_tokens?: number;
  ls_stop?: string[];
  [key: string]: any;
}

type Attachments = Record<string, AttachmentData>;

interface AttachmentData {
  mime_type: string;
  data: string | Uint8Array;
}

Usage Examples

import { traceable } from "langsmith/traceable";

// Basic tracing
const myFunction = traceable(
  async (input: string) => {
    return `Processed: ${input}`;
  },
  { name: "my-function", run_type: "chain" }
);

// Trace with metadata and tags
const pipeline = traceable(
  async (query: string, context: string[]) => {
    // Your logic
    return result;
  },
  {
    name: "rag-pipeline",
    run_type: "chain",
    metadata: { version: "1.0" },
    tags: ["production", "rag"],
  }
);

// Transform inputs/outputs before logging
const sanitized = traceable(
  async (apiKey: string, data: any) => {
    return await callAPI(apiKey, data);
  },
  {
    name: "api-call",
    processInputs: (inputs) => ({ data: inputs.data }), // Hide API key
    processOutputs: (outputs) => ({ success: true }), // Hide sensitive response
  }
);

// Nested tracing (automatic)
const parent = traceable(async (input: string) => {
  const step1 = await child1(input);
  const step2 = await child2(step1);
  return step2;
}, { name: "parent" });

const child1 = traceable(async (x: string) => x.toUpperCase(), { name: "child1" });
const child2 = traceable(async (x: string) => x + "!", { name: "child2" });

// Create traceable functions with different configurations
const withTags = traceable(async (x: string) => x, { name: "base", tags: ["experiment"] });
await withTags("test");

Run Tree Context

Access and manipulate the current run tree from within traced functions.

Get Current Run Tree

Access the current run tree from async context.

/**
 * Get the current run tree from async context
 * @returns Current RunTree instance
 * @throws Error if no run tree is active
 */
function getCurrentRunTree(): RunTree;

/**
 * Get the current run tree from async context (optional)
 * @param permitAbsentRunTree - If true, returns undefined instead of throwing
 * @returns Current RunTree instance or undefined
 */
function getCurrentRunTree(permitAbsentRunTree: true): RunTree | undefined;

Usage Examples:

import { traceable, getCurrentRunTree } from "langsmith/traceable";

const myFunction = traceable(async (input: string) => {
  // Access current run tree
  const runTree = getCurrentRunTree();

  // Add metadata dynamically
  runTree.metadata = { ...runTree.metadata, processed: true };

  // Create child run manually
  const childRun = runTree.createChild({
    name: "sub-operation",
    run_type: "tool",
  });

  return result;
});

// Optional access (returns undefined if not in traced context)
function helperFunction() {
  const runTree = getCurrentRunTree(true);
  if (runTree) {
    runTree.metadata = { helper: true };
  }
}

Execute With Run Tree Context

Execute a function with a specific run tree as context.

/**
 * Execute function with run tree context
 * @param runTree - Run tree to set as context
 * @param fn - Function to execute
 * @returns Result of function execution
 */
function withRunTree<T>(runTree: RunTree, fn: (...args: any[]) => T): T;

Usage Examples:

import { withRunTree } from "langsmith/traceable";
import { RunTree } from "langsmith";

const runTree = new RunTree({
  name: "custom-run",
  run_type: "chain",
});

// Execute with context
const result = await withRunTree(runTree, async () => {
  // getCurrentRunTree() will return this runTree
  return await someOperation();
});

await runTree.end({ result });
await runTree.postRun();

Check If Traceable

Type guard to check if a function is traceable.

/**
 * Check if a function is traceable
 * @param x - Value to check
 * @returns True if the value is a traceable function
 */
function isTraceableFunction(x: any): boolean;

Usage Examples:

import { traceable, isTraceableFunction } from "langsmith/traceable";

const traced = traceable(async () => "result", { name: "traced" });
const normal = async () => "result";

console.log(isTraceableFunction(traced)); // true
console.log(isTraceableFunction(normal)); // false

// Use in conditional logic
if (isTraceableFunction(fn)) {
  await fn(); // fn is traceable, will be traced automatically
} else {
  await fn(); // fn is not traceable, will run normally
}

Root Symbol

Symbol representing the root run for distributed tracing.

const ROOT: unique symbol;

Usage Examples:

import { ROOT } from "langsmith/traceable";
import { RunTree } from "langsmith";

// Use ROOT to indicate a root run
const runTree = new RunTree({
  name: "root-operation",
  parent_run: ROOT, // Explicitly mark as root
});

Manual Run Trees

For fine-grained control over trace structure, use RunTree class directly.

RunTree Class

Create and manage hierarchical trace structures manually.

/**
 * Hierarchical run tree for manual tracing
 */
class RunTree {
  /** Unique run ID */
  id: string;
  /** Run name */
  name: string;
  /** Run type */
  run_type?: string;
  /** Project name */
  project_name?: string;
  /** Parent run */
  parent_run?: RunTree;
  /** Child runs */
  child_runs: RunTree[];
  /** Start timestamp (ms) */
  start_time: number;
  /** End timestamp (ms) */
  end_time?: number;
  /** Input data */
  inputs: KVMap;
  /** Output data */
  outputs?: KVMap;
  /** Error message if failed */
  error?: string;
  /** Metadata */
  metadata?: KVMap;
  /** Tags */
  tags?: string[];
  /** Dotted order for distributed tracing */
  dotted_order?: string;
  /** Trace ID */
  trace_id?: string;
  /** Client instance */
  client?: Client;
  /** Attachments */
  attachments?: Attachments;
  /** LLM invocation parameters */
  invocation_params?: InvocationParamsSchema;

  /**
   * Create new run tree
   * @param config - Run tree configuration
   */
  constructor(config: RunTreeConfig);

  /**
   * Create child run
   * @param config - Partial configuration (inherits from parent)
   * @returns Child RunTree instance
   */
  createChild(config: Partial<RunTreeConfig>): RunTree;

  /**
   * End the run
   * @param outputs - Output data
   * @param error - Error message if failed
   * @param endTime - End timestamp (defaults to Date.now())
   * @param metadata - Additional metadata to merge
   */
  end(
    outputs?: KVMap,
    error?: string,
    endTime?: number,
    metadata?: KVMap
  ): Promise<void>;

  /**
   * Post run to LangSmith API
   * @param excludeChildRuns - If true, only post this run (not children)
   */
  postRun(excludeChildRuns?: boolean): Promise<void>;

  /**
   * Update run via PATCH request
   */
  patchRun(): Promise<void>;

  /**
   * Convert to JSON representation
   */
  toJSON(): object;

  /**
   * Add event to run
   * @param event - Run event
   */
  addEvent(event: RunEvent): void;

  /**
   * Convert to headers for distributed tracing
   * @param headers - Existing headers to merge with
   * @returns Headers with trace context
   */
  toHeaders(headers?: Record<string, string>): Record<string, string>;

  /**
   * Create from LangChain runnable config
   * @param parentConfig - Parent runnable config
   * @param props - Additional run tree properties
   * @returns RunTree instance
   */
  static fromRunnableConfig(
    parentConfig: RunnableConfigLike,
    props: Partial<RunTreeConfig>
  ): RunTree;

  /**
   * Create from dotted order string
   * @param dottedOrder - Dotted order format string
   * @returns RunTree instance
   */
  static fromDottedOrder(dottedOrder: string): RunTree;

  /**
   * Create from trace headers
   * @param headers - HTTP headers containing trace context
   * @param inheritArgs - Additional configuration
   * @returns RunTree instance or undefined if headers don't contain trace context
   */
  static fromHeaders(
    headers: Record<string, string>,
    inheritArgs?: Partial<RunTreeConfig>
  ): RunTree | undefined;
}

interface RunTreeConfig {
  /** Run name (required) */
  name: string;
  /** Run type */
  run_type?: string;
  /** Run ID (auto-generated if not provided) */
  id?: string;
  /** Project name */
  project_name?: string;
  /** Parent run */
  parent_run?: RunTree | typeof ROOT;
  /** Parent run ID */
  parent_run_id?: string;
  /** Child runs */
  child_runs?: RunTree[];
  /** Client instance */
  client?: Client;
  /** Start timestamp in milliseconds or ISO string */
  start_time?: number | string;
  /** End timestamp in milliseconds or ISO string */
  end_time?: number | string;
  /** Extra metadata */
  extra?: KVMap;
  /** Metadata */
  metadata?: KVMap;
  /** Tags */
  tags?: string[];
  /** Error message */
  error?: string;
  /** Input data */
  inputs?: KVMap;
  /** Output data */
  outputs?: KVMap;
  /** Reference example ID for evaluation */
  reference_example_id?: string;
  /** Serialized representation */
  serialized?: object;
  /** Whether tracing is enabled for this run */
  tracingEnabled?: boolean;
  /** End callback */
  on_end?: (runTree: RunTree) => void;
  /** Execution order */
  execution_order?: number;
  /** Child execution order */
  child_execution_order?: number;
  /** Dotted order for distributed tracing */
  dotted_order?: string;
  /** Trace ID */
  trace_id?: string;
  /** Attachments */
  attachments?: Attachments;
  /** Replicas for distributed runs */
  replicas?: Replica[];
  /** Distributed parent ID */
  distributedParentId?: string;
}

type KVMap = Record<string, any>;

type Attachments = Record<string, AttachmentData>;

interface AttachmentData {
  mime_type: string;
  data: string | Uint8Array;
}

type Replica = ProjectReplica | WriteReplica;

type ProjectReplica = [string, KVMap | undefined];

interface WriteReplica {
  apiUrl?: string;
  apiKey?: string;
  workspaceId?: string;
  projectName?: string;
  updates?: KVMap | undefined;
  fromEnv?: boolean;
  reroot?: boolean;
}

Usage Examples:

import { RunTree } from "langsmith";

// Create root run
const parentRun = new RunTree({
  name: "parent-operation",
  run_type: "chain",
  inputs: { query: "What is AI?" },
});

// Create child runs
const llmRun = parentRun.createChild({
  name: "llm-call",
  run_type: "llm",
  inputs: { prompt: "What is AI?" },
});

await llmRun.end({ response: "AI is..." });
await llmRun.postRun();

// End parent run
await parentRun.end({ result: "Complete" });
await parentRun.postRun();

// With error handling
const errorRun = new RunTree({
  name: "failing-operation",
  run_type: "tool",
});

try {
  const result = await riskyOperation();
  await errorRun.end({ result });
} catch (error) {
  await errorRun.end(undefined, error.message);
}
await errorRun.postRun();

Run Events

Add timestamped events to runs for detailed logging.

interface RunEvent {
  /** Event name */
  name: string;
  /** Event timestamp in milliseconds */
  time: number;
  /** Event metadata */
  kwargs?: KVMap;
}

Usage Examples:

import { RunTree } from "langsmith";

const run = new RunTree({
  name: "complex-operation",
  run_type: "chain",
});

// Add events during execution
run.addEvent({
  name: "retrieval_started",
  time: Date.now(),
  kwargs: { query: "search term" },
});

const docs = await retrieveDocuments();

run.addEvent({
  name: "retrieval_completed",
  time: Date.now(),
  kwargs: { num_docs: docs.length },
});

await run.end({ result: docs });
await run.postRun();

Distributed Tracing

Propagate trace context across services using headers or dotted order.

Convert to Headers

Export trace context as HTTP headers for distributed tracing.

/**
 * Convert run tree to headers for distributed tracing
 * @param headers - Existing headers to merge with
 * @returns Headers with trace context
 */
runTree.toHeaders(headers?: Record<string, string>): Record<string, string>;

Create from Headers

Reconstruct run tree from distributed trace headers.

/**
 * Create from trace headers
 * @param headers - HTTP headers containing trace context
 * @param inheritArgs - Additional configuration
 * @returns RunTree instance or undefined if headers don't contain trace context
 */
static fromHeaders(
  headers: Record<string, string>,
  inheritArgs?: Partial<RunTreeConfig>
): RunTree | undefined;

Dotted Order Format

Convert epoch and run ID to dotted order format.

/**
 * Convert epoch and run ID to dotted order format
 * @param epoch - Epoch timestamp
 * @param runId - Run ID
 * @param executionOrder - Execution order (optional)
 * @returns Dotted order string
 */
function convertToDottedOrderFormat(
  epoch: number,
  runId: string,
  executionOrder?: number
): string;

Create from Dotted Order

Create run tree from dotted order string.

/**
 * Create from dotted order string
 * @param dottedOrder - Dotted order format string
 * @returns RunTree instance
 */
static fromDottedOrder(dottedOrder: string): RunTree;

Distributed Tracing Examples:

import { RunTree } from "langsmith";

// Service A: Create run and export headers
const runA = new RunTree({
  name: "service-a",
  run_type: "chain",
});

const headers = runA.toHeaders();
// Send headers to Service B

// Service B: Receive and continue trace
const runB = RunTree.fromHeaders(headers, {
  name: "service-b",
  run_type: "chain",
});

// Runs are now linked in the same trace
await runB.end({ result: "done" });
await runB.postRun();

// Alternative: Use dotted order
const dottedOrder = convertToDottedOrderFormat(
  Date.now(),
  runA.id,
  1
);

const runC = RunTree.fromDottedOrder(dottedOrder);

Context Management

Async Local Storage

LangSmith uses AsyncLocalStorage to maintain run tree context across async operations automatically.

const AsyncLocalStorageProviderSingleton: {
  getInstance(): AsyncLocalStorage<RunTree | typeof ROOT>;
};

The async context is managed automatically when using traceable(). Manual context management is rarely needed but available through withRunTree() and getCurrentRunTree().

Type Guards

Check if a value is a RunTree instance.

/**
 * Type guard for RunTree
 * @param x - Value to check
 * @returns True if value is a RunTree
 */
function isRunTree(x: any): x is RunTree;

Usage Examples:

import { isRunTree, RunTree } from "langsmith";

function logRun(run: any) {
  if (isRunTree(run)) {
    console.log(`Run: ${run.name} (${run.id})`);
  }
}

LangChain Integration

Create RunTree from LangChain runnable config.

/**
 * Type guard for LangChain runnable config
 * @param x - Value to check
 * @returns True if value is a runnable config
 */
function isRunnableConfigLike(x: any): x is RunnableConfigLike;

interface RunnableConfigLike {
  callbacks?: any;
  tags?: string[];
  metadata?: KVMap;
  run_name?: string;
  [key: string]: any;
}

Usage Examples:

import { RunTree } from "langsmith";

// From LangChain config
const langchainConfig = {
  callbacks: callbackManager,
  tags: ["langchain"],
  metadata: { version: "1.0" },
};

const runTree = RunTree.fromRunnableConfig(langchainConfig, {
  name: "my-chain",
  run_type: "chain",
});

Advanced Patterns

When to Use RunTree vs Traceable

  • Use traceable() for automatic tracing of functions (recommended for most cases)
  • Use RunTree for:
    • Fine-grained control over trace structure
    • Manual integration with non-function code
    • Distributed tracing across services
    • Custom event logging within runs

Nested Tracing Patterns

import { traceable } from "langsmith/traceable";

// Parent-child relationship (automatic)
const parent = traceable(async (input: string) => {
  const result1 = await child1(input);
  const result2 = await child2(result1);
  return result2;
}, { name: "parent-operation" });

const child1 = traceable(
  async (x: string) => x.toUpperCase(),
  { name: "uppercase", run_type: "tool" }
);

const child2 = traceable(
  async (x: string) => x + "!",
  { name: "add-exclamation", run_type: "tool" }
);

// Creates trace hierarchy automatically
await parent("hello");

Dynamic Metadata

Add metadata dynamically during execution:

import { traceable, getCurrentRunTree } from "langsmith/traceable";

const processWithMetadata = traceable(async (input: string) => {
  const runTree = getCurrentRunTree();

  // Add metadata as you go
  runTree.metadata = {
    ...runTree.metadata,
    startedAt: new Date().toISOString()
  };

  const result = await performProcessing(input);

  // Add more metadata
  runTree.metadata = {
    ...runTree.metadata,
    processedItems: result.count,
    completedAt: new Date().toISOString()
  };

  return result;
}, { name: "process-with-metadata" });

Error Handling with Traces

Errors are automatically captured, but you can add custom error handling:

import { traceable } from "langsmith/traceable";

const robustFunction = traceable(
  async (input: string) => {
    try {
      return await riskyOperation(input);
    } catch (error) {
      // Error is automatically logged in trace
      console.error("Operation failed:", error.message);

      // Can add custom error context
      throw new Error(`Failed to process "${input}": ${error.message}`);
    }
  },
  { name: "robust-function", run_type: "tool" }
);

Memory Management

Post runs as you complete them to avoid memory buildup:

import { RunTree } from "langsmith";

const parent = new RunTree({ name: "parent", run_type: "chain" });

for (let i = 0; i < 1000; i++) {
  const child = parent.createChild({ name: `child-${i}`, run_type: "tool" });
  await child.end({ result: i });
  await child.postRun(); // Post immediately to free memory
}

await parent.end();
await parent.postRun();

Conditional Tracing

Enable or disable tracing based on conditions:

import { traceable } from "langsmith/traceable";

const conditionalTrace = traceable(
  async (input: string) => {
    // Your logic
    return processInput(input);
  },
  {
    name: "conditional-trace",
    // Only trace in production
    client: process.env.NODE_ENV === "production" ? client : undefined
  }
);

Sampling

Trace only a percentage of requests:

import { Client } from "langsmith";

const client = new Client({
  // Trace 10% of requests
  tracingSamplingRate: 0.1
});

const sampledFunction = traceable(
  async (input: string) => {
    return process(input);
  },
  { name: "sampled-function", client }
);

Performance Optimization

Batching

LangSmith automatically batches trace uploads for performance:

import { Client } from "langsmith";

const client = new Client({
  autoBatchTracing: true,
  batchSizeBytesLimit: 20_000_000, // 20 MB
  traceBatchConcurrency: 5, // Concurrent uploads
});

Manual Flush

For serverless or short-lived processes:

import { Client } from "langsmith";

const client = new Client();

// Your traced operations
await myTracedFunction();

// Ensure all traces are uploaded before exit
await client.awaitPendingTraceBatches();

Blocking Mode

Block until root runs are finalized (useful for testing):

import { Client } from "langsmith";

const client = new Client({
  blockOnRootRunFinalization: true
});

Privacy and Security

Hide Inputs/Outputs

Redact sensitive data from traces:

import { Client } from "langsmith";

const client = new Client({
  hideInputs: true,  // Hide all inputs
  hideOutputs: false, // Show outputs
});

// Or use functions for selective hiding
const client = new Client({
  hideInputs: (inputs) => {
    // Remove sensitive fields
    const { apiKey, password, ...safe } = inputs;
    return safe;
  },
  hideOutputs: (outputs) => {
    // Redact PII
    return {
      ...outputs,
      email: "[REDACTED]"
    };
  }
});

Data Anonymization

Use anonymizer for pattern-based redaction:

import { traceable } from "langsmith/traceable";
import { createAnonymizer } from "langsmith/anonymizer";

const anonymizer = createAnonymizer([
  { pattern: /\b[\w\.-]+@[\w\.-]+\.\w+\b/g, replace: "[EMAIL]" },
  { pattern: /\bsk-[a-zA-Z0-9]{32,}\b/g, replace: "[API_KEY]" },
]);

const privateFunction = traceable(
  async (input: { email: string; query: string }) => {
    return await processQuery(input);
  },
  {
    name: "private-function",
    processInputs: anonymizer,
    processOutputs: anonymizer
  }
);

Types

interface RunTreeLike {
  id: string;
  name: string;
  run_type?: string;
  trace_id?: string;
  dotted_order?: string;
}

Best Practices

1. Use Descriptive Names

// Good
const summarizeDocument = traceable(fn, { name: "summarize-document" });
const extractEntities = traceable(fn, { name: "extract-entities" });

// Bad
const func1 = traceable(fn, { name: "func1" });
const process = traceable(fn, { name: "process" });

2. Choose Appropriate Run Types

// LLM calls
traceable(fn, { run_type: "llm" });

// Chains of operations
traceable(fn, { run_type: "chain" });

// Tool/function calls
traceable(fn, { run_type: "tool" });

// Document retrieval
traceable(fn, { run_type: "retriever" });

// Embedding generation
traceable(fn, { run_type: "embedding" });

3. Add Meaningful Metadata

const myFunction = traceable(
  async (input: string) => {
    return process(input);
  },
  {
    name: "my-function",
    metadata: {
      version: "2.1.0",
      environment: process.env.NODE_ENV,
      model: "gpt-4",
      temperature: 0.7
    },
    tags: ["production", "critical"]
  }
);

4. Always Flush in Serverless

// Lambda/serverless function
export const handler = async (event) => {
  const result = await myTracedFunction(event);

  // Ensure traces are uploaded before function ends
  await client.awaitPendingTraceBatches();

  return result;
};

5. Use Run Events for Milestones

import { RunTree } from "langsmith";

const run = new RunTree({ name: "pipeline", run_type: "chain" });

run.addEvent({ name: "started", time: Date.now() });

const step1 = await processStep1();
run.addEvent({ name: "step1_complete", time: Date.now(), kwargs: { items: step1.length } });

const step2 = await processStep2();
run.addEvent({ name: "step2_complete", time: Date.now(), kwargs: { items: step2.length } });

await run.end({ result: step2 });
await run.postRun();

Common Use Cases

RAG Application

import { traceable } from "langsmith/traceable";

const retrieveDocuments = traceable(
  async (query: string) => {
    const docs = await vectorDB.similaritySearch(query, 5);
    return docs;
  },
  { name: "retrieve-docs", run_type: "retriever" }
);

const generateAnswer = traceable(
  async (query: string, docs: string[]) => {
    const context = docs.join("\n");
    const answer = await llm.generate({ query, context });
    return answer;
  },
  { name: "generate-answer", run_type: "llm" }
);

const ragPipeline = traceable(
  async (query: string) => {
    const docs = await retrieveDocuments(query);
    const answer = await generateAnswer(query, docs);
    return answer;
  },
  { name: "rag-pipeline", run_type: "chain" }
);

// Creates hierarchical trace: pipeline > retrieve > generate
await ragPipeline("What is LangSmith?");

Multi-Step Agent

import { traceable, getCurrentRunTree } from "langsmith/traceable";

const planSteps = traceable(
  async (goal: string) => {
    return ["Step 1", "Step 2", "Step 3"];
  },
  { name: "plan-steps", run_type: "chain" }
);

const executeStep = traceable(
  async (step: string) => {
    return `Executed: ${step}`;
  },
  { name: "execute-step", run_type: "tool" }
);

const agent = traceable(
  async (goal: string) => {
    const runTree = getCurrentRunTree();

    // Plan
    const steps = await planSteps(goal);
    runTree.addEvent({
      name: "planning_complete",
      time: Date.now(),
      kwargs: { num_steps: steps.length }
    });

    // Execute
    const results = [];
    for (const step of steps) {
      const result = await executeStep(step);
      results.push(result);
    }

    return { goal, steps, results };
  },
  { name: "agent", run_type: "chain" }
);

await agent("Analyze data");

API Integration

import { traceable } from "langsmith/traceable";
import express from "express";

const app = express();

const processRequest = traceable(
  async (body: any) => {
    // Your processing logic
    return await handleRequest(body);
  },
  { name: "api-request", run_type: "chain" }
);

app.post("/api/process", async (req, res) => {
  try {
    const result = await processRequest(req.body);
    res.json(result);
  } catch (error) {
    // Error is captured in trace
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000);

Related Documentation

  • Client API - Full Client API reference
  • Evaluation - Evaluate traced runs
  • Datasets - Create datasets for testing
  • LangChain Integration - Integrate with LangChain
  • OpenTelemetry Integration - Standards-based distributed tracing
  • Data Anonymization - Protect sensitive data in traces
  • Annotation Queues - Human feedback workflows
  • Advanced Topics - Overview of advanced features