The Bedrock Converse API supports function calling (tool use), which lets a model request execution of locally defined functions. The model doesn’t execute functions directly. Instead, it returns a tool_use stop reason with the function name and input arguments. Your application runs the function and sends the result back to the model for a final response.
The following script defines a top_song tool that returns the most popular song for a given radio station call sign. The model receives a user question, decides to call the tool, and then incorporates the tool result into its final answer.
Create the script:
cat > bedrock-tool-use-demo.py << 'EOF'
#!/usr/bin/env python3
"""Demonstrate AWS Bedrock function calling (tool use) through Kong's AI Gateway"""
import logging
import json
import boto3
from botocore.exceptions import ClientError
GATEWAY_URL = "http://localhost:8000"
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
logger = logging.getLogger(__name__)
class StationNotFoundError(Exception):
"""Raised when a radio station isn't found."""
pass
def get_top_song(call_sign):
"""Returns the most popular song for the given radio station call sign."""
if call_sign == "WZPZ":
return "Elemental Hotel", "8 Storey Hike"
raise StationNotFoundError(f"Station {call_sign} not found.")
def generate_text(bedrock_client, model_id, tool_config, input_text):
"""Sends a message to Bedrock and handles tool use if the model requests it."""
logger.info("Sending request to model %s", model_id)
messages = [{"role": "user", "content": [{"text": input_text}]}]
response = bedrock_client.converse(
modelId=model_id, messages=messages, toolConfig=tool_config
)
output_message = response["output"]["message"]
messages.append(output_message)
stop_reason = response["stopReason"]
if stop_reason == "tool_use":
tool_requests = output_message["content"]
for tool_request in tool_requests:
if "toolUse" not in tool_request:
continue
tool = tool_request["toolUse"]
logger.info(
"Model requested tool: %s (ID: %s)", tool["name"], tool["toolUseId"]
)
if tool["name"] == "top_song":
try:
song, artist = get_top_song(tool["input"]["sign"])
tool_result = {
"toolUseId": tool["toolUseId"],
"content": [{"json": {"song": song, "artist": artist}}],
}
except StationNotFoundError as err:
tool_result = {
"toolUseId": tool["toolUseId"],
"content": [{"text": err.args[0]}],
"status": "error",
}
messages.append(
{"role": "user", "content": [{"toolResult": tool_result}]}
)
response = bedrock_client.converse(
modelId=model_id, messages=messages, toolConfig=tool_config
)
output_message = response["output"]["message"]
for content in output_message["content"]:
print(json.dumps(content, indent=4))
def main():
model_id = "cohere.command-r-v1:0"
input_text = "What is the most popular song on WZPZ?"
tool_config = {
"tools": [
{
"toolSpec": {
"name": "top_song",
"description": "Get the most popular song played on a radio station.",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"sign": {
"type": "string",
"description": "The call sign for the radio station for which you want the most popular song. Example call signs are WZPZ and WKRP.",
}
},
"required": ["sign"],
}
},
}
}
]
}
bedrock_client = boto3.client(
"bedrock-runtime",
endpoint_url=GATEWAY_URL,
region_name="us-west-2",
aws_access_key_id="dummy",
aws_secret_access_key="dummy",
)
try:
print(f"Question: {input_text}")
generate_text(bedrock_client, model_id, tool_config, input_text)
except ClientError as err:
message = err.response["Error"]["Message"]
logger.error("A client error occurred: %s", message)
print(f"A client error occurred: {message}")
else:
print(f"Finished generating text with model {model_id}.")
if __name__ == "__main__":
main()
EOF
The script creates a Boto3 client pointed at the AI Gateway endpoint (http://localhost:8000) instead of directly at AWS. AI Gateway handles AWS authentication, so the client uses dummy credentials. The allow_override: false setting in the plugin configuration ensures that Kong always uses its own credentials, regardless of what the client sends.
The conversation flow works as follows:
- The client sends the user question and tool definition to the model through Kong.
- The model responds with a
tool_use stop reason and the top_song function call with {"sign": "WZPZ"}.
- The client executes
get_top_song("WZPZ") locally and sends the result back to the model through Kong.
- The model generates a final text response that incorporates the tool result.