<output>
<object name="patient_info">
<string name="gender" description="Patient's gender" />
<integer name="age" format="valid-range: 0 100" />
<list
name="symptoms"
description="Symptoms that the patient is currently experiencing. Each symptom should be classified into a separate item in the list.">
<object>
<string name="symptom" description="Symptom that a patient is experiencing"/>
<string
name="affected area"
description="What part of the body the symptom is affecting"
format="valid-choices: {['head', 'neck', 'chest']}"
on-fail-valid-choices="reask"
/>
</object>
</list>
<list name="current_meds" description="Medications the patient is currently taking and their response">
<object>
<string name="medication" description="Name of the medication the patient is taking" />
<string
name="response"
description="How the patient is responding to the medication"
/>
</object>
</list>
</object>
</output>

<prompt>

Given the following doctor's notes about a patient, please extract a dictionary that contains the patient's information.

{{doctors_notes}}

@complete_json_suffix_v2
</prompt>
</rail>

可以看到,guardrails 定義了一套類似 XML 的語言用于結構化輸出,又結合了自然語言的 Prompt。雖然比起常見的模板語言要更加“繁瑣”,但可以包含的內容也可以更加完善。比如可以提供字段的描述信息,檢查規范,一定程度上也能幫助 LLM 更好地理解需求,生成預期的結果。

I was given the following JSON response, which had problems due to incorrect values.

{
"patient_info": {
"symptoms": [
{
"affected area": {
"incorrect_value": "face & hair",
"error_message": "Value face & hair is not in choices ['head', 'neck', 'chest']."
}
},
{
"affected area": {
"incorrect_value": "beard, eyebrows & nares",
"error_message": "Value beard, eyebrows & nares is not in choices ['head', 'neck', 'chest']."
}
}
]
}
}

Help me correct the incorrect values based on the given error messages.

后續 LLM 的返回可以僅針對這部分問題的修正,而不需要再重復生成整個 JSON。生成的新結果會由 guardrails 再自動填寫回原來的位置,非常絲滑。除了 JSON 格式的檢查外,RAIL spec 中還提供了通過腳本檢查的擴展支持,可以用來檢查更加復雜的內容,例如 Python 代碼是否合法,結果中是否有敏感信息,甚至通過 LLM 再來檢查生成的內容是否有害,做結果過濾等。

NeMo-Guardrails

來自 Nvidia 的一個同名項目,其目標相比 guardrails 更有野心,想要確保 LLM 應用整體的可信度,無害性以及數據安全性等,而不僅僅只是輸出的結構化檢查和修復。因此其實現思路上也復雜不少,設計了一種專門的 Colang 語言,來支持更加通用多樣的業務流,而不僅僅是生成 -> 檢查 -> 修復。不過它的設計都是基于對話做的。實際開發應用可能不太合適。

define user ask capabilities
"What can you do?"
"What can you help me with?"
"tell me what you can do"
"tell me about you"
"How can I use your help?"

define flow
user ask capabilities
bot inform capabilities

define bot inform capabilities
"I am an AI assistant which helps answer questions based on a given knowledge base. For this interaction, I can answer question based on the job report published by US Bureau of Labor Statistics."

從代碼可以看出其結合了 Python 和自然語言,方便相似度檢索。

其整體的運作流程如下:

  1. 根據用戶輸入識別用戶意圖。在這一步,系統會將用戶的輸入在 flow 定義的各種用戶回復文本中做相似性查找,也就是上面文件中“What can you do?”這一連串內容。這些檢索到的預設用戶意圖內容,結合其它信息如對話樣例,最近聊天記錄等,形成整體的 Prompt,發給 LLM 來生成回復。最終再從回復中提取用戶意圖。
  2. 根據意圖,判斷下一步操作動作。這一步有兩種做法,一是當前的狀態能夠匹配上預定義的 flow。例如用戶就是提了一個 bot 能力的問題,那么就會匹配上面定義的 user ask capabilities,下一步動作自然就是 bot inform capabilities。如果沒有匹配上,就要由 LLM 自己來決定下一步動作,這時候也會跟生成用戶意圖一樣,對于 flow 定義做一個相似性查找,將相關信息發給 LLM 來做生成。
  3. 生成 bot 回復。如果上一步生成的 bot 回復意圖已經有明確定義了(例如上面的 bot 能力的回復),那么就直接用預定義的回復內容來回復用戶。如果沒有,就跟生成用戶意圖一樣,做意圖的相似性查找,將相關信息給 LLM 來生成回復。注意到很多動態的問題例如 QA 場景,是很難預先定義好回復內容的,這里也支持對接知識庫,同樣是做 vector search 之后,將相關 context 信息發給 LLM 來生成具體回復。

guidance

之前在 guardrails 中的做法是在 Prompt 中給出說明和示范,希望 LLM 能夠遵循指令來輸出。但現實中往往會出現各種問題,例如額外帶了一些其它的文字說明,或者生成的 JSON 格式不正確等,所以需要后續的 ReAsk 來進行修正。LangChain 里也提供了各種 output parser 來幫忙提取回復中的結構化信息部分,但也經常容易運行失敗。

在 guidance 中,也是通過“模板語言”來定義 LLM 的輸出結構,以確保輸出格式的正確性。

# load a model locally (we use LLaMA here)
guidance.llm = guidance.llms.Transformers("your_local_path/llama-7b", device=0)

# we can pre-define valid option sets
valid_weapons = ["sword", "axe", "mace", "spear", "bow", "crossbow"]

# define the prompt
program = guidance("""The following is a character profile for an RPG game in JSON format.
json
{
"description": "{{description}}",
"name": "{{gen 'name'}}",
"age": {{gen 'age' pattern='[0-9]+' stop=','}},
"armor": "{{#select 'armor'}}leather{{or}}chainmail{{or}}plate{{/select}}",
"weapon": "{{select 'weapon' options=valid_weapons}}",
"class": "{{gen 'class'}}",
"mantra": "{{gen 'mantra'}}",
"strength": {{gen 'strength' pattern='[0-9]+' stop=','}},
"items": [{{#geneach 'items' num_iterations=3}}
"{{gen 'this'}}",{{/geneach}}
]
}""")

# execute the prompt
program(description="A quick and nimble fighter.", valid_weapons=valid_weapons)

在之前傳統的做法中,這一整個 JSON 都需要由 LLM 來生成。但是 JSON 的結構是我們預先定義的,例如有哪些字段,開閉的花括號等,其實都不需要 LLM 來生成。優點:

  1. 生成的 JSON 結構是保證合法且可控的,不會出現語法錯誤或者缺失/錯誤字段等。
  2. 通過 LLM 生成的 token 數量減少了,理論上可以提升生成速度。

除了 Prompt 模板,它還提供了:

從項目代碼來看,還是有比較濃的“research 味道”的,可讀性并不好。實際測試結果也比較翻車。

lmql

在 guidance 的基礎上,lmql 這個項目進一步把“Prompt 模板”這個概念推進到了一種新的編程語言。從官網能看到給出的一系列示例。語法結構看起來有點像 SQL,但函數與縮進都是 Python 的風格。

從支持的功能來看,相比 guidance 毫不遜色。例如各種限制條件,代碼調用,各種 caching 加速,工具集成等基本都具備。這個框架的格式化輸出是其次,其各種可控的輸出及語言本身或許更值得關注。

TypeChat

TypeChat 將 Prompt 工程替換為 schema 工程:無需編寫非結構化的自然語言 Prompt 來描述所需輸出的格式,而是編寫 TS 類型定義。TypeChat 可以幫助 LLM 以 JSON 的形式響應,并且響應結果非常合理:例如用戶要求將這句話「我可以要一份藍莓松餅和一杯特級拿鐵咖啡嗎?」轉化成 JSON 格式,TypeChat 響應結果如下:

其本質原理是把 interface 之類的 ts 代碼作為 Prompt 模板。因此它不僅可以對輸出結果進行 ts校驗,甚至能夠輸入注釋描述,不可謂非常方便 js 開發者。不過,近日 typechat 爆火,很多開發者企圖嘗試將 typechat 移植到 Python,筆者認為這是緣木求魚,因為其校驗本身依賴的是 ts。筆者在開發過程中,將 typechat 融合到自己的庫中,效果不錯。但是它本身自帶的 Prompt 和筆者輸入的 Prompt 還是存在沖突,還是需要扣扣源碼。

Langchain

如果你關注了過去幾個月中人工智能的爆炸式發展,那你大概率聽說過 LangChain。簡單來說,LangChain 是一個 Python 和 JavaScript 庫,由 Harrison Chase 開發,用于連接 OpenAI 的 GPT API(后續已擴展到更多模型)以生成人工智能文本。

LangChain 具有特別多的結構化輸出工具。例如使用 yaml 定義 Schema,輸出結構化 JSON。使用 zodSchema 定義 Schema,輸出結構化 JSON。使用 FunctionParameters 定義 Schema,輸出結構化 JSON

但是筆者這里不打算介紹 LangChain。究其原因,是筆者被 LangChain 折磨不堪。明明可以幾行代碼寫清楚的東西,LangChain 可以各種封裝,花了好幾十行才寫出來。更何況,筆者是用 ts 開發,開發時甚至偷不了任何懶,甚至其文檔絲毫不友好。這幾天,《機器之心》發布文章表示放棄 LangChain。要想讓 LangChain 做筆者想讓它做的事,就必須花大力氣破解它,這將造成大量的技術負擔。因為使用人工智能本身就需要花費足夠的腦力。LangChain 是為數不多的在大多數常用情況下都會增加開銷的軟件之一。所以筆者建議非必要,不使用 LangChain。

LLM 對于結構化信息的理解

LLM 的可控性、穩定性、事實性、安全性等問題是推進企業級應用中非常關鍵的問題,上面分享的這些項目都是在這方面做了很多探索,也有很多值得借鑒的地方。總體思路上來說,主要是:

即使我們不直接使用上述的項目做開發,也可以從中學習到很多有用的思路。當然也非常期待這個領域出現更多有意思的想法與研究,以及 Prompt 與編程語言結合能否碰撞出更多的火花。

同時筆者認為自動處理機制、自己設計的編程語言等等內容,隨著時間發展,一定會層出不窮,不斷迭代更新。筆者拋去這些時效性較弱的內容,從描述信息和位置信息兩方面思考 Prompt 模板該如何設計,當然只是淺淺的拋磚引玉一下。

描述信息

到底哪種方式更容易于LLM去理解?我們不談框架的設計,只考慮 Prompt 的設計。上述框架關于這方面有一些參考,例如有些直接拿 JSON 作為 Prompt模板,有些拿 xml 作為 Prompt 模板,有些拿自己設計的語言作為 Prompt,有些拿自然語言作為 Prompt 模板。時至今日,選用哪種最適合LLM去理解格式化的信息,輸出格式化的內容完全沒有蓋棺定論。甚至時至今日,格式化輸出問題還是沒有得到可靠穩定的解決,要不然筆者肯定不會介紹這么多框架實踐了。

筆者認為不管哪種方式,都可以從兩個方面考量:更簡單,更結構。如果想要在開發的時候更簡單,或者在使用時更簡單,選擇 md、yaml 方式描述結構化信息更合適。如果想要更結構化的方式,選擇 JSON、XML、TS,輸出都能更有結構,甚至之后做結構校驗都更方便。

想要 LLM 結構化輸出更加穩定和理想,筆者認為選擇 Prompt 模板時必須考慮每個字段是否有足夠的輔助信息。例如 XML 描述時,每個標簽都有一個描述屬性描述這個標簽時什么意思。

額外引申

筆者之前在開發 LLM 應用時,也曾思考類似的問題。筆者需要將多模態的數據進行結構化的標注,方便 LLM 去理解。但是標注成什么樣卻是一個很大的難題。筆者選擇的是 JSON。但是,關于里面許多內容的標注。筆者在眾多方案中徘徊。在細節處深挖,如何設計一種既簡單,又能表示各種結構復雜關系,還能夠節約 token 的方案及其的難。

位置信息

是否有人注意到 LLM 對于關鍵信息在 Prompt 中的位置會對結果產生影響呢?在設計 Prompt 方面,人們通常建議為語言模型提供詳盡的任務描述和背景信息。近期的一些語言模型有能力輸入較長的上下文,但它究竟能多好地利用更長的上下文?這一點卻相對少有人知。近日,有學者研究發現如果上下文太長,語言模型會更關注其中的前后部分,中間部分卻幾乎被略過不看,導致模型難以找到放在輸入上下文中部的相關信息。下文部分是該論文一些核心內容:

這是由其本身訓練和結構設計有關的,但卻對于我們開發有著莫大的幫助和指導意義。

相比之下,在多文檔問答任務上,查詢感知型上下文化的影響很小。特別指出,當相關信息位于輸入上下文的最開始時,它可以提高性能,但在其他設置中會稍微降低性能。借此,我們可以認為,將重要的信息放在開頭,結尾放置結構化模板,或許是一種優質選擇。

那么如果真的為其提供這么多 token,那會真的有用嗎?這個問題的答案是:由下游任務決定。因為這取決于所添加上下文的邊際價值以及模型有效使用長輸入上下文的能力。所以如果能有效地對檢索文檔排序(讓相關信息與輸入上下文的起始處更近)或對已排序的列表進行截斷處理(必要時返回更少的文檔),那么也許可以提升基于語言模型的閱讀器使用檢索上下文的能力。

參考資料:

https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid=2650885029&idx=4&sn=ac01576a8957b41529dd3c877d262d5e&chksm=84e48fdbb39306cd8979a4fa7f7da14a9428dc28ccc47880d668ef6293b1a8b7b0964569ec36&mpshare=1&scene=23&srcid=0725w9FPsVnOOzkPGPB7lH8h&sharer_sharetime=1690303766527&sharer_shareid=d2396b329b12f49d34967e2b183540dd#rd

https://mp.weixin.qq.com/s/BngY2WgCcpTOlvdyBNJxqA

https://microsoft.github.io/TypeChat/

https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid=2650885029&idx=4&sn=ac01576a8957b41529dd3c877d262d5e&chksm=84e48fdbb39306cd8979a4fa7f7da14a9428dc28ccc47880d668ef6293b1a8b7b0964569ec36&mpshare=1&scene=23&srcid=0725w9FPsVnOOzkPGPB7lH8h&sharer_sharetime=1690303766527&sharer_shareid=d2396b329b12f49d34967e2b183540dd#rd

本文章轉載微信公眾號@HelloTech技術派

上一篇:

全面認識AI Agent,一文讀懂AI智能體的架構指南

下一篇:

不知道,但是可能超有用的 Web API
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費