🎯 What You’ll Build

By the end of this guide, you’ll have:
  • βœ… A custom async OpenAI client configured for Sonar API
  • βœ… An intelligent agent with function calling capabilities
  • βœ… A working example that fetches real-time information
  • βœ… Production-ready integration patterns

πŸ—οΈ Architecture Overview

This integration allows you to:
  1. Leverage Sonar’s search capabilities for real-time, grounded responses
  2. Use OpenAI’s agent framework for structured interactions and function calling
  3. Combine both for powerful, context-aware applications

πŸ“‹ Prerequisites

Before starting, ensure you have:
  • Python 3.7+ installed
  • Perplexity API Key - Get one here
  • OpenAI Agents SDK access and familiarity

πŸš€ Installation

Install the required dependencies:
pip install openai nest-asyncio
:::info The nest-asyncio package is required for running async code in environments like Jupyter notebooks that already have an event loop running. :::

βš™οΈ Environment Setup

Configure your environment variables:
# Required: Your Perplexity API key
export EXAMPLE_API_KEY="your-perplexity-api-key"

# Optional: Customize the API endpoint (defaults to official endpoint)
export EXAMPLE_BASE_URL="https://api.perplexity.ai"

# Optional: Choose your model (defaults to sonar-pro)
export EXAMPLE_MODEL_NAME="sonar-pro"

πŸ’» Complete Implementation

Here’s the full implementation with detailed explanations:
# Import necessary standard libraries
import asyncio  # For running asynchronous code
import os       # To access environment variables

# Import AsyncOpenAI for creating an async client
from openai import AsyncOpenAI

# Import custom classes and functions from the agents package.
# These handle agent creation, model interfacing, running agents, and more.
from agents import Agent, OpenAIChatCompletionsModel, Runner, function_tool, set_tracing_disabled

# Retrieve configuration from environment variables or use defaults
BASE_URL = os.getenv("EXAMPLE_BASE_URL") or "https://api.perplexity.ai"
API_KEY = os.getenv("EXAMPLE_API_KEY") 
MODEL_NAME = os.getenv("EXAMPLE_MODEL_NAME") or "sonar-pro"

# Validate that all required configuration variables are set
if not BASE_URL or not API_KEY or not MODEL_NAME:
    raise ValueError(
        "Please set EXAMPLE_BASE_URL, EXAMPLE_API_KEY, EXAMPLE_MODEL_NAME via env var or code."
    )

# Initialize the custom OpenAI async client with the specified BASE_URL and API_KEY.
client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)

# Disable tracing to avoid using a platform tracing key; adjust as needed.
set_tracing_disabled(disabled=True)

# Define a function tool that the agent can call.
# The decorator registers this function as a tool in the agents framework.
@function_tool
def get_weather(city: str):
    """
    Simulate fetching weather data for a given city.
    
    Args:
        city (str): The name of the city to retrieve weather for.
        
    Returns:
        str: A message with weather information.
    """
    print(f"[debug] getting weather for {city}")
    return f"The weather in {city} is sunny."

# Import nest_asyncio to support nested event loops
import nest_asyncio

# Apply the nest_asyncio patch to enable running asyncio.run() 
# even if an event loop is already running.
nest_asyncio.apply()

async def main():
    """
    Main asynchronous function to set up and run the agent.
    
    This function creates an Agent with a custom model and function tools,
    then runs a query to get the weather in Tokyo.
    """
    # Create an Agent instance with:
    # - A name ("Assistant")
    # - Custom instructions ("Be precise and concise.")
    # - A model built from OpenAIChatCompletionsModel using our client and model name.
    # - A list of tools; here, only get_weather is provided.
    agent = Agent(
        name="Assistant",
        instructions="Be precise and concise.",
        model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
        tools=[get_weather],
    )

    # Execute the agent with the sample query.
    result = await Runner.run(agent, "What's the weather in Tokyo?")
    
    # Print the final output from the agent.
    print(result.final_output)

# Standard boilerplate to run the async main() function.
if __name__ == "__main__":
    asyncio.run(main())

πŸ” Code Breakdown

Let’s examine the key components:

1. Client Configuration

client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
This creates an async OpenAI client pointed at Perplexity’s Sonar API. The client handles all HTTP communication and maintains compatibility with OpenAI’s interface.

2. Function Tools

@function_tool
def get_weather(city: str):
    """Simulate fetching weather data for a given city."""
    return f"The weather in {city} is sunny."
Function tools allow your agent to perform actions beyond text generation. In production, you’d replace this with real API calls.

3. Agent Creation

agent = Agent(
    name="Assistant",
    instructions="Be precise and concise.",
    model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
    tools=[get_weather],
)
The agent combines Sonar’s language capabilities with your custom tools and instructions.

πŸƒβ€β™‚οΈ Running the Example

  1. Set your environment variables:
    export EXAMPLE_API_KEY="your-perplexity-api-key"
    
  2. Save the code to a file (e.g., pplx_openai_agent.py)
  3. Run the script:
    python pplx_openai_agent.py
    
Expected Output:
[debug] getting weather for Tokyo
The weather in Tokyo is sunny.

πŸ”§ Customization Options

Different Sonar Models

Choose the right model for your use case:
# For quick, lightweight queries
MODEL_NAME = "sonar"

# For complex research and analysis (default)
MODEL_NAME = "sonar-pro"

# For deep reasoning tasks
MODEL_NAME = "sonar-reasoning-pro"

Custom Instructions

Tailor the agent’s behavior:
agent = Agent(
    name="Research Assistant",
    instructions="""
    You are a research assistant specializing in academic literature.
    Always provide citations and verify information through multiple sources.
    Be thorough but concise in your responses.
    """,
    model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
    tools=[search_papers, get_citations],
)

Multiple Function Tools

Add more capabilities:
@function_tool
def search_web(query: str):
    """Search the web for current information."""
    # Implementation here
    pass

@function_tool
def analyze_data(data: str):
    """Analyze structured data."""
    # Implementation here
    pass

agent = Agent(
    name="Multi-Tool Assistant",
    instructions="Use the appropriate tool for each task.",
    model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
    tools=[get_weather, search_web, analyze_data],
)

πŸš€ Production Considerations

Error Handling

async def robust_main():
    try:
        agent = Agent(
            name="Assistant",
            instructions="Be helpful and accurate.",
            model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
            tools=[get_weather],
        )
        
        result = await Runner.run(agent, "What's the weather in Tokyo?")
        return result.final_output
        
    except Exception as e:
        print(f"Error running agent: {e}")
        return "Sorry, I encountered an error processing your request."

Rate Limiting

import aiohttp
from openai import AsyncOpenAI

# Configure client with custom timeout and retry settings
client = AsyncOpenAI(
    base_url=BASE_URL, 
    api_key=API_KEY,
    timeout=30.0,
    max_retries=3
)

Logging and Monitoring

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@function_tool
def get_weather(city: str):
    logger.info(f"Fetching weather for {city}")
    # Implementation here

πŸ”— Advanced Integration Patterns

Streaming Responses

For real-time applications:
async def stream_agent_response(query: str):
    agent = Agent(
        name="Streaming Assistant",
        instructions="Provide detailed, step-by-step responses.",
        model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
        tools=[get_weather],
    )
    
    async for chunk in Runner.stream(agent, query):
        print(chunk, end='', flush=True)

Context Management

For multi-turn conversations:
class ConversationManager:
    def __init__(self):
        self.agent = Agent(
            name="Conversational Assistant",
            instructions="Maintain context across multiple interactions.",
            model=OpenAIChatCompletionsModel(model=MODEL_NAME, openai_client=client),
            tools=[get_weather],
        )
        self.conversation_history = []
    
    async def chat(self, message: str):
        result = await Runner.run(self.agent, message)
        self.conversation_history.append({"user": message, "assistant": result.final_output})
        return result.final_output

⚠️ Important Notes

  • API Costs: Monitor your usage as both Perplexity and OpenAI Agents may incur costs
  • Rate Limits: Respect API rate limits and implement appropriate backoff strategies
  • Error Handling: Always implement robust error handling for production applications
  • Security: Keep your API keys secure and never commit them to version control

🎯 Use Cases

This integration pattern is perfect for:
  • πŸ” Research Assistants - Combining real-time search with structured responses
  • πŸ“Š Data Analysis Tools - Using Sonar for context and agents for processing
  • πŸ€– Customer Support - Grounded responses with function calling capabilities
  • πŸ“š Educational Applications - Real-time information with interactive features

πŸ“š References


Ready to build? This integration opens up powerful possibilities for creating intelligent, grounded agents. Start with the basic example and gradually add more sophisticated tools and capabilities! πŸš€