跳转到主要内容

热门内容

今日:


总体:


最近浏览:


Chinese, Simplified

category

TLDR:我们在AIMessage上引入了一个新的tool_calls属性。越来越多的LLM提供程序正在公开API用于可靠的工具调用。新属性的目标是提供一个用于与工具调用交互的标准接口。这是完全向后兼容的,并且在所有支持本机工具调用的模型上都受支持。为了访问这些最新功能,您需要升级langchain_core和合作伙伴包的版本。

YouTube Walkthrough

Python:

JS:

简介


大型语言模型(LLM)可以通过工具调用功能与外部数据源进行交互。工具调用是一种强大的技术,它允许开发人员构建复杂的应用程序,这些应用程序可以利用LLM访问、交互和操作数据库、文件和API等外部资源。

提供商一直在将本机工具调用功能引入到他们的模型中。在实践中,当LLM为提示提供自动完成时,除了纯文本之外,它还可以返回工具调用列表。大约一年前,OpenAI率先发布了“函数调用”,并于11月迅速演变为“工具调用”。从那时起,其他模型提供商也纷纷效仿:Gemini(12月)、Mistral(2月)、Fireworks(3月)、Together(3月。

所有这些提供商都暴露了略有不同的接口(特别是:OpenAI、Anthropic和Gemini,这三种性能最高的模型是不兼容的)。我们听到社区希望为工具调用提供一个标准化的接口,以便在这些提供者之间轻松切换,我们很高兴今天发布。

标准接口包括:

  • ChatModel.bind_tools():一种将工具定义附加到模型调用的方法。
     
  • AIMessage.tool_calls:从模型返回的AIMessage上的一个属性,用于轻松访问模型决定进行的工具调用。
     
  • create_tool_calling_agent():一个代理构造函数,用于实现bind_tools并返回tool_calls的ANY模型。
     

让我们来看看这些组件中的每一个。

ChatModel.bind_tools(...)


为了允许模型使用工具,我们需要告诉它哪些工具是可用的。我们通过指定将工具定义列表传递给模型来实现这一点,其中包括工具参数的模式。工具定义的确切格式取决于模型提供者——OpenAI需要一个带有“name”、“description”和“parameters”键的字典,而Anthropic需要“name”和“description和”input_schema“。

ChatModel.bind_tools提供了一个由所有工具调用模型实现的标准接口,允许您指定哪些工具可用于模型。您不仅可以传入原始工具定义(dict),还可以传入可以派生工具定义的对象:即Pydantic类、LangChain工具和任意函数。这使得创建可用于任何工具调用模型的通用工具定义变得容易:

from langchain_anthropic import ChatAnthropic
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.tools import tool
# ✅ Pydantic class
class multiply(BaseModel):
   """Return product of 'x' and 'y'."""
   x: float = Field(..., description="First factor")
   y: float = Field(..., description="Second factor")
   
# ✅ LangChain tool
@tool
def exponentiate(x: float, y: float) -> float:
   """Raise 'x' to the 'y'."""
   return x**y
   
# ✅ Function
def subtract(x: float, y: float) -> float:
   """Subtract 'x' from 'y'."""
   return y-x
   
# ✅ OpenAI-format dict
# Could also pass in a JSON schema with "title" and "description" 
add = {
 "name": "add",
 "description": "Add 'x' and 'y'.",
 "parameters": {
   "type": "object",
   "properties": {
     "x": {"type": "number", "description": "First number to add"},
     "y": {"type": "number", "description": "Second number to add"}
   },
   "required": ["x", "y"]
 }
}
llm = ChatAnthropic(model="claude-3-sonnet-20240229", temperature=0)
# Whenever we invoke `llm_with_tool`, all three of these tool definitions
# are passed to the model.
llm_with_tools = llm.bind_tools([multiply, exponentiate, add, subtract])


如果我们想使用不同的工具调用模型,我们的代码看起来会非常相似:

from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
llm_with_tools = llm.bind_tools([multiply, exponentiate, add, subtract])


那么,调用llm_with_tools会是什么样子呢?这就是AIMessage.tool_calls的用武之地。

AIMessage.tool_calls


在使用工具调用模型之前,模型返回的任何工具调用都可以在AIMessage.additional_kwargs或AIMessage.content中找到,具体取决于模型提供程序的API,并遵循特定于提供程序的格式。也就是说,您需要自定义逻辑来从不同模型的输出中提取工具调用。现在,AIMessage.tool_calls为获取模型工具调用提供了一个标准化接口。因此,在使用绑定工具调用模型后,您将获得以下表单的输出:

llm_with_tools.invoke([
    ("system", "You're a helpful assistant"), 
    ("human", "what's 5 raised to the 2.743"),
])
# 👀 Notice the tool_calls attribute 👀
# -> AIMessage(
#       content=..., 
#       additional_kwargs={...},
#       tool_calls=[{'name': 'exponentiate', 'args': 
{'y': 2.743, 'x': 5.0}, 'id': 
'54c166b2-f81a-481a-9289-eea68fc84e4f'}]
#       response_metadata={...}, 
#       id='...'
#   )


其中AIMessage有一个tool_calls:List[ToolCall]属性,如果有任何工具调用,该属性将被填充,并遵循工具调用的标准接口:

class ToolCall(TypedDict):
 name: str
 args: Dict[str, Any]
    id: Optional[str]


也就是说,无论你是调用Anthropic、OpenAI、Gemini等,只要有工具调用,它都会作为工具调用出现在AIMessage.tool_calls中。

我们还添加了一些其他属性,用于处理流式工具调用块和无效工具调用。点击此处阅读更多关于工具中调用文档的内容。

create_tool_calling_agent()


LLM工具调用功能最强大和最明显的用途之一是构建代理。LangChain已经有了create_openai_tool_agent()构造函数,可以轻松地使用遵循openai工具调用API的工具调用模型构建代理,但这对Anthropic和Gemini等模型不起作用。由于有了新的bind_tools()和tool_calls接口,我们添加了一个create_tool_calling_agent(),它可以与任何工具调用模型一起使用。

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import ConfigurableField
from langchain_core.tools import tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
@tool
def multiply(x: float, y: float) -> float:
   """Multiply 'x' times 'y'."""
   return x * y
@tool
def exponentiate(x: float, y: float) -> float:
   """Raise 'x' to the 'y'."""
   return x**y
@tool
def add(x: float, y: float) -> float:
   """Add 'x' and 'y'."""
   return x + y
prompt = ChatPromptTemplate.from_messages([
   ("system", "you're a helpful assistant"), 
   ("human", "{input}"), 
   ("placeholder", "{agent_scratchpad}"),
])
tools = [multiply, exponentiate, add]

llm = ChatAnthropic(model="claude-3-sonnet-20240229",
 temperature=0)

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, 
verbose=True)
agent_executor.invoke({"input": 
"what's 3 plus 5 raised to the 2.743.
 also what's 17.24 - 918.1241", })


我们可以使用VertexAI

from langchain_google_vertexai import ChatVertexAI
llm = ChatVertexAI(
    model="gemini-pro", 
    temperature=0, 
    convert_system_message_to_human=True
)
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent,
 tools=tools, verbose=True)
agent_executor.invoke({"input": "what's 3 plus 5 raised 
to the 2.743. also what's 17.24 - 918.1241", })


或OpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0)
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, 
verbose=True)
agent_executor.invoke({"input": "what's 3 plus 5 raised 
to the 2.743. also what's 17.24 - 918.1241", })


有关新代理的完整文档,请参阅此处。

LangGraph


如果您还没有签出LangGraph,那么绝对应该签出。它是LangChain的一个扩展,使构建任意agent和多agent流变得容易。可以想象,在构建LangGraph代理或流时,使用新的tool_calls接口也会使生活变得更简单。查看此处的笔记本,了解如何在LangGraph代理中使用tool_calls的详细演练。

带_结构化_输出
我们最近发布了ChatModel.with_structured_output()接口,用于从模型中获取结构化输出,这是非常相关的。虽然具体的实现因模型提供程序而异,但with_structured_output是在大多数支持它的模型的工具调用之上构建的。在后台,with_structure d_output使用bind_tools将给定的结构化输出模式传递给模型。

那么,什么时候应该使用with_structured_output,而不是直接使用绑定工具和读取工具调用呢?

with_structured_output始终返回指定模式中的结构化输出。当您希望强制LLM输出与特定模式匹配的信息时,这非常有用。这对于信息提取任务非常有用。

bind_tools更通用,可以选择特定的工具——或者不选择工具,或者选择多个工具!当您希望允许LLM在如何响应方面具有更大的灵活性时,这一点非常有用——例如,在代理应用程序中,您需要选择调用哪些工具,同时还要响应用户。

结论


我们预计,在LLM中引入本机工具调用功能的趋势将在未来继续下去。我们希望标准化的工具调用界面能够帮助LangChain用户节省时间和精力,并使他们能够更容易地在不同的LLM提供商之间切换。

请记住更新您的langchain_core和合作伙伴包版本以利用新接口!

本文地址
最后修改
星期日, 五月 12, 2024 - 18:38
Article