For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Sign inTry it free
DocsGuidesSDKsIntegrationsAPI docsTutorialsFlagship blog
DocsGuidesSDKsIntegrationsAPI docsTutorialsFlagship blog
  • Guides
    • Feature flags
    • AgentControl
      • Getting started with OpenAI and AgentControl
      • Getting started with Anthropic Claude and AgentControl
      • Getting started with Google Gemini and AgentControl
      • Getting started with Amazon Bedrock and AgentControl
      • Getting started with LangChain and AgentControl
      • Getting started with LangGraph and AgentControl
      • Getting started with Strands and AgentControl
      • Managing AI model configuration outside of code
      • Using targeting to manage AI model usage by tier
      • When to use prompt-based vs agent mode
      • Building a chatbot with multiple AI providers using AgentControl
    • Experimentation
    • Statistical methodology
    • Metrics
    • Infrastructure
    • Account management
    • Teams and custom roles
    • SDKs
    • Integrations
    • REST API
    • Additional resources
Sign inTry it free
LogoLogo
On this page
  • Overview
  • Prerequisites
  • Concepts
  • LangGraph agents
  • Agent mode AgentControl configs
  • The agent_config function
  • Step 1: Install dependencies
  • Step 2: Create an AgentControl config in LaunchDarkly
  • Step 3: Set up targeting rules
  • Step 4: Integrate LangGraph with AgentControl configs
  • Complete example
  • Step 5: Monitor results
  • Agent mode vs completion mode
  • Conclusion
GuidesAgentControl

Getting started with LangGraph and AgentControl configs

Was this page helpful?
Previous

Getting started with Strands and AgentControl configs

Next
Built with

Overview

This guide shows how to integrate LangGraph agent workflows with LaunchDarkly AgentControl. Using AgentControl configs with LangGraph lets you manage agent instructions, model configuration, and parameters outside of your application code.

This guide uses agent mode for LangGraph workflows. Agent mode uses a single instructions string rather than a messages array, which maps directly to LangGraph’s agent prompts. To learn more, read Agents.

New to AgentControl?

If you’re new to AgentControl, start with the Quickstart and return to this guide when you are ready for a LangGraph-specific example.

To learn more about AgentControl-specific SDKs, read AI SDKs. For Python-specific details, read the Python AI SDK reference.

Prerequisites

To complete this guide, you must have the following prerequisites:

  • A LaunchDarkly account, including:
    • A LaunchDarkly SDK key for your environment.
    • A member role that allows AgentControl actions. The LaunchDarkly project admin, maintainer, and developer project roles, as well as the admin and owner base roles, include this ability. To learn more about LaunchDarkly roles, read Roles.
  • A Python 3.10+ or Node.js 20+ development environment.
  • LangGraph installed in your application.
  • An API key for your chosen model provider (OpenAI, Anthropic, or another supported provider).

Concepts

Before you begin, review these key concepts.

LangGraph agents

LangGraph provides a framework for building agent workflows as directed graphs. The create_agent function (in langchain.agents; replaces the deprecated langgraph.prebuilt.create_react_agent in LangGraph 1.0+) creates a ReAct-style agent that can use tools and maintain state across conversation turns. Agents receive a system prompt that defines their behavior and capabilities.

Agent mode AgentControl configs

Agent mode AgentControl configs use an instructions field instead of a messages array. This single instruction string serves as the system prompt for your agent. Agent mode is ideal for:

  • Multi-step agent workflows
  • Tool-using agents
  • Persistent agent sessions

The agent_config function

The agent_config function retrieves the AgentControl config variation for a given context. It returns an AIAgentConfig object that includes the customized instructions, model configuration, and a create_tracker() (Python) or createTracker() (Node.js) factory method that returns a tracker for recording metrics. Call agent_config each time you create an agent so LaunchDarkly can evaluate targeting and return the current configuration.

Step 1: Install dependencies

Install the LaunchDarkly SDKs and LangGraph packages.

$pip install "launchdarkly-server-sdk-ai>=0.20.0" "launchdarkly-server-sdk-ai-langchain>=0.7.0" langgraph langchain langchain-core python-dotenv

Install the LangChain provider package for your model. Common provider packages include:

  • langchain-openai for OpenAI models
  • langchain-anthropic for Anthropic models
  • langchain-google-genai for Google Gemini models

Step 2: Create an AgentControl config in LaunchDarkly

Create an AgentControl config in agent mode to store your agent configuration.

To create an AgentControl config:

  1. In the left navigation, click Create and select AgentControl config.
  2. In the “Create AgentControl config” dialog, select Agent.
  3. Enter a name for your AgentControl config, for example, “LangGraph Agent.”
  4. Click Create.

Then, create a variation:

  1. On the Variations tab, replace “Untitled variation” with a variation name, such as “GPT-4o Agent”.
  2. Click Select a model and choose the gpt-4o OpenAI model.
  3. Click Parameters and set temperature to 0.7 and max_tokens to 2000.
  4. In the Instructions field, enter your agent’s system prompt:
You are a helpful assistant that can perform calculations and check weather. Use the available tools to provide accurate information. Always explain your reasoning step by step.
  1. Click Review and save.

A completed variation with model configuration and instructions.

A completed variation with model configuration and instructions.

Step 3: Set up targeting rules

Configure targeting rules to control which users receive the AgentControl config variation.

To set up the default rule:

  1. Select the Targeting tab for your AgentControl config.
  2. In the “Default rule” section, click Edit.
  3. Configure the default rule to serve your variation, such as “GPT-4o Agent”.
  4. Click Review and save.

The default targeting rule configured to serve a variation.

The default targeting rule configured to serve a variation.

The AgentControl config is enabled by default. After you add the integration code to your application, LaunchDarkly serves the configured variation to your users.

Step 4: Integrate LangGraph with AgentControl configs

The integration involves these key steps:

  1. Define the tools your agent can call.
  2. Initialize the LaunchDarkly SDK and AI client.
  3. Get the agent config using agent_config() (Python) or aiClient.agentConfig() (Node.js).
  4. Build a LangChain model from the AgentControl config using the LaunchDarkly LangChain provider.
  5. Create a LangGraph ReAct agent with a MemorySaver checkpointer.
  6. Invoke the agent and track metrics with the config’s tracker.

Define the agent’s tools.

1from langchain_core.tools import tool
2
3
4@tool
5def get_order_status(order_id: str) -> str:
6 """Look up the status of a customer order by order ID."""
7 orders = {
8 "ORD-123": "Shipped — arrives Thursday",
9 "ORD-456": "Processing — estimated ship date: tomorrow",
10 "ORD-789": "Delivered on Monday",
11 }
12 return orders.get(order_id, f"No order found with ID {order_id}")
13
14
15# Map tool keys (matching the LaunchDarkly tool keys) to local handlers. The agent
16# build step below resolves the active tool list from `agent_config.model.parameters['tools']`
17# so detaching `get_order_status` from the variation in LaunchDarkly takes effect on
18# the next agent invocation, with no code change.
19TOOL_REGISTRY = {"get_order_status": get_order_status}

Initialize the LaunchDarkly SDK and AI client, fetch the agent config, build the LangChain model with create_langchain_model (Python) or createLangChainModel (Node.js), and create the ReAct agent.

The provider reads the model name, provider, and all parameters (temperature, max tokens, and others) from the variation, maps LaunchDarkly provider names to LangChain equivalents — for example, "gemini" to "google_genai" — and returns a configured chat model. The same AgentControl config key can serve OpenAI, Anthropic, or any other provider-backed variation from the same code path.

1import os
2import ldclient
3from ldclient import Context
4from ldclient.config import Config
5from ldai.client import LDAIClient
6from ldai.providers.types import LDAIMetrics
7from ldai_langchain import (
8 create_langchain_model,
9 get_tool_calls_from_response,
10 sum_token_usage_from_messages,
11)
12from langchain_core.tools import tool
13from langchain.agents import create_agent
14from langgraph.checkpoint.memory import MemorySaver
15
16
17ldclient.set_config(Config(os.environ.get("LAUNCHDARKLY_SDK_KEY")))
18
19ai_client = LDAIClient(ldclient.get())
20
21context = Context.builder("user-123").kind("user").name("Sandy").build()
22
23# Pass a default for improved resiliency when the AgentControl config is unavailable
24# or LaunchDarkly is unreachable; omit for a disabled default.
25# Example:
26# from ldai import AIAgentConfigDefault
27# default = AIAgentConfigDefault(
28# enabled=True,
29# model={"name": "gpt-5"},
30# provider={"name": "openai"},
31# instructions="You are a helpful assistant.",
32# )
33# agent_config = ai_client.agent_config("langgraph-agent", context, default)
34agent_config = ai_client.agent_config("langgraph-agent", context)
35
36# create_langchain_model reads agent_config.model.name / .parameters and picks the
37# right chat model class (OpenAI, Anthropic, …) with no per-provider branching.
38llm = create_langchain_model(agent_config)
39
40# Resolve the agent's tool list from the active variation. LaunchDarkly returns
41# attached tools under `parameters.tools` in OpenAI function shape; we only need
42# the names to look up the local handlers from TOOL_REGISTRY.
43ld_tool_params = (agent_config.model.to_dict().get("parameters") or {}).get("tools") or []
44resolved_tools = [
45 TOOL_REGISTRY[t["name"]] for t in ld_tool_params if t["name"] in TOOL_REGISTRY
46]
47
48# MemorySaver gives the ReAct agent short-term memory per thread_id —
49# follow-up turns on the same thread see the earlier conversation.
50checkpointer = MemorySaver()
51agent = create_agent(
52 llm,
53 resolved_tools,
54 system_prompt=agent_config.instructions,
55 checkpointer=checkpointer,
56)

Invoke the agent and track metrics. Each turn is one execution as far as the tracker is concerned: track_metrics_of_async (Python) / trackMetricsOf (Node.js) records duration and tracks success or error itself, so the surrounding try/except only needs to log. The Python example uses the SDK’s sum_token_usage_from_messages helper to aggregate token counts and get_tool_calls_from_response to feed track_tool_call. The Node.js example uses LangChainProvider.getAIMetricsFromResponse per message and reads msg.tool_calls directly until the matching JS helper ships.

1from ldai.providers.types import LDAIMetrics
2from ldai_langchain import get_tool_calls_from_response, sum_token_usage_from_messages
3
4
5async def run_turn(agent, agent_config, user_input, thread_id):
6 # Each tracker is one execution. `track_metrics_of_async`
7 # records duration + success/error itself; the extractor only returns
8 # LDAIMetrics. The SDK helpers handle token aggregation and tool-call
9 # name extraction.
10 tracker = agent_config.create_tracker()
11 try:
12 result = await tracker.track_metrics_of_async(
13 lambda: agent.ainvoke(
14 {"messages": [{"role": "user", "content": user_input}]},
15 config={"configurable": {"thread_id": thread_id}},
16 ),
17 lambda res: LDAIMetrics(
18 success=True,
19 usage=sum_token_usage_from_messages(res.get("messages", [])),
20 ),
21 )
22 for msg in result.get("messages", []):
23 for name in get_tool_calls_from_response(msg):
24 tracker.track_tool_call(name)
25 messages = result.get("messages", [])
26 if messages:
27 print(f"Agent: {messages[-1].content}")
28 except Exception as e:
29 # `track_metrics_of_async` already recorded the error and re-raised.
30 print(f"Error: {e}")
31
32
33thread_id = "demo-thread"
34await run_turn(agent, agent_config, "What's the status of order ORD-123?", thread_id)
35await run_turn(agent, agent_config, "What about ORD-456?", thread_id)
36await run_turn(agent, agent_config, "Summarize both orders for me.", thread_id)

The fallback argument to agent_config / agentConfig is optional. When omitted, LaunchDarkly returns a disabled config if the flag is off or the SDK is unreachable. Pass an explicit fallback to keep the agent running during outages.

Complete example

Here is a complete working example that combines all the steps.

Click to expand full example code
1import asyncio
2import os
3import ldclient
4from ldclient import Context
5from ldclient.config import Config
6from ldai.client import LDAIClient
7from ldai.providers.types import LDAIMetrics
8from ldai_langchain import (
9 create_langchain_model,
10 get_tool_calls_from_response,
11 sum_token_usage_from_messages,
12)
13from langchain_core.tools import tool
14from langchain.agents import create_agent
15from langgraph.checkpoint.memory import MemorySaver
16from dotenv import load_dotenv
17
18load_dotenv()
19
20SDK_KEY = os.environ.get("LAUNCHDARKLY_SDK_KEY")
21AGENT_CONFIG_KEY = "langgraph-agent"
22
23
24@tool
25def get_order_status(order_id: str) -> str:
26 """Look up the status of a customer order by order ID."""
27 orders = {
28 "ORD-123": "Shipped — arrives Thursday",
29 "ORD-456": "Processing — estimated ship date: tomorrow",
30 "ORD-789": "Delivered on Monday",
31 }
32 return orders.get(order_id, f"No order found with ID {order_id}")
33
34
35# Map tool keys (matching the LaunchDarkly tool keys) to local handlers.
36TOOL_REGISTRY = {"get_order_status": get_order_status}
37
38
39async def run_turn(agent, agent_config, user_input, thread_id):
40 # Each tracker is one execution. `track_metrics_of_async`
41 # records duration + success/error itself; the extractor only returns
42 # LDAIMetrics. SDK helpers handle token aggregation and tool-call name
43 # extraction.
44 tracker = agent_config.create_tracker()
45 try:
46 result = await tracker.track_metrics_of_async(
47 lambda: agent.ainvoke(
48 {"messages": [{"role": "user", "content": user_input}]},
49 config={"configurable": {"thread_id": thread_id}},
50 ),
51 lambda res: LDAIMetrics(
52 success=True,
53 usage=sum_token_usage_from_messages(res.get("messages", [])),
54 ),
55 )
56 for msg in result.get("messages", []):
57 for name in get_tool_calls_from_response(msg):
58 tracker.track_tool_call(name)
59 messages = result.get("messages", [])
60 if messages:
61 print(f"Agent: {messages[-1].content}")
62 except Exception as e:
63 # `track_metrics_of_async` already recorded the error and re-raised.
64 print(f"Error: {e}")
65
66
67async def async_main():
68 ldclient.set_config(Config(SDK_KEY))
69 if not ldclient.get().is_initialized():
70 print("LaunchDarkly SDK failed to initialize")
71 return
72
73 ai_client = LDAIClient(ldclient.get())
74
75 context = Context.builder("user-123").kind("user").name("Sandy").build()
76
77 # Pass a default for improved resiliency when the AgentControl config is unavailable
78 # or LaunchDarkly is unreachable; omit for a disabled default.
79 # Example:
80 # from ldai import AIAgentConfigDefault
81 # default = AIAgentConfigDefault(
82 # enabled=True,
83 # model={"name": "gpt-5"},
84 # provider={"name": "openai"},
85 # instructions="You are a helpful assistant.",
86 # )
87 # agent_config = ai_client.agent_config(AGENT_CONFIG_KEY, context, default)
88 agent_config = ai_client.agent_config(AGENT_CONFIG_KEY, context)
89
90 if not agent_config.enabled:
91 print("Agent Config is disabled — run the notebook to set up the config")
92 return
93
94 # create_langchain_model reads agent_config.model.name / .parameters and picks the
95 # right chat model class (OpenAI, Anthropic, …) with no per-provider branching.
96 llm = create_langchain_model(agent_config)
97
98 # Resolve the agent's tool list from the active variation. LaunchDarkly returns
99 # attached tools under `parameters.tools` in OpenAI function shape.
100 ld_tool_params = (agent_config.model.to_dict().get("parameters") or {}).get("tools") or []
101 resolved_tools = [
102 TOOL_REGISTRY[t["name"]] for t in ld_tool_params if t["name"] in TOOL_REGISTRY
103 ]
104
105 # MemorySaver gives the ReAct agent short-term memory per thread_id —
106 # follow-up turns on the same thread see the earlier conversation.
107 checkpointer = MemorySaver()
108 agent = create_agent(
109 llm,
110 resolved_tools,
111 system_prompt=agent_config.instructions,
112 checkpointer=checkpointer,
113 )
114
115 # Three turns on one thread: first fires the tool, second reuses memory
116 # to answer a follow-up that reuses the tool, third summarizes — no tool.
117 # Each turn gets its own tracker (its own runId).
118 thread_id = "demo-thread"
119 await run_turn(agent, agent_config, "What's the status of order ORD-123?", thread_id)
120 await run_turn(agent, agent_config, "What about ORD-456?", thread_id)
121 await run_turn(agent, agent_config, "Summarize both orders for me.", thread_id)
122
123 # Always flush events before closing — trailing events are at risk of being
124 # lost otherwise, in short-lived scripts and long-running services alike.
125 ldclient.get().flush()
126 ldclient.get().close()
127
128
129def main():
130 asyncio.run(async_main())
131
132
133if __name__ == "__main__":
134 main()

Step 5: Monitor results

View metrics for your AgentControl config in the LaunchDarkly UI.

To monitor results:

  1. In LaunchDarkly, navigate to your AgentControl config.
  2. Select the Monitoring tab.

LaunchDarkly displays metrics including:

  • Generation count
  • Token usage (input, output, total)
  • Time to generate
  • Error rate

Use these metrics to compare agent performance, identify cost differences, and make data-driven decisions about which configuration to use for different user segments. To learn more, read Monitor AgentControl configs.

To view aggregated metrics across all your AgentControl configs, navigate to Insights in the left navigation under the AI section. The Insights overview page displays cost, latency, error rate, invocation counts, and model distribution across your organization. To learn more, read about AI insights.

The Insights overview page showing cost, latency, error rate, and invocation metrics for a LangGraph AgentControl config.

The Insights overview page showing cost, latency, error rate, and invocation metrics for a LangGraph AgentControl config.

Agent mode vs completion mode

AspectAgent ModeCompletion Mode
Config fieldinstructions (string)messages (array)
SDK methodagent_config()completion_config()
Default classAIAgentConfigDefaultAICompletionConfigDefault
Use caseMulti-step workflows, tool useSingle-turn completions

Conclusion

In this guide, you learned how to integrate LangGraph agent workflows with LaunchDarkly AgentControl to manage agent configuration outside of your application code.

You can now:

  • Change agent models and instructions without redeploying your application
  • Target different agent configurations to different users based on context attributes
  • Track and compare agent performance across variations
  • Maintain conversation state with LangGraph checkpointing
  • Coordinate multi-agent workflows with centralized configuration

To explore additional capabilities, read:

  • Run experiments with AgentControl to compare agent variations using statistical analysis
  • Config targeting to serve different agents to different user segments
  • Agent graphs to orchestrate multi-agent workflows

For more AgentControl examples, read the other AgentControl guides in this section.