Skip to content

Commit 19c6015

Browse files
feat: add configurable maxResults (default 5, max 10) to vector search tools
- AISearchService.ExecuteVectorSearch gains optional top param (default 5, clamped to 1-10) - SearchBookContent, LookupConcept, FindRelatedSections expose maxResults to MCP clients - Raises default from 3→5 for better coverage of broad C# concepts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2d5678f commit 19c6015

2 files changed

Lines changed: 13 additions & 6 deletions

File tree

EssentialCSharp.Chat.Shared/Services/AISearchService.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ public class AISearchService(
1313
{
1414
// TODO: Implement Hybrid Search functionality, may need to switch db providers to support full text search?
1515

16+
public const int DefaultSearchTop = 5;
17+
public const int MaxSearchTop = 10;
18+
1619
public async Task<IReadOnlyList<VectorSearchResult<BookContentChunk>>> ExecuteVectorSearch(
17-
string query, string? collectionName = null, CancellationToken cancellationToken = default)
20+
string query, string? collectionName = null, int top = DefaultSearchTop, CancellationToken cancellationToken = default)
1821
{
22+
top = Math.Clamp(top, 1, MaxSearchTop);
1923
collectionName ??= EmbeddingService.CollectionName;
2024

2125
VectorStoreCollection<string, BookContentChunk> collection = vectorStore.GetCollection<string, BookContentChunk>(collectionName);
@@ -32,7 +36,7 @@ public async Task<IReadOnlyList<VectorSearchResult<BookContentChunk>>> ExecuteVe
3236
try
3337
{
3438
var results = new List<VectorSearchResult<BookContentChunk>>();
35-
await foreach (var result in collection.SearchAsync(searchVector, options: vectorSearchOptions, top: 3, cancellationToken: cancellationToken))
39+
await foreach (var result in collection.SearchAsync(searchVector, options: vectorSearchOptions, top: top, cancellationToken: cancellationToken))
3640
{
3741
results.Add(result);
3842
}

EssentialCSharp.Web/Tools/BookSearchTool.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public BookSearchTool(IServiceProvider serviceProvider, ISiteMappingService site
3232
Description("Search the Essential C# book content using semantic vector search. Returns relevant text chunks with chapter and heading context. Use this to find information about C# programming concepts covered in the book.")]
3333
public async Task<string> SearchBookContent(
3434
[Description("The search query describing the C# concept or topic to find in the book.")] string query,
35+
[Description("Number of results to return (1–10). Default is 5. Use a higher value for broad topics or comprehensive research; lower for quick lookups.")] int maxResults = AISearchService.DefaultSearchTop,
3536
CancellationToken cancellationToken = default)
3637
{
3738
if (string.IsNullOrWhiteSpace(query))
@@ -48,7 +49,7 @@ public async Task<string> SearchBookContent(
4849
return "Book search is not available in this environment (AI services are not configured).";
4950
}
5051

51-
var results = await _SearchService.ExecuteVectorSearch(query, cancellationToken: cancellationToken);
52+
var results = await _SearchService.ExecuteVectorSearch(query, top: maxResults, cancellationToken: cancellationToken);
5253

5354
var sb = new StringBuilder();
5455
int resultCount = 0;
@@ -172,6 +173,7 @@ public string GetDirectContentUrl(
172173
Description("Find all sections in the Essential C# book that cover a specific C# concept. Combines section heading search with semantic vector search (when available) to give broad coverage. Returns section slugs, chapter numbers, and direct links.")]
173174
public async Task<string> LookupConcept(
174175
[Description("The C# concept, feature, or topic to find in the book (e.g., 'LINQ', 'async/await', 'pattern matching', 'generics').")] string concept,
176+
[Description("Number of semantic search results to return (1–10). Default is 5.")] int maxResults = AISearchService.DefaultSearchTop,
175177
CancellationToken cancellationToken = default)
176178
{
177179
if (string.IsNullOrWhiteSpace(concept))
@@ -197,7 +199,7 @@ public async Task<string> LookupConcept(
197199
var vectorMatches = new List<(int chapter, string heading, string chunkText)>();
198200
if (_SearchService is not null)
199201
{
200-
var results = await _SearchService.ExecuteVectorSearch(concept, cancellationToken: cancellationToken);
202+
var results = await _SearchService.ExecuteVectorSearch(concept, top: maxResults, cancellationToken: cancellationToken);
201203
foreach (var r in results)
202204
{
203205
vectorMatches.Add((r.Record.ChapterNumber ?? 0, r.Record.Heading ?? "", r.Record.ChunkText));
@@ -415,6 +417,7 @@ public async Task<string> FindBookHelpForDiagnostic(
415417
Description("Find other sections in the Essential C# book that are semantically related to a given section. Uses the section heading as a search query to discover thematically connected content across the entire book. Requires AI services to be configured.")]
416418
public async Task<string> FindRelatedSections(
417419
[Description("The section slug/key to find related content for (e.g., 'async-await'). Use GetChapterSections to get valid slugs.")] string sectionKey,
420+
[Description("Number of related sections to return (1–10). Default is 5.")] int maxResults = AISearchService.DefaultSearchTop,
418421
CancellationToken cancellationToken = default)
419422
{
420423
if (string.IsNullOrWhiteSpace(sectionKey))
@@ -434,7 +437,7 @@ public async Task<string> FindRelatedSections(
434437
}
435438

436439
string query = $"{mapping.RawHeading} {mapping.ChapterTitle}";
437-
var results = await _SearchService.ExecuteVectorSearch(query, cancellationToken: cancellationToken);
440+
var results = await _SearchService.ExecuteVectorSearch(query, top: maxResults, cancellationToken: cancellationToken);
438441

439442
var sb = new StringBuilder();
440443
sb.AppendLine(CultureInfo.InvariantCulture, $"# Sections Related to: {mapping.RawHeading}");
@@ -447,7 +450,7 @@ public async Task<string> FindRelatedSections(
447450
{
448451
string heading = r.Record.Heading ?? "";
449452
if (!seen.Add(heading)) continue;
450-
if (count++ >= 3) break;
453+
if (count++ >= maxResults) break;
451454

452455
// Find the SiteMapping for this heading to get the link
453456
SiteMapping? relatedMapping = _SiteMappingService.SiteMappings

0 commit comments

Comments
 (0)