構建在大語言模型基礎上的應用通常有兩種,第一種叫做text completion,也就是一問一答的模式,輸入是text,輸出也是text。這種模型下應用並不會記憶之前的問題內容,每一個問題都是最新的。通常用來做知識庫。
還有一種是類似聊天機器人這種對談模式,也叫Chat models。這種模式下輸入是一個Chat Messages的列表。從而可以儲存上下文資訊,讓模型的回覆更加真實。
實際上Chat models的底層還是LLMs,只不過在呼叫方式上有些變化。
什麼是LLMs呢?LLMs是Large Language Models的簡稱,也就是我們常說的大語言模型。
對於langchain來說,它本身並不提供大語言模型,它只是一箇中間的粘合層,提供了統一的介面,方便我們對接底層的各種LLMs模型。
langchain除了可以對接OpenAI之外,還可以對接Cohere, Hugging Face等其他的大語言模型。
比如下面是openAI的使用:
from langchain.llms import OpenAI
llm = OpenAI(openai_api_key="...")
接下來就可以呼叫llm的方法來進行text completion了。
一般來說有兩種方式。第一種方式就是直接輸出:
llm("給我寫首詩")
還有一種方式呼叫他的generate方法:
llm_result = llm.generate(["給我唱首歌", "給我寫首詩"])
這種方式可以傳入一個陣列,用來生成比較複雜的結果。
現在大語言模型可謂是蓬勃發展,一不留神就可能出一個新的大語言模型。
就目前而言,基本的國外主流模型langchain都是支援的。
比如:openai,azure openai,AmazonAPI,Hugging Face Hub等等。數目繁多,功能齊全,你想要的他全都有,你沒想到的他也有。
那麼有小夥伴可能要問題了,langchain支不支援國產的大語言模型呢?
答案是肯定的,但並不是直接的。
如果你發現langchain並沒有你想要的llm,那麼你可以嘗試進行自定義。
langchain為我們提供了一個類叫做LLM,我們只需要繼承這個LLM即可:
class LLM(BaseLLM):
@abstractmethod
def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
) -> str:
"""Run the LLM on the given prompt and input."""
其中,唯一一個必須要實現的方法就是_call,這個方法傳入一個字串和一些可選的stop word,然後返回LLM的輸出即可。
另外還可以實現一個_identifying_params方法,用來輸出自定義LLM的一些引數資訊。
大家可以自行嘗試和接入不同的LLM模型。
很多時候呼叫LLM是需要收費的,如果我們在開發的過程中也要不斷的消耗token肯定是得不償失。
所以langchain為了給我們省錢,提供了一個FakeLLM來使用。
顧名思義,FakeLLM就是可以手動來mock一些LLM的回答,方便測試。
from langchain.llms.fake import FakeListLLM
responses = ["窗前明月光\n低頭鞋兩雙"]
llm = FakeListLLM(responses=responses)
print(llm("給我寫首詩"))
上面的輸出結果如下:
窗前明月光
低頭鞋兩雙
langchain中還有一個和FakeLLM類似的叫做HumanInputLLM。
這個LLM可以列印出給使用者的prompt,並且將使用者的輸入作為輸出返回給使用者,大家可以自行體驗。
除了正常的LLM呼叫之外,langchain還提供了一些LLM的高階用法。
比如非同步呼叫LLM。當然目前只支援OpenAI, PromptLayerOpenAI, ChatOpenAI 和 Anthropic這幾個LLM。其他的對LLM的支援貌似正在開發中。
非同步方法也很簡單,主要是呼叫llm的agenerate方法,比如下面這樣:
async def async_generate(llm):
resp = await llm.agenerate(["Hello, how are you?"])
print(resp.generations[0][0].text)
另外,對於一些重複的請求來說,langchain還提供了快取功能,這樣可以重複的請求就不需要再傳送到LLM去了,給我們節約了時間和金錢,非常好用。
langchain提供的cache也有很多種,比如InMemoryCache,FullLLMCache,SQLAlchemyCache,SQLiteCache和RedisCache等等。
我們以InMemoryCache為例,看看是怎麼使用的:
from langchain.cache import InMemoryCache
langchain.llm_cache = InMemoryCache()
# 第一次沒有使用快取
llm.predict("Tell me a joke")
# 第二次使用了快取
llm.predict("Tell me a joke")
使用起來很簡單,只需要新增一行llm_cache即可。
如果你使用其他的cache,除了建構函式不同之外,其他的都是類似的。
有時候我們設定好了LLM之外,還可以把LLM相關的引數以文字的形式儲存起來。
儲存llm到檔案:
llm.save("llm.json")
載入llm:
llm = load_llm("llm.json")
LLM的速度是一個硬傷,由於返回整個響應的速度太慢了,所以推出了流式響應。只要有response返回,就傳輸給使用者。並不需要等待所有內容都獲得之後再處理。這樣對使用者的體驗是最好的。
目前langchain只支援OpenAI,ChatOpenAI和ChatAnthropic。
要實現這個流式處理, langchain提供了BaseCallbackHandler,我們只需要繼承這個類,實現on_llm_new_token這個方法即可。
當然langchain已經給我們提供了一個實現好的類叫做:StreamingStdOutCallbackHandler。下面是他的實現:
def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
sys.stdout.write(token)
sys.stdout.flush()
使用的時候,只需要在構建llm的是傳入對應的callback即可:
from langchain.llms import OpenAI
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
llm = OpenAI(streaming=True, callbacks=[StreamingStdOutCallbackHandler()], temperature=0)
resp = llm("給我寫首詩")
這個統計token使用數目的功能目前只能在openai使用。
from langchain.llms import OpenAI
from langchain.callbacks import get_openai_callback
llm = OpenAI(model_name="text-davinci-002", n=2, best_of=2)
with get_openai_callback() as cb:
result = llm("T給我寫首詩")
print(cb)
LLM是大語言模型最基礎的模式,chat模式的底層就是基於LLM實現的。後續我們會詳細介紹chat模式,盡請期待。