LangChain實(shí)戰(zhàn) | Tool Calling :讓AI真正動(dòng)起來(lái)的關(guān)鍵技術(shù)
近年來(lái)大模型發(fā)展過(guò)程中面臨的幾個(gè)核心挑戰(zhàn):靜態(tài)知識(shí)的局限性、執(zhí)行能力的缺失、與外部系統(tǒng)的割裂。為了應(yīng)對(duì)這些挑戰(zhàn),推動(dòng)大模型從單純的語(yǔ)言生成工具演變?yōu)檎嬲娜蝿?wù)執(zhí)行引擎,F(xiàn)unction calling 誕生了,成為大模型一項(xiàng)不可或缺的核心能力。
概念 Function calling 和 Tool Calling 會(huì)混用
我們?cè)谧鰬?yīng)用開(kāi)發(fā)的時(shí)候,大部分時(shí)候盡量避免直接耦合到OpenAI,會(huì)使得程序兼容性不好,這時(shí)只要面向 LangChain 開(kāi)發(fā)就可以了。
LangChain 是一個(gè)靈活的框架,它提供了與多種大模型進(jìn)行交互的能力。
它的設(shè)計(jì)允許集成和使用來(lái)自不同源的多種模型,包括但不限于OpenAl、Cohere和 Hugging Face 等模型庫(kù)中的模型。這樣,你不必拘泥于某種模型,而是為自己的應(yīng)用選擇最合適的模型。對(duì)于Tool Calling能力來(lái)說(shuō),LangChain 也做了抽象。
調(diào)用其他工具的 API(如:Database Tool) 通常需要特定的有效負(fù)載格式。可以使用 Tool Calling 來(lái)向模型請(qǐng)求與特定格式匹配的響應(yīng)。隨后可以使用這個(gè)響應(yīng)作為負(fù)載去做“工具(Tool)實(shí)際的執(zhí)行”。
通俗來(lái)將就是:讓大模型通過(guò)理解用戶的提示詞,來(lái)決定是否需要調(diào)用工具(如上圖),
如果需要調(diào)用工具,會(huì)返回需要調(diào)用的工具名稱和調(diào)用參數(shù)(不是直接執(zhí)行工具),后續(xù)由代碼去執(zhí)行對(duì)應(yīng)的工具(Tool)。
如果不需要調(diào)用工具,那么就直接回復(fù)自然語(yǔ)言(如:How can I assist you?)。
工具(Tool)
tool抽象 在 LangChain 中將 Python函數(shù) 與 定義“函數(shù)名稱、描述和預(yù)期參數(shù)”的schema 關(guān)聯(lián)起來(lái)。
工具(Tool) 可以傳給支持 tool calling 的 聊天模型,允許模型使用特定輸入執(zhí)行特定函數(shù)。
創(chuàng)建工具的推薦方法是使用@tool 裝飾器。此裝飾器旨在簡(jiǎn)化工具創(chuàng)建過(guò)程,在大多數(shù)情況下應(yīng)使用它。定義函數(shù)后,可以使用@tool 對(duì)其進(jìn)行裝飾,以創(chuàng)建實(shí)現(xiàn)工具接口 的工具。
代碼如:
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""兩個(gè)數(shù)字相乘."""
return a * b
默認(rèn)情況下,裝飾器使用函數(shù)名稱作為工具名稱。
裝飾器將使用函數(shù)的文檔字符串作為工具的描述 —— 因此必須提供文檔字符串。
定義工具后,可以通過(guò)調(diào)用直接使用它。
result = multiply.invoke({"a": 2, "b": 3})
print(result)
# Output: 6
也能直接看到工具的具體信息。
print(multiply.name)
print(multiply.description)
print(multiply.args)
# 輸出
multiply
兩個(gè)數(shù)字相乘.
{'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}
通過(guò)參數(shù)自定義工具
@tool("multiplication-tool", args_schema=CalculatorInput, return_direct=True)
屬性 | 類型 | 描述 |
名稱 | str | 在提供給 LLM 或代理的一組工具中必須是唯一的。 |
描述 | str | 描述工具的作用。用作 LLM 或代理的上下文。 |
args_schema | pydantic.BaseModel | 可選但推薦,如果使用回調(diào)處理程序則為必需。它可用于提供更多信息(例如,少量示例)或驗(yàn)證預(yù)期參數(shù)。 |
return_direct | 布爾值 | 僅與agent相關(guān)。當(dāng)為 True 時(shí),在調(diào)用給定的工具后,代理將停止并將結(jié)果直接返回給用戶。 |
代碼如:
from pydantic import BaseModel, Field
class CalculatorInput(BaseModel):
a: int = Field(descriptinotallow="第一個(gè)數(shù)字")
b: int = Field(descriptinotallow="第二個(gè)數(shù)字")
# 通過(guò)參數(shù)自定義
@tool("multiplication-tool", args_schema=CalculatorInput, return_direct=True)
def multiply(a: int, b: int) -> int:
"""兩個(gè)數(shù)字相乘."""
return a * b
# 查看工具的具體信息
print(multiply.name)
print(multiply.description)
print(multiply.args)
print(multiply.return_direct)
輸出:
# 輸出
multiplication-tool
兩個(gè)數(shù)字相乘.
{'a': {'description': '第一個(gè)數(shù)字', 'title': 'A', 'type': 'integer'}, 'b': {'description': '第二個(gè)數(shù)字', 'title': 'B', 'type': 'integer'}}
True
通過(guò)解析文檔字符串配置定義工具
@tool 可以選擇性地解析Google Style 文檔字符串,并將文檔字符串組件(例如參數(shù)描述)與工具schame的相關(guān)部分關(guān)聯(lián)起來(lái)。使用這種方法,需要指定 parse_docstring
代碼如:
@tool(parse_docstring=True) # 解析文檔字符串
def multiply(a: int, b: int) -> int:
"""兩個(gè)數(shù)字相乘.
Args:
a: 第一個(gè)數(shù)字
b: 第二個(gè)數(shù)字
Returns:
兩個(gè)數(shù)字相乘的結(jié)果
"""
return a * b
# 查看工具的具體信息
print(multiply.name)
print(multiply.description)
print(multiply.args)
print(multiply.return_direct)
結(jié)果:
# 輸出
multiply
兩個(gè)數(shù)字相乘.
{'a': {'description': '第一個(gè)數(shù)字', 'title': 'A', 'type': 'integer'}, 'b': {'description': '第二個(gè)數(shù)字', 'title': 'B', 'type': 'integer'}}
False
通過(guò)大模型的 Tool calling 調(diào)用工具
Tool calling 允許聊天模型通過(guò)“Tool calling”來(lái)響應(yīng)給定的提示詞。
雖然“Tool calling”這個(gè)名字暗示模型正在直接執(zhí)行某些操作,但實(shí)際上并非如此!模型僅生成工具的參數(shù),而是否運(yùn)行工具(或不運(yùn)行)取決于用戶。
Tool calling 可以從模型生成結(jié)構(gòu)化輸出,即使您不打算調(diào)用任何工具,也可以使用它。該技術(shù)是從非結(jié)構(gòu)化文本中提取信息。
如下圖,把用戶輸入的文本,通過(guò)大模型的Tool calling提取出了符合工具get_weather的信息。
代碼示例
第一步:定義工具
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
model = ChatOpenAI(
api_key='hk-iwtb1e427',
base_url='https://api.openai-hk.com/v1',
temperature=0
)
print("第一步 :定義工具")
@tool
def multiply(a: int, b: int) -> int:
"""兩個(gè)數(shù)字相乘."""
return a * b
tools = [multiply]
第二步:把工具綁定到大模型
# Tool binding
print("第二步 :把工具綁定到大模型")
model_with_tools = model.bind_tools(tools)
第三步:大模型 Tool calling
# Tool calling
print("第三步 :大模型Tool calling")
query = "2乘以3"
messages = [HumanMessage(query)]
ai_msg = model_with_tools.invoke(messages)
print(ai_msg)
# 獲取返回的response中工具名稱和調(diào)用參數(shù)
print("大模型 Tool calling 返回結(jié)果 : ",ai_msg.tool_calls)
# [{'name': 'multiplication-tool', 'args': {'a': 2, 'b': 3}, 'id': 'call_2bJbBe74qhuDfg3ZGCu7p9e3', 'type': 'tool_call'}]
messages.append(ai_msg)
第四步:工具的執(zhí)行(Tool calling 返回需要執(zhí)行的工具)
print("第四步 :工具的執(zhí)行")
# 定義所有的工具字典
all_tools = {
"multiply": multiply
}
for tool_call in ai_msg .tool_calls:
selected_tool = all_tools[tool_call["name"].lower()]
tool_msg = selected_tool.invoke(tool_call)
print("工具的執(zhí)行 返回結(jié)果 : ",tool_msg)
messages.append(tool_msg)
# cnotallow='6' name='multiply' tool_call_id='call_CTCJAFlibfN3zhM9jMMStBlp'
print("聊天上下文 :")
print(messages)
第五步:大模型處理工具的返回結(jié)果
print("第五步:大模型處理工具的返回結(jié)果")
response = model_with_tools.invoke(messages)
print("大模型返回 :",response.content)
# 大模型返回 : 2乘以3的結(jié)果是6。
用戶輸入 :2乘以3
大模型返回 : 2乘以3的結(jié)果是6。
日志:
本文轉(zhuǎn)載自 ??AI取經(jīng)路??,作者: AI取經(jīng)路
