Skip to content

Commit 96d74d4

Browse files
committed
Add custom orchestration with Semantic Kernel
1 parent d70badb commit 96d74d4

20 files changed

+307
-53
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## About
44

5-
This project provides a very easy to use learning and experimentation playground to try out various AI-enabled search scenarios in Azure. It provides a web application front-end which uses [Azure Cognitive Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) and [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview) to execute searches with a variety of options. This allows you to quickly understand what each option does, how it affects the search results, and how various approaches compare against each other.
5+
This project provides a very easy to use learning and experimentation playground to try out various AI-enabled search scenarios in Azure. It provides a web application front-end which uses [Azure Cognitive Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search) and [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview) to execute searches with a variety of options - ranging from simple text search, to semantic search, vector and hybrid search, and using generative AI to answer search queries in various ways. This allows you to quickly understand what each option does, how it affects the search results, and how various approaches compare against each other.
66

77
By default, a few documents are added automatically to allow you to use the application directly. You're encouraged to upload your own documents (which you can also easily do via the web app) so you can experiment with searching over your own content.
88

@@ -44,7 +44,7 @@ When you deploy the solution, it creates an [Azure Cognitive Search](https://lea
4444

4545
The documents in the index are also chunked into smaller pieces, and vector embeddings are created for these chunks using a Function App based on the [Azure OpenAI Embeddings Generator power skill](https://github.com/Azure-Samples/azure-search-power-skills/tree/main/Vector/EmbeddingGenerator). This allows you to easily try out [vector and hybrid search](https://learn.microsoft.com/azure/search/vector-search-overview). With Azure Cognitive Search on its own, the responses *always* come directly from the source data, rather than being generated by an AI model. You can optionally use [semantic search](https://learn.microsoft.com/azure/search/semantic-search-overview) which *does* use AI, not to generate content but to increase the relevancy of the results and provide semantic answers and captions.
4646

47-
The solution also deploys an [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview) service. It provides an embeddings model to generate the vector representations of the document chunks and search queries, and a GPT model to generate answers to your search queries. If you choose the option to use [Azure OpenAI "on your data"](https://learn.microsoft.com/azure/ai-services/openai/concepts/use-your-data), these AI-generated responses can be grounded in (and even limited to) the information in your Azure Cognitive Search indexes. This option allows you to let Azure OpenAI orchestrate the [Retrieval Augmented Generation (RAG)](https://aka.ms/what-is-rag) pattern. This means your search query will first be used to retrieve the most relevant documents (or preferably *smaller chunks of those documents*) from your private data source. Those search results are then used as context in the prompt that gets sent to the AI model, along with the original search query. This allows the AI model to generate a response based on the most relevant source data, rather than the public data that was used to train the model.
47+
The solution also deploys an [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview) service. It provides an embeddings model to generate the vector representations of the document chunks and search queries, and a GPT model to generate answers to your search queries. If you choose the option to use [Azure OpenAI "on your data"](https://learn.microsoft.com/azure/ai-services/openai/concepts/use-your-data), these AI-generated responses can be grounded in (and even limited to) the information in your Azure Cognitive Search indexes. This option allows you to let Azure OpenAI orchestrate the [Retrieval Augmented Generation (RAG)](https://aka.ms/what-is-rag) pattern. This means your search query will first be used to retrieve the most relevant documents (or preferably *smaller chunks of those documents*) from your private data source. Those search results are then used as context in the prompt that gets sent to the AI model, along with the original search query. This allows the AI model to generate a response based on the most relevant source data, rather than the public data that was used to train the model. Next to letting Azure OpenAI orchestrate the RAG pattern, the web application can also use [Semantic Kernel](https://learn.microsoft.com/semantic-kernel/overview/) to perform that orchestration, using a prompt and other parameters you can control yourself.
4848

4949
## Deployment
5050

@@ -117,7 +117,8 @@ The ARM template deploys the services and sets the configuration settings for th
117117
| `SearchIndexNameBlobChunks`* | The name of the search index that contains the document chunks | `blob-chunks` |
118118
| `SearchIndexerScheduleMinutes`* | The number of minutes between indexer executions in Azure Cognitive Search | `5` |
119119
| `InitialDocumentUrls` | A space-separated list of URLs for the documents to include by default | A [resiliency](https://azure.microsoft.com/mediahandler/files/resourcefiles/resilience-in-azure-whitepaper/Resiliency-whitepaper.pdf) and [compliance](https://azure.microsoft.com/mediahandler/files/resourcefiles/data-residency-data-sovereignty-and-compliance-in-the-microsoft-cloud/Data_Residency_Data_Sovereignty_Compliance_Microsoft_Cloud.pdf) document |
120-
| `DefaultSystemRoleInformation` | The default instructions for the AI model | You are an AI assistant that helps people find information. |
120+
| `DefaultSystemRoleInformation` | The default instructions for the AI model | "You are an AI assistant that helps people find information." |
121+
| `DefaultCustomOrchestrationPrompt` | The default prompt for the AI model when using custom orchestration | A prompt that instructs the AI model to respond from provided data sources (with citations). |
121122
| `DisableUploadDocuments` | Set this to `true` to disable the functionality to upload documents, preventing uploads by users of the Web App (you can still upload documents directly to the Azure storage container if you have permissions there) | `false` |
122123
| `DisableResetSearchConfiguration` | Set this to `true` to disable the functionality to reset the search configuration by users of the Web App | `false` |
123124

azuredeploy-webapp.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@
6666
"searchIndexNameBlobDocuments": "blob-documents",
6767
"searchIndexNameBlobChunks": "blob-chunks",
6868
"searchIndexerScheduleMinutes": 5,
69-
"defaultSystemRoleInformation": "You are an AI assistant that helps people find information.",
69+
"defaultSystemRoleInformation": "",
70+
"defaultCustomOrchestrationPrompt": "",
7071
"disableUploadDocuments": false,
7172
"disableResetSearchConfiguration": false
7273
},
@@ -380,6 +381,10 @@
380381
"name": "DefaultSystemRoleInformation",
381382
"value": "[variables('defaultSystemRoleInformation')]"
382383
},
384+
{
385+
"name": "DefaultCustomOrchestrationPrompt",
386+
"value": "[variables('defaultCustomOrchestrationPrompt')]"
387+
},
383388
{
384389
"name": "DisableUploadDocuments",
385390
"value": "[variables('disableUploadDocuments')]"
@@ -478,6 +483,10 @@
478483
"type": "string",
479484
"value": "[variables('defaultSystemRoleInformation')]"
480485
},
486+
"defaultCustomOrchestrationPrompt": {
487+
"type": "string",
488+
"value": "[variables('defaultCustomOrchestrationPrompt')]"
489+
},
481490
"disableUploadDocuments": {
482491
"type": "bool",
483492
"value": "[variables('disableUploadDocuments')]"

media/compare-results.png

151 KB
Loading

media/search-options.png

151 KB
Loading

src/Azure.AISearch.WebApp/AppSettings.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,18 @@ public class AppSettings
2222
public string? SearchIndexNameBlobChunks { get; set; }
2323
public int? SearchIndexerScheduleMinutes { get; set; } // If unspecified, will be set to 5 minutes.
2424
public string? InitialDocumentUrls { get; set; }
25-
public string? DefaultSystemRoleInformation { get; set; } = "You are an AI assistant that helps people find information.";
25+
public string? DefaultSystemRoleInformation { get; set; }
26+
public string? DefaultCustomOrchestrationPrompt { get; set; }
2627
public bool DisableUploadDocuments { get; set; } // If true, the Upload Documents functionality will be disabled.
2728
public bool DisableResetSearchConfiguration { get; set; } // If true, the Reset Search Configuration functionality will be disabled.
29+
30+
public string GetDefaultSystemRoleInformation()
31+
{
32+
return string.IsNullOrWhiteSpace(this.DefaultSystemRoleInformation) ? Constants.Defaults.SystemRoleInformation : this.DefaultSystemRoleInformation;
33+
}
34+
35+
public string GetDefaultCustomOrchestrationPrompt()
36+
{
37+
return string.IsNullOrWhiteSpace(this.DefaultCustomOrchestrationPrompt) ? Constants.Defaults.CustomOrchestrationPrompt : this.DefaultCustomOrchestrationPrompt;
38+
}
2839
}

src/Azure.AISearch.WebApp/Azure.AISearch.WebApp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<PackageReference Include="Azure.Storage.Blobs" Version="12.17.0" />
1414
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.20" />
1515
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
16+
<PackageReference Include="Microsoft.SemanticKernel" Version="0.23.230906.2-preview" />
1617
</ItemGroup>
1718

1819
</Project>
Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,57 @@
1+
using Azure.Search.Documents.Indexes.Models;
2+
13
namespace Azure.AISearch.WebApp;
24

35
public static class Constants
46
{
5-
public static class ChatRoles
6-
{
7-
public const string System = "system";
8-
public const string Assistant = "assistant";
9-
public const string Tool = "tool";
10-
public const string User = "user";
11-
}
12-
137
public static class ConfigurationNames
148
{
159
public const string SemanticConfigurationNameDefault = "default";
1610
public const string VectorSearchConfigurationNameDefault = "default";
1711
}
12+
13+
public static class Defaults
14+
{
15+
public const string SystemRoleInformation = "You are an AI assistant that helps people find information.";
16+
17+
// Adapted from https://github.com/Azure-Samples/azure-search-openai-demo-csharp/blob/feature/embeddingSearch/app/backend/Services/RetrieveThenReadApproachService.cs
18+
public const string CustomOrchestrationPrompt = @"You are an intelligent assistant.
19+
Use 'you' to refer to the individual asking the questions even if they ask with 'I'.
20+
Answer the following question using only the data provided in the sources below.
21+
For tabular information return it as an HTML table. Do not return markdown format.
22+
Each source has a name followed by a colon and the actual information, always include the source name for each fact you use in the response.
23+
If you cannot answer using the sources below, say you don't know.
24+
25+
###
26+
Question: 'What is the deductible for the employee plan for a visit to Overlake in Bellevue?'
27+
28+
Sources:
29+
info1.txt: deductibles depend on whether you are in-network or out-of-network. In-network deductibles are $500 for employees and $1000 for families. Out-of-network deductibles are $1000 for employees and $2000 for families.
30+
info2.pdf: Overlake is in-network for the employee plan.
31+
info3.pdf: Overlake is the name of the area that includes a park and ride near Bellevue.
32+
info4.pdf: In-network institutions include Overlake, Swedish, and others in the region
33+
34+
Answer:
35+
In-network deductibles are $500 for employees and $1000 for families <cite>info1.txt</cite> and Overlake is in-network for the employee plan <cite>info2.pdf</cite><cite>info4.pdf</cite>.
36+
37+
###
38+
Question: {{$query}}?
39+
40+
Sources:
41+
{{$sources}}
42+
43+
Answer:
44+
";
45+
public const int VectorNearestNeighborsCount = 50;
46+
public const int MaxTokens = 800;
47+
public const double Temperature = 0.7;
48+
public const double TopP = 0.95;
49+
public const double FrequencyPenalty = 0.0;
50+
public const double PresencePenalty = 0.0;
51+
public const string StopSequences = "";
52+
public const int HnswParametersM = 4;
53+
public const int HnswParametersEfConstruction = 400;
54+
public const int HnswParametersEfSearch = 500;
55+
public static readonly VectorSearchAlgorithmMetric HnswParametersMetric = VectorSearchAlgorithmMetric.Cosine;
56+
}
1857
}

src/Azure.AISearch.WebApp/Models/EngineType.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ namespace Azure.AISearch.WebApp.Models;
33
public enum EngineType
44
{
55
AzureOpenAI,
6-
AzureCognitiveSearch
6+
AzureCognitiveSearch,
7+
CustomOrchestration
78
}

src/Azure.AISearch.WebApp/Models/SearchRequest.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,16 @@ public class SearchRequest
88
public SearchIndexType SearchIndex { get; set; } = SearchIndexType.Documents;
99
public QueryType QueryType { get; set; } = QueryType.TextStandard;
1010
public DataSourceType DataSource { get; set; } = DataSourceType.None;
11+
public int? VectorNearestNeighborsCount { get; set; } = Constants.Defaults.VectorNearestNeighborsCount;
1112
public bool LimitToDataSource { get; set; } = true; // "Limit responses to your data content"
1213
public string? SystemRoleInformation { get; set; } // Give the model instructions about how it should behave and any context it should reference when generating a response. You can describe the assistant’s personality, tell it what it should and shouldn’t answer, and tell it how to format responses. There’s no token limit for this section, but it will be included with every API call, so it counts against the overall token limit.
14+
public string? CustomOrchestrationPrompt { get; set; }
15+
public int? MaxTokens { get; set; } = Constants.Defaults.MaxTokens;
16+
public double? Temperature { get; set; } = Constants.Defaults.Temperature;
17+
public double? TopP { get; set; } = Constants.Defaults.TopP;
18+
public double? FrequencyPenalty { get; set; } = Constants.Defaults.FrequencyPenalty;
19+
public double? PresencePenalty { get; set; } = Constants.Defaults.PresencePenalty;
20+
public string? StopSequences { get; set; } = Constants.Defaults.StopSequences;
1321

1422
public bool IsVectorSearch => QueryType == Models.QueryType.Vector || QueryType == Models.QueryType.HybridStandard || QueryType == Models.QueryType.HybridSemantic;
1523
public bool IsSemanticSearch => QueryType == Models.QueryType.TextSemantic || QueryType == Models.QueryType.HybridSemantic;

0 commit comments

Comments
 (0)