@@ -103,18 +103,21 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
103
103
using OpenAI.Chat;
104
104
105
105
namespace AzureSearch.Quickstart
106
- { class Program
106
+ {
107
+ class Program
107
108
{
108
109
static async Task Main(string[] args)
109
- {
110
+ {
110
111
// Load environment variables from .env file
111
112
// Ensure you have a .env file in the same directory with the required variables.
112
113
DotEnv.Load ();
113
114
114
115
string endpoint = Environment.GetEnvironmentVariable(" AZURE_SEARCH_ENDPOINT" )
115
116
?? throw new InvalidOperationException(" AZURE_SEARCH_ENDPOINT is not set." );
116
117
string azureOpenAIEndpoint = Environment.GetEnvironmentVariable(" AZURE_OPENAI_ENDPOINT" )
117
- ?? throw new InvalidOperationException(" AZURE_OPENAI_ENDPOINT is not set." ); string azureOpenAIGptDeployment = " gpt-4.1-mini" ;
118
+ ?? throw new InvalidOperationException(" AZURE_OPENAI_ENDPOINT is not set." );
119
+
120
+ string azureOpenAIGptDeployment = " gpt-4.1-mini" ;
118
121
string azureOpenAIGptModel = " gpt-4.1-mini" ;
119
122
string azureOpenAIEmbeddingDeployment = " text-embedding-3-large" ;
120
123
string azureOpenAIEmbeddingModel = " text-embedding-3-large" ;
@@ -123,15 +126,35 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
123
126
string agentName = " earth-search-agent" ;
124
127
125
128
var credential = new DefaultAzureCredential ();
129
+
126
130
// Define the fields for the index
127
131
var fields = new List< SearchField>
128
132
{
129
- new SimpleField(" id" , SearchFieldDataType.String) { IsKey = true, IsFilterable = true, IsSortable = true, IsFacetable = true },
130
- new SearchField(" page_chunk" , SearchFieldDataType.String) { IsFilterable = false, IsSortable = false, IsFacetable = false },
131
- new SearchField(" page_embedding_text_3_large" , SearchFieldDataType.Collection(SearchFieldDataType.Single)) { VectorSearchDimensions = 3072, VectorSearchProfileName = " hnsw_text_3_large" },
132
- new SimpleField(" page_number" , SearchFieldDataType.Int32) { IsFilterable = true, IsSortable = true, IsFacetable = true }
133
- };
134
- // Define the vectorizer
133
+ new SimpleField(" id" , SearchFieldDataType.String)
134
+ {
135
+ IsKey = true,
136
+ IsFilterable = true,
137
+ IsSortable = true,
138
+ IsFacetable = true
139
+ },
140
+ new SearchField(" page_chunk" , SearchFieldDataType.String)
141
+ {
142
+ IsFilterable = false,
143
+ IsSortable = false,
144
+ IsFacetable = false
145
+ },
146
+ new SearchField(" page_embedding_text_3_large" , SearchFieldDataType.Collection(SearchFieldDataType.Single))
147
+ {
148
+ VectorSearchDimensions = 3072,
149
+ VectorSearchProfileName = " hnsw_text_3_large"
150
+ },
151
+ new SimpleField(" page_number" , SearchFieldDataType.Int32)
152
+ {
153
+ IsFilterable = true,
154
+ IsSortable = true,
155
+ IsFacetable = true
156
+ }
157
+ }; // Define the vectorizer
135
158
var vectorizer = new AzureOpenAIVectorizer(vectorizerName: " azure_openai_text_3_large" )
136
159
{
137
160
Parameters = new AzureOpenAIVectorizerParameters
@@ -191,7 +214,7 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
191
214
SemanticSearch = semanticSearch
192
215
};
193
216
194
- // Create the index client and delete the index if it exists, then create it
217
+ // Create the index client. Delete the index if it exists and then recreate it.
195
218
var indexClient = new SearchIndexClient(new Uri(endpoint), credential);
196
219
try
197
220
{
@@ -201,9 +224,8 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
201
224
catch (Exception ex)
202
225
{
203
226
Console.WriteLine($" Index '{indexName}' could not be deleted or did not exist: {ex.Message}" );
204
- }
227
+ }
205
228
await indexClient.CreateOrUpdateIndexAsync(index);
206
-
207
229
Console.WriteLine($" Index '{indexName}' created or updated successfully" );
208
230
209
231
// Download the documents from the GitHub URL
@@ -221,13 +243,11 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
221
243
{
222
244
KeyFieldAccessor = doc => doc["id"].ToString (),
223
245
}
224
- );
225
-
246
+ );
226
247
await searchIndexingBufferedSender.UploadDocumentsAsync(documents);
227
248
await searchIndexingBufferedSender.FlushAsync ();
249
+ Console.WriteLine($" Documents uploaded to index '{indexName}'" );
228
250
229
- Console.WriteLine($" Documents uploaded to index '{indexName}'" );
230
-
231
251
var openAiParameters = new AzureOpenAIVectorizerParameters
232
252
{
233
253
ResourceUri = new Uri(azureOpenAIEndpoint),
@@ -240,8 +260,7 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
240
260
var targetIndex = new KnowledgeAgentTargetIndex(indexName)
241
261
{
242
262
DefaultRerankerThreshold = 2.5f
243
- };
244
-
263
+ };
245
264
// Create the knowledge agent
246
265
var agent = new KnowledgeAgent(
247
266
name: agentName,
@@ -250,7 +269,6 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
250
269
await indexClient.CreateOrUpdateKnowledgeAgentAsync(agent);
251
270
Console.WriteLine($" Search agent '{agentName}' created or updated successfully" );
252
271
253
-
254
272
string instructions = @"
255
273
A Q&A agent that can answer questions about the Earth at night.
256
274
Sources have a JSON format with a ref_id that must be cited in the answer.
@@ -264,46 +282,42 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
264
282
{ " role" , " system" },
265
283
{ " content" , instructions }
266
284
}
267
- };
268
-
285
+ };
269
286
var agentClient = new KnowledgeAgentRetrievalClient(
270
287
endpoint: new Uri(endpoint),
271
288
agentName: agentName,
272
289
tokenCredential: new DefaultAzureCredential ()
273
- );
274
-
290
+ );
291
+
275
292
messages.Add(new Dictionary< string, object>
276
293
{
277
294
{ " role" , " user" },
278
295
{ " content" , @"
279
- Why do suburban belts display larger December brightening than urban cores even though absolute light levels are higher downtown?
280
- Why is the Phoenix nighttime street grid is so sharply visible from space, whereas large stretches of the interstate between midwestern cities remain comparatively dim?
281
- " }
282
- });
283
-
296
+ Why do suburban belts display larger December brightening than urban cores even though absolute light levels are higher downtown?
297
+ Why is the Phoenix nighttime street grid is so sharply visible from space, whereas large stretches of the interstate between midwestern cities remain comparatively dim?
298
+ " }
299
+ });
284
300
var retrievalResult = await agentClient.RetrieveAsync(
285
301
retrievalRequest: new KnowledgeAgentRetrievalRequest(
286
- messages: messages
287
- .Where(message => message["role"].ToString () ! = " system" )
288
- .Select(
289
- message => new KnowledgeAgentMessage(
290
- role: message["role"].ToString (),
291
- content: new[] { new KnowledgeAgentMessageTextContent(message["content"].ToString ()) }))
292
- .ToList ()
293
- )
294
- {
295
- TargetIndexParams = { new KnowledgeAgentIndexParams { IndexName = indexName, RerankerThreshold = 2.5f } }
296
- }
297
- );
298
-
302
+ messages: messages
303
+ .Where(message => message["role"].ToString () ! = " system" )
304
+ .Select(message => new KnowledgeAgentMessage(
305
+ role: message["role"].ToString (),
306
+ content: new[] { new KnowledgeAgentMessageTextContent(message["content"].ToString ()) }))
307
+ .ToList ()
308
+ )
309
+ {
310
+ TargetIndexParams = { new KnowledgeAgentIndexParams { IndexName = indexName, RerankerThreshold = 2.5f } }
311
+ }
312
+ );
299
313
messages.Add(new Dictionary< string, object>
300
314
{
301
315
{ " role" , " assistant" },
302
316
{ " content" , (retrievalResult.Value.Response[0].Content[0] as KnowledgeAgentMessageTextContent).Text }
303
317
});
304
318
305
- // Print
306
- Console.WriteLine (( retrievalResult.Value.Response[ 0 ].Content[ 0 ] as KnowledgeAgentMessageTextContent).Text);
319
+ Console.WriteLine (( retrievalResult.Value.Response[ 0 ].Content[ 0 ] as KnowledgeAgentMessageTextContent).Text);
320
+
307
321
Console.WriteLine("Activities:");
308
322
foreach (var activity in retrievalResult.Value.Activity)
309
323
{
@@ -325,50 +339,46 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
325
339
reference.GetType(),
326
340
new JsonSerializerOptions { WriteIndented = true }
327
341
);
328
- Console.WriteLine(referenceJson);
329
- }
330
-
342
+ Console.WriteLine(referenceJson); }
331
343
332
344
AzureOpenAIClient azureClient = new(
333
345
new Uri(azureOpenAIEndpoint),
334
346
new DefaultAzureCredential()) ;
335
- ChatClient chatClient = azureClient.GetChatClient(azureOpenAIGptDeployment);
347
+ ChatClient chatClient = azureClient.GetChatClient(azureOpenAIGptDeployment);
348
+
336
349
List< ChatMessage> chatMessages = messages
337
350
.Select< Dictionary< string, object> , ChatMessage>( m => m["role"].ToString () switch
338
351
{
339
352
" user" => new UserChatMessage(m["content"].ToString ()),
340
353
" assistant" => new AssistantChatMessage(m["content"].ToString ()),
341
354
" system" => new SystemChatMessage(m["content"].ToString ()),
342
355
_ => null
343
- })
356
+ })
344
357
.Where(m => m ! = null)
345
358
.ToList ();
346
359
347
-
348
360
var result = await chatClient.CompleteChatAsync(chatMessages);
349
-
350
361
Console.WriteLine($" [ASSISTANT]: {result.Value.Content[0].Text.Replace(" ." , " \n " )}" );
351
362
352
363
messages.Add(new Dictionary< string, object>
353
364
{
354
365
{ " role" , " user" },
355
- { " content" , " How do I find lava at night?" }
366
+ { " content" , " How do I find lava at night?" }
356
367
});
357
368
358
369
var retrievalResult2 = await agentClient.RetrieveAsync(
359
370
retrievalRequest: new KnowledgeAgentRetrievalRequest(
360
- messages: messages
361
- .Where(message => message["role"].ToString () ! = " system" )
362
- .Select(
363
- message => new KnowledgeAgentMessage(
364
- role: message["role"].ToString (),
365
- content: new[] { new KnowledgeAgentMessageTextContent(message["content"].ToString ()) }))
366
- .ToList ()
367
- )
368
- {
369
- TargetIndexParams = { new KnowledgeAgentIndexParams { IndexName = indexName, RerankerThreshold = 2.5f } }
370
- }
371
- );
371
+ messages: messages
372
+ .Where(message => message["role"].ToString () ! = " system" )
373
+ .Select(message => new KnowledgeAgentMessage(
374
+ role: message["role"].ToString (),
375
+ content: new[] { new KnowledgeAgentMessageTextContent(message["content"].ToString ()) }))
376
+ .ToList ()
377
+ )
378
+ {
379
+ TargetIndexParams = { new KnowledgeAgentIndexParams { IndexName = indexName, RerankerThreshold = 2.5f } }
380
+ }
381
+ );
372
382
373
383
messages.Add(new Dictionary< string, object>
374
384
{
@@ -400,29 +410,27 @@ Although you can provide your own data, this quickstart uses [sample JSON docume
400
410
new JsonSerializerOptions { WriteIndented = true }
401
411
);
402
412
Console.WriteLine(referenceJson2 );
403
- } List<ChatMessage> chatMessages2 = messages
413
+ }
414
+
415
+ List<ChatMessage> chatMessages2 = messages
404
416
.Select<Dictionary<string, object>, ChatMessage>(m => m["role"].ToString() switch
405
417
{
406
418
"user" => new UserChatMessage(m["content"].ToString()) ,
407
419
" assistant" => new AssistantChatMessage(m["content"].ToString ()),
408
420
" system" => new SystemChatMessage(m["content"].ToString ()),
409
421
_ => null
410
- })
422
+ })
411
423
.Where(m => m ! = null)
412
424
.ToList ();
413
425
414
-
415
426
var result2 = await chatClient.CompleteChatAsync(chatMessages2);
416
-
417
427
Console.WriteLine($" [ASSISTANT]: {result2.Value.Content[0].Text.Replace(" ." , " \n " )}" );
418
428
419
429
await indexClient.DeleteKnowledgeAgentAsync(agentName);
420
430
System.Console.WriteLine($" Search agent '{agentName}' deleted successfully" );
421
431
422
- await indexClient.DeleteIndexAsync(indexName);
432
+ await indexClient.DeleteIndexAsync(indexName);
423
433
System.Console.WriteLine($" Index '{indexName}' deleted successfully" );
424
-
425
-
426
434
}
427
435
}
428
436
}
0 commit comments