DSPy:AI Prompt Engineering 的重要補足與程式化開發框架

從傳統提示工程到模組化 AI 軟體,探索 DSPy 如何革新 LLM 應用開發方式


DSPy(Declarative Self-improving Python)是一個由 Stanford NLP 研究人員開發的革命性框架,以「Programming, not Prompting」為核心理念,旨在解決傳統 Prompt Engineering 的根本性問題。本文將深入探討 DSPy 的核心組件、運作機制,以及它如何補足傳統 Prompt Engineering 的不足之處。

DSPy 核心概念:從「提示工程」到「程式化開發」

傳統 Prompt Engineering 的困境

傳統 AI 開發流程繁瑣且耗時,開發者需要反覆開出功能需求、建立 Prompt、整合步驟、微調系統並嘗試不同模型。每次更換管道、語言模型或資料時,就必須重新調整 Prompt,導致開發效率低下。更根本的問題在於,傳統 Prompt 將介面定義、實作細節、推理策略和手動優化等關注點混雜在一起,使得系統難以維護與擴展。

DSPy 的創新解決方案

DSPy 框架以兩個核心創新解決傳統問題。首先是模組化設計,將程序流程與提示語分離,讓開發者能靈活重組模組並調整提示,無需反覆修改提示或生成合成數據。其次是智能優化器(Optimizer),這些由 LLM 驅動的算法能根據預設指標自動調整提示,讓系統自主探索最佳組合。

💡 亮點:DSPy 不僅提高了模型性能,還大幅減少所需提示數量,同時維持或提升結果質量。

DSPy 核心組件深度解析

Signatures:任務藍圖

Signature 作為你要求語言模型要做的藍圖。你不用編寫準確的 Prompt,而是根據任務的輸入、輸出來描述任務就可以。

基本用法示例

舉例來說,在 DSPy 結構下要讓語言模型協助進行情緒分析的話,只要撰寫 sentence → sentiment 就可以:

# 聲明語言模型任務 classify = dspy.Predict('sentence -> sentiment') # 實操 sentence = "你人真好" classify(sentence=sentence).sentiment # 輸出'Positive'

這種用法讓 Signature 可以表達常見的 NLP 任務:

  • 簡易問答:"question → answer"
  • 文章摘要:"document → summary"
  • 文字翻譯:"English → Chinese"
  • 實體識別:"sentence → entity"
  • 檢索增強問答:"context, question → answer"

進階用法:Class-based Signature

對於更進階的執行任務,Signature 需要被描述得更詳細:

class QuestionAnswer(dspy.Signature): """Answer questions based on the input question.""" question = dspy.InputField(desc='Question related to customer support') answer = dspy.OutputField(desc='Response in nice.')

每一條 Signature 都包含三個核心區塊:任務描述(在類別文件字串中定義)、輸入(dspy.InputField())和輸出(dspy.OutputField()),確保模型清楚理解任務要求。

Modules:LLM 行為構建塊

在實際應用中,單純要求語言模型執行任務往往不夠,通常需要加入角色扮演、思考方式、推論步驟等進階技巧。DSPy 透過 Module 將這些操作模組化,官方提供多種預設模組,包括鼓勵逐步思考的 ChainOfThought()、使用程式碼解決問題的 ProgramOfThought()、與外部工具互動的 ReAct(),以及比較多個推理鏈的 MultiChainComparison()

官方預設模組範例

# 假設問題 question = "What's something great about the ColBERT retrieval model?" # 執行函數 classify = dspy.ChainOfThought('question -> answer', n=5) response = classify(question=question) # 產生輸出 response.completions.answer

每一個 module 都需要填入 signature。這種方法確保提示是系統產生的,保持一致性並減少手動編寫提示的需要。

自定義模組

可以透過 Module 方式將 LLM 開發當中的邏輯像是樂高積木般堆疊起來使用:

class BasicQA(dspy.Module): def __init__(self): super().__init__() self.prog = dspy.Predict("question -> answer") def forward(self, question): """forward 方法呼叫 __call__,類似於 pytorch 中的工作方式。""" return self.prog(question=question) basic_qa = BasicQA()

Optimizers:自動化提示優化

DSPy Optimizer 不僅僅是一個工具,它代表了一種全新的思維方式。在 DSPy 的世界中,Optimizer 是一種專門用於優化提示語的算法,其核心目標是根據用戶定義的指標來提升模型性能。

Optimizer 的運作機制

在 Optimizer 中會需要三個輸入:

  1. DSPy Program:從簡單的 dspy.Predict 到複雜的多模組系統
  2. Metric:評估 DSPy Program 輸出質量的函數,分數越高表示性能越好
  3. Data:包含多個輸入-輸出對的訓練數據集

Optimizer 程式碼示例

from dspy.teleprompt import BootstrapFewShotWithRandomSearch config = dict( max_bootstrapped_demos=2, max_labeled_demos=4, num_candidate_programs=2, num_threads=6 ) teleprompter = BootstrapFewShotWithRandomSearch(metric=eval_metric, **config) optimized_qa = teleprompter.compile(basic_qa, trainset=trainset, valset=valset) # 保存優化後的程序 optimized_program.save("path_to_save.json")

Optimizer 選擇指南

選擇合適的 Optimizer 需考量數據量、計算資源和任務需求。小數據集(約 10 個樣本)推薦 BootstrapFewShot,中等數據集(約 50 個樣本)適合 BootstrapFewShotWithRandomSearch,較大數據集(300+ 樣本)建議使用 MIPROv2,而大型語言模型且重視效能時可考慮 BootstrapFineTune

DSPy 組件懶人包

ComponentDescription
Signature模組的預期行為,包括輸入和輸出。
ModuleDSPy 程式(使用語言模型的程式)的概念和功能建構塊。可以連結在一起形成多模組程式。需要作為優化器的輸入。
Optimizers用於調整語言模型任務中使用的提示或權重的元件。由模組、指標和訓練輸入組成。

DSPy 如何補足傳統 Prompt Engineering

解決「可移植性」問題

傳統 Prompt Engineering 的問題:當你為某個特定的 LLM(例如 GPT-4)精心設計了一個完美的 Prompt,如果換成另一個模型(例如 Claude 或 Gemini),這個 Prompt 可能就完全失效了。你必須重新設計、重新測試、重新優化。

DSPy 的解決方案:DSPy 將「任務定義」(Signature)與「如何告訴模型執行任務」(Adapter)分離。這意味著:

  • 你可以用同樣的 Signature 和 Module 結構,輕鬆切換不同的語言模型
  • 當你更換模型時,DSPy 會自動調整適配器,無需重寫整個系統
  • 你的核心邏輯(Module 的組合方式)保持不變,只有底層的提示生成會改變

解決「可維護性」問題

傳統 Prompt Engineering 的問題

  • Prompt 是「字串」,難以進行版本控制
  • 當系統變複雜時,Prompt 散落在各處,難以追蹤
  • 修改一個 Prompt 可能影響其他部分,但這種影響關係不明顯

DSPy 的解決方案

  • 程式碼化:DSPy 將 Prompt 邏輯轉換為結構化的 Python 程式碼
  • 模組化:每個 Module 都是獨立的組件,可以單獨測試和優化
  • 可組合性:可以像樂高積木一樣組合不同的 Module,建立複雜的系統

解決「優化效率」問題

傳統 Prompt Engineering 的問題:優化 Prompt 是一個反覆試錯的過程:

  1. 寫一個 Prompt
  2. 測試幾個例子
  3. 發現問題
  4. 修改 Prompt
  5. 重複步驟 2-4

這個過程非常耗時,而且往往依賴於開發者的經驗和直覺。

DSPy 的解決方案:DSPy 透過 Optimizer 自動探索提示空間,基於實際評估指標和數據集進行優化,整個過程可重複且可追蹤。實際案例顯示,基礎問答方法可獲得約 50% 的相對性能提升,思維鏈方法也有約 10% 的提升。

解決「系統架構」問題

傳統 Prompt Engineering 的問題:在傳統方法中,系統架構(如何組織不同的步驟)與提示內容(如何告訴模型執行任務)混雜在一起。這導致:

  • 難以重構系統架構
  • 難以重用組件
  • 難以測試和除錯

DSPy 的解決方案:DSPy 實現關注點分離,Signature 定義任務內容,Module 定義組織方式,Optimizer 定義優化策略。這種設計讓 Module 可以在不同系統中重用,且每個 Module 都能獨立測試。

解決「規模化」問題

傳統 Prompt Engineering 的問題:當系統規模擴大時,管理數百個 Prompt 變得困難,每個 Prompt 都需要手動編寫、測試、優化和維護。

DSPy 的解決方案:DSPy 可自動生成提示,Optimizer 能同時優化整個系統的所有組件,程式碼化的方式也讓版本控制變得容易。

實際應用案例:翻譯錯誤檢測系統

讓我們透過一個實際案例來理解 DSPy 的威力。這個案例來自 BIG-Bench Hard 資料集中的「顯著翻譯錯誤檢測」任務。

基礎問答模組

首先,我們定義一個簡單的問答模組:

class BasicQA(dspy.Module): def __init__(self): super().__init__() self.prog = dspy.Predict("question -> answer") def forward(self, question): return self.prog(question=question) basic_qa = BasicQA()

評估方法

我們設計一個評估指標來檢查 LLM 輸出是否包含正確的多項選擇答案:

import re def eval_metric(true, prediction, trace=None): pred = prediction.answer matches = re.findall(r"\([A-Z]\)", pred) parsed_answer = matches[-1] if matches else "" return parsed_answer == true.answer

DSPy 優化

使用 DSPy 的 BootstrapFewShotWithRandomSearch 優化器來完善我們的模組:

from dspy.teleprompt import BootstrapFewShotWithRandomSearch config = dict( max_bootstrapped_demos=2, max_labeled_demos=4, num_candidate_programs=2, num_threads=6 ) teleprompter = BootstrapFewShotWithRandomSearch(metric=eval_metric, **config) optimized_qa = teleprompter.compile(basic_qa, trainset=trainset, valset=valset)

性能提升結果

優化後的模組評分從約 31% 提升至約 48%,相對提升超過 50%,且完全無需手動調整 Prompt。

進階技巧:思維鏈

接下來,我們引入思維鏈(Chain of Thought)技術:

class CoT(dspy.Module): def __init__(self): super().__init__() self.prog = dspy.ChainOfThought("question -> answer") def forward(self, question): return self.prog(question=question) cot_qa = CoT()

經過優化後,思維鏈模組評分從約 51% 提升至約 57%,相對提升約 10%。

DSPy 的優勢總結

  • 開發效率提升:DSPy 大幅減少手動工作,無須反覆編寫與測試 Prompt。開發者能快速實驗不同架構與策略,並透過 Optimizer 自動找到更佳提示組合。
  • 系統可靠性提升:DSPy 確保重複性,相同程式碼可產生一致結果。每個 Module 均能獨立測試,優化過程完全可追蹤、可重現。
  • 可移植性提升:DSPy 採用模型無關設計,同樣程式碼可於不同 LLM 執行,易於切換推理策略(如 ChainOfThought 與 ReAct),也能輕鬆整合新的 LLM 或優化技術。
  • 性能提升:實例顯示,DSPy 優化能讓基礎模型提升超過 50%,進階模型亦有 10% 以上額外成長,使系統表現更為穩定可靠。

DSPy 與傳統 Prompt Engineering 的對比

面向傳統 Prompt EngineeringDSPy
開發方式手動編寫字串程式化模組
可移植性模型特定,難以移植模型無關,易於移植
可維護性難以追蹤和版本控制程式碼化,易於管理
優化方式手動試錯自動優化
系統架構與提示混雜關注點分離
規模化難以管理大量 Prompt自動生成和管理
性能提升依賴經驗和直覺數據驅動,可量化

結論:DSPy 作為 Prompt Engineering 的重要補足

為什麼是「補足」而非「取代」?

DSPy 並非完全取代傳統 Prompt Engineering,而是提供更高層次的抽象,讓開發者專注於系統設計而非提示細節,快速迭代實驗不同架構和策略,透過自動化優化讓系統自主找到最佳提示組合,並以程式碼化方式提高可維護性。

DSPy 的適用場景

DSPy 特別適合複雜的多模組協作系統、需要根據數據持續改進的系統、需要在不同 LLM 間切換的多模型環境,以及需要可靠、可維護、可追蹤的生產環境。

未來展望

DSPy 代表 AI 開發的重要轉折點,從「提示工程」轉向「程式化開發」,不僅提高開發效率,也讓 AI 系統更可靠、可維護和可擴展。隨著生態系統發展,我們可期待更多針對不同場景的優化器和模組、更強大的開發除錯工具,以及從研究到生產環境的更廣泛應用。

參考資料:

  1. 【Day 27】- 告別提示工程:DSPy如何革新大型語言模型的應用開發
  2. 【Day 28】- 從零開始的 DSPy:打造高效翻譯錯誤檢測系統
  3. DSPy 官方文件 - Programming Overview
  4. DSPy 官方網站