提示詞
瞭解如何在 Flutter 中透過系統指令、動態引數和版本控制技術構建並最佳化生成式 AI 提示詞(Prompts)。
假設你已經配置好了使用 Firebase AI Logic SDK 所需的 Firebase 專案和配置(具體可參考 README),你就可以開始使用生成式 AI 了。生成式 AI 是機器學習(ML)的一個分支,它利用在海量人類語言資料上訓練的神經網路來構建大語言模型(LLM)。目前,最優秀的模型(如 Google Gemini)基本上是在整個網際網路資料上訓練出來的。
在如此大規模的規模下,經過海量資料訓練的模型已經能夠理解人類語言並生成有用的人類語言輸出。相信你現在已經使用過 Gemini 聊天應用(或者 ChatGPT、Claude 等其他聊天應用),所以你應該知道,如果使用模糊的語言與 LLM 對話,你很可能會得到模糊甚至錯誤的回覆。如果你想獲得高質量的結果,就必須使用高質量的提示詞。
提示詞構建
#提示詞(Prompt)是你輸入給 LLM 以獲取期望輸出的內容。它包括文字以及零個或多個檔案(如影像或 PDF)。如果你正在應用中構建聊天功能,使用者將自行輸入提示詞(Flutter AI Toolkit 對於構建聊天 UI 非常有用)。如果你使用 LLM 來實現應用的功能,例如解析影像以獲取填字遊戲資料,那麼就需要由你來構建提示詞。構建的方式非常關鍵。
以構建《Crossword Companion》(填字遊戲助手)為例,最初的線索解答提示詞看起來是這樣的:
You are a crossword puzzle solver. Your goal is to solve the puzzle by filling in the grid with the correct answers. Given the current state of the crossword grid and a single clue, provide the answer for that clue. The answer should be a single word, returned in a JSON object that matches the following schema: '{"type": "object", "properties": {"answer": {"type": "string"}}}'.
# Puzzle Information
## Grid Layout
The grid is (${grid.width}x${grid.height}):
${_getGridStateAsString(grid)}
## Clue
${clue.number} ${clue.direction == ClueDirection.across ? 'Across' : 'Down'}: ${clue.text}
這個提示詞並不算太糟——它包含了一些有用的部分:
- 角色(Persona):“你是一個填字遊戲解謎者”這句話縮小了模型的關注範圍。
- 上下文(Context):謎題的當前狀態。
- 查詢(Query):請求解答某個線索。
- 格式(Format):以 JSON 格式提供輸出,以便結果可以被程式化解析。
然而,由於資料具有二維特性,這對某些模型來說是一個很難處理的提示詞。Gemini 2.5 Flash(當時可用的模型中效率更高的一款)產生的結果不穩定。Gemini 2.5 Pro 的結果質量極佳,但速度較慢且成本較高。除錯顯示,Pro 模型在每次呼叫時實際上都在嘗試解決整個謎題,而不僅僅是回應單個線索的答案。
我們需要的是 Flash 的高效與 Pro 的高質量。要做到這一點,需要對提示詞進行一些最佳化。
Your task is to solve the following crossword clue.
**Clue:** "${clue.text}"
**Constraints:**
- The answer is a **$length-letter** word.
- The current letter pattern is `$pattern`, where `_` represents an unknown letter.
Return your answer and confidence score in the required JSON format.
這個提示詞要求解決線索,提供了關鍵的上下文,並指定了輸出格式。輸入不再是整個二維網格的狀態,而是簡化為長度要求和模式(例如 "_ R _ Y")。這些簡化使 Flash 能夠產生高質量的結果,且響應速度快到足以帶來流暢的體驗。
提示詞分層
#用於解答線索的提示詞並不是模型看到的唯一資訊。它還有系統指令(也稱為系統訊息或系統提示詞),這是在模型例項建立時設定的。你可以把系統指令想象成“你的職責是這樣的”,而單個提示詞則是“現在去做這件事”。
這是線索解答模型的部分系統指令(其餘部分稍後會看到):
final clueSolverSystemInstruction =
'''
You are an expert crossword puzzle solver.
**Follow these rules at all times:**
1. **Prefer Common Words:** Prioritize common English words and proper nouns. Avoid obscure, archaic, or highly technical terms unless the clue strongly implies them.
2. **Match the Clue:** Ensure your answer strictly matches the clue's tense, plurality (singular vs. plural), and part of speech.
3. **Verify Grammatically:** If a clue implies a specific part of speech (e.g., it's a verb, adverb, or plural), it's a good idea to use the `getWordMetadata` tool to verify your candidate answer matches. However, avoid using it for every clue.
4. **Be Confident:** Provide a confidence score from 0.0 to 1.0 indicating your certainty.
5. **Trust the Clue Over the Pattern:** The provided letter pattern is only a suggestion based on other potentially incorrect answers. Your primary goal is to find the best word that fits the **clue text**. If you are confident in an answer that contradicts the provided pattern, you should use that answer.
6. **Format Correctly:** You must return your answer in the specified JSON format.
...
''';
有了想要使用的模型和系統指令,我們現在就具備了建立例項所需的一切:
// The model for solving clues.
_clueSolverModel = FirebaseAI.googleAI().generativeModel(
model: 'gemini-2.5-flash',
systemInstruction: Content.text(clueSolverSystemInstruction),
...
);
雖然系統指令通常是靜態的,但單個提示詞通常是基於資料動態建立的。
提示詞引數化
#每個線索解答提示詞都是使用線索文字、答案的目標長度以及根據已解答線索得出的模式(如 "_R_Y")動態生成的。
String getSolverPrompt(Clue clue, int length, String pattern) =>
'''
Your task is to solve the following crossword clue.
**Clue:** "${clue.text}"
**Constraints:**
- The answer is a **$length-letter** word.
- The current letter pattern is `$pattern`, where `_` represents an unknown letter.
Return your answer and confidence score in the required JSON format.
''';
有了提示詞,我們就可以將其傳遞給模型來獲取線索答案:
final result = await _clueSolverModel.generateContent(
prompt: getSolverPrompt(clue, length, pattern),
);
提示詞版本控制
#這個基礎應用將提示詞字串保留在程式碼中,這使得它們難以追蹤和更新。對於生產環境應用,最好將提示詞與程式碼分離,例如作為 Flutter 資源打包。安排提示詞檔案的一種方法是使用 Google dotprompt 格式,它允許你編寫像下面這樣的 .prompt 檔案:
---
model: googleai/gemini-2.5-flash
input:
schema:
text: string
output:
format: json
schema:
title?: string, the title of the article if it has one
summary: string, a 3-sentence summary of the text
tags?(array, a list of string tag category for the text): string
---
Extract the requested information from the given text. If a piece of information is not present, omit that field from the output.
Text:
要在 Dart 和 Flutter 專案中使用 .prompt 檔案,你可以使用 dotprompt_dart 軟體包。