Skip to content

Groundlane 實戰系列(篇 6):Document 工具全家桶 — effort 旋鈕、field-aware chunking 與 confidence routing

2026年9月11日1 分鐘
TL;DRdocument_parse 新增 effort 參數(fast/standard/deep)把 anydoc WASM、OCR.space、Docling VLM 三條路徑統一成一個旋鈕;document_chunk 的 fieldAware 模式從表格 header 和 metadata 抽欄位名附到 chunk,解決 RAG 的 attribute conflation;document_smart_parse 回傳 confidence 分數讓 agent 自己決定要不要升級。
目錄
  1. 為什麼需要 effort 旋鈕
  2. field-aware chunking:解決 RAG 的 attribute conflation
  3. confidence routing:讓 agent 自己決定
  4. Docling-serve VLM adapter
  5. 整體來說
  6. 參考資料
系列: Groundlane 實戰系列 (6 / 1)

🌏 English version

前五篇把 Groundlane 的 Web 工具從概念走到踩坑清單(篇 1:為什麼需要受控存取層篇 2:三個工具的參數與回傳篇 3:與傳統方案對比篇 4:站內應用篇 5:踩坑與最佳實踐)。這篇進入 Document 工具——Groundlane 從 v0.1.0 之後擴展到 55 個工具,其中文件解析相關佔了超過 20 個。這篇聚焦三個設計決策:effort 參數、field-aware chunking、confidence routing。

為什麼需要 effort 旋鈕

Groundlane 的文件解析有三條路徑,各自獨立存在:

路徑工具成本精度適合
確定性本地解析document_parse(anydoc WASM)$0數位原生 PDF/DOCX/CSV
OCRdocument_ocr(OCR.space)免費額度 25k/月高(掃描件)掃描 PDF、圖片
VLM 版面解析Docling-serve(GraniteDocling 258M)自架成本最高複雜表格、多欄、圖文混排

問題是:caller 必須自己判斷該用哪個工具。一個 PDF 可能前三頁是數位文字、第四頁是掃描的附件——你要先用 document_smart_parse 偵測,再決定走哪條路。

MinerU 的設計(effort: medium | high 參數,在同一引擎內調整解析深度),Groundlane 把三條路徑統一成 document_parseeffort 參數:

{
  "name": "document_parse",
  "arguments": {
    "source": {
      "kind": "inline",
      "dataBase64": "...",
      "mimeType": "application/pdf",
      "filename": "report.pdf"
    },
    "output": "markdown",
    "effort": "standard"
  }
}
  • fast(預設):走 anydoc WASM 確定性解析,零成本,適合已知是數位原生的文件
  • standard:先跑 fast,然後偵測內容是否為掃描件(用 pdf.js 分析前 5 頁的文字量);若超過半數頁面文字量低於 5 個字元,自動升級到 OCR.space
  • deep:走 Docling-serve VLM 路徑,用 GraniteDocling 258M 做版面感知解析

response 加了 effortUsed 欄位,告訴 caller 實際走了哪條路:

{
  "ok": true,
  "data": {
    "effortUsed": "standard",
    "envelope": { "..." },
    "projection": { "..." },
    "mediaType": "application/pdf",
    "bytes": 245760
  }
}

與 MinerU 的差異:MinerU 的 effort 在同一引擎內調整(規則引擎的強度),Groundlane 的 effort 跨引擎路由(anydoc → OCR → VLM)。MinerU 的 vlm-engine 是通用介面可接不同 VLM,Groundlane 目前固定接 Docling-serve。兩者不是替代關係——MinerU 是獨立的解析工具,Groundlane 是 MCP server 的統一入口。

field-aware chunking:解決 RAG 的 attribute conflation

這個功能直接源自一個在攀岩推薦系統上踩到的 RAG 問題(完整分析):使用者查「美人照鏡 5.11b,推薦類似難度的路線」,結果回來的全是名字像的路線——難度從 5.8 到 5.12 都有。

根因是 dense embedding(如 bge-m3)把多個獨立屬性壓進同一個向量。「美人照鏡」作為專有名詞在 embedding 空間裡區辨力極高,「5.11b」作為結構化等級標記出現頻率遠高於特定路線名——模型自然把更多注意力放在稀有詞上。這就是 attribute conflation。

解法之一是在 chunk 階段就保留欄位資訊,讓下游向量庫做 metadata pre-filter。Groundlane 的 document_chunk 新增了 fieldAware 參數:

{
  "name": "document_chunk",
  "arguments": {
    "dataBase64": "...",
    "mimeType": "text/csv",
    "filename": "routes.csv",
    "fieldAware": true
  }
}

開啟後,每個 chunk 會多一個 fields 陣列:

{
  "chunkId": "chunk-L0-0",
  "text": "Name | Grade | Location | Type\nBeauty Mirror | 5.11b | Dragon Cave | Sport",
  "tokenCount": 18,
  "blockRefs": ["table-1"],
  "fields": ["Name", "Grade", "Location", "Type"]
}

欄位名從兩個來源提取:

  1. 表格 header:表格第一行(row 0)的非空白內容
  2. Document metadata:envelope 裡的 metadata key-value pairs

下游寫入向量庫時,可以把 fields 存為 metadata:

# 寫入 Vectorize / Pinecone / Qdrant 時
for chunk in response["data"]["chunks"]:
    vector_db.upsert(
        id=chunk["chunkId"],
        text=chunk["text"],
        metadata={"fields": chunk["fields"]}  # 用於 pre-filter
    )

# 查詢時
results = vector_db.query(
    text="推薦 5.11b 難度的路線",
    filter={"fields": {"$contains": "Grade"}}  # 只搜有 Grade 欄位的 chunk
)

這不是完整的解法——完整方案需要 query rewriting + score fusion(見原文的三層防線)——但它在 chunking 階段就減少了噪音,成本是零(純規則提取,不呼叫 LLM)。

confidence routing:讓 agent 自己決定

document_smart_parse 原本就會偵測掃描件(用 pdf.js 分析每頁文字量),但它只在 response 裡告訴你「這是掃描 PDF」而不會建議你下一步該做什麼。新版加了 confidence 物件:

{
  "ok": true,
  "data": {
    "routedTo": "document_parse",
    "routeReason": "Mixed PDF: pages 1, 2 have text, pages 3, 4 appear scanned",
    "confidence": {
      "score": 0.75,
      "suggestedEffort": "standard",
      "reason": "2 of 4 pages appear scanned"
    },
    "content": "...",
    "engine": "groundlane-bounded-document-v3"
  }
}

confidence 的計算邏輯:

情況scoresuggestedEffort
全部頁面有文字0.95fast
全部掃描,有 OCR 且已使用0.7standard
全部掃描,OCR 未配置0.1deep
混合(部分掃描)1 - scannedRatio × 0.5scannedRatio > 0.3 → standard
大檔案但幾乎沒提取到文字0.2standard

這遵循 Agentic Parsing 的核心思路:不是自動升級(那會違反 bounded cost 原則),而是給 agent 資訊讓它決定。agent 可以這樣用:

  1. 先呼叫 document_smart_parse
  2. confidence.score——如果 > 0.8,用 fast 就夠了
  3. 如果 < 0.5,用 document_parseeffort: "standard""deep" 重新解析

Docling-serve VLM adapter

effort: "deep" 背後接的是 Docling-serve,IBM 開源的文件解析 API server(MIT 授權,依 Docling 深入介紹 的分析,它的核心價值是結構化 JSON 輸出和可替換階段 pipeline)。

Groundlane 的 adapter 做了幾件事:

  1. 標準化輸入:把 Groundlane 的 base64 inline source 轉成 Docling-serve 的 FormData file upload
  2. 標準化輸出:把 Docling 的 DoclingDocument JSON(main_text + tables)轉成 Groundlane 的 DocumentBlock 格式(TextBlock + TableBlock
  3. pipeline 選擇:支援 standard(確定性規則引擎)和 vlm(GraniteDocling 258M)兩種 pipeline

配置方式是設定 DOCLING_SERVE_URL 環境變數指向自架的 Docling-serve 實例。不配置時 effort: "deep" 仍然可用但不會啟動 VLM——只會標記 effortUsed: "deep" 讓 caller 知道它要求了高精度但 VLM backend 未就緒。

整體來說

這三個功能解決的是同一個問題:文件解析不是一刀切的

  • effort 讓 caller 不需要知道「該用哪個工具」,只需要說「我要多高的精度」
  • fieldAware 讓 chunking 保留結構化語意,而不是把所有欄位壓進同一個文字塊
  • confidence 讓 agent 在「成本」和「品質」之間自主決策,而不是由系統硬性決定

三者都是 additive(新增參數,不破壞現有行為)、deterministic(不引入隱式 LLM 呼叫)、bounded(不自動升級到更貴的路徑——除非 caller 明確要求)。這和 Groundlane 的核心設計原則一致:確定性 extraction 不以隱藏的 LLM call 假裝穩定 structured output。

參考資料