LangChain(四)工具調用的底層原理!給大模型按上雙手吧!(新手向)

背景

經過前面三篇的內容,我想大家對于大模型的構建、Langchain的優勢、Chain的構建有了相當程度的理解(雖然只是最簡單的示例,但是足夠有代表性)。

后續Chain的使用將會更加豐富多彩,您會了解Langchain開發的大模型會有多么逆天的可擴展性。但今天我們先暫緩此部分,我們來講講Langchain里面最最最重要的功能:工具調用!

我們會先從Langchain規定的官方API開始構建,帶著大家跑通一系列工具之后,從底層原理出發,為大家講解大模型是怎么調用工具的(不必擔心,非常淺顯易懂,本欄目始終是新手向的)。

工具說明

在Langchain眼中,所謂的工具都只是函數而已,我們要做的就是把函數寫好,并交給大模型去自主的調用。

Langchain給大模型調用的函數專門設定了一個函數裝飾器: @tool

有關于函數裝飾器,作為新手其實沒必要理解太深刻,只需要理解裝飾器給函數添加了一些功能和變量即可。而這個tool裝飾器僅僅是給函數增加了幾個變量而已,如下:

  • 工具名稱:(tool.name)
  • 該工具是什么的描述(tool.description)
  • 輸入內容的 JSON 格式 (tool.args)
  • 工具的結果是否應直接返回給用戶(tool.return_direct)
@tool
def func(input:int):'''沒用的函數'''return input print(func.name)
# 輸出:funcprint(func.description)
# 輸出:沒用的函數print(func.args)
# 輸出: {'input': {'title': 'Input', 'type': 'int'}}print(func.return_direct)
# 輸出:false

在這個裝飾器中最主要的必須知曉的就是tool.nametool.?description。這個是后續工具調用的基礎。

  • tool.name

若無特殊設定,默認為函數名。作為新手向,該變量就不要去有額外的操作。只需要知道 tool.name == 函數名 即可。(操作更多也不會有額外的效果,還增加理解難度)

  • tool.description

若無特殊設定,默認為函數的文檔字符串(即函數下方的函數說明),有關文檔字符串的內容可以參考下面的博客,簡單清晰。該部分作為小白直接利用該部分特性即可。有更高要求的看客可以查閱有關BaseTool類的相關知識。

Python 文檔字符串(DocStrings)是個啥??-CSDN博客

大模型的工具調用(直接使用API)

在之前的項目中我們編寫了有關基礎大模型的相關內容,開發了第一個問答大模型以及嘗試了LLMchain的相關內容,我們將在此基礎上繼續往前!

LangChain(二)基礎問答大模型,純新手向-CSDN博客

LangChain(三)基礎問答大模型,從LLMchain開始了解chain!純新手向-CSDN博客

其實不看也可以啦,看了理解起來會更快而已……

step1:工具定義!

該部分我們先定義需要的工具,代碼如下。@tool裝飾器說明這是一個工具。工具名稱為“multiply”,工具描述為“Multiply two integers together.”。

from langchain_core.tools import tool@tool
def multiply(first_int: int, second_int: int) -> int:"""Multiply two integers together."""return first_int * second_int

?這部分沒啥難度,其實就是你自己設定一個函數,然后前面加上@tool,函數內部首行用""" """ 定義一下函數功能描述即可。

step2:大模型定義

該部分我們定義大模型,詳細內容可以參考我之前的博客內容哦。使用百度的千帆大模型


import os
from langchain_community.chat_models import QianfanChatEndpoint# 設定百度千帆大模型的AK和SK-去百度千帆官網的控制臺新建一個應用即可
os.environ["QIANFAN_AK"] = "your AK“"
os.environ["QIANFAN_SK"] = "your SK"#創建千帆LLM模型
qianfan_chat = QianfanChatEndpoint(model="ERNIE-3.5-8K",temperature=0.2,timeout=30,
)

這部分依舊沒啥難度,按部就班走即可。?

?step3:工具設定與綁定!

該部分我們進行工具的設定和與大模型進行綁定!

tools = [multiply]
llm_with_tools = qianfan_chat.bind_tools(tools)
tool_map = {tool.name: tool for tool in tools}

該部分必須要好好解釋一下。不然大家初看之下可能會一頭霧水。

tools = [multiply]

????????由于在實際開發過程中,不可能只有一個工具,我們常常會調用多個工具,那么和大模型進行綁定難道要每個工具函數都綁定一次嗎?咋可能對不對。這部分就是把所有需要調用的函數打造成一個列表,列表內保存的是各個函數(不是函數名!函數名是string,函數就是函數,本質上是個對象,這里理解不了跳過即可,我還記得這是個新手向的博客~~~)。

llm_with_tools = qianfan_chat.bind_tools(tools)

? ? ? ? 這一行是把大模型和工具進行一個綁定,構建一個工具選擇模塊(一個 agent)大模型就是通過該模塊進行的工具選擇,具體的原理在下一篇博客會詳細講解,此部分我們先暫緩跳過~。

tool_map = {tool.name: tool for tool in tools}

? ? ? ? 這一行是把函數名稱(string)和函數(對象)作為一個字典保存。

????????key:函數名稱,value:函數

? ? ? ? 這個變量大家先留意一下,現在可能看不出用途,后面就有用了。

step4:實際運行!

接下來我們把后面的代碼一次性和盤托出!?

def call_tools(msg: AIMessage) -> Runnable:"""Simple sequential tool calling helper."""tool_calls = msg.tool_calls.copy()for tool_call in tool_calls:tool_call["output"] = tool_map[tool_call["name"]].invoke(tool_call["args"])return tool_callschain = llm_with_tools | call_toolschain.invoke("What's 25 times 11?"
)

I know,I know,突然信息量就上來了對不對。沒事,我們一個一個來! 我們先跳過call_tools的函數定義,我們先看下面:

  • chain = llm_with_tools | call_tools

????????對于chain還不理解的同學可以先看我之前的博客,鏈接在上面!看了我之前博客的同學想必依舊有疑惑,我們只是使用過LLMchain,怎么就變成這樣了?

????????實際上Langchain確實有很多已經定義好的chain,只需要調用即可,但是在實際開發中,最實用的依舊是自己定義的chain,個性化的定義才能滿足個性化的需求嘛。

????????Langchain官方自然有可以讓我們自己個性化定義chain的方式。該處就是一個典型。

????????該處的chain是如何工作的呢?作為小白我們不需要去理解源碼。從高維去俯瞰它。步驟如下:

  • 用戶輸入給到?llm_with_tools(該部分有大模型)
  • llm_with_tools?獲取用戶輸入和函數名稱與描述,大模型進行處理并返回需要的函數名和對應的輸入變量,記為“AIMessage”(這就是上面call_tools的參數哦~)。
  • call_tools獲取上一個步驟輸出的參數,并幫助大模型調用對應的函數,并返回結果。

llm_with_tools 的實際輸出!

我們運行下面的代碼:

query = "25 * 11 = ?"messages = [HumanMessage(query)]print("messages1 = ", messages)ai_msg = llm_with_tools.invoke(messages)print("ai_msg = ", ai_msg)

可得輸出如下(手動標準格式了下):

messages1 =  [HumanMessage(content='25 * 11 = ?')]
ai_msg =  
content='' 
additional_kwargs={'finish_reason': 'function_call', 'request_id': 'as-y3xqr3j5b5', 'object': 'chat.completion', 'search_info': [], 'function_call': {'name': 'Multiply', 'arguments': '{"a":25,"b":11}'}, 'tool_calls': [{'type': 'function', 'function': {'name': 'Multiply', 'arguments': '{"a":25,"b":11}'}, 'id': '07eeb8f7-56b0-42f0-b828-4c7d4b17c850'}]} 
response_metadata={'token_usage': {'prompt_tokens': 51, 'completion_tokens': 24, 'total_tokens': 75},  'model_name': 'ERNIE-3.5-8K', 'finish_reason': 'function_call', 'id': 'as-y3xqr3j5b5', 'object': 'chat.completion', 'created': 1720421110, 'result': '', 'is_truncated': False, 'need_clear_history': False, 'function_call': {'name': 'Multiply', 'thoughts': '用戶需要進行乘法運算,我可以使用工具Multiply來完成這個任務。', 'arguments': '{"a":25,"b":11}'}, 'usage': {'prompt_tokens': 51, 'completion_tokens': 24, 'total_tokens': 75}}     
id='run-082b9676-4902-4bf6-af1b-545f4a095001-0' 
tool_calls=[{'name': 'Multiply', 'args': {'a': 25, 'b': 11}, 'id': '07eeb8f7-56b0-42f0-b828-4c7d4b17c850'}]

大家先別慌!別著急!重點其實很少~。聽我細細說來。

第一行的 messages1中的HumanMessage,僅僅只是告訴大模型這是用戶發出的信息而已,至少在現在這個階段不是重點,不用管他!

最主要的是下面的ai_msg,有三個重要模塊

  • “additional_kwargs”:額外信息,對新手沒啥用
  • “response_metadata”:正式的響應信息,一堆沒啥用的信息之外,thoughts該字段反映了大模型是如何思考的。并且格式化返回了需要調用的相關函數名稱(string)和函數的參數。
  • “tool_calls”:最重要的信息,單獨提出來單純只是降低層級而已,你可以看到上面幾個字段都有一樣的信息。

總而言之,在本篇工具調用欄目看來,最重要的就是tool_calls字段,其他直接忽略。函數選擇器的詳細原理將會放置下一篇博客詳細講解,本文僅說Langchain的API調用的步驟和思路。畢竟是新手向嘛~

綜上 函數選擇器 的功能輸出正式講解完畢,其實大家只需要知道函數選擇器就是用來選擇函數的,最重要的功能就是輸出的tool_calls字段,其中保存大模型想要調用的函數名稱(string)和對應的參數。

call_tools函數的原理和操作!

以防大家往上翻太煩,再粘貼一次。這個函數的主要作用就是獲取AI想要調用的工具,并幫AI調用該工具。

def call_tools(msg: AIMessage) -> Runnable:"""Simple sequential tool calling helper."""tool_calls = msg.tool_calls.copy()for tool_call in tool_calls:tool_call["output"] = tool_map[tool_call["name"]].invoke(tool_call["args"])return tool_calls

該部分的輸入參數就是上一步函數選擇器的輸出:AImessage(不知道大家有沒有注意到,這和HumanMessage正好是對應關系,其實就是一個是用戶的信息,一個是AI的信息而已,僅僅是對信息做一個標識,其實沒啥用)?

后面的 --> Runnable 請忽略,新手直接跳過即可,想了解可以自行了解。?接下來讓我們分行說明!

  • tool_calls = msg.tool_calls.copy()

????????養成好習慣,直接copy,解耦互不影響,尤其在流式場景下。

  • for tool_call in tool_calls

? ? ? ? 因為AI可能需要調用多個函數,所以對每一個AI想要調用的函數都需要處理。我不知道為什么我要解釋這個……

  • tool_call["output"] = tool_map[tool_call["name"]].invoke(tool_call["args"])

????????最重要的是這一行,不知道大家還記不記得?tool_map?這個變量,在上文提過,截圖如下。這一行我們慢慢來,對于當前需要調用的tool_call,有一個字段“name”保存著需要調用函數的函數名稱。用tool_map訪問該名稱,返回該函數名稱(string)對應的函數(對象)!這下大家終于理解為什么我需要強調這多次了吧~。即:

  • tool_map[tool_call["name"]] == multiply
  • tool_call["args"]?==?{'a': 25, 'b': 11}

這一行 == multiply.invoke({'a': 25, 'b': 11}) ==?multiply('a': 25, 'b': 11) == 275,此時tool_call多了一個字段“output”,value = 275

到此就結束了,我們終于實現了大模型調用工具的基礎操作。大家安心,上面代碼好像很多,好像很復雜,我們最后復習一下,看一下全部的代碼,你會發現沒什么難的其實。

import os
from langchain_community.chat_models import QianfanChatEndpoint
from langchain_core.tools import tool
from langchain_core.messages import AIMessage
from langchain_core.runnables import Runnable# 設定百度千帆大模型的AK和SK
os.environ["QIANFAN_AK"] = " your AK"
os.environ["QIANFAN_SK"] = " your SK"# 定義千帆大模型
qianfan_chat = QianfanChatEndpoint(model="ERNIE-3.5-8K",temperature=0.2,timeout=30,
)# 設定兩個函數,記得描述函數功能,這很重要
@tool
def func1():''' useless function '''return 0@tool
def Multiply(a: int, b: int) -> int:"""Multiplies a and b."""return a * b# 工具集合
tools = [Multiply, func1]
# 工具與大模型綁定,構建函數選擇模塊
llm_with_tools = qianfan_chat.bind_tools(tools)
# 構建一一對應的map
tool_map = {tool.name: tool for tool in tools}# 工具函數執行
def call_tools(msg: AIMessage) -> Runnable:"""Simple sequential tool calling helper."""tool_calls = msg.tool_calls.copy()for tool_call in tool_calls:tool_call["output"] = tool_map[tool_call["name"]].invoke(tool_call["args"])return tool_calls# 構建鏈
chain = llm_with_tools | call_toolsprint(chain.invoke("What's 25 times 11?")[0]["output"])

?輸出:275

總結

有一說一,工具調用會了,世界上還有什么功能實現不了?

但是本篇博客是從API的角度出發為大家構建一個工具調用的操作,下一篇博客我們將從原理出發,直接手擼工具調用!放寬心,依舊是新手向~

由于小博主依舊是個卑微的打工人,只能上班摸魚的時候寫寫博客,后續的博客將保持一周一篇的頻率~ 敬請期待~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/41847.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/41847.shtml
英文地址,請注明出處:http://en.pswp.cn/web/41847.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

14-31 劍和詩人5 - 使用 AirLLM 和分層推理在單個 4GB GPU 上運行 LLama 3 70B

利用分層推理實現大模型語言(LLM) 大型語言模型 (LLM) 領域最近取得了顯著進展,LLaMa 3 70B 等模型突破了之前認為可能實現的極限。然而,這些模型的龐大規模給其部署和實際使用帶來了巨大挑戰,尤其是在資源受限的設備上,例如內存…

怎么壓縮pdf文件的大小?減小PDF文件大小的四種方法

怎么壓縮pdf文件的大小?文件大小不僅影響傳輸速度,還可能涉及存儲空間的管理。當處理大型PDF文件時,可能會面臨電子郵件附件限制或云存儲容量不足的問題。此外,過大的文件在瀏覽和加載時也會導致延遲,影響閱讀體驗。這…

3款自己電腦就可以運行AI LLM的項目

AnythingLLM、LocalGPT和PrivateGPT都是與大語言模型(LLM)相關的項目,它們允許用戶在本地環境中與文檔進行交互,但它們在實現方式和特點上存在一些差異。AnythingLLM使用Pinecone和ChromaDB來處理矢量嵌入,并使用OpenA…

【C語言】return 關鍵字詳解

在C語言中,return是一個關鍵字,用于從函數中返回值或者結束函數的執行。它是函數的重要組成部分,負責將函數的計算結果返回給調用者,并可以提前終止函數的執行。 主要用途和原理: 返回值給調用者: 當函數執…

mysql數據庫創建用戶并授權某個庫的所有權限

這個就直接上語句吧!只是注意要用管理員帳號執行,比如root去執行。 -- 創建新用戶(替換new_user為您的用戶名,password為您的密碼) CREATE USER new_user% IDENTIFIED BY password; -- 授予權限(替換data…

社交媒體數據分析:賦能企業營銷策略的利器

在這個數字化時代,社交媒體不僅是品牌與消費者互動的舞臺,更是企業洞察市場趨勢、優化營銷策略的金礦。本文將探討如何利用社交媒體數據分析賦能企業營銷,通過實戰案例與技巧分享,揭示這把“利器”如何幫助企業精準定位目標受眾、…

【論文閱讀】-- Visual Traffic Jam Analysis Based on Trajectory Data

基于軌跡數據的可視化交通擁堵分析 摘要1 引言2 相關工作2.1 交通事件檢測2.2 交通可視化2.3 傳播圖可視化 3 概述3.1 設計要求3.2 輸入數據說明3.3 交通擁堵數據模型3.4 工作流程 4 預處理4.1 路網處理4.2 GPS數據清理4.3 地圖匹配4.4 道路速度計算4.5 交通擁堵檢測4.6 傳播圖…

架構面試-場景題-單點登錄(SSO)怎么實現的

文章目錄 概述基于Cookie基于Token(OAuth, JWT)集中式認證服務 (CAS, SAML)分布式Session:輕型目錄訪問協議(LDAP)OAuth 2.0/OIDCKerberos 概述 單點登錄(Single Sign-On,簡稱SSO)是一種身份驗證機制,允許…

掌握【Python異常處理】:打造健壯代碼的現代編程指南

目錄 ?編輯 1. 什么是異常? 知識點 示例 小李的理解 2. 常見的內置異常類型 知識點 示例 小李的理解 3. 異常機制的意義 知識點 示例 小李的理解 4. 如何處理異常 知識點 示例 小李的理解 5. 拋出異常 知識點 示例 小李的理解 6. Python內置…

Springboot整合Jsch-Sftp

背景 開發一個基于jsch的sftp工具類&#xff0c;方便在以后的項目中使用。寫代碼的過程記錄下來&#xff0c;作為備忘錄。。。 Maven依賴 springboot依賴 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-par…

codeforces 1633A

文章目錄 1. 題目鏈接2. 題目代碼正確代碼錯誤代碼 3. 題目總結 1. 題目鏈接 Div. 7 2. 題目代碼 正確代碼 #include<iostream> using namespace std; int main(){int testCase;cin >> testCase;while(testCase --){int ingeter;cin >> ingeter;if(!(inget…

SpringBoot彩蛋之定制啟動畫面

寫在前面 在日常開發中&#xff0c;我們經常會看到各種各樣的啟動畫面。例如以下幾種 ① spring項目啟動畫面 ② mybatisplus啟動畫面 ③若依項目啟動畫面 還有很多各式各樣好看的啟動畫面&#xff0c;那么怎么定制這些啟動畫面呢&#xff1f; 一、小試牛刀 ① 新建一個Spr…

Java 8 到 Java 22 新特性詳解

Java 8 到 Java 22 新特性詳解 Java自發布以來一直在不斷演進&#xff0c;添加新特性以提升開發效率和性能。本文將介紹Java 8到Java 22的主要新特性&#xff0c;幫助開發者了解各版本的新功能和改進。 Java 8 (2014) 1. Lambda 表達式 Lambda 表達式允許使用簡潔的語法定義…

SQL 之 concat_ws和concat的區別

concat_ws和concat都是用于連接字符串的函數&#xff0c;但它們在使用上有一些區別&#xff1a; 一、concat、concat_ws函數格式&#xff1a; concat格式&#xff1a; concat&#xff08;參數1,參數2,…參數n&#xff09;&#xff0c;如果要加’分隔符’直接寫在 各參數中間就…

關于微信支付-商戶平臺:查詢訂單提示“查詢失敗:操作失敗,請稍候重試”的分析

目錄 引子 分析 應對 小結 引子 在開發和實施微信 JSAPI 支付的應用后&#xff0c;我們遇到了一些問題&#xff0c;訂單的狀態更新不正常&#xff0c;當然我們首先需要從自身尋找原因和完善解決問題的辦法和方案。在支付的過程中&#xff0c;客戶會給我們一些反饋&#xf…

Open-Sora1.2環境搭建推理測試

引子 前陣子寫了一篇Open-Sora1.0環境搭建&推理測試&#xff08;Open-Sora1.0環境搭建&推理測試_自己搭建sora服務-CSDN博客&#xff0c;感興趣的童鞋&#xff0c;請移步&#xff09;。Open-Sora1.1發布的時候&#xff0c;撇了一眼新聞。后面一轉頭&#xff0c;忘記這…

ARL聯動AWVS實現自動化漏洞掃描

0x01 前言 很多場景下需要大范圍的掃描漏洞和快速排查互聯網暴露面的漏洞&#xff0c;需要使用這種自動化的手段&#xff0c;常規滲透測試的找互聯網暴露面是&#xff0c;域名>子域名>IP>C段>端口&#xff0c;可以手動收集&#xff0c;也可以借助一些網絡搜索引擎…

css中偽元素 :: before的用法

在CSS中&#xff0c;偽元素 ::before 用于在選定元素的內容前插入內容。它常用于添加圖標、文本或裝飾性的元素&#xff0c;而不需要在HTML中實際添加額外的標簽。 以下是一個示例說明 ::before 的用法&#xff1a; <!DOCTYPE html> <html lang"en"> &…

一文解決Postman請求發送難題

標題&#xff1a;【技術深度解析】一文解決Postman請求發送難題 在API開發和測試過程中&#xff0c;Postman作為一款強大的工具&#xff0c;其重要性不言而喻。然而&#xff0c;開發者們時常會遇到Postman無法發送請求的問題&#xff0c;這無疑會嚴重影響開發進度和測試效率。…

wordpress網站添加一個臨時維護功能

把以下代碼放到functions.php文件中&#xff0c;主要用網站臨時維護或者用于備案。事情做好了&#xff0c;把以下代碼刪除即可&#xff01;&#xff01;&#xff01; 有時遇到一些情況&#xff0c;比如站點需要閉站備案、或者被要求停站等等&#xff0c;我們就可以使用本文的功…