Migrating from Bing Search APIs to Azure OpenAI Agent with Grounding Bing Search

5
(3)

With Bing Search APIs scheduled for retirement on August 11, 2025, developers need a robust migration strategy to maintain search-powered AI applications. Microsoft has introduced a compelling alternative through Azure OpenAI Agents with the “Grounding with Bing Search” tool, seamlessly integrated with Semantic Kernel.

This comprehensive guide covers the complete migration process, from Azure AI Foundry project setup to implementing grounding capabilities in your .NET applications.

Strategic Advantages of Migration

The transition from standalone Bing Search APIs to Azure OpenAI Agent’s grounding capabilities delivers several key benefits:

  • Integrated Experience: Search results are automatically processed and contextually integrated with your AI responses
  • Improved Accuracy: Grounding helps reduce hallucinations by anchoring responses to real-time web data
  • Simplified Architecture: No need to manage separate search API calls and response processing
  • Better Cost Management: Consolidated billing and usage tracking through Azure OpenAI

Prerequisites

Ensure you have the following before beginning:

  • Active Azure subscription
  • Azure OpenAI services access
  • Visual Studio or Visual Studio Code with .NET 8.0 or later
  • Foundational knowledge of C# and Azure services

Step 1: Setting Up Azure AI Foundry

Create Your Azure AI Foundry

  1. Navigate to the Azure Portal
  2. Search for “Azure AI Foundry” and select it
  3. Click “Create” to start setting up your hub
  4. Configure the following settings:
    • Subscription: Select your Azure subscription
    • Resource Group: Create new or select existing
    • Region: Select a region that supports Azure OpenAI (e.g., East US, West Europe)
    • Default project name: Choose a descriptive name (e.g., “MyAIAgentProject”)
  5. Click “Review + Create” and then “Create”

Step 2: Setting Up Azure OpenAI Resources

Deploy Required Models

  1. In your AI Foundry project, navigate to “Models + Endpoints”
  2. Click “Deploy Model” and select:
    • GPT-4 or GPT-4o (or your preferred model) for your main language model, bear in mind that it doesn’t support GPT-4o-mini
    • Choose appropriate deployment settings based on your needs
  3. Note down the deployment names – you’ll need them in your code

Create a Grounding with Bing Search Resource

  1. Navigate to the Azure Portal
  2. Create a new “Grounding with Bing Search” resource
  3. Configure the resource settings:
    • Subscription: Select your Azure subscription
    • Resource Group: Use the same resource group as your AI Foundry project
    • Resource Name: Choose a descriptive name (e.g., “MyBingGroundingSearch”)
    • Region: Global
    • Pricing Tier: Select appropriate pricing tier based on your needs
  4. Click “Review + Create” and then “Create”
  5. Once created, note down the resource details – you’ll need them for connecting to your agent

Connect the Resource to Your AI Foundry Project

  1. In your AI Foundry project, go to “Connected Resources”
  2. Click “Add Connection”
  3. Select your Grounding with Bing Search resource
  4. This connection will allow your agents to use the Bing grounding capabilities

Step 3: .NET Project Setup

Install Required NuGet Packages

Create a new .NET console application or add to your existing project (I’m using .NET 9.0 and the latest versions of the Azure and Semantic Kernel packages (as of July 2025)):

<PackageReference Include="Azure.AI.Agents.Persistent" Version="1.1.0-beta.3" />
<PackageReference Include="Azure.AI.Projects" Version="1.0.0-beta.9" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.7" />

Configuration Setup

Create an appsettings.json file:

{
  "AzureAI": {
    "ConnectionString": "your-azure-ai-project-connection-string"
  },
  "AzureOpenAI": {
    "Endpoint": "https://your-resource-name.openai.azure.com",
    "ApiKey": "your-api-key",
    "DeploymentName": "gpt-4o"
  },
  "BingGrounding": {
    "ConnectionName": "your-bing-connection-name"
  }
}

Step 4: Implementation

Basic Agent Setup

Here’s how to create an Azure OpenAI Agent with Bing Search grounding:

using System.ClientModel;
using Azure.AI.Agents.Persistent;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;

namespace BingGroundingAgent;

public sealed class BingGroundingAgent
{
    private readonly IConfiguration _configuration;
    private readonly ILogger<BingGroundingAgent> _logger;
    private PersistentAgent? _agent;
    private PersistentAgentsClient? _persistentClient;
    private Connections? _connections;
    private AIProjectClient? _projectClient;

    public BingGroundingAgent(IConfiguration configuration, ILogger<BingGroundingAgent> logger)
    {
        _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async Task InitializeAsync()
    {
        try
        {
            // Validate configuration
            var connectionString =
                _configuration["AzureAI:ConnectionString"]
                ?? throw new InvalidOperationException(
                    "Azure AI connection string is not configured"
                );
            var connectionName =
                _configuration["BingGrounding:ConnectionName"]
                ?? throw new InvalidOperationException(
                    "Bing grounding connection name is not configured"
                );

            // Create Azure AI Project client
            _projectClient = new AIProjectClient(
                new Uri(connectionString),
                new DefaultAzureCredential()
            );
            _connections = _projectClient.GetConnectionsClient();

            // Create Azure AI persistent client
            _persistentClient = new PersistentAgentsClient(
                connectionString,
                new DefaultAzureCredential()
            );

            // Define the agent with Bing Search grounding
            var bingConnection = await GetConnectionByToolResourceNameAsync(connectionName);
            if (bingConnection == null)
            {
                throw new InvalidOperationException(
                    $"Failed to get Bing Search connection '{connectionName}'"
                );
            }

            var bingGroundingTool = new BingGroundingToolDefinition(
                new BingGroundingSearchToolParameters(
                    [new BingGroundingSearchConfiguration(bingConnection.Id)]
                )
            );
            var agentName = "Bing Grounding Agent";
            var agent = await this.GetAgentAsync(agentName);
            if (agent == null)
            {
                _agent = await _persistentClient.Administration.CreateAgentAsync(
                    model: deploymentName,
                    name: agentName,
                    instructions: """
                    You are a helpful assistant that can search the web for current information.
                    When users ask questions that require up-to-date information, use the Bing search tool
                    to find relevant information and provide accurate, grounded responses.
                    Always cite your sources when providing information from search results.
                    """,
                    tools: [bingGroundingTool]
                );
            }
            _logger.LogInformation(
                "Agent initialized successfully with Bing Search grounding. Agent ID: {AgentId}",
                _agent.Id
            );
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to initialize Bing Grounding Agent");
            throw;
        }
    }

    public async Task<AsyncCollectionResult<StreamingUpdate>> ProcessQueryAsync(string userQuery)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(userQuery);

        if (_persistentClient == null || _agent == null)
        {
            throw new InvalidOperationException(
                "Agent must be initialized before processing queries. Call InitializeAsync() first."
            );
        }

        try
        {
            _logger.LogInformation("Processing query: {Query}", userQuery);

            // Create a new thread for the conversation
            var thread = await _persistentClient.Threads.CreateThreadAsync();

            // Add user message
            await _persistentClient.Messages.CreateMessageAsync(
                thread.Value.Id,
                MessageRole.User,
                userQuery
            );

            // Get response from agent
            return _persistentClient.Runs.CreateRunStreamingAsync(thread.Value.Id, _agent.Id);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing query: {Query}", userQuery);
            throw;
        }
    }

    private async Task<PersistentAgent?> GetAgentAsync(string name)
    {
        try
        {
            var agent = await _persistentClient.Administration.GetAgentAsync(name);
            return agent;
        }
        catch (Exception ex)
        {
            this._logger.LogError(ex, "Failed to get agent {AgentName}", name);
            return null;
        }
    }

    private async Task<Connection?> GetConnectionByToolResourceNameAsync(string toolName)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(toolName);

        if (_connections == null)
        {
            throw new InvalidOperationException("Connections client is not initialized");
        }

        await foreach (
            var connection in _connections.GetConnectionsAsync(
                connectionType: ConnectionType.APIKey
            )
        )
        {
            if (string.Equals(connection.Name, toolName, StringComparison.OrdinalIgnoreCase))
            {
                return connection;
            }
        }
        _logger.LogWarning("Connection with name '{ConnectionName}' not found", toolName);
        return null;
    }
}

Program.cs Example

Here is how to run it:
using Azure.AI.Agents.Persistent;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var builder = Host.CreateApplicationBuilder(args);

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddEnvironmentVariables()
    .Build();

builder.Services.AddSingleton<IConfiguration>(configuration);
builder.Services.AddLogging(logging =>
{
    logging.AddConsole();
    logging.SetMinimumLevel(LogLevel.Information);
});

builder.Services.AddSingleton<BingGroundingAgent.BingGroundingAgent>();

var host = builder.Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
var agent = host.Services.GetRequiredService<BingGroundingAgent.BingGroundingAgent>();

try
{
    logger.LogInformation("Initializing Bing Grounding Agent...");
    await agent.InitializeAsync();

    while (true)
    {
        Console.Write("\nYou: ");
        var input = Console.ReadLine();
        if (string.IsNullOrEmpty(input) || input.ToLower() == "exit")
            break;

        logger.LogInformation("Processing query: {Query}", input);

        Console.Write("Assistant: ");
        await foreach (var update in await agent.ProcessQueryAsync(input))
        {
            if (update.UpdateKind == StreamingUpdateReason.MessageUpdated)
            {
                MessageContentUpdate messageContent = (MessageContentUpdate)update;
                Console.Write(messageContent.Text);
            }
        }
    }
}
catch (Exception ex)
{
    logger.LogError(ex, "An error occurred: {Message}", ex.Message);
}

logger.LogInformation("Application completed");
await host.StopAsync();

Step 5: Testing and Validation

Test Scenarios

  1. Current Events: Query recent news or developments
  2. Technical Information: Request current technical documentation
  3. Market Data: Retrieve real-time prices or statistics
  4. Comparison Queries: Perform comparisons requiring fresh data

Example Test Queries

  • What are the latest developments in AI technology this month?
  • What are the newest features in .NET 9?
  • What is the current stock price of Microsoft?

Migration Considerations

Key Differences from Bing Search APIs

  1. Response Format: Results are now integrated into conversational responses rather than raw JSON
  2. Rate Limiting: Managed through Azure OpenAI quotas instead of separate Bing API limits
  3. Pricing: Included in Azure OpenAI Agent pricing rather than separate search API costs
  4. Authentication: Uses Azure OpenAI credentials instead of Bing Search API keys

Conclusion

Migrating from Bing Search APIs to Azure OpenAI Agent with Grounding Bing Search delivers a more integrated and powerful solution for AI applications requiring real-time web information. The Semantic Kernel integration simplifies building sophisticated AI agents that seamlessly blend trained knowledge with current web data.

While the transition requires architectural adjustments, the benefits in accuracy, maintainability, and cost-effectiveness justify the investment. Begin planning your migration now to ensure a smooth transition before the August 11, 2025 deadline.

In my next post, I’ll explore Grounding with Bing Custom Search and Deep Research, examining advanced techniques for implementing sophisticated search capabilities and research workflows within AI applications.

Source Code

Access the complete source code for all examples in this blog post on GitHub: GitHub Repository Link

Resources

How useful was this post?

Click on a star to rate it!

Average rating 5 / 5. Vote count: 3

No votes so far! Be the first to rate this post.