spacy-llm:把 LLM 提示詞塞進 spaCy 管線的取捨
🦙 Integrating LLMs into structured NLP pipelines
秒懂
- 它是什麼?
- spacy-llm 讓你在 spaCy 的 config 與 registry 體系裡呼叫 OpenAI、Anthropic、Cohere 或 Hugging Face 上的開源模型,把非結構化的模型回應轉成 Doc 上的標註。它的價值在原型階段,代價是介面仍標示為 experimental,且 prompt 與解析邏輯會滲進你的 config。
- 適合誰用?
- 如果你正在做需要快速驗證的 NLP 原型,或者想在既有 spaCy 管線裡先插入一兩個 LLM 元件、日後再逐步替換成監督式模型,spacy-llm 的 registry 與 config 設計能省下不少接線工作。反過來說,若你的任務已有明確輸出格式與數百到數千筆標註資料,README 自己就指出監督式學習在效率、可靠性、可控性與準確度上通常更好,這時導入 spacy-llm 只是多一層不穩定的依賴。
- 可以商用嗎?
- 可以。MIT 是寬鬆授權:你可以使用、修改並販售以它為基礎的軟體,只需保留著作權與授權聲明。
- 還在維護嗎?
- 有在維護。儲存庫最近一次提交在 173 天前。
- 用什麼語言寫的?
- 主要是 Python(依據 GitHub 的語言統計)。
以上回答依據專案的 GitHub 資料(最近同步於 2026年9月15日)與我們的分析,不構成法律意見。
開源專案深度解析
它解決的是接線問題,不是模型能力問題
LLM 本身能做的事,README 講得很直白:給幾個例子甚至不給例子,就能做文本分類、命名實體辨識、指代消解與資訊抽取。真正的麻煩在周邊。你要管理 API key、把 prompt 送出去、把回傳的自由文字解析成結構化標註、把標註掛回 spaCy 的 Doc 物件上,還要處理切分與合併。spacy-llm 針對的是這一段。它提供的是一個可序列化的 llm 元件,加上一組模組化的 task(負責 prompting 與 parsing)與 model(負責呼叫哪個後端),讓 prompt 這件事變成 spaCy 管線裡的一個環節,而不是散落在腳本中的字串拼接。
目標讀者是有 spaCy 使用經驗、想在管線中試用 LLM 的人。README 強調 no training data required,這對還沒有標註資料、只想先看效果如何的團隊是實際的誘因。反過來說,如果你的問題已經有清楚的輸出定義,這條路未必划算,理由在後面幾節會談。
task 與 model 分離:資料怎麼流過 llm 元件
spacy-llm 的架構沿著 spaCy 的 registry 展開。task 定義兩件事:怎麼把 Doc 變成 prompt,以及怎麼把模型回傳的字串解析回標註。model 定義呼叫哪個後端。兩者分開註冊,因此你可以把同一個 NER task 接到 OpenAI,也可以接到本機的 Hugging Face 模型,只要換掉 config 裡的 model 區塊。
README 列出的現成 task 涵蓋 NER、textcat、lemmatization、relationship extraction、sentiment、spancat、summarization、entity linking、translation,以及一個 raw prompt execution 用於最大彈性。model 端則支援 OpenAI、Cohere、Anthropic、Google PaLM、Microsoft Azure AI 的 API,以及 Hugging Face 上的 Falcon、Dolly、Llama 2、OpenLLaMA、StableLM、Mistral。另外還有 LangChain 整合,README 的說法是所有 langchain 模型與功能都能在 spacy-llm 中使用。
對超長輸入,文件描述了 map-reduce 式的 task sharding:把超過模型 context window 的 prompt 切開,分別送出,再把結果融合回單一標註。這是實作上最容易出錯的一段,因為合併邏輯取決於 task 的語意,不是通用的。
值得注意的是 registry 這條路是雙向的。你可以只寫自己的 prompting、parsing 與 model 整合函式並註冊進去,README 指向文件中的範例。這意味著當內建 task 的解析不夠穩時,你有地方可以改,而不必 fork 整個套件。
安裝與最小可跑範例
安裝指令在 README 中很單純,且要求在已經裝好 spaCy 的同一個虛擬環境中執行:
python -m pip install spacy-llm
README 同時說明,未來 spaCy 版本會自動安裝 spacy-llm,目前仍需手動。同一段還附了一個警告,指出這個套件仍是 experimental,介面有可能在 minor 版本更新中出現破壞性變更。這不是客套話,v0.7.4 的 release note 就提到 Pydantic v2 migration,這類底層相依的遷移通常會影響自訂 task 與 model 的實作。
快速實驗用 Python 即可,從 0.5.0 起支援:
import spacy
nlp = spacy.blank("en") llm = nlp.add_pipe("llm_textcat") llm.add_label("INSULT") llm.add_label("COMPLIMENT") doc = nlp("You look gorgeous!") print(doc.cats)
README 給出的預期輸出是 {"COMPLIMENT": 1.0, "INSULT": 0.0}。使用 llm_textcat factory 時,會採用內建 textcat task 的最新版本,以及 OpenAI 的預設 GPT-3-5 模型。
要控制參數就得走 spaCy 的 config 系統。API key 依文件建議設為環境變數,細節在 large-language-models 的 API keys 一節。這裡有一個容易被忽略的點:因為 prompt 與解析設定都寫在 config 裡,你的 config 檔案實際上變成了程式邏輯的一部分,需要跟程式碼一起版控與審查。
v0.7.3 的 Jinja 沙箱化說明了 config 是攻擊面
v0.7.3 的 release note 標題是 Sandbox Jinja to prevent code execution from untrusted configs。這句話本身就把風險講清楚了:在該版本之前,config 中的 Jinja 模板可以導致程式碼執行。如果你的 config 來自外部、來自使用者上傳、或來自你無法完全信任的來源,這是一個必須知道的界線。
這個修補的存在也反向說明了 spacy-llm 的設計把相當大的表達能力放進了 config。prompt 模板是 Jinja,task 與 model 由 registry 名稱指定,因此一份 config 就足以決定要送什麼內容給哪個模型、以及怎麼解讀回應。方便,但也意味著 config 的審查等級應該比照程式碼。
版本選擇上,若你的環境無法立即升級到 v0.7.3 以上,就不要讓不受信任的 config 進入流程。這不是效能問題,是執行邊界的問題。
什麼時候它是錯的工具
README 自己寫得很坦白:對於輸出定義明確的任務,能在單張 GPU 上跑得動的 transformer 模型極可能比 LLM prompting 更合適。用幾百到幾千筆標註資料訓練,模型會學會就做那件事,效率、可靠性與控制都更好,準確度通常也更高。這段話放在一個 LLM 整合套件的 README 裡,份量不輕。
實務上的失敗模式有幾類。第一是解析脆弱:LLM 回傳的是自由文字,task 的 parser 必須把它轉成標註,一旦模型輸出格式漂移,錯誤會以難以預期的方式出現在下游。第二是成本與延遲:每個 doc 都要打一次 API,批次處理大量文本時的帳單與等待時間與本機模型不是同一個量級。第三是切分語意:map-reduce 對摘要這類可加總的任務相對自然,對 NER 或關係抽取這種需要跨段落一致性的任務,切開再融合可能產生邊界上的重複或遺漏。
如果你的任務是低延遲、高吞吐、且輸出格式固定,spacy-llm 不是合適的起點。若你只是想要一個能處理多份文件、生成細緻摘要的元件,README 的立場是 bigger is better,但即便如此,它仍建議管線的其他環節用便宜的分類模型或規則系統來做前後處理。
與 LangChain 的差別在於 Doc 與管線
spacy-llm 有 LangChain 整合,README 說所有 langchain 模型與功能都能在 spacy-llm 中使用。既然如此,為什麼不直接用 LangChain?差別在於兩者組織程式的方式不同。LangChain 以 chain 與 runnable 為中心,輸出通常是字串或字典,你需要自己決定怎麼把它變成標註。spacy-llm 的輸出落點是 spaCy 的 Doc,標註直接掛在 token 與 span 上,可以接上 spaCy 既有的管線、序列化與評估流程。
這個差異在混合式管線裡才顯得具體。README 描述的情境是:用便宜的分類模型找出要摘要的文本,或在摘要輸出後加一層規則系統做檢查。這些前後任務在 spaCy 裡就是管線中的其他元件,共用同一個 nlp 物件與同一份 config。用 LangChain 要達成同樣的組合,你得自己在兩套抽象之間搬資料。
代價是耦合。選擇 spacy-llm 等於接受 spaCy 的 config 與 registry 作為組織單位,也接受它 experimental 的介面穩定性。如果你的專案本來就不是 spaCy 生態,這個代價未必值得。
維護成本與授權
授權是 MIT,寬鬆,對商業使用沒有額外條款。這部分不需要法律意見,條文本身很短。
維護成本主要來自兩個方向。一是介面變動:README 明講 minor 版本可能破壞介面,而 v0.7.4 的 Pydantic v2 migration 就是這類工作的實例,自訂 task 或 model 的人需要跟著調整。二是外部相依:你接的每一個 API 後端都有自己的版本節奏與棄用政策,spacy-llm 的 model 層是這些變動的緩衝,但緩衝不是免費的。
升級前值得確認的是 Python 版本支援範圍。v0.7.4 加入 Python 3.14 支援,v0.7.2 加入 Python 3.12 支援並修了一個與 Torch 相關的 bug,這表示版本矩陣會隨時間移動。若你的環境鎖在較舊的 Python,先確認對應的 spacy-llm 版本再決定。
編輯結論
如果你正在做需要快速驗證的 NLP 原型,或者想在既有 spaCy 管線裡先插入一兩個 LLM 元件、日後再逐步替換成監督式模型,spacy-llm 的 registry 與 config 設計能省下不少接線工作。反過來說,若你的任務已有明確輸出格式與數百到數千筆標註資料,README 自己就指出監督式學習在效率、可靠性、可控性與準確度上通常更好,這時導入 spacy-llm 只是多一層不穩定的依賴。採用前先確認三件事:你的 spaCy 版本與 spacy-llm 是否相容、你的 config 是否會載入不受信任的來源(v0.7.3 之前的 Jinja 未沙箱化)、以及你的 prompt 是否可能超過模型 context window 而需要 task sharding。
社群筆記