見出し画像

LangChain の Tool Calling 標準インタフェース の概要

以下の記事が面白かったので、簡単にまとめました。

Tool Calling with LangChain


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」の標準インターフェイスの構成は、次のとおりです。

・ChatModel.bind_tools()
ツール定義をモデルにアタッチするメソッド

・AIMessage.tool_calls
モデルが決定したツールの情報を伝えるプロパティ

・create_tool_calling_agent()
Tool Callingを利用するエージェントのコンストラクタ

2-1. ChatModel.bind_tools()

「Tool Calling」でははじめに、どのツールが利用可能であるかをモデルに伝える必要があります。具体的には、ツール定義のリストをモデルに渡します。

ツール定義の書式はプロバイダーごとに異なります。

・OpenAI : name、description、parameters を含む辞書
・Anthropic : name、description、input_schema を含む辞書

生のツール定義だけでなく、ツール定義の派生元となるオブジェクト (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の応答方法をより柔軟にできるようにしたい場合に便利です。



いいなと思ったら応援しよう!