LangChain の Tool Calling 標準インタフェース の概要
以下の記事が面白かったので、簡単にまとめました。
1. はじめに
LLMは「Tool Calling」を介して外部データと対話できます。開発者がLLMを活用してデータベース、ファイル、APIなどの外部リソースにアクセスできる高度なアプリケーションを構築できる強力な手法です。
各プロバイダーは、ネイティブの「Tool Calling」の機能を提供しています。LLMがプロンプトのオートコンプリートを提供する時、プレーンテキストに加えて「Tool Calling」のリストを返すことができます。
OpenAIは約1年前に「Function Calling」をリリースし、11月には「Tool Calling」に進化しました。他のプロバイダーも、Gemini (12月)、Mistral (2月)、Fireworks (3月)、Togetter (3月)、Groq (4月)、Cohere (4月)、Anthropic (4月) と続いています。
しかし、これらのプロバイダーが提供しているインターフェイスは、それぞれわずかに異なります。そこで、LangChainではプロバイダーの切り替えを簡単にするため、「Tool Calling」の標準インタフェースを実装しました。
2. Tool Calling の標準インタフェース
「Tool Calling」の標準インターフェイスの構成は、次のとおりです。
2-1. ChatModel.bind_tools()
「Tool Calling」でははじめに、どのツールが利用可能であるかをモデルに伝える必要があります。具体的には、ツール定義のリストをモデルに渡します。
ツール定義の書式はプロバイダーごとに異なります。
生のツール定義だけでなく、ツール定義の派生元となるオブジェクト (Pydanticクラス、LangChainツール、関数) を渡すこともできます。
from langchain_anthropic import ChatAnthropic
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.tools import tool
# Pydanticクラス
class multiply(BaseModel):
"""Return product of 'x' and 'y'."""
x: float = Field(..., description="First factor")
y: float = Field(..., description="Second factor")
# LangChainツール
@tool
def exponentiate(x: float, y: float) -> float:
"""Raise 'x' to the 'y'."""
return x**y
# 関数
def subtract(x: float, y: float) -> float:
"""Subtract 'x' from 'y'."""
return y-x
# OpenAIのツール定義
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の準備
llm = ChatAnthropic(model="claude-3-sonnet-20240229", temperature=0)
# Tool Calling LLMの準備
llm_with_tools = llm.bind_tools([multiply, exponentiate, add, subtract])
2-2. AIMessage.tool_calls
以前は「Tool Calling LLM」を使用する場合、モデルが決定したツールの情報は、AIMessage.additional_kwargs または AIMessage.content で、プロバイダ固有の書式で返されていました。
現在は AIMessage.tool_calls が、モデルが決定したツールの情報を返す標準インタフェースになります。LLM呼び出しを行うと、次のような出力が返されます。
# LLM呼び出し
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] を持ちます。ToolCall の型は次のとおりです。
class ToolCall(TypedDict):
name: str
args: Dict[str, Any]
id: Optional[str]
2-3. create_tool_calling_agent()
「Tool Calling」の最も強力な用途の1つは、エージェントを構築することです。LangChainにはすでに、「OpenAI Tool Calling API」に準拠した Tool Calling を備えたエージェントを構築できる create_openai_tools_agent() がありますが、これは Anthropic や Gemini などでは機能しません。新しい bind_tools() および tool_calls のおかげで、あらゆる Tool Calling モデルで動作する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
# LangChainツール
@tool
def multiply(x: float, y: float) -> float:
"""Multiply 'x' times 'y'."""
return x * y
# LangChainツール
@tool
def exponentiate(x: float, y: float) -> float:
"""Raise 'x' to the 'y'."""
return x**y
# LangChainツール
@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の準備
llm = ChatAnthropic(model="claude-3-sonnet-20240229", temperature=0)
# Tool Calling エージェントの準備
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Tool Calling エージェントの実行
agent_executor.invoke({"input": "what's 3 plus 5 raised to the 2.743. also what's 17.24 - 918.1241", })
3. LangGraph
「LangGraph」は、任意のエージェントフローおよびマルチエージェントフローの構築を容易にするLangChainの拡張機能です。tool_callsを使用すると、LangGraphエージェントまたはフローの構築も簡単になります。LangGraph エージェントでの Tool Calling のtool_callsの使用方法については、こちらのノートブックを参照してください。
4. with_structured_output
ChatModel.with_structed_output() は、モデルから構造化された出力を取得するための機能です。正確な実装はプロバイダーごとに異なりますが、サポートするモデルの「Tool Calling」上に構築されます。内部では、tool_callsを使用して、指定された構造化出力スキーマをモデルに渡します。
ChatModel.with_structed_output() は常に、指定したスキーマで構造化された出力を返します。これは、特定のスキーマに一致する情報をLLM に出力させる場合に便利です。 これは、情報抽出タスクに役立ちます。
bind_tools はより汎用的で、特定のツールを選択することも、ツールを選択しないことも、複数のツールを選択することもできます。これは、LLMの応答方法をより柔軟にできるようにしたい場合に便利です。