Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Note
This document refers to the Microsoft Foundry (classic) agents.
🔍 View the new Grounding with Bing Search documentation. Agents (classic) are deprecated and retire on March 31, 2027. Use the new agents in the generally available Foundry Agent Service. Follow the migration guide to update your workloads.
This article provides step-by-step instructions and code samples for using the Grounding with Bing Custom Search tool in the Foundry Agent Service.
Prerequisites
- A Grounding with Bing Custom Search resource and configuration. Creating the resource requires the Contributor role scoped to the resource group where you create it. Activate this role only for provisioning, preferably through Microsoft Entra Privileged Identity Management (PIM) for Azure resources, and deactivate it after you create the resource and configuration.
- The
2025-05-15-previewAgent Service API. - Sign in locally with
az loginsoDefaultAzureCredentialcan authenticate. - For Python 3.9 or later, install
pip install --pre "azure-ai-projects==1.1.0b4" "azure-ai-agents==1.2.0b6" azure-identity. - For REST, install
jqto create request bodies, capture IDs, and inspect responses. - Don't use
azure-ai-projects2.x with these classic threads-and-runs samples. - For the Python samples, collect these values:
- Your Foundry Project endpoint. In the Foundry portal, open your project's Overview page, and then select Libraries > Foundry. Save the endpoint to an environment variable named
PROJECT_ENDPOINT. - The name of your Grounding with Bing Custom Search resource. In the Foundry portal, select Management center > Connected resources, and save the resource name to an environment variable named
BING_CUSTOM_CONNECTION_NAME. - The name of your Grounding with Bing Custom Search configuration, which contains the URLs you want to allow or disallow. In the Azure portal, open the overview page for your resource, select Configurations, and then select your configuration. Save the configuration name to an environment variable named
BING_CUSTOM_INSTANCE_NAME. - Your model deployment name. In the Foundry portal, select Models + Endpoints, and save the deployment name to an environment variable named
MODEL_DEPLOYMENT_NAME.
- Your Foundry Project endpoint. In the Foundry portal, open your project's Overview page, and then select Libraries > Foundry. Save the endpoint to an environment variable named
Grounding with Bing Custom Search incurs separate charges, requires publicly indexed content, and sends queries outside the Azure compliance boundary. Private endpoints and VPN routing don't apply to Bing traffic. Display returned citations without altering their URLs.
Go to the Agents screen for your agent in the Microsoft Foundry portal. Scroll down the Setup pane on the right to knowledge. Then select Add.
Select the Grounding with Bing Custom Search tool.
Select to create a new connection or use an existing connection.
- For a new connection, select your Grounding with Bing Custom Search resource.
After you connect to a resource, select the configuration name.
Save the tool and start chatting with your agent.
Create a project client
Create a client object that holds the connection string for connecting to your AI project and other resources.
import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from azure.ai.agents.models import BingCustomSearchTool
# Create an Azure AI Client from an endpoint, copied from your Foundry project.
# You need to login to Azure subscription via Azure CLI and set the environment variables
project_endpoint = os.environ["PROJECT_ENDPOINT"] # Ensure the PROJECT_ENDPOINT environment variable is set
# Create an AIProjectClient instance
project_client = AIProjectClient(
endpoint=project_endpoint,
credential=DefaultAzureCredential(),
)
Create an agent with the Grounding with Bing Custom Search tool enabled
To make the Grounding with Bing Custom Search tool available to your agent, use a connection to initialize the tool and attach it to the agent.
bing_custom_connection = project_client.connections.get(name=os.environ["BING_CUSTOM_CONNECTION_NAME"])
conn_id = bing_custom_connection.id
print(conn_id)
configuration_name = os.environ["BING_CUSTOM_INSTANCE_NAME"]
# Initialize Bing Custom Search tool with connection id and configuration name
bing_custom_tool = BingCustomSearchTool(connection_id=conn_id, instance_name=configuration_name)
# Keep the client open until the final cleanup step.
agents_client = project_client.agents
agent = agents_client.create_agent(
model=os.environ["MODEL_DEPLOYMENT_NAME"],
name="my-agent",
instructions="You are a helpful agent",
tools=bing_custom_tool.definitions,
)
print(f"Created agent, ID: {agent.id}")
Create a thread
# Create thread for communication
thread = agents_client.threads.create()
print(f"Created thread, ID: {thread.id}")
# Create message to thread
message = agents_client.messages.create(
thread_id=thread.id,
role="user",
content="How many medals did the USA win in the 2024 summer olympics?",
)
print(f"Created message, ID: {message.id}")
Create a run and check the output
Create a run and observe that the model uses the Grounding with Bing Search tool to provide a response to the user's question.
# Create and process Agent run in thread with tools
run = agents_client.runs.create_and_process(thread_id=thread.id, agent_id=agent.id)
print(f"Run finished with status: {run.status}")
if run.status == "failed":
print(f"Run failed: {run.last_error}")
# Fetch and log all messages
messages = agents_client.messages.list(thread_id=thread.id)
for msg in messages:
if msg.text_messages:
for text_message in msg.text_messages:
print(f"Agent response: {text_message.text.value}")
for annotation in msg.url_citation_annotations:
print(f"URL Citation: [{annotation.url_citation.title}]({annotation.url_citation.url})")
agents_client.threads.delete(thread.id)
agents_client.delete_agent(agent.id)
project_client.close()
print("Deleted thread and agent, and closed the project client")
Expected output
The response text depends on your custom search domains. A successful run ends with output similar to:
Run finished with status: RunStatus.COMPLETED
Agent response: <grounded answer>
URL Citation: [<source title>](<source URL>)
Deleted thread and agent, and closed the project client
Understand URL citations in the response
When the agent response includes URL citations, you can show them to users as a list of references.
In the Python SDK, you can find the answer text in msg.text_messages[*].text.value. You can find the citations in msg.url_citation_annotations[*].url_citation.
Important
- This REST API enables developers to invoke the Grounding with Bing Custom Search tool through the Agent Service. It doesn't send calls to the Grounding with Bing Custom Search API directly.
- Your connection ID should be in this format:
/subscriptions/<sub-id>/resourceGroups/<your-rg-name>/providers/Microsoft.CognitiveServices/accounts/<your-ai-services-name>/projects/<your-project-name>/connections/<your-bing-connection-name>.
Complete the REST API quickstart to set AGENT_TOKEN and AZURE_AI_FOUNDRY_PROJECT_ENDPOINT. Then set the classic preview version and tool values:
export API_VERSION="2025-05-15-preview"
export MODEL_DEPLOYMENT_NAME="<your-model-deployment-name>"
export BING_CUSTOM_CONNECTION_ID="/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.CognitiveServices/accounts/<foundry-resource>/projects/<project>/connections/<bing-connection>"
export BING_CUSTOM_INSTANCE_NAME="<your-custom-search-configuration-name>"
Create an agent
Create an agent with the Grounding with Bing Custom Search tool, and capture its ID:
AGENT_ID=$(
jq -n \
--arg model "$MODEL_DEPLOYMENT_NAME" \
--arg connection "$BING_CUSTOM_CONNECTION_ID" \
--arg instance "$BING_CUSTOM_INSTANCE_NAME" \
'{instructions:"Answer with citations from the configured domains.",
name:"my-custom-search-agent", model:$model,
tools:[{type:"bing_custom_search", bing_custom_search:{
search_configurations:[{connection_id:$connection,
instance_name:$instance, count:7, market:"en-US",
set_lang:"en"}]}}]}' |
curl --silent --show-error --fail-with-body --request POST \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/assistants?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @- |
jq -r '.id'
)
printf 'Agent ID: %s\n' "$AGENT_ID"
Create a thread and add a question
THREAD_ID=$(
curl --silent --show-error --fail-with-body --request POST \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
--data '{}' |
jq -r '.id'
)
curl --silent --show-error --fail-with-body --request POST \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/$THREAD_ID/messages?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
--data '{"role":"user","content":"<ask a question answered by your configured domains>"}' \
| jq -r '"Message ID: \(.id)"'
Run the agent
Start a run, capture its ID, and poll until the run reaches a terminal state:
RUN_ID=$(
jq -n --arg agent "$AGENT_ID" '{assistant_id:$agent}' |
curl --silent --show-error --fail-with-body --request POST \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/$THREAD_ID/runs?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @- |
jq -r '.id'
)
while true; do
RUN_STATUS=$(curl --silent --show-error --fail-with-body \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/$THREAD_ID/runs/$RUN_ID?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN" | jq -r '.status')
[[ "$RUN_STATUS" != "queued" && "$RUN_STATUS" != "in_progress" ]] && break
sleep 1
done
printf 'Run status: %s\n' "$RUN_STATUS"
Verify the response and citations
Retrieve the assistant message and print its answer and citations:
MESSAGES=$(
curl --silent --show-error --fail-with-body \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/$THREAD_ID/messages?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN"
)
jq -r '.data[] | select(.role == "assistant") | .content[] |
select(.type == "text") | "Answer: \(.text.value)",
(.text.annotations[]? | select(.type == "url_citation") |
"Citation: [\(.url_citation.title)](\(.url_citation.url))")' \
<<< "$MESSAGES"
Expected output resembles the following example. The answer and citations depend on your configured domains:
Agent ID: <agent-id>
Message ID: <message-id>
Run status: completed
Answer: <grounded answer>
Citation: [<source title>](<source URL>)
Clean up resources
Delete the thread and agent after you verify the response:
curl --silent --show-error --fail-with-body --request DELETE \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/threads/$THREAD_ID?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN"
curl --silent --show-error --fail-with-body --request DELETE \
--url "$AZURE_AI_FOUNDRY_PROJECT_ENDPOINT/assistants/$AGENT_ID?api-version=$API_VERSION" \
-H "Authorization: Bearer $AGENT_TOKEN"
printf 'Deleted thread and agent.\n'
Troubleshooting
| Symptom | Resolution |
|---|---|
ImportError for BingCustomSearchTool |
Install the preview package versions listed in Prerequisites. Current azure-ai-projects 2.x doesn't expose the classic threads-and-runs API used here. |
| The run fails with a connection error | Confirm the project connection ID and custom search configuration name, and verify the Bing resource is available to the project. |
| The run completes without citations | Confirm your allowed domains are publicly indexed by Bing and contain results relevant to the question. |
| Requests time out from a secured network | Allow public outbound Bing traffic. VPN and private endpoint routing don't carry Bing requests. |