From 246eb7a7e2f48f673a3f4667a1ca6c951a68f16b Mon Sep 17 00:00:00 2001 From: bielie Date: Mon, 16 Feb 2026 23:26:45 +0800 Subject: [PATCH] tune recall threshold and increase distant evidence budget --- modules/story-summary/generate/prompt.js | 26 ++++++++++++++++--- .../story-summary/vector/retrieval/recall.js | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/modules/story-summary/generate/prompt.js b/modules/story-summary/generate/prompt.js index 3364b33..8ac6d98 100644 --- a/modules/story-summary/generate/prompt.js +++ b/modules/story-summary/generate/prompt.js @@ -49,7 +49,7 @@ const CONSTRAINT_MAX = 2000; const ARCS_MAX = 1500; const EVENT_BUDGET_MAX = 5000; const RELATED_EVENT_MAX = 500; -const SUMMARIZED_EVIDENCE_MAX = 1500; +const SUMMARIZED_EVIDENCE_MAX = 2000; const UNSUMMARIZED_EVIDENCE_MAX = 2000; const TOP_N_STAR = 5; @@ -949,6 +949,8 @@ async function buildVectorPrompt(store, recallResult, causalById, focusCharacter const candidates = [...eventHits].sort((a, b) => (b.similarity || 0) - (a.similarity || 0)); const eventBudget = { used: 0, max: Math.min(EVENT_BUDGET_MAX, total.max - total.used) }; const relatedBudget = { used: 0, max: RELATED_EVENT_MAX }; + // Once budget becomes tight, keep high-score L2 summaries and stop attaching evidence. + let allowEventEvidence = true; const selectedDirect = []; const selectedRelated = []; @@ -964,27 +966,39 @@ async function buildVectorPrompt(store, recallResult, causalById, focusCharacter // 硬规则:RELATED 事件不挂证据(不挂 L0/L1,只保留事件摘要) // DIRECT 才允许收集事件内证据组。 - const evidenceGroups = isDirect + const useEvidenceForThisEvent = isDirect && allowEventEvidence; + const evidenceGroups = useEvidenceForThisEvent ? collectEvidenceGroupsForEvent(e.event, l0Selected, l1ByFloor, usedL0Ids) : []; // 格式化事件(含证据) const text = formatEventWithEvidence(e, 0, evidenceGroups, causalById); const cost = estimateTokens(text); + const fitEventBudget = eventBudget.used + cost <= eventBudget.max; + const fitRelatedBudget = isDirect || (relatedBudget.used + cost <= relatedBudget.max); // 预算检查:整个事件(含证据)作为原子单元 - if (total.used + cost > total.max) { + // 约束:总预算 + 事件预算 + related 子预算(若 applicable) + if (total.used + cost > total.max || !fitEventBudget || !fitRelatedBudget) { // 尝试不带证据的版本 const textNoEvidence = formatEventWithEvidence(e, 0, [], causalById); const costNoEvidence = estimateTokens(textNoEvidence); + const fitEventBudgetNoEvidence = eventBudget.used + costNoEvidence <= eventBudget.max; + const fitRelatedBudgetNoEvidence = isDirect || (relatedBudget.used + costNoEvidence <= relatedBudget.max); - if (total.used + costNoEvidence > total.max) { + if (total.used + costNoEvidence > total.max || !fitEventBudgetNoEvidence || !fitRelatedBudgetNoEvidence) { // 归还 usedL0Ids for (const group of evidenceGroups) { for (const l0 of group.l0Atoms) { usedL0Ids.delete(l0.id); } } + // Hard cap reached: no-evidence version also cannot fit total/event budget. + // Keep ranking semantics (higher-score events first): stop here. + if (total.used + costNoEvidence > total.max || !fitEventBudgetNoEvidence) { + break; + } + // Related sub-budget overflow: skip this related event and continue. continue; } @@ -994,6 +1008,10 @@ async function buildVectorPrompt(store, recallResult, causalById, focusCharacter usedL0Ids.delete(l0.id); } } + // Enter summary-only mode after first budget conflict on evidence. + if (useEvidenceForThisEvent && evidenceGroups.length > 0) { + allowEventEvidence = false; + } if (isDirect) { selectedDirect.push({ diff --git a/modules/story-summary/vector/retrieval/recall.js b/modules/story-summary/vector/retrieval/recall.js index ed2ba8b..b049e32 100644 --- a/modules/story-summary/vector/retrieval/recall.js +++ b/modules/story-summary/vector/retrieval/recall.js @@ -60,7 +60,7 @@ const CONFIG = { // Event (L2 Events) EVENT_CANDIDATE_MAX: 100, EVENT_SELECT_MAX: 50, - EVENT_MIN_SIMILARITY: 0.55, + EVENT_MIN_SIMILARITY: 0.60, EVENT_MMR_LAMBDA: 0.72, EVENT_ENTITY_BYPASS_SIM: 0.70,