Skip to content

[enhancement] import-markdown: batch embedding + bulkStore for large memory imports #728

@jlin53882

Description

@jlin53882

問題描述

目前 CLI 在處理大量 bullet point 時,是逐筆處理

// cli.ts:714-723(目前實作)
for (const line of lines) {
  const vector = await ctx.embedder!.embedPassage(text);  // N 次 API call
  await ctx.store.store({ text, vector, ... });            // N 次 lock acquire
}

當一個 .md 檔有 100 個 bullet point,就會產生 100 次 API call + 100 次 lock acquisition,效率很差。

觀察到的瓶頸

步驟 目前行為 優化方向
Embedding 每個 entry 單獨 call 改用 一次 API call
Deduplication 每個 entry 單獨 call 已在 PR #720 改用 hybrid search
Store 每個 entry 單獨 call 改用 一次 lock

建議實作方向

Phase 1:批次收集結構

在處理每個 .md 檔時,先把整個檔案的 bullet point 收集到陣列,再批次處理:

// 1. 先收集所有要處理的 entry(跳過 short / dedup 過的)
const pendingEntries: Array<{text: string, scope: string, filePath: string}> = [];
for (const line of lines) {
  if (!/^[-*+]\s/.test(line)) continue;
  const text = line.slice(2).trim();
  if (text.length < minTextLength) continue;
  // dedup check(已在 PR #720 使用 retrieve())
  if (dedupEnabled) {
    const existing = await ctx.retriever.retrieve({ query: text, limit: 20, scopeFilter: [effectiveScope], source: "cli" });
    if (existing.length > 0 && existing[0].entry.text === text) { skipped++; continue; }
  }
  pendingEntries.push({ text, scope: effectiveScope, filePath });
}

// 2. 批次 embedding(一次 API call)
const vectors = await ctx.embedder!.embedBatchPassage(pendingEntries.map(e => e.text));

// 3. 組裝並一次 bulkStore
const entries = pendingEntries.map((e, i) => ({
  text: e.text,
  vector: vectors[i],
  importance: importanceDefault,
  category: "other",
  scope: e.scope,
  metadata: JSON.stringify({ importedFrom: e.filePath }),
}));
await ctx.store.bulkStore(entries);
imported += entries.length;

需保持相容的行為

  • 模式:依然逐項報告,行為不變
  • Error handling:批次中某筆失敗不影響其他筆
  • Scope 正確性:每個 entry 保持原本推導的 scope
  • 進度回饋:大量 import 時仍有 console.log 讓使用者知道進度

相關改動

  • 需等 PR #720 合併(dedup 改用 retrieve)
  • API 已存在,直接使用
  • API 已存在,直接使用

預期效益

情境 改之前 改之後
100 個 entry 的 .md 100 次 embed call + 100 次 lock 1 次 embed call + 1 次 lock
1000 個 entry 1000 次 embed call + 1000 次 lock 1 次 embed call + 1 次 lock

連結的 Issue / PR

  • PR #720 — dedup uses retrieve() hybrid search(需先 merge)
  • Issue #629 — Ollama batch embedding bug fix(已關閉,相關 API 已修復)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions