Files
AnotherReplayReader/Utils/AiContextBudget.cs
T
2026-08-21 15:34:24 +02:00

80 lines
3.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
namespace AnotherReplayReader.Utils
{
/// <summary>
/// 上下文预算策略:每模型软上限、输出余量、估算安全系数与请求护栏。
/// </summary>
internal static class AiContextBudget
{
public const int Tier1MBudget = 160_000;
public const int Tier256KBudget = 100_000;
public const double EstimatorSafetyFactor = 1.2;
public const double HardUsageRatio = 0.9;
/// <summary>
/// 获取模型的一次请求总 token 软上限。0 表示该模型不支持长录像(只能短录像单 slice)。
/// </summary>
public static int GetContextBudget(AiModel model)
{
if (model.ContextBudget is { } explicitBudget && explicitBudget > 0)
{
return explicitBudget;
}
if (model.ContextLength >= 1_000_000)
{
return Tier1MBudget;
}
if (model.ContextLength >= 200_000)
{
return Tier256KBudget;
}
return 0;
}
/// <summary>为输出/推理 tokens 预留的余量。</summary>
public static int GetOutputHeadroom(AiProvider provider, AiModel model)
{
var maxTokens = provider.DefaultMaxTokens;
return Math.Max(2 * maxTokens, 32_000);
}
/// <summary>带安全系数的 token 估算(对中文偏乐观的 bytes/2.2 估算 × 1.2)。</summary>
public static int EstimateTokens(string text) =>
(int)Math.Ceiling(AIAnalyze.EstimateTokenCount(text).EstimatedTokenCount * EstimatorSafetyFactor);
/// <summary>请求护栏:超过硬上限返回 Block,超过软预算返回 Warn,否则 null。</summary>
public static ContextCheckResult CheckPromptUsage(
int estimatedPromptTokens,
AiProvider provider,
AiModel model)
{
if (model.ContextLength > 0)
{
var hardLimit = (int)(model.ContextLength * HardUsageRatio);
if (estimatedPromptTokens > hardLimit)
{
return new ContextCheckResult(
true,
$"估算输入 {estimatedPromptTokens:N0} token 超过模型上下文 {model.ContextLength:N0} 的 90%,已拒绝发起请求。请改用更长上下文的模型,或缩短操作记录。");
}
}
var budget = GetContextBudget(model);
if (budget > 0 && estimatedPromptTokens > budget)
{
return new ContextCheckResult(
false,
$"估算输入 {estimatedPromptTokens:N0} token 超过上下文预算 {budget:N0}(可在模型设置中调整),长录像将自动分段,超出部分会被压缩。");
}
return ContextCheckResult.Ok;
}
}
internal sealed record ContextCheckResult(bool Block, string Message)
{
public static ContextCheckResult Ok { get; } = new(false, string.Empty);
public bool IsOk => !Block && string.IsNullOrEmpty(Message);
}
}