OpenAI Agents Go SDK

repository·main·Indexed 42 days ago

https://github.com/nlpodyssey/openai-agents-go

A lightweight, provider-agnostic framework for building multi-agent workflows in Go. A port of the OpenAI Agents Python SDK, it enables developers to implement complex patterns including agent handoffs, tool usage, and guardrails. It supports OpenAI-compatible APIs and integrates with LiteLLM for multi-provider routing (OpenAI, Anthropic, Google, etc.) via direct providers, prefix routing, or global default clients.

Tokens
3.5K
Snippets
9
Records
14
Agent score
55%

What's inside OpenAI Agents Go SDK

  1. Patterns for using custom LLM providers in Go

    main

    The SDK supports several ways to integrate non-OpenAI providers, mirroring the patterns available in the Python SDK:

    • Runner-level provider: Provide a custom ModelProvider directly to the Runner to control the provider for the entire execution context.
    • Per-agent client: Use WithModelInstance(...) to set a specific custom client for an individual agent.
    • Global default client: Set a global default OpenAI client and default API (e.g., chat_completions) to be used across the application.
    • MultiProvider with prefix routing: When using LiteLLM, you can implement prefix routing (e.g., using litellm/... prefixes) to route requests to different providers via a single entry point.
  2. How the agent loop works

    main

    When agents.Run() is called, the SDK enters a loop that continues until a final output is reached or MaxTurns is hit. The loop follows these steps:

    1. LLM Call: The SDK calls the LLM using the agent's model, settings, and message history.
    2. Response Evaluation:
      • Final Output: If the response contains a final output, the loop ends.
      • Handoff: If the response contains a handoff, the SDK switches to the new agent and returns to step 1.
      • Tool Call: If the response contains tool calls, the SDK executes them, appends the tool responses to the history, and returns to step 1.

    Final Output Logic

    • With OutputType: If an OutputType is configured on the agent, the loop runs until the LLM returns structured output matching that type.
    • Without OutputType: The loop runs until the LLM produces a message that contains no tool calls or handoffs.
  3. Core concepts of the OpenAI Agents SDK

    main

    The SDK is built around three primary abstractions:

    1. Agents: LLMs configured with specific instructions, tools, guardrails, and handoffs.
    2. Handoffs: A specialized type of tool call used to transfer control from one agent to another.
    3. Guardrails: Configurable safety mechanisms used for validating inputs and outputs.

    The SDK is provider-agnostic and supports OpenAI Responses, Chat Completions, and other LLMs.

  4. Use LiteLLM as an OpenAI-compatible proxy

    main

    You can use LiteLLM via Docker to act as an OpenAI-compatible proxy for various upstream providers. This requires a litellm_config.yaml file in your current directory and an OPENAI_API_KEY for the upstream services.

    1. Start the LiteLLM Docker container:
    docker run \
      -v $(pwd)/litellm_config.yaml:/app/config.yaml \
      -e OPENAI_API_KEY="$OPENAI_API_KEY" \
      -p 4000:4000 \
      ghcr.io/berriai/litellm:main-stable \
      --config /app/config.yaml \
      --detailed_debug
    1. Run the LiteLLM example in Go:
    go run ./examples/model_providers/custom_example_litellm
  5. Configure environment variables for custom LLM providers

    main

    To use non-OpenAI providers in the Go examples, you must configure the base URL, API key, and model name. You can either set these as environment variables or modify the source code directly.

    Required environment variables:

    • EXAMPLE_BASE_URL: The endpoint of your custom provider.
    • EXAMPLE_API_KEY: Your authentication key.
    • EXAMPLE_MODEL_NAME: The identifier for the model you wish to use.
    export EXAMPLE_BASE_URL="http://your-provider-host"
    export EXAMPLE_API_KEY="your-provider-api-key"
    export EXAMPLE_MODEL_NAME="model-name"
  6. Integrate LiteLLM with OpenAI Agents Go SDK

    main

    This guide demonstrates how to use LiteLLM as a unified proxy for multiple LLM providers (OpenAI, Anthropic, Google, etc.) within the OpenAI Agents Go SDK. LiteLLM runs in Docker and provides an OpenAI-compatible API endpoint that the SDK can consume.

    Architecture

    Go Application (Agents SDK) -> LiteLLM Docker (Port 4000) -> LLM Providers

    # 1. Set your OpenAI API key
    export OPENAI_API_KEY="sk-your-openai-api-key-here"
    
    # 2. Start LiteLLM Docker Container
    docker run \
      -v $(pwd)/litellm_config.yaml:/app/config.yaml \
      -e OPENAI_API_KEY="$OPENAI_API_KEY" \
      -p 4000:4000 \
      ghcr.io/berriai/litellm:main-stable \
      --config /app/config.yaml \
      --detailed_debug
    
    # 3. Run the Go Example
    go run main.go
  7. Configure LiteLLM via litellm_config.yaml

    main

    LiteLLM uses a YAML configuration file to map internal model names to specific provider models and API keys. You can define models for OpenAI, Anthropic, or local providers like Ollama.

    Example Configuration

    model_list:
      # OpenAI Models
      - model_name: openai-gpt-4o
        litellm_params:
          model: openai/gpt-4o-mini
          api_key: os.environ/OPENAI_API_KEY
    
      # Anthropic Models
      - model_name: claude-3-sonnet
        litellm_params:
          model: anthropic/claude-3-5-sonnet-20240620
          api_key: os.environ/ANTHROPIC_API_KEY
    
      # Local Ollama Models
      - model_name: ollama-llama3
        litellm_params:
          model: ollama/llama3
          api_base: http://localhost:11434
  8. Troubleshoot LiteLLM integration issues

    main

    Common Errors

    • Connection Refused: Error: connection refused on port 4000.
      • Solution: Ensure the Docker container is running and port 4000 is accessible.
    • Unauthorized: Error: 401 Unauthorized.
      • Solution: Verify that your API keys (e.g., OPENAI_API_KEY, ANTHROPIC_API_KEY) are correctly set as environment variables.
    • Model Not Found: Error: model "xyz" not found.
      • Solution: Ensure the model name matches the model_name defined in your litellm_config.yaml.

    Debugging

    • LiteLLM Verbose Logging: Set general_settings.set_verbose: true in your litellm_config.yaml.
    • Docker Logs: Use docker logs <container-id> to inspect LiteLLM output.
  9. Implement agent handoffs

    main

    Handoffs allow one agent to transfer control to another. This is achieved by using WithAgentHandoffs(agents...) on a 'triage' or 'router' agent. When the LLM decides to hand off, the SDK switches the active agent and continues the loop.

    package main
    
    import (
    	"context"
    	"fmt"
    
    	"github.com/nlpodyssey/openai-agents-go/agents"
    )
    
    func main() {
        spanishAgent := agents.New("Spanish agent").
            WithInstructions("You only speak Spanish.").
            WithModel("gpt-4o")
    
        englishAgent := agents.New("English agent").
            WithInstructions("You only speak English.").
            WithModel("gpt-4o")
    
        triageAgent := agents.New("Triage agent").
            WithInstructions("Handoff to the appropriate agent based on the language of the request.").
            WithAgentHandoffs(spanishAgent, englishAgent).
            WithModel("gpt-4o")
    	
        result, err := agents.Run(context.Background(), triageAgent, "Hola, ¿cómo estás?")
        if err != nil {
            panic(err)
        }
    
        fmt.Println(result.FinalOutput)
    }
  10. Use LiteLLM with three different integration patterns

    main

    The SDK supports three ways to consume LiteLLM services:

    1. Direct LiteLLM Provider

    Create a dedicated provider instance and pass it to the agents.Runner configuration.

    2. MultiProvider with Prefix Routing

    Register LiteLLM in a MultiProviderMap with a prefix (e.g., litellm). You can then call models using the format prefix/model-name.

    3. Global Default Provider

    Configure a custom OpenaiClient pointing to the LiteLLM endpoint and set it as the global default. This allows you to use standard model names without prefixes.

    // 1. Direct LiteLLM Provider
    litellmProvider := NewLiteLLMProvider("", "")
    result, err := (agents.Runner{
        Config: agents.RunConfig{
            ModelProvider: litellmProvider,
            Model: param.NewOpt(agents.NewAgentModelName("openai-gpt-4o")),
        },
    }).Run(context.Background(), agent, "Your prompt here")
    
    // 2. MultiProvider with Prefix Routing
    providerMap := agents.NewMultiProviderMap()
    providerMap.AddProvider("litellm", NewLiteLLMProvider("", ""))
    multiProvider := agents.NewMultiProvider(agents.NewMultiProviderParams{
        ProviderMap: providerMap,
    })
    agent.WithModel("litellm/openai-gpt-4o")
    
    // 3. Global Default Provider
    litellmClient := agents.NewOpenaiClient(
        param.NewOpt("http://localhost:4000"),
        param.NewOpt("dummy-key"),
    )
    agents.SetDefaultOpenaiClient(litellmClient, false)
    agent.WithModel("openai-gpt-4o")
  11. Register and use custom tools with NewFunctionTool

    main

    To give an agent capabilities, define a Go function and register it as a tool using agents.NewFunctionTool(name, description, function). Then, attach it to the agent using WithTools(...).

    package main
    
    import (
            "context"
            "fmt"
    
            "github.com/nlpodyssey/openai-agents-go/agents"
    )
    
    type GetWeatherParams struct {
            City string `json:"city"` 
    }
    
    func getWeather(_ context.Context, params GetWeatherParams) (string, error) {
            return fmt.Sprintf("The weather in %s is sunny.", params.City), nil
    }
    
    var getWeatherTool = agents.NewFunctionTool("GetWeather", "", getWeather)
    
    func main() {
            agent := agents.New("Hello world").
                    WithInstructions("You are a helpful agent.").
                    WithModel("gpt-4o").
                    WithTools(getWeatherTool)
    	
            result, err := agents.Run(context.Background(), agent, "What's the weather in Tokyo?")
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(result.FinalOutput)
    }