陪讀蛙

一次請求是怎麼拼出來的

陪讀蛙按什麼順序拼出最終送出的提示詞,以及它拿模型回傳的文字做了些什麼。

你填的那兩個欄位並不是真正離開瀏覽器的內容。陪讀蛙會追加規則區塊、取代變數、附上術語;而在模型回覆落到頁面上之前,它還要對回覆做不少處理。本頁按順序把這兩半都走一遍。

這裡講的都是 LLM 服務商。Google 翻譯、微軟翻譯和 DeepL 不接收提示詞,以下各步與它們無關。

請求是怎麼拼出來的

1. 挑出段落

內容腳本在段落接近可視範圍時把它們收集起來,剔掉被跳過規則或小段落過濾排除的那些,其餘的交給佇列。在 LLM 服務商上,佇列會把彼此相容的段落合併成一次請求——同一個服務商、同一對語言、同一份頁面上下文——直到撞上請求控制與批次翻譯頁面上的字元數和段落數上限。這一組就是 {{input}} 的內容。

2. 選定提示詞

陪讀蛙按你選取的提示詞 id 去找。命中內建的就用內建的;否則在你自己的提示詞裡找;兩邊都找不到——比如你把當時正在使用的提示詞刪掉了——它會退回到通用,而不是直接失敗。

3. 追加規則區塊

額外的指令會追加到系統提示詞上,而且只在需要的時候追加。這就是同一個提示詞在不同段落上會產生不同請求的原因。

規則區塊什麼時候追加
多段落規則本次請求帶了不止一個段落
已是目標語言規則本次請求帶了不止一個段落,且僅限網頁翻譯
HTML 標記保護規則文字裡含有 data-rf-attr 標記
佔位符保護規則文字裡含有帶編號的公式佔位符

只帶一個段落的請求一個都不會有。字幕翻譯會拿到多段落規則,但永遠不會拿到「已是目標語言」那條。

4. 取代變數

這時才把 {{...}} 這些名稱取代掉,兩個欄位都取代,取值見提示詞變數。只有已知名稱會被取代,其他內容原樣保留。

5. 附上術語

最後,把你術語庫裡真正出現在這段文字中的術語追加到系統提示詞後面。放在最後是故意的:術語是你自己輸入的文字,如果在取代變數之前就拼進去,一條恰好含有變數名稱的術語就能改寫它周圍的提示詞。

一次成型的請求

一篇英文文章的兩個段落,翻譯成簡體中文,用通用提示詞,AI 智慧上下文關閉。送出去的系統提示詞是:

You are a professional Simplified Mandarin Chinese native translator who needs to fluently translate text into Simplified Mandarin Chinese.

## Translation Rules
1. Output only the translated content, without explanations or additional content ...
2. The returned translation must maintain exactly the same number of paragraphs and format as the original text.
3. If the text contains HTML tags, consider where the tags should be placed in the translation while maintaining fluency.
4. For content that should not be translated (such as proper nouns, code, etc.), keep the original text.

## Document Metadata for Context Awareness
Webpage title: Why your timestamps are eight hours off — devblog
Webpage summary: No summary available

## Multi-paragraph Translation Rules
1. If input contains a standalone line containing only %%, use a standalone %% line in your output ...
2. **CRITICAL**: Treat %% as a separator only when it appears on its own line ...

## OUTPUT FORMAT:
- **Single paragraph input** → Output translation directly (no separators, no extra text)
- **Multi-paragraph input** → Put %% on its own line between translations

## Already-translated Input Rule
Output only {{NO_TRANSLATION_NEEDED}} when only non-translatable names, brands, handles, URLs, numbers, or code differ from Simplified Mandarin Chinese. A foreign-language phrase or clause must be translated.

提示詞是:

Translate to Simplified Mandarin Chinese:


Every timestamp you store without a zone is a bug waiting for a plane ticket.

%%

The fix is boring: store UTC, render local, and never let the two meet in a database column.

注意冒號後面那兩個空行——它們來自提示詞欄位本身,也就是 Translate to {{targetLanguage}}: 之後跟兩個空行再跟 {{input}}

回覆是怎麼處理的

1. 去空白、切分

回覆先做首尾去空白,然後按「整列只有 %%」的列切開。每一段再各自去一次空白,並與請求中相同位置的段落對應起來。出現在句子中間、程式碼範例裡或引文裡的 %% 不算分隔符號——只有除它之外什麼都沒有的那一列才算。

2. 驗證數量

陪讀蛙要求切出來的段數和送出去的完全一致。數量不對是整組的徹底失敗,而不是部分成功:這次請求會以遞增的間隔重試最多三次,如果還是對不上,這一組裡的每個段落會被單獨重送一遍。這更慢也更貴,所以一個鼓勵模型加評論、或者把段落合併的提示詞,不只是不整齊,而是真的費錢。

3. 處理「不需要翻譯」

{{NO_TRANSLATION_NEEDED}} 是我們告訴模型的一個答案:當某個段落本來就是用你的目標語言寫的時候,就回傳它。當某一段恰好只是這個標記時,陪讀蛙會把譯文當作空,而空譯文什麼都不算繪——雙語模式下那個段落底下不會出現第二列,僅譯文模式下原文繼續顯示。

這個標記會原樣寫入快取,所以以這種方式結案的段落下次造訪時不會再送一遍請求。它被故意做成變數的樣子:變數取代只取代它認識的名稱,所以這個標記能毫髮無損地穿過整個提示詞拼裝過程,每次到達模型時的寫法都完全一致。

4. 丟掉什麼也沒說的譯文

模型拿到本來就是目標語言的文字時,常常不用上面那個標記,而是把原文帶著一點表面差異回抄一遍——空白重排、直引號變成彎引號、標點變全形。陪讀蛙會在把這些差異正規化之後拿回覆和原文比較,一致就同樣當作空。這就是混合語言頁面上有些段落明明送過請求、卻看不到譯文的原因。

5. 核對標記

如果送出的文字帶了 data-rf-attr 標記,回覆必須把每一個都原樣回傳一次,並且掛在同一種元素上。標記缺失、重複、被憑空造出來、或者跑到了另一種標籤上,這個段落會直接判為失敗——而不是算繪出一個指向別處的連結。

帶編號的公式佔位符處理得寬鬆一些。丟了或重複了佔位符的回覆仍然會顯示出來——缺失的公式會被補在後面——但它不會寫入快取,這樣下次造訪會重新試一遍,而不是讓這個段落永久保持降級狀態。

6. 存下來

活下來的結果寫入翻譯快取,頁面隨之更新。

快取的鍵

一條快取譯文的鍵裡包含了——除別的東西之外——最終成型的系統提示詞和提示詞:追加規則區塊之後、取代變數之後、附上術語之後的那兩段。

由此帶來三個值得知道的結果:

  • 改提示詞會讓所有用舊提示詞翻出來的譯文失去歸屬。 你已經讀過的頁面會被重新翻譯,也會重新計費。
  • 改術語庫只會影響那些命中了術語的段落。 一條術語都沒命中的段落,送出的提示詞和「完全沒有術語庫」逐位元組一致,所以它的快取項目不受影響。
  • 開或關 AI 智慧上下文會改變每一個鍵,因為摘要變數變了——從一份真實摘要變成 No summary available,或者反過來。

設定 → 網頁翻譯裡清除快取,會刪掉已存的譯文和網頁摘要,但不會動你的提示詞、服務商和術語庫。

On this page