LangChain初探:為你的AI應用之旅導航

banner.jpg

先來個溫馨的小提醒:

這篇文章雖然較為全面地介紹了 LangChain馒吴,但都是點到為止俭厚,只是讓你了解一下它的皮毛而已,適合小白選手澡刹。

So呻征,如果你是 LangChain 的小白,看完之后還是一頭霧水罢浇,那就請毫不留情地陆赋,狠狠地 .................................... 給我點贊吧 ( ???) ??!有了你的鼓勵己莺,我會再接再厲的奏甫!(? ?_?)?

What?


丹尼爾:蛋兄,剛剛聽到別人在說 LangChain凌受,你知道是啥玩意嗎?

蛋先生:哦思杯,LangChain 啊胜蛉,一個開發(fā)框架

丹尼爾:開發(fā)啥的框架?

蛋先生:一個用于開發(fā)語言模型驅動的應用的框架

丹尼爾:哦色乾,開發(fā)這種應用誊册,不就是寫寫 Prompt 提示語,調調語言模型 API 的事么暖璧?

蛋先生:沒錯案怯。但 LangChain 使得 Prompt 的編寫,API 的調用更加標準化

丹尼爾:就這樣嗎澎办?

蛋先生:當然不止嘲碱,它還有很多很酷的功能

丹尼爾:比如?

蛋先生:它可以連接外部數(shù)據(jù)源局蚀,根據(jù)輸入檢索相關數(shù)據(jù)作為上下文給到語言模型麦锯,使得語言模型可以回答訓練數(shù)據(jù)之外的問題。這是由 LangChain 的 Retrieval 來實現(xiàn)的

丹尼爾:太酷了琅绅,我想到了一個場景扶欣,比如通過它來連接客服的回答話術庫,這樣就可以讓語言模型搖身一變,變成一個專業(yè)的客服了

蛋先生:恩料祠,這是一個很好的場景

丹尼爾:還有其它更酷的功能嗎骆捧?

蛋先生:它可以讓語言模型來自行決定采取哪些行動

丹尼爾:這個就不是很明白了

蛋先生:接著你那個客服的例子繼續(xù)說。如果用戶問的問題是關于公司產(chǎn)品的髓绽,我們就想讓語言模型使用客服的話術庫來回答凑懂;如果是其它問題,就讓語言模型用它自己的知識來直接回答梧宫。如果是你接谨,你會怎么實現(xiàn)?

丹尼爾:我想我會先通過語言模型來判斷用戶的問題是否關于公司產(chǎn)品塘匣。如果是脓豪,就走連接話術庫的邏輯;如果不是忌卤,就走讓語言模型直接回答的邏輯

蛋先生:恩扫夜,你這種就是 hardcode 邏輯的方式。還有一種更加 amazing 的 方式驰徊,就是讓語言模型自行決定采取哪種行為笤闯。這個由 LangChain 的 Agent 來實現(xiàn)。

丹尼爾:聽上去太酷了棍厂,怎么用呢颗味?

蛋先生:莫急,待我慢慢道來

Why?


丹尼爾:蛋兄牺弹,你剛剛說到 LangChain 使得 Prompt 的編寫浦马,API 的調用更加標準化,標準化了肯定是好的张漂,但好處很大嗎晶默?我用語言模型的 SDK 不也用得好好的嗎?

蛋先生:那你先給一個使用 SDK 與語言模型交互的例子唄

丹尼爾:這還不簡單航攒,我就用這個吧:fireworks.ai (注:這個平臺提供免費的資源磺陡,訪問也方便)

from fireworks.client import Fireworks

client = Fireworks(api_key="<FIREWORKS_API_KEY>")
response = client.chat.completions.create(
  model="accounts/fireworks/models/llama-v2-7b-chat",
  messages=[{
    "role": "user",
    "content": "Who are you?",
  }],
)
print(response.choices[0].message.content)
輸出:
Hello! I'm just an AI assistant, here to help you in any way I can. My purpose is to provide helpful and respectful responses, always being safe and socially unbiased. I'm here to assist you in a positive and ethical manner, and I'm happy to help you with any questions or tasks you may have. Is there anything specific you would like me to help you with?

蛋先生:很好,再給另外一個語言模型的例子唄

丹尼爾:額漠畜,一樣的操作啊币他,你這是在消遣我嗎?好吧盆驹,那我就再給一個百度的文心一言的例子

import os
import qianfan

os.environ["QIANFAN_AK"] = "<QIANFAN_AK>"
os.environ["QIANFAN_SK"] = "<QIANFAN_SK>"

chat_comp = qianfan.ChatCompletion()

resp = chat_comp.do(messages=[{
    "role": "user",
    "content": "Who are you?"
}])

print(resp.body['result'])
輸出:
您好圆丹,我是百度研發(fā)的知識增強大語言模型,中文名是文心一言躯喇,英文名是ERNIE Bot辫封。我能夠與人對話互動硝枉,回答問題,協(xié)助創(chuàng)作倦微,高效便捷地幫助人們獲取信息妻味、知識和靈感。

蛋先生:Good欣福,現(xiàn)在假設我一開始使用 fireworks 來開發(fā)應用责球,過程中發(fā)現(xiàn)效果不太理想,想換成文心一言呢拓劝?

丹尼爾:Oh~雏逾,各個語言模型的 SDK 的接口定義是不一樣的,替換起來確實麻煩郑临。來吧栖博,是時候開始你的表演了

蛋先生:我們直接來看下通過 LangChain 使用 fireworks 和 文心一言 的代碼示例吧,畢竟 No Code No BB 嘛

  • fireworks LangChain 示例
import os
from langchain_community.chat_models.fireworks import ChatFireworks

os.environ["FIREWORKS_API_KEY"] = '<FIREWORKS_API_KEY>'
model = ChatFireworks(model="accounts/fireworks/models/llama-v2-13b-chat")

res = model.invoke("Who are you?")
print(res.content)
  • 文心一言 LangChain 示例
import os
from langchain_community.chat_models import QianfanChatEndpoint

os.environ["QIANFAN_AK"] = "<QIANFAN_AK>"
os.environ["QIANFAN_SK"] = "<QIANFAN_SK>"
model = QianfanChatEndpoint(model="ERNIE-Bot-turbo")

res = model.invoke("Who are you?")
print(res.content)

丹尼爾:好像看出來了厢洞,標準化之后仇让,要更換語言模型變得非常方便了,只需要更換下 model 的實例化就行了

蛋先生:是的躺翻,這只是個最簡單的例子丧叽,LangChain 還有很多種優(yōu)雅的方式來切換不同的模型。從此以后我們就可以專注于 Prompt 的開發(fā)了公你。語言模型嘛踊淳,哪個合適換哪個

How?


丹尼爾:好了,我決定入坑 LangChain 了省店,那咱們進一步聊聊嚣崭?

蛋先生:當然可以!我們從簡單到復雜懦傍,結合代碼和流程圖來展示 LangChain 的一些用法。先來最簡單的代替 SDK 的用法芦劣,這個上邊已經(jīng)有提到了

res = model.invoke("tell me a short joke about a cat")
print(res.content)

[圖片上傳失敗...(image-307658-1709280564539)]

丹尼爾:恩粗俱,這個 so easy,一瞄就懂

蛋先生:OK虚吟,那接下來我們來使用 PromptTemplate寸认,通過變量的方式來控制模板里的部分內容

from langchain_core.prompts import ChatPromptTemplate

...

prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
chain = prompt | model
res = chain.invoke({"topic": "a cat"})
print(res.content)

[圖片上傳失敗...(image-ac6583-1709280564539)]

丹尼爾:使用 PromptTemplate 的方式來寫 prompt,確實比字符串的拼接要優(yōu)雅不少

蛋先生:再加個簡單的輸出轉換吧

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

...

prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
output_parser = StrOutputParser()
chain = prompt | model | output_parser
res = chain.invoke({"topic": "a cat"})
print(res)

[圖片上傳失敗...(image-441f77-1709280564539)]

丹尼爾:終于知道為啥叫 chain

蛋先生:繼續(xù)串慰?

丹尼爾:繼續(xù)...

蛋先生:接下來這段代碼可能有點長哦

from langchain_community.embeddings import QianfanEmbeddingsEndpoint
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import faiss
from langchain_community.chat_models import QianfanChatEndpoint

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains.combine_documents import create_stuff_documents_chain

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

# 1
docs = WebBaseLoader("https://docs.smith.langchain.com").load()
embeddings = QianfanEmbeddingsEndpoint()
documents = RecursiveCharacterTextSplitter(chunk_size=900).split_documents(docs)
vector = faiss.FAISS.from_documents(documents, embeddings)
retriever = vector.as_retriever(search_kwargs={'k': 4})

# 2
setup_and_retrieval = RunnableParallel(
    {"context": retriever, "input": RunnablePassthrough()}
)
prompt = ChatPromptTemplate.from_template("""Answer the following question based only on the provided context:
<context>
{context}
</context>
Question: {input}""")
model = QianfanChatEndpoint(streaming=False, model="ERNIE-Bot-turbo")
output_parser = StrOutputParser()

# 3
retrieval_chain = setup_and_retrieval | prompt | model | output_parser

res = retrieval_chain.invoke("how can langsmith help with testing?")
print(res)

丹尼爾:請把“可能”去掉偏塞,謝謝

蛋先生:但邏輯其實并不復雜,主要分為三塊

1)加載網(wǎng)頁文檔邦鲫,通過 Embeddings 將文檔內容轉成向量并存儲在向量數(shù)據(jù)庫 FAISS 中灸叼,retriever 就是一個可以根據(jù)輸入從向量數(shù)據(jù)庫獲取相關文檔的檢索工具

2)聲明 chain 的各個步驟

3)將各個步驟按順序 chain 起來

丹尼爾:等等神汹,看著有點腦殼疼。Embeddings古今?向量屁魏?向量數(shù)據(jù)庫?

蛋先生:咱們今天是“初探”捉腥,所以也只能簡單講講氓拼,不然很多同學就要昏昏欲睡了

丹尼爾:沒問題,有個大概印象也好

蛋先生:首先抵碟,為什么要將文本轉成向量呢桃漾?因為通過計算兩個向量的距離,我們就可以量化地評估它們的相關性拟逮。距離越小撬统,通常意味著文本之間的相關性越高。我們這里是需要檢索與輸入相關的文檔內容唱歧,將其作為會話上下文提供給語言模型宪摧。如果是整個文檔都傳過去,是不是就太大了呢颅崩?

丹尼爾:哦几于,原來向量有這么高級的功能啊

蛋先生:沒錯。然后要將文本轉成向量沿后,就需要用到 Embeddings(詞嵌入)技術沿彭。Embeddings 在歷史上有過多種方法,如基于統(tǒng)計的計數(shù)方法尖滚,基于神經(jīng)網(wǎng)絡的推理方法等喉刘。 QianfanEmbeddingsEndpoint 正是一個利用深度學習訓練得到的 Embeddings 模型服務,輸入為文本漆弄,輸出為向量

丹尼爾:大概有點明白了

蛋先生:那我們接著看下流程圖

[圖片上傳失敗...(image-b6a110-1709280564539)]

丹尼爾:能否為小弟我解釋一下上面這個流程圖的前半部分

蛋先生:當然睦裳!首先輸入是 "how can langsmith help with testing?";接著有個并行的邏輯撼唾,一個是通過 Retriever 根據(jù)輸入檢索相關的文檔內容作為 context 的值廉邑,另一個則是直接 pass 將輸入作為 input 的值;然后就是將數(shù)據(jù)傳給 Prompt 模板倒谷,最終就可以得到傳給語言模型的 PromptValue 了

丹尼爾:Soga

蛋先生:注意蛛蒙,壓軸要登場了哦,現(xiàn)在讓我們來請出大名鼎鼎的 Agent 吧

from langchain import hub
from langchain.agents import AgentExecutor, create_json_chat_agent
from langchain.tools import tool
from langchain_community.chat_models.fireworks import ChatFireworks

@tool
def leng(word: str) -> str:
    """Please use this tool if you want to find the length of the word."""
    return len(word)
@tool
def lower(word: str) -> str:
    """Please use this tool if you need to change the word to lowercase."""
    return f'dx_{word.lower()}'


tools = [leng, lower]
model = ChatFireworks(model="accounts/fireworks/models/llama-v2-70b-chat")
prompt = hub.pull("hwchase17/react-chat-json")

agent = create_json_chat_agent(model, tools, prompt, stop_sequence=False)
agent_executor = AgentExecutor(
    agent=agent, tools=tools, verbose=True, handle_parsing_errors=True, max_iterations=5)
    
res = agent_executor.invoke({"input": "Make this word lowercase: 'Daniel'"})
print(res)

{'input': "Make this word lowercase: 'Daniel'", 'output': "The lowercase version of 'Daniel' is 'dx_daniel'"}

丹尼爾:好耶渤愁,快點講解一下吧

蛋先生:首先我們聲明了兩個工具:一個是 leng(用于求字符串長度)牵祟,一個是 lower(用于將字符串變成小寫)。這里為了證明結果是通過我們的工具來得到結果的抖格,所以特意在 lower 的實現(xiàn)中加了個 dx_ 前綴

丹尼爾:等等诺苹,hub.pull("hwchase17/react-chat-json") 是什么神秘代碼咕晋?

蛋先生:這是 LangChain hub 社區(qū)上共享的用于實現(xiàn) Agent 的眾多 Prompt 中的一個,你可以在這里找到很多有用的 Prompt筝尾。畢竟捡需,語言工程也是一種藝術,也是需要實踐積累的筹淫。

丹尼爾:明白站辉,請繼續(xù)

蛋先生:通過 Agent,語言模型就可以根據(jù)輸入自行判斷應該使用哪個工具了

丹尼爾:哇损姜,這太神奇了饰剥!我對它是怎么自行判斷很感興趣

蛋先生:簡單來說,語言模型可以根據(jù)輸入摧阅,再根據(jù)各個工具的描述汰蓉,來判斷哪個工具更適合,然后將結果輸出為可以讓 LangChain 理解的執(zhí)行指令(比如 JSON)

丹尼爾:太棒了棒卷!現(xiàn)在我對 LangChain 有了一個大致的了解顾孽,希望以后還能跟你繼續(xù)深入探討

蛋先生:機會有滴是,咱們后會有期比规!ヾ( ̄▽ ̄)ByeBye

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末若厚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜒什,更是在濱河造成了極大的恐慌测秸,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灾常,死亡現(xiàn)場離奇詭異霎冯,居然都是意外死亡,警方通過查閱死者的電腦和手機钞瀑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門沈撞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雕什,你說我怎么就攤上這事关串。” “怎么了监徘?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吧碾。 經(jīng)常有香客問我凰盔,道長,這世上最難降的妖魔是什么倦春? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任户敬,我火速辦了婚禮落剪,結果婚禮上,老公的妹妹穿的比我還像新娘尿庐。我一直安慰自己忠怖,他們只是感情好,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布抄瑟。 她就那樣靜靜地躺著凡泣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪皮假。 梳的紋絲不亂的頭發(fā)上鞋拟,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音惹资,去河邊找鬼贺纲。 笑死,一個胖子當著我的面吹牛褪测,可吹牛的內容都是我干的猴誊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侮措,長吁一口氣:“原來是場噩夢啊……” “哼懈叹!你這毒婦竟也來了?” 一聲冷哼從身側響起萝毛,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤项阴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后笆包,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體环揽,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年庵佣,在試婚紗的時候發(fā)現(xiàn)自己被綠了歉胶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡巴粪,死狀恐怖通今,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情肛根,我是刑警寧澤辫塌,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站派哲,受9級特大地震影響臼氨,放射性物質發(fā)生泄漏。R本人自食惡果不足惜芭届,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一储矩、第九天 我趴在偏房一處隱蔽的房頂上張望感耙。 院中可真熱鬧,春花似錦持隧、人聲如沸即硼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽只酥。三九已至,卻和暖如春洁仗,著一層夾襖步出監(jiān)牢的瞬間层皱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工赠潦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叫胖,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓她奥,卻偏偏與公主長得像瓮增,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哩俭,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內容