精打細算用好 LLMs :LLM 落地應(yīng)用成本及響應(yīng)延遲優(yōu)化 原創(chuàng) 精華
編者按: LLMs 被視為 AI 領(lǐng)域的一個里程碑式的突破,但要將其應(yīng)用于實際生產(chǎn)環(huán)境,并且還能用對、用好并非易事。模型的使用成本和響應(yīng)延遲是目前將大語言模型(LLMs)應(yīng)用于生產(chǎn)環(huán)境中的核心難題之一。
在本期刊載的這篇文章中,作者從自身項目的實踐經(jīng)驗出發(fā),分享了一系列實用技巧,幫助優(yōu)化 LLM Prompt ,能夠一定程度上降低大模型的使用成本和響應(yīng)延遲。
文章首先解析了導致高成本和高延遲的根源在于輸入輸出 tokens 的數(shù)量,而非任務(wù)本身的復雜度。接下來,作者逐一闡述了包括提示詞拆分、模塊化設(shè)計、與傳統(tǒng)編程技術(shù)結(jié)合使用等多種優(yōu)化策略。這些策略體現(xiàn)了作者對大模型應(yīng)用本質(zhì)的深刻理解,注重發(fā)揮 LLMs 在復雜推理方面的優(yōu)勢,同時將數(shù)學計算、數(shù)據(jù)聚合等工作外包給 SQL/Python 等更高效的工具。
本文貫穿了一種務(wù)實的方法論 ------ 理性看待 LLMs 技術(shù),揚長避短,與其他技術(shù)工具形成合力,而非將其視為解決一切問題的"靈丹妙藥"。這種觀點和方法論對于企業(yè)更好地將 LLMs 技術(shù)應(yīng)用于生產(chǎn)實踐至關(guān)重要。
作者 :Jan Majewski
編譯 :岳揚
image generated by author with GPT-4o
高成本和延遲是將大語言模型應(yīng)用于生產(chǎn)環(huán)境中的主要障礙之一,二者均與提示詞信息的體量(prompt size)緊密相連。
鑒于大語言模型(LLM)展現(xiàn)出極強的廣泛適用性,不少人視其為解決各類問題的靈丹妙藥。通過與諸如檢索增強生成技術(shù)(RAG\\)及 API 調(diào)用等在內(nèi)的工具整合,并配以精細的指導性提示詞,LLM 時常能展現(xiàn)出逼近人類水平的工作能力。
然而,這種無所不包的應(yīng)用策略,其潛在隱患在于可能會導致提示詞的信息量迅速膨脹,直接引發(fā)高昂的使用成本以及較大的響應(yīng)延遲,令 LLMs 在生產(chǎn)環(huán)境的實際部署面臨重重困難。
針對高價值任務(wù)(如代碼優(yōu)化任務(wù))使用 LLMs 時,成本這方面的考量或許會退居其次 ------ 一段平常半小時才能編寫完成的代碼現(xiàn)在等待半分鐘即完成,花費一定的成本尚可接受。但轉(zhuǎn)至 To C 領(lǐng)域,面對成千上萬次的即時對話需求,成本控制與響應(yīng)速度便成為決定項目成敗的關(guān)鍵。
本文將分享為 ??Resider.pl?? 構(gòu)建由 LLM 支持的房地產(chǎn)搜索助手 "Mieszko" 這一過程的心得。本文的重點是:如何跨越從吸引眼球的概念驗證(impressive POC) 到在實操中有效運用 LLMs 的鴻溝。
01 Prompt is all you have
在構(gòu)建 "Mieszko" 時,我非常倚重 LangChain 這一個出色的框架。該框架以一種有序且清晰的方式,將復雜的邏輯或組件抽象化,并配備了高效易用的提示詞模板,僅需寥寥數(shù)行代碼即可實現(xiàn)調(diào)用。
LangChain 的易用性或許會讓我們不經(jīng)意間忘卻一個核心要點:不論我們的解決方案有多么繁瑣,實質(zhì)上所有組件都會匯總成一條長長的文本信息------"指令性提示詞"------傳遞給LLM。接下來將要展示的內(nèi)容是一個概括性的示例說明,用于展示 LLM Agent 在接收指令性提示詞或執(zhí)行任務(wù)前,其輸入提示詞的基本結(jié)構(gòu)和主要組成部分。
使用 LLM Agent 中的指令性提示詞模板時所采用的基本結(jié)構(gòu)
02 是什么影響了使用成本和響應(yīng)延遲?
LLMs(大語言模型)是有史以來構(gòu)建的最復雜的人工智能模型之一,但其響應(yīng)延遲和使用成本主要取決于輸入和輸出處理的 tokens 數(shù)量,而非任務(wù)本身的難度。
撰寫本文時,OpenAI 旗艦模型 GPT-4 Turbo 的定價公式大致如下:
響應(yīng)延遲的相關(guān)計算方法則并不那么直接,但根據(jù) "Mieszko" 的應(yīng)用場景,可簡單歸結(jié)為以下這個公式:
從成本角度看,input tokens 通常是 LLMs 使用成本的"大頭",其價格僅為 output tokens 的三分之一,但對于更復雜的任務(wù),提示詞長度會遠超面向用戶的 output tokens 長度。
然而,延遲主要受 output tokens 影響,處理 output tokens 的時間大約是 input tokens 的 200 倍。
在使用 LLM Agents 時,約 80% 的 tokens 來自 input tokens ,主要是初始的提示詞和 Agents 推理過程中的消耗。這些 input tokens 是使用成本的關(guān)鍵組成部分,但對響應(yīng)時間的影響有限。
03 監(jiān)控和管理 tokens 的消耗
在構(gòu)建任何 LLMs 應(yīng)用程序時,除了初始提示詞模板之外,至少還需要以下組件:
- 記憶庫(每次與 LLMs 的交互(每次調(diào)用)中,都需要包含之前所有的對話消息或歷史上下文。)
- 工具箱(如供 LLMs 調(diào)用的API),及其詳細的指導性提示詞
- 檢索增強生成(RAG)系統(tǒng)及其產(chǎn)生的上下文
從技術(shù)上講,我們可以添加任意數(shù)量的工具,但如果依賴最簡單的 Agent\&Tools 架構(gòu),可能系統(tǒng)的擴展性就會很差。對于每一種可用的工具,都需要在每次調(diào)用 Agents 時發(fā)送諸如 API 文檔之類的詳細說明。
在準備新系統(tǒng)組件時,需要考慮每次調(diào)用增加多少個 tokens 是值得的。 如果使用的是 OpenAI 的模型,可以快速評估新工具或額外的指導性提示詞的"tokens 消耗"情況,方法如下:
- 直接訪問網(wǎng)站:??https://platform.openai.com/tokenizer??
- 如果你更喜歡使用 Python,可以使用 tiktoken 庫,通過以下簡單函數(shù)實現(xiàn):
import tiktoken
def num_tokens_from_string(string: str, model_name: str) -> int:
try:
encoding = tiktoken.encoding_for_model(model_name)
except KeyError as e:
raise KeyError(f"Error: No encoding available for the model '{model_name}'. Please check the model name and try again.")
num_tokens = len(encoding.encode(string))
return num_tokens
04 如何在保持提示詞精簡的同時不犧牲準確性
初次接觸時,大語言模型(LLMs)可能令人感到無所適從,但歸根結(jié)底,重要的是要記住我們打交道的仍是軟件。這意味著我們應(yīng)當事先預料到會出現(xiàn)錯誤,管理和控制軟件系統(tǒng)設(shè)計中的抽象層次和模塊化程度,并尋找更高效的解決方案來處理子任務(wù)。
在開發(fā) Mieszko 的過程中,我發(fā)現(xiàn)以下一些通用技巧特別有用。我將在未來幾周內(nèi)撰寫后續(xù)文章講解其中的大多數(shù)通用技巧,因此,如果你想不錯過這些內(nèi)容,歡迎您在此(??https://medium.com/@janekmajewski/subscribe)?? 訂閱我的個人主頁,以便在文章發(fā)布時接收到通知。
4.1 將大段提示詞拆分成多層然后再調(diào)用
軟件工程的關(guān)鍵原則之一是模塊化和抽象化。試圖用單個提示詞來處理更復雜的問題,就如同編寫難以維護的"意大利面條式"代碼(Spaghetti code)(譯者注:這個比喻來源于意大利面(spaghetti)纏繞不清、難分難解的形象。當一段代碼缺乏清晰的結(jié)構(gòu)、正確的模塊劃分和合理的邏輯順序,而是充斥著大量的嵌套條件語句、無序的跳轉(zhuǎn)、重復的代碼塊時,就被視為"意大利面式代碼"。)一樣低效。
在構(gòu)建 Mieszko 時,性能顯著提升的一個關(guān)鍵點是將提示詞拆分為兩個部分:
- 用于決策的 Agent (Decision Agent):對下一步可以采取的措施以及如何處理提示詞輸出的一般指導原則。
- 用于執(zhí)行任務(wù)的 Agent / 對話型 LLMs 系統(tǒng):含有針對具體步驟(如房源搜索、數(shù)據(jù)比較或房地產(chǎn)知識查詢)的詳細指導性提示詞。
分層決策與執(zhí)行架構(gòu)圖
分層決策和執(zhí)行調(diào)用架構(gòu)圖,圖片由原文作者提供
這種架構(gòu)使得我們能夠在每次調(diào)用時,首先選取需要使用的特定任務(wù)提示詞,而無需隨附沉重的、消耗大量 tokens 的執(zhí)行指令(execution instructions),從而平均減少了超過 60% 的 tokens 使用量。
4.2 務(wù)必監(jiān)控每次調(diào)用時的最終提示詞
LLM 接收到的最終提示詞(final prompt)可能與最初的提示詞模板相去甚遠。通過工具(tools)、記憶庫(memory)、上下文(context)及 Agent 的內(nèi)部推理來豐富提示詞模板這一過程,可能會使提示詞的規(guī)模激增數(shù)千個 tokens 。
此外,LLMs 有時會展現(xiàn)出如洛奇·巴爾博亞(Rocky Balboa)(譯者注:洛奇·巴爾博亞(Rocky Balboa),美國電影《洛奇》系列的主角,業(yè)余拳擊手出身,憑借自身的努力,登上拳壇最高峰。)般的韌性,即使面對存在錯誤和矛盾的提示詞,也能"站起來"給出合理的答案。
通過仔細審查數(shù)十次 LLMs 的調(diào)用,并深入了解大語言模型(LLM)實際上接收到了什么信息,能為關(guān)鍵突破(key breakthroughs)和消除漏洞(bug elimination)提供寶貴洞見。我強烈推薦使用 LangSmith 來進行深入分析。
如果想要尋求最簡便的方案,也可以啟用 LangChain 中的調(diào)試功能,它將為我們提供每次調(diào)用時確切發(fā)送的提示詞,以及大量有用信息,幫助我們更好地監(jiān)控和優(yōu)化提示詞內(nèi)容。
import langchain
langchain.debug=True
4.3 如只需幾行代碼即可處理的事,向 LLMs 提交前請三思
在使用 LLMs 時,最大的誤區(qū)是忘記你仍然可以利用編程來解決問題。 以我為例,一些最大的性能提升,就是通過使用 Python 函數(shù)在 LLMs 調(diào)用的上下游處理一些極為簡單的任務(wù)。
在使用 LangChain 時,這一點尤為有效,我們可以輕松地將 LLMs 的調(diào)用與傳統(tǒng)的 Python 函數(shù)進行鏈式處理。下面是一個簡化的示例,我曾用它來解決一個難題:即便指示 LLMs 保持回答與用戶發(fā)送的消息相同的語言,LLMs 仍默認回復英文。
我們無需借助 LLMs 來檢測目前的對話使用的是什么語言,利用 Google Translate API 或甚至是一個簡單的 Python 庫(如 langdetect ),可以更快、更準確地完成這項任務(wù)。一旦我們確定了輸入語言,就可以明確地將其傳入指導性提示詞中,從而減少在 LLMs 的調(diào)用過程中需要處理的工作量。
from langdetect import detect
prompt = """
Summarize the following message in {language}:
Message: {input}
"""
prompt = ChatPromptTemplate.from_template(prompt)
def detect_language(input_message):
input_message["language"] = detect(input_message["input"])
return input_message
detect_language_step= RunnablePassthrough.assign(input_message=detect_language)
chain_summarize_in_message_language = (
detect_language_step
* RunnablePassthrough.assign(
language=lambda x: x["input_message"]["language"]
)
* prompt
* llm )
4.4 在設(shè)計 Agent 的提示詞時要精打細算,因為它們通常至少會被調(diào)用兩次
集成了工具的 Agent 能夠?qū)?LLMs 的能力提升到新的層次,但同時它們也非常消耗 tokens(計算資源)。 下面的圖表展示了 LLM Agent 針對 query 提供答案的一般邏輯流程。
AI Agent 兩次調(diào)用 LLM,圖片由原文作者提供
如上圖所示,Agent 通常至少需要調(diào)用 LLM 兩次:第一次是為了規(guī)劃如何使用工具,第二次則是解析這些工具的輸出以便給出最終答案。這一特點意味著,我們在設(shè)計提示詞時節(jié)省的每一個 token,實際上都會帶來雙倍的效益。
對于某些較為簡單的任務(wù),采用 Agent 的方式可能是"用牛刀殺雞",而直接使用帶有 Completion 的簡單指導性提示詞(譯者注:模型接收到 instruction prompt 后的內(nèi)容生成過程。)可能就能夠達到相似的結(jié)果,且速度甚至還能快上一倍。以 Mieszko 項目為例,我們決定將大部分任務(wù)從 Multi-Agent 架構(gòu)轉(zhuǎn)變?yōu)榛谔囟ㄈ蝿?wù)的 Agent+Completion 模式。
4.5 將大語言模型和傳統(tǒng)編程工具結(jié)合使用,發(fā)揮各自的優(yōu)勢(Use LLMs for reasoning but calculate and aggregate with SQL or Python)
相較于早期的 GPT-3.5,最新頂尖大語言模型已經(jīng)有了很大的進步,那時它們在處理基礎(chǔ)數(shù)學公式時都還會出錯?,F(xiàn)在,在諸如計算 segment averages (譯者注:在一組數(shù)據(jù)中,將數(shù)據(jù)分成若干個段或區(qū)間,然后計算每個段內(nèi)數(shù)據(jù)的平均值。)任務(wù)上,LLMs 已經(jīng)能夠輕松處理數(shù)百個數(shù)字。
但它們更擅長編寫 Python 或 SQL,無需數(shù)以萬億計的模型參數(shù),就能以 100% 的準確率執(zhí)行復雜的數(shù)學運算。然而,向 LLMs 傳遞大量數(shù)字會消耗大量 tokens ,在最好的情況下,每 3 位數(shù)字都會轉(zhuǎn)換為一個 token ;若數(shù)值龐大,單個數(shù)字就可能占用多個 tokens 。
想要更低成本、更高效率地分析數(shù)學運算,獲得運算結(jié)果,竅門在于如何運用 LLMs 理解問題及手頭數(shù)據(jù),繼而將之轉(zhuǎn)譯為 SQL 或 Python 這類更適合進行數(shù)學分析的編程語言。
實踐中,可將編寫的代碼嵌入一個函數(shù)內(nèi)執(zhí)行,此函數(shù)負責連接數(shù)據(jù)源并僅將最終分析結(jié)果呈現(xiàn)給 LLM,供其直接理解、分析。
05 Summary
希望本文介紹的這些通用技巧,能夠幫助各位讀者更好地了解 LLMs 應(yīng)用中使用成本和響應(yīng)延遲的主要影響因素,以及如何優(yōu)化它們。我希望盡可能多地分享我在開發(fā)基于 LLM 的生產(chǎn)級應(yīng)用中學到的關(guān)鍵經(jīng)驗教訓。在本系列接下來的文章中,我將從更具體、實踐性更強的實踐案例著手:
- 使用 Python guardrails (譯者注:使用 Python 編寫基于規(guī)則的驗證函數(shù)。)提升 LLM 輸出內(nèi)容的可靠性
- 通過模塊化和抽象化(Modularity and Abstraction)增強 LLM Agents
- 利用 LangSmith 了解、監(jiān)控基于 LLMs 的應(yīng)用(預計六月中旬發(fā)布)
最后,特別感謝 Filip Danieluk ,并向 Filip Danieluk 致以崇高的敬意,他是 Mieszko 引擎的 co-creator 。無數(shù)個晝夜的深入討論和結(jié)對編程(pair-programming)催生了本系列文中闡述的內(nèi)容,這些見解既屬于我,也屬于 Filip 。
Thanks for reading!
Jan Majewski
??https://medium.com/@janekmajewski??
Leveraging LLMs to transform Real Estate search. Data Scientist passionate about NLP, geo-analytics and price-benchmarking
END
本文經(jīng)原作者授權(quán),由 Baihai IDP 編譯。如需轉(zhuǎn)載譯文,請聯(lián)系獲取授權(quán)。
原文鏈接:
