AWSAWS Certified Generative AI Developer - Professional2026-102.1 Implement agentic AI solutions and tool integrations
Bound the loop before granting tools
Completed by the knowledge check
Learning objective
Implement the agent loop with Strands Agents model, tools, state, and termination criteria.
Core idea
An agent loop lets a model choose the next action after observing the previous result. In Strands Agents, an Agent combines the model, its instructions, and its available tools. The SDK handles the repeated exchange between model inference and tool execution until the model produces a final answer.
For a production design, distinguish model completion from application completion. A final answer ends the reasoning loop, but it does not prove that an order was changed, a tool succeeded, or the evidence supports the answer. You define the business success condition and enforce resource and permission boundaries outside the model’s instructions.
Treat autonomy as a bounded search for an acceptable result. Give the agent enough tools to discover a path, a state representation that preserves what happened, and a terminal outcome when the path cannot be completed safely. A prompt that says “stop after several attempts” is guidance, not an execution limit.
How it works
Select the model and tool contract
The Agent constructor accepts model, tools, and system_prompt. For Amazon Bedrock, the BedrockModel provider accepts model_id and region_name. Set these explicitly so that the deployed configuration identifies the model and invocation Region. Model eligibility and inference-profile boundaries belong to 1.2.1 and 1.2.4; an agent framework does not remove those constraints.
Define Python tools with the @tool decorator and register them in tools. Strands uses the function’s type hints and docstring to describe its contract to the model. A clear tool description separates reading an order from submitting a cancellation. Ambiguous descriptions make the model choose between operations without knowing their consequences.
The model proposes a tool name and arguments; application code performs the operation. Validate identifiers and business preconditions inside that code. Bind the caller’s authorization context through trusted application data rather than accepting a tenant or customer identity supplied by the model. A well-typed argument can still name an unauthorized resource.
Preserve observations and working state
Strands maintains conversation history in agent.messages. The history contains the context used for subsequent reasoning, including observations from tool use. The loop incorporates a tool result before asking the model what to do next. This is the feedback path that distinguishes an agent from a single inference call.
Keep authoritative application state separate from conversational assertions. For example, your application can track an order revision, the number of attempted lookups, a deadline, and whether an approval exists. Those fields are your design, not automatically created Strands properties. Update them from validated tool outcomes, not from a sentence in the assistant’s response. An AfterToolCallEvent callback receives event.result, including toolUseId, status, and content, after execution and before the result reaches the agent. Use it to classify outcomes and update attempt counters; it can also replace event.result, for example with status: "error" when validation fails.
A retry needs the observation that caused it. Preserve whether the tool returned no matching record, rejected permission, or failed operationally. Those outcomes call for different behavior: clarify an identifier, stop an unauthorized action, or retry a transient failure. Do not flatten all three into “try another tool.” Session persistence and AgentCore Memory are covered in 2.1.3.
Enforce termination at execution boundaries
Use separate terminal conditions for success, missing input, denied action, exhausted budget, and infrastructure failure. A successful run needs a verified result; a blocked run needs an explanation that does not imply the requested operation occurred.
Strands exposes lifecycle callbacks through HookProvider, registered using HookRegistry, and accepts hook instances through the hooks constructor parameter. A BeforeToolCallEvent callback can inspect event.tool_use before execution and set event.cancel_tool to cancel that tool call. This is a concrete interception point for checking your application-maintained attempt budget or approval requirement before another side effect.
Canceling a tool call is not equivalent to terminating all reasoning. The agent may receive the cancellation and continue. Enforce an overall deadline and inference-attempt budget in the code that owns execution as well. Count nested calls and retries against the same request budget; otherwise, each layer can obey its local limit while the complete request keeps running.
For an AgentCore-hosted agent, LifecycleConfiguration provides idleRuntimeSessionTimeout and maxLifetime. Their defaults are 900 and 28,800 seconds respectively. For microVM compute, each accepts 60–28,800 seconds; Instances compute accepts up to 1,209,600 seconds, or 14 days. These are compute-lifecycle settings, not business step limits. An active loop is not idle, and a long compute lifetime does not authorize more tool calls.
Key distinctions and trade-offs
Model autonomy versus application control: The model chooses among exposed operations. Your code controls whether their arguments and effects are permitted. Strands tool registration describes capability; it does not establish business authorization.
Conversation history versus authoritative state: History supports reasoning. A validated tool result establishes that an operation occurred. A model-generated summary cannot replace the operation’s returned identifier or status.
Natural completion versus bounded termination: A final answer is the loop’s ordinary completion path. A deadline or exhausted attempt budget is an application terminal outcome. Design both, because an agent can finish too early or continue without progress.
A larger tool set increases the available solution paths but also increases selection ambiguity and the number of privileged operations you must protect. Start with task-specific tools. Add a general-purpose operation only when the use case needs it and its authorization boundary remains enforceable.
Architecture / decision scenario
A support agent must explain why a delivery is late and cancel an order only when the customer requests cancellation and the order is eligible. The team configures Agent with an explicit BedrockModel, a read-only order-status tool, and a separate cancellation tool.
The backend binds the authenticated customer’s identity before entering the loop. It records the authoritative order revision from the lookup result and maintains a shared attempt count and deadline. These application controls prevent an uncertain lookup from becoming an unlimited investigation.
A BeforeToolCallEvent hook cancels a cancellation request when the required approval or remaining budget is absent. The cancellation tool independently checks ownership and eligibility before acting. If the operation succeeds, the tool returns its operation identifier, which becomes the evidence for completion.
If the model produces an answer claiming cancellation without that identifier, the application rejects the completion claim. If the tool fails transiently, the application permits a bounded retry; if ownership fails, it stops the action. The agent can still explain delivery status without presenting a denied cancellation as successful.
Common exam traps
- Treating
system_promptinstructions as a hard execution or authorization limit. - Assuming the model executes a tool directly without application enforcement.
- Treating a final answer as proof that the requested side effect succeeded.
- Using
agent.messagesas the authoritative record of a business transaction. - Assuming
event.cancel_toolterminates the entire agent loop. - Using an idle-session timeout to bound an active reasoning loop.
- Giving every nested agent its own fresh budget and calling the complete run bounded.
What to remember
- Configure
Agentwith an explicit model, tool set, and instructions. - Use
@toolcontracts to describe operations and application code to authorize them. - Preserve observations while keeping business state authoritative outside model prose.
- Use lifecycle hooks to intercept calls and execution-owner controls to bound the complete run.
- Verify success separately from model completion.
Knowledge check
A Strands support agent exposes a cancel_order tool whose customer_id argument the model fills in. The system_prompt tells the agent to cancel only eligible orders that belong to the signed-in customer. Where must ownership and eligibility be enforced so that a confused or manipulated model cannot cancel another customer’s order?
system_prompt , with stricter wording about ownershipA customer asks why an order is late and to cancel it. The agent’s final answer explains the delay and says the order is canceled, but the cancellation tool’s only result in the run has status: "error" and no operation identifier. What should the application return?
agent.messagesA BeforeToolCallEvent hook sets event.cancel_tool once the request’s shared attempt budget is spent. In testing, the agent keeps calling the model and proposing other tools for twenty minutes after the first cancellation. What change bounds the run?
idleRuntimeSessionTimeout so the session ends soonersystem_prompt instruction to stop when the budget is spentAn AfterToolCallEvent callback replaces every failed order lookup with the text “lookup failed, try another approach”. The failures are actually of three kinds: no matching record, permission denied, and a transient service error. What should the callback do instead?