Back to All
Ai/ml
Blog

4 AWS Bedrock AgentCore Lessons We Learned the Hard Way

Listen
4 AWS Bedrock AgentCore Lessons We Learned the Hard Way
13:58

At Mission Cloud, we've built several Bedrock AgentCore based AI systems for clients over the past year, each with its own set of hard-won lessons.

For one client, a data migration consultancy, we built a multi-agent system combining a guided validation workflow agent with a text-to-SQL agent. It reduced the onboarding of new organizations from months to weeks and cut validation cycles from weeks to days. In another instance, we built a closed-loop, RAG-grounded authoring tool that helps instructors draft new chapters strictly from the textbook publisher's own vetted back catalog, with zero tolerance for fabricated content. These are just two examples of many projects that we've delivered, and the lessons below are drawn from all of them. No two AWS architectures are ever quite the same, which is exactly where partner expertise makes the difference.

The Agentcore documentation is fairly extensive, but there are some things we learned once we moved from theory and simple demos into real, practical use cases like these. Here are four lessons we learned the hard way.

Short on time? Here's the quick version:

  • Start with the samples repo, not just the docs. The AWS Labs GitHub repo (especially the Customer Support Agent blueprint and Memory Dashboard) fills in the edge cases the official docs don't cover.
  • Check for known issues before building a workaround. AgentCore ships fixes and features fast; today's rough edge may already be resolved or in flight.
  • Enable semantic tool search early. If your tool catalog will grow or multiple agents will share it, turn on Gateway's semantic search from day one instead of retrofitting it later.
  • Default to AgentCore Memory over framework-native memory. Reach for it as soon as you need event filtering, long-term memory strategies, or namespace-based access control; reserve lightweight alternatives (like Strands' built-in memory) for genuinely simple, session-scoped use cases.

1. Visit the AWS Labs GitHub repo before you start building

The AWS developer guide taught us what features AgentCore has, while the Bedrock AgentCore Samples Repo taught us how to use them.

The documentation covers the single-agent, textbook use case well. Where it gets thin are the edge cases, like sharing memory context across multiple agents, which is exactly the kind of thing you'll need in production.

When AgentCore was released in preview, our team relied heavily on the Customer Support Agent blueprint to build our first POC and validate whether AgentCore was a suitable service to host our customers’ agents. Our use case had specific needs that included user authentication with Cognito, session conversation memory, and custom MCP tools. This accelerated our delivery and helped us understand how some of these integrations worked far better than the documentation could.

One sample worth calling out specifically is the AgentCore  Memory Dashboard, a React + FastAPI dashboard for browsing memory resources (events, turns, long-term records) by memoryId, actorId, and sessionId. Being able to see your memory store visually makes debugging multi-agent memory sharing much easier than piecing it together from API references alone.

When you are stuck, go find the sample before you go re-read the reference page for the third time. Docs describe the happy path; samples show you what it actually took to get a real use case working.

2. Check for known issues before you build a workaround

Over the last several years of working with AWS services, from tried-and-true offerings to the newest innovations, we’ve seen firsthand the level of investment AWS puts behind its services. AgentCore stands out for its strong support and rapid pace of innovation. New features continue to arrive faster than we can keep up with.

In the early months of AgentCore’s release, we filed a bug on a Runtime endpoint issue and received quick, responsive support. The specific bug: Runtime supports versioning, and endpoints are supposed to let you pin to a specific version. Instead, endpoints were only ever resolving to the latest version, regardless of which version you'd pinned. We needed this to work so we could keep a stable version running for our end users while testing a new one, as well as A/B testing some prompt iterations. We reported it, and it was fixed within 48 business hours.

AgentCore is a reliable choice for managing your agentic infrastructure. It keeps growing in features we didn't expect, often ones we assumed just months earlier would stay a "nice to have" in our projects. Therefore, before you build a workaround for a missing feature or a rough edge, it's worth checking whether it's already a known issue or in active development. AgentCore is evolving fast enough that today's gap may not be worth engineering around. If you need a new feature that would make your build work, file a ticket. The Service team may add it to their roadmap.

3. Enable semantic tool search before your tool catalog grows

If you're stuffing dozens of tool schemas into every prompt, you're burning thousands of tokens before the user even asks a question. A GitHub MCP server, for example, exposes around 40 tools, and loading all of their schemas adds roughly 10 to 15 KB of text per turn, or somewhere in the ballpark of 2,500 to 4,000 tokens, even if the agent only ends up calling two of them, according to GitHub’s analysis.

AgentCore Gateway has built-in semantic search for tools that lets agents query for relevant tools by natural language instead of loading the entire tool catalog's schema into context on every turn.

This matters most in multi-agent setups where different agents need access to large, overlapping tool catalogs. Instead of every agent paying the token cost of every tool's full schema, each call only pulls in the handful of tools relevant to that specific query. This cuts prompt bloat significantly, leading to lower costs and better response latency.

If you expect your tool count to grow past a handful or anticipate 2 or more agent streams to share these tools, it's worth enabling from day one rather than spending extra time retrofitting it later.

4. The Deep Dive: Default to AgentCore Memory

AgentCore Memory is purpose-built to handle the complexity that comes with production agent memory, and for most applications beyond the simplest proof of concept, it's the right default. That said, AgentCore Runtime is framework-agnostic, so if you have a niche use case with simple, well-defined memory needs, you're not locked in. Most popular agentic frameworks, including Strands (the open-source framework designed and maintained by AWS), have their own built-in memory handling that can serve as a lightweight alternative when it fits.

AgentCore Memory becomes the better choice as soon as requirements grow beyond raw conversation history into any of the following:

Event filtering at retrieval time

AgentCore's short-term memory supports metadata-tagged events filterable via ListEvents, out of the box. Equivalent filtering on a self-managed store typically requires a separate query layer, since S3 alone isn't natively queryable by attribute.

For our data validation agent, consultants' sessions get tagged with metadata like the current validation step, so we can pull just the events relevant to a specific step out of a much longer session history:

schema_issues = data.list_events(
    memoryId=memory_id,
    actorId=CONSULTANT_ID,
    sessionId=SESSION_ID,
    includePayloads=True,
    filter={
        "eventMetadata": [
            {
                "left": {"metadataKey": "validation_step"},
                "operator": "EQUALS_TO",
                "right": {"metadataValue": {"stringValue": "schema_validation"}},
            }
        ]
    },
)["events"]

Built-in long-term memory with easy customization.

AgentCore ships four extraction strategies (Semantic, User Preference, Summary, Episodic+Reflection) usable out of the box or customized via prompt overrides, plus a formal consolidation step to prevent duplicate or conflicting facts. Framework-native alternatives have no extraction logic of their own and require custom development to replicate this.

In the same validation agent, we use this to let consultants search across past sessions for issues previously flagged on a client engagement, without needing to remember which session it came up in:

print("\nSearching past sessions for validation issues flagged on this client engagement...")
issue_response = data_client.retrieve_memory_records(
    memoryId=memory_id,
    namespacePath=f"/summaries/{consultant_actor_id}/",
    searchCriteria={"searchQuery": "What data quality issues were flagged during validation?"}
)
for record in issue_response.get('memoryRecordSummaries', []):
    print(f"- Retrieved Record: {record}")

Namespaces for scoped access control.

AgentCore's namespace hierarchy and structured metadata filtering let long-term memory be scoped, filtered, and access-controlled by dimensions like actor, project, or compliance tier. Replicating this with a self-managed backend means building and maintaining your own convention with no service-level enforcement.

This matters for us because instructors often draft chapters across multiple textbook titles, and the house style or sourcing conventions they follow on one title shouldn't leak into another. Namespacing rules by instructor, and optionally by textbook title, keeps that knowledge properly scoped:

FACTS_TEMPLATE = "/authoring_rules/{actorId}/"
 
# Two instructors drafting solo, and the same two instructors contributing chapters to a shared textbook title.
ACTORS = [
    ("instructor_maria", "Note: always define new terms inline on first use, per this author's house style."),
    ("instructor_dave", " Note: prefers worked examples before formal proofs, per this author's house style."),
    ("algebra2ed/instructor_maria", "Note: Algebra II, 2nd Edition restricts all examples to the vetted problem-set bank in Chapters 1-6."),
    ("algebra2ed/instructor_dave", "Note: Algebra II, 2nd Edition requires every claim to cite a chapter/section, not just the textbook title."),
]
 
# Three query scopes this namespace template supports:
# namespace="/authoring_rules/instructor_maria/" -> one instructor's own house style (exact) 
# namespacePath="/authoring_rules/algebra2ed/" -> every instructor's rules for this textbook title 
# namespacePath="/authoring_rules/" -> everything, across all instructors and titles
QUERIES = [
    ("Exact — instructor_maria", "instructor_maria's known authoring rules", {"namespace": "/authoring_rules/instructor_maria/"}),
    ("Title — algebra2ed/*", "Algebra II, 2nd Edition authoring rules", {"namespacePath": "/authoring_rules/algebra2ed/"}),
    ("All — /authoring_rules/*", "all known authoring rules across instructors and titles", {"namespacePath": "/authoring_rules/"}),
]

For narrower cases where a lightweight, session-scoped approach is genuinely sufficient, like a POC with simple memory needs, Strands offers a quick way to add memory, including persisting it beyond the runtime session via an S3 backend. A community plugin even supports S3 vectors for long-term semantic memory. Setting up S3-based short-term memory in Strands takes just a few lines:

from strands import Agent
from strands.session.file_session_manager import FileSessionManager
from strands.session.s3_session_manager import S3SessionManager
 
# S3-based persistence
session_manager = S3SessionManager(
    session_id="user-123",
    bucket="my-agent-sessions",
    prefix="production/",
)
 
agent = Agent(session_manager=session_manager)

Default to AgentCore Memory for anything beyond the simplest session-scoped use case. Its filtering, long-term memory strategies, and namespace-based access control solve real problems that would otherwise require significant custom engineering, and its managed infrastructure means you get these capabilities without having to build and maintain them yourself. Starting with AgentCore Memory also saves you from a costly migration later, since framework-native memory has no clean upgrade path if your requirements outgrow it. Reach for a framework-native backend only when your use case is narrow enough that those capabilities are genuinely unlikely to be needed for the foreseeable future.

In Summary: AgentCore is worth building on now

Building past the demo stage taught us a few things we didn't expect going in: how costs actually scale in production, the debugging habits that only show up once multiple agents share memory, and the moments when "good enough" infrastructure beats the fully-featured option. AgentCore has earned a level of trust from our team that we don't extend to every managed service, largely because AWS has backed it with fixes and features to keep pace, plus enough samples to match the pace we're building at. If you're evaluating AgentCore for your own use case, our advice is simple: start with the samples repo, then run a quick ROI analysis to see where AgentCore Memory fits best. It’s most worth adopting where offloading the heavy lifting of state management and contextual summarization frees your team to focus strictly on core agent logic.

We learned these four lessons on real client work. You don't have to. Whether you're deciding if AgentCore is the right home for your agents, wiring up your first Gateway and Memory resources, or trying to get a promising demo to survive real users, our team has already mapped the terrain, including the parts the documentation doesn't cover yet.

Contact our team at Mission Cloud to discuss your agentic AI roadmap, and let's put our hard-won lessons to work for you.

6 minutes read