mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 21:12:11 +00:00
improved stability of embedding chunks
This commit is contained in:
parent
1bf9328fb9
commit
759c7f9d89
@ -25,6 +25,7 @@ public sealed record EmbeddingProvider(
|
|||||||
int TokenLimit = 8_191) : ConfigurationBaseObject, ISecretId
|
int TokenLimit = 8_191) : ConfigurationBaseObject, ISecretId
|
||||||
{
|
{
|
||||||
public const int DEFAULT_TOKEN_LIMIT = 8_191;
|
public const int DEFAULT_TOKEN_LIMIT = 8_191;
|
||||||
|
private const int ASSUMED_TOKEN_LIMIT_SAFETY_PERCENT = 80;
|
||||||
|
|
||||||
private static readonly ILogger<EmbeddingProvider> LOGGER = Program.LOGGER_FACTORY.CreateLogger<EmbeddingProvider>();
|
private static readonly ILogger<EmbeddingProvider> LOGGER = Program.LOGGER_FACTORY.CreateLogger<EmbeddingProvider>();
|
||||||
|
|
||||||
@ -57,6 +58,16 @@ public sealed record EmbeddingProvider(
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public int EffectiveTokenLimit => this.TokenLimit > 0 ? this.TokenLimit : DEFAULT_TOKEN_LIMIT;
|
public int EffectiveTokenLimit => this.TokenLimit > 0 ? this.TokenLimit : DEFAULT_TOKEN_LIMIT;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool UsesAssumedTokenSizing => string.IsNullOrWhiteSpace(this.TokenizerPath)
|
||||||
|
|| this.TokenLimit <= 0
|
||||||
|
|| this.TokenLimit == DEFAULT_TOKEN_LIMIT;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public int EffectiveChunkTokenLimit => this.UsesAssumedTokenSizing
|
||||||
|
? Math.Max(1, (int)Math.Ceiling(this.EffectiveTokenLimit * ASSUMED_TOKEN_LIMIT_SAFETY_PERCENT / 100d) - 1)
|
||||||
|
: this.EffectiveTokenLimit;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static bool TryParseEmbeddingProviderTable(int idx, LuaTable table, Guid configPluginId, out ConfigurationBaseObject provider)
|
public static bool TryParseEmbeddingProviderTable(int idx, LuaTable table, Guid configPluginId, out ConfigurationBaseObject provider)
|
||||||
|
|||||||
@ -82,7 +82,7 @@ public sealed partial class DataSourceEmbeddingService
|
|||||||
|
|
||||||
private async IAsyncEnumerable<string> SplitChunkByEmbeddingTokenLimitAsync(string chunk, EmbeddingProvider embeddingProvider, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken token)
|
private async IAsyncEnumerable<string> SplitChunkByEmbeddingTokenLimitAsync(string chunk, EmbeddingProvider embeddingProvider, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken token)
|
||||||
{
|
{
|
||||||
var tokenLimit = embeddingProvider.EffectiveTokenLimit;
|
var tokenLimit = embeddingProvider.EffectiveChunkTokenLimit;
|
||||||
var tokenCount = await this.GetEmbeddingTokenCountAsync(embeddingProvider, chunk, token);
|
var tokenCount = await this.GetEmbeddingTokenCountAsync(embeddingProvider, chunk, token);
|
||||||
if (tokenCount <= tokenLimit)
|
if (tokenCount <= tokenLimit)
|
||||||
{
|
{
|
||||||
@ -90,6 +90,15 @@ public sealed partial class DataSourceEmbeddingService
|
|||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (embeddingProvider.UsesAssumedTokenSizing)
|
||||||
|
{
|
||||||
|
logger.LogDebug(
|
||||||
|
"Using conservative embedding chunk limit {ChunkTokenLimit} for provider '{EmbeddingProviderName}' because tokenizer or token limit sizing is assumed. ConfiguredTokenLimit={ConfiguredTokenLimit}.",
|
||||||
|
tokenLimit,
|
||||||
|
embeddingProvider.Name,
|
||||||
|
embeddingProvider.EffectiveTokenLimit);
|
||||||
|
}
|
||||||
|
|
||||||
logger.LogDebug(
|
logger.LogDebug(
|
||||||
"Splitting an embedding chunk for provider '{EmbeddingProviderName}' because it has {TokenCount} tokens and the configured limit is {TokenLimit}.",
|
"Splitting an embedding chunk for provider '{EmbeddingProviderName}' because it has {TokenCount} tokens and the configured limit is {TokenLimit}.",
|
||||||
embeddingProvider.Name,
|
embeddingProvider.Name,
|
||||||
@ -430,7 +439,8 @@ public sealed partial class DataSourceEmbeddingService
|
|||||||
embeddingProvider.Host,
|
embeddingProvider.Host,
|
||||||
embeddingProvider.Hostname,
|
embeddingProvider.Hostname,
|
||||||
embeddingProvider.TokenizerPath,
|
embeddingProvider.TokenizerPath,
|
||||||
embeddingProvider.EffectiveTokenLimit);
|
embeddingProvider.EffectiveTokenLimit,
|
||||||
|
embeddingProvider.EffectiveChunkTokenLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> BuildFingerprintAsync(FileInfo file, CancellationToken token)
|
private async Task<string> BuildFingerprintAsync(FileInfo file, CancellationToken token)
|
||||||
|
|||||||
@ -424,7 +424,20 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
|||||||
dataSource.Id);
|
dataSource.Id);
|
||||||
|
|
||||||
var texts = batch.Select(item => item.Text).ToList();
|
var texts = batch.Select(item => item.Text).ToList();
|
||||||
var vectors = await provider.EmbedTextAsync(embeddingProvider.Model, settingsManager, token, texts);
|
IReadOnlyList<IReadOnlyList<float>> vectors;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
vectors = await provider.EmbedTextAsync(embeddingProvider.Model, settingsManager, token, texts);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"The embedding provider failed to embed {batch.Count} chunk(s) for file '{file.Name}'. Provider message: {exception.Message}", exception);
|
||||||
|
}
|
||||||
|
|
||||||
if (vectors.Count != batch.Count)
|
if (vectors.Count != batch.Count)
|
||||||
throw new InvalidOperationException($"The embedding provider returned {vectors.Count} vectors for {batch.Count} text chunks.");
|
throw new InvalidOperationException($"The embedding provider returned {vectors.Count} vectors for {batch.Count} text chunks.");
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user