Decisions in an agent
You call a decision model from your own code: a tool, a hook, or the application around the agent. It runs outside the agent loop, so it isn’t a tool the agent picks, and it doesn’t add messages to the conversation.
Ask from a tool
Section titled “Ask from a tool”A tool can hand part of its work to a decision model. This tool routes a customer
message to a team. Each tool call carries an invocation context, a handle to the agent
request it belongs to. The tool passes it to ask, so the decision’s tokens count toward
that request:
from strands import Agent, LLMDecisionModel, ToolContext, tool
decisions = LLMDecisionModel()
@tool(context=True)async def route_message(message: str, tool_context: ToolContext) -> str: """Send a customer message to the team that handles it.""" result = await decisions.ask( message, { "team": { "question": "Which team should handle this message?", "choices": ["billing", "shipping", "technical"], "uncertainty": False, }, }, invocation_context=tool_context.invocation_context, ) return f"Routed to {result.answers['team']}"
agent = Agent(tools=[route_message])result = agent("Route this message: my package never arrived.")print(result.invocation_context.usage)
# Typical output:# {'turns_taken': 2, 'inputTokens': 2162, 'outputTokens': 149, 'totalTokens': 2311}import { Agent, LLMDecisionModel, tool } from '@strands-agents/sdk'import { z } from 'zod'
const decisions = new LLMDecisionModel()
const routeMessage = tool({ name: 'route_message', description: 'Send a customer message to the team that handles it.', inputSchema: z.object({ message: z.string() }), callback: async ({ message }, context) => { const result = await decisions.ask( message, { team: { question: 'Which team should handle this message?', choices: ['billing', 'shipping', 'technical'], uncertainty: false, }, }, { ...(context?.invocationContext && { invocationContext: context.invocationContext, }), } ) return `Routed to ${result.answers.team}` },})
const agent = new Agent({ tools: [routeMessage] })const result = await agent.invoke('Route this message: my package never arrived.')console.log(result.invocationContext?.usage)
// Typical output:// { turnsTaken: 2, inputTokens: 2154, outputTokens: 142, totalTokens: 2296 }Hook events that belong to a request carry the same invocation context, so a hook passes
it to ask the same way.
Token usage
Section titled “Token usage”With the invocation context, the decision’s tokens add to the request’s usage, which the agent result reports. The agent’s own model metrics stay separate and cover only the agent’s model calls. A decision always runs to completion, even when the request has reached one of its invocation limits, and it doesn’t count as a turn. Its tokens do count toward the request’s token limits, so later turns can stop sooner.
Without the invocation context, the decision still reports its tokens in its own result, but the request doesn’t include them.
Approve tool calls
Section titled “Approve tool calls”HumanInTheLoop can ask a decision model whether each tool call needs a person’s
approval. An Uncertain answer requires approval:
from strands import Agent, LLMDecisionModelfrom strands.vended_interventions.hitl import HumanInTheLoop
agent = Agent(interventions=[HumanInTheLoop(classifier=LLMDecisionModel())])import { Agent, LLMDecisionModel } from '@strands-agents/sdk'import { HumanInTheLoop } from '@strands-agents/sdk/vended-interventions/hitl'
const agent = new Agent({ interventions: [ new HumanInTheLoop({ classifier: { decisionModel: new LLMDecisionModel() } }), ],})Human in the loop covers the risk criteria and the other classifier options.