iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
生成式 AI

2024 年用 LangGraph 從零開始實現 Agentic AI System系列 第 27

【Day 27】- 告別提示工程:DSPy如何革新大型語言模型的應用開發

  • 分享至 

  • xImage
  •  

摘要
DSPy 是一個由 Stanford NLP 研究人員開發的框架,旨在簡化大型語言模型 (LLM) 的開發。它以 "Programming, not Prompting" 為口號,強調直接對 LLM 進行編程,而不是花費時間設計提示。DSPy 使用「Signatures」定義任務,使用「Modules」將 LLM 行為組合起來,並使用「Optimizers」自動調整提示以優化模型性能。Signatures 就像是任務的藍圖,描述了輸入和輸出,而 Modules 提供了像 ChainOfThought、ReAct 等常見的 LLM 行為模式。Optimizers 則能根據特定指標自動調整提示,讓開發者不必手動調整。通過將這些元素結合在一起,DSPy 讓開發者能夠以更系統化、更高效的方式開發 LLM 應用程式,並提高模型的性能。

引言

在人工智能快速發展的今天,DSPy(Declarative Self-improving Language Programs in Python)作為一個革命性的框架,正在改變我們與大型語言模型(LLMs)互動的方式。本文將深入探討 DSPy 的核心理念、主要組件以及它如何解決當前 AI 開發中的痛點。

img

1. DSPy 簡介:程式化而非提示工程

DSPy 的口號 "Programming, not Prompting" 精確地概括了其核心理念。這個由 standford NLP 研究人員開發的框架旨在簡化 AI 模型的開發過程,使開發者能夠直接對模型進行編程,而不是耗時費力地製作完美提示。

圖片:DSPy logo

1.1 DSPy 的問題導向

差異圖
使用語言模型打造 GenAI 系統時通常需要以下幾個步驟:

  1. 開出功能需求,並且逐一列出功能細節項目
  2. 針對功能細節項目建立良好的 Prompt,確認運作良好
  3. 將每個步驟整合再一起,調教成運作正常狀況。
  4. 利用 AI 產生合成資料微調系統上每一個環節。
  5. 嘗試改用其他模型,改善當中的環節。

這個方法既複雜又耗時,每次只要更改管道、語言模型、資料時,就需要重新調整 Prompt。

DSPy 致力於解決這些問題,提供更系統化、更高效的開發方法。

1.2 DSPy 的創新解決方案

DSPy框架為大型語言模型(LLM)的優化帶來了革命性的突破,其創新之處主要體現在兩個方面:

  1. 模組化設計:將程序流程(module)與提示語分離,提高了開發靈活性。
  2. 智能優化器:引入 "Optimizer" 概念,自動調整 LLM 調用的提示,無需人工干預。

首先,DSPy巧妙地將程序流程(即「module」)與每個步驟的提示語分離。這種設計理念使得開發者能夠靈活地重組模組並調整提示語,無需反覆修改提示或生成合成數據,大大提高了開發效率。

其次,DSPy引入了創新的「Optimizer」概念。這些優化器本質上是由LLM驅動的算法,能夠根據預設的指標自動調整LLM調用的提示。這意味著系統可以在無需人工干預的情況下,自主探索最佳的提示組合。

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

2.DSPy 核心組件

2.1 Signatures:任務藍圖

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

基本用法示例:

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


# 聲明語言模型任務
classify = dspy.Predict('sentence -> sentiment')

# 實操
sentence = "你人真好"
classify(sentence=sentence).sentiment

#輸出
'Positive'

神奇吧,我們拋開了冗長的細解,化繁約簡的變成一條聲明處理。

鑑於這種用法,Signature 就可以表達常見的 NLP 任務

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

有經驗的小夥伴可能會注意到,如果想要更自由的描述任務細節的話可以怎麼做?

進階用法:

DSPy 提供 Class-based 的用法,如下呈現

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 需要被描述的更詳細,特別是以下幾方面的敘述:

  1. 對於 執行任務 的性質(以 docstring 的形式表示)
  2. 對於 輸入欄位 性質的 提示(hint) 。(以 dspy.InputField 裏的 desc 參數來敘述)
  3. 提供 輸出欄位 的 約束。(以 dspy.OutputField 裏的 desc 參數來敘述)

💡 提示:Signature 應包含任務描述、輸入定義和輸出約束,以確保模型理解任務要求。

2.1.1Signaute 延伸內容

官方文件表明 signature 是告訴語言模型要查成什麼目標,而非鉅細靡遺告訴模型要怎模執行。
每一條 Signature 都可以被解構成三個區塊:

  • 任務描述(Task description):我們在 Signature 類別文件字串中定義。
  • 輸入(Input):我們將其定義為dspy.InputField() 。
  • 輸出(Output):我們將其定義為dspy.OutputField() 。

![img]https://i.imgur.com/pRJTLUi.png[/img]

取自官方文件圖片

而在 Class Based Signature 中 Signature 類別抽象化了上述內容,並允許您透過其輸入和輸出(回應)來表達您的任務。在內部,框架將 Signature 類別轉換為提示。它們以聲明方式指定規範,定義並規定了我們在 DSPy 中使用的任何模組的行為。

官方圖片
取自官方文件圖片

正如您所看到的,文件字串中的任務指令更明確地定義了該指令。 answer欄位的前綴和描述反映了我們的定義。這確保了更精細的提示結構,使用戶能夠更好地控制每個任務要求定義其內容。

2.2 Modules:LLM 行為構建塊

補一張來自 Medium 圖片
取自Leonie Monigatti Medium

有經驗的朋友肯定注意到,光是要求語言模型做摘要還不夠,通常會加上角色扮演、思考方式、推論步驟等進階用法,而這類操作早已變成固定模版操作。例如說 ChainOfThought 鼓勵語言模型逐步思考,使其能夠完成複雜的推理任務。ReAct 讓語言模型可以跟外部工具互動等。在 DSPy 中可以善用 module 來達成,官方現有支持的方式有幾種:

  • dspy.ChainOfThought()
  • dspy.ProgramOfThought()
  • dspy.ReAct()
  • dspy.MultiChainComparison()

更多可以參考官方文件:https://dspy-docs.vercel.app/docs/deep-dive/modules/guide#2-what-dspy-modules-are-currently-built-in

官方預設模組範例

# 假設問題
question = "What's something great about the ColBERT retrieval model?"

# 執行函數
classify = dspy.ChainOfThought('question -> answer', n=5)
response = classify(question=question)

# 產生輸出
response.completions.answer

['One great aspect of the ColBERT retrieval model is its ability to efficiently and accurately retrieve information from large-scale datasets.']

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

透過這種方式,模組獲取簽名,應用其特定行為或技術,並產生符合任務要求的提示。這種簽名和模組的整合允許構建複雜且靈活的LLM需要最少人工干預的應用程式。

如果好奇中間如何思考的話,在 dspy.ChainOfThought 這個模組會在輸出欄位多加一個 rationale

print(f"Rationale: {response.rationale}") # 回傳第一個推導的過程
print(f"Answer: {response.answer}") # 回傳經過完整的 CoT 推導後的輸出

Rationale: produce the answer. We know that the ColBERT retrieval model is designed specifically for efficient and accurate retrieval of information from large-scale datasets. It utilizes a compact vector representation of documents to quickly and effectively identify relevant information based on user queries. This allows for faster and more precise search results compared to traditional retrieval models.
Answer: One great aspect of the ColBERT retrieval model is its ability to efficiently and accurately retrieve information from large-scale datasets.

自定義模組:

言而總之,可以透過 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()

2.3 Optimizers:自動化提示優化

補一張來自 Medium 圖片
取自Leonie Monigatti Medium

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

DSPy 中已有內建多種 。每個都採用不同演算法執行。在 Optimizer 中會需要三個輸入:

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

Optimizer程式碼示例: 客戶服務聊天機器人優化

假設您正在為一家電商平台開發客戶服務聊天機器人。您有 50 個樣本數據,包含常見問題和相應答案。
因數據量適中,需要一定的搜索能力來找到最佳提示,選擇: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)

# 保存優化後的程序
optimized_program.save("path_to_save.json")

# 稍後加載程序
loaded_program = YourProgramClass()
loaded_program.load(path="path_to_save.json")

DSPy採用了一種多階段的優化算法,能根據程序需求從零開始生成示例,並通過多種高效方法進行優化。這種方法往往能產生比人工編寫更優秀的提示。值得注意的是,DSPy 中的示範遠非簡單的少量樣本示例,它們具有強大的生成和優化能力,能夠根據程序需求從零開始創建,並通過多種高效方法進行優化。

實踐證明,DSPy 的編譯優化往往能夠產生比人工編寫更優秀的提示。這並非意味著 DSPy 的優化器在創造力上超越了人類,而是因為它能夠更系統、更全面地嘗試各種可能性,並直接針對特定指標進行調整。這種方法不僅提高了效率,還為 AI 系統的優化開闢了新的途徑。

2.3.1 實作上我要選擇哪個 Optimizer ?

在 AI 模型優化的世界中,選擇正確的 Optimizer 可以成為項目成功與否的關鍵。DSPy 框架提供了多種強大的 Optimizer,每一種都有其獨特的優勢和適用場景。

DSPy Optimizer 概覽

首先,讓我們快速瀏覽 DSPy 提供的各種 Optimizer。您可以通過以下方式導入這些工具:

from dspy.teleprompt import *

Optimizer 分類表

類別 Optimizer
自動少樣本學習 LabeledFewShot, BootstrapFewShot, BootstrapFewShotWithRandomSearch, BootstrapFewShotWithOptuna
自動指令優化 COPRO, MIPRO
自動微調 BootstrapFinetune
程式轉化 KNNFewShot, Ensemble
Optimizer 選擇指南

選擇合適的 Optimizer 取決於多個因素,包括數據量、計算資源和具體任務需求。以下是一些基本原則:

  • 💡 小數據集(約 10 個樣本) 推薦使用 BootstrapFewShot
  • 💡 中等數據集(約 50 個樣本) 推薦使用 BootstrapFewShotWithRandomSearch
  • 💡 較大數據集(300+ 樣本) 推薦使用 MIPRO
  • 💡 大型語言模型 + 效能要求 考慮使用 BootstrapFineTune

選擇合適的 DSPy Optimizer 是一門藝術,需要考慮數據規模、任務複雜度和可用資源。通過本指南,您應該能夠為大多數常見場景選擇適當的 Optimizer。記住,實踐和實驗是提高選擇能力的最佳方法。

對於更複雜的場景或特定需求,建議查閱 DSPy 官方文檔 以獲取更詳細的信息和最新更新。持續學習和實驗將幫助您成為 DSPy Optimizer 的專家,為您的 AI 項目帶來顯著的性能提升。

2.4 DSPy 中每個組件的區別是什麼?我要懶人包

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

現在我們了解了每個元件的使用方式,讓我們透過一個範例來了解如何使用 DSPy。在下一節中,我們將探討使用 DSPy 最佳化大型語言模型的端到端範例。

結語

DSPy 為 AI 開發帶來了新的可能性。通過其創新的模組化設計和智能優化器,開發者可以更專注於任務邏輯,而不是花費大量時間調整提示。這不僅提高了開發效率,還為 AI 系統的優化開闢了新的途徑。

即刻前往教學程式碼 Repo,親自體驗解放提示語工程的泥淖中吧!別忘了給專案按個星星並持續關注更新,讓我們一起探索AI代理的新境界。

X. 參考

  1. Leonie Monigatti Medium
  2. Fearnworks 撰寫文章,有系統性整理 DSPy
  3. Chris Levy 使用 Custom Dataset 來進行評估

上一篇
【Day 26】- Ollama: 革命性工具讓本地 AI 開發觸手可及 - 從安裝到進階應用的完整指南
下一篇
【Day 28】- 從零開始的 DSPy:打造高效翻譯錯誤檢測系統
系列文
2024 年用 LangGraph 從零開始實現 Agentic AI System29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言