SambaNova CloudのFunction calling (関数呼び出し) 機能を使うと、ユーザーの入力に応じて、モデルが実行すべき関数を選択・提案できるようになり、エージェントワークフローの構築に役立ちます。あらかじめ使用する関数またはツールの一覧を定義しておくことで、モデルにコンテキストを与え、必要な引数を適切に補完させることが可能になります。

Function callingの仕組み

Function callingを使うことで、リアルタイムデータや構造化出力に対応した柔軟なワークフローを構築でき、よりダイナミックかつ応答性の高いモデルの対話が実現します。
  1. ツールを含むクエリの送信:まず、JSON Schemaで定義された利用可能なツール群とともに、ユーザからのクエリを送信します。各関数のパラメータもスキーマで指定します。
  2. モデルによる処理と提案:モデルはクエリを解釈し、意図を判断した上で、通常の会話を返すか、function callingを提案するかを選択します。関数が呼び出される場合、定義されたスキーマに基づいて引数を補完します。
  3. モデルから応答を受信:モデルからの応答には、function callingの提案が含まれる場合があります。提供された引数を使って関数を実行し、その結果を再度モデルに返すことで対話を継続します。

対応モデル

  • Meta-Llama-3.1-8B-Instruct
  • Meta-Llama-3.1-405B-Instruct
  • Meta-Llama-3.3-70B-Instruct
Meta社は、会話とツール呼び出しを組み合わせたアプリケーションには、Llama 70B-InstructまたはLlama 405B-Instructの使用を推奨しています。Llama 8B-Instructはツール呼び出しの定義を伴う会話を安定して保持できないため、ゼロショットのツール呼び出しなど限定的な用途に向いています。

使用例

以下の例では、function callingを使用するための各ステップを順に説明します。最後に、これらを通したend-to-endの実装例も紹介します。

ステップ1:関数スキーマの定義

まず、使用する関数のJSON Schemaを定義します。以下の要素を指定する必要があります。
  • 関数名
  • 関数の処理内容に関する説明
  • 各パラメータの名前、データ型、および説明
例:2次方程式の解を求める関数のスキーマ
{
    "type": "function",
    "function": {
        "name": "solve_quadratic",
        "description": "Solves a quadratic equation given coefficients a, b, and c.",
        "parameters": {
            "type": "object",
            "properties": {
                "a": {"type": "integer", "description": "Coefficient of the squared term"},
                "b": {"type": "integer", "description": "Coefficient of the linear term"},
                "c": {"type": "integer", "description": "Constant term"},
                "root_type": {"type": "string", "description": "Type of roots to return: 'real' or 'all'"}
            },
            "required": ["a", "b", "c"]
        }
    }
}

ステップ2:リクエストにfunction callingを設定

SambaNova Cloudにリクエストを送信する際、関数スキーマをtoolsパラメータに含め、tool_choiceに以下のいずれかを指定します。
  • auto:モデルが通常の応答とfunction callingを自動で選択。(デフォルト)
  • required:モデルにfunction callingを強制。
  • 特定の関数の呼び出しを強制するには、tool_choice = {"type": "function", "function": {"name": "solve_quadratic"}}を設定します。これにより、モデルは指定された関数のみを使用することが保証されます。
Example Python request
import openai
import cmath
import json

# Initialize the client with SN Cloud base URL and your API key
client = openai.OpenAI(
    base_url="https://api.sambanova.ai/v1", 
    api_key="YOUR SAMBANOVA API KEY"
)

def solve_quadratic(a, b, c, root_type="real"):
    """
    Solve a quadratic equation of the form ax^2 + bx + c = 0.
    """
    discriminant = b**2 - 4*a*c
    
    if root_type == "real":
        if discriminant < 0:
            return []  # No real roots
        else:
            root1 = (-b + discriminant**0.5) / (2 * a)
            root2 = (-b - discriminant**0.5) / (2 * a)
            return [root1, root2]
    else:
        root1 = (-b + cmath.sqrt(discriminant)) / (2 * a)
        root2 = (-b - cmath.sqrt(discriminant)) / (2 * a)
        return [
            {"real": root1.real, "imag": root1.imag},
            {"real": root2.real, "imag": root2.imag}
        ]


# Define user input and function schema
user_prompt = "Find all the roots of a quadratic equation given coefficients a = 3, b = -11, and c = -4."
messages = [

        {
            "role": "user",
            "content": user_prompt,
        }
    ]

tools = [
    {
        "type": "function",
        "function": {
            "name": "solve_quadratic",
            "description": "Solves a quadratic equation given coefficients a, b, and c.",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {"type": "integer", "description": "Coefficient of the squared term"},
                    "b": {"type": "integer", "description": "Coefficient of the linear term"},
                    "c": {"type": "integer", "description": "Constant term"},
                    "root_type": {"type": "string", "description": "Type of roots: 'real' or 'all'"}
                },
                "required": ["a", "b", "c"]
            }
        }
    }
]

response = client.chat.completions.create(
    model="Meta-Llama-3.3-70B-Instruct",
    messages=messages,
    tools=tools,
    tool_choice="required"
)

print(response)

ステップ3:ツール呼び出しの処理

モデルがfunction callingを選択した場合、応答にtool_callsフィールドが含まれます。この中からfunction callingの詳細を抽出し、指定されたパラメータを使って対応する関数を実行します。
Example code
response_message = response.choices[0].message
tool_calls = response_message.tool_calls

# If tool call is present
if tool_calls:
    tool_call = tool_calls[0]
    function_name = tool_call.function.name
    arguments = tool_call.function.arguments
    arguments = json.loads(arguments)

    # Call the appropriate function with parsed arguments
    if function_name == "solve_quadratic":
        result = solve_quadratic(
            a=arguments["a"],
            b=arguments["b"],
            c=arguments["c"],
            root_type=arguments.get("root_type", "real")
        )
        print(result)

ステップ4:関数の実行結果をモデルに返す

計算結果が得られたら、会話を続けるか出力を確認するためにモデルに結果を返します。
Example code
# Convert result to JSON string format to return to model
function_response = json.dumps({"result": result})

# Provide the function response back to the model as a message
messages.append(
    {
        "tool_call_id": tool_call.id,
        "role": "tool",
        "name": function_name,
        "content": function_response
    }
)

# Second API call to incorporate the function result into conversation
second_response = client.chat.completions.create(
    model="Meta-Llama-3.3-70B-Instruct",
    messages=messages,
    
)

# print the final response from the model
print(second_response.choices[0].message.content)

ステップ5:最終出力の例

以下に出力例を示します。
The roots of the quadratic equation with coefficients a = 3, b = -11, and c = -4 are 4 and -1/3.

OpenAI互換性を使用したend-to-endの実装例

End-to-end example using OpenAI compatibility
import openai
import cmath
import json

# Define the OpenAI client
client = openai.OpenAI(
    base_url="https://api.sambanova.ai/v1", 
    api_key="YOUR SAMBANOVA API KEY"
)

MODEL = 'Meta-Llama-3.3-70B-Instruct'

# Function to solve the quadratic equation
def solve_quadratic(a, b, c, root_type="real"):
    """
    Solve a quadratic equation of the form ax^2 + bx + c = 0.
    """
    discriminant = b**2 - 4*a*c
    
    if root_type == "real":
        if discriminant < 0:
            return []  # No real roots
        else:
            root1 = (-b + discriminant**0.5) / (2 * a)
            root2 = (-b - discriminant**0.5) / (2 * a)
            return [root1, root2]
    else:
        root1 = (-b + cmath.sqrt(discriminant)) / (2 * a)
        root2 = (-b - cmath.sqrt(discriminant)) / (2 * a)
        return [
            {"real": root1.real, "imag": root1.imag},
            {"real": root2.real, "imag": root2.imag}
        ]

# Function to run conversation and provide tool result back to the model
def run_conversation(user_prompt):
    # Initial conversation with user input
    messages = [
        {
            "role": "system",
            "content": "You are an assistant that can solve quadratic equations given coefficients a, b, and c."
        },
        {
            "role": "user",
            "content": user_prompt,
        }
    ]

    # Define the tool
    tools = [
        {
            "type": "function",
            "function": {
                "name": "solve_quadratic",
                "description": "Solve a quadratic equation given coefficients a, b, and c.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "a": {"type": "integer", "description": "Coefficient of the squared term."},
                        "b": {"type": "integer", "description": "Coefficient of the linear term."},
                        "c": {"type": "integer", "description": "Constant term."},
                        "root_type": {"type": "string", "description": "Type of roots: 'real' or 'all'."}
                    },
                    "required": ["a", "b", "c"],
                }
            }
        }
    ]

    # First API call to get model's response
    response = client.chat.completions.create(
        model=MODEL,
        messages=messages,
        tools=tools,
        tool_choice="auto",
        max_tokens=500
    )

    response_message = response.choices[0].message
    tool_calls = response_message.tool_calls

    # If tool call is present
    if tool_calls:
        tool_call = tool_calls[0]
        function_name = tool_call.function.name
        arguments = tool_call.function.arguments
        arguments = json.loads(arguments)

        # Call the appropriate function with parsed arguments
        if function_name == "solve_quadratic":
            result = solve_quadratic(
                a=arguments["a"],
                b=arguments["b"],
                c=arguments["c"],
                root_type=arguments.get("root_type", "real")
            )
            # Convert result to JSON string format to return to model
            function_response = json.dumps({"result": result})

            # Provide the function response back to the model as a message
            messages.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response
                }
            )

            # Second API call to incorporate the function result into conversation
            second_response = client.chat.completions.create(
                model=MODEL,
                messages=messages,
                max_tokens=500
            )

            # Return the final response from the model
            return second_response.choices[0].message.content

# Example user prompt
user_prompt = "Find all the roots of a quadratic equation given coefficients a = 3, b = -11, and c = -4."
print(run_conversation(user_prompt))

JSONモード

リクエスト時にresponse_format パラメータを json_objectに設定することで、モデルが有効なJSONを出力するように制御できます。
モデルが有効なJSONを生成できない場合、次のようなエラーが表示されます:Model did not output valid JSON
Example code
import openai

# Define the OpenAI client
client = openai.OpenAI(
    base_url="https://api.sambanova.ai/v1", 
    api_key="YOUR SAMBANOVA API KEY"
)

MODEL = 'Meta-Llama-3.3-70B-Instruct'


def run_conversation(user_prompt):
    # Initial conversation with user input
    messages = [
        {
            "role": "system",
            "content": "Always provide the response in this JSON format: {\"country\": \"name\", \"capital\": \"xx\"}"
        },

        {
            "role": "user",
            "content": user_prompt,
        }
    ]

    # First API call to get model's response
    response = client.chat.completions.create(
        model=MODEL,
        messages=messages,
        max_tokens=500,
        response_format = { "type": "json_object"},
        # stream = True
    )
    
    response_message = response.choices[0].message
    print(response_message)


run_conversation('what is the capital of Austria')
Example response
ChatCompletionMessage(content='{"country": "Austria", "capital": "Vienna"}', role='assistant', function_call=None, tool_calls=None)