> ## Documentation Index
> Fetch the complete documentation index at: https://launchdarkly-preview.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting started with OpenAI and AI Configs

> This guide shows how to connect an OpenAI-powered application to LaunchDarkly AI Configs to manage model configuration, prompts, and metrics outside of application code.

> For the complete documentation index, see [llms.txt](/llms.txt). For the full documentation snapshot, see [llms-full.txt](/llms-full.txt).

## Overview

This guide shows how to connect an OpenAI-powered application to LaunchDarkly AI Configs. OpenAI models are widely adopted for chat completions, function calling, and structured outputs. By the end, you will be able to manage your model configuration and prompts outside of your application code, track metrics automatically, and switch between models or update prompts without redeploying.

This guide uses the base SDK with `track_openai_metrics` (Python) / `trackOpenAIMetrics` (Node.js) tracking helpers. LaunchDarkly also publishes higher-level OpenAI provider packages for [Python](https://github.com/launchdarkly/python-server-sdk-ai/tree/main/packages/ai-providers/server-ai-openai) and [Node.js](https://github.com/launchdarkly/js-core/tree/main/packages/ai-providers/server-ai-openai) that handle model creation, parameter forwarding, and structured output.AI Configs support two modes:

* **Completion mode** returns messages and roles (such as "system," "user," "assistant"). Use it for chat-style interactions and message-oriented workflows. Completion mode supports online evaluations with judges attached in the LaunchDarkly user interface (UI).
* **Agent mode** returns a single `instructions` string. Use it when your runtime or framework expects a goal/instructions input for a structured workflow. Agent mode changes the configuration shape from messages to instructions. Your application maps these instructions into your provider or framework's native input. Both modes support tool calling. This guide walks through completion mode as the main path, with an optional agent config section and an advanced tool-calling example. To learn more about when to use each mode, read [When to use prompt-based vs agent mode](/guides/ai-configs/agent-vs-completion). This guide provides examples in both Python and Node.js (TypeScript).

<Tip title="Additional resources for AI Configs">
  If you are not familiar with AI Configs, start with the [Quickstart for AI Configs](/home/ai-configs/quickstart) and return to this guide when you are ready for a more detailed example.

  You can find reference guides for each of the AI SDKs at [AI SDKs](/sdk/ai).
</Tip>

## Prerequisites

To complete this guide, you need the following:

* A [LaunchDarkly account](https://app.launchdarkly.com/).
* An OpenAI API key.
* A development environment:
  * **Python**: Python 3.10 or higher
  * **Node.js**: Node.js 20 or higher
* Familiarity with LaunchDarkly contexts. To learn more, read [Contexts and segments](/home/flags/contexts).

## Concepts

Before you begin, review these key concepts.

### AI Configs

An AI Config is a LaunchDarkly resource that controls how your application uses large language models. Each AI Config contains one or more variations. Each variation specifies:

* A model configuration, including the model name and parameters
* Messages that define the promptYou can update these settings in LaunchDarkly at any time without changing your application code.

### Contexts

A context represents the end user interacting with your application. LaunchDarkly uses context attributes to:

* Determine which variation to serve based on targeting rules
* Populate template variables in your prompts

### The tracker

When you retrieve an AI Config, the SDK returns a config object with a `tracker` property. The tracker records metrics from your OpenAI calls, including:

* Generation count
* Input and output tokens
* Latency
* Success and error ratesThese metrics appear on the **Monitoring** tab in LaunchDarkly.

## Step 1: Install the SDKInstall the Launch

Darkly AI SDK and the OpenAI SDK in your application. AI Configs are supported by LaunchDarkly server-side SDKs only. The Node.js examples in this guide use the [server-side Node.js AI SDK](https://github.com/launchdarkly/js-core/tree/main/packages/sdk/server-ai).

Here is how to install the required packages:

<CodeGroup>
  ```bash title="Python" theme={null}
      pip install launchdarkly-server-sdk
      pip install launchdarkly-server-sdk-ai
      pip install openai
      pip install python-dotenv
  ```

  ```bash title="Node.js" theme={null}
      npm install @launchdarkly/node-server-sdk
      npm install @launchdarkly/server-sdk-ai
      npm install openai
      npm install dotenv
  ```
</CodeGroup>

Create a `.env` file in your project root with your API keys:

```bash theme={null}
# .env
LAUNCHDARKLY_SDK_KEY=<your-launchdarkly-sdk-key>
OPENAI_API_KEY=<your-openai-api-key>
```

## Step 2: Initialize the clients

Initialize both the LaunchDarkly client and the OpenAI client. Store your API keys in environment variables.

Here is the initialization code:

<CodeGroup>
  ```python title="Python" theme={null}
      import os
      import ldclient
      from ldclient import Context
      from ldclient.config import Config
      from ldai.client import LDAIClient, AICompletionConfigDefault
      from openai import OpenAI

      # Initialize OpenAI
      openai_client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

      # Initialize LaunchDarkly
      ldclient.set_config(Config(os.environ.get("LAUNCHDARKLY_SDK_KEY")))

      if not ldclient.get().is_initialized():
          print("LaunchDarkly SDK failed to initialize")
          exit(1)

      # Initialize the AI client
      aiclient = LDAIClient(ldclient.get())
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      import { init, LDClient, LDContext } from '@launchdarkly/node-server-sdk';
      import { initAi, LDAIClient, LDAIConfig } from '@launchdarkly/server-sdk-ai';
      import OpenAI from 'openai';

      // Initialize OpenAI
      const openaiClient = new OpenAI({
        apiKey: process.env.OPENAI_API_KEY,
      });

      // Initialize LaunchDarkly
      const ldClient: LDClient = init(process.env.LAUNCHDARKLY_SDK_KEY as string);

      try {
        await ldClient.waitForInitialization({ timeout: 10 });
      } catch (error) {
        console.error('LaunchDarkly SDK failed to initialize');
        process.exit(1);
      }

      // Initialize the AI client
      const aiClient: LDAIClient = initAi(ldClient);
  ```
</CodeGroup>

## Step 3: Create an AI Config in Launch

DarklyCreate an AI Config in the LaunchDarkly UI to store your OpenAI model settings and prompts.

<Tip title="Using the MCP server or agent skills">
  If you have the [LaunchDarkly MCP server](https://github.com/launchdarkly/mcp-server) or [agent skills](https://github.com/launchdarkly/agent-skills) configured, prompt your coding assistant to create the AI Config for you. For example:

  "Create a completion mode AI Config called 'OpenAI assistant' with a GPT-4o variation that has a system message: 'You are a helpful assistant. Provide clear, concise answers.' Set temperature to 0.7 and enable targeting."
</Tip>

To create the AI Config:

1. Click **Create** and select **AI Config**.

2. In the **Create AI Config** dialog, select **Completion**.

3. Enter a name, such as "OpenAI assistant".

4. Click **Create**.To create a variation:

5. On the **Variations** tab, replace "Untitled variation" with a name, such as "GPT-4o variation".

6. Click **Select a model** and choose an OpenAI model, such as "gpt-4o".

7. Add a **system** message to define your assistant's behavior. Here is an example:

<CodeGroup>
  ```title="System message" theme={null}
      You are a helpful assistant. Provide clear, concise answers.
  ```
</CodeGroup>

4. Click **Review and save**.

<Frame caption="A completed variation with model configuration and system message.">
  ![A completed variation with model configuration and system message.](https://files.buildwithfern.com/https://launchdarkly.docs.buildwithfern.com/docs/ba733ae36d048e2d1fb3fbd9e30b44fa1b85790e910cdd5440f0d411e5fb5a09/assets/images/auto/ai-config-variation-complete.auto.png)
</Frame>

To enable targeting:

1. Select the **Targeting** tab.
2. In the "Default rule" section, click **Edit**.
3. Set the default rule to serve your variation.
4. Click **Review and save**.

<Frame caption="The default targeting rule configured to serve a variation.">
  ![The default targeting rule configured to serve a variation.](https://files.buildwithfern.com/https://launchdarkly.docs.buildwithfern.com/docs/5dd50b9ee0b404e60eae3ce10489d1a1048069ffabe139d33b0c655a9da56ec2/assets/images/auto/guide-ai-config-model-config-update-default-targeting-rule.auto.png)
</Frame>

## Step 4: Get the AI Config in your application

Retrieve the AI Config from LaunchDarkly by calling the completion config function. Pass a context that represents the current user and a fallback configuration.

Here is how to get the AI Config:

<CodeGroup>
  ```python title="Python" theme={null}
      # Define the context for the current user
      context = Context.builder("user-123") \
          .kind("user") \
          .name("Sandy") \
          .build()

      # Define a fallback configuration
      fallback_value = AICompletionConfigDefault(enabled=False)

      # Get the AI Config
      config = aiclient.completion_config(
          "openai-assistant",
          context,
          fallback_value
      )
      tracker = config.tracker
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      // Define the context for the current user
      const context: LDContext = {
        kind: 'user',
        key: 'user-123',
        name: 'Sandy',
      };

      // Define a fallback configuration
      const fallbackConfig = { enabled: false };

      // Get the AI Config
      const aiConfig: LDAIConfig = await aiClient.completionConfig(
        'openai-assistant',
        context,
        fallbackConfig
      );
  ```
</CodeGroup>

The SDK uses the fallback configuration when LaunchDarkly is unreachable. Check the `enabled` property and handle the disabled case in your application.

<Note title="Best practices">
  For production use:

  * Retrieve the AI Config each time you generate content so LaunchDarkly can evaluate the latest targeting rules and prompt changes.
  * Provide a fallback configuration when possible so your application can fail gracefully if LaunchDarkly is unavailable.
  * Avoid sending personally identifiable information in contexts unless you have a specific need and an approved handling pattern. To learn more, read [Privacy in AI Configs](/home/ai-configs/privacy).
</Note>

## Step 5: Call Open

AI and track metricsUse the tracker to call OpenAI and record metrics automatically. The SDK provides a `track_openai_metrics` function (Python) or `trackOpenAIMetrics` function (Node.js) that wraps your OpenAI call.

Here is how to make the API call:

<CodeGroup>
  ```python title="Python" theme={null}
      if config.enabled:
          messages = [] if config.messages is None else config.messages

          config_dict = config.to_dict()
          params = config_dict.get("model", {}).get("parameters", {})

          completion = tracker.track_openai_metrics(
              lambda: openai_client.chat.completions.create(
                  model=config.model.name,
                  messages=[message.to_dict() for message in messages],
                  **params,
              )
          )

          print(completion.choices[0].message.content)
      else:
          print("AI Config is disabled")
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      if (aiConfig.enabled) {
        const { tracker } = aiConfig;

        const params = aiConfig.model?.parameters || {};

        const completion = await tracker.trackOpenAIMetrics(async () =>
          openaiClient.chat.completions.create({
            model: aiConfig.model?.name || 'gpt-4o',
            messages: aiConfig.messages || [],
            ...params,
          })
        );

        console.log(completion.choices[0].message.content);
      } else {
        console.log('AI Config is disabled');
      }
  ```
</CodeGroup>

The tracker automatically records token usage, latency, and success or error status.

<Note title="Streaming">
  The `track_openai_metrics` (Python) and `trackOpenAIMetrics` (Node.js) helpers expect a complete response object. If your application uses streaming responses, use the lower-level `track_duration`, `track_tokens`, `track_success`, and `track_error` methods to record metrics manually. To learn more, read [Monitor AI Configs](/home/ai-configs/monitor).
</Note>

Not every parameter or capability applies uniformly to every OpenAI model. For example, function calling behavior and token limits differ between model families. Refer to OpenAI's model documentation for model-specific details.

## Step 6: Add user input to the conversation

Combine the messages from your AI Config with user input to create a complete conversation.

Here is how to add a user message:

<CodeGroup>
  ```python title="Python" theme={null}
      if config.enabled:
          messages = [] if config.messages is None else config.messages

          # Convert to list and add user message
          message_list = [message.to_dict() for message in messages]
          message_list.append({
              "role": "user",
              "content": "What is the capital of France?"
          })

          config_dict = config.to_dict()
          params = config_dict.get("model", {}).get("parameters", {})

          completion = tracker.track_openai_metrics(
              lambda: openai_client.chat.completions.create(
                  model=config.model.name,
                  messages=message_list,
                  **params,
              )
          )

          print(completion.choices[0].message.content)
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      if (aiConfig.enabled) {
        const { tracker } = aiConfig;

        const configMessages = aiConfig.messages || [];
        const userMessage = {
          role: 'user' as const,
          content: 'What is the capital of France?'
        };
        const allMessages = [...configMessages, userMessage];

        const params = aiConfig.model?.parameters || {};

        const completion = await tracker.trackOpenAIMetrics(async () =>
          openaiClient.chat.completions.create({
            model: aiConfig.model?.name || 'gpt-4o',
            messages: allMessages,
            ...params,
          })
        );

        console.log(completion.choices[0].message.content);
      }
  ```
</CodeGroup>

## Step 7: Use template variables

Use template variables in your AI Config messages to customize prompts at runtime. Variables use double curly brace syntax: `{{ variable_name }}`.To use context attributes, prefix with `ldctx`:

```
Address the user as {{ ldctx.name }}.
```

To use custom variables, pass them when calling the completion config function.

Here is an example AI Config message with variables:

<CodeGroup>
  ```title="AI Config message in LaunchDarkly" theme={null}
      You are a {{ assistant_type }} assistant. Help {{ ldctx.name }} with their questions about {{ topic }}.
  ```
</CodeGroup>

Here is how to pass variables in your application code:

<CodeGroup>
  ```python title="Python" theme={null}
      config = aiclient.completion_config(
          "openai-assistant",
          context,
          fallback_value,
          {
              "assistant_type": "technical",
              "topic": "Python programming"
          }
      )
      tracker = config.tracker
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      const aiConfig = await aiClient.completionConfig(
        'openai-assistant',
        context,
        fallbackConfig,
        {
          assistant_type: 'technical',
          topic: 'Python programming'
        }
      );
  ```
</CodeGroup>

The SDK replaces variables with their values before returning the configuration.

## Step 8: Monitor your AI Config

To view aggregated metrics across all your AI 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 [Trends Explorer](/home/ai-configs/trends).

To view metrics for a specific AI Config:

1. Navigate to your AI Config.
2. Select the **Monitoring** tab.

The **Monitoring** tab displays the following metrics:

* **Generations**: Average number of successful generations per variation.
* **Token usage**: Input and output tokens consumed by each variation.
* **Time to generate**: The latency of each model call, measured end to end.
* **Error rate**: The percentage of invocations that returned an error.
* **Costs**: Estimated costs based on token usage and the model's pricing. Metrics update approximately every minute. Use these metrics to compare variations and optimize your prompts.

<Note title="Observability">
  LaunchDarkly provides metrics for AI Config invocations, including latency, token usage, costs, and error rates. If you also want traces associated with an evaluated AI Config, run the model request inside an active OpenTelemetry parent span. To learn more, read [Observability](/home/observability) and [LLM observability](/home/observability/llm-observability).
</Note>

## Optional: Retrieve an agent-based AI Config

Agent mode returns a single `instructions` string instead of a messages array. Use it when your runtime or framework expects a goal/instructions input for a structured workflow. Agent mode changes the configuration shape from messages to instructions. Your application maps these instructions into your provider or framework's native input.

To use agent mode, create an AI Config with mode set to **Agent** in the LaunchDarkly UI, then retrieve it with the agent config function. Map the LaunchDarkly `instructions` field into OpenAI's top-level `instructions` parameter.

<CodeGroup>
  ```python title="Python" theme={null}
      from ldai.client import AIAgentConfigDefault

      agent = aiclient.agent_config(
          'openai-agent',
          context,
          AIAgentConfigDefault(enabled=False),
      )

      if agent.enabled:
          tracker = agent.tracker
          agent_dict = agent.to_dict()
          params = agent_dict.get("model", {}).get("parameters", {})

          completion = tracker.track_openai_metrics(
              lambda: openai_client.chat.completions.create(
                  model=agent.model.name,
                  messages=[
                      {"role": "system", "content": agent.instructions},
                      {"role": "user", "content": "Triage this support request: my order hasn't arrived"},
                  ],
                  **params,
              )
          )
          print(completion.choices[0].message.content)
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      import { type LDAIAgentConfig } from '@launchdarkly/server-sdk-ai';

      const agentConfig: LDAIAgentConfig = await aiClient.agentConfig(
        'openai-agent',
        context,
        { enabled: false },
      );

      if (agentConfig.enabled && agentConfig.tracker && agentConfig.instructions) {
        const { tracker } = agentConfig;
        const params = agentConfig.model?.parameters || {};

        const completion = await tracker.trackOpenAIMetrics(async () =>
          openaiClient.chat.completions.create({
            model: agentConfig.model?.name || 'gpt-4o',
            messages: [
              { role: 'system', content: agentConfig.instructions },
              { role: 'user', content: "Triage this support request: my order hasn't arrived" },
            ] as any,
            ...params,
          })
        );
        console.log(completion.choices[0].message.content);
      }
  ```
</CodeGroup>

In completion mode, you can attach judges to variations in the LaunchDarkly UI for automatic evaluation. In agent mode, invoke judges programmatically through the AI SDK.To learn more, read [When to use prompt-based vs agent mode](/guides/ai-configs/agent-vs-completion) and [Agents in AI Configs](/home/ai-configs/agents).

## Step 9: Close the client

Close the LaunchDarkly client when your application shuts down to flush pending events.

Here is how to close the client:

<CodeGroup>
  ```python title="Python" theme={null}
      ldclient.get().close()
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      await ldClient.close();
  ```
</CodeGroup>

For short-lived applications such as scripts, explicitly flush events before closing.

Here is how to flush events:

<CodeGroup>
  ```python title="Python" theme={null}
      ldclient.get().flush()
      ldclient.get().close()
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      await ldClient.flush();
      await ldClient.close();
  ```
</CodeGroup>

## Complete example

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

<CodeGroup>
  ```python title="Python" theme={null}
      import os
      import ldclient
      from ldclient import Context
      from ldclient.config import Config
      from ldai.client import LDAIClient, AICompletionConfigDefault
      from openai import OpenAI
      from dotenv import load_dotenv

      def main():
          # Load environment variables
          load_dotenv()

          # Initialize clients
          openai_client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

          ldclient.set_config(Config(os.environ.get("LAUNCHDARKLY_SDK_KEY")))

          if not ldclient.get().is_initialized():
              print("LaunchDarkly SDK failed to initialize")
              return

          aiclient = LDAIClient(ldclient.get())

          # Define context and fallback
          context = Context.builder("user-123") \
              .kind("user") \
              .name("Sandy") \
              .build()

          fallback_value = AICompletionConfigDefault(enabled=False)

          # Get AI Config
          config = aiclient.completion_config(
              "openai-assistant",
              context,
              fallback_value,
              {"topic": "Python programming"}
          )
          tracker = config.tracker

          # Call OpenAI
          if config.enabled:
              messages = [] if config.messages is None else config.messages
              message_list = [message.to_dict() for message in messages]
              message_list.append({
                  "role": "user",
                  "content": "How do I read a file in Python?"
              })

              config_dict = config.to_dict()
              params = config_dict.get("model", {}).get("parameters", {})

              try:
                  completion = tracker.track_openai_metrics(
                      lambda: openai_client.chat.completions.create(
                          model=config.model.name,
                          messages=message_list,
                          **params,
                      )
                  )
                  print(completion.choices[0].message.content)
              except Exception as e:
                  print(f"Error: {e}")
          else:
              print("AI Config is disabled")

          # Close client
          ldclient.get().flush()
          ldclient.get().close()

      if __name__ == "__main__":
          main()
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      import 'dotenv/config';
      import { init, LDClient, LDContext } from '@launchdarkly/node-server-sdk';
      import { initAi, LDAIClient, LDAIConfig } from '@launchdarkly/server-sdk-ai';
      import OpenAI from 'openai';

      async function main() {
        // Initialize clients
        const openaiClient = new OpenAI({
          apiKey: process.env.OPENAI_API_KEY,
        });

        const ldClient: LDClient = init(process.env.LAUNCHDARKLY_SDK_KEY as string);

        try {
          await ldClient.waitForInitialization({ timeout: 10 });
        } catch (error) {
          console.error('LaunchDarkly SDK failed to initialize');
          return;
        }

        const aiClient: LDAIClient = initAi(ldClient);

        // Define context and fallback
        const context: LDContext = {
          kind: 'user',
          key: 'user-123',
          name: 'Sandy',
        };

        const fallbackConfig = { enabled: false };

        // Get AI Config
        const aiConfig: LDAIConfig = await aiClient.completionConfig(
          'openai-assistant',
          context,
          fallbackConfig,
          { topic: 'Python programming' }
        );

        // Call OpenAI
        if (aiConfig.enabled) {
          const { tracker } = aiConfig;

          const configMessages = aiConfig.messages || [];
          const userMessage = {
            role: 'user' as const,
            content: 'How do I read a file in Python?'
          };
          const allMessages = [...configMessages, userMessage];

          const params = aiConfig.model?.parameters || {};

          try {
            const completion = await tracker.trackOpenAIMetrics(async () =>
              openaiClient.chat.completions.create({
                model: aiConfig.model?.name || 'gpt-4o',
                messages: allMessages,
                ...params,
              })
            );
            console.log(completion.choices[0].message.content);
          } catch (error) {
            console.error('Error:', error);
          }
        } else {
          console.log('AI Config is disabled');
        }

        // Close client
        await ldClient.flush();
        await ldClient.close();
      }

      main();
  ```
</CodeGroup>

## What to explore next

After you have the basic integration working, you can extend it with:

* [Tools](/home/ai-configs/tools-library) for calling external functions from your workflows
* [Online evaluations](/home/ai-configs/online-evaluations) to score response quality automatically
* [Experiments](/home/ai-configs/experimentation) to compare AI Config variations statistically
* [Agents](/home/ai-configs/agents) for multi-step workflowsFor more AI Configs guides, read the other guides in the [AI Configs guides](/guides/ai-configs) section.

## Advanced: Add tool calling with Open

AIOpenAI's function calling lets the model request tool executions during a conversation. You can combine this with either completion or agent mode AI Configs. The following example uses an agent config with a tool-calling loop.

<CodeGroup>
  ```python title="Python" theme={null}
      from ldai.client import AIAgentConfigDefault
      import json

      # Define a tool
      def get_order_status(order_id: str) -> str:
          orders = {
              "ORD-123": "Shipped — arrives Thursday",
              "ORD-456": "Processing — estimated ship date: tomorrow",
              "ORD-789": "Delivered on Monday",
          }
          return orders.get(order_id, f"No order found with ID {order_id}")

      tool_handlers = {"get_order_status": get_order_status}

      tools = [{
          "type": "function",
          "function": {
              "name": "get_order_status",
              "description": "Look up the status of a customer order",
              "parameters": {
                  "type": "object",
                  "properties": {
                      "order_id": {"type": "string", "description": "The order ID"}
                  },
                  "required": ["order_id"],
              },
          },
      }]

      agent = aiclient.agent_config(
          'openai-agent', context, AIAgentConfigDefault(enabled=False),
      )

      if agent.enabled:
          tracker = agent.tracker
          agent_dict = agent.to_dict()
          params = agent_dict.get("model", {}).get("parameters", {})

          messages = [
              {"role": "system", "content": agent.instructions},
              {"role": "user", "content": "What's the status of order ORD-123?"},
          ]

          # Tool-calling loop
          MAX_STEPS = 5
          for step in range(MAX_STEPS):
              completion = tracker.track_openai_metrics(
                  lambda: openai_client.chat.completions.create(
                      model=agent.model.name,
                      messages=messages,
                      tools=tools,
                      **params,
                  )
              )

              choice = completion.choices[0]
              if choice.finish_reason != "tool_calls":
                  print(choice.message.content)
                  break

              messages.append(choice.message)
              for tool_call in choice.message.tool_calls:
                  fn_name = tool_call.function.name
                  fn_args = json.loads(tool_call.function.arguments)
                  result = tool_handlers[fn_name](**fn_args)
                  messages.append({
                      "role": "tool",
                      "tool_call_id": tool_call.id,
                      "content": result,
                  })
  ```

  ```typescript title="Node.js (TypeScript)" theme={null}
      import { type LDAIAgentConfig } from '@launchdarkly/server-sdk-ai';

      function getOrderStatus(orderId: string): string {
        const orders: Record<string, string> = {
          'ORD-123': 'Shipped — arrives Thursday',
          'ORD-456': 'Processing — estimated ship date: tomorrow',
          'ORD-789': 'Delivered on Monday',
        };
        return orders[orderId] || `No order found with ID ${orderId}`;
      }

      const toolHandlers: Record<string, (a: any) => string> = {
        get_order_status: (a) => getOrderStatus(a.order_id),
      };

      const tools = [{
        type: 'function' as const,
        function: {
          name: 'get_order_status',
          description: 'Look up the status of a customer order',
          parameters: {
            type: 'object',
            properties: { order_id: { type: 'string', description: 'The order ID' } },
            required: ['order_id'],
          },
        },
      }];

      const agentConfig: LDAIAgentConfig = await aiClient.agentConfig(
        'openai-agent', context, { enabled: false },
      );

      if (agentConfig.enabled && agentConfig.tracker && agentConfig.instructions) {
        const { tracker } = agentConfig;
        const params = agentConfig.model?.parameters || {};

        const messages: any[] = [
          { role: 'system', content: agentConfig.instructions },
          { role: 'user', content: "What's the status of order ORD-123?" },
        ];

        const MAX_STEPS = 5;
        for (let step = 0; step < MAX_STEPS; step++) {
          const completion = await tracker.trackOpenAIMetrics(async () =>
            openaiClient.chat.completions.create({
              model: agentConfig.model?.name || 'gpt-4o',
              messages, tools, ...params,
            })
          );

          const choice = completion.choices[0];
          if (choice.finish_reason !== 'tool_calls') {
            console.log(choice.message.content);
            break;
          }

          messages.push(choice.message);
          for (const toolCall of choice.message.tool_calls || []) {
            const fnName = toolCall.function.name;
            const result = toolHandlers[fnName](
              JSON.parse(toolCall.function.arguments)
            );
            messages.push({ role: 'tool', tool_call_id: toolCall.id, content: result });
          }
        }
      }
  ```
</CodeGroup>

<Note title="Production considerations">
  Always set a maximum iteration limit to prevent runaway loops. You can manage tool definitions in the [Tools Library](/home/ai-configs/tools-library) in LaunchDarkly and attach them to your AI Config variations.
</Note>

For multi-agent orchestration patterns with OpenAI Swarm, LangGraph, or Strands, read [Compare AI orchestrators](/tutorials/ai-orchestrators).

## Troubleshooting

Some solutions for common problems are outlined below.

### Metrics not appearing

If metrics do not appear on the **Monitoring** tab:

* Verify that you are calling `tracker.track_openai_metrics()` (Python) or `tracker.trackOpenAIMetrics()` (Node.js).
* Ensure you call `flush()` before closing the client, especially for short-lived scripts.
* Wait at least one minute for metrics to process.

### SDK initialization failures

If the LaunchDarkly SDK fails to initialize:

* Verify your SDK key is correct and matches the environment you are targeting.
* Check that your network can reach LaunchDarkly servers.
* Review the SDK logs for specific error messages.

### Config returns fallback value

If you always receive the fallback configuration:

* Verify targeting is enabled for your AI Config.
* Check that the AI Config key in your code matches the key in LaunchDarkly.
* Ensure your context matches the targeting rules.

## Conclusion

In this guide, you connected an OpenAI-powered application to LaunchDarkly AI Configs. You can now:

* Manage prompts and model settings in LaunchDarkly without code changes
* Track token usage, latency, and success rates automatically
* Use template variables to customize prompts per user
