Agents

OpenAI Agent

Learn how to build OpenAI agents using native function calling capabilities with tools integration.

OpenAI Agent

OpenAI agents leverage the platform's native function calling capabilities to create intelligent assistants that can interact with external tools and APIs. This approach provides a more streamlined and robust implementation compared to manual ReAct pattern parsing.

OpenAI Function Calling vs ReAct

While ReAct agents manually parse action patterns from text responses, OpenAI's native function calling provides:

  • Structured Output: Direct function calls instead of text parsing
  • Type Safety: JSON schema validation for parameters
  • Better Reliability: No regex parsing failures
  • Native Integration: Built-in tool selection and argument extraction

Complete Implementation

index.js - Main Agent Logic

import OpenAI from "openai"
import { getCurrentWeather, getLocation, tools } from "./tools"

export const openai = new OpenAI({
    apiKey: process.env.OPENAI_API_KEY,
    dangerouslyAllowBrowser: true
})

const availableFunctions = {
    getCurrentWeather,
    getLocation
}

async function agent(query) {
    const messages = [
        { 
            role: "system", 
            content: "You are a helpful AI agent. Give highly specific answers based on information you're provided. Prefer to gather information with tools provided to you rather than giving basic, generic answers." 
        },
        { role: "user", content: query }
    ]

    const MAX_ITERATIONS = 5

    for (let i = 0; i < MAX_ITERATIONS; i++) {
        console.log(`Iteration #${i + 1}`)
        const response = await openai.chat.completions.create({
            model: "gpt-3.5-turbo-1106",
            messages,
            tools
        })

        const { finish_reason: finishReason, message } = response.choices[0]
        const { tool_calls: toolCalls } = message
        console.log(toolCalls)
        
        messages.push(message)
        
        if (finishReason === "stop") {
            console.log(message.content)
            console.log("AGENT ENDING")
            return
        } else if (finishReason === "tool_calls") {
            for (const toolCall of toolCalls) {
                const functionName = toolCall.function.name
                const functionToCall = availableFunctions[functionName]
                const functionArgs = JSON.parse(toolCall.function.arguments)
                const functionResponse = await functionToCall(functionArgs)
                console.log(functionResponse)
                messages.push({
                    tool_call_id: toolCall.id,
                    role: "tool",
                    name: functionName,
                    content: functionResponse
                })
            }
        }
    }
}

await agent("What's the current weather in my current location?")

/**
Expected Output:
The current weather in New York is sunny with a temperature of 75°F.
 */

tools.js - Tool Definitions and Implementations

export async function getCurrentWeather({ location }) {
    const weather = {
        location,
        temperature: "75",
        forecast: "sunny"
    }
    return JSON.stringify(weather)
}

export async function getLocation() {
  try {
    const response = await fetch('https://ipapi.co/json/')
    const text = await response.json()
    return JSON.stringify(text)
  } catch (err) {
    console.log(err)
  }
}

export const tools = [
    {
        type: "function",
        function: {
            name: "getCurrentWeather",
            description: "Get current weather",
            parameters: {
                type: "object",
                properties: {
                    location: {
                        type: "string",
                        description: "The location from where to get weather"
                    }
                },
                required: ["location"]
            }
        }
    },
    {
        type: "function",
        function: {
            name: "getLocation",
            description: "Get user's current location",
            parameters: {
                type: "object",
                properties: {}
            }
        }
    },
]

How OpenAI Function Calling Works

1. Tool Definition

Tools are defined using JSON Schema format:

{
    type: "function",
    function: {
        name: "getCurrentWeather",
        description: "Get current weather",
        parameters: {
            type: "object",
            properties: {
                location: {
                    type: "string",
                    description: "The location from where to get weather"
                }
            },
            required: ["location"]
        }
    }
}

2. API Request

The tools array is passed to the API:

const response = await openai.chat.completions.create({
    model: "gpt-3.5-turbo-1106",
    messages,
    tools  // ← Tools array passed here
})

3. Response Handling

OpenAI returns structured tool calls:

const { finish_reason: finishReason, message } = response.choices[0]
const { tool_calls: toolCalls } = message

// toolCalls structure:
[
    {
        id: "call_abc123",
        type: "function",
        function: {
            name: "getCurrentWeather",
            arguments: '{"location": "New York"}'
        }
    }
]

4. Function Execution

Execute the function and add result to conversation:

for (const toolCall of toolCalls) {
    const functionName = toolCall.function.name
    const functionToCall = availableFunctions[functionName]
    const functionArgs = JSON.parse(toolCall.function.arguments)
    const functionResponse = await functionToCall(functionArgs)
    
    messages.push({
        tool_call_id: toolCall.id,
        role: "tool",
        name: functionName,
        content: functionResponse
    })
}

Key Differences from ReAct

AspectReActOpenAI Function Calling
Tool SelectionManual text parsingAutomatic tool selection
Argument ExtractionRegex patternsJSON schema validation
Error HandlingManual parsing errorsStructured error responses
ReliabilityProne to parsing failuresMore reliable
ComplexityHigher implementation complexityLower implementation complexity

Example Execution Flow

Query: "What's the current weather in my current location?"

Iteration 1:

  1. OpenAI Response: tool_calls with getLocation function
  2. Function Execution: getLocation() returns user IP location
  3. Message Added: Tool response with location data

Iteration 2:

  1. OpenAI Response: tool_calls with getCurrentWeather function
  2. Function Execution: getCurrentWeather({location: "New York"}) returns weather
  3. Message Added: Tool response with weather data

Iteration 3:

  1. OpenAI Response: finish_reason: "stop" with final answer
  2. Agent Output: "The current weather in New York is sunny with a temperature of 75°F."

Best Practices

Tool Design

  • Clear Descriptions: Help OpenAI understand when to use each tool
  • Required Parameters: Specify which parameters are mandatory
  • Type Safety: Use proper JSON Schema types
  • Error Handling: Implement robust error handling in tool functions

Message Management

  • Context Preservation: Maintain full conversation history
  • Tool Responses: Add tool results with proper role and IDs
  • Iteration Limits: Prevent infinite loops with MAX_ITERATIONS

Error Handling

try {
    const functionResponse = await functionToCall(functionArgs)
    messages.push({
        tool_call_id: toolCall.id,
        role: "tool",
        name: functionName,
        content: functionResponse
    })
} catch (error) {
    messages.push({
        tool_call_id: toolCall.id,
        role: "tool",
        name: functionName,
        content: JSON.stringify({ error: error.message })
    })
}

Advanced Features

Parallel Tool Calls

OpenAI can call multiple tools simultaneously:

// OpenAI might return multiple tool_calls in one response
for (const toolCall of toolCalls) {
    // Execute each tool call
    const functionResponse = await functionToCall(functionArgs)
    // Add each response separately
}

Conditional Tool Usage

Design tools that can be used conditionally:

export const tools = [
    {
        type: "function",
        function: {
            name: "searchDatabase",
            description: "Search database for information",
            parameters: {
                type: "object",
                properties: {
                    query: { type: "string" },
                    filters: { type: "object" }
                },
                required: ["query"]
            }
        }
    }
]

OpenAI function calling provides a more robust and reliable way to build AI agents compared to manual ReAct implementations, with better error handling, type safety, and integration with OpenAI ecosystem.

Future: OpenAI Responses API

Note: OpenAI has introduced the new Responses API, which is an evolution of the Chat Completions API. The Responses API brings added simplicity and powerful agentic primitives to your integrations.

Key improvements in the Responses API:

  • Enhanced simplicity - More streamlined API interface
  • Powerful agentic primitives - Built-in capabilities for agent development
  • Better tool integration - Improved function calling mechanisms
  • Future-proof - Designed with agentic applications in mind

As this API matures, future implementations should migrate to the Responses API for the most current and capable agent development experience.

// Future implementation will use Responses API
// (API subject to change as it evolves)
const response = await openai.responses.create({
    // Enhanced parameters for better agent capabilities
})