使用 AI 模型產生內容

生成式 AI 的核心是 AI 模型。生成式模型最常見的兩個例子是大型語言模型 (LLM) 和圖片生成模型。這些模型會接收輸入內容 (稱為「提示」,通常是文字、圖片或兩者組合),並產生文字、圖片,甚至是音訊或影片。

這些模型的輸出內容令人驚艷,因為 LLM 產生的文字看起來就像是人類所寫,而圖像生成模型則能產生與真實相片或人類創作藝術品極為相似的圖像。

此外,大型語言模型已證明自己能處理的任務不只限於簡單的文字產生:

  • 編寫電腦程式。
  • 規劃完成大型工作所需的子工作。
  • 整理未整理的資料。
  • 從文字集合中瞭解及擷取資訊資料。
  • 根據活動的文字說明,執行自動活動。

您可以選擇多家供應商提供的多種型號。每個模型都有各自的優缺點,某個模型可能擅長某項工作,但在其他工作上表現不佳。應用程式在使用生成式 AI 時,通常會根據手邊工作使用多種不同的模型。

身為應用程式開發人員,您通常不會直接與生成式 AI 模型互動,而是透過以網路 API 形式提供的服務。雖然這些服務通常提供類似的功能,但都透過不同的 API 提供,且這些 API 不相容。如果您想使用多個模型服務,就必須使用各自的專屬 SDK,但這些 SDK 可能彼此不相容。而且如果您想從一個模型升級至最新且功能最強大的模型,可能就必須重新建構該整合。

Genkit 提供單一介面,可抽離存取任何生成式 AI 模型服務的詳細資料,並提供多個預先建構的實作項目,解決這項挑戰。以 Genkit 為基礎建構 AI 應用程式,可簡化首次生成式 AI 呼叫的程序,並讓您輕鬆結合多個模型,或在有新模型出現時交換模型。

事前準備

如果您想執行本頁的程式碼範例,請先完成「開始使用」指南中的步驟。所有範例都假設您已在專案中安裝 Genkit 做為依附元件。

Genkit 支援的模型

Genkit 的設計十分靈活,可支援任何生成式 AI 模型服務。其核心程式庫會定義處理模型的通用介面,而模型外掛程式會定義處理特定模型及其 API 的實作詳細資料。

Genkit 團隊會維護外掛程式,以便使用 Vertex AI、Google 生成式 AI 和 Ollama 提供的模型:

載入及設定模型外掛程式

您必須先載入並設定模型外掛程式,才能使用 Genkit 開始產生內容。如果您是從「開始使用」指南前來,表示您已完成這項操作。否則,請參閱入門指南或個別外掛程式的說明文件,並按照其中的步驟操作,再繼續操作。

genkit.Generate() 函式

在 Genkit 中,您與生成式 AI 模型互動的主要介面是 genkit.Generate() 函式。

最簡單的 genkit.Generate() 呼叫會指定要使用的模型和文字提示:

import (
    "context"
    "log"

    "github.com/firebase/genkit/go/ai"
    "github.com/firebase/genkit/go/genkit"
    "github.com/firebase/genkit/go/plugins/googlegenai"
)

func main() {
    ctx := context.Background()

    g, err := genkit.Init(ctx,
        genkit.WithPlugins(&googlegenai.GoogleAI{}),
        genkit.WithDefaultModel("googleai/gemini-2.0-flash"),
    )
    if err != nil {
        log.Fatal(err)
    }

    resp, err := genkit.Generate(ctx, g,
        ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
    )
    if err != nil {
        log.Fatal(err)
    }

    log.Println(resp.Text())
}

執行這個簡短範例時,系統會列印一些偵錯資訊,接著是 genkit.Generate() 呼叫的輸出內容,通常會是 Markdown 文字,如下例所示:

## The Blackheart's Bounty

**A hearty stew of slow-cooked beef, spiced with rum and molasses, served in a
hollowed-out cannonball with a side of crusty bread and a dollop of tangy
pineapple salsa.**

**Description:** This dish is a tribute to the hearty meals enjoyed by pirates
on the high seas. The beef is tender and flavorful, infused with the warm spices
of rum and molasses. The pineapple salsa adds a touch of sweetness and acidity,
balancing the richness of the stew. The cannonball serving vessel adds a fun and
thematic touch, making this dish a perfect choice for any pirate-themed
adventure.

再次執行指令碼,您會看到不同的輸出結果。

上述程式碼範例會將產生要求傳送至預設模型,您在設定 Genkit 執行個體時已指定該模型。

您也可以為單一 genkit.Generate() 呼叫指定模型:

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.5-pro"),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)

模型字串 ID 的格式為 providerid/modelid,其中提供者 ID (在本例中為 googleai) 會識別外掛程式,而模型 ID 則是特定版本模型的外掛程式專屬字串 ID。

這些範例也說明瞭一個重要重點:當您使用 genkit.Generate() 呼叫生成式 AI 模型時,只要將不同的值傳遞至模型參數,即可變更要使用的模型。使用 genkit.Generate() 而非原生模型 SDK,可讓您在應用程式中更輕鬆地使用多種不同的模型,並在日後變更模型。

到目前為止,您只看到最簡單的 genkit.Generate() 呼叫範例。不過,genkit.Generate() 也提供介面,可與生成式模型進行更進階的互動,您將在後續章節中看到這項介面。

系統提示

部分模型支援提供系統提示,可讓模型瞭解如何回應使用者傳送的訊息。您可以使用系統提示指定特徵,例如希望模型採用的角色、回應的語氣和回應格式。

如果您使用的模型支援系統提示,您可以使用 WithSystem() 選項提供提示:

resp, err := genkit.Generate(ctx, g,
    ai.WithSystem("You are a food industry marketing consultant."),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)

如果模型不支援系統提示,WithSystem() 會修改要求,讓其「看起來像」系統提示,以模擬系統提示。

模型參數

genkit.Generate() 函式會採用 WithConfig() 選項,您可以透過該選項指定可選設定,控制模型產生內容的方式:

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.0-flash"),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
    ai.WithConfig(&googlegenai.GeminiConfig{
        MaxOutputTokens: 500,
        StopSequences:   ["<end>", "<fin>"],
        Temperature:     0.5,
        TopP:            0.4,
        TopK:            50,
    }),
)

支援的確切參數取決於個別模型和模型 API。不過,上述範例中的參數幾乎適用於所有模型。以下是這些參數的說明:

控制輸出長度的參數

MaxOutputTokens

LLM 會處理稱為「符記」的單位。符記通常會對應至特定字元序列,但不一定如此。當您將提示傳遞至模型時,模型會先將提示字串轉為符記,接著,LLM 會從已切割的輸入內容產生符記序列。最後,符號序列會轉換回文字,也就是輸出內容。

輸出符記數量上限參數會設定使用 LLM 產生的符記數量上限。每個模型都可能使用不同的分詞器,但一般來說,單一英文單字可視為由 2 到 4 個字元組成。

如前所述,某些符記可能無法對應至字元序列。舉例來說,通常會有一個符記可指出序列的結尾:當 LLM 產生這個符記時,就會停止產生更多符記。因此,LLM 產生的符記可能會少於上限,因為它會產生「stop」符記。

StopSequences

您可以使用這個參數設定符記或符記序列,當系統產生這些符記或符記序列時,就會表示 LLM 輸出結束。這裡使用的正確值通常取決於模型的訓練方式,通常由模型外掛程式設定。不過,如果您已提示模型產生其他停止序列,可以在這裡指定。

請注意,您指定的是字元序列,而非符記。在大多數情況下,您會指定字元序列,讓模型的分析器將其對應至單一符記。

控制「創意」的參數

溫度前 P 個前 K 個參數會共同控制您希望模型採取的「創意」程度。本節會簡要說明這些參數的含義,但更重要的是:這些參數可用於調整 LLM 輸出的字元。這些值的最佳值取決於您的目標和偏好設定,而且可能只有透過實驗才能找出。

溫度

大型語言模型基本上是符號預測機器,對於特定的符記序列 (例如提示),LLM 會針對詞彙中的每個符記,預測符記在序列中出現的可能性。溫度是一種縮放因子,用於將這些預測值除以 0 和 1 之間的概率,以便正規化。

低溫度值 (介於 0.0 和 1.0 之間) 會放大符號之間的可能性差異,導致模型更不可能產生已評估為不太可能的符號。這通常會被視為不太有創意的輸出內容。雖然 0.0 在技術上並非有效值,但許多模型都將其視為模型應以確定性行為運作,並只考慮單一最可能的符記。

高溫度值 (大於 1.0) 會壓縮符號之間的可能性差異,導致模型更有可能產生先前判定為不太可能的符號。這通常被視為更具創意的輸出內容。某些模型 API 會設有溫度上限,通常為 2.0。

TopP

Top-p 是介於 0.0 和 1.0 之間的值,可透過指定符元的累積機率,控制模型要考量的可能符元數量。舉例來說,如果值為 1.0,表示系統會考慮所有可能的符記 (但仍會考量每個符記的機率)。值為 0.4 表示只考慮機率總和為 0.4 的機率最高的符記,並排除其他符記。

TopK

Top-k 是整數值,同樣可控制模型要考慮的可能符號數量,但這次是透過明確指定符號的最大數量。如果指定的值為 1,表示模型應以確定性運作。

嘗試使用模型參數

您可以使用開發人員 UI 實驗這些參數對不同模型和提示組合產生的輸出內容有何影響。使用 genkit start 指令啟動開發人員 UI,系統會自動載入專案中所配置外掛程式定義的所有模型。您可以快速嘗試不同的提示和設定值,而不必在程式碼中重複進行這些變更。

將模型與其設定配對

由於每個供應商或特定型號可能都有自己的設定結構定義或保證特定設定,因此使用 WithModelName()WithConfig() 設定個別選項可能會發生錯誤,因為後者並未對前者進行強型別設定。

如要將模型與其設定配對,您可以建立模型參照,並改為將該參照傳遞至產生呼叫:

model := googlegenai.GoogleAIModelRef("gemini-2.0-flash", &googlegenai.GeminiConfig{
    MaxOutputTokens: 500,
    StopSequences:   ["<end>", "<fin>"],
    Temperature:     0.5,
    TopP:            0.4,
    TopK:            50,
})

resp, err := genkit.Generate(ctx, g,
    ai.WithModel(model),
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)
if err != nil {
    log.Fatal(err)
}

模型參照的建構函式會強制提供正確的設定類型,以減少不相符的情形。

結構化輸出內容

將生成式 AI 用於應用程式中的元件時,您通常會希望輸出格式為純文字以外的格式。即使您只是要產生內容來向使用者顯示,也可以利用結構化輸出內容,讓內容更吸引人。不過,如果是更進階的生成式 AI 應用程式 (例如以程式輔助方式使用模型輸出內容,或將一個模型的輸出內容提供給另一個模型),就必須使用結構化輸出內容。

在 Genkit 中,您可以在呼叫 genkit.Generate() 時指定輸出類型,從模型要求結構化輸出內容:

type MenuItem struct {
    Name        string   `json:"name"`
    Description string   `json:"description"`
    Calories    int      `json:"calories"`
    Allergens   []string `json:"allergens"`
}

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
    ai.WithOutputType(MenuItem{}),
)
if err != nil {
  log.Fatal(err) // One possible error is that the response does not conform to the type.
}

模型輸出類型會使用 invopop/jsonschema 套件指定為 JSON 結構定義。這項功能可提供執行階段類型檢查,填補靜態 Go 類型與生成式 AI 模型不可預測輸出內容之間的差距。這個系統可讓您編寫可依賴以下事實的程式碼:成功的產生呼叫一律會傳回符合 Go 類型的輸出內容。

genkit.Generate() 中指定輸出類型時,Genkit 會在幕後執行多項作業:

  • 針對所選輸出格式,提供額外提示和指引。這也會產生副作用,向模型指定您要產生的確切內容 (例如,不僅建議選單項目,還要產生說明、過敏原清單等)。
  • 驗證輸出內容是否符合結構定義。
  • 將模型輸出內容轉換為 Go 型別。

如要從成功的產生呼叫取得結構化輸出內容,請對模型回應呼叫 Output(),並使用該類型的空值:

var item MenuItem
if err := resp.Output(&item); err != nil {
    log.Fatalf(err)
}

log.Printf("%s (%d calories, %d allergens): %s\n",
    item.Name, item.Calories, len(item.Allergens), item.Description)

或者,您也可以使用 genkit.GenerateData() 來簡化呼叫:

item, resp, err := genkit.GenerateData[MenuItem](ctx, g,
    ai.WithPrompt("Invent a menu item for a pirate themed restaurant."),
)
if err != nil {
  log.Fatal(err)
}

log.Printf("%s (%d calories, %d allergens): %s\n",
    item.Name, item.Calories, len(item.Allergens), item.Description)

這個函式需要輸出類型參數,但會在傳回值之前自動設定 WithOutputType() 選項並呼叫 resp.Output()

處理錯誤

請注意,在前一個範例中,genkit.Generate() 呼叫可能會導致錯誤。當模型無法產生符合結構定義的輸出內容時,就可能發生錯誤。處理這類錯誤的最佳策略取決於您的實際用途,但以下提供一些一般提示:

  • 嘗試其他模型。如要成功產生結構化輸出內容,模型必須能夠以 JSON 產生輸出內容。最強大的 LLM (例如 Gemini) 具有足夠的多功能性,可執行這項操作;不過,較小的模型 (例如您在 Ollama 中使用的部分本機模型) 可能無法可靠地產生結構化輸出,除非經過特別訓練才能做到。

  • 簡化結構定義。大型語言模型可能無法產生複雜或深層巢狀類型。如果無法穩定產生結構化資料,請嘗試使用清楚的名稱、較少的欄位或扁平化結構。

  • 重試 genkit.Generate() 呼叫。如果您選擇的模型很少產生不符合規範的輸出內容,您可以將錯誤視為網路錯誤,並使用某種遞增的輪詢策略重試要求。

串流

產生大量文字時,您可以透過串流方式呈現產生的輸出內容,為使用者提供更優質的體驗。在大多數 LLM 即時通訊應用程式中,您可以看到串流運作情形的常見例子:使用者可以讀取模型對其訊息的回應,並且在回應產生時即時顯示,這有助於提升應用程式的回應速度,並強化使用者與智慧對象對話的錯覺。

在 Genkit 中,您可以使用 WithStreaming() 選項串流輸出內容:

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("Suggest a complete menu for a pirate themed restaurant."),
    ai.WithStreaming(func(ctx context.Context, chunk *ai.ModelResponseChunk) error {
        // Do something with the chunk...
        log.Println(chunk.Text())
        return nil
    }),
)
if err != nil {
    log.Fatal(err)
}

log.Println(resp.Text())

多模態輸入

您目前看到的範例都使用文字字串做為模型提示。雖然這仍是提示生成式 AI 模型最常見的方式,但許多模型也能接受其他媒體做為提示。媒體提示通常會與文字提示搭配使用,指示模型對媒體執行某些作業,例如為圖片加上說明文字或轉錄音訊。

接受媒體輸入內容的能力,以及可使用的媒體類型,完全取決於模型及其 API。舉例來說,Gemini 2.0 系列模型可接受圖片、影片和音訊做為提示。

如要向支援媒體提示的模型提供媒體提示,請傳遞包含媒體部分和文字部分的陣列,而非將簡單的文字提示傳遞至 genkit.Generate()。這個範例會使用可公開存取的 HTTPS 網址指定圖片。

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.0-flash"),
    ai.WithMessages(
        NewUserMessage(
            NewMediaPart("image/jpeg", "https://example.com/photo.jpg"),
            NewTextPart("Compose a poem about this image."),
        ),
    ),
)

您也可以將媒體資料編碼為資料網址,直接傳遞媒體資料。例如:

image, err := ioutil.ReadFile("photo.jpg")
if err != nil {
    log.Fatal(err)
}

resp, err := genkit.Generate(ctx, g,
    ai.WithModelName("googleai/gemini-2.0-flash"),
    ai.WithMessages(
        NewUserMessage(
            NewMediaPart("image/jpeg", "data:image/jpeg;base64," + base64.StdEncoding.EncodeToString(image)),
            NewTextPart("Compose a poem about this image."),
        ),
    ),
)

所有支援媒體輸入的模型都支援資料網址和 HTTPS 網址。部分模型外掛程式會新增其他媒體來源的支援功能。舉例來說,Vertex AI 外掛程式也允許使用 Cloud Storage (gs://) 網址。

後續步驟

進一步瞭解 Genkit

  • 應用程式開發人員影響生成式 AI 模型輸出內容的主要方式,就是透過提示。請參閱「使用 Dotprompt 管理提示」,瞭解 Genkit 如何協助您開發有效的提示,並在程式碼集區中管理提示。
  • 雖然 genkit.Generate() 是每個生成式 AI 應用程式的核心,但實際應用程式通常需要在叫用生成式 AI 模型前後進行額外作業。為反映這項趨勢,Genkit 引入了「flow」概念,其定義與函式類似,但會新增其他功能,例如可觀察性和簡化部署。詳情請參閱「定義 AI 工作流程」。

進階 LLM 用法

應用程式可運用某些技巧,進一步發揮 LLM 的效益。

  • 提升 LLM 功能的方式之一,就是提供一長串提示,讓系統可以向您索取更多資訊,或要求您執行某些動作。這稱為「工具呼叫」或「函式呼叫」。經過訓練可支援這項功能的模型,可透過特殊格式的回應來回應提示,這會向呼叫應用程式指出應執行某些動作,並將結果傳回 LLM 以及原始提示。Genkit 提供程式庫函式,可自動產生提示,並在呼叫工具實作時產生呼叫-回應迴圈元素。詳情請參閱「工具呼叫」。
  • 檢索增強生成 (RAG) 是一種技術,可將特定領域的資訊引入模型輸出內容。方法是先在提示中插入相關資訊,再將其傳遞至語言模型。完整的 RAG 導入作業需要整合多項技術:文字嵌入生成模型、向量資料庫和大型語言模型。請參閱「檢索增強生成 (RAG)」一文,瞭解 Genkit 如何簡化協調這些不同元素的程序。