🤖 AI Tools
Amazon Bedrock Converse API Tool Use Planner: toolConfig and toolSpec JSON Schemas, toolChoice Options, the tool_use Stop Reason Loop, toolResult Error Status, Inference Profiles, and boto3 Code
Plan a tool calling agent on Amazon Bedrock with the Converse API: write toolSpec definitions with inputSchema JSON, choose auto, any, or a forced tool, run the stopReason tool_use loop that returns toolResult blocks, mark tool errors with status, pick an inference profile ID, and get working boto3 code plus a test checklist.
0Reviews
Prompt
Act as an AWS generative AI engineer who builds tool using assistants on Amazon Bedrock with the model agnostic Converse API in boto3 (bedrock-runtime client, converse and converse_stream). Inputs: - Model and how it is reached: model ID or inference profile ID copied from the Bedrock console, plus region and whether model access is enabled: [ModelId] - Tools the assistant needs: name, what it does, its parameters with types and allowed values, and the backend call behind it: [ToolList] - Conversation flow: what the user asks, which tool should run when, and when the model must answer without a tool: [ConversationFlow] - Error policy: what happens on timeouts, not found, permission denied, and bad arguments: [ErrorPolicy] - Runtime limits: max tool rounds per request, latency budget, streaming or not, logging rules for PII: [RuntimeLimits] - Output format: [Format] Generate: 1. A toolConfig block: one toolSpec per tool in ToolList with a name, a description written for the model (when to use it and when not to), and inputSchema.json with types, enums, required fields, and additionalProperties false. 2. A toolChoice decision: auto for normal turns, any when a tool call is required, or tool with a name to force one tool, and a note to check that the chosen model supports that option. 3. A system prompt block (system list of text) that states the ConversationFlow rules and tells the model never to invent tool results. 4. The request loop in Python: call converse with modelId, messages, system, inferenceConfig (maxTokens, temperature), and toolConfig; when stopReason is tool_use, append the assistant message, run each toolUse block, and send one user message with matching toolResult blocks by toolUseId; stop at end_turn or the round cap from RuntimeLimits. 5. Error handling from ErrorPolicy: return a toolResult with status error and a short text the model can explain to the user, and retry throttling exceptions with backoff. 6. Argument validation before running any backend call, rejecting values outside the schema. 7. A test checklist: one prompt per path in ConversationFlow, a forced error case, a no tool question, and the usage fields (inputTokens, outputTokens) to log per round. Constraints: - Read the model ID from configuration; never hardcode or guess an ID. - Never execute a tool the model names unless it is in ToolList. - Keep secrets and PII out of logs per RuntimeLimits. No em dashes.
Instructions
Replace every [bracket] with your details before running. Works on ChatGPT, Claude, and Gemini.
Generated Output
This image was generated using the prompt above.

Examples
Example Input
ModelId: Claude Sonnet cross region inference profile ID from our console (us. prefix), us-east-1, model access granted; read from env BEDROCK_MODEL_ID ToolList: lookup_ticket(ticket_id: string like "IT-12345") returns status, assignee, last update from ServiceNow; reset_mfa(employee_email: string, method: enum "authenticator" | "sms") opens an MFA reset request, never resets directly ConversationFlow: employee asks about a ticket, call lookup_ticket; employee locked out of MFA, confirm their work email then call reset_mfa; policy questions answered from the system prompt without tools ErrorPolicy: ticket not found returns a friendly not found; ServiceNow timeout after 8 seconds, tell the user to try again; reset_mfa for an email outside @northwind.example is refused RuntimeLimits: max 3 tool rounds, non streaming, never log employee emails in full Format: toolConfig, toolChoice, system, loop code, errors, validation, tests
Example Output
TOOLCONFIG
tool_config = {"tools": [
{"toolSpec": {"name": "lookup_ticket",
"description": "Get status of an existing IT ticket. Use only when the user gives or asks about a ticket ID.",
"inputSchema": {"json": {"type": "object", "properties": {
"ticket_id": {"type": "string", "pattern": "^IT-[0-9]{5}$"}},
"required": ["ticket_id"], "additionalProperties": False}}}},
{"toolSpec": {"name": "reset_mfa",
"description": "Open an MFA reset request after the user confirms their work email. Does not reset MFA directly.",
"inputSchema": {"json": {"type": "object", "properties": {
"employee_email": {"type": "string"},
"method": {"type": "string", "enum": ["authenticator", "sms"]}},
"required": ["employee_email", "method"], "additionalProperties": False}}}}],
"toolChoice": {"auto": {}}}
TOOLCHOICE
auto. Policy questions need no tool, so any or a forced tool would be wrong here. Confirm the model supports toolChoice before using any.
SYSTEM
system = [{"text": "You are the Northwind IT helpdesk assistant. Use lookup_ticket for ticket questions. Before reset_mfa, ask the user to confirm their work email. Never invent ticket details or tool results."}]
LOOP
def run(messages):
for _ in range(3):
r = client.converse(modelId=os.environ["BEDROCK_MODEL_ID"], messages=messages,
system=system, toolConfig=tool_config,
inferenceConfig={"maxTokens": 800, "temperature": 0.2})
msg = r["output"]["message"]
messages.append(msg)
log_usage(r["usage"])
if r["stopReason"] != "tool_use":
return msg
results = []
for block in msg["content"]:
if "toolUse" in block:
tu = block["toolUse"]
results.append({"toolResult": run_tool(tu["toolUseId"], tu["name"], tu["input"])})
messages.append({"role": "user", "content": results})
return {"role": "assistant", "content": [{"text": "Sorry, I could not finish that. Please open a ticket."}]}
ERRORS
def run_tool(tid, name, args):
if name not in TOOLS:
return {"toolUseId": tid, "status": "error", "content": [{"text": "Unknown tool."}]}
try:
return {"toolUseId": tid, "content": [{"json": TOOLS[name](**validate(name, args))}]}
except NotFound:
return {"toolUseId": tid, "status": "error", "content": [{"text": "Ticket not found."}]}
except Timeout:
return {"toolUseId": tid, "status": "error", "content": [{"text": "ServiceNow timed out after 8s; ask the user to try again."}]}
Wrap converse in a retry with backoff on ThrottlingException.
VALIDATION
- ticket_id must match ^IT-[0-9]{5}$
- employee_email must end with @northwind.example, else refuse
- method must be authenticator or sms
TESTS
1. "What's happening with IT-48213?" calls lookup_ticket
2. "I'm locked out of MFA" asks to confirm email, then calls reset_mfa
3. "How long is the password policy?" gets no tool call
4. Email at another domain is refused
5. Forced timeout returns a status error result and a polite retry message
Log inputTokens and outputTokens per round, and emails masked as j***@northwind.example.