ETH官方钱包

前往
大廳
主題

關於LLM的Prompt中的「奇怪格式」(適用所有平臺)

慕儀 | 2024-11-30 06:44:27 | 巴幣 1114 | 人氣 766

前言
這裡我介紹一些常見的「奇怪格式」及其功能和用途。
首先,要明確聲明的一點是,LLM並不會真的執行或運算,這些代碼也不存在什麼魔力,只是某些情境下可以用很簡潔的方法處理自然語言需要花費大篇幅才能表達的事情。
這裡主要介紹:
  • Markdown
  • XML、JSON、類JSON
  • CSV、TSV、Markdown表格
  • 偽高級語言
  • 偽變數


Markdown

  • 適用情境:絕大多數時候。
  • 介紹:Markdown是一種非常泛用的輕量化標記式格式,易學易用,好的標記可以強化LLM對Prompt的理解,也能節省大量Tokens。

範例

例如原文為:
{{char}}喜歡:A、B、C
{{char}}討厭:D、E
{{char}}擅長:F、G

若要節省一些字,改寫為:
{{char}}的資訊:
喜歡:A、B、C
討厭:D、E
擅長:F、G

這時候如何讓LLM知道這個「{{char}}的資訊」的內容該從哪裡開始,哪裡結束呢?可以這樣寫:
{{char}}的資訊:
- 喜歡:A、B、C
- 討厭:D、E
- 擅長:F、G

這樣,LLM就會知道底下的列表是延伸定義上面的「{{char}}的資訊」,到列表結束時,自然也就是「{{char}}的資訊」結束時。
(註:為了節省版面,這是一個極簡單的例子,這個例子實際上即便直接寫自然語言,LLM也不容易理解錯誤,但假設你有非常長的篇幅,就不一定了。)

建議

  • # 標題、列表- 、分隔線---、縮排等,讓LLM理解哪些指令是一起作用的,哪些指令擁有更高優先權等等。
  • 符號也要佔用Tokens,請依情境選擇是否使用,簡單的資訊或許完全不需要標記。


XML、JSON或類JSON

  • 適用情境:為複雜提示分類、分塊時。雖然Markdown足以應付大多數狀況,但如果你的提示結構十分複雜,即便你使用高Tokens輸入量的LLM,它也未必能清晰的判斷其重點,反而容易因結構複雜而丟三落四、首尾不能相顧。這時,你就需要更明確的標記來指引LLM如何更好地理解層次與邏輯,這在長篇幅的提示中更為重要。
  • 介紹:
    • XML是一種廣泛的資訊交換格式。可以明確標註資料的屬性、用途、起訖、層次,它支援比JSON更複雜的結構,但寫起來也更為冗長。
    • JSON是一種比XML更簡潔、輕量的資料交換格式。

範例

假設我的提示有幾個大段落,每個段落都有不同的重點與行為準則,其上下文間過長,即便用Markdown也難以讓LLM清楚區分開來,例如原文為:
世界運行的規則
(省略十萬字)
角色的資訊
(十個角色)
事件的流程
(省略十萬字)
回應的格式
(省略十萬字)

XML

<world_rules desc="定義世界運行的規則。">
(省略十萬字)
</world_rules>

<char_info desc="所有預設角色的資訊。">
  <char name="角色1的名字">角色1的資訊</char>
  <char name="角色2的名字">角色2的資訊</char>
  <char name="角色3的名字">角色3的資訊</char>
(省略剩餘角色)
</char_info>

<event_flow desc="定義事件的流程。">
(省略十萬字)
</event_flow>

<response_format desc="定義回應的格式。">
(省略十萬字)
</response_format>

JSON

{
  "world_rules": {
    "desc": "定義世界運行的規則。",
    "content": "(省略十萬字)"
  },
  "char_info": {
    "desc": "所有預設角色的資訊。",
    "chars": [
      {
        "name": "角色1的名字",
        "info": "角色1的資訊"
      },
      {
        "name": "角色2的名字",
        "info": "角色2的資訊"
      },
      {
        "name": "角色3的名字",
        "info": "角色3的資訊"
      }  // (省略剩餘角色)
    ]
  },
  "event_flow": {
    "desc": "定義事件的流程。",
    "content": "(省略十萬字)"
  },
  "response_format": {
    "desc": "定義回應的格式。",
    "content": "(省略十萬字)"
  }
}
至於最後的「類JSON」,你在很多角色看到作者使用大量{[()]}之類符號處理資訊的就是了,理論上LLM也會將之當做「不太規範的JSON變體」理解,但其實那完全沒有必要,那可能只是一種以訛傳訛的迷信,那點資訊量用自然語言或Markdown完全不致於讓LLM產生歧義,用特殊的格式只是浪費Tokens罷了。
類似的選項還有YAML,LLM也能正常理解它,但因為它跟JSON挺類似的,就不再浪費版面寫介紹,有興趣的同學可以自行查詢。

建議:

  • 因為比起Markdown,會消耗更多Tokens,因此若非必要,並不建議。


CSV、TSV、Markdown表格

  • 適用情境:有大量資料,擁有重複的鍵值,並且其格式可以編排為二維表格。
  • 介紹:這三種都是一種表格形式,在情境合適下,可以節省版面與Tokens。
    • CSV與TSV:是一種最簡單的表格形式,使用,逗號或\t分隔符來分割表格內容。
    • Markdown表格:Markdown所使用的表格形式,消耗Tokens會多些,但實測時不知道為什麼,不管什麼LLM都更容易處理這種形式,可能與預先的訓練內容有關。

範例

如果我建立一個開放世界類型的模擬器,而其中內建的預設角色有26人,那麼我原文得這樣寫:
A姓名:莉莉亞
A性別:女
A特質:可愛
A外貌:金馬尾
A性格:害羞
A喜好:甜食
A厭惡:孤獨

B姓名:雅柔
B性別:女
B特質:學霸
B外貌:黑長髮
B性格:矜持
B喜好:鴨子
B厭惡:虛偽
(??中略)
Y姓名:露比娜
Y性別:女
Y特質:高雅
Y外貌:紅長髮
Y性格:溫柔
Y喜好:劍術
Y厭惡:男權

Z姓名:星瑩
Z性別:女
Z特質:笨蛋
Z外貌:黑短髮
Z性格:開朗
Z喜好:漫畫
Z厭惡:規矩
即便使用Markdown或其他方法標記,其中也會有大量重複內容,浪費許多Tokens,但這種資料形式可以排成表格,在資料不太大時,LLM能夠很好的理解它。

CSV

姓名,性別,特質,外貌,性格,喜好,厭惡
莉莉亞,女,可愛,馬尾,害羞,甜食,孤獨
雅柔,女,學霸,長髮,矜持,鴨子,虛偽
(??中略)
露比娜,女,高雅,紅長髮,溫柔,劍術,男權
星瑩,女,笨蛋,短髮,開朗,漫畫,規矩

TSV

姓名  性別  特質  外貌  性格  喜好  厭惡
莉莉亞  女  可愛  馬尾  害羞  甜食  孤獨
雅柔  女  學霸  長髮  矜持  鴨子  虛偽
(??中略)
露比娜  女  高雅  紅長髮  溫柔  劍術  男權
星瑩  女  笨蛋  短髮  開朗  漫畫  規矩

Markdown表格

|姓名|性別|特質|外貌|性格|喜好|厭惡|
|---|---|---|---|---|---|---|
|莉莉亞|女|可愛|馬尾|害羞|甜食|孤獨|
|雅柔|女|學霸|長髮|矜持|鴨子|虛偽|
(??中略)
|露比娜|女|高雅|紅長髮|溫柔|劍術|男權|
|星瑩|女|笨蛋|短髮|開朗|漫畫|規矩|

建議

  • 中等資料量時節省Token用。
  • 量太大時低成本LLM處理表格的表現都不太好,高成本LLM也有機率出錯。
  • 使用CSV、TSV時,用Markdown的代碼框將之框起來,明確告訴LLM這是什麼格式。例如:
    ```csv
    表格內容
    ```


偽高級語言

  • 適用情境:敘述中「如果」、「否則」、狀況眾多,或者引入變數後容易產生歧義,難以用自然語言表達清楚時。
  • 簡介:使用一些「看起來像高級語言」(實際上不是)的寫法,明確的區分出每個條件的區塊。

範例

假設原文是「如果{{user}}做A,則{{char}}反應1,否則若{{user}}做B,且目前場景正在洗澡,則{{char}}反應2,若{{user}}沒有做A,且{{user}}做B,且目前場景在泡溫泉,則{{char}}反應3,{{user}}沒有做A,且目前場景是洗澡和泡溫泉以外,{{char}}反應4」,這種如同繞口令般的複雜嵌套,不僅浪費許多Tokens,也容易把LLM繞暈,甚至把創作者自己繞暈,可以這樣寫:
if({{user}}正在做 == 'A'){
  {{char}}反應1;
}else if({{user}}正在做 == 'B'){
  if(目前場景 == '洗澡'){
    {{char}}反應2;
  }else if(目前場景 == '泡溫泉'){
    {{char}}反應3;
  }else{
    {{char}}反應4;
  }
}

建議

  • 不用真的嚴格按照程式語言撰寫。也不要使用對格式要求太嚴格的語言,雖然LLM最熟悉的可能是Python,但它也可能因為你格式錯誤而當成無意義的囈語。
  • 建議模仿Javascript的形式,因為它不太嚴格,且它是一種易學易用的語言,最後它或許是LLM除Python外最熟悉的語言。
  • 不要加Markdown代碼框,避免LLM真的把它理解成一種高級語言,而產生奇怪的結果。


偽變數

  • 適用情境:一個詞有多種可能時、讓LLM隨機多選一時、使用相同的輸出格式但替換不同的關鍵詞時。
  • 簡介:自行建立一個偽變數,就像Caveduck內建的{{user}}與{{char}}那樣,但不同的是,Caveduck內建的{{var}}是真的會被程式取代成正確的值,才扔給LLM處理,而我們定義的只是在提示內讓LLM按照它的理解去處理這些字。

範例

原文:
生成以下文字:「{{user}}被派到(隨機選取:中國、韓國、日本、英國)執行任務,任務內容是(隨機選取:建立聯絡網、刺探情報、意識形態宣傳、收買官員)。」

LLM有時只會傻傻的把整句一字不差的輸出,或者因前文有什麼影響它認知的東西,生成牛頭不對馬嘴的內容,但我們使用變數就能避免這種情形:
## 變數
(這裡最好再加一段解釋如何執行的內容)
-
$location$:隨機選取(中國、韓國、日本、英國)
-
$mission$:隨機選取(建立聯絡網、刺探情報、意識形態宣傳、收買官員)

生成以下文字:「{{user}}被派到
$location$執行任務,任務內容是$mission$。」

建議

  • 此類狀況不多時,內容能用自然語言清晰描述時,可能是多此一舉,但如果內容較多,這是個很好的辦法。
  • 你可以用任何方式去標記變數,但盡量不要與自然語言的常見符號衝突。
  • 不是必須,但建議將之前後封閉,例如$var$優於$var,如果是非封閉的變數,必須明確其後面有空格,這在拼音語言中問題不大,但使用表意文字時可能時常會忽略其空格,畢竟表意文字並不依賴空格切分詞彙或語素,另外也無法保證由自動翻譯系統將拼音文字翻譯為表意文字時,會保留那個空格。
  • 不建議和Caveduck使用一樣的方式{{var}},一來是你自己容易弄混。二來是有小道消息稱,他們正在開發一個名為「模板」的功能,屆時可以讓創作者將常用、容易重複的文字設成模板,並自行插入Prompt內,我認為如果此訊息為真,到時使用方式很可能也是{{template}}
  • 條件複雜時可配合偽高級語言使用。

總結

雖然提出了很多方法,但由於LLM的原理,我們很難將它調教得完全理解並遵從,而且隨著提示長度與內容的不同,可能原本好用的方法變得沒什麼效果,任何方法都需要創作者自己長時間的嘗試才能找到最優解,難以千篇一律的生搬硬套。

手冊

Markdown


XML


JSON


  • LLM(Large Language Model):大型語言模型,像是OpenAI的GPT等,能基於大量文字資料進行自然語言處理或生成。例如在Caveduck中,與AI角色的所有互動都是透過LLM完成。LLM擅長理解與生成類似人類語言的文字,但需要精確的提示(Prompt)來達成理想效果。
  • 提示詞(Prompt):創作者提供給LLM的文字輸入,用於引導模型生成回應。Prompt的設計對生成結果影響甚大。清晰、簡潔的Prompt能提高模型理解意圖的準確性,冗長或含糊的提示則可能導致回應偏離預期。
  • Token:Token是LLM處理文字的最小單位,可包括單詞、標點符號或部分單詞。在Caveduck中,每次互動都會消耗Token,包括使用者輸入的內容、角色的Prompt,和角色產生的回應。每個LLM的Token處理上限不同,但Caveduck未公開具體的上限數字,大致可透過消耗的點數推測。過多的Token可能導致內容被截斷,因此設計Prompt時需要優化長度與信息密度,確保最重要的部分能完整被處理。希望未來Caveduck能公佈詳細Token上限資訊,方便創作者更有效率地設計提示詞。
  • YAML(Yet Another Markup Language):一種簡潔的資料表示語言,類似JSON,但更容易讀寫。適合用於簡單結構化資料,常見於設定檔中。
  • 層次結構(Hierarchy):指資訊的組織方式。透過明確的層級標示(例如以嵌套結構呈現內容),能幫助LLM更有效地理解並解析指令或內容。

追蹤 創作集

作者相關創作

相關創作

更多創作