LangChain框架入門07:AI應用監控神器LangSmith
在上一篇文章中,我們介紹了LCEL表達式和Runnable組件,通過LCEL表達式可以很輕松的構建復雜的AI應用,LCEL將多個可運行組件串聯起來,在執行LCEL表達式時出現了錯誤,如何判斷是哪個組件出現了錯誤?又如何獲取出現錯誤的上下文呢?
本文將會詳細介紹使用LangChain提供的Callback回調機制,如何對LLM應用以及LCEL執行的各個關鍵節點進行監控,最后,還會介紹LangChain推出的一款在開發階段的調試監控神器LangSmith,只需要簡單的配置就可以和LangChain構建的應用進行無縫集成,自動監控整個項目的生命周期,將監控的結果自動上傳到LangSmith平臺,使項目監控變得非常簡單。
一、什么是LangSmith
LangSmith 是一個由LangChain推出,用于構建LLM應用的監控平臺,如下圖所示,LangSmith的功能主要包括以下三個方面:
可觀測性:LangSmith可以進行數據的分析和追蹤,并提供了儀表盤、告警等功能。
可評估:可以對應用運行情況進行評估,分析其性能表現。
提示詞工程:支持對提示詞進行管理,并且提供提示詞版本控制功能

LangSmith由LangChain提供,無需本地部署,LangSmith地址如下:
登錄后界面

二、LangSmith使用
首先點擊Tracing Projects

系統中默認存在一個項目,點擊New Project創建新項目

LangSmith支持LangChain項目和非LangChain項目,并且分別提供了將LangSmith接入到應用的方法,點擊Generate API Key,生成API Key

復制保存好API KEY,并修改項目名為langchain-study,下方的配置也會自動變成對應項目名稱

復制上方配置,放到項目中的.env文件中
# LangSmith配置
LANGSMITH_TRACING="true"
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="lsv2_pt_***************************"
LANGSMITH_PROJECT="langchain-study"
通過一個最簡單的示例進行測試:
import dotenv
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
# 讀取env配置
dotenv.load_dotenv()
# 1.創建提示詞模板
prompt = ChatPromptTemplate.from_template("{question}")
# 2.構建GPT-3.5模型
llm = ChatOpenAI(model="gpt-3.5-turbo")
# 3.創建輸出解析器
parser = StrOutputParser()
# 4.執行鏈
chain = prompt | llm | parser
print(chain.invoke({"question": "請以表格的形式返回三國演義實力最強的十個人,并進行簡要介紹"}))
執行完成之后,在Tracing Projects頁面就可以看到langchain-study項目被成功創建

點擊進入項目,就可以看到剛剛那一次的調用過程,包括輸入、輸出、發起時間、總耗時等信息

點擊All Runs可以查看各個組件的執行過程,包括Prompt生成、LLM響應、輸出解析器處理等各環節的詳細執行信息

點擊任意組件,如ChatPromptTemplate,就會將組件的輸入和輸出結果進行展示

下拉選擇,選擇Raw Input就可以展示原始的輸入,輸出部分也可以以相同方式查看原始信息

支持 JSON 與 YAML 格式展示,其中 JSON 更便于觀察,如下圖可以清晰的觀察到ChatPromptTemplate組件的原始輸入輸出信息

下面我們將程序改成不存在的模型gpt-3.6-turbo,重新執行程序,來模擬出現錯誤的情況。
llm = ChatOpenAI(model="gpt-3.6-turbo")
在LangSmith中,可以看到執行記錄和錯誤原因

也可以詳細查看錯誤詳細原因

三、什么是Callback機制
除了使用LangSmith之外,LangChain還提供了一種回調機制,可以在 LLM 應用程序的各種階段執行特定的鉤子方法。通過這些鉤子方法,我們可以輕松地進行日志輸出、異常監控等任務,Callback支持以下事件的鉤子方法:
| Event 事件 | 觸發時機 | 關聯鉤子方法 |
|---|---|---|
| Chat model start | 聊天模型啟動 | on_chat_model_start |
| LLM start LLM | LLM模型啟動 | on_llm_start |
| LLM new token LLM | LLM生成新的 token 時觸發,僅在啟用流式輸出(streaming)模式下生效 | on_llm_new_token |
| LLM ends | LLM 或聊天模型完成運行時 | on_llm_end |
| LLM errors | LLM 或聊天模型出錯 | on_llm_error |
| Chain start | 鏈開始執行(實際上就是每個可運行組件開始執行) | on_chain_start |
| Chain end | 鏈結束執行(實際上就是每個可運行組件結束執行) | on_chain_end |
| Chain error | 鏈執行出錯 | on_chain_error |
| Tool start | 工具開始執行 | on_tool_start |
| Tool end | 工具結束執行 | on_tool_end |
| Tool error | 工具執行出錯 | on_tool_error |
| Agent action | agent開始執行 | on_agent_action |
| Agent finish | agent結束執行 | on_agent_finish |
| Retriever start | 檢索器開始執行 | on_retriever_start |
| Retriever end | 檢索器結束執行 | on_retriever_end |
| Retriever error | 檢索器執行出錯 | on_retriever_error |
| Text | 每次模型輸出一段文本時,就會調用這個方法 | on_text |
| Retry | 當某個組件(比如 LLM 調用或鏈)發生失敗并觸發重試機制時 | on_retry |
四、如何使用Callback機制
首先,使用Callback機制,需要使用到Callback handler,即回調處理器,那些各個生命周期的鉤子方法,就定義在回調處理器中,回調處理器支持同步和異步,同步回調處理器繼承BaseCallbackHandler類,異步回調處理器繼承AsyncCallbackHandler類。
如下圖在PyCharm中,定義類繼承BaseCallbackHandler類,使用ctrl+o快捷鍵,就會出現這些可以重寫的鉤子方法。

那么,如何使自定義的CallbackHandler生效呢?可以在調用可執行組件的invoke()方法中,除了傳遞輸入參數外,再傳遞config配置參數,config配置參數可以傳遞各種配置信息,其中,callbacks屬性用來傳遞回調處理器,callbacks屬性接收一個數組,數組里面包含自定義的CallbackHandler對象,代碼示例如下:
from typing import Dict, Any, Optional, List
from uuid import UUID
import dotenv
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.messages import BaseMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.outputs import LLMResult
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
dotenv.load_dotenv()
class CustomCallbackHandler(BaseCallbackHandler):
"""自定義回調處理類"""
def on_chat_model_start(self, serialized: Dict[str, Any], messages: List[List[BaseMessage]], *, run_id: UUID,
parent_run_id: Optional[UUID] = None, tags: Optional[List[str]] = None,
metadata: Optional[Dict[str, Any]] = None, **kwargs: Any) -> Any:
print("======聊天模型結束執行======")
def on_llm_end(self, response: LLMResult, *, run_id: UUID, parent_run_id: Optional[UUID] = None,
**kwargs: Any) -> Any:
print("======聊天模型結束執行======")
def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], *, run_id: UUID,
parent_run_id: Optional[UUID] = None, tags: Optional[List[str]] = None,
metadata: Optional[Dict[str, Any]] = None, **kwargs: Any) -> Any:
print(f"開始執行當前組件{kwargs['name']},run_id: {run_id}, 入參:{inputs}")
def on_chain_end(self, outputs: Dict[str, Any], *, run_id: UUID, parent_run_id: Optional[UUID] = None,
**kwargs: Any) -> Any:
print(f"結束執行當前組件,run_id: {run_id}, 執行結果:{outputs}, {kwargs}")
# 1.創建提示詞模板
prompt = ChatPromptTemplate.from_template("{question}")
# 2.構建GPT-3.5模型
llm = ChatOpenAI(model="gpt-3.5-turbo")
# 3.創建輸出解析器
parser = StrOutputParser()
# 4.執行鏈
chain = prompt | llm | parser
chain.invoke({"question": "請輸出靜夜思的原文"},
{"callbacks": [CustomCallbackHandler()]})
在示例中,創建了一個CustomCallbackHandler類,繼承了BaseCallbackHandler,分別重寫了on_chain_start、on_llm_end、on_chain_start、on_chain_end,在聊天模型開始執行和結束執行進行了信息輸出,在on_chain_start、on_chain_end打印了當前鏈執行的組件名稱、運行id、輸入參數、輸出結果。
執行結果如下,通過輸出結果可以清晰地看到每一個組件的輸入和輸出結果,以及LLM何時開始執行、結束執行,若需監控異常情況,可重寫 on_chain_error 方法。
開始執行當前組件RunnableSequence,run_id: 6eaf8cba-87d8-4e8f-8ec3-ea67a2b2cc6c, 入參:{'question': '請輸出靜夜思的原文'}
開始執行當前組件ChatPromptTemplate,run_id: 5f452385-74e3-40bf-a7b7-2dcbb921b801, 入參:{'question': '請輸出靜夜思的原文'}
結束執行當前組件,run_id: 5f452385-74e3-40bf-a7b7-2dcbb921b801, 執行結果:messages=[HumanMessage(content='請輸出靜夜思的原文')], {'tags': ['seq:step:1']}
======聊天模型結束執行======
======聊天模型結束執行======
開始執行當前組件StrOutputParser,run_id: 7c1043c0-aa7c-4969-9822-f8464b312922, 入參:content='《靜夜思》是唐代詩人李白創作的一首詩,原文如下:\n\n**靜夜思**\n\n床前明月光, \n疑是地上霜。 \n舉頭望明月, \n低頭思故鄉。' response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 17, 'total_tokens': 93, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-80f91d8a-c8d0-47c5-8255-806272bdbfcf-0' usage_metadata={'input_tokens': 17, 'output_tokens': 76, 'total_tokens': 93}
結束執行當前組件,run_id: 7c1043c0-aa7c-4969-9822-f8464b312922, 執行結果:《靜夜思》是唐代詩人李白創作的一首詩,原文如下:
**靜夜思**
床前明月光,
疑是地上霜。
舉頭望明月,
低頭思故鄉。, {'tags': ['seq:step:3']}
結束執行當前組件,run_id: 6eaf8cba-87d8-4e8f-8ec3-ea67a2b2cc6c, 執行結果:《靜夜思》是唐代詩人李白創作的一首詩,原文如下:
**靜夜思**
床前明月光,
疑是地上霜。
舉頭望明月,
低頭思故鄉。, {'tags': []}
五、總結
本文介紹了什么是LangSmith,以及如何創建LangSmith應用、無縫集成到LangChain當中,通過LangSmith可以清晰的監控到AI應用每一步的執行過程,包括執行時間、原始輸入輸出、花費金額、使用token數等詳細信息。
隨后我們還介紹了LangChain提供的Callback機制,利用BaseCallbackHandler提供的鉤子方法,可以輕松地監控各個關鍵執行流程,有讀者可能會疑惑:既然有了 LangSmith,為何還需要 Callback 機制?在實際開發中,LangSmith 更適合在開發調試階段使用,而在生產環境下,出于數據隱私和安全考量,我們通常不會將敏感數據上傳到LangSmith平臺。這時,Callback 機制就能將執行信息接入到本地或自定義的監控系統,實現同樣的可觀測性。
相信通過本文你已經掌握如何對AI應用進行監控,后續將繼續深入介紹LangChain的核心模塊和高級用法,敬請期待。

浙公網安備 33010602011771號