記錄一次Langgraph流式返回的問(wèn)題處理過(guò)程——以及智能體debug的心得體會(huì) 原創(chuàng)
“ 智能體debug最好的方式就是一個(gè)功能點(diǎn)一個(gè)功能點(diǎn)的測(cè)試;原因在于智能體不可控因素太多,會(huì)導(dǎo)致排查問(wèn)題異常困難。”
最近在做智能體的過(guò)程中遇到了一個(gè)問(wèn)題,就是流式返回的問(wèn)題;剛開(kāi)始為了方便,使用的是langgraph提供的create_react_agent接口;但使用過(guò)這個(gè)接口的人應(yīng)該都知道,它提供的流式接口是一個(gè)偽流式或者說(shuō)根本不是流式輸出,因它的(a)stream流式方法中調(diào)用的是(a)invoke接口。
因此,后來(lái)還是選擇使用自定義智能體的方式,使用StateGraph創(chuàng)建智能體。
def create_graph(self):
"""自定義智能體"""
graph_builder = StateGraph(MessagesState)
graph_builder.add_node("chatbot", self.chat_model)
graph_builder.add_node("tools", self.tool_node)
graph_builder.add_edge(START, "chatbot")
graph_builder.add_conditional_edges("chatbot",tools_condition)
graph_builder.add_edge("tools", "chatbot")
return graph_builder.compile()
智能體流式返回問(wèn)題
從用戶體驗(yàn)的角度出發(fā),大家都知道大模型有流式返回的功能;但基于大模型的流式返回相對(duì)比較簡(jiǎn)單,當(dāng)把大模型與工具相結(jié)合做成Agent智能體時(shí),其復(fù)雜度就直線上升,出問(wèn)題的概率也比較大。
智能體是大模型和工具的集合體,由于工具的存在就導(dǎo)致大模型的流式返回處理起來(lái)比較復(fù)雜;比如說(shuō)調(diào)用工具時(shí),必須要等到工具響應(yīng)之后才能進(jìn)行下一步,否則大模型無(wú)法獲取工具的執(zhí)行結(jié)果,那么調(diào)用工具就沒(méi)了意義。
再有Langgraph為了解決節(jié)點(diǎn)調(diào)用過(guò)程中的數(shù)據(jù)通訊問(wèn)題,使用了狀態(tài)圖(State)的方式進(jìn)行數(shù)據(jù)傳輸;這樣下層節(jié)點(diǎn)只能等上層節(jié)點(diǎn)執(zhí)行完畢之后,才能從狀態(tài)圖中獲取上層節(jié)點(diǎn)的執(zhí)行結(jié)果;備注: 工具節(jié)點(diǎn)也是節(jié)點(diǎn)。
所以,這時(shí)影響智能體進(jìn)行流式輸出的因素就比較多了;可能是模型節(jié)點(diǎn)問(wèn)題,工具節(jié)點(diǎn)問(wèn)題,代碼bug問(wèn)題,工具包的版本問(wèn)題,甚至是模型本身問(wèn)題和模型的部署問(wèn)題等等。
而作者這次遇到流式返回的問(wèn)題,就是在模型的部署問(wèn)題上;在智能體的測(cè)試過(guò)程中,一直都是一次性返回;剛開(kāi)始一直以為是代碼寫的有bug導(dǎo)致無(wú)法流式返回,然后把代碼改了又改,最后找到那些能正常流式返回的智能體代碼,拿過(guò)來(lái)跑還是無(wú)法進(jìn)行流式返回。
等發(fā)現(xiàn)這個(gè)問(wèn)題又開(kāi)始懷疑是不是環(huán)境問(wèn)題,然后把兩個(gè)環(huán)境的工具版本對(duì)照了一下,然后版本確實(shí)不太一樣;但等把版本更新成統(tǒng)一版本時(shí),還是無(wú)法流式返回。
智能體的流式返回有多種模式,不同的模式適合不同的業(yè)務(wù)場(chǎng)景。
這時(shí)才開(kāi)始懷疑是不是模型的原因,但在測(cè)試智能體的過(guò)程中,也試過(guò)直接調(diào)用模型,但可以進(jìn)行正常的流式返回;所以剛開(kāi)始并沒(méi)有懷疑模型的問(wèn)題。
而最后經(jīng)過(guò)替換第三方模型,發(fā)現(xiàn)確實(shí)是模型的問(wèn)題;而這時(shí)又需要考慮是模型本身還是部署的原因;因?yàn)槲覀兡P筒渴鹗褂昧薾ginx做了反向代理,并且使用的是ollama部署的。
然后經(jīng)過(guò)一通測(cè)試,發(fā)現(xiàn)是ollama的版本問(wèn)題導(dǎo)致無(wú)法正常流式輸出。
經(jīng)過(guò)這次問(wèn)題,也發(fā)現(xiàn)了一個(gè)debug的方法;在智能體開(kāi)發(fā)中,由于智能體本身的復(fù)雜性,其涉及的環(huán)節(jié)比較多,再加上大模型本身的不穩(wěn)定性;就導(dǎo)致其問(wèn)題排查過(guò)程非常困難。
因此,在智能體開(kāi)發(fā)中比較好的debug方式就是,一個(gè)問(wèn)題一個(gè)問(wèn)題,一個(gè)節(jié)點(diǎn)一個(gè)節(jié)點(diǎn)的排查;比如說(shuō)懷疑工具調(diào)用有問(wèn)題就只測(cè)試工具調(diào)用的功能;把其它無(wú)關(guān)代碼全部注釋掉,如果確認(rèn)這個(gè)環(huán)節(jié)沒(méi)問(wèn)題之后,再測(cè)試其它功能模塊。
在智能體這種長(zhǎng)距離調(diào)用以及復(fù)雜環(huán)境下,最忌諱的就是全流程的debug方法;原因就在于其不穩(wěn)定因素太多,不可控變量也太多;這樣就會(huì)導(dǎo)致你無(wú)法判斷到底是哪個(gè)環(huán)節(jié)出了問(wèn)題。
本文轉(zhuǎn)載自???AI探索時(shí)代?? 作者:DFires
