# AI 分析 v2 计划:上下文策略与管线重构 ## 状态 - 日期:2026-08-20 - 版本:v2(重写)。v1 初稿未覆盖第一轮审视的部分问题;本文新增第 2 节"问题追踪表"并重组章节结构,确保第一轮提出的每一条问题都有对应的落地章节。 - 关联文档:[WIP.md](WIP.md)、[CONTEXT.md](CONTEXT.md)、`docs/adr/0001-hidden-revision-pass.md`、`docs/adr/0002-structured-game-knowledge.md` ## 实施状态(2026-08-20) 里程碑全部完成,代码已落地并通过 124 项单元测试(`AiV2.Tests`,见 §12 M7)。 | 里程碑 | 状态 | 备注 | | --- | --- | --- | | M1 预算与护栏 | ✅ | `AiModel.ContextBudget`(0/空 = 档位默认 160K/100K)、`AiContextBudget` 安全系数与硬护栏、设置 UI 编辑项 | | M2 管线重构 | ✅ | 机械分段 + 对局摘要 + 总览轮 + 分段独立会话 + 已发现事实 + 总结轮;移除 `[分段列表]` 解析与旧流式状态机;提示词与知识文件已重新生成 | | M3 回查机制 | ✅ | `[回查]` 标记、容错时间解析、切片提取、每段 3 次上限、失败降级 Info | | M4 验证修正 | ✅ | 所有权强/弱分层与 4 条规则、施法者归属(仅 `0x1FE/0x200`)、协议记录与校验、多 JSON 块合并、move 降级、首次出兵时间线、player 映射接线 | | M5 知识修正 | ✅ | `knowledge_units_default.json` 按 mod 加载、旧提示词副作用修复、标签体系补全与加载校验、渲染按参战阵营过滤、用户知识 JSON 覆盖 | | M6 修订 pass | ✅ | 段内 1 次修订、修订期间抑制流式显示、完成后替换段内容、UI 日志提示 | | M7 测试与评估 | ✅/部分 | 单元测试完成;A/B 对比与估算校准需真实 API 运行(见 §13) | **实施中的取舍与遗留** - `Data/StringHashes.xml` 是随仓库分发的本地 SDK 临时快照(约 3.5MB / 47,860 条),后续应改为可配置路径或只打包需要的 hash 子集。 - Corona 结构化知识(`knowledge_units_corona.json`)尚未编写:Corona 当前走 flat 文本(不剥离、不注入结构化条目),验证回退到启发式。 - 修订 pass 的展示采用"实时流式 + 修订后整段替换";ADR 0001 的"完全缓冲至验证完成"仍是开放项。 - `Fatal` 在“所有机器可读声明块均无法解析”时产生;修订输出为空时保留原分析。 - `MissingMachineReadableClaims` 为 Warning,并与其他 Warning/WeakEvidence 一样触发一次隐藏修订;是否保留该策略待 A/B 评估。 - 测试工程 `AiV2.Tests` 通过 `ProjectReference` 引用主工程;构建时通过 `AiV2TestsBuilding=true` 跳过主工程的 DLL 移动目标。 ## 实施状态修订(2026-08-22) - “重新分析”策略:除 `Info` 外,`Warning/WeakEvidence/Contradiction/Fatal` 都触发一次隐藏修订;修订后遗留问题仅记录,不循环请求。 - 预算检查改为“估算 prompt + 输出/推理余量”,并在回查/修订前重新检查;`stream` 标志尊重模型配置。 - 事实索引:编队所有权按玩家隔离;接入 `0x1F6/0x22A`;unpack 歧义规则只作用于 MCV/基地车类实体。 - 知识:`aliases/alsoProducedBy` 已解析;摘要补充协议选择与所有权证据;总览的段落描述和回查提示会传入分段指令。 - 测试:当前 `AiV2.Tests` 为 144 项断言全部通过。 ## 1. 背景与目标 应用现有 AI 分析流程为"全量日志 + LLM 分段建议 + 分段分析 + 总结",经文档与代码审视,存在四类问题:上下文膨胀(每轮重发全量日志)、验证层可信度(施法者/目标混淆、所有权证据缺失、解析脆弱)、知识层作用域(结构化数据无 mod 维度、提示词与验证知识漂移)、修订机制未落地(ADR 0001)。 本计划的目标: 1. 用"部分操作记录 + 结构化上下文"替代"每轮全量日志",在不明显牺牲远距离关联能力的前提下提升长录像的分析质量与成本效率。 2. 只维护一条分析管线:"短录像 = 只有一个 slice",不保留两个独立模式。 3. 上下文预算成为每模型可配置的软上限,并把长期未使用的 `ContextLength` 接进护栏。 4. 修正验证层与知识层在本会话中发现的所有问题(见第 2 节追踪表)。 5. 落地 ADR 0001 的隐藏修订 pass。 ## 2. 问题追踪表(第一轮审视 + 后续讨论确认) 下表汇总 2026-08-20 会话对 WIP/文档/代码的审视结论。后续讨论(所有权分层、缓存、预算、统一管线)调整了部分原始结论,表中"处理章节"指向本文的落地位置。 | # | 问题 | 处理章节 | | --- | --- | --- | | P1 | 结构化单位知识无 mod 维度:`knowledge_units.json` 是全局单例,Corona 盟军数据被基础版替换(如 `AlliedBomberAircraft` vs `AlliedAntiStructureBomberAircraft`),违背 ADR 0002"每 mod 自包含" | §8.1 | | P2 | `GetSystemPrompt` 无条件执行旧 `BuildDefaultSystemPrompt`,即使走知识文件也会弹"缺乏苏联/未知地图"MessageBox(副作用) | §8.2 | | P3 | 事实索引把特殊能力的施法者与目标混淆(`0x201/0x232` 的 ObjectId 不一定是施法者),Contradiction 校验可能误报/漏报 | §7.2 | | P4 | 协议(`0x24E 选择协议`)不在验证体系,evidence schema 无法表达无单位能力 | §7.3 | | P5 | 全量日志每轮重发、对话历史只增不减,长录像易超上下文;`ContextLength` 配置了但从未使用 | §4、§5、§6 | | P6 | 解析健壮性:`[分段列表]` 缺失导致整体失败、`ParseAITimeSpan` 抛异常、机器可读声明只解析最后一个 JSON 块(中间块静默丢失) | §7.4 | | P7 | `move` 证据只带坐标不带 UnitId,永远无法验证,却允许撑高置信结论 | §7.5 | | P8 | 所有权归属:原建议"只能选中自己单位"过强;修正为强/弱分层(编队≈确定,选择≈弱信号) | §7.1 | | P9 | 标签体系漂移:JSON 出现 `land/sea/miner/scout/support/siege/bomber` 等未定义 tag,`KnowledgeTag` 常量未被执行 | §8.3 | | P10 | `PlayerFirstProductionTime` 已建未消费,"首次出兵时间线"规则(如轰炸机)未做 | §7.6 | | P11 | 修订 pass 未接线:`RequiresRevision` 存在但未用,`Fatal` 严重度从不产生,严重度语义未统一 | §10、§7.7 | | P12 | 验证器/解析器/事实索引是纯逻辑但无测试 | §12 M7 | | P13 | token 估算 `bytes/2.2` 对中文偏乐观,且无真实用量校准 | §4.3 | | P14 | flat 文本作为单一 global 条目渲染,未参战阵营的知识也全部进入提示词(token 浪费) | §8.4 | | P15 | 提示词/知识文件写死三阶段流程(`[分段列表]` 输出要求),需与 v2 管线同步修改 | §9 | ## 3. 决策摘要 | 决策点 | 结论 | | --- | --- | | 上下文预算 | 每模型 `ContextBudget` 软上限,默认档位:≥1M → 160K;200K~256K → 100K;<200K → 只支持短录像(单 slice) | | 模式 | 单一管线;"全量模式"取消,短录像 = 1 个 slice | | 分段 | 机械式(按 token 预算 + 事件数,带重叠);不再由 LLM 决定边界 | | 总览轮 | 保留;输入为摘要 + 分段元数据(不读全量日志);输出允许跨段描述、跨段线索、回查建议 | | 回查机制 | 进 v1;允许模型按需请求远处原始区间 | | 缓存 | 稳定内容前置;跨段前缀 = system+摘要+总览;段内复用 = 前缀+slice(修订/回查共用) | | 128K 及以下 | 允许短录像(切片后为 1 个 slice 时自然工作),不承诺长录像质量 | | 修订 pass | 按 ADR 0001 在段内落地,每段最多 1 次 | ## 4. 上下文预算策略 ### 4.1 语义 - `ContextBudget` = 一次请求的总 token 软上限(prompt + 输出/推理余量)。 - 用户给出的 150K / 90K 已经是保守值;为显式容纳估算误差与输出余量,默认档位取 **160K(≥1M)/ 100K(200K~256K)**。 - 每个模型可单独覆盖(新增 `AiModel.ContextBudget`,0 表示用档位默认)。 ### 4.2 输出余量与切片上限 - 输出余量 = `max(2 × max_tokens, 32K)`,推理模型的 thinking token 计入输出余量。 - 切片上限由预算反推:`slice_max = ContextBudget − 固定开销 − 已发现事实 − 输出余量`。 - 参考值:1M 档 slice ≈ 90K;256K 档 slice ≈ 40K(固定开销约 system 20K + 摘要 3K + 总览 3K + 指令 1K)。 ### 4.3 估算与护栏 - 现用 `bytes / 2.2` 对中文偏乐观;切片计算统一加安全系数 ×1.2。 - 用 API 返回的真实 `usage`(已收集 `PromptTokens`)校准估算系数,可记录在设置中或仅用于诊断。 - 硬护栏:估算总用量超过 `ContextLength` 的 90% 时拒绝发起请求并提示;超过 `ContextBudget` 时警告并自动收缩 slice。 ## 5. 统一管线(单一模式) 流程:预处理 → 机械分段 → 对局摘要 → 总览轮 → 分段分析轮(每段独立会话)→ 总结轮。 ### 5.1 预处理 - 保留现有 `CompactLevel` 压缩逻辑。 - 长录像的切片若仍超过 slice_max(密集事件区),对切片再做一次噪声过滤(如丢弃纯选择、空选择),仍超限则按时间二次细分。 ### 5.2 机械分段 - 按事件累积估计 token,达到 slice_max 即切段;相邻段重叠前一段尾部 5%~10%(或 min(10%, 2K 事件))。 - 每段最小约 2K token;边界对齐 `TimeIndexedPrefixSums` 的事件分块。 - 分段数上限(如 20);超限时提高切片压缩力度而不是无限增加段数。 - N=1 时即旧"全量模式"的特例:整份日志作为一个 slice。 ### 5.3 对局摘要(确定性) - 来源:`ReplayFactIndex` + 规则采样器,不依赖 LLM 输出,保证同一次运行内稳定。 - 内容:玩家/阵营、首次出兵时间表、打包/展开链、建造者/生产者/所有权证据、协议选择、每段时间范围与事件数、每段采样关键事件(建造/摆放/出售/技能/协议)。 - 目标 2~5K token;是跨段缓存前缀的一部分。 ### 5.4 总览轮 - 输入:system + 对局摘要 + 机械分段元数据(每段时间范围、事件数、采样事件)。 - 输出(自由格式,允许跨段): - 每段标题 + 一两句概述(以机械段为锚点,不要求逐段对齐); - 整局走势的跨段描述; - 值得注意的跨段线索(如"第 1 段打包基地,第 3 段才重新展开"); - 回查建议(如"第 4 段分析时可回查 1:20~1:45")。 - 不读全量原始日志;输出在同一次运行内作为稳定前缀的一部分。 - 若总览轮输出明确建议合并/调整边界,v1 忽略,仅记录为后续可选优化。 - 总览轮失败(空输出/解析异常)→ 重试 1 次,仍失败则降级为"无总览输出"直接进入分段分析轮。 ### 5.5 分段分析轮 - 每段一个独立会话,消息顺序(缓存关键,稳定在前): `system → 对局摘要 → 总览输出 → slice_i → 已发现事实(1..i-1) → 段指令_i` - 段指令:段标题/概述 + "请重点分析第 N 段(起止时间),可回查远处区间";N=1 时改为"分析整局"。 - 输出:自然语言分析 + `[机器可读声明]`(沿用现有 schema,见 §7.4 的解析修正)。 - 同一段的后续请求(修订、回查)复用同一消息列表。 ### 5.6 已发现事实 - 每段分析完成后,由验证过的机器可读声明 + 3~5 句小结组成追加条目,每段 ≤ ~1K token。 - 追加在消息尾部,不影响前缀缓存;是跨段关联的主要载体。 ### 5.7 回查协议(v1) - 格式:段回复末尾输出 `[回查] mm:ss~mm:ss`(可多个)。 - 程序解析后从缓存日志切出该区间,作为同一会话的追加 user 消息发回。 - 限制:每段最多 3 次;单次区间 ≤ 10K token;总回查量受预算约束。 - 解析失败/越界/超限 → 忽略并记录 Info 级 issue,不中断流程。 - 时间解析复用容错解析器(见 §7.4),不允许抛异常导致整段失败。 - 回查区间内容不进入"已发现事实"(它是临时上下文,不跨会话累积)。 ### 5.8 总结轮 - 输入:system + 摘要 + 总览 + 各段分析 + 已发现事实(不含原始日志)。 - 沿用现有指令:允许跨段修正之前的分析;修正理由记录回验证层。 - 后段分析不直接改写前段结论,跨段修正统一由总结轮承担。 ## 6. 缓存设计 - 前缀顺序是核心实现细节:稳定内容在前,变量内容在后,不要在稳定段中间插入变化内容。 - 两层复用: - 跨段:`system + 摘要 + 总览输出` 对所有分段请求一致(主要命中点); - 段内:`以上 + slice_i` 被分析、修订、回查多次复用(P5 缓存诉求的落点)。 - 系统提示本身约 20K token,通常已超过各家缓存最小前缀要求;若未来换更短的 system,需复核。 - 成本说明:缓存折扣可达 90~95%,但本方案的主要动机是质量与延迟,成本是次要收益。 ## 7. 验证与事实索引修正 ### 7.1 所有权证据(强/弱分层)与校验规则(P8) - 强证据(近乎确定是己方单位):`0x1FA 创建编队` 的成员;以建造者/出兵建筑身份出现(`0x207/0x209/0x205`);维修(`0x228`)、出售(`0x20A`)、矿车指令(`0x212/0x248`);特殊能力施法者(仅 `0x1FE/0x200`,见 §7.2)。 - 弱证据(可能是点了敌方单位):`0x1F5 选择单位`;`0x1FB/0x1FC` 通过编队状态解析出的成员可升级为强证据。 - 注意:`0x205` 不带新单位 UnitId,不能作为所有权证据(只能做时间线检查,见 §7.6)。 - 校验规则: 1. 声称 X 属于 PlayerA 且为 `confirmed`/`highly likely`,但 X 对 A 无任何强/弱证据 → `WeakEvidence`。 2. X 存在 PlayerB 的强证据而声称属于 A → `Contradiction`。 3. X 仅有 PlayerB 的弱证据且对 A 无证据 → `Warning`,建议降置信度。 4. 双玩家强证据冲突(异常/作弊操作)→ `Contradiction`,提示无法判定归属。 - `unitClaims.player` 接入上述规则。 ### 7.2 特殊能力归属修正(P3) - 只对布局确凿的 `0x1FE/0x200` 记录施法者;`0x201/0x232`(及待核实的 `0x1FF`)不用于施法者校验。 - 用真实回放抽样验证各命令类型的 ObjectId 含义后再扩展。 ### 7.3 协议与选择类指令(P4) - 事实索引记录 `0x24E 选择协议`;evidence schema 新增 `protocol|时间|科技名`。 - 事实索引/编队状态补全:`0x1F6`、`0x1FA`、`0x1FB`、`0x1FC`、`0x22A`;维护编队号 → 成员 UnitId 的状态表。 ### 7.4 机器可读声明解析健壮性(P6) - 机器可读声明不再"只取最后一个 JSON 块":改为解析标记之后的所有 JSON 块并合并声明(重复 unitId 取后块),或至少对被忽略的块记录 Info issue。 - v2 移除 `[分段列表]` 解析(分段改机械式),消除"分段标记缺失导致整体失败"的路径。 - 时间解析统一改为容错实现(返回 null + issue,而不是抛异常),回查与段边界共用。 ### 7.5 move 证据处理(P7) - 提示词注明:`move` 证据只带坐标不带 UnitId,不能单独支撑 `confirmed`/`highly likely` 结论。 - 验证器对 move 证据不做交叉校验;若高置信声明仅有 move 类证据,补发 `WeakEvidence` 提示。 ### 7.6 首次出兵时间线规则(P10) - 消费 `PlayerFirstProductionTime`:如"某 UnitId 被操作的时间早于该玩家首次生产对应单位"→ `Contradiction`;"轰炸机在首次生产轰炸机之前就被操作"→ 要求降级或解释。 - 需要结构化知识的类型 tag 映射(如 `bomber`/`aircraft`/`producedBy`)支持"哪个单位名属于哪类",随 §8.1 的 mod 拆分落地。 ### 7.7 严重度语义统一(P11) - 明确 `Fatal` 的产生条件:段输出为空、机器可读声明完全不可解析,且修订后仍失败。 - `MissingMachineReadableClaims` 当前为 Warning(仅记录);是否升级为一次"修复请求"由 M6 与修订 pass 一并决定。 ## 8. 知识架构修正 ### 8.1 结构化数据按 mod 拆分(P1) - `knowledge_units.json` 按 mod 拆分(如 `knowledge_corona_units.json`)或加 mod 键,与 flat 文本同作用域。 - `StripUnitSections` 只剥离"该 mod 确有结构化数据"的阵营;硬编码章节标题改为可配置/可校验。 ### 8.2 旧提示词构建副作用修复(P2) - `GetSystemPrompt` 先查知识文件,命中即走 `RenderAsPrompt`;旧 `BuildDefaultSystemPrompt` 的副作用(苏联/未知地图 MessageBox)只在 fallback 路径执行。 ### 8.3 标签体系执行(P9) - 加载 `knowledge_units.json` 时校验未知 tag 并告警;补全/收敛 taxonomy(`land/sea/miner/scout/support/siege/bomber` 等要么进定义、要么移除)。 - 加载告警在 Debug/设置页可见,避免静默漂移。 ### 8.4 渲染过滤(P14) - flat 文本按参战阵营过滤非参战阵营章节;结构化渲染只渲染参战阵营(`RenderAsPrompt` 已有 factionNames 参数,flat 文本需要配套切分)。 ### 8.5 用户知识 JSON 加载(WIP 遗留) - 落地 `AnotherReplayReader.user_knowledge.json`:按 id 覆盖内置条目,加载顺序:内置 → 用户覆盖。 ## 9. 提示词与知识文件更新 ### 9.1 v2 流程(P15) - 三阶段流程改为:总览轮(无 `[分段列表]` 输出)→ 分段分析轮 → 总结轮。 - 同步修改 `knowledge_default.md`、`knowledge_corona.md`、`BuildDefaultSystemPrompt` 回退路径和 `tools/expand_knowledge.py` 生成的模板。 ### 9.2 选择/所有权表述修正(P8) - 修正"选择单位……这些操作的对象是玩家自己的单位":选择可能包含敌方单位(不能下达命令);加入编队几乎可确定是己方单位。 ### 9.3 evidence 格式更新(P4、P7) - 补充 `protocol|时间|科技名` 类型。 - 注明 `move` 证据的验证限制(见 §7.5)。 ## 10. 修订 pass(ADR 0001 落地,P11) - 段内执行:草稿 + 验证 issue + 相关事实 → 干净修正版;每段最多 1 次。 - 修订后仍 `Fatal` → 回退显示原文 + 警告(`Fatal` 条件见 §7.7)。 - 修订请求复用段内会话(同一前缀,缓存友好)。 - UI:增加"验证器发现并修正 N 个问题"提示;沿用 ADR 0001 的缓冲决策(段内容缓冲至验证/修订完成)。 ## 11. 设置与 UI - `AiModel.ContextBudget`(0 = 档位默认);`AIProviderSettingsControl` 增加编辑项。 - 128K 及以下模型:允许短录像(单 slice),设置页提示"长录像不保证质量"。 - 请求 Token 构成展示:system / 摘要 / 总览 / slice / 已发现事实 / 输出余量。 - 可选:回查统计(次数、命中率)与估算系数校准结果显示。 ## 12. 实施步骤(里程碑) 1. **M1 预算与护栏**:`ContextBudget` + 档位默认 + 估算安全系数 + 超限警告/拒绝。 2. **M2 管线重构**:机械分段 + 对局摘要 + 总览轮 + 分段独立会话;移除 `[分段列表]` 解析(P5、P6)。 3. **M3 回查机制**:标记解析(容错时间解析)、切片提取、限流、失败降级。 4. **M4 验证修正**:所有权证据与规则(§7.1)、施法者归属(§7.2)、协议与选择指令(§7.3)、JSON 解析健壮性(§7.4)、move 降级(§7.5)、首次出兵时间线(§7.6)、严重度语义(§7.7)。 5. **M5 知识修正**:mod 拆分(§8.1)、副作用修复(§8.2)、标签校验(§8.3)、渲染过滤(§8.4)、用户知识 JSON(§8.5)。 6. **M6 修订 pass**:段内修订 + UI 提示 + 缓冲(§10)。 7. **M7 测试与评估**:单元测试(解析器/验证器/事实索引/分段)+ A/B 对比(§13)。 依赖关系:M2 先于 M3;M4/M5 可与 M2 并行;M6 依赖 M2 + M4;M7 覆盖全部。 完成标准(每步):`dotnet build` 通过;对应功能用手工回放验证一次;解析/验证改动附单元测试(M7 前至少保证新增逻辑可测)。 ## 13. 评估方法 - 指标:验证 issue 数量与严重度分布;关键事件覆盖率(人工清单抽查);总 token/费用;耗时;回查次数与命中率;总览轮失败率。 - A/B:同一录像对比现状(全量模式)与 v2 管线,优先选短/中/长各一局。 - 校准:用真实 `usage` 修正估算系数,检查预算是否被实际超用。 ## 14. 风险与开放问题 - 密集事件段可能仍超 slice 预算 → 切片压缩与二次细分是兜底。 - 总览轮质量影响后续所有段 → 摘要/采样质量需要迭代;失败降级路径见 §5.4。 - 回查滥用或格式不稳定 → 限流 + 失败降级(§5.7)。 - 修订后机器可读声明可能与正文不一致 → 修订轮要求同时重出声明并重新验证。 - 用户在运行中修改设置导致前缀变化 → 缓存失效,仅影响本次运行。 - 开放:段内容缓冲 vs 实时流式的最终 UI 决策;是否允许总览轮建议边界调整(v2 候选);`MissingMachineReadableClaims` 是否触发修复请求(§7.7)。 ## 15. 本计划不涉及 - 非 AI 分析功能、其他 UI 改动、第三方库升级。