サイトのデザインが新しくなりました。

【Anthropic Tool】Claude 3の自分用AIエージェントの作り方

2024年4月5日、Anthropic社がMessages APIにてClaude 3シリーズ向けにTool機能を開放しました。

これはOpenAIでいうところのFunction Calling機能のようなもので、ユーザーからの入力メッセージに対して、特定のツールを使用して回答を生成します。

このツールは、250以上設定でき、ユーザーからの入力に応じて90%以上の精度で適切なツールを選択して、応答を生成できるそうです。

ただ、ツールについては、使用方法についての詳細に記述することが重要で、ツールの目的やパラメータ、使用時の注意点などを明確にする必要があります。

今回は、Tool機能の概要を紹介し、実際に使ってみようと思います。

是非最後までご覧ください!

なお弊社では、生成AIツール開発についての無料相談を承っています。こちらからお気軽にご相談ください。

目次

Tool機能の概要

Anthropic社がMessages APIにてClaude 3シリーズ向けにベータ版として開放したTool機能は、OpenAIでいうところのFunction Calling機能にあたるものです。

この機能の開放により、ユーザーは事前に定義された特定のツール(例えば、株価を取得するツールや天気情報を提供するツールなど)を利用して応答を生成できるようになりました。

ツールは、ユーザーが定義することができ、実際のツール定義の例を以下に示します。

{
  "name": "get_weather",
  "description": "Get the current weather in a given location",
  "input_schema": {
    "type": "object", 
    "properties": {
      "location": {
        "type": "string",
        "description": "The city and state, e.g. San Francisco, CA"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
      }
    },
    "required": ["location"]
  }
}

こちらは、特定の場所の最近の天気を取得するツールです。

ツール定義の主要部分の説明です。

  • name: ツールの名前で、次の正規表現に従うする必要があります。 ^[a-zA-Z0-9_-]{1,64}$
  • description: ツールの機能、使用時期、動作方法についての詳細なプレーンテキストの説明を記載します。
  • input_schema:予期されるパラメータを定義するオブジェクトです。

このツール定義について、Anthropicからベストプラクティスがアナウンスされているので紹介します。

  • ツールに関する以下の情報を詳細に説明する必要がある
    • ツールの機能
    • いつ使用すべきか(いつ使用すべきでないか)
    • 各パラメータの意味とそれがツールの動作にどのように影響するか
    • ツール名が不明な場合にツールが返さない情報など、重要な注意事項や制限事項
  • 少なくとも3~4文を目標に説明を記述する
    • もしツールが複雑な場合は、それ以上の量の説明を記述することを目標にします。
  • 例よりも説明を優先
    • ツールの使用方法の例をプロンプトに含めることはできますが、最も重要なのは目的とパラメータについての具体的な説明で、例は説明が完全に具体化された場合のみ記載します。

これらのベストプラクティスをもとに作成されたツール定義がこちらです。

{
  "name": "get_stock_price",
  "description": "Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. It should be used when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company.",
  "input_schema": {
    "type": "object",
    "properties": {
      "ticker": {
        "type": "string",
        "description": "The stock ticker symbol, e.g. AAPL for Apple Inc."
      }
    },
    "required": ["ticker"]
  }
}

こちらは、特定の銘柄の現在または直近の株価を取得するツールです。

descriptionはとても詳細に書かれています。

Retrieves the current stock price for a given ticker symbol. The ticker symbol must be a valid symbol for a publicly traded company on a major US stock exchange like NYSE or NASDAQ. The tool will return the latest trade price in USD. It should be used when the user asks about the current or most recent price of a specific stock. It will not provide any other information about the stock or company.

指定したティッカーシンボルの現在の株価を取得します。ティッカーシンボルは、NYSEやNASDAQのような米国の主要な証券取引所で公開されている企業の有効なシンボルでなければなりません。このツールは、最新の取引価格を米ドルで返します。このツールは、ユーザーが特定の銘柄の現在または直近の価格について尋ねる場合に使用します。その銘柄や企業に関するその他の情報は提供されません。

次に、Claudeによるツールの使用について解説します。

Claudeは、以下のような流れでツールを使用して、応答を生成します。

  • ツールの指定と入力の提供: ユーザーまたはシステムからのメッセージに基づいて、Claudeは利用すべきツールを判断し、そのツールに渡すべき具体的な入力情報を生成します。この入力情報は、ツールのinput_schemaに基づいて構成されます。
  • tool_useレスポンスブロックの生成: Claudeがツールの使用を決定した場合、stop_reasonがtool_useとされ、ツールの名前、一意の識別子(id)、およびツールへの入力情報が含まれたtool_useコンテンツブロックがAPIレスポンスに含まれます。このブロックは、ユーザーが実際にツールを実行するために必要な情報を提供します。
  • ツールの実行: ユーザーはtool_useブロックから情報を取得し、対応するツールを自身のコードベースで実行します。このとき、Claudeから提供された入力パラメータをツールに渡します。
  • ツール結果のフィードバック: ツールの実行結果(成功またはエラー)を、tool_resultタイプのコンテンツブロックを含む新しいメッセージとしてClaudeに送り返します。このメッセージには、対応するtool_useリクエストのidと結果の内容が含まれます。
  • 応答の生成: ツールの実行結果を受け取ったClaudeは、その情報を基にユーザーへの最終的な応答を生成します。この応答は、ユーザーの元の質問に対する具体的な答えや、ツールの実行に関連する追加情報を含むことができます。

また、ツールの使用の際のベストプラクティスも共有されています。

  • モデル選択:複雑なツールの使用をナビゲートするには Claude 3 Opusを使用し、単純なツールを扱う場合は Haikuを使用することをお勧めします。
  • ツール選択:250以上のツールから、ユーザーの入力に応じて90%以上の精度で適切なツールを選択できます。
  • 最適なツール定義:よりシンプルなインターフェイスとよりシンプルなツールを使用することが推奨され、複雑で深くネストされたツールの使用は避けてください。
  • 順次ツール使用:Claude は通常、一度に1つのツールを使用し、そのツールの出力を使用して次のアクションを通知することを好みます。プロンプトとツールを慎重に設計することで、Claude に複数のツールを並行して使用するように指示できますが、これにより、Claude が以前のツール使用の結果に依存するパラメーターにダミー値を入力する可能性があります。
  • 再試行:Claudeはツール使用リクエストが無効であるか、必要なパラメータが欠落している場合、エラー応答を返して再試行できますが、2 ~ 3 回試行が失敗すると、諦めてさらに再試行する代わりにユーザーに謝罪するようになります。
  • デバッグ:予期しないツール使用動作をデバッグするときは、Claude の思考の連鎖出力 (ある場合) に注意して、なぜその選択が行われているかを理解してください。
  • タグ:検索ツールを使用すると、 <検索品質_反射> XML タグとその応答内の検索品質スコアが返ってくることがあります。その際は、「応答で返された検索結果の品質を反映しないでください」という文プロンプトの最後に追加することで対処できます。

ここからは、実際にTool機能を使ってみようと思います。

なお、Claude 3 Haikuについて知りたい方はこちらの記事をご覧ください。
【Claude 3 Haiku】AnthropicのLLMで最も高速なLLMをChatGPTとGeminiと比較してみた

Tool機能のトークン数

Tool機能のトークン数は、モデルに送信された入力トークンの総数と生成された出力トークンの数の合計であり、これが課金対象になります。

また、モデルごとにシステムプロンプトが異なり、それらのトークン数は各モデル固定で追加されます。

  • Claude 3 Opus: 395トークン
  • Claude 3 Sonnet: 159トークン
  • Claude 3 Haiku: 264トークン

各モデルの料金については、以下のリンクから確認してください。

models-overview

Tool機能の使い方

Messaging APIを使用するので、まずはANTHROPIC APIキーの取得と環境変数の設定、anthropicのインストールを行います。

APIキーは、以下のリンクから取得できます。

Anthropic console

取得したAPIキーを環境変数に追加します。

export ANTHROPIC_API_KEY=your_api_key

次に、anthropicパッケージのインストールを行います。

pip install anthropic

これでMessaging APIは利用できるので、試しに先ほどの例にあった天気を取得するツール定義を使ってみましょう。

import anthropic
client = anthropic.Anthropic()

response = client.beta.tools.messages.create(
    model="claude-3-opus-20240229",
    max_tokens=1024,
    tools=[
        {
            "name": "get_weather",
            "description": "Get the current weather in a given location",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "The unit of temperature, either \"celsius\" or \"fahrenheit\""
                    }
                },
                "required": ["location"]
            }
        }
    ],
    messages=[{"role": "user", "content": "What is the weather like in San Francisco?"}]
)

print(response)

すると、このような応答が出力されました。(出力されたものを綺麗に整えています)

{
  "id": "msg_01LitcYPe64A1BG1na6Udja5",
  "model": "claude-3-opus-20240229",
  "role": "assistant",
  "stop_reason": "tool_use",
  "stop_sequence": null,
  "type": "message",
  "usage": {
    "input_tokens": 527,
    "output_tokens": 159
  },
  "content": [
    {
      "text": "<thinking>\nThe user has asked for the current weather in San Francisco. The relevant tool is get_weather, which requires a location parameter. The user provided the location \"San Francisco\", but did not specify a state. However, given San Francisco is a major, well-known city, we can reasonably infer they mean San Francisco, CA without needing to ask for clarification. The unit parameter is optional, so we do not need to ask the user to provide that.\n</thinking>",
      "type": "text"
    },
    {
      "id": "toolu_01FgoznQmsmMkaKtss5jAGVb",
      "input": {
        "location": "San Francisco, CA"
      },
      "name": "get_weather",
      "type": "tool_use"
    }
  ]
}

テキストの部分にはこう書かれています。

ユーザーはサンフランシスコの現在の天気を尋ねている。該当するツールは get_weather で、location パラメータが必要です。ユーザは location 〚San Francisco〛を指定したが、州は指定しなかった。しかし、San Franciscoが有名な大都市であることから、説明を求めるまでもなく、カリフォルニア州サンフランシスコを意味していると合理的に推測できます。unitパラメータはオプションなので、ユーザーにその入力を求める必要はありません。

このまま続けて以下のコードを実行します。

import anthropic
client = anthropic.Anthropic()

response = client.beta.tools.messages.create(
    model="claude-3-opus-20240229",
    max_tokens=1024,
    tools=[
        {
            "name": "get_weather",
            "description": "Get the current weather in a given location",
            "input_schema": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA"
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "The unit of temperature, either 'celsius' or 'fahrenheit'"
                    }
                },
                "required": ["location"]
            }
        }
    ],
    messages=[
        {
            "role": "user",
            "content": "What's the weather like in San Francisco?"
        },
        {
            "role": "assistant",
            "content": [
                {
                    "type": "text",
                    "text": "<thinking>\nThe user has asked for the current weather in San Francisco. The relevant tool is get_weather, which requires a location parameter. The user provided the location \"San Francisco\", but did not specify a state. However, given San Francisco is a major, well-known city, we can reasonably infer they mean San Francisco, CA without needing to ask for clarification. The unit parameter is optional, so we do not need to ask the user to provide that.\n</thinking>",
                },
                {
                    "type": "tool_use",
                    "id": "toolu_01FgoznQmsmMkaKtss5jAGVb",
                    "name": "get_weather",
                    "input": {"location": "San Francisco, CA"}
                }
            ]
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "tool_result",
                    "tool_use_id": "toolu_01FgoznQmsmMkaKtss5jAGVb", # from the API response
                }
            ]
        }
    ]
)

print(response)

結果はこのようになりました。

{
  "id": "msg_01FeeQLgTHox74PfEJjCxmDj",
  "model": "claude-3-opus-20240229",
  "role": "assistant",
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "type": "message",
  "usage": {
    "input_tokens": 712,
    "output_tokens": 32
  },
  "content": [
    {
      "text": "According to the weather information, it is currently 65°F (18°C) and partly cloudy in San Francisco, CA.",
      "type": "text"
    }
  ]
}

出力された応答を日本語訳したものです。

気象情報によると、サンフランシスコ(カリフォルニア州)の現在の気温は65°F(18℃)、一部曇り。

このように、気温と天気の情報を教えてくれました。

ただ、実行時のサンフランシスコは気温12℃で晴れだったので、全然違う情報を出力しています。

その点は気になりますが、これで実際に使えることが分かりました。

ここからは、指定した銘柄の株価を取得するツールを作って、株価検索エージェントを作ってみようと思います!

Tool機能を使って株価検索エージェントを作ってみた!

早速、株価検索エージェントを作成していきましょう!

今回は、公式ドキュメントなどを参考に作成していきます。

まず現在の株価を取得する方法ですが、ここではYahoo! Financeから情報を取得するためのAPIであるyfinanceを使用します。

yfinanceは、オープンソースなのでpip installで簡単にインストールできます。

pip install yfinance

最初は先ほどと同じように、必要なモジュールをインポートして、ツールを定義します。

import anthropic
import yfinance as yf

client = anthropic.Anthropic()

tools = [
    {
        "name": "get_stock_price",
        "description": "Get the current stock price for a given ticker symbol",
        "input_schema": {
            "type": "object",
            "properties": {
                "ticker_symbol": {
                    "type": "string",
                    "description": "The stock ticker symbol, e.g., AAPL for Apple Inc."
                }
            },
            "required": ["ticker_symbol"]
        }
    }
]

ツール定義は、claudeのドキュメントにあったものをそのまま使っています。

次に、株価を取得するための関数を定義します。

# 株価を取得するための関数
def get_stock_price(ticker_symbol):
    stock = yf.Ticker(ticker_symbol)
    hist = stock.history(period="1d")
    current_price = hist['Close'].iloc[0]
    return current_price

ここでは、ticker_symbolから株価を取得したい銘柄のティッカーシンボルを受け取り、yfinanceライブラリを使用して現在の株価を取得する関数を定義しています。

histで株価履歴の取得をし、current_priceで現在の株価の抽出しています。

次に、ユーザーからの質問をAnthropic APIに送信します。

#ユーザーからの質問をAnthropic APIに送信
def ask_claude(question):
    initial_response = client.beta.tools.messages.create(
        model="claude-3-sonnet-20240229",
        max_tokens=1024,
        tools=tools,
        messages=[{"role": "user", "content": question}]
    )

ここで、初期応答にツールの使用が必要とされる場合(tool_use)、定義されたツール(get_stock_price)を呼び出し、その入力(ティッカーシンボル)に基づいて株価を取得します。

    if initial_response.stop_reason == "tool_use":
        tool_use = next(block for block in initial_response.content if block.type == "tool_use")
        tool_name = tool_use.name
        tool_input = tool_use.input

        #ここで株価取得ツールを呼び出す
        #株価取得ツールを呼び出して結果を取得
        tool_result = get_stock_price(tool_input["ticker_symbol"])

        #ツール結果を文字列に変換
        tool_result_str = str(tool_result) 

ここで結果を文字列に変換しないと、エラーになってしまうのでご注意ください。

最後に、ツールの結果をClaudeに送り返し、最終的な応答を得ます。

        #ツールの結果をClaudeに送り返し、最終的な応答を得る
        response = client.beta.tools.messages.create(
            model="claude-3-sonnet-20240229",
            max_tokens=4096,
            messages=[
                {"role": "user", "content": question},
                {"role": "assistant", "content": initial_response.content},
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "tool_result",
                            "tool_use_id": tool_use.id,
                            "content": tool_result_str,
                        }
                    ],
                },
            ],
            tools=tools,
        )   

        final_response = next(
            (block.text for block in response.content if hasattr(block, "text")),
            None,
        )
        
        return final_response
    else:
        #ツールが使用されなかった場合の処理
        return next(
            (block.text for block in initial_response.content if hasattr(block, "text")),
            "Unable to process the request."
        )

question = "What is the stock price of AAPL?"
print(ask_claude(question))

これらのパートをすべてまとめたコードがこちらです。

import anthropic
import yfinance as yf

client = anthropic.Anthropic()

tools = [
    {
        "name": "get_stock_price",
        "description": "Get the current stock price for a given ticker symbol",
        "input_schema": {
            "type": "object",
            "properties": {
                "ticker_symbol": {
                    "type": "string",
                    "description": "The stock ticker symbol, e.g., AAPL for Apple Inc."
                }
            },
            "required": ["ticker_symbol"]
        }
    }
]

#株価を取得するための関数
def get_stock_price(ticker_symbol):
    stock = yf.Ticker(ticker_symbol)
    hist = stock.history(period="1d")
    current_price = hist['Close'].iloc[0]
    return current_price

#ユーザーからの質問をAnthropic APIに送信
def ask_claude(question):
    initial_response = client.beta.tools.messages.create(
        model="claude-3-sonnet-20240229",
        max_tokens=1024,
        tools=tools,
        messages=[{"role": "user", "content": question}]
    )

    if initial_response.stop_reason == "tool_use":
        tool_use = next(block for block in initial_response.content if block.type == "tool_use")
        tool_name = tool_use.name
        tool_input = tool_use.input

        #ここで株価取得ツールを呼び出す
        #株価取得ツールを呼び出して結果を取得
        tool_result = get_stock_price(tool_input["ticker_symbol"])

        #ツール結果を文字列に変換
        tool_result_str = str(tool_result) 

        #ツールの結果をClaudeに送り返し、最終的な応答を得る
        response = client.beta.tools.messages.create(
            model="claude-3-sonnet-20240229",
            max_tokens=4096,
            messages=[
                {"role": "user", "content": question},
                {"role": "assistant", "content": initial_response.content},
                {
                    "role": "user",
                    "content": [
                        {
                            "type": "tool_result",
                            "tool_use_id": tool_use.id,
                            "content": tool_result_str,
                        }
                    ],
                },
            ],
            tools=tools,
        )   

        final_response = next(
            (block.text for block in response.content if hasattr(block, "text")),
            None,
        )
        
        return final_response
    else:
        #ツールが使用されなかった場合の処理
        return next(
            (block.text for block in initial_response.content if hasattr(block, "text")),
            "Unable to process the request."
        )

question = "What is the stock price of AAPL?"
print(ask_claude(question))

これを実行すれば、question = “What is the stock price of AAPL?”に対する回答が得られるはずです。

結果は、この通りAppleの現在の株価を出力してくれました。

Googleで調べても、同じ株価なので正しい情報だということが分かりますね!

ちなみに、ティッカーシンボルではなく企業名で質問しても、問題なく答えてくれます。

question = "What is the stock price of Apple?"

今回紹介したツール機能は、比較的簡単に自分がやらせたいことをAIにやらせることができる便利機能ですので、みなさんも是非使ってみてください!

なお、Claude 3がプロンプトエンジニアリングをしてくれるclaude-prompt-engineerについて知りたい方はこちらの記事をご覧ください。
【claude-prompt-engineer】ChatGPTを解約してClaude 3をもっと使いたくなるAIエージェントの使い方を解説

Tool機能を使って自分だけの最強エージェントを作ろう!

AnthropicのTool機能は、OpenAIでいうところのFunction Calling機能のようなもので、ユーザーからの入力メッセージに対して、特定のツールを使用して回答を生成します。

ツールは、ユーザー自身で定義できますが、使用方法についての詳細に記述することが重要で、ツールの目的やパラメータ、使用時の注意点などを明確にする必要があります。

また、ツールを実際に使用する際も、タスクに応じてモデルを変更したり、できるだけ並列処理はさせず、一つ一つタスクを実行することで、より良い応答が得られます。

ツール使用時もトークン数に応じて料金がかかり、システムプロンプト分のトークンは、固定で入力トークンに追加されるので、その点は注意が必要です。

この機能を活用すれば、自分の目的に合わせたこれまでにない高度なAIエージェントの作成が可能になります。

もしこの記事を読んで気になった方は是非試してみてください!

サービス紹介資料

生成系AIの業務活用なら!

・生成系AIを活用したPoC開発

・生成系AIのコンサルティング

・システム間API連携

最後に

いかがだったでしょうか?

弊社では

・マーケティングやエンジニアリングなどの専門知識を学習させたAI社員の開発
・要件定義・業務フロー作成を80%自動化できる自律型AIエージェントの開発
・生成AIとRPAを組み合わせた業務自動化ツールの開発
・社内人事業務を99%自動化できるAIツールの開発
ハルシネーション対策AIツールの開発
自社専用のAIチャットボットの開発

などの開発実績がございます。

まずは、「無料相談」にてご相談を承っておりますので、ご興味がある方はぜひご連絡ください。

➡︎生成AIを使った業務効率化、生成AIツールの開発について相談をしてみる。

生成AIを社内で活用していきたい方へ

「生成AIを社内で活用したい」「生成AIの事業をやっていきたい」という方に向けて、生成AI社内セミナー・勉強会をさせていただいております。

セミナー内容や料金については、ご相談ください。

また、弊社紹介資料もご用意しておりますので、併せてご確認ください。

投稿者

  • ゆうや

    ロボット工学専攻。 大学時代は、対話ロボットのための画像キャプションの自動生成について研究。 趣味は、サウナとドライブ。

  • URLをコピーしました!
  • URLをコピーしました!
目次