LangSmith SDK

repository·main·Indexed 21 days ago

https://github.com/langchain-ai/langsmith-sdk

Client libraries for Python and JavaScript/TypeScript to connect to the LangSmith Observability and Evaluation Platform. The SDK enables developers to debug, evaluate, and monitor LLM applications and intelligent agents through features like tracing with wrapOpenAI and traceable, manual trace tracking via RunTree, and the creation of datasets from existing runs. It also includes a SandboxClient for running code in isolated containers with support for AWS and GCP auth proxies.

Tokens
75K
Snippets
237
Records
310
Agent score
76%

What's inside langsmith-sdk

  1. Use Sandbox Mounts for filesystem access

    main

    LangSmith sandboxes can access external data (like S3, GCS, or Git repositories) using mount_config.

    • S3 Mounts: Require AWS authentication via aws_auth within the mount_config.auth list.
    • GCS Mounts: Require GCP authentication via gcp_auth within the mount_config.auth list.
    • Git Mounts: Public Git repositories can be mounted using git_mount without explicit AWS/GCP auth. For private repositories, use proxy_config rules.

    Note: Explicit AWS/GCP proxy auth rules in proxy_config will conflict with mount_config auth for the same provider.

    # Example: S3 Mount
    from langsmith.sandbox import (
        aws_auth,
        mount_config,
        s3_mount,
        workspace_secret,
    )
    
    mount_cfg = mount_config(
        auth=[
            aws_auth(
                access_key_id=workspace_secret("SANDBOX_AWS_ACCESS_KEY_ID"),
                secret_access_key=workspace_secret("SANDBOX_AWS_SECRET_ACCESS_KEY"),
            )
        ],
        mounts=[
            s3_mount(
                id="customer_data",
                mount_path="/mnt/mounts/customer-data",
                bucket="example-bucket",
                prefix="datasets/customer-data",
                region="us-east-1",
                endpoint_url="https://s3.amazonaws.com",
                path_style=False,
                read_only=False,
            )
        ],
    )
    
    # Example: Git Mount
    from langsmith.sandbox import git_mount, mount_config
    
    mount_cfg_git = mount_config(
        mounts=[
            git_mount(
                id="repo",
                mount_path="/mnt/repo",
                remote_url="https://github.com/langchain-ai/langsmith-sdk.git",
                ref={"type": "branch", "name": "main"},
                refresh_interval_seconds=60,
            )
        ],
    )
  2. Manually log traces using RunTree

    main

    For fine-grained control, you can use the RunTree class to manually manage the hierarchy of traces. A RunTree represents a single run and can have child runs (e.g., a chain calling an LLM, which then calls a tool).

    Key attributes for a RunTree:

    • name (str): Identifier for the component.
    • run_type (str): Currently supports "llm", "chain", or "tool".
    • inputs (dict): The inputs to the component.
    • outputs (Optional[dict]): The returned values.
    • error (Optional[str]): Error messages if the run failed.

    Workflow:

    1. Initialize RunTree with name and run_type.
    2. Call .post() to start the run.
    3. Use .create_child(...) to nest runs.
    4. Call .end(outputs=...) or .end(error=...) to finish a run.
    5. Call .patch() to sync changes to the server.
    from langsmith.run_trees import RunTree
    
    parent_run = RunTree(
        name="My Chat Bot",
        run_type="chain",
        inputs={"text": "Summarize this morning's meetings."},
    )
    parent_run.post()
    
    child_llm_run = parent_run.create_child(
        name="My Proprietary LLM",
        run_type="llm",
        inputs={"prompts": ["Summarize..."],
    }
    child_llm_run.post()
    child_llm_run.end(outputs={"generations": ["..."],})
    child_llm_run.patch()
    
    parent_run.end(outputs={"output": ["Summary text"]})
    parent_run.patch()
  3. Reconnect to a command

    main

    CommandHandle automatically reconnects on transient network issues. For manual reconnection (e.g., in a different process), use sb.reconnect(command_id) with the ID from the original handle.

    with client.sandbox(snapshot_id=snapshot_id) as sb:
        handle = sb.run("make build", timeout=600, wait=False)
        command_id = handle.command_id
    
        # ... later, possibly in a different process ...
    
        handle = sb.reconnect(command_id)
        for chunk in handle:
            print(chunk.data, end="")
        result = handle.result
  4. Manage LangSmith Sandbox command lifecycles

    main

    The sandbox daemon manages command sessions using two timeout mechanisms:

    1. Session TTL (finished commands): After a command exits, its session remains in memory for a TTL period, allowing you to reconnect() to retrieve output. Once the TTL expires, reconnect() throws a LangSmithSandboxOperationError.

    2. Idle Timeout (running commands): Running commands with no connected clients are killed after an idle timeout (default: 5 minutes). The timer resets whenever a client connects.

    Lifecycle Configuration Options:

    • idleTimeout: Seconds before an idle command is killed. Set to -1 for no idle timeout.
    • ttlSeconds: Seconds to keep a finished session in memory. Set to -1 for infinite TTL.
    • timeout: Maximum execution time for the command (0 for no timeout).
    • killOnDisconnect: If true, the command is killed immediately when the last client disconnects.
    // Example: Long-running task with specific lifecycle settings
    const sandbox = await client.createSandbox(snapshot.id);
    try {
      const handle = await sandbox.run("python train.py", {
        timeout: 0,              // No command timeout
        idleTimeout: 1800,       // Kill after 30min with no clients
        ttlSeconds: 3600,        // Keep session for 1 hour after exit
        wait: false,
      });
    
      // Example: Fire-and-forget background job
      const bg = await sandbox.run("python background_job.py", {
        timeout: 0,
        idleTimeout: -1,         // Never kill due to idle
        ttlSeconds: -1,          // Keep session forever
        wait: false,
      });
    } finally {
      await sandbox.delete();
    }
  5. Understand Sandbox lifetime and retention (TTL)

    main

    Sandboxes use a two-stage retention model based on activity and state. There is no hard wall-clock maximum lifetime.

    1. idle_ttl_seconds (Idle Timeout): The launcher stops the sandbox after this many seconds of inactivity. Any command execution or file I/O resets this timer. Default is 600 (10 mins). Set to 0 to disable auto-stop.
    2. delete_after_stop_seconds (Stop-anchored Deletion): Once a sandbox is stopped (via idle timeout or explicit stop), this timer starts. After the deadline, the sandbox and its filesystem are permanently deleted. Default is typically 14 days. Set to 0 to disable auto-deletion.

    Lifecycle: running $\rightarrow$ (idle for idle_ttl_seconds) $\rightarrow$ stopped $\rightarrow$ (wait delete_after_stop_seconds) $\rightarrow$ deleted.

    # Aggressive: stop after 5 min idle, delete 1 hour after stop
    sb = client.create_sandbox(
        snapshot_id=snapshot_id,
        idle_ttl_seconds=300,
        delete_after_stop_seconds=3600,
    )
    
    # Long-running: never auto-stop, delete 7 days after manual stop
    sb = client.create_sandbox(
        snapshot_id=snapshot_id,
        idle_ttl_seconds=0,
        delete_after_stop_seconds=604800,
    )
  6. How RunTree works for manual trace tracking

    main

    A RunTree allows you to manually track the lifecycle of your application's execution. It is useful for building complex, nested trace structures that don't follow a simple function-wrapping pattern.

    Key lifecycle methods:

    • new RunTree(config): Initializes a parent run.
    • .postRun(): Sends the initial run data to LangSmith.
    • .createChild(config): Creates a nested run under the current tree.
    • .end(options): Finalizes a run with outputs or errors.
    • .patchRun(): Updates an existing run (e.g., to add error info or final outputs).
    import { RunTree, RunTreeConfig } from "langsmith";
    
    const parentRunConfig: RunTreeConfig = {
      name: "My Chat Bot",
      run_type: "chain",
      inputs: { text: "Summarize this morning's meetings." },
    };
    
    const parentRun = new RunTree(parentRunConfig);
    await parentRun.postRun();
    
    const childLlmRun = await parentRun.createChild({
      name: "My Proprietary LLM",
      run_type: "llm",
      inputs: { prompts: ["Summarize...", "... "] },
    });
    
    await childLlmRun.postRun();
    await childLlmRun.end({
      outputs: { generations: ["...result..."] },
    });
    await childLlmRun.patchRun();
    
    await parentRun.end({ outputs: { output: ["Final result"] } });
  7. Configure GCP Auth Proxy for Sandbox

    main

    Use the GCP auth proxy to allow sandbox code to call Google APIs. The proxy injects OAuth bearer tokens for Google API hosts automatically. You must store your service account JSON as a LangSmith workspace secret.

    Note: Use opaque_secret() for short-lived service account JSON; plaintext JSON is not accepted directly.

    from langsmith.sandbox import (
        SandboxClient,
        gcp_auth,
        proxy_config,
        workspace_secret,
    )
    
    client = SandboxClient()
    auth_config = proxy_config(
        rules=[
            gcp_auth(
                service_account_json=workspace_secret(
                    "SANDBOX_GCP_SERVICE_ACCOUNT_JSON"
                ),
                scopes=["https://www.googleapis.com/auth/devstorage.read_write"],
            )
        ],
    )
    
    with client.sandbox(
        name="gcp-sandbox",
        proxy_config=auth_config,
    ) as sb:
        result = sb.run("python your_gcp_script.py")
        print(result.stdout)
  8. Configure AWS Auth Proxy for Sandbox

    main

    Use the AWS auth proxy to allow sandbox code to call AWS services (like S3 or Bedrock) without exposing real credentials. The proxy signs outbound requests with SigV4 using credentials stored as LangSmith workspace secrets.

    Important: Do not put plaintext AWS credentials in sandbox environment variables. If you are passing short-lived credentials, wrap them in opaque_secret().

    from langsmith.sandbox import (
        SandboxClient,
        aws_auth,
        proxy_config,
        workspace_secret,
    )
    
    client = SandboxClient()
    auth_config = proxy_config(
        rules=[
            aws_auth(
                access_key_id=workspace_secret("SANDBOX_AWS_ACCESS_KEY_ID"),
                secret_access_key=workspace_secret("SANDBOX_AWS_SECRET_ACCESS_KEY"),
            )
        ],
    )
    
    with client.sandbox(
        name="aws-sandbox",
        proxy_config=auth_config,
    ) as sb:
        result = sb.run("python your_aws_script.py")
        print(result.stdout)
  9. Quick Start with the Python SDK

    main

    To begin tracing your Python applications with LangSmith, install the langsmith package and configure the required environment variables. You can then use the wrap_openai wrapper to automatically trace OpenAI calls.

    pip install -U langsmith
    export LANGSMITH_TRACING=true
    export LANGSMITH_API_KEY=ls_...
    export LANGSMITH_WORKSPACE_ID=<your-workspace-id> # Required for org-scoped keys
    import openai
    from langsmith import traceable
    from langsmith.wrappers import wrap_openai
    
    client = wrap_openai(openai.Client())
    
    client.chat.completions.create(
        messages=[{"role": "user", "content": "Hello, world"}],
        model="gpt-3.5-turbo"
    )
  10. Log Traces with LangChain

    main

    LangSmith integrates seamlessly with the JavaScript LangChain library. If the required environment variables are set, LangChain will automatically record traces to LangSmith.

    1. Install LangChain: pnpm add langchain.
    2. Set the environment variables (see Connect to LangSmith via Environment Variables).
    3. Run your LangChain code normally.
    import { ChatOpenAI } from "langchain/chat_models/openai";
    
    const chat = new ChatOpenAI({ temperature: 0 });
    const response = await chat.predict(
      "Translate this sentence from English to French. I love programming."
    );
    console.log(response);
  11. Create a Dataset from existing runs

    main

    You can programmatically convert existing traces in LangSmith into a dataset using the Client. This is useful for evaluation workflows.

    1. Use client.listRuns to fetch specific runs (e.g., by project name or filtering for successful runs).
    2. Use client.createDataset to initialize a new dataset.
    3. Iterate through the runs and use client.createExample to add the run's inputs and outputs to the dataset.
    import { Client } from "langsmith/client";
    
    const client = new Client();
    const datasetName = "Example Dataset";
    
    // Fetch runs from a project
    const runs = await client.listRuns({
      projectName: "my_project",
      executionOrder: 1,
      error: false,
    });
    
    // Create the dataset
    const dataset = await client.createDataset(datasetName, {
      description: "An example dataset",
    });
    
    // Convert runs to examples
    for (const run of runs) {
      await client.createExample(run.inputs, run.outputs ?? {}, {
        datasetId: dataset.id,
      });
    }