模型 / 資料集
pguso/rag-from-scratch avatar
pguso/rag-from-scratch

rag-from-scratch:用 node-llama-cpp 把 RAG 拆成十個可執行的範例

Demystify RAG by building it from scratch. Local LLMs, no black boxes - real understanding of embeddings, vector search, retrieval, and context-augmented generation.

1,629 個 Star195 個 ForkJavaScriptMIT
GitHub

秒懂

它是什麼?
這個專案把檢索增強生成拆成一條從資料載入到生成的學習路徑,每個階段都有獨立可執行的 example.js。它適合想理解向量檢索內部機制的人,不適合想直接部署問答服務的人。
適合誰用?
如果你需要的是理解 RAG 每個環節的實際行為,例如分塊重疊怎麼影響召回、RRF 如何融合多份排序結果,這個專案值得照著 examples/ 的編號順序跑一遍;如果你要的是一個能上線的問答服務,它缺少持久化、併發與服務化介面,應該改用 LangChain.js 或 LlamaIndex.TS 這類框架。動手前先確認 node-llama-cpp 在你的 Node 版本與作業系統上能載入 GGUF 模型,並確認 examples/05_building_vector_store/ 是否真的提供磁碟持久化,這兩點決定你能不能把它當成後續專案的起點。
可以商用嗎?
可以。MIT 是寬鬆授權:你可以使用、修改並販售以它為基礎的軟體,只需保留著作權與授權聲明。
還在維護嗎?
活躍度在下降。儲存庫最近一次提交在 6 個月前。
用什麼語言寫的?
主要是 JavaScript(依據 GitHub 的語言統計)。

以上回答依據專案的 GitHub 資料(最近同步於 2026年9月15日)與我們的分析,不構成法律意見。

開源專案深度解析

它處理的不是 RAG 本身,而是 RAG 的黑箱感

多數人第一次接觸檢索增強生成,是透過框架的一行鏈式呼叫:載入文件、切分、嵌入、存入向量庫、查詢、生成,全部藏在抽象層後面。東西能跑,但當檢索結果不對時,你很難判斷問題出在分塊邊界、嵌入模型、相似度計算,還是提示組裝。pguso/rag-from-scratch 針對的就是這個斷層。它的 README 開頭寫得很直白:No black boxes. No cloud APIs.,目標是把每個環節攤開成可以逐行讀的 JavaScript。

目標讀者是已經會寫 Node.js、但沒親手實作過向量檢索的開發者。專案首頁把學習路徑列成編號清單,從 examples/00_how_rag_works/ 開始,README 說明那是一個 under 70 lines of code 的最小端到端流程。之後每一站只處理一個概念:資料載入、文字切分、嵌入生成、向量儲存、基礎檢索,再往後是查詢前處理、混合檢索、多查詢檢索。這種一站一例的安排,讓你可以只讀你卡住的那一段,不必先吞下整條管線。

它不提供套件、不提供 CLI,也不是拿來當依賴安裝的。從 repository 結構看,主體是 examples/ 底下的目錄,每個目錄裡有 example.js、CODE.md 與 CONCEPT.md 三份檔案。這個組合透露了它的定位:example.js 是可執行的實作,CODE.md 逐段解釋程式碼,CONCEPT.md 講背後的觀念。換句話說,它是一份可以執行的教材,而不是一個產品。

十個階段的資料流:從原始文字到有依據的回答

README 的 Concept Overview 把管線列成十步,這個順序本身就是專案的架構說明。前段是離線索引:定義知識需求、載入文件、切分成塊、生成嵌入、寫入向量儲存。後段是查詢時的路徑:檢索、重排序、查詢前處理與嵌入正規化、把上下文併入提示、生成。

值得注意的是第 7 與第 8 步的位置。多數教學會把查詢改寫放在檢索之前當作前置步驟,這裡把 Post-Retrieval Re-Ranking 排在 Retrieval 之後、Query Preprocessing 之前,等於承認檢索與排序是兩件事:先用向量相似度撈出一批候選,再重新排序決定哪些真的進提示。這個區分在實作上很實際,因為兩者的成本結構不同,檢索要掃過整個索引,重排序只處理前 k 筆。

嵌入與檢索之間的關係,專案用 examples/05_building_vector_store/01_in_memory_store/ 示範。README 說這一站要學的是 how to store embeddings 與 how nearest-neighbor search works,關鍵概念列了 indexing、vector search、metadata storage。名稱裡的 01_in_memory_store 暗示後續可能有其他儲存後端,但從提供的目錄清單看不出有沒有第二種實作,這點需要進 repository 確認。

檢索策略被拆成四站,這是整個專案最厚的一段。01_basic_retrieval 講 top-k 與相似度分數;02_query_preprocessing 講停用詞移除與查詢清理,README 把它連到 vector stability;03_hybrid_search 明確提到 BM25 + embeddings 的加權組合;04_multi_query_retrieval 則處理查詢分解、平行檢索與 reciprocal rank fusion。RRF 出現在教學專案裡有點意外,因為它是把多份排序清單合併的技術,通常在意準確率的正式系統才會用到。

本地模型這條線:node-llama-cpp 換來的是可解釋性

專案選擇在本機跑模型,topic 標籤裡有 node-llama-cpp。這個決定直接影響你能學到什麼。用雲端 API 做嵌入與生成,你拿到的是黑箱回傳的向量與文字,中間沒有任何可觀察的狀態;用本地模型,嵌入維度、推論延遲、模型載入的記憶體佔用都攤在你面前。README 把 No cloud APIs 寫進開頭,是把這件事當成賣點而非限制。

代價是環境。node-llama-cpp 是原生綁定,需要對應平台的預編譯檔或本地編譯工具鏈,模型本身要另外取得 GGUF 格式的權重檔。這些步驟在提供的 README 裡沒有展開,只出現在各站範例的執行說明中。也就是說,這個專案的入門門檻不在 JavaScript,而在能不能把本地推論環境弄起來。對已經有 llama.cpp 使用經驗的人,這是幾分鐘的事;對只寫過網頁前端的人,這可能是第一個卡點。

另一個結構性影響是硬體。嵌入模型與生成模型都要佔記憶體,兩者同時存在時,可用記憶體決定你能跑多大的模型與多大的批次。教學範例的資料量小,通常感覺不到壓力,但當你把同一套程式碼指向真實文件集,瓶頸會從程式邏輯轉移到資源配置。這個落差是教學專案與生產系統之間最容易被低估的一段。

怎麼把它跑起來:範例即入口

這個專案沒有安裝指令可以照抄。README 給的是學習路徑,每一站指向 examples/ 底下的目錄,例如 examples/02_data_loading/example.js 與 examples/03_text_splitting_and_chunking/example.js。要跑哪一段,就進到那個目錄執行對應的檔案。

建議的順序是照編號走。examples/00_how_rag_works/ 是起點,README 說它用不到 70 行展示完整的檢索到生成流程,適合先建立整體感。接著 examples/02_data_loading/ 處理檔案讀取與文件結構正規化,examples/03_text_splitting_and_chunking/ 處理分塊與重疊。注意編號從 00 跳到 02,01 的位置在 README 裡沒有對應條目,可能是尚未發布或已移除,實際情形要進 repository 看目錄才知道。

嵌入與檢索這兩段的路徑比較深。生成嵌入在 examples/04_intro_to_embeddings/02_generate_embeddings/,向量儲存在 examples/05_building_vector_store/01_in_memory_store/。子目錄的命名方式顯示作者打算在同一個主題下放多種做法,02_generate_embeddings 暗示有 01 存在。檢索策略集中在 examples/06_retrieval_strategies/ 底下,四個子目錄分別是 01_basic_retrieval、02_query_preprocessing、03_hybrid_search、04_multi_query_retrieval。

README 另外提到 examples/06_retrieval_strategies/01_basic_retrieval/showcase.js,說它把前面學到的東西整合起來展示。如果你的目標只是快速看一遍全貌,這個檔案比從 00 開始逐站讀更省時間。每個目錄裡的 CODE.md 是逐函式解說,CONCEPT.md 是觀念背景,兩者都不需要執行環境就能讀,適合在裝環境之前先確認內容是否符合你的需求。

它不會幫你解決的事:持久化、規模與評估

最明顯的邊界是向量儲存的範圍。範例目錄叫 01_in_memory_store,顧名思義是把嵌入放在記憶體裡。這對教學是正確選擇,因為你能直接看到陣列與相似度計算;但記憶體索引意味著每次啟動都要重新嵌入整份文件集,而且文件量受可用記憶體限制。README 沒有提到任何磁碟持久化或外部向量資料庫的整合。

第二個缺口是評估。管線裡有重排序、有混合檢索、有 RRF 融合,這些都是為了提升檢索品質,但提供的材料裡看不到任何衡量檢索品質的方法,沒有召回率、沒有命中率、沒有標註資料集。少了這一層,你只能憑感覺判斷調整分塊大小或權重之後有沒有變好。這不是專案的疏漏,而是教學專案常見的取捨:先讓你看到機制,評估留給你自己補。

第三個是服務化。整個 repository 是範例集合,沒有 HTTP 伺服器、沒有請求佇列、沒有併發控制。本地模型推論通常是同步且佔用資源的,多個請求同時進來時的行為不在教學範圍內。如果你的情境是單人問答或離線批次處理,這不構成問題;如果是多人同時使用的服務,你需要自己加上排隊與逾時機制,而這些程式碼得從零寫起。

還有一個容易被忽略的點:範例資料集通常是為了示範而挑選的乾淨文字。真實文件常有表格、多欄排版、頁首頁尾、編碼混亂等問題,這些在資料載入階段的處理方式,README 只寫了 normalizing and preparing documents,具體怎麼做要看 examples/02_data_loading/ 的實作。

與框架路線的差異:LangChain.js 給你鏈,這裡給你零件

在 JavaScript 生態裡做 RAG,多數人會先想到 LangChain.js 或 LlamaIndex.TS。這兩者的做法是提供現成的抽象:文件載入器、文字分割器、向量儲存介面、檢索器、提示模板,你用設定把它們串起來,幾十行就能跑出一個可用的問答流程。它們的價值在於省掉重複實作,並且能直接接到 Pinecone、pgvector 這類外部向量庫。

rag-from-scratch 走的是相反方向。它不提供抽象層,而是讓你自己寫相似度計算、自己決定分塊邊界、自己實作 RRF 的融合邏輯。這樣做的直接後果是:你不會得到一個能馬上換資料集上線的系統,但你會知道每個數字從哪裡來。當檢索結果不如預期時,你能沿著自己寫過的程式碼往回追。

兩條路線的差異也反映在依賴上。框架路線的依賴樹很深,版本升級時可能牽動多層;這個專案的核心依賴集中在 node-llama-cpp 與 Node.js 本身,從 topic 標籤看就是 nodejs、llm、rag 這幾個方向。維護面積小,但社群支援也少,遇到問題時能查的資料主要來自 llama.cpp 生態而非這個 repository 本身。

實務上這兩者不必然互斥。先照著範例把機制跑過一遍,再決定要用哪個框架,是常見的順序;反過來,先用框架做出成果再回頭補機制,也說得通。差別在於你希望除錯時手上握有多少線索。

維護狀態與授權:教學專案的時間尺度

授權是 MIT,這是寬鬆授權,允許修改、再散布與商業使用,只要保留著作權聲明與授權條文。把它當成自己專案的起點在授權上沒有障礙。要注意的是範例程式碼與你從中衍生的產品是兩件事,後者的責任在你身上。這裡不構成法律意見,實際條文以 repository 內的 LICENSE 檔案為準。

維護成本要放在教學專案的時間尺度上看。最後一次推送是 2026 年 3 月,沒有檢索到任何 release。沒有 release 意味著沒有版本號可以鎖定,你引用的是 main 分支上的某個 commit,日後作者調整範例結構時,路徑可能變動。README 裡已經出現編號跳號(00 之後接 02)與子目錄編號(02_generate_embeddings、01_in_memory_store)的情況,說明內容還在增補中。

真正會隨時間失效的不是專案本身,而是它依賴的底層。node-llama-cpp 與 llama.cpp 都在快速演進,綁定 API、模型格式支援、預編譯目標都可能變動。教學範例的程式碼一旦寫定就不太會改,但當你把它接到新版綁定時,可能需要自己調整。這也是為什麼這類專案適合當學習材料而非長期依賴:學到的觀念不會過期,抄下來的程式碼會。

如果你打算把它當成內部教材,建議連同 examples/ 底下的 CODE.md 一起保留,因為那些說明檔才是專案的主要產出,example.js 是它們的佐證。只留程式碼而丟掉解說,會失去這個 repository 大部分的價值。

編輯結論

如果你需要的是理解 RAG 每個環節的實際行為,例如分塊重疊怎麼影響召回、RRF 如何融合多份排序結果,這個專案值得照著 examples/ 的編號順序跑一遍;如果你要的是一個能上線的問答服務,它缺少持久化、併發與服務化介面,應該改用 LangChain.js 或 LlamaIndex.TS 這類框架。動手前先確認 node-llama-cpp 在你的 Node 版本與作業系統上能載入 GGUF 模型,並確認 examples/05_building_vector_store/ 是否真的提供磁碟持久化,這兩點決定你能不能把它當成後續專案的起點。

官方來源

  1. Issues
  2. License: MIT
  3. pguso/rag-from-scratch on GitHub
  4. README
社群筆記

社群筆記