CocoIndex V1 - 專為長週期 Agent 設計的增量引擎
CocoIndex V1 - 專為長週期 Agent 設計的增量引擎
CocoIndex V1 現已正式發布。這是我們對增量資料管道(incremental data pipelines)撰寫方式的根本性重構——這一切源於過去一年我們觀察到開發者真正想用 CocoIndex 做什麼。CocoIndex V1 是專為 AI 工程師與 Agent 開發者打造的工具,適用於建構 Agent 所依賴的程式碼智慧、context、RAG、記憶與知識圖譜。點擊此處閱讀我們在超過 50 個版本更新中所投入的重大努力。
那麼,CocoIndex 究竟是什麼?
CocoIndex 是一個增量 context 引擎,能持續將程式碼庫、會議記錄、收件匣、Slack、PDF 與影片轉化為即時、持續更新的 context,讓你的 AI Agent 與 LLM 應用程式能有效進行推理,且僅需極少的增量處理。你可以在 10 分鐘內準備好生產級的 AI Agent,並獲得可靠、持續更新的資料——不再有過時的批次處理,也不再有 context 斷層。
你能用 CocoIndex 建構什麼?
殺手級範例:CocoIndex-code,它能透過任何處理邏輯,為你提供具備增量處理能力的最新程式碼庫索引。
為什麼我們如此執著於重寫它?
Jeff Dean 在 GTC 上說得很好:Agent 的執行速度比人類快約 50 倍,但它們所依賴的工具卻是為人類速度所設計的。
當人類在早上閱讀輸出時,隔夜的批次重建(Batch-rebuild-overnight)是可以接受的。但當 Agent 在撰寫程式碼、做出決策並每秒更新 50 次自己的 context 時,這就完全行不通了。過時的 context 就是一個 Bug。隔夜處理是錯誤的時間單位。
CocoIndex 是專為長週期(long-horizon)Agent 設計的增量引擎。來源變更 → 衍生資料隨之更新——無論是區塊(chunks)、嵌入(embeddings)、知識圖譜,還是你建構的任何內容。無需完整重建,無需手動比對差異,也不用擔心「我是否已經對這個區塊進行過嵌入」的瑣事。
V1 的思維模型 - 想像一下 React,但用於資料處理
CocoIndex 一直是一個狀態驅動(state-driven)的框架。你不需要撰寫「計算此增量並應用它」的程式碼;你只需描述目標狀態應如何作為來源的函數呈現,引擎就會自動處理轉換過程。如果你使用過 React、試算表或 SQL 物化視圖(materialized views),你已經熟悉這種模式:
- React:將 UI 宣告為狀態的函數 → React 重新渲染變更的部分。
- 試算表:宣告公式 → 當輸入變更時,儲存格自動重新計算。
- CocoIndex:將目標狀態宣告為來源的函數 → 引擎同步變更的部分。
V1 的新之處在於你宣告的方式。整個管道現在就是純粹的非同步 Python。函數呼叫其他函數,迴圈就是迴圈,if 語句就是 if 語句。在幕後,CocoIndex 會追蹤你宣告的每一個目標狀態以及每一個經過記憶化(memoized)的中間值,因此下一次執行時只會處理變更的部分。
V1 特意設計為非侵入式。你可以從一個簡單的 @coco.fn 裝飾器開始,隨著管道擴展,再逐步啟用引擎的更多功能。沒有所謂「必須先設定框架」的步驟,也不需要在獲得價值前撰寫冗長的儀式性程式碼——當你真正需要時,再開啟增量開關即可。
什麼是增量引擎,為什麼為生產環境建構它很困難?
簡單來說,增量引擎只做一件事:
保持衍生資料與原始資料同步——同時不重複執行已經完成的工作。
這聽起來很直觀,但當你考慮到各種限制時,情況就不同了。

你的來源資料並非靜態的。它在不斷變化:
檔案被編輯、資料列被更新、事件亂序到達、API 回傳新的快照。
同時,你的處理邏輯也不是靜態的。
你會重構函數、調整解析方式、修復 Bug、變更 Schema。
一個真正正確的增量系統必須處理這兩者——資料變更與程式碼變更——而無需退回到完整重新計算。
這就是問題變得複雜的地方。
Notion 最近發表了他們的工程文章,探討了在維護內部資料管道時,針對簡單資料轉換(例如不含分群等)進行增量處理的冰山一角,以支援即時 Agent。
V1 能達到的應用場景
V1 使其成為適合 Agent 時代工作負載的正確形態:同樣具備增量、狀態驅動的保證,但現在足夠靈活,能涵蓋 Agent 實際產生的管道形態——實體解析、分群、多階段縮減、租戶拓撲、超出嵌入範圍的條件式目標等等。範例庫中的每一個模式都是長週期 Agent 可能會自行執行的任務,並讓其輸出成為下一個 Agent 的新鮮來源資料——無需人類隨時監控作業。


開始使用
宣告你的目標中應該包含什麼——CocoIndex 會讓它永遠保持同步,且只重新計算 Δ(增量)。
pip install -U --pre cocoindex # v1 處於預覽階段 — 需要加上 --pre 旗標
import cocoindex as coco
from cocoindex.connectors import localfs, postgres
from cocoindex.ops.text import RecursiveSplitter
@coco.fn(memo=True) # ← 透過 hash(input) + hash(code) 快取
async def index_file(file, table):
for chunk in RecursiveSplitter().split(await file.read_text()):
table.declare_row(text=chunk.text, embedding=embed(chunk.text))
@coco.fn
async def main(src):
table = await postgres.mount_table_target(PG, table_name="docs")
table.declare_vector_index(column="embedding")
await coco.mount_each(index_file, localfs.walk_dir(src).items(), table)
coco.App(coco.AppConfig(name="docs"), main, src="./docs").update_blocking()
為什麼選擇 V1:V0 的瓶頸
V0 是有效的——開發者確實將真實的管道部署到了生產環境——但由於 DSL 優先的設計,四個限制一直存在:
- 兩個世界,一個程式:FlowBuilder / DataScope / DataSlice 用於拓撲結構,普通 Python 用於葉節點。DSL 世界無法輕易轉換形態,無法將值傳遞給普通 Python 再傳回來。分群、實體解析、跨項目縮減、條件式來源——每一個都卡在這些接縫處。
- 獨立的型別系統:像資料庫一樣,引擎擁有獨立於 Python 的型別系統,因此你想要使用的每個 Python 型別都需要編寫雙向轉換邏輯。dataclass 和 NDArray 有支援;但 PIL Image 或 pyarrow array 則沒有——如果沒有轉換邏輯,你就無法將其傳遞給函數,且跨越邊界傳遞的資料在進出時都需要進行序列化。
- Postgres 作為硬性依賴:引擎使用 Postgres 進行自身的帳務處理,因此
pip install cocoindex && python script.py並不是一個可行的路徑——即使是微小的本地管道,你也必須先架設一個資料庫。 - 靜態拓撲:
add_source()和.export()在執行前就已宣告,因此多租戶、配置驅動的拓撲以及執行時的目標選擇,都需要在 CocoIndex 周圍建立額外的腳手架,而不是在 CocoIndex 內部直接表達。
修復其中任何一個問題都意味著必須改變設計。
CocoIndex V1:四個改變你建構能力的轉變
1. 流程即執行 — 無需 DSL
V0 需要 FlowBuilder 提供的凍結圖(frozen graph),引擎稍後再進行解釋。在 V1 中,app_main 作為根處理元件執行:每一個 await coco.mount(...) 都會增加一個子元件,每一個 declare_* 都會記錄目標狀態。元件樹是透過執行你的程式碼來建構的。
這解鎖了以下能力:
- 縮減模式:使用
coco.map進行扇出,然後進行聚合(參見multi_codebase_summarization)。 - 多階段管道:例如,每會話提取 → 跨會話實體解析 → 知識庫組裝,全部作為普通的函數呼叫。
- 條件式拓撲:
if config.enable_kafka: await mount_kafka_target(...)。
除錯就是一般的 Python 除錯:中斷點、逐步執行、列印。中間沒有不透明的圖形解釋器。
2. 原生 Python 型別,沒有平行的型別系統
V1 直接使用 Python 的型別系統。Dataclasses、Pydantic、NDArray、dict/list/tuple 依然有效——此外還支援 V0 無法表達的內容:PIL.Image、pyarrow.Table、torch.Tensor 以及任意函式庫類別。
3. 嵌入式 LMDB — 無需 Postgres 依賴
引擎的帳務處理從 Postgres 移至單一本地檔案中的 LMDB:無需伺服器、無需遷移、無需連接埠。
4. 動態來源與目標
來源/目標是在執行期間透過普通函數呼叫建立的;元件路徑樹會追蹤跨次執行的身份。這實現了:
- 從配置、環境變數或功能旗標進行條件式掛載。
- 每個項目對應目標:每個租戶對應 Postgres Schema、每個類別對應 Kafka 主題、每個資料集對應 S3 前綴。
- 來自即時註冊表的拓撲——在啟動時查詢活躍租戶,並為每個租戶掛載一個元件;當租戶離開時,CocoIndex 會自動清理其狀態。
支持我們
如果你覺得這很有用,在 GitHub 上為 CocoIndex 加星(Star)是幫助我們最直接的方式。這也是其他開發者發現這個專案的方式 :)
