LangChain 提供了多種工具和框架,協助開發者構建自動化代理,提升開發效率。OpenAI 函式適用於單一工具的簡單任務,例如資料提取;ReAct 則適合需要多工具協作和迭代思考的複雜任務。LangChain 的代理工具包整合了多種工具和連結,方便快速自動化任務,例如 CSV 代理能處理 CSV 檔案,而 SQL 代理則能與 SQL 資料函式庫互動。

開發者可以根據任務需求選擇合適的代理型別,例如 Zero-Shot ReAct 或 OpenAI 函式。理解不同代理型別的特性,例如平行函式呼叫或順序工具執行,有助於選擇最佳方案。此外,LangChain 也支援自定義代理,允許開發者設定字首、字尾、最大迭代次數等引數,更精細地控制代理行為。設定提示範本時,可以加入系統訊息、使用者訊息和訊息佔位符,方便代理儲存中間步驟。

在建立自定義代理時,需要將工具繫結到語言模型,並設定代理鏈,包括輸入、代理記憶體和 LLM 輸出解析。LangChain 提供了多種記憶體管理機制,例如短期記憶體和長期記憶體,可以儲存對話歷史、避免重複查詢,並提供上下文資訊。開發者可以根據應用需求選擇合適的記憶體管理策略,例如使用向量資料函式庫或自定義檢索函式。

自動化代理與工具

在開發自動化代理時,選擇合適的工具和框架至關重要。OpenAI 函式和 ReAct 是兩種不同的方法,適用於不同的任務和需求。

OpenAI 函式

OpenAI 函式適合於需要單一工具執行的任務,例如簡單搜尋或資料提取。它們易於實作,可以與對話代理整合,並支援平行函式呼叫,以在同一個 API 請求中呼叫多個函式。

ReAct

ReAct 則適合於需要多個工具執行和更深入的前一步驟檢查的任務。它可以生成多個思考迴圈,以達到更高層次的目標,並支援多重意圖處理和順序工具執行。ReAct 的使用案例包括需要檢查前一步驟結果並根據結果選擇下一步驟的任務。

工具包比較

以下是 OpenAI 函式和 ReAct 的功能比較:

功能 OpenAI 函式 ReAct
執行時決策
單一工具執行
易於實作 ×
平行函式呼叫 ×
迭代思考過程 ×
多重意圖處理
順序工具執行 ×
可自定義提示

指導方向

在與不同 AI 框架互動時,瞭解每個框架的優勢和權衡是非常重要的。每個框架都會為您的 LLM 提供唯一的指導方向。

代理工具包

代理工具包是 LangChain 的一個整合,提供多個工具和連結,以便您快速自動化任務。一些流行的代理工具包包括:

  • CSV 代理
  • Gmail 工具包
  • OpenAI 代理
  • Python 代理
  • JSON 代理
  • Pandas DataFrame 代理

CSV 代理

CSV 代理使用 Pandas DataFrame 代理和 python_repl_ast 工具來調查.csv 檔案。您可以要求它量化資料、識別欄位名稱或建立相關矩陣。

實作 CSV 代理

要建立一個 CSV 代理,您需要在 content/chapter_6 目錄中建立一個新的 Jupyter Notebook 或 Python 檔案。然後,您需要匯入 create_csv_agent、ChatOpenAI 和 AgentType。create_csv_agent 函式需要一個 LLM、資料集檔案路徑和代理型別。

# 匯入相關套件:
from langchain.agents.agent_types import AgentType
from langchain_experimental.agents.agent_toolkits import create_csv_agent
from langchain_openai.chat_models import ChatOpenAI

內容解密:

上述程式碼匯入了必要的套件,包括 AgentType、create_csv_agent 和 ChatOpenAI。create_csv_agent 函式需要一個 LLM、資料集檔案路徑和代理型別,以建立一個 CSV 代理。

圖表翻譯:

  flowchart TD
    A[開始] --> B[匯入套件]
    B --> C[建立 CSV 代理]
    C --> D[調查.csv 檔案]
    D --> E[量化資料]
    E --> F[識別欄位名稱]
    F --> G[建立相關矩陣]

此圖表展示了建立 CSV 代理的流程,從匯入套件到調查.csv 檔案,並進行資料量化、欄位名稱識別和相關矩陣建立。

建立 CSV 代理:深度剖析

在 LangChain 中,建立一個 CSV 代理(agent)是非常簡單的。首先,我們需要匯入必要的模組,包括 create_csv_agent 函式、ChatOpenAI 類別以及 AgentType 列舉。然後,我們可以使用 create_csv_agent 函式建立一個 CSV 代理,傳入必要的引數,例如聊天模型、資料檔案路徑、代理型別等。

from langchain import create_csv_agent
from langchain_openai import ChatOpenAI
from langchain.agents import AgentType

# 建立 CSV 代理
agent = create_csv_agent(
    llm=ChatOpenAI(temperature=0),
    file_path="data/heart_disease_uci.csv",
    verbose=True,
    agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
)

建立代理後,我們可以使用 invoke 方法向代理傳送命令。例如,我們可以詢問代理有多少行資料、資料中的欄位是什麼等。

# 問代理有多少行資料
agent.invoke("How many rows of data are in the file?")

# 問代理資料中的欄位是什麼
agent.invoke("What are the columns within the dataset?")

代理也可以執行更複雜的任務,例如建立相關矩陣並儲存到檔案中。

# 要求代理建立相關矩陣並儲存到檔案中
agent.invoke("Create a correlation matrix for the data and save it to a file.")

除了 CSV 代理外,LangChain 還支援 SQL 資料函式庫代理。使用 SQL 資料函式庫代理,我們可以與 SQL 資料函式庫進行互動,執行 SQL 查詢等。

from langchain.agents import create_sql_agent
from langchain_community.agent_toolkits import SQLDatabaseToolkit
from langchain.sql_database import SQLDatabase

# 建立 SQL 資料函式庫代理
db = SQLDatabase.from_uri("sqlite:///./data/demo.db")
toolkit = SQLDatabaseToolkit(db=db, llm=ChatOpenAI(temperature=0))
agent_executor = create_sql_agent(
    llm=ChatOpenAI(temperature=0),
    toolkit=toolkit,
    verbose=True,
    agent_type=AgentType.OPENAI_FUNCTIONS,
)

使用 SQL 代理,我們可以執行各種 SQL 查詢,例如查詢所有表格、新增使用者等。

# 查詢所有表格
agent_executor.invoke("Identify all of the tables")

# 新增使用者
user_sql = agent_executor.invoke(
    '''Add 5 new users to the database. Their names are:
    John, Mary, Peter, Paul, and Jane.'''
)

自定義標準代理

LangChain 還允許我們自定義標準代理。其中一個重要的功能是設定代理的字首和字尾,這可以幫助我們控制代理的行為。

# 自定義代理的字首和字尾
prefix = "您好,"
suffix = "。"

此外,我們還可以設定代理的最大迭代次數和最大執行時間,以避免代理陷入無窮迴圈。

# 設定代理的最大迭代次數和最大執行時間
max_iterations = 100
max_execution_time = 60  # 秒

建立SQL代理

為了展示如何建立一個SQL代理,我們將使用create_sql_agent函式。這個函式需要多個引數,包括語言模型、SQL工具包、代理型別、回撥管理器、字首、字尾、格式化指令、輸入變數、頂級結果數量、最大迭代次數、最大執行時間、早期停止方法、詳細模式以及代理執行器引數。

建立SQL代理函式

def create_sql_agent(
    llm: BaseLanguageModel,
    toolkit: SQLDatabaseToolkit,
    agent_type: Any | None = None,
    callback_manager: BaseCallbackManager | None = None,
    prefix: str = SQL_PREFIX,
    suffix: str | None = None,
    format_instructions: str | None = None,
    input_variables: List[str] | None = None,
    top_k: int = 10,
    max_iterations: int | None = 15,
    max_execution_time: float | None = None,
    early_stopping_method: str = "force",
    verbose: bool = False,
    agent_executor_kwargs: Dict[str, Any] | None = None,
    extra_tools: Sequence[BaseTool] = (),
    **kwargs: Any
) -> AgentExecutor:

SQL字首

SQL字首是一個字串,定義了代理的行為和互動方式。以下是SQL字首的示例:

SQL_PREFIX = """您是一個設計用於與SQL資料函式庫互動的代理。
給定一個輸入問題,建立一個語法正確的{dialect}查詢,然後檢視查詢結果並傳回答案。

除非使用者指定了一個特定的示例數,否則始終限制您的查詢至最多{top_k}個結果。
您可以按玄貓排序結果。永遠不要查詢特定表格的所有列,只問相關列。
您可以存取用於與資料函式庫互動的工具。只使用以下工具。
只使用由玄貓傳回的資訊。您必須在執行查詢之前雙重檢查您的查詢。
如果您在執行查詢時出現錯誤,請重寫查詢並再試一次。
如果問題似乎與資料函式庫無關,只傳回"I don't know"作為答案。
"""

建立代理執行器

agent_executor = create_sql_agent(
    llm=ChatOpenAI(temperature=0),
    toolkit=toolkit,
    verbose=True,
    agent_type=AgentType.OPENAI_FUNCTIONS,
    prefix=SQL_PREFIX,
)

測試代理

agent_executor.invoke(user_sql)

測試Peter是否在資料函式庫中

agent_executor.invoke("我們是否有一個名為Peter的使用者在資料函式庫中?")

自定義代理

建立自定義代理非常容易。以下是建立一個聊天模型的示例:

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool

# 1. 建立模型
llm = ChatOpenAI(temperature=0)

@tool
def get_word_length(word: str) -> int:
    """傳回單詞的長度"""
    return len(word)

內容解密:

上述程式碼定義了一個名為get_word_length的工具,該工具傳回單詞的長度。這個工具可以用於建立自定義代理。

圖表翻譯:

  flowchart TD
    A[建立模型] --> B[定義工具]
    B --> C[建立代理]
    C --> D[測試代理]

圖表解釋:

上述圖表展示了建立自定義代理的流程。首先,建立一個模型,然後定義工具,接著建立代理,最後測試代理。

建立工具和設定提示

在開始建立自定義代理之前,我們需要準備一些工具和設定提示。首先,我們定義了一個工具列表,其中包含一個函式 get_word_length,用於計算單詞的長度。

tools = [get_word_length]

接下來,我們設定了一個提示範本,包含系統訊息、使用者訊息和一個訊息佔位符,允許代理儲存其中間步驟。

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            """您是一個非常強大的助手,但不知道當前事件和不擅長計算單詞長度。""",
        ),
        ("user", "{input}"),
        # 這是代理將寫入/讀取其訊息的位置
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

將工具繫結到語言模型

在建立代理之前,我們需要將工具直接繫結到大語言模型(LLM)以進行函式呼叫。

from langchain_core.utils.function_calling import convert_to_openai_tool
from langchain.agents.format_scratchpad.openai_tools import (
    format_to_openai_tool_messages,
)

# 將工具轉換為OpenAI工具
llm_with_tools = llm.bind_tools(tools=[convert_to_openai_tool(t) for t in tools])

設定代理鏈

現在,我們設定代理鏈,包括輸入、代理記憶體和LLM的輸出解析。

from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser

agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_tool_messages(
            x["intermediate_steps"]
        ),
    }
    | prompt
    | llm_with_tools
    | OpenAIToolsAgentOutputParser()
)

建立和使用代理執行器

最後,我們建立一個代理執行器,並使用它來執行代理。

from langchain.agents import AgentExecutor

agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executor.invoke({"input": "Software這個單詞有多少個字母?"})

這樣就完成了自定義代理的建立和使用。透過這個例子,我們可以看到如何將工具繫結到語言模型,設定代理鏈,並使用代理執行器來執行代理。

瞭解和使用記憶

在與大語言模型(LLM)互動時,瞭解記憶的角色和重要性至關重要。這不僅僅是關於這些模型如何回憶資訊,也是關於長期記憶(LTM)和短期記憶(STM)之間的戰略互動。

長期記憶

長期記憶就像LLM的圖書館,是一個龐大的、精心企劃的資料集合,儲存從文字到概念框架的所有東西。這個知識函式庫幫助模型理解和生成回應。

應用包括:

  • 向量資料函式庫:這些資料函式庫可以儲存非結構化文字資料,為模型提供生成內容的參考點。透過玄貓,LLM可以迅速透過相似度距離度量檢索相關資訊。
  • 自我反思:高階應用包括LLM自我反思、記錄和儲存想法。想象一個LLM,它仔細觀察使用者在書評平臺上的模式並將其歸類別為深刻見解。隨著時間的推移,它找出偏好,例如最愛的型別和寫作風格。這些見解被儲存和存取,當使用者尋求書籍推薦時,LLM提供了與他們口味相符的定製建議。
  • 自定義檢索器:建立特定的檢索函式可以顯著提高LLM的效率。以人類記憶系統為類別比,這些函式可以根據資料的相關性、自上次記憶以來的時間和其實用性來優先處理資料。

短期記憶

LLM中的短期記憶就像一個臨時工作區。在這裡,最近的互動、活躍任務或正在進行的對話被保持在前沿,以確保連續性和上下文。

應用包括:

  • 對話歷史:對於聊天機器人,跟蹤對話歷史是必不可少的。它允許機器人在多次交換中保持上下文,防止冗餘查詢,確保對話自然流暢。
  • 重複避免:短期記憶在類別似或相同的查詢被提出時證明是無價的。透過玄貓,模型可以提供一致的答案或根據應用的要求多樣化其回應。

記憶在LangChain中的應用

LangChain提供了簡單的技術來向LLM新增記憶。如圖6-3所示,每個鏈中的每個記憶系統都執行兩個基本操作:讀取和儲存。

鏈中的記憶

在鏈中的每個操作中,都有兩個與其記憶的重要互動:

  • 在收集初始使用者資料但在執行之前,鏈從其記憶中檢索資訊,新增到使用者的輸入中。
  • 在鏈完成但在傳回答案之前,鏈將當前執行的輸入和輸出寫入記憶中,以便未來執行時可以參照。

建立記憶系統時,您需要做出兩個關鍵選擇:

  • 儲存狀態的方法
  • 查詢記憶狀態的方法

保留狀態

在底層,生成性AI模型的基礎記憶結構為聊天訊息序列。這些訊息可以儲存在暫時的記憶體列表中或錨定在更持久的資料函式庫中。對於那些傾向於長期儲存的人,有一系列資料函式庫整合可用,可以簡化過程並節省手動整合的麻煩。

查詢狀態

基本的記憶框架可能只會在每次互動中傳遞最新的訊息。設定得更細膩一些可能會從最後一組訊息中提取出一個簡潔的摘要。一個更先進的設定會從對話中辨別出具體實體,並只傳遞關於會話中突出顯示的實體的資料。

不同的應用對記憶查詢有不同的需求。LangChain提供了多種方法來查詢狀態,從簡單地傳遞最新訊息到提取特定實體並傳遞相關資料等。

深入剖析自動化代理的工具與框架後,我們可以看到 OpenAI 函式和 ReAct 提供了截然不同的自動化途徑,各有其優劣。OpenAI 函式簡潔易用,適合單一工具的快速執行,而 ReAct 則擅長處理複雜的多步驟任務,允許迭代思考和多重意圖處理。LangChain 的代理工具包,如 CSV 和 SQL 代理,更進一步簡化了特定資料型別的自動化流程,展現了高度的實用價值。然而,代理的效能也受限於工具本身的能力和 LLM 的理解力。從技術演進角度來看,更智慧的代理設計,例如結合長期和短期記憶管理、更精細的提示工程以及更強大的工具整合,將是未來發展的關鍵。對於追求效率的開發者,建議優先探索 LangChain 提供的預建代理工具包,並根據實際需求逐步整合自定義工具和提示策略,以最大化自動化效益。隨著技術的持續發展,我們預見客製化代理的門檻將顯著降低,進而推動更廣泛的自動化應用場景。