mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: AzureAI Bing Connection Name Support (#1364)
* bing connection name support * error handling + unit tests * connection id and name handling
This commit is contained in:
committed by
GitHub
Unverified
parent
4cd81fe8e7
commit
7238cde5af
@@ -862,8 +862,9 @@ class AzureAIAgentClient(BaseChatClient):
|
||||
config_args["market"] = market
|
||||
if set_lang := additional_props.get("set_lang"):
|
||||
config_args["set_lang"] = set_lang
|
||||
# Bing Grounding
|
||||
# Bing Grounding (support both connection_id and connection_name)
|
||||
connection_id = additional_props.get("connection_id") or os.getenv("BING_CONNECTION_ID")
|
||||
connection_name = additional_props.get("connection_name") or os.getenv("BING_CONNECTION_NAME")
|
||||
# Custom Bing Search
|
||||
custom_connection_name = additional_props.get("custom_connection_name") or os.getenv(
|
||||
"BING_CUSTOM_CONNECTION_NAME"
|
||||
@@ -872,8 +873,26 @@ class AzureAIAgentClient(BaseChatClient):
|
||||
"BING_CUSTOM_INSTANCE_NAME"
|
||||
)
|
||||
bing_search: BingGroundingTool | BingCustomSearchTool | None = None
|
||||
if connection_id and not custom_connection_name and not custom_configuration_name:
|
||||
bing_search = BingGroundingTool(connection_id=connection_id, **config_args)
|
||||
if (
|
||||
(connection_id or connection_name)
|
||||
and not custom_connection_name
|
||||
and not custom_configuration_name
|
||||
):
|
||||
if connection_id:
|
||||
conn_id = connection_id
|
||||
elif connection_name:
|
||||
try:
|
||||
bing_connection = await self.project_client.connections.get(name=connection_name)
|
||||
except HttpResponseError as err:
|
||||
raise ServiceInitializationError(
|
||||
f"Bing connection '{connection_name}' not found in the Azure AI Project.",
|
||||
err,
|
||||
) from err
|
||||
else:
|
||||
conn_id = bing_connection.id
|
||||
else:
|
||||
raise ServiceInitializationError("Neither connection_id nor connection_name provided.")
|
||||
bing_search = BingGroundingTool(connection_id=conn_id, **config_args)
|
||||
if custom_connection_name and custom_configuration_name:
|
||||
try:
|
||||
bing_custom_connection = await self.project_client.connections.get(
|
||||
@@ -892,10 +911,11 @@ class AzureAIAgentClient(BaseChatClient):
|
||||
)
|
||||
if not bing_search:
|
||||
raise ServiceInitializationError(
|
||||
"Bing search tool requires either a 'connection_id' for Bing Grounding "
|
||||
"Bing search tool requires either 'connection_id' or 'connection_name' for Bing Grounding "
|
||||
"or both 'custom_connection_name' and 'custom_instance_name' for Custom Bing Search. "
|
||||
"These can be provided via the tool's additional_properties or environment variables: "
|
||||
"'BING_CONNECTION_ID', 'BING_CUSTOM_CONNECTION_NAME', 'BING_CUSTOM_INSTANCE_NAME'"
|
||||
"These can be provided via additional_properties or environment variables: "
|
||||
"'BING_CONNECTION_ID', 'BING_CONNECTION_NAME', 'BING_CUSTOM_CONNECTION_NAME', "
|
||||
"'BING_CUSTOM_INSTANCE_NAME'"
|
||||
)
|
||||
tool_definitions.extend(bing_search.definitions)
|
||||
case HostedCodeInterpreterTool():
|
||||
|
||||
@@ -46,7 +46,7 @@ from azure.ai.agents.models import (
|
||||
)
|
||||
from azure.ai.projects.models import ConnectionType
|
||||
from azure.core.credentials_async import AsyncTokenCredential
|
||||
from azure.core.exceptions import HttpResponseError
|
||||
from azure.core.exceptions import HttpResponseError, ResourceNotFoundError
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
from pydantic import BaseModel, Field, ValidationError
|
||||
from pytest import MonkeyPatch
|
||||
@@ -834,7 +834,7 @@ async def test_azure_ai_chat_client_prep_tools_web_search_bing_grounding(mock_ai
|
||||
|
||||
web_search_tool = HostedWebSearchTool(
|
||||
additional_properties={
|
||||
"connection_id": "test-connection-id",
|
||||
"connection_name": "test-connection-name",
|
||||
"count": 5,
|
||||
"freshness": "Day",
|
||||
"market": "en-US",
|
||||
@@ -842,6 +842,11 @@ async def test_azure_ai_chat_client_prep_tools_web_search_bing_grounding(mock_ai
|
||||
}
|
||||
)
|
||||
|
||||
# Mock connection get
|
||||
mock_connection = MagicMock()
|
||||
mock_connection.id = "test-connection-id"
|
||||
mock_ai_project_client.connections.get = AsyncMock(return_value=mock_connection)
|
||||
|
||||
# Mock BingGroundingTool
|
||||
with patch("agent_framework_azure_ai._chat_client.BingGroundingTool") as mock_bing_grounding:
|
||||
mock_bing_tool = MagicMock()
|
||||
@@ -857,6 +862,35 @@ async def test_azure_ai_chat_client_prep_tools_web_search_bing_grounding(mock_ai
|
||||
)
|
||||
|
||||
|
||||
async def test_azure_ai_chat_client_prep_tools_web_search_bing_grounding_with_connection_id(
|
||||
mock_ai_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _prep_tools with HostedWebSearchTool using Bing Grounding with connection_id (no HTTP call)."""
|
||||
|
||||
chat_client = create_test_azure_ai_chat_client(mock_ai_project_client, agent_id="test-agent")
|
||||
|
||||
web_search_tool = HostedWebSearchTool(
|
||||
additional_properties={
|
||||
"connection_id": "direct-connection-id",
|
||||
"count": 3,
|
||||
}
|
||||
)
|
||||
|
||||
# Mock BingGroundingTool
|
||||
with patch("agent_framework_azure_ai._chat_client.BingGroundingTool") as mock_bing_grounding:
|
||||
mock_bing_tool = MagicMock()
|
||||
mock_bing_tool.definitions = [{"type": "bing_grounding"}]
|
||||
mock_bing_grounding.return_value = mock_bing_tool
|
||||
|
||||
result = await chat_client._prep_tools([web_search_tool]) # type: ignore
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0] == {"type": "bing_grounding"}
|
||||
# Verify that connection_id was used directly (no HTTP call to connections.get)
|
||||
mock_ai_project_client.connections.get.assert_not_called()
|
||||
mock_bing_grounding.assert_called_once_with(connection_id="direct-connection-id", count=3)
|
||||
|
||||
|
||||
async def test_azure_ai_chat_client_prep_tools_web_search_custom_bing(mock_ai_project_client: MagicMock) -> None:
|
||||
"""Test _prep_tools with HostedWebSearchTool using Custom Bing Search."""
|
||||
|
||||
@@ -912,15 +946,23 @@ async def test_azure_ai_chat_client_prep_tools_web_search_custom_bing_connection
|
||||
await chat_client._prep_tools([web_search_tool]) # type: ignore
|
||||
|
||||
|
||||
async def test_azure_ai_chat_client_prep_tools_web_search_missing_config(mock_ai_project_client: MagicMock) -> None:
|
||||
"""Test _prep_tools with HostedWebSearchTool missing required configuration."""
|
||||
async def test_azure_ai_chat_client_prep_tools_web_search_bing_grounding_connection_error(
|
||||
mock_ai_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test _prep_tools with HostedWebSearchTool when Bing Grounding connection is not found."""
|
||||
|
||||
chat_client = create_test_azure_ai_chat_client(mock_ai_project_client, agent_id="test-agent")
|
||||
|
||||
# Web search tool with no connection configuration
|
||||
web_search_tool = HostedWebSearchTool()
|
||||
web_search_tool = HostedWebSearchTool(
|
||||
additional_properties={
|
||||
"connection_name": "nonexistent-bing-connection",
|
||||
}
|
||||
)
|
||||
|
||||
with pytest.raises(ServiceInitializationError, match="Bing search tool requires either a 'connection_id'"):
|
||||
# Mock connection get to raise HttpResponseError
|
||||
mock_ai_project_client.connections.get = AsyncMock(side_effect=HttpResponseError("Connection not found"))
|
||||
|
||||
with pytest.raises(ServiceInitializationError, match="Bing connection 'nonexistent-bing-connection' not found"):
|
||||
await chat_client._prep_tools([web_search_tool]) # type: ignore
|
||||
|
||||
|
||||
@@ -1397,6 +1439,28 @@ async def test_azure_ai_chat_client_create_agent_stream_submit_tool_outputs(
|
||||
assert final_thread_id == "test-thread"
|
||||
|
||||
|
||||
async def test_azure_ai_chat_client_setup_azure_ai_observability_resource_not_found(
|
||||
mock_ai_project_client: MagicMock,
|
||||
) -> None:
|
||||
"""Test setup_azure_ai_observability when Application Insights connection string is not found."""
|
||||
chat_client = create_test_azure_ai_chat_client(mock_ai_project_client, agent_id="test-agent")
|
||||
|
||||
# Mock telemetry.get_application_insights_connection_string to raise ResourceNotFoundError
|
||||
mock_ai_project_client.telemetry.get_application_insights_connection_string = AsyncMock(
|
||||
side_effect=ResourceNotFoundError("No Application Insights found")
|
||||
)
|
||||
|
||||
# Mock logger.warning to capture the warning message
|
||||
with patch("agent_framework_azure_ai._chat_client.logger") as mock_logger:
|
||||
await chat_client.setup_azure_ai_observability()
|
||||
|
||||
# Verify warning was logged
|
||||
mock_logger.warning.assert_called_once_with(
|
||||
"No Application Insights connection string found for the Azure AI Project, "
|
||||
"please call setup_observability() manually."
|
||||
)
|
||||
|
||||
|
||||
def get_weather(
|
||||
location: Annotated[str, Field(description="The location to get the weather for.")],
|
||||
) -> str:
|
||||
|
||||
@@ -38,16 +38,18 @@ Before running the examples, you need to set up your environment variables. You
|
||||
AZURE_AI_MODEL_DEPLOYMENT_NAME="your-model-deployment-name"
|
||||
```
|
||||
|
||||
3. For samples using Bing Grounding search (like `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`), you'll also need:
|
||||
3. For samples using Bing Grounding search (like `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`), you'll also need either:
|
||||
```
|
||||
BING_CONNECTION_ID="/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.CognitiveServices/accounts/{ai-service-name}/projects/{project-name}/connections/{connection-name}"
|
||||
BING_CONNECTION_NAME="bing-grounding-connection"
|
||||
# OR
|
||||
BING_CONNECTION_ID="your-bing-connection-id"
|
||||
```
|
||||
|
||||
To get your Bing connection ID:
|
||||
To get your Bing connection details:
|
||||
- Go to [Azure AI Foundry portal](https://ai.azure.com)
|
||||
- Navigate to your project's "Connected resources" section
|
||||
- Add a new connection for "Grounding with Bing Search"
|
||||
- Copy the connection ID
|
||||
- Copy either the connection name or ID
|
||||
|
||||
### Option 2: Using environment variables directly
|
||||
|
||||
@@ -56,7 +58,9 @@ Set the environment variables in your shell:
|
||||
```bash
|
||||
export AZURE_AI_PROJECT_ENDPOINT="your-project-endpoint"
|
||||
export AZURE_AI_MODEL_DEPLOYMENT_NAME="your-model-deployment-name"
|
||||
export BING_CONNECTION_ID="your-bing-connection-id" # Optional, only needed for web search samples
|
||||
export BING_CONNECTION_NAME="your-bing-connection-name" # Optional, only needed for web search samples
|
||||
# OR
|
||||
export BING_CONNECTION_ID="your-bing-connection-id" # Alternative to BING_CONNECTION_NAME
|
||||
```
|
||||
|
||||
### Required Variables
|
||||
@@ -66,4 +70,4 @@ export BING_CONNECTION_ID="your-bing-connection-id" # Optional, only needed for
|
||||
|
||||
### Optional Variables
|
||||
|
||||
- `BING_CONNECTION_ID`: Your Bing connection ID (required for `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`)
|
||||
- `BING_CONNECTION_NAME` or `BING_CONNECTION_ID`: Your Bing connection name or ID (required for `azure_ai_with_bing_grounding.py` and `azure_ai_with_multiple_tools.py`)
|
||||
|
||||
@@ -12,23 +12,22 @@ uses Bing Grounding search to find real-time information from the web.
|
||||
|
||||
Prerequisites:
|
||||
1. A connected Grounding with Bing Search resource in your Azure AI project
|
||||
2. Set the BING_CONNECTION_ID environment variable to your Bing connection ID
|
||||
Example: BING_CONNECTION_ID="/subscriptions/{subscription-id}/resourceGroups/{resource-group}/
|
||||
providers/Microsoft.CognitiveServices/accounts/{ai-service-name}/projects/{project-name}/
|
||||
connections/{connection-name}"
|
||||
2. Set either BING_CONNECTION_NAME or BING_CONNECTION_ID environment variable
|
||||
Example: BING_CONNECTION_NAME="bing-grounding-connection"
|
||||
Example: BING_CONNECTION_ID="your-bing-connection-id"
|
||||
|
||||
To set up Bing Grounding:
|
||||
1. Go to Azure AI Foundry portal (https://ai.azure.com)
|
||||
2. Navigate to your project's "Connected resources" section
|
||||
3. Add a new connection for "Grounding with Bing Search"
|
||||
4. Copy the connection ID and set it as the BING_CONNECTION_ID environment variable
|
||||
4. Copy either the connection name or ID and set the appropriate environment variable
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Main function demonstrating Azure AI agent with Bing Grounding search."""
|
||||
# 1. Create Bing Grounding search tool using HostedWebSearchTool
|
||||
# The connection_id will be automatically picked up from BING_CONNECTION_ID environment variable
|
||||
# The connection_name or ID will be automatically picked up from environment variable
|
||||
bing_search_tool = HostedWebSearchTool(
|
||||
name="Bing Grounding Search",
|
||||
description="Search the web for current information using Bing",
|
||||
|
||||
Reference in New Issue
Block a user