Advanced framework guide
Advanced Strands Agents
Scale Strands from static tool demos to governed agent workloads with genuine per-turn tool selection, explicit LLM-call policy, tracing, and deployment boundaries.
Advanced page: per-turn dynamic tool selection
Strands fires a BeforeModelCallEvent hook immediately before every model call, and only reads the agent's tool registry after that hook runs. Agent-Gantry uses this to re-select tools on every single model call — not just once per top-level run — which is the deepest re-selection tier Strands supports (it mirrors the depth of Google ADK's before_model_callback).
from agent_gantry.strands import StrandsAdapter
# Build an Agent with NO static tools; the hook injects the relevant
# slice before every model call, tracking the conversation turn by turn.
agent = StrandsAdapter(gantry).agent(
limit=5,
system_prompt="You are a helpful assistant.",
)
result = await agent.invoke_async(user_message) To wire the hook onto an agent you build yourself (or attach it after construction), use tool_hook() directly:
from strands import Agent
from agent_gantry.strands import StrandsAdapter
hook = StrandsAdapter(gantry).tool_hook(limit=5, score_threshold=0.2)
agent = Agent(tools=[], hooks=[hook]) Prefer a fixed tool set for a single run instead? The static path still works — select once and hand the framework's native objects to Agent(tools=[...]):
candidate_tools = await StrandsAdapter(gantry).select(
query=user_message,
limit=8,
)
agent = Agent(tools=candidate_tools) LLM calls and model policy
Centralize LLM calls through Strands' strands.models providers (Bedrock, Anthropic, OpenAI, and others) when possible; otherwise add middleware around the framework call via Strands hooks. The policy should select the provider, enforce budget ceilings, redact sensitive fields, emit token metrics, and decide whether tool results should be summarized before returning to the model.
response = llm_policy.complete(
framework="Strands",
model="primary-or-fallback-model",
messages=messages,
tools=framework_tools,
trace_id=trace_id,
) Production patterns
- Observability: attach trace IDs to every Strands run, LLM call, and tool execution — Strands' hook system (
BeforeToolCallEvent/AfterToolCallEvent) is a natural place to record them alongsidegantry.on_tool_call(cb). - Safety: keep high-risk tools behind explicit allowlists, human approval, or dry-run executors — Gantry's
SecurityPolicystill gates every call routed throughgantry.execute, even when the tool surface is re-selected per turn. - Resilience: add provider fallback for LLM calls and executor fallback for remote MCP/A2A tools.
- Evaluation: replay representative prompts with fixed tool snapshots before broadening dynamic retrieval.