Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.langchain.com/llms.txt

Use this file to discover all available pages before exploring further.

This guide shows you how to deploy a Google Agent Development Kit (ADK) agent on LangSmith Agent Server using the deployments-wrap-sdk package. deployments-wrap-sdk provides a thin wrapper that turns a configured ADK Runner into a LangGraph-compatible graph, so you can deploy ADK agents without writing the Functional API glue yourself. The wrapper:

Prerequisites

Installation

Install the package with the google-adk extra. The extra pulls in google-adk and other dependencies needed for the wrapper:
pip install "deployments-wrap-sdk[google-adk]"
The PyPI distribution name is deployments-wrap-sdk, but the Python import path is saf_sdk. Both refer to the same package.

Quickstart

This minimal example builds an agent that returns the input as its response and does not require a model API key. The agent bypasses the LLM call so you can verify that the deployment works correctly before connecting a real model. Create agent.py:
agent.py
from google.adk.agents import Agent
from google.adk.models.llm_response import LlmResponse
from google.adk.runners import Runner
from google.genai.types import Content, Part
from saf_sdk.adk import LangsmithSessionService, wrap


def echo_callback(callback_context, llm_request):
    """Return the user's message instead of calling a real model."""
    user_text = ""
    if callback_context.user_content and callback_context.user_content.parts:
        for part in callback_context.user_content.parts:
            if part.text:
                user_text += part.text
    return LlmResponse(
        content=Content(role="model", parts=[Part(text=f"echo: {user_text}")])
    )


agent = wrap(
    Runner(
        agent=Agent(
            name="echo_agent",
            model="gemini-2.0-flash",
            instruction="Echo the user message.",
            before_model_callback=echo_callback,
        ),
        app_name="adk_echo",
        session_service=LangsmithSessionService(),
    )
)
Two things are essential:
  1. Pass LangsmithSessionService() as the runner’s session_service. wrap() raises a TypeError if you forget. Agent Server needs this hook to load and save ADK session state through its checkpointer.
  2. Export the wrapped agent as a module-level variable. Agent Server imports this symbol when serving the graph.
For a real agent, drop the before_model_callback and configure a model directly. For example, use Gemini by setting model="gemini-2.0-flash" with GOOGLE_API_KEY set, or use Claude/OpenAI via ADK’s LiteLLM adapter (google.adk.models.lite_llm.LiteLlm, available through google-adk[extensions]).

Project layout

A deployable project needs three files:
my-adk-agent/
├── agent.py              # exports the wrapped agent
├── langgraph.json        # Agent Server config
└── pyproject.toml        # Python dependencies
langgraph.json points Agent Server at the exported symbol:
langgraph.json
{
  "$schema": "https://langgra.ph/schema.json",
  "dependencies": ["."],
  "graphs": {
    "adk_echo": "./agent.py:agent"
  },
  "env": ".env"
}
pyproject.toml declares dependencies:
pyproject.toml
[project]
name = "my-adk-agent"
version = "0.0.1"
requires-python = ">=3.11"
dependencies = [
    "deployments-wrap-sdk[google-adk]>=0.0.1",
]

Install dependencies

pip install -e .

Run locally

Start the local Agent Server with the LangGraph CLI:
langgraph dev
This serves the agent at http://127.0.0.1:2024 and opens LangSmith Studio so you can chat with the agent. Send a request directly with curl:
# Create a thread
THREAD=$(curl -s -X POST http://127.0.0.1:2024/threads \
  -H "Content-Type: application/json" -d '{}' | python -c "import sys, json; print(json.load(sys.stdin)['thread_id'])")

# Run the agent and wait for the final response
curl -s -X POST "http://127.0.0.1:2024/threads/$THREAD/runs/wait" \
  -H "Content-Type: application/json" \
  -d '{
    "assistant_id": "adk_echo",
    "input": {"messages": [{"type": "human", "content": "Hello"}]}
  }'

Deploy to LangSmith

Once the agent runs locally, deploy it to LangSmith with langgraph deploy:
langgraph deploy --name my-adk-agent
For environment configuration, deployment types, and revision management, refer to Deploy to cloud. For self-hosted setups, refer to Self-hosted deployments.

Enable tracing

wrap() calls langsmith.integrations.google_adk.configure_google_adk() automatically whenever LangSmith tracing is enabled, so all you need to do is set the environment variables on the deployment:
.env
LANGSMITH_API_KEY=your-langsmith-api-key
LANGSMITH_TRACING=true
LANGSMITH_PROJECT=my-adk-agent     # optional
GOOGLE_API_KEY=your-google-api-key
Traces show agent invocations, tool calls, and LLM interactions in the LangSmith UI. For more on the underlying tracing integration, see Trace Google ADK applications.

API reference

wrap(runner)

Wraps a configured google.adk.runners.Runner and returns a LangGraph Pregel graph that can be exported from your module and served by Agent Server.
ArgumentTypeDescription
runnergoogle.adk.runners.RunnerA configured ADK Runner. Its session_service must be a LangsmithSessionService.
Returns: A Pregel graph whose name is runner.app_name. Raises: TypeError if runner.session_service is not a LangsmithSessionService. If runner.agent defines an output_key, that key’s value is also exposed on the graph’s output, in addition to messages. This is what makes ADK structured-output agents (output_schema=..., output_key=...) work with Studio and the /runs/wait response.

LangsmithSessionService

A google.adk.sessions.BaseSessionService implementation backed by Agent Server’s checkpoint store. The wrapper manages session lifecycle automatically. It creates a session on the first turn of a thread, loads it from the checkpoint on subsequent turns, and writes the updated session back when the run completes. Use a fresh instance per Runner:
session_service = LangsmithSessionService()
You should not need to call its methods directly; wrap() drives them through ADK’s normal session lifecycle.

ADKInput

The default input schema for a wrapped agent.
FieldTypeDescription
messageslist[AnyMessage](Required) Conversation messages; the wrapper sends messages[-1].content to the ADK runner as the new user message.
state_deltadict[str, Any] | None(Optional) Passed through to runner.run_async(state_delta=...) to mutate ADK session state for this turn.

ADKOutput

The default output schema for a wrapped agent.
FieldTypeDescription
messageslist[AnyMessage]The agent’s response messages, appended to the thread via LangGraph’s add_messages reducer.
Exposing messages as a typed field (rather than a plain dict) is what lets Studio detect the graph as chat-compatible and enable the chat-mode toggle.

How it works

When a run arrives:
  1. The wrapped graph reads thread_id from the run config and uses it as the ADK session_id. If authentication is enabled, the authenticated user’s id becomes the ADK user_id; otherwise the user id is "anonymous".
  2. The wrapper loads the previous session (if any) from the LangGraph checkpoint into LangsmithSessionService, then asks the runner to handle the latest message.
  3. The runner emits ADK events. The wrapper forwards partial-token events through LangGraph’s async callback manager so they stream out via stream_mode="messages", and collects final text for the response message.
  4. When the run finishes, the wrapper serializes the ADK session and saves it to the checkpoint via entrypoint.final(save=...). The next run on the same thread resumes from that state.
This means ADK’s own session/state semantics are preserved end-to-end while the deployment gets the standard Agent Server features: durable runs, streaming, multi-thread persistence, and tracing.