一、簡介

LangGraph是LangChain、LangServe和LangSmith系列的最新成員,旨在使用LLM構建生成式人工智能應用程序。請記住,所有這些都是獨立的包,必須單獨進行pip安裝。

在深入學習LangGraph之前,需要了解LangChain的兩個主要概念。

1. 鏈:圍繞LLM編寫的程序,用于執行任務,例如自動SQL編寫或NER提取鏈等。請注意,鏈不能用于任何其他任務(甚至不能用于一般用例),如果嘗試這樣做,可能會損壞鏈。鏈中要遵循的步驟是預定義的,不可靈活調整。

2. 代理:鏈的更加靈活版本,代理通常是啟用第三方工具(例如谷歌搜索、YouTube)的LLM,由LLM本身決定下一步如何解決給定的查詢。

現在,當處理現實世界的問題時,一個常見的問題是希望找到介于鏈和代理之間的解決方案。即不像鏈那樣硬編碼,但也不像代理那樣完全由LLM驅動。

二、LangGraph

LangGraph是以LangChain為核心,用于創建工作流程中的循環圖的工具。因此,我們假設以下示例:

你希望在知識庫上搭建一個基于RAG的檢索系統。現在,你希望引入這樣一種情況:如果RAG的輸出未滿足特定質量要求,代理/鏈應該再次檢索數據,但這次是自行更改提示。并且重復此過程,直到達到質量閾值為止。

使用LangGraph可以實現這種循環邏輯。這只是一個示例,使用LangGraph還可以做更多事情。

注:可以將其視為向鏈中引入循環邏輯,使其成為循環鏈。

顧名思義,LangGraph具有一般圖形所具有的所有組件,例如節點、邊等,接下來通過一個示例來了解。

三、使用LangGraph改善RAG

在此示例中,希望將RAG系統在數據庫中的最終輸出減少到不超過30個字符。如果輸出長度大于30個字符,則希望引入循環,使用不同的提示再次嘗試,直到長度小于30個字符為止。這是一個演示目的的基本邏輯。你甚至可以實現復雜的邏輯來改善RAG結果。

我們將創建的圖形如下所示。

此處使用的版本為 langchain===0.0.349, openai===1.3.8, langgraph===0.0.26。

3.1 首先,讓我們導入重要的內容并初始化LLM。這里使用的是OpenAI API,但你也可以使用其他LLM。

from typing import Dict, TypedDict, Optional
from langgraph.graph import StateGraph, END
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI
from langchain.embeddings.openai import OpenAIEmbeddings

llm = OpenAI(openai_api_key='your API')

接下來,我們將定義一個StateGraph。

class GraphState(TypedDict):
question: Optional[str] = None
classification: Optional[str] = None
response: Optional[str] = None
length: Optional[int] = None
greeting: Optional[str] = None

workflow = StateGraph(GraphState)

什么是StateGraph?

StateGraph是任何LangGraph流程的核心,它存儲了在執行工作流程時我們將存儲的各種變量的狀態。在本例中,我們有5個變量,其值在執行圖形時將進行更新,并將與所有邊和節點共享。

3.2 接下來,讓我們從現有向量數據庫中初始化一個RAG檢索鏈。代碼已在以下視頻中進行了解釋。

def retriever_qa_creation():
embeddings = OpenAIEmbeddings()
db = Chroma(embedding_function=embeddings,persist_directory='/database',collection_name='details')
qa = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=db.as_retriever())
return qa

rag_chain = retriever_qa_creation()

3.3 接下來,我們將向該圖形添加節點。

def classify(question):
return llm("classify intent of given input as greeting or not_greeting. Output just the class.Input:{}".format(question)).strip()

def classify_input_node(state):
question = state.get('question', '').strip()
classification = classify(question)
return {"classification": classification}

def handle_greeting_node(state):
return {"greeting": "Hello! How can I help you today?"}

def handle_RAG(state):
question = state.get('question', '').strip()
prompt = question
if state.get("length")<30:
search_result = rag_chain.run(prompt)
else:
search_result = rag_chain.run(prompt+'. Return total count only.')

return {"response": search_result,"length":len(search_result)}

def bye(state):
return{"greeting":"The graph has finished"}

workflow.add_node("classify_input", classify_input_node)
workflow.add_node("handle_greeting", handle_greeting_node)
workflow.add_node("handle_RAG", handle_RAG)
workflow.add_node("bye", bye)

這需要一些解釋。

①讀取任何狀態變量。

②更新任何狀態變量。在這種情況下,每個節點的返回函數都會更新某個或某些狀態變量的狀態/值。

3.4 接下來,我們將添加入口點和邊緣。

workflow.set_entry_point("classify_input")
workflow.add_edge('handle_greeting', END)
workflow.add_edge('bye', END)

在上述的代碼片段中,

3.5 接下來,讓我們添加條件邊界。

def decide_next_node(state):
return "handle_greeting" if state.get('classification') == "greeting" else "handle_RAG"

def check_RAG_length(state):
return "handle_RAG" if state.get("length")>30 else "bye"

workflow.add_conditional_edges(
"classify_input",
decide_next_node,
{
"handle_greeting": "handle_greeting",
"handle_RAG": "handle_RAG"
}
)

workflow.add_conditional_edges(
"handle_RAG",
check_RAG_length,
{
"bye": "bye",
"handle_RAG": "handle_RAG"
}
)

條件邊界可根據條件(例如if-else)在兩個節點之間進行選擇。在創建的兩個條件邊界中:

第一個條件邊界

當遇到classify_input時,根據decide_next_node函數的輸出選擇handle_greetinghandle_RAG

第二個條件邊界

如果遇到handle_RAG,則根據check_RAG_length條件選擇handle_RAGbye

3.6 編譯并調用提示。初始時保持length變量設置為0。

app = workflow.compile()
app.invoke({'question':'Mehul developed which projects?','length':0})
# 輸出
{'question': 'Mehul developed which projects?',
'classification': 'not_greeting',
'response': ' 4',
'length': 2,
'greeting': 'The graph has finished'}

對于上述提示,圖形流程如下所示:

classify_input: 情感將為not_greeting

由于第一個條件邊界,移至handle_RAG

由于length=0,使用第一個提示并檢索答案(總長度將大于30)。

由于第二個條件邊界,再次移至handle_RAG

由于length>30,使用第二個提示符。

由于第二個條件邊界,移至bye

END

如果沒有使用LangGraph:

rag_chain.run("Mehul developed which projects?")

# 輸出
"Mehul developed projects like ABC, XYZ, QWERTY. Not only these, he has major contribution in many other projects as well at OOO organization"

3.7 下一個輸入。

app.invoke({'question':'Hello bot','length':0})

# 輸出
{'question': 'Hello bot',
'classification': 'greeting',
'response': None,
'length': 0,
'greeting': 'Hello! How can I help you today?'}

這里的流程會更簡單。

classify_input: 情感將為greeting

由于第一個條件邊界,移至handle_greeting

END

雖然我在這里應用的條件相當簡單,但通過添加更復雜的條件,這個框架可以很容易地用于改進你的結果。

本文章轉載微信公眾號@Python學研大本營

熱門推薦
一個賬號試用1000+ API
助力AI無縫鏈接物理世界 · 無需多次注冊
3000+提示詞助力AI大模型
和專業工程師共享工作效率翻倍的秘密
熱門推薦
一個賬號試用1000+ API
助力AI無縫鏈接物理世界 · 無需多次注冊
返回頂部
上一篇
解鎖AgenticRAG,使用LangChain和OpenAI進行實踐
下一篇
【AIGC】 一文帶你了解什么是AIGC!(全面詳解)
国内精品久久久久影院日本,日本中文字幕视频,99久久精品99999久久,又粗又大又黄又硬又爽毛片
久久久久久久国产精品影院| 欧美三级乱人伦电影| 欧美一区二区三区视频在线观看 | 中文字幕成人在线观看| 亚洲三级在线免费| 午夜国产精品一区| 欧美天堂一区二区三区| 国产人久久人人人人爽| 中文字幕视频一区| 成人美女在线视频| 日韩av电影免费观看高清完整版| 欧美电视剧免费全集观看| 成人av网站在线| 男人的j进女人的j一区| 亚洲欧美日韩小说| 国产视频不卡一区| 久久婷婷综合激情| 日韩视频国产视频| 欧美成人video| 欧美大片一区二区| 精品国产一区二区三区久久久蜜月 | 亚洲第一av色| 亚洲a一区二区| 日韩精品乱码免费| 一区二区三区在线视频播放| 久久久777精品电影网影网 | 日韩黄色片在线观看| 性感美女极品91精品| 免费国产亚洲视频| 性做久久久久久免费观看欧美| 午夜伦理一区二区| 精品中文字幕一区二区小辣椒| 国产精品69久久久久水密桃| 成人国产精品免费网站| 欧美精品色一区二区三区| 久久综合九色综合欧美就去吻| 国产人久久人人人人爽| 亚洲蜜臀av乱码久久精品| 丝瓜av网站精品一区二区 | 色综合久久综合网欧美综合网 | 国产精品福利一区| 亚洲午夜免费福利视频| 国产一区二区不卡| 日本道免费精品一区二区三区| 欧美写真视频网站| 中文字幕av免费专区久久| 久久久久久久电影| 亚洲一区在线视频| 成人高清免费在线播放| 日韩欧美一级精品久久| 日韩av不卡一区二区| 在线欧美小视频| 最新高清无码专区| 波波电影院一区二区三区| 精品国产凹凸成av人导航| 免费观看30秒视频久久| 欧美精品一二三区| 日本va欧美va欧美va精品| 欧美一卡二卡三卡| 九九国产精品视频| 欧美激情资源网| 欧美怡红院视频| 日本在线不卡视频| 亚洲精品在线网站| 国产不卡免费视频| 亚洲国产综合色| 久久久精品国产免费观看同学| 国产盗摄视频一区二区三区| 综合久久久久综合| 精品国产一区二区在线观看| 高清beeg欧美| 日韩av在线发布| 亚洲视频免费在线观看| 日韩视频一区二区三区| av资源网一区| 六月丁香综合在线视频| 4hu四虎永久在线影院成人| av一区二区不卡| 亚洲不卡av一区二区三区| 欧美午夜精品久久久久久孕妇| 成人一二三区视频| 中文字幕一区二区三区四区不卡| 欧美一区二区视频在线观看2022| 奇米影视7777精品一区二区| 专区另类欧美日韩| 日韩一区在线看| 亚洲日本在线视频观看| 国产精品国产三级国产| 国产精品天天看| 国产精品久久夜| 综合电影一区二区三区 | 亚洲精品高清视频在线观看| 中文字幕不卡在线| 在线电影一区二区三区| 国产成人丝袜美腿| 在线观看一区不卡| 欧美日韩三级一区二区| 欧美久久婷婷综合色| 欧美一级二级在线观看| 26uuu亚洲| 一级做a爱片久久| 国产精品69毛片高清亚洲| 午夜精品免费在线观看| 成人性生交大片免费看中文网站| 秋霞av亚洲一区二区三| 99视频国产精品| 久久新电视剧免费观看| 亚洲欧美综合网| 国产精品一区二区视频| 99久久精品国产观看| 久久丝袜美腿综合| 日韩不卡在线观看日韩不卡视频| 亚洲综合激情网| 成人免费av网站| 久久麻豆一区二区| 美女看a上一区| 欧美男男青年gay1069videost| 久久久99精品久久| 国产精品中文有码| 日韩一区二区三区av| 亚洲高清在线视频| 97精品国产97久久久久久久久久久久| 日韩一级视频免费观看在线| 亚洲国产精品ⅴa在线观看| 成人一区二区在线观看| 日韩欧美一区在线观看| 国产69精品久久久久777| 久久精品亚洲乱码伦伦中文| 成人午夜电影小说| 久久久精品黄色| 国产91对白在线观看九色| 一区二区三区免费在线观看| 色婷婷av一区二区三区大白胸| 一区二区三区四区乱视频| 91精品综合久久久久久| 国产综合成人久久大片91| 中文子幕无线码一区tr| 欧美乱妇20p| 成人av免费网站| 五月婷婷综合激情| 国产精品国产三级国产aⅴ中文 | 麻豆精品一区二区| 国产精品天干天干在观线| 在线不卡中文字幕播放| 成人av资源在线| 蓝色福利精品导航| 中文字幕亚洲综合久久菠萝蜜| 7777精品久久久大香线蕉| 成人精品免费看| 国产自产视频一区二区三区| 奇米影视在线99精品| 精品国产91亚洲一区二区三区婷婷 | 国产精品系列在线观看| 亚洲一区在线电影| 亚洲一区在线观看免费观看电影高清 | 麻豆精品视频在线| 欧美成人官网二区| 欧美久久久久久久久| 91首页免费视频| 三级成人在线视频| 婷婷开心久久网| 婷婷中文字幕综合| 久久综合狠狠综合久久综合88| 欧美国产日韩精品免费观看| 99久久精品国产一区| 色综合色综合色综合色综合色综合| 风流少妇一区二区| 色8久久人人97超碰香蕉987| 色婷婷综合中文久久一本| 欧美日韩国产首页| 国产午夜精品美女毛片视频| 欧美性xxxxx极品少妇| 国产成人精品影院| 欧美日韩激情一区二区| 日韩亚洲欧美在线| 欧美日韩国产另类不卡| 中文字幕在线视频一区| 国产精品电影一区二区三区| 亚洲小少妇裸体bbw| 国产综合久久久久影院| 欧美精品日韩一本| 欧美va亚洲va香蕉在线| 一区二区视频在线| 成人一级视频在线观看| 26uuu亚洲综合色| 美女国产一区二区| 在线观看国产一区二区| 亚洲色图制服诱惑| 日本伊人午夜精品| 97精品超碰一区二区三区| 精品久久一区二区| 美国毛片一区二区三区| 在线成人av网站| 日本不卡一二三区黄网| 欧美一区永久视频免费观看| 奇米四色…亚洲| 久久亚洲一区二区三区四区| 风间由美一区二区三区在线观看 | 国产一区视频在线看| 国产精品系列在线|