LoginSignup
6
7

AnthropicとCohereとBedrockのTool Useを比較

Posted at

先に結論

接続先→
↓使用するSDK
Claude 3 (Anthropic) Claude 3 (Bedrock) Command R (Cohere) Command R (Bedrock)
Anthropic Python API library ✅️ ✅️
Cohere Python SDK ✅️ ✅️
Boto3 ✅️ ✅️

Boto3を使う場合、呼び出し方は統一されているが、レスポンスが統一されない印象

Anthropic Python API library

こちらを参考に実施します。

pip install anthropic

Bedrockを使用する場合はboto3もインストールします。

クライアントを生成します。

from anthropic import Anthropic

client = Anthropic(api_key="sk-*****")

Bedrockを使用する場合はこうなります。

from anthropic import AnthropicBedrock

client = AnthropicBedrock()

ツールの関数を作成します。

calculator関数
def calculator(operation, operand1, operand2):
    if operation == "add":
        return operand1 + operand2
    elif operation == "subtract":
        return operand1 - operand2
    elif operation == "multiply":
        return operand1 * operand2
    elif operation == "divide":
        if operand2 == 0:
            raise ValueError("Cannot divide by zero.")
        return operand1 / operand2
    else:
        raise ValueError(f"Unsupported operation: {operation}")

Claudeに教えるツールのスキーマを作成します。

ツールの定義
calculator_tool = {
    "name": "calculator",
    "description": "A simple calculator that performs basic arithmetic operations.",
    "input_schema": {
        "type": "object",
        "properties": {
            "operation": {
                "type": "string",
                "enum": ["add", "subtract", "multiply", "divide"],
                "description": "The arithmetic operation to perform.",
            },
            "operand1": {"type": "number", "description": "The first operand."},
            "operand2": {"type": "number", "description": "The second operand."},
        },
        "required": ["operation", "operand1", "operand2"],
    },
}

Claude 3を呼び出します。

response = client.messages.create(
    model="claude-3-haiku-20240307",  # Bedrockの場合は"anthropic.claude-3-haiku-20240307-v1:0"
    system="You have access to tools, but only use them when necessary.  If a tool is not required, respond as normal",
    messages=[
        {
            "role": "user",
            "content": "Multiply 1984135 by 9343116. Only respond with the result",
        }
    ],
    max_tokens=300,
    # Tell Claude about our tool
    tools=[calculator_tool],
)

responseを確認します。

response.stop_reason
'tool_use'
response.content
[ToolUseBlock(id='toolu_bdrk_01Q1xoTJvFXuPKoLpemL3k6z', input={'operand1': 1984135, 'operand2': 9343116, 'operation': 'multiply'}, name='calculator', type='tool_use')]

responseからツールの名前とインプットを取得します。

tool_name = response.content[0].name
tool_inputs = response.content[0].input

print("The Tool Name Claude Wants To Call:", tool_name)
print("The Inputs Claude Wants To Call It With:", tool_inputs)
The Tool Name Claude Wants To Call: calculator
The Inputs Claude Wants To Call It With: {'operand1': 1984135, 'operand2': 9343116, 'operation': 'multiply'}

ツール名「calculator」とパラメーター「{'operand1': 1984135, 'operand2': 9343116, 'operation': 'multiply'}」が取得できました。

定義しておいた関数を呼び出します。

operation = tool_inputs["operation"]
operand1 = tool_inputs["operand1"]
operand2 = tool_inputs["operand2"]

result = calculator(operation, operand1, operand2)
print("RESULT IS", result)
RESULT IS 18538003464660

ツール呼び出しができました。

Cohere Python SDK

同じ内容をCohere Python SDKでやってみましょう。

pip install cohere

Bedrockを使用する場合はboto3もインストールします。

クライアントを生成します。

import cohere

co = cohere.Client(api_key="*****")

Bedrockを使用する場合はこうなります。

co = cohere.BedrockClient(
    aws_region="us-east-1",
)

ツールの関数を作成します。

calculator関数
def calculator(operation, operand1, operand2):
    if operation == "add":
        return operand1 + operand2
    elif operation == "subtract":
        return operand1 - operand2
    elif operation == "multiply":
        return operand1 * operand2
    elif operation == "divide":
        if operand2 == 0:
            raise ValueError("Cannot divide by zero.")
        return operand1 / operand2
    else:
        raise ValueError(f"Unsupported operation: {operation}")

Command Rに教えるツールのスキーマを作成します。

AnthropicのAPIとは形式が異なります。
例えば、Anthropicではenumとして定義していましたが、Cohereはdescriptionで指定する必要があります。参考

ツールの定義
calculator_tool = {
    "name": "calculator_tool",
    "description": "A simple calculator that performs basic arithmetic operations.",
    "parameter_definitions": {
        "operation": {
            "type": "string",
            "description": "The arithmetic operation to perform. Possible enum values: add, subtract, multiply, divide.",
            "required": True,
        },
        "operand1": {
            "type": "number",
            "description": "The first operand.",
            "required": True,
        },
        "operand2": {
            "type": "number",
            "description": "The second operand.",
            "required": True,
        },
    },
}

Toolのnameを「calculator」にすると以下のエラーが発生します。

status_code: 400, body: {'message': "invalid request: the 'calculator' tool can't be used with a custom definition: choose a different name or remove the provided definition"}

calculator2calculator_toolではエラーにならないので、内部的な予約語とバッティングしているのかもしれません。

Command Rを呼び出します。

# user request
message = "Multiply 1984135 by 9343116. Only respond with the result"

response = co.chat(
    message=message,
    tools=[calculator_tool],
    preamble="You have access to tools, but only use them when necessary.  If a tool is not required, respond as normal",
    model="command-r",  # Bedrockの場合はcohere.command-r-v1:0
)

responseを確認します。

response.finish_reason
'COMPLETE'
response.tool_calls
[ToolCall(name='calculator_tool', parameters={'operand1': 1984135, 'operand2': 9343116, 'operation': 'multiply'})]

responseからツールの名前とインプットを取得します。

tool_name = response.tool_calls[0].name
tool_inputs = response.tool_calls[0].parameters

print("The Tool Name Claude Wants To Call:", tool_name)
print("The Inputs Claude Wants To Call It With:", tool_inputs)
The Tool Name Claude Wants To Call: calculator_tool
The Inputs Claude Wants To Call It With: {'operand1': 1984135, 'operand2': 9343116, 'operation': 'multiply'}

定義しておいた関数を呼び出します。

operation = tool_inputs["operation"]
operand1 = tool_inputs["operand1"]
operand2 = tool_inputs["operand2"]

result = calculator(operation, operand1, operand2)
print("RESULT IS", result)
RESULT IS 18538003464660

ツール呼び出しができました。

Boto3

最後はBoto3です。新しく追加になったConverse APIを使用します。

pip install boto3

クライアントを生成します。

import boto3

client = boto3.client("bedrock-runtime")

ツールの関数を作成します。

calculator関数
def calculator(operation, operand1, operand2):
    if operation == "add":
        return operand1 + operand2
    elif operation == "subtract":
        return operand1 - operand2
    elif operation == "multiply":
        return operand1 * operand2
    elif operation == "divide":
        if operand2 == 0:
            raise ValueError("Cannot divide by zero.")
        return operand1 / operand2
    else:
        raise ValueError(f"Unsupported operation: {operation}")

使えるツールのスキーマを作成します。
Anthropic Python API libraryやCohere Python SDKと比べ、階層が深い印象です。

enumの記述方法は、Claudeに合わせています。

ツールの定義
calculator_tool = {
    "toolSpec": {
        "name": "calculator_tool",
        "description": "A simple calculator that performs basic arithmetic operations.",
        "inputSchema": {
            "json": {
                "type": "object",
                "properties": {
                    "operation": {
                        "type": "string",
                        "enum": ["add", "subtract", "multiply", "divide"],
                        "description": "The arithmetic operation to perform.",
                    },
                    "operand1": {
                        "type": "number",
                        "description": "The first operand.",
                    },
                    "operand2": {
                        "type": "number",
                        "description": "The second operand.",
                    },
                },
                "required": ["operation", "operand1", "operand2"],
            }
        },
    }
}

Claude 3 (Bedrock)

Claude 3で実行します。

model_id = "anthropic.claude-3-haiku-20240307-v1:0"

response = client.converse(
    modelId=model_id,
    system=[
        {
            "text": "You have access to tools, but only use them when necessary.  If a tool is not required, respond as normal"
        }
    ],
    messages=[
        {
            "role": "user",
            "content": [
                {"text": "Multiply 1984135 by 9343116. Only respond with the result"}
            ],
        }
    ],
    toolConfig={"tools": [calculator_tool]},
    inferenceConfig={"maxTokens": 400},
)

import json
print(json.dumps(response["output"], indent=2, ensure_ascii=False))
response["output"]
{
  "message": {
    "role": "assistant",
    "content": [
      {
        "toolUse": {
          "toolUseId": "tooluse_VioZeA2_TSySf54-3AmGQg",
          "name": "calculator_tool",
          "input": {
            "operation": "multiply",
            "operand1": 1984135,
            "operand2": 9343116
          }
        }
      }
    ]
  }
}
response["stopReason"]
'tool_use'
response["output"]["message"]["content"]
[{'toolUse': {'toolUseId': 'tooluse_bOgY4tZ8QOC9-Fq58nvTHA',
   'name': 'calculator',
   'input': {'operand1': 1984135,
    'operand2': 9343116,
    'operation': 'multiply'}}}]

responseからツールの名前とインプットを取得します。

tool_name = response["output"]["message"]["content"][0]["toolUse"]["name"]
tool_inputs = response["output"]["message"]["content"][0]["toolUse"]["input"]

print("The Tool Name Claude Wants To Call:", tool_name)
print("The Inputs Claude Wants To Call It With:", tool_inputs)
The Tool Name Claude Wants To Call: calculator_tool
The Inputs Claude Wants To Call It With: {'operand1': 1984135, 'operand2': 9343116, 'operation': 'multiply'}

定義しておいた関数を呼び出します。

operation = tool_inputs["operation"]
operand1 = tool_inputs["operand1"]
operand2 = tool_inputs["operand2"]

result = calculator(operation, operand1, operand2)
print("RESULT IS", result)
RESULT IS 18538003464660

ツール呼び出しができました。

Command R (Bedrock)

モデルIDをcohere.command-r-v1:0に変えて実行してみます。

model_id = "cohere.command-r-v1:0"

response = client.converse(
    modelId=model_id,
    system=[
        {
            "text": "You have access to tools, but only use them when necessary.  If a tool is not required, respond as normal"
        }
    ],
    messages=[
        {
            "role": "user",
            "content": [
                {"text": "Multiply 1984135 by 9343116. Only respond with the result"}
            ],
        }
    ],
    toolConfig={"tools": [calculator_tool]},
    inferenceConfig={"maxTokens": 400},
)

import json
print(json.dumps(response["output"], indent=2, ensure_ascii=False))
response["output"]
{
  "message": {
    "role": "assistant",
    "content": [
      {
        "text": "I will use the calculator tool to multiply the two given numbers and respond with the result."
      },
      {
        "toolUse": {
          "toolUseId": "tooluse_3Vx63WQyQmmZ45jFNU8mgA",
          "name": "calculator_tool",
          "input": {
            "operand1": {
              "value": 1984135
            },
            "operand2": {
              "value": 9343116
            },
            "operation": {
              "enum": [
                "multiply"
              ]
            }
          }
        }
      }
    ]
  }
}

Claude 3の実行結果と比べると、色々違いがあります。

  • Claude 3はcontent内がtoolUseのみですが、Command RはtexttoolUseが含まれる(なので、配列の0番目で取得できない)
  • toolUse.inputの内容も微妙に形式が異なるので、受け取った側で頑張る必要がある
Claude 3
"input": {
    "operation": "multiply",
    "operand1": 1984135,
    "operand2": 9343116
}
Command R
"input": {
    "operand1": {
        "value": 1984135
    },
    "operand2": {
        "value": 9343116
    },
    "operation": {
        "enum": [
            "multiply"
        ]
    }
}

なので、結果を受け取ってパースする処理に変更が必要です。

tool_name = ""
tool_inputs = ""

for content in response["output"]["message"]["content"]:
    if "toolUse" in content:
        tool_name = content["toolUse"]["name"]
        tool_inputs = content["toolUse"]["input"]

print("The Tool Name Claude Wants To Call:", tool_name)
print("The Inputs Claude Wants To Call It With:", tool_inputs)
operation = tool_inputs["operation"]["enum"][0]
operand1 = tool_inputs["operand1"]["value"]
operand2 = tool_inputs["operand2"]["value"]

result = calculator(operation, operand1, operand2)
print("RESULT IS", result)
RESULT IS 18538003464660

毎回enumvalueが返ってくるのか、enumは必ず配列なのかなど、不確定要素がありそうな印象です。

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7