This commit is contained in:
2026-08-22 00:59:46 +02:00
parent 9250528442
commit a2f0bcb371
6 changed files with 292 additions and 6 deletions
+48
View File
@@ -133,6 +133,27 @@ namespace AiV2.Tests
// 小预算 → 至少 MinSliceTokens 才切
var (minSlices, _) = MechanicalSegmenter.Slice(fullText, spans.ToImmutable(), 100, 50);
Program.Assert(!minSlices.IsEmpty, "小预算仍应有切片");
// 超过 20 段时优先压缩纯选择块
var mixedBuilder = ImmutableArray.CreateBuilder<EventSpan>();
var mixedTextBuilder = new StringBuilder();
for (var i = 0; i < 30; ++i)
{
var text = $"[{i}:00]\nPlayerA: 选择单位\n [UnitId]{i}\n\n";
mixedBuilder.Add(new EventSpan(TimeSpan.FromMinutes(i), mixedTextBuilder.Length, text.Length, 1000));
mixedTextBuilder.Append(text);
}
for (var i = 30; i < 60; ++i)
{
var text = $"[{i}:00]\nPlayerA: 开始建造\n [UnitId]{i}\n\n";
mixedBuilder.Add(new EventSpan(TimeSpan.FromMinutes(i), mixedTextBuilder.Length, text.Length, 1000));
mixedTextBuilder.Append(text);
}
var mixedText = mixedTextBuilder.ToString();
var (mixedSlices, mixedWarnings) = MechanicalSegmenter.Slice(
mixedText, mixedBuilder.ToImmutable(), 2000, 400);
Program.Assert(mixedSlices.Length <= MechanicalSegmenter.MaxSlices, "压缩后分段数不超过上限");
Program.Assert(mixedWarnings.Any(w => w.Contains("过滤纯选择")), "超过上限时先压缩噪声块");
}
}
@@ -455,6 +476,23 @@ namespace AiV2.Tests
var conflictingPower = Validate("[机器可读声明]\n```json\n{\"unitClaims\":[{\"unitId\":7,\"player\":\"PlayerA\",\"claim\":\"AlliedMCV\",\"evidenceLevel\":\"confirmed\",\"evidence\":[\"power|0:01.00|SpecialPower_UnpackReplaceSelf|7\"]}]}\n```", index);
Program.Assert(conflictingPower.Issues.Any(i => i.Kind == AIValidationIssueKind.UnitCapabilityContradiction
&& i.Message.Contains("SpecialPower_UnpackReplaceSelf")), "记录过其他能力 → Contradiction");
// 事件声明:引用不存在的 UnitId → Warning
var badEventUnit = Validate("[机器可读声明]\n```json\n{\"eventClaims\":[{\"claim\":\"某事件\",\"evidenceLevel\":\"confirmed\",\"evidence\":[\"power|0:01.00|SpecialPower_Nonexistent|999\"]}]}\n```", index);
Program.Assert(badEventUnit.Issues.Any(i => i.Kind == AIValidationIssueKind.InvalidMachineReadableClaims
&& i.Severity == AIValidationSeverity.Warning
&& i.Message.Contains("999")), "事件声明引用不存在 UnitId → Warning");
// 事件声明:技能与事实索引冲突 → Contradiction
var badEventPower = Validate("[机器可读声明]\n```json\n{\"eventClaims\":[{\"claim\":\"基地迁移\",\"evidenceLevel\":\"confirmed\",\"evidence\":[\"power|0:01.00|SpecialPower_UnpackReplaceSelf|7\"]}]}\n```", index);
Program.Assert(badEventPower.Issues.Any(i => i.Kind == AIValidationIssueKind.UnitCapabilityContradiction
&& i.Severity == AIValidationSeverity.Contradiction), "事件声明技能冲突 → Contradiction");
// 事件声明:协议未在任何玩家选择中观察到 → Warning
var badEventTech = Validate("[机器可读声明]\n```json\n{\"eventClaims\":[{\"claim\":\"协议事件\",\"evidenceLevel\":\"confirmed\",\"evidence\":[\"protocol|0:02.00|PlayerTech_Unknown\"]}]}\n```", index);
Program.Assert(badEventTech.Issues.Any(i => i.Kind == AIValidationIssueKind.InvalidMachineReadableClaims
&& i.Severity == AIValidationSeverity.Warning
&& i.Message.Contains("PlayerTech_Unknown")), "事件声明未观察协议 → Warning");
}
private static AIValidationResult Validate(string response, ReplayFactIndex index) =>
@@ -608,6 +646,11 @@ namespace AiV2.Tests
Program.Assert(prompt.Contains("基地车"), "结构化渲染包含盟军单位");
Program.Assert(!prompt.Contains("神州常用建筑"), "未参战阵营(神州)被过滤");
Program.Assert(prompt.Contains("地图参数") || prompt.Contains("出生点"), "地图知识保留");
var corona = KnowledgeSet.ForMod("corona", AppContext.BaseDirectory);
var coronaPrompt = corona.RenderAsPrompt(new[] { "盟军" }, "map_mp_2_rao1");
Program.Assert(coronaPrompt.Contains("盟军"), "Corona 盟军知识保留");
Program.Assert(!coronaPrompt.Contains("神州常用建筑"), "Corona 未参战阵营(神州)被过滤");
}
}
@@ -709,6 +752,11 @@ namespace AiV2.Tests
{
public static void Run()
{
if (Environment.GetEnvironmentVariable("ARR_E2E_REPLAY") != "1")
{
Console.WriteLine(" [跳过] 未设置 ARR_E2E_REPLAY=1,跳过真实回放诊断");
return;
}
var replayPath = @"C:\Users\lanyi\Documents\Red Alert 3\Replays\安洁莉娜.(C)_VS_机枢舞者(A)[1V1][无限岛][2026_06_16 05_57][ra3battle.net].RA3Replay";
if (!File.Exists(replayPath))
{