View a markdown version of this page

Optimize your agent for Amazon Bedrock AgentCore Runtime V2 - Amazon Bedrock AgentCore

Optimize your agent for Amazon Bedrock AgentCore Runtime V2

Amazon Bedrock AgentCore Runtime V2 starts your agent by restoring a snapshot. This changes how you structure your agent code. Work that your agent does at startup is captured in the snapshot and shared by every restored instance. Produce any value that must differ between requests, or that can expire, in your request handler instead. This topic describes how to structure your agent around startup work and per-request work so that it stays correct after each restore. For an overview of platform version V2, see Platform versions.

Your agent has two execution contexts:

Startup

Code that runs once as your process starts, before AgentCore Runtime takes the snapshot. AgentCore Runtime captures this code in the snapshot, and every instance inherits its results.

Request handling

The code in your /invocations handler. This code runs on every request on every instance.

Use one rule to decide where code belongs. Compute a value at startup if it stays the same for the life of the snapshot. Compute it in your handler if it varies per request or can expire. AgentCore Runtime takes one snapshot per agent version and uses it until you create or update the agent, so the life of the snapshot is the life of that version.

Initialize once at startup

Do expensive, reusable work as your process starts, before the snapshot. For example, import dependencies, load model weights, or read static configuration from your deployment bundle. With the AgentCore SDK, do this work at module scope, before you call app.run(). Your agent does not listen on port 8080 until app.run() runs, so no /ping can succeed and no snapshot can be taken until your startup work finishes. The snapshot captures a fully initialized agent by construction, and you do not need to gate /ping. Complete initialization within 120 seconds of startup. If your agent does not become healthy in time, the runtime fails its health check. For more information about the /ping and /invocations endpoints, see Understand the AgentCore Runtime service contract.

import json, pathlib from bedrock_agentcore.runtime import BedrockAgentCoreApp # Runs once at import, before app.run() starts the server and before the # snapshot. Every restored instance inherits these objects. MODEL = load_model_weights() SETTINGS = json.loads((pathlib.Path(__file__).parent / "agent.json").read_text()) app = BedrockAgentCoreApp() @app.entrypoint def invoke(payload): # Per-request work runs here on every instance. ... app.run() # starts listening on 8080; the snapshot is taken after this

If your agent runs its own HTTP server instead of the AgentCore SDK, report a healthy status from /ping only after initialization completes, so that the snapshot captures a fully initialized agent.

Read only data at startup that is the same for every instance and does not expire. Handle time-sensitive values, such as short-lived credentials, in your handler.

Note

Do not compute anything at startup that you change without redeploying. For example, a tool catalog fetched from AgentCore Gateway looks like an ideal startup value because it is slow and expensive to load, but caching it at startup freezes your agent’s tool inventory at the time of the snapshot.

Keep per-request state fresh

The snapshot is captured once and shared by every restored instance, so any value that your agent generates at startup is identical across instances and fixed at the time of the snapshot. Handle values that the snapshot cannot carry in your /invocations handler. The following table describes values to compute in your handler instead of at startup.

To do this Do it in the handler Reason

Generate random values, identifiers, or tokens

Call os.urandom(), secrets, or uuid.uuid4() on each request

os.urandom() returns fresh entropy only each time you call it after a restore. A value read at startup is copied into the snapshot and is identical on every instance, however good the entropy source was when it was read. The random module is likewise seeded at startup, so restored instances repeat the same sequence.

Read the current time

Compute it for each request

A timestamp captured at startup is fixed at the time of the snapshot.

Measure elapsed time

Take the reference timestamp in your handler

time.monotonic() does not advance across a restore, so a duration measured from a startup reference is wrong without looking wrong.

Use credentials or tokens

Refresh them when they expire

Credentials loaded at startup can expire before an instance starts.

Identify the instance or worker

Generate an id per request; do not derive it from the host

Every restored instance reports the same hostname (localhost) and PID (1), so using either as an id collapses metrics, log streams, and lock owners across the fleet.

Build reusable clients at startup, and compute per-request values on each call.

import os, time # Build reusable clients at startup, before the snapshot. Exercise them here too # (for example, with a warm-up call) so the setup the client caches — endpoint and # credential resolution, connection pool — is captured in the snapshot. client = build_client() warm_up(client) @app.entrypoint def invoke(payload): creds = get_credentials() # refreshed when expired, not read at startup request_id = os.urandom(16).hex() # unique per request now = time.time() # current time, not snapshot time # Handle the request.

Use snapshot-safe cryptographic libraries

When AgentCore Runtime restores an instance from a snapshot, a cryptographic library that cached random state at startup can reuse that state across instances. Your cryptographic libraries must use a snapshot-safe (snapsafe) build that reseeds after a restore.

Direct code deployments

The service-managed base image already includes a snapshot-safe build of its cryptographic libraries, so you do not need to take any action for them.

Bring-your-own cryptographic libraries

If you bring your own cryptographic libraries, for example in a container agent, use snapshot-safe builds so that they reseed after a restore. On Amazon Linux 2023, use openssl-snapsafe-libs.

Networking

Build clients at startup and expect a transparent reconnect

The socket you open at startup does not survive a restore, but the setup your client library caches around it — service-model parsing, endpoint resolution, credential resolution, and the connection pool — does. Construct and exercise your clients at startup, and expect the first call after a restore to re-establish the connection transparently.

Do not use the hostname or PID as a unique instance identifier

Every restored instance starts from the same snapshot and reports the same hostname and process ID. Generate a unique identifier in each request.

Avoid binding to a fixed source port

After a restore, the connection held at snapshot time is re-established, and a fixed source port can collide with that replacement within the instance. Restored instances are separate microVMs with their own network namespaces, so the conflict is within an instance, not across them.