Skip to content

Commit bdbe000

Browse files
committed
Add more request options
1 parent 0410efe commit bdbe000

File tree

5 files changed

+79
-28
lines changed

5 files changed

+79
-28
lines changed

src/Azure.AISearch.WebApp/Constants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public static class Defaults
5858
public const double FrequencyPenalty = 0.0;
5959
public const double PresencePenalty = 0.0;
6060
public const string StopSequences = "";
61+
public const int Strictness = 3;
62+
public const int DocumentCount = 5;
6163
public const int HnswParametersM = 4;
6264
public const int HnswParametersEfConstruction = 400;
6365
public const int HnswParametersEfSearch = 500;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public class SearchRequest
2121
public double? FrequencyPenalty { get; set; } = Constants.Defaults.FrequencyPenalty;
2222
public double? PresencePenalty { get; set; } = Constants.Defaults.PresencePenalty;
2323
public string? StopSequences { get; set; } = Constants.Defaults.StopSequences;
24+
public int? Strictness { get; set; } = Constants.Defaults.Strictness;
25+
public int? DocumentCount { get; set; } = Constants.Defaults.DocumentCount;
2426

2527
public bool IsVectorSearch => QueryType == Models.QueryType.Vector || QueryType == Models.QueryType.HybridStandard || QueryType == Models.QueryType.HybridSemantic;
2628
public bool IsSemanticSearch => QueryType == Models.QueryType.TextSemantic || QueryType == Models.QueryType.HybridSemantic;

src/Azure.AISearch.WebApp/Pages/Index.cshtml

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,8 @@
274274
<label class="form-check-label" for="searchRequest-DataSource-AzureCognitiveSearch">Azure AI Search</label>
275275
<span class="info-tip" data-bs-toggle="popover" data-bs-content="Use source data from an Azure AI Search index. For best results, you should use the <code>Chunks</code> index, as this contains smaller and typically more contextually relevant pieces of information. This makes the prompt that is sent to the AI model better suited to generate a meaningful response from."><i class="bi bi-info-circle"></i></span>
276276
</div>
277-
<div class="form-check form-check-inline form-switch">
278-
<input class="form-check-input" type="checkbox" role="switch" name="@nameof(SearchRequest.LimitToDataSource)" id="searchRequest-LimitToDataSource" value="true" v-model="searchRequest.limitToDataSource" v-bind:disabled="searchRequest.dataSource == '@DataSourceType.None'">
277+
<div class="form-check form-check-inline form-switch" v-show="searchRequest.dataSource != '@DataSourceType.None'">
278+
<input class="form-check-input" type="checkbox" role="switch" name="@nameof(SearchRequest.LimitToDataSource)" id="searchRequest-LimitToDataSource" value="true" v-model="searchRequest.limitToDataSource">
279279
<input type="hidden" name="@nameof(SearchRequest.LimitToDataSource)" value="false" />
280280
<label class="form-check-label" for="searchRequest-LimitToDataSource">Limit to your data</label>
281281
<span class="info-tip" data-bs-toggle="popover" data-bs-content="Limit responses to your data content only, not including the data that was used for training the model."><i class="bi bi-info-circle"></i></span>
@@ -312,18 +312,18 @@
312312
<label class="form-check-label" for="searchRequest-QueryType-TextSemantic">Semantic keyword</label>
313313
<span class="info-tip" data-bs-toggle="popover" data-bs-content="Use <a href='https://learn.microsoft.com/azure/search/semantic-search-overview' target='_blank'>semantic ranking</a>, which returns more relevant results by applying language understanding to initial search results. It can also return <a href='https://learn.microsoft.com/azure/search/semantic-how-to-query-request' target='_blank'>semantic captions</a> (parts of a document that best summarize the content) and even <a href='https://learn.microsoft.com/azure/search/semantic-answers' target='_blank'>semantic answers</a> (direct answers to queries that look like a question). In all cases, the responses aren't AI-generated but come directly from the source data."><i class="bi bi-info-circle"></i></span>
314314
</div>
315-
<div class="form-check form-check-inline">
316-
<input class="form-check-input" type="radio" name="@nameof(SearchRequest.QueryType)" id="searchRequest-QueryType-Vector" value="@QueryType.Vector" v-model="searchRequest.queryType" v-bind:disabled="searchRequest.searchIndex == '@SearchIndexType.Documents'">
315+
<div class="form-check form-check-inline" v-show="searchRequest.searchIndex != '@SearchIndexType.Documents'">
316+
<input class="form-check-input" type="radio" name="@nameof(SearchRequest.QueryType)" id="searchRequest-QueryType-Vector" value="@QueryType.Vector" v-model="searchRequest.queryType">
317317
<label class="form-check-label" for="searchRequest-QueryType-Vector">Vector only</label>
318318
<span class="info-tip" data-bs-toggle="popover" data-bs-content="First send the search query to an <a href='https://learn.microsoft.com/azure/ai-services/openai/how-to/embeddings' target='_blank'>embedding model in Azure OpenAI</a> to generate a vector representing the query itself. Then perform a <a href='https://learn.microsoft.com/azure/search/vector-search-overview' target='_blank'>vector search</a> to retrieve the nearest neighbors in vector space from the chunked and vectorized documents in the <code>Chunks</code> index. This should return results that are semantically similar to the query, as determined by the embedding model's vector representations."><i class="bi bi-info-circle"></i></span>
319319
</div>
320-
<div class="form-check form-check-inline">
321-
<input class="form-check-input" type="radio" name="@nameof(SearchRequest.QueryType)" id="searchRequest-QueryType-HybridStandard" value="@QueryType.HybridStandard" v-model="searchRequest.queryType" v-bind:disabled="searchRequest.searchIndex == '@SearchIndexType.Documents'">
320+
<div class="form-check form-check-inline" v-show="searchRequest.searchIndex != '@SearchIndexType.Documents'">
321+
<input class="form-check-input" type="radio" name="@nameof(SearchRequest.QueryType)" id="searchRequest-QueryType-HybridStandard" value="@QueryType.HybridStandard" v-model="searchRequest.queryType">
322322
<label class="form-check-label" for="searchRequest-QueryType-HybridStandard">Standard hybrid (keyword + vector)</label>
323323
<span class="info-tip" data-bs-toggle="popover" data-bs-content="Combine the results of a <a href='https://learn.microsoft.com/azure/search/vector-search-overview' target='_blank'>vector search</a> with the regular <a href='https://learn.microsoft.com/azure/search/search-lucene-query-architecture' target='_blank'>keyword search</a> results into a single ranked response."><i class="bi bi-info-circle"></i></span>
324324
</div>
325-
<div class="form-check form-check-inline">
326-
<input class="form-check-input" type="radio" name="@nameof(SearchRequest.QueryType)" id="searchRequest-QueryType-HybridSemantic" value="@QueryType.HybridSemantic" v-model="searchRequest.queryType" v-bind:disabled="searchRequest.searchIndex == '@SearchIndexType.Documents'">
325+
<div class="form-check form-check-inline" v-show="searchRequest.searchIndex != '@SearchIndexType.Documents'">
326+
<input class="form-check-input" type="radio" name="@nameof(SearchRequest.QueryType)" id="searchRequest-QueryType-HybridSemantic" value="@QueryType.HybridSemantic" v-model="searchRequest.queryType">
327327
<label class="form-check-label" for="searchRequest-QueryType-HybridSemantic">Semantic hybrid (keyword + vector)</label>
328328
<span class="info-tip" data-bs-toggle="popover" data-bs-content="Combine the results of <a href='https://learn.microsoft.com/azure/search/vector-search-overview' target='_blank'>vector search</a> and <a href='https://learn.microsoft.com/azure/search/semantic-search-overview' target='_blank'>search with semantic ranking</a> into a single ranked response. Compared to standard hybrid search, this provides even more accuracy with L2 reranking using the same language models that power Bing."><i class="bi bi-info-circle"></i></span>
329329
</div>
@@ -346,6 +346,30 @@
346346
</div>
347347
</div>
348348

349+
<div class="mb-2" v-show="!(searchRequest.engine == '@EngineType.AzureOpenAI' && searchRequest.dataSource == '@DataSourceType.None')">
350+
<label class="form-label">Result parameters</label>
351+
<div class="row row-cols-lg-auto g-3 align-items-center">
352+
<div class="col-12">
353+
<div class="input-group">
354+
<div class="input-group-text">
355+
Document count
356+
<span class="info-tip" data-bs-toggle="popover" data-bs-content="The number of documents to return."><i class="bi bi-info-circle"></i></span>
357+
</div>
358+
<input type="number" class="form-control form-control-small" name="@nameof(SearchRequest.DocumentCount)" value="@Model.SearchRequest.DocumentCount" />
359+
</div>
360+
</div>
361+
<div class="col-12" v-show="searchRequest.engine == '@EngineType.AzureOpenAI' && searchRequest.dataSource == '@DataSourceType.AzureCognitiveSearch'">
362+
<div class="input-group">
363+
<div class="input-group-text">
364+
Strictness
365+
<span class="info-tip" data-bs-toggle="popover" data-bs-content="Sets the threshold to categorize documents as relevant to your queries. Raising the value means a higher threshold for relevance and filters out more less-relevant documents for responses. Setting this value too high might cause the model to fail to generate responses due to limited available documents."><i class="bi bi-info-circle"></i></span>
366+
</div>
367+
<input type="number" class="form-control form-control-small" name="@nameof(SearchRequest.Strictness)" value="@Model.SearchRequest.Strictness" />
368+
</div>
369+
</div>
370+
</div>
371+
</div>
372+
349373
<div class="mb-2" v-show="!(searchRequest.engine == '@EngineType.AzureOpenAI' && searchRequest.dataSource == '@DataSourceType.None') && (searchRequest.queryType == '@QueryType.Vector' || searchRequest.queryType == '@QueryType.HybridStandard' || searchRequest.queryType == '@QueryType.HybridSemantic')">
350374
<label class="form-label">Vector parameters</label>
351375
<div class="row row-cols-lg-auto g-3 align-items-center">
@@ -359,8 +383,8 @@
359383
</div>
360384
</div>
361385
<div class="col-12">
362-
<div class="form-check form-check-inline form-switch">
363-
<input class="form-check-input" type="checkbox" role="switch" name="@nameof(SearchRequest.UseIntegratedVectorization)" id="searchRequest-UseIntegratedVectorization" value="true" v-model="searchRequest.useIntegratedVectorization" v-bind:disabled="searchRequest.engine == '@EngineType.AzureOpenAI'">
386+
<div class="form-check form-check-inline form-switch" v-show="searchRequest.engine != '@EngineType.AzureOpenAI'">
387+
<input class="form-check-input" type="checkbox" role="switch" name="@nameof(SearchRequest.UseIntegratedVectorization)" id="searchRequest-UseIntegratedVectorization" value="true" v-model="searchRequest.useIntegratedVectorization">
364388
<input type="hidden" name="@nameof(SearchRequest.UseIntegratedVectorization)" value="false" />
365389
<label class="form-check-label" for="searchRequest-UseIntegratedVectorization">Use integrated vectorization</label>
366390
<span class="info-tip" data-bs-toggle="popover" data-bs-content="Use <a href='https://learn.microsoft.com/azure/search/vector-search-integrated-vectorization' target='_blank'>integrated vectorization</a> to let Azure AI Search generate the vector embedding for the search query text, rather than the app doing that upfront and sending the vector directly to the search service."><i class="bi bi-info-circle"></i></span>
@@ -369,7 +393,7 @@
369393
</div>
370394
</div>
371395

372-
<div class="mb-2" v-show="searchRequest.engine == '@EngineType.CustomOrchestration'">
396+
<div class="mb-2" v-show="searchRequest.engine == '@EngineType.CustomOrchestration' || searchRequest.engine == '@EngineType.AzureOpenAI'">
373397
<label class="form-label">Model parameters</label>
374398
<div class="row row-cols-lg-auto g-3 align-items-center">
375399
<div class="col-12">

src/Azure.AISearch.WebApp/Services/AzureCognitiveSearchService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public async Task<SearchResponse> SearchAsync(SearchRequest request)
3333
var searchOptions = new SearchOptions
3434
{
3535
QueryType = request.IsSemanticSearch ? SearchQueryType.Semantic : (request.QuerySyntax == QuerySyntax.Lucene ? SearchQueryType.Full : SearchQueryType.Simple),
36+
Size = request.DocumentCount ?? Constants.Defaults.DocumentCount,
3637
HighlightPreTag = "<mark>",
3738
HighlightPostTag = "</mark>"
3839
};

src/Azure.AISearch.WebApp/Services/AzureOpenAISearchService.cs

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,23 @@ public async Task<SearchResponse> SearchAsync(SearchRequest request)
2828
ArgumentNullException.ThrowIfNull(request.Query);
2929

3030
var searchResponse = new SearchResponse();
31-
var chatCompletionsOptions = new ChatCompletionsOptions { DeploymentName = this.settings.OpenAIGptDeployment };
31+
var chatCompletionsOptions = new ChatCompletionsOptions
32+
{
33+
DeploymentName = this.settings.OpenAIGptDeployment,
34+
MaxTokens = request.MaxTokens ?? Constants.Defaults.MaxTokens,
35+
Temperature = (float)(request.Temperature ?? Constants.Defaults.Temperature),
36+
NucleusSamplingFactor = (float)(request.TopP ?? Constants.Defaults.TopP),
37+
FrequencyPenalty = (float)(request.FrequencyPenalty ?? Constants.Defaults.FrequencyPenalty),
38+
PresencePenalty = (float)(request.PresencePenalty ?? Constants.Defaults.PresencePenalty),
39+
};
40+
var stopSequences = (request.StopSequences ?? Constants.Defaults.StopSequences).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
41+
if (stopSequences.Any())
42+
{
43+
foreach (var stopSequence in stopSequences)
44+
{
45+
chatCompletionsOptions.StopSequences.Add(stopSequence);
46+
}
47+
}
3248
chatCompletionsOptions.Messages.Add(new ChatRequestSystemMessage(request.SystemRoleInformation));
3349

3450
if (request.History != null && request.History.Any())
@@ -66,27 +82,30 @@ public async Task<SearchResponse> SearchAsync(SearchRequest request)
6682
throw new InvalidOperationException("Azure OpenAI didn't return a meaningful response.");
6783
}
6884

69-
// Process citations within the answer, which take the form "[doc1][doc2]..." and refer to the (1-based) index of
70-
// the citations in the tool message.
71-
foreach (var extensionMessage in answerMessage.AzureExtensionsContext.Messages.Where(m => m.Role == ChatRole.Tool))
85+
if (answerMessage.AzureExtensionsContext != null)
7286
{
73-
Console.WriteLine(extensionMessage.Content);
74-
var content = JsonSerializer.Deserialize<ChatResponseMessageContent>(extensionMessage.Content!);
75-
if (content?.Citations != null && content.Citations.Any())
87+
// Process citations within the answer, which take the form "[doc1][doc2]..." and refer to the (1-based) index of
88+
// the citations in the tool message.
89+
foreach (var extensionMessage in answerMessage.AzureExtensionsContext.Messages.Where(m => m.Role == ChatRole.Tool))
7690
{
77-
var citationIndex = 0;
78-
foreach (var citation in content.Citations)
91+
Console.WriteLine(extensionMessage.Content);
92+
var content = JsonSerializer.Deserialize<ChatResponseMessageContent>(extensionMessage.Content!);
93+
if (content?.Citations != null && content.Citations.Any())
7994
{
80-
answerText = answerText.Replace($"[doc{++citationIndex}]", $"<cite>{citation.Title}</cite>", StringComparison.OrdinalIgnoreCase);
81-
searchResponse.SearchResults.Add(new SearchResult
95+
var citationIndex = 0;
96+
foreach (var citation in content.Citations)
8297
{
83-
DocumentId = citation.Id,
84-
DocumentTitle = citation.Title,
85-
Captions = string.IsNullOrWhiteSpace(citation.Content) ? Array.Empty<string>() : new[] { citation.Content }
86-
});
98+
answerText = answerText.Replace($"[doc{++citationIndex}]", $"<cite>{citation.Title}</cite>", StringComparison.OrdinalIgnoreCase);
99+
searchResponse.SearchResults.Add(new SearchResult
100+
{
101+
DocumentId = citation.Id,
102+
DocumentTitle = citation.Title,
103+
Captions = string.IsNullOrWhiteSpace(citation.Content) ? Array.Empty<string>() : new[] { citation.Content }
104+
});
105+
}
106+
// Stop looping through the tool messages once we find the first one holding the citations.
107+
break;
87108
}
88-
// Stop looping through the tool messages once we find the first one holding the citations.
89-
break;
90109
}
91110
}
92111

@@ -117,6 +136,9 @@ private AzureCognitiveSearchChatExtensionConfiguration GetAzureCognitiveSearchDa
117136
},
118137
ShouldRestrictResultScope = request.LimitToDataSource, // Limit responses to data from the data source only
119138
QueryType = GetQueryType(request),
139+
RoleInformation = request.SystemRoleInformation ?? Constants.Defaults.SystemRoleInformation,
140+
Strictness = request.Strictness ?? Constants.Defaults.Strictness,
141+
DocumentCount = request.DocumentCount ?? Constants.Defaults.DocumentCount,
120142
SemanticConfiguration = request.IsSemanticSearch ? Constants.ConfigurationNames.SemanticConfigurationNameDefault : null,
121143
EmbeddingEndpoint = request.IsVectorSearch ? new Uri(new Uri(this.settings.OpenAIEndpoint), $"openai/deployments/{this.settings.OpenAIEmbeddingDeployment}/embeddings?api-version={this.settings.OpenAIApiVersion}") : null,
122144
EmbeddingKey = request.IsVectorSearch ? this.settings.OpenAIApiKey : null

0 commit comments

Comments
 (0)