Refactor token usage and enhance logging capabilities

- Updated `TokenUsage` class properties to `PromptTokens` and `CompletionTokens`.
- Modified `Ask.razor` to display new token counts.
- Added logger to `ChatService` constructor for improved logging.
- Implemented logging for token usage in `ChatService` methods.
- Changed logging level to `Debug` for paragraph storage in `VectorSearchService`.
- Updated logging configuration in `appsettings.Development.json` for better visibility.
This commit is contained in:
Marco Minerva
2025-03-24 10:12:04 +01:00
parent a0d1126d15
commit 406618527c
5 changed files with 13 additions and 8 deletions
@@ -235,9 +235,9 @@
return string.Empty; return string.Empty;
} }
return $"Input Token Count: {tokenUsage.InputTokenCount}<br />" + return $"Prompt tokens: {tokenUsage.PromptTokens}<br />" +
$"Output Token Count: {tokenUsage.OutputTokenCount}<br />" + $"Completion tokens: {tokenUsage.CompletionTokens}<br />" +
$"Total Token Count: {tokenUsage.TotalTokenCount}"; $"Total tokens: {tokenUsage.TotalTokens}";
} }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
namespace SqlDatabaseVectorSearch.Models; namespace SqlDatabaseVectorSearch.Models;
public record class TokenUsage(int InputTokenCount, int OutputTokenCount) public record class TokenUsage(int PromptTokens, int CompletionTokens)
{ {
public int TotalTokenCount => InputTokenCount + OutputTokenCount; public int TotalTokens => PromptTokens + CompletionTokens;
} }
@@ -10,7 +10,7 @@ using SqlDatabaseVectorSearch.Settings;
namespace SqlDatabaseVectorSearch.Services; namespace SqlDatabaseVectorSearch.Services;
public class ChatService(IChatCompletionService chatCompletionService, TokenizerService tokenizerService, HybridCache cache, IOptions<AppSettings> appSettingsOptions) public class ChatService(IChatCompletionService chatCompletionService, TokenizerService tokenizerService, HybridCache cache, IOptions<AppSettings> appSettingsOptions, ILogger<ChatService> logger)
{ {
private readonly AppSettings appSettings = appSettingsOptions.Value; private readonly AppSettings appSettings = appSettingsOptions.Value;
@@ -36,6 +36,7 @@ public class ChatService(IChatCompletionService chatCompletionService, Tokenizer
await UpdateCacheAsync(conversationId, chat, cancellationToken); await UpdateCacheAsync(conversationId, chat, cancellationToken);
var tokenUsage = GetTokenUsage(reformulatedQuestion); var tokenUsage = GetTokenUsage(reformulatedQuestion);
logger.LogDebug("Reformulation: {TokenUsage}", tokenUsage);
return new(reformulatedQuestion.Content!, tokenUsage); return new(reformulatedQuestion.Content!, tokenUsage);
} }
@@ -53,6 +54,7 @@ public class ChatService(IChatCompletionService chatCompletionService, Tokenizer
await SetChatHistoryAsync(conversationId, question, answer.Content!, cancellationToken); await SetChatHistoryAsync(conversationId, question, answer.Content!, cancellationToken);
var tokenUsage = GetTokenUsage(answer); var tokenUsage = GetTokenUsage(answer);
logger.LogDebug("Ask question: {TokenUsage}", tokenUsage);
return new(answer.Content!, tokenUsage); return new(answer.Content!, tokenUsage);
} }
@@ -78,6 +80,7 @@ public class ChatService(IChatCompletionService chatCompletionService, Tokenizer
var tokenUsage = GetTokenUsage(token); var tokenUsage = GetTokenUsage(token);
if (tokenUsage is not null) if (tokenUsage is not null)
{ {
logger.LogDebug("Ask streaming: {TokenUsage}", tokenUsage);
yield return new(null, tokenUsage); yield return new(null, tokenUsage);
} }
} }
@@ -47,7 +47,7 @@ public class VectorSearchService(IServiceProvider serviceProvider, ApplicationDb
// Save the document chunks and the corresponding embedding in the database. // Save the document chunks and the corresponding embedding in the database.
foreach (var (index, paragraph) in paragraphs.Index()) foreach (var (index, paragraph) in paragraphs.Index())
{ {
logger.LogInformation("Storing a paragraph of {TokenCount} tokens.", tokenizerService.CountChatCompletionTokens(paragraph)); logger.LogDebug("Storing a paragraph of {TokenCount} tokens.", tokenizerService.CountChatCompletionTokens(paragraph));
var documentChunk = new Entities.DocumentChunk { Document = document, Index = index, Content = paragraph!, Embedding = embeddings[index].ToArray() }; var documentChunk = new Entities.DocumentChunk { Document = document, Index = index, Content = paragraph!, Embedding = embeddings[index].ToArray() };
dbContext.DocumentChunks.Add(documentChunk); dbContext.DocumentChunks.Add(documentChunk);
@@ -103,7 +103,9 @@ public class VectorSearchService(IServiceProvider serviceProvider, ApplicationDb
{ {
// Reformulate the question taking into account the context of the chat to perform keyword search and embeddings. // Reformulate the question taking into account the context of the chat to perform keyword search and embeddings.
var reformulatedQuestion = reformulate ? await chatService.CreateQuestionAsync(question.ConversationId, question.Text, cancellationToken) : new(question.Text); var reformulatedQuestion = reformulate ? await chatService.CreateQuestionAsync(question.ConversationId, question.Text, cancellationToken) : new(question.Text);
var embeddingTokenCount = tokenizerService.CountEmbeddingTokens(reformulatedQuestion.Text!); var embeddingTokenCount = tokenizerService.CountEmbeddingTokens(reformulatedQuestion.Text!);
logger.LogDebug("Embedding Token Count: {EmbeddingTokenCount}", embeddingTokenCount);
// Perform Vector Search on SQL Database. // Perform Vector Search on SQL Database.
var questionEmbedding = await textEmbeddingGenerationService.GenerateEmbeddingAsync(reformulatedQuestion.Text!, cancellationToken: cancellationToken); var questionEmbedding = await textEmbeddingGenerationService.GenerateEmbeddingAsync(reformulatedQuestion.Text!, cancellationToken: cancellationToken);
@@ -3,7 +3,7 @@
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning", "Microsoft.AspNetCore": "Warning",
"Microsoft.KernelMemory": "Debug" "SqlDatabaseVectorSearch": "Debug"
} }
} }
} }