Improve L0 extraction flow and recall robustness

This commit is contained in:
2026-02-10 12:43:43 +08:00
parent 3af76a9651
commit 1fe0647462
5 changed files with 370 additions and 120 deletions

View File

@@ -526,6 +526,52 @@ async function handleClearVectors() {
xbLog.info(MODULE_ID, "向量数据已清除");
}
// ═══════════════════════════════════════════════════════════════════════════
// L0 自动补提取(每收到新消息后检查并补提取缺失楼层)
// ═══════════════════════════════════════════════════════════════════════════
async function maybeAutoExtractL0() {
const vectorCfg = getVectorConfig();
if (!vectorCfg?.enabled) return;
if (anchorGenerating || vectorGenerating) return;
const { chatId, chat } = getContext();
if (!chatId || !chat?.length) return;
const stats = await getAnchorStats();
if (stats.pending <= 0) return;
anchorGenerating = true;
try {
await incrementalExtractAtoms(chatId, chat, null, { maxFloors: 20 });
// 为新提取的 L0 楼层构建 L1 chunks
await buildIncrementalChunks({ vectorConfig: vectorCfg });
invalidateLexicalIndex();
await sendAnchorStatsToFrame();
await sendVectorStatsToFrame();
xbLog.info(MODULE_ID, "自动 L0 补提取完成");
} catch (e) {
xbLog.error(MODULE_ID, "自动 L0 补提取失败", e);
} finally {
anchorGenerating = false;
}
}
// ═══════════════════════════════════════════════════════════════════════════
// Embedding 连接预热
// ═══════════════════════════════════════════════════════════════════════════
function warmupEmbeddingConnection() {
const vectorCfg = getVectorConfig();
if (!vectorCfg?.enabled) return;
embed(['.'], vectorCfg, { timeout: 5000 }).catch(() => {});
}
// ═══════════════════════════════════════════════════════════════════════════
// 实体词典注入 + 索引预热
// ═══════════════════════════════════════════════════════════════════════════
@@ -1284,6 +1330,9 @@ async function handleChatChanged() {
// 实体词典注入 + 索引预热
refreshEntityLexiconAndWarmup();
// Embedding 连接预热(保持 TCP keep-alive减少首次召回超时
warmupEmbeddingConnection();
setTimeout(() => checkVectorIntegrityAndWarn(), 2000);
}
@@ -1316,7 +1365,10 @@ async function handleMessageReceived() {
// 向量全量生成中时跳过 L1 sync避免竞争写入
if (vectorGenerating) return;
await syncOnMessageReceived(chatId, lastFloor, message, vectorConfig);
await syncOnMessageReceived(chatId, lastFloor, message, vectorConfig, () => {
sendAnchorStatsToFrame();
sendVectorStatsToFrame();
});
await maybeAutoBuildChunks();
applyHideStateDebounced();
@@ -1324,6 +1376,9 @@ async function handleMessageReceived() {
// 新消息后刷新实体词典(可能有新角色)
refreshEntityLexiconAndWarmup();
// 自动补提取缺失的 L0延迟执行避免与当前楼提取竞争
setTimeout(() => maybeAutoExtractL0(), 2000);
}
function handleMessageSent() {