Skip to content

Commit ff61714

Browse files
authored
Fix AI Search sample (Azure#48818)
* Fix AI Search sample * Fix * Fix * Fix link
1 parent 3d89952 commit ff61714

File tree

2 files changed

+122
-8
lines changed

2 files changed

+122
-8
lines changed

sdk/ai/Azure.AI.Projects/README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Use the AI Projects client library to:
2727
- [File search](#file-search)
2828
- [Enterprise File Search](#create-agent-with-enterprise-file-search)
2929
- [Code interpreter attachment](#create-message-with-code-interpreter-attachment)
30+
- [Azure AI Search](#create-agent-with-azure-ai-search)
3031
- [Function call](#function-call)
3132
- [Azure function call](#azure-function-call)
3233
- [Azure Function Call](#create-agent-with-azure-function-call)
@@ -314,6 +315,92 @@ var attachment = new MessageAttachment(
314315
);
315316
```
316317

318+
#### Create Agent with Azure AI Search
319+
320+
Azure AI Search is an enterprise search system for high-performance applications.
321+
It integrates with Azure OpenAI Service and Azure Machine Learning, offering advanced
322+
search technologies like vector search and full-text search. Ideal for knowledge base
323+
insights, information discovery, and automation. Creating an Agent with Azure AI
324+
Search requires an existing Azure AI Search Index. For more information and setup
325+
guides, see [Azure AI Search Tool Guide](https://learn.microsoft.com/azure/ai-services/agents/how-to/tools/azure-ai-search).
326+
327+
```C# Snippet:CreateAgentWithAzureAISearchTool
328+
ListConnectionsResponse connections = await projectClient.GetConnectionsClient().GetConnectionsAsync(ConnectionType.AzureAISearch).ConfigureAwait(false);
329+
330+
if (connections?.Value == null || connections.Value.Count == 0)
331+
{
332+
throw new InvalidOperationException("No connections found for the Azure AI Search.");
333+
}
334+
335+
ConnectionResponse connection = connections.Value[0];
336+
337+
ToolResources searchResource = new ToolResources
338+
{
339+
AzureAISearch = new AzureAISearchResource
340+
{
341+
IndexList = { new IndexResource(connection.Id, "sample_index") }
342+
}
343+
};
344+
345+
AgentsClient agentClient = projectClient.GetAgentsClient();
346+
347+
Response<Agent> agentResponse = await agentClient.CreateAgentAsync(
348+
model: modelName,
349+
name: "my-assistant",
350+
instructions: "You are a helpful assistant.",
351+
tools: new List<ToolDefinition> { new AzureAISearchToolDefinition() },
352+
toolResources: searchResource);
353+
Agent agent = agentResponse.Value;
354+
```
355+
356+
If the agent has found the relevant information in the index, the reference
357+
and annotation will be provided in the message response. In the example above, we replace
358+
the reference placeholder by the actual reference and url. Please note, that to
359+
get sensible result, the index needs to have fields "title" and "url".
360+
361+
```C# Snippet:PopulateReferencesAgentWithAzureAISearchTool
362+
PageableList<ThreadMessage> messages = await agentClient.GetMessagesAsync(
363+
threadId: thread.Id,
364+
order: ListSortOrder.Ascending
365+
);
366+
367+
// Note: messages iterate from newest to oldest, with the messages[0] being the most recent
368+
foreach (ThreadMessage threadMessage in messages)
369+
{
370+
Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
371+
foreach (MessageContent contentItem in threadMessage.ContentItems)
372+
{
373+
if (contentItem is MessageTextContent textItem)
374+
{
375+
// We need to annotate only Agent messages.
376+
if (threadMessage.Role == MessageRole.Agent && textItem.Annotations.Count > 0)
377+
{
378+
string annotatedText = textItem.Text;
379+
foreach (MessageTextAnnotation annotation in textItem.Annotations)
380+
{
381+
if (annotation is MessageTextUrlCitationAnnotation urlAnnotation)
382+
{
383+
annotatedText = annotatedText.Replace(
384+
urlAnnotation.Text,
385+
$" [see {urlAnnotation.UrlCitation.Title}] ({urlAnnotation.UrlCitation.Url})");
386+
}
387+
}
388+
Console.Write(annotatedText);
389+
}
390+
else
391+
{
392+
Console.Write(textItem.Text);
393+
}
394+
}
395+
else if (contentItem is MessageImageFileContent imageFileItem)
396+
{
397+
Console.Write($"<image from ID: {imageFileItem.FileId}");
398+
}
399+
Console.WriteLine();
400+
}
401+
}
402+
```
403+
317404
#### Function call
318405

319406
Tools that reference caller-defined capabilities as functions can be provided to an agent to allow it to

sdk/ai/Azure.AI.Projects/tests/Samples/Agent/Sample_Agents_Azure_AI_Search.cs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Azure.Core.TestFramework;
1010
using NUnit.Framework;
1111
using System.Collections.Generic;
12+
using NUnit.Framework.Internal;
1213

1314
namespace Azure.AI.Projects.Tests;
1415

@@ -18,13 +19,14 @@ public partial class Sample_Agents_Azure_AI_Search : SamplesBase<AIProjectsTestE
1819
public async Task AzureAISearchExample()
1920
{
2021
var connectionString = TestEnvironment.AzureAICONNECTIONSTRING;
22+
var modelName = TestEnvironment.MODELDEPLOYMENTNAME;
2123

2224
var clientOptions = new AIProjectClientOptions();
2325

2426
// Adding the custom headers policy
2527
clientOptions.AddPolicy(new CustomHeadersPolicy(), HttpPipelinePosition.PerCall);
2628
var projectClient = new AIProjectClient(connectionString, new DefaultAzureCredential(), clientOptions);
27-
29+
#region Snippet:CreateAgentWithAzureAISearchTool
2830
ListConnectionsResponse connections = await projectClient.GetConnectionsClient().GetConnectionsAsync(ConnectionType.AzureAISearch).ConfigureAwait(false);
2931

3032
if (connections?.Value == null || connections.Value.Count == 0)
@@ -45,13 +47,13 @@ public async Task AzureAISearchExample()
4547
AgentsClient agentClient = projectClient.GetAgentsClient();
4648

4749
Response<Agent> agentResponse = await agentClient.CreateAgentAsync(
48-
model: "gpt-4",
50+
model: modelName,
4951
name: "my-assistant",
5052
instructions: "You are a helpful assistant.",
5153
tools: new List<ToolDefinition> { new AzureAISearchToolDefinition() },
5254
toolResources: searchResource);
5355
Agent agent = agentResponse.Value;
54-
56+
#endregion
5557
// Create thread for communication
5658
Response<AgentThread> threadResponse = await agentClient.CreateThreadAsync();
5759
AgentThread thread = threadResponse.Value;
@@ -60,7 +62,7 @@ public async Task AzureAISearchExample()
6062
Response<ThreadMessage> messageResponse = await agentClient.CreateMessageAsync(
6163
thread.Id,
6264
MessageRole.User,
63-
"Hello, send an email with the datetime and weather information in New York?");
65+
"What is the temperature rating of the cozynights sleeping bag?");
6466
ThreadMessage message = messageResponse.Value;
6567

6668
// Run the agent
@@ -74,9 +76,15 @@ public async Task AzureAISearchExample()
7476
while (runResponse.Value.Status == RunStatus.Queued
7577
|| runResponse.Value.Status == RunStatus.InProgress);
7678

77-
Response<PageableList<ThreadMessage>> afterRunMessagesResponse
78-
= await agentClient.GetMessagesAsync(thread.Id);
79-
IReadOnlyList<ThreadMessage> messages = afterRunMessagesResponse.Value.Data;
79+
Assert.AreEqual(
80+
RunStatus.Completed,
81+
runResponse.Value.Status,
82+
runResponse.Value.LastError?.Message);
83+
#region Snippet:PopulateReferencesAgentWithAzureAISearchTool
84+
PageableList<ThreadMessage> messages = await agentClient.GetMessagesAsync(
85+
threadId: thread.Id,
86+
order: ListSortOrder.Ascending
87+
);
8088

8189
// Note: messages iterate from newest to oldest, with the messages[0] being the most recent
8290
foreach (ThreadMessage threadMessage in messages)
@@ -86,7 +94,25 @@ Response<PageableList<ThreadMessage>> afterRunMessagesResponse
8694
{
8795
if (contentItem is MessageTextContent textItem)
8896
{
89-
Console.Write(textItem.Text);
97+
// We need to annotate only Agent messages.
98+
if (threadMessage.Role == MessageRole.Agent && textItem.Annotations.Count > 0)
99+
{
100+
string annotatedText = textItem.Text;
101+
foreach (MessageTextAnnotation annotation in textItem.Annotations)
102+
{
103+
if (annotation is MessageTextUrlCitationAnnotation urlAnnotation)
104+
{
105+
annotatedText = annotatedText.Replace(
106+
urlAnnotation.Text,
107+
$" [see {urlAnnotation.UrlCitation.Title}] ({urlAnnotation.UrlCitation.Url})");
108+
}
109+
}
110+
Console.Write(annotatedText);
111+
}
112+
else
113+
{
114+
Console.Write(textItem.Text);
115+
}
90116
}
91117
else if (contentItem is MessageImageFileContent imageFileItem)
92118
{
@@ -95,5 +121,6 @@ Response<PageableList<ThreadMessage>> afterRunMessagesResponse
95121
Console.WriteLine();
96122
}
97123
}
124+
#endregion
98125
}
99126
}

0 commit comments

Comments
 (0)