Build a Memory-Powered Multi-Agent Financial Advisor with Strands SDK & Amazon Bedrock
Adeline Mako
·
2026-04-23
·
via DEV Community
<p><strong>Why Agents — Not Just Chatbots</strong></p> <p>A chatbot answers your question and forgets you. An <strong>AI agent</strong> takes actions, uses tools, and loops until the job is actually done. The difference isn't the model, it's the architecture.</p> <p><a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw51u1zxzo1ytup8zuyre.png" class="article-body-image-wrapper"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw51u1zxzo1ytup8zuyre.png" alt=" " width="800" height="302"></a></p> <p>The agent loop has four steps:</p> <ol> <li> <strong>Perceive</strong>- read the user's request plus any injected context (memory, RAG results, past turns)</li> <li> <strong>Plan</strong>- reason about what to do next; choose which tool(s) to call</li> <li> <strong>Act</strong>- call the chosen tool(s), APIs, or sub-agents</li> <li> <strong>Reflect</strong>- evaluate the results; decide whether the task is done or the loop should continue</li> </ol> <p>Unlike a simple LLM call, the agent decides autonomously when it has gathered enough information to answer and it keeps going until it has.</p> <p><strong>The Project: A Multi-Agent Financial Advisor</strong></p> <p>To make this concrete, we'll build a <strong>memory-powered multi-agent financial advisor</strong>. It:</p> <ul> <li>Accepts natural-language questions ("Should I rebalance my portfolio?")</li> <li>Delegates to specialist sub-agents for portfolio data, market prices, and financial news</li> <li>Uses <strong>Amazon Bedrock Guardrails</strong> to enforce compliance rules at every step</li> <li>Stores client preferences and past conversations using <strong>Amazon Bedrock AgentCore Memory</strong> </li> <li>Deploys as a serverless endpoint with a single <code>agentcore deploy</code> command</li> </ul> <p>The full stack:</p> <div class="table-wrapper-paragraph"><table> <thead> <tr> <th>Layer</th> <th>Technology</th> </tr> </thead> <tbody> <tr> <td>Agent framework</td> <td> <a href="https://github.com/strands-agents/sdk-python" rel="noopener noreferrer">Strands Agents SDK</a> (open-source)</td> </tr> <tr> <td>Foundation model</td> <td>Claude 3.5 Sonnet via Amazon Bedrock</td> </tr> <tr> <td>Safety layer</td> <td>Amazon Bedrock Guardrails</td> </tr> <tr> <td>Memory layer</td> <td>Amazon Bedrock AgentCore Memory</td> </tr> <tr> <td>Runtime</td> <td>Amazon Bedrock AgentCore Runtime</td> </tr> <tr> <td>Observability</td> <td>AWS CloudWatch + OpenTelemetry</td> </tr> </tbody> </table></div> <p><a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvha4c8lxnouayd1itbed.png" class="article-body-image-wrapper"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvha4c8lxnouayd1itbed.png" alt=" " width="800" height="401"></a></p> <p>The orchestrator agent receives every user request and intelligently routes sub-tasks to the right specialist. Results are synthesized into a single, coherent response.</p> <p><strong>Meet the Strands Agents SDK</strong></p> <p><a href="https://github.com/strands-agents/sdk-python" rel="noopener noreferrer">Strands</a> is an open-source Python framework from AWS Labs that makes building production agents dramatically simpler. You define tools, wrap them in an <code>Agent</code>, and Strands handles the loop.</p> <p><code>pip install strands-agents</code></p> <p>The core idea is minimal boilerplate. Three imports and a decorator are enough to expose any Python function to an agent as a callable tool.</p> <h2> Step 1 — Define Tools with <code>@tool</code> </h2> <p><a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6b1vxw3qw08fnhm93oth.png" class="article-body-image-wrapper"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6b1vxw3qw08fnhm93oth.png" alt=" " width="800" height="280"></a></p> <p>The <code>@tool</code> decorator does the heavy lifting automatically:</p> <ul> <li>Parses Python <strong>type hints</strong> into a JSON schema the model can read</li> <li>Converts the <strong>docstring</strong> into the tool's description (what the agent uses to decide when to call it)</li> <li>Handles invocation so the agent decides when, and with what arguments, to call the function </li> </ul> <div class="highlight js-code-highlight"> <pre class="highlight python"><code><span class="c1"># tools/financial_tools.py </span><span class="kn">from</span> <span class="n">strands</span> <span class="kn">import</span> <span class="n">tool</span> <span class="kn">from</span> <span class="n">typing</span> <span class="kn">import</span> <span class="n">Optional</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">get_portfolio_value</span><span class="p">(</span> <span class="n">client_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">include_unrealized_gains</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="bp">True</span> <span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Retrieve the current portfolio value and positions for a client.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">fetch_portfolio_data</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="n">include_unrealized_gains</span><span class="p">)</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">get_market_data</span><span class="p">(</span><span class="n">tickers</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">period</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">"</span><span class="s">1d</span><span class="sh">"</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Retrieve current market prices and key metrics for a list of tickers.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">fetch_market_prices</span><span class="p">(</span><span class="n">tickers</span><span class="p">,</span> <span class="n">period</span><span class="p">)</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">get_financial_news</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">max_results</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">5</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Retrieve recent financial news articles relevant to a query.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">fetch_news_feed</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">max_results</span><span class="p">)</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">get_risk_analysis</span><span class="p">(</span> <span class="n">client_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">risk_tolerance</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="bp">None</span> <span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Perform a risk analysis on a client</span><span class="sh">'</span><span class="s">s portfolio.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">compute_risk_metrics</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="n">risk_tolerance</span><span class="p">)</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">get_investment_recommendations</span><span class="p">(</span> <span class="n">client_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">goal</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">"</span><span class="s">growth</span><span class="sh">"</span><span class="p">,</span> <span class="n">time_horizon_years</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">10</span> <span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Generate personalised investment recommendations for a client.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">generate_recommendations</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="n">goal</span><span class="p">,</span> <span class="n">time_horizon_years</span><span class="p">)</span> </code></pre> </div> <p>Each function becomes a first-class tool — no YAML, no schema files, no extra config.</p> <h2> Step 2- Build Specialist Sub-Agents </h2> <p>Rather than one monolithic agent with 15 tools, we split responsibilities. Each specialist agent gets only the tools it needs, which keeps the system prompt focused and improves tool selection accuracy.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight python"><code><span class="c1"># agents/specialists.py </span><span class="kn">from</span> <span class="n">strands</span> <span class="kn">import</span> <span class="n">Agent</span> <span class="kn">from</span> <span class="n">strands.models</span> <span class="kn">import</span> <span class="n">BedrockModel</span> <span class="kn">from</span> <span class="n">tools.financial_tools</span> <span class="kn">import</span> <span class="p">(</span> <span class="n">get_portfolio_value</span><span class="p">,</span> <span class="n">get_risk_analysis</span><span class="p">,</span> <span class="n">get_market_data</span><span class="p">,</span> <span class="n">get_financial_news</span><span class="p">,</span> <span class="p">)</span> <span class="n">MODEL_ID</span> <span class="o">=</span> <span class="sh">"</span><span class="s">us.anthropic.claude-3-5-sonnet-20241022-v2:0</span><span class="sh">"</span> <span class="k">def</span> <span class="nf">_make_model</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="n">BedrockModel</span><span class="p">:</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">model_id</span><span class="sh">"</span><span class="p">:</span> <span class="n">MODEL_ID</span><span class="p">,</span> <span class="sh">"</span><span class="s">region_name</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">us-east-1</span><span class="sh">"</span><span class="p">}</span> <span class="k">if</span> <span class="n">guardrail_id</span><span class="p">:</span> <span class="n">kwargs</span><span class="p">[</span><span class="sh">"</span><span class="s">guardrail_id</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="n">guardrail_id</span> <span class="n">kwargs</span><span class="p">[</span><span class="sh">"</span><span class="s">guardrail_version</span><span class="sh">"</span><span class="p">]</span> <span class="o">=</span> <span class="sh">"</span><span class="s">DRAFT</span><span class="sh">"</span> <span class="k">return</span> <span class="nc">BedrockModel</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> <span class="k">def</span> <span class="nf">create_portfolio_agent</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="n">Agent</span><span class="p">:</span> <span class="k">return</span> <span class="nc">Agent</span><span class="p">(</span> <span class="n">model</span><span class="o">=</span><span class="nf">_make_model</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">),</span> <span class="n">system_prompt</span><span class="o">=</span><span class="p">(</span> <span class="sh">"</span><span class="s">You are a Portfolio Specialist. Analyse holdings, risk metrics, </span><span class="sh">"</span> <span class="sh">"</span><span class="s">and P&L. Be precise and cite specific numbers.</span><span class="sh">"</span> <span class="p">),</span> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_portfolio_value</span><span class="p">,</span> <span class="n">get_risk_analysis</span><span class="p">],</span> <span class="p">)</span> <span class="k">def</span> <span class="nf">create_market_data_agent</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="n">Agent</span><span class="p">:</span> <span class="k">return</span> <span class="nc">Agent</span><span class="p">(</span> <span class="n">model</span><span class="o">=</span><span class="nf">_make_model</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">),</span> <span class="n">system_prompt</span><span class="o">=</span><span class="p">(</span> <span class="sh">"</span><span class="s">You are a Market Data Specialist. Provide current prices, </span><span class="sh">"</span> <span class="sh">"</span><span class="s">52-week ranges, and key indices. Stick to facts.</span><span class="sh">"</span> <span class="p">),</span> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_market_data</span><span class="p">],</span> <span class="p">)</span> <span class="k">def</span> <span class="nf">create_news_agent</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="n">Agent</span><span class="p">:</span> <span class="k">return</span> <span class="nc">Agent</span><span class="p">(</span> <span class="n">model</span><span class="o">=</span><span class="nf">_make_model</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">),</span> <span class="n">system_prompt</span><span class="o">=</span><span class="p">(</span> <span class="sh">"</span><span class="s">You are a Financial News Analyst. Summarise recent news and </span><span class="sh">"</span> <span class="sh">"</span><span class="s">provide sentiment analysis. Be objective.</span><span class="sh">"</span> <span class="p">),</span> <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">get_financial_news</span><span class="p">],</span> <span class="p">)</span> </code></pre> </div> <h2> Step 3- The Orchestrator & Agent-as-Tool Pattern </h2> <p>The orchestrator doesn't call specialist agents directly, it treats them as <strong>tools</strong>. This is the agent-as-tool pattern: each sub-agent is wrapped in a <code>@tool</code> function, so the orchestrator's model reasons about <em>which</em> specialist to consult, exactly like it would choose any other tool.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight python"><code><span class="c1"># agents/orchestrator.py </span><span class="kn">from</span> <span class="n">strands</span> <span class="kn">import</span> <span class="n">Agent</span><span class="p">,</span> <span class="n">tool</span> <span class="kn">from</span> <span class="n">strands.models</span> <span class="kn">import</span> <span class="n">BedrockModel</span> <span class="kn">from</span> <span class="n">agents.specialists</span> <span class="kn">import</span> <span class="p">(</span> <span class="n">create_portfolio_agent</span><span class="p">,</span> <span class="n">create_market_data_agent</span><span class="p">,</span> <span class="n">create_news_agent</span><span class="p">,</span> <span class="p">)</span> <span class="kn">from</span> <span class="n">tools.financial_tools</span> <span class="kn">import</span> <span class="n">get_investment_recommendations</span> <span class="k">def</span> <span class="nf">_build_specialist_tools</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span><span class="p">):</span> <span class="n">portfolio_agent</span> <span class="o">=</span> <span class="nf">create_portfolio_agent</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">)</span> <span class="n">market_agent</span> <span class="o">=</span> <span class="nf">create_market_data_agent</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">)</span> <span class="n">news_agent</span> <span class="o">=</span> <span class="nf">create_news_agent</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">)</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">ask_portfolio_agent</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Delegate a portfolio analysis or risk question to the Portfolio Specialist Agent.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">str</span><span class="p">(</span><span class="nf">portfolio_agent</span><span class="p">(</span><span class="n">query</span><span class="p">))</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">ask_market_data_agent</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Delegate a market data or pricing question to the Market Data Specialist Agent.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">str</span><span class="p">(</span><span class="nf">market_agent</span><span class="p">(</span><span class="n">query</span><span class="p">))</span> <span class="nd">@tool</span> <span class="k">def</span> <span class="nf">ask_news_agent</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Delegate a news or sentiment analysis question to the News Analyst Agent.</span><span class="sh">"""</span> <span class="k">return</span> <span class="nf">str</span><span class="p">(</span><span class="nf">news_agent</span><span class="p">(</span><span class="n">query</span><span class="p">))</span> <span class="k">return</span> <span class="p">[</span><span class="n">ask_portfolio_agent</span><span class="p">,</span> <span class="n">ask_market_data_agent</span><span class="p">,</span> <span class="n">ask_news_agent</span><span class="p">]</span> <span class="n">ORCHESTRATOR_PROMPT</span> <span class="o">=</span> <span class="sh">"""</span><span class="s"> You are a Senior Financial Advisor AI. Your role is to provide comprehensive, personalised financial guidance. You have three specialist agents available: - Portfolio Specialist: portfolio values, positions, risk metrics - Market Data Specialist: prices, indices, volatility - News Analyst: financial news and sentiment Always delegate to the right specialist(s), then synthesise their findings into a clear, actionable response for the client. </span><span class="sh">"""</span> <span class="k">def</span> <span class="nf">create_financial_advisor</span><span class="p">(</span> <span class="n">guardrail_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">memory_context</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">""</span><span class="p">,</span> <span class="n">model_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">"</span><span class="s">us.anthropic.claude-3-5-sonnet-20241022-v2:0</span><span class="sh">"</span><span class="p">,</span> <span class="p">)</span> <span class="o">-></span> <span class="n">Agent</span><span class="p">:</span> <span class="n">specialist_tools</span> <span class="o">=</span> <span class="nf">_build_specialist_tools</span><span class="p">(</span><span class="n">guardrail_id</span><span class="p">)</span> <span class="n">system_prompt</span> <span class="o">=</span> <span class="n">ORCHESTRATOR_PROMPT</span> <span class="k">if</span> <span class="n">memory_context</span><span class="p">:</span> <span class="n">system_prompt</span> <span class="o">+=</span> <span class="sa">f</span><span class="sh">"</span><span class="se">\n\n</span><span class="s">## Client Memory</span><span class="se">\n</span><span class="si">{</span><span class="n">memory_context</span><span class="si">}</span><span class="sh">"</span> <span class="n">model_kwargs</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">model_id</span><span class="sh">"</span><span class="p">:</span> <span class="n">model_id</span><span class="p">,</span> <span class="sh">"</span><span class="s">region_name</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">us-east-1</span><span class="sh">"</span><span class="p">}</span> <span class="k">if</span> <span class="n">guardrail_id</span><span class="p">:</span> <span class="n">model_kwargs</span><span class="p">.</span><span class="nf">update</span><span class="p">({</span><span class="sh">"</span><span class="s">guardrail_id</span><span class="sh">"</span><span class="p">:</span> <span class="n">guardrail_id</span><span class="p">,</span> <span class="sh">"</span><span class="s">guardrail_version</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">DRAFT</span><span class="sh">"</span><span class="p">})</span> <span class="k">return</span> <span class="nc">Agent</span><span class="p">(</span> <span class="n">model</span><span class="o">=</span><span class="nc">BedrockModel</span><span class="p">(</span><span class="o">**</span><span class="n">model_kwargs</span><span class="p">),</span> <span class="n">system_prompt</span><span class="o">=</span><span class="n">system_prompt</span><span class="p">,</span> <span class="n">tools</span><span class="o">=</span><span class="n">specialist_tools</span> <span class="o">+</span> <span class="p">[</span><span class="n">get_investment_recommendations</span><span class="p">],</span> <span class="p">)</span> </code></pre> </div> <p>When the user asks "Should I rebalance my portfolio given today's market?", the orchestrator:</p> <ol> <li>Calls <code>ask_portfolio_agent</code> → gets current holdings & risk score</li> <li>Calls <code>ask_market_data_agent</code> → gets today's index moves</li> <li>Calls <code>ask_news_agent</code> → gets relevant headlines</li> <li>Synthesizes everything into a single coherent recommendation</li> </ol> <h2> Step 4- Persistent Memory Across Sessions </h2> <p>Without memory, every conversation starts cold. AgentCore Memory gives the agent a persistent, semantic store, the agent remembers past interactions and client preferences across sessions.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight python"><code><span class="c1"># memory/memory_manager.py </span><span class="kn">import</span> <span class="n">boto3</span> <span class="kn">from</span> <span class="n">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">field</span> <span class="k">class</span> <span class="nc">MemoryManager</span><span class="p">:</span> <span class="sh">"""</span><span class="s"> Wraps Amazon Bedrock AgentCore Memory with a local in-process fallback so the demo runs without any AWS credentials. </span><span class="sh">"""</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span> <span class="n">self</span><span class="p">,</span> <span class="n">memory_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">session_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">region</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">"</span><span class="s">us-east-1</span><span class="sh">"</span><span class="p">,</span> <span class="n">use_local_fallback</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="p">):</span> <span class="n">self</span><span class="p">.</span><span class="n">memory_id</span> <span class="o">=</span> <span class="n">memory_id</span> <span class="n">self</span><span class="p">.</span><span class="n">session_id</span> <span class="o">=</span> <span class="n">session_id</span> <span class="ow">or</span> <span class="sh">"</span><span class="s">default</span><span class="sh">"</span> <span class="n">self</span><span class="p">.</span><span class="n">use_local</span> <span class="o">=</span> <span class="n">use_local_fallback</span> <span class="ow">or</span> <span class="p">(</span><span class="n">memory_id</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">)</span> <span class="n">self</span><span class="p">.</span><span class="n">_local_memory</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">dict</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">self</span><span class="p">.</span><span class="n">use_local</span><span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">_client</span> <span class="o">=</span> <span class="n">boto3</span><span class="p">.</span><span class="nf">client</span><span class="p">(</span><span class="sh">"</span><span class="s">bedrock-agentcore</span><span class="sh">"</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="n">region</span><span class="p">)</span> <span class="k">def</span> <span class="nf">save_turn</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">user_input</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">agent_response</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="bp">None</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Persist a conversation turn.</span><span class="sh">"""</span> <span class="k">if</span> <span class="n">self</span><span class="p">.</span><span class="n">use_local</span><span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">_local_memory</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span> <span class="p">{</span><span class="sh">"</span><span class="s">user</span><span class="sh">"</span><span class="p">:</span> <span class="n">user_input</span><span class="p">,</span> <span class="sh">"</span><span class="s">assistant</span><span class="sh">"</span><span class="p">:</span> <span class="n">agent_response</span><span class="p">}</span> <span class="p">)</span> <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">_client</span><span class="p">.</span><span class="nf">save_memory</span><span class="p">(</span> <span class="n">memoryId</span><span class="o">=</span><span class="n">self</span><span class="p">.</span><span class="n">memory_id</span><span class="p">,</span> <span class="n">sessionId</span><span class="o">=</span><span class="n">self</span><span class="p">.</span><span class="n">session_id</span><span class="p">,</span> <span class="n">messages</span><span class="o">=</span><span class="p">[</span> <span class="p">{</span><span class="sh">"</span><span class="s">role</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">user</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">content</span><span class="sh">"</span><span class="p">:</span> <span class="n">user_input</span><span class="p">},</span> <span class="p">{</span><span class="sh">"</span><span class="s">role</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">assistant</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">content</span><span class="sh">"</span><span class="p">:</span> <span class="n">agent_response</span><span class="p">},</span> <span class="p">],</span> <span class="p">)</span> <span class="k">def</span> <span class="nf">get_recent_context</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">max_turns</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span> <span class="n">query</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="sh">"""</span><span class="s">Return a formatted string of recent memory to inject into the system prompt.</span><span class="sh">"""</span> <span class="k">if</span> <span class="n">self</span><span class="p">.</span><span class="n">use_local</span><span class="p">:</span> <span class="n">recent</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">_local_memory</span><span class="p">[</span><span class="o">-</span><span class="n">max_turns</span><span class="p">:]</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">recent</span><span class="p">:</span> <span class="k">return</span> <span class="sh">""</span> <span class="n">lines</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">Previous conversation context:</span><span class="sh">"</span><span class="p">]</span> <span class="k">for</span> <span class="n">turn</span> <span class="ow">in</span> <span class="n">recent</span><span class="p">:</span> <span class="n">lines</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">User: </span><span class="si">{</span><span class="n">turn</span><span class="p">[</span><span class="sh">'</span><span class="s">user</span><span class="sh">'</span><span class="p">]</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span> <span class="n">lines</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Assistant: </span><span class="si">{</span><span class="n">turn</span><span class="p">[</span><span class="sh">'</span><span class="s">assistant</span><span class="sh">'</span><span class="p">][</span><span class="si">:</span><span class="mi">200</span><span class="p">]</span><span class="si">}</span><span class="s">...</span><span class="sh">"</span><span class="p">)</span> <span class="k">return</span> <span class="sh">"</span><span class="se">\n</span><span class="sh">"</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">lines</span><span class="p">)</span> <span class="n">response</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">_client</span><span class="p">.</span><span class="nf">retrieve_memory</span><span class="p">(</span> <span class="n">memoryId</span><span class="o">=</span><span class="n">self</span><span class="p">.</span><span class="n">memory_id</span><span class="p">,</span> <span class="n">sessionId</span><span class="o">=</span><span class="n">self</span><span class="p">.</span><span class="n">session_id</span><span class="p">,</span> <span class="n">query</span><span class="o">=</span><span class="n">query</span> <span class="ow">or</span> <span class="sh">"</span><span class="s">recent client interactions</span><span class="sh">"</span><span class="p">,</span> <span class="n">maxResults</span><span class="o">=</span><span class="n">max_turns</span><span class="p">,</span> <span class="p">)</span> <span class="k">return</span> <span class="sh">"</span><span class="se">\n</span><span class="sh">"</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="sh">"</span><span class="s">content</span><span class="sh">"</span><span class="p">]</span> <span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="n">response</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">results</span><span class="sh">"</span><span class="p">,</span> <span class="p">[]))</span> </code></pre> </div> <p>Memory context is injected into the orchestrator's system prompt on every turn:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight python"><code><span class="n">memory</span> <span class="o">=</span> <span class="nc">MemoryManager</span><span class="p">(</span><span class="n">use_local_fallback</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="c1"># swap to AWS for prod </span><span class="n">context</span> <span class="o">=</span> <span class="n">memory</span><span class="p">.</span><span class="nf">get_recent_context</span><span class="p">(</span><span class="n">query</span><span class="o">=</span><span class="n">user_input</span><span class="p">)</span> <span class="n">advisor</span> <span class="o">=</span> <span class="nf">create_financial_advisor</span><span class="p">(</span><span class="n">memory_context</span><span class="o">=</span><span class="n">context</span><span class="p">)</span> <span class="n">response</span> <span class="o">=</span> <span class="nf">advisor</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span> <span class="n">memory</span><span class="p">.</span><span class="nf">save_turn</span><span class="p">(</span><span class="n">user_input</span><span class="p">,</span> <span class="nf">str</span><span class="p">(</span><span class="n">response</span><span class="p">))</span> </code></pre> </div> <blockquote> <p><strong>Why this matters:</strong> "Persistent memory lets the agent remember past conversations and client preferences, enabling truly personalized financial guidance at scale."</p> </blockquote> <h2> Step 5- Compliance with Bedrock Guardrails </h2> <p>Financial applications have strict compliance requirements: no guaranteed return promises, no off-topic advice, PII must be redacted. Bedrock Guardrails handles all of this at the infrastructure level, <strong>zero code changes</strong> in your agent logic.</p> <p><a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flo8xbls0p8a3qxhxnirh.png" class="article-body-image-wrapper"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flo8xbls0p8a3qxhxnirh.png" alt=" " width="800" height="287"></a></p> <p>Guardrails are applied at <strong>both</strong> the input and output layers:</p> <ul> <li> <strong>Input filter:</strong> blocks prompt injection, off-topic requests (medical, legal), and PII before the LLM ever sees them</li> <li> <strong>Output filter:</strong> checks grounding, redacts any leaked PII, blocks harmful or hallucinated content</li> </ul> <p>Here's how we configure it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight python"><code><span class="c1"># guardrails/config.py </span><span class="kn">import</span> <span class="n">boto3</span> <span class="kn">from</span> <span class="n">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span><span class="p">,</span> <span class="n">field</span> <span class="kn">from</span> <span class="n">typing</span> <span class="kn">import</span> <span class="n">Optional</span> <span class="nd">@dataclass</span> <span class="k">class</span> <span class="nc">GuardrailsConfig</span><span class="p">:</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">"</span><span class="s">financial-advisor-guardrail</span><span class="sh">"</span> <span class="n">content_filter_strength</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">"</span><span class="s">HIGH</span><span class="sh">"</span> <span class="n">denied_topics</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">dict</span><span class="p">]</span> <span class="o">=</span> <span class="nf">field</span><span class="p">(</span><span class="n">default_factory</span><span class="o">=</span><span class="k">lambda</span><span class="p">:</span> <span class="p">[</span> <span class="p">{</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">Non-Financial Advice</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">definition</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">Any advice outside personal finance, investments, or markets.</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">examples</span><span class="sh">"</span><span class="p">:</span> <span class="p">[</span><span class="sh">"</span><span class="s">medical diagnosis</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">legal advice</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">relationship counselling</span><span class="sh">"</span><span class="p">]},</span> <span class="p">{</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">Guaranteed Returns</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">definition</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">Claims that any investment guarantees specific returns.</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">examples</span><span class="sh">"</span><span class="p">:</span> <span class="p">[</span><span class="sh">"</span><span class="s">guaranteed 20% return</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">risk-free investment</span><span class="sh">"</span><span class="p">]},</span> <span class="p">])</span> <span class="n">pii_redaction_types</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="nf">field</span><span class="p">(</span><span class="n">default_factory</span><span class="o">=</span><span class="k">lambda</span><span class="p">:</span> <span class="p">[</span> <span class="sh">"</span><span class="s">US_SOCIAL_SECURITY_NUMBER</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">CREDIT_DEBIT_CARD_NUMBER</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">US_BANK_ACCOUNT_NUMBER</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">EMAIL</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">PHONE</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">NAME</span><span class="sh">"</span><span class="p">,</span> <span class="p">])</span> <span class="n">blocked_words</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="nf">field</span><span class="p">(</span><span class="n">default_factory</span><span class="o">=</span><span class="k">lambda</span><span class="p">:</span> <span class="p">[</span> <span class="sh">"</span><span class="s">guaranteed returns</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">risk-free investment</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">100% safe</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">cannot lose</span><span class="sh">"</span><span class="p">,</span> <span class="p">])</span> <span class="n">enable_grounding_check</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="bp">True</span> <span class="n">grounding_threshold</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.7</span> <span class="k">def</span> <span class="nf">get_or_create_guardrail</span><span class="p">(</span> <span class="n">config</span><span class="p">:</span> <span class="n">GuardrailsConfig</span> <span class="o">|</span> <span class="bp">None</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">region</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="sh">"</span><span class="s">us-east-1</span><span class="sh">"</span><span class="p">,</span> <span class="p">)</span> <span class="o">-></span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span> <span class="sh">"""</span><span class="s">Create (or retrieve existing) guardrail and return its ID.</span><span class="sh">"""</span> <span class="n">config</span> <span class="o">=</span> <span class="n">config</span> <span class="ow">or</span> <span class="nc">GuardrailsConfig</span><span class="p">()</span> <span class="n">client</span> <span class="o">=</span> <span class="n">boto3</span><span class="p">.</span><span class="nf">client</span><span class="p">(</span><span class="sh">"</span><span class="s">bedrock</span><span class="sh">"</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="n">region</span><span class="p">)</span> <span class="c1"># Check if it already exists </span> <span class="k">for</span> <span class="n">g</span> <span class="ow">in</span> <span class="n">client</span><span class="p">.</span><span class="nf">list_guardrails</span><span class="p">().</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">guardrails</span><span class="sh">"</span><span class="p">,</span> <span class="p">[]):</span> <span class="k">if</span> <span class="n">g</span><span class="p">[</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">]</span> <span class="o">==</span> <span class="n">config</span><span class="p">.</span><span class="n">name</span><span class="p">:</span> <span class="k">return</span> <span class="n">g</span><span class="p">[</span><span class="sh">"</span><span class="s">id</span><span class="sh">"</span><span class="p">]</span> <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="nf">create_guardrail</span><span class="p">(</span> <span class="n">name</span><span class="o">=</span><span class="n">config</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="n">contentPolicyConfig</span><span class="o">=</span><span class="p">{</span> <span class="sh">"</span><span class="s">filtersConfig</span><span class="sh">"</span><span class="p">:</span> <span class="p">[</span> <span class="p">{</span><span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">SEXUAL</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">inputStrength</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">content_filter_strength</span><span class="p">,</span> <span class="sh">"</span><span class="s">outputStrength</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">content_filter_strength</span><span class="p">},</span> <span class="p">{</span><span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">VIOLENCE</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">inputStrength</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">content_filter_strength</span><span class="p">,</span> <span class="sh">"</span><span class="s">outputStrength</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">content_filter_strength</span><span class="p">},</span> <span class="p">{</span><span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">HATE</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">inputStrength</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">content_filter_strength</span><span class="p">,</span> <span class="sh">"</span><span class="s">outputStrength</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">content_filter_strength</span><span class="p">},</span> <span class="p">]</span> <span class="p">},</span> <span class="n">topicPolicyConfig</span><span class="o">=</span><span class="p">{</span><span class="sh">"</span><span class="s">topicsConfig</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">denied_topics</span><span class="p">},</span> <span class="n">sensitiveInformationPolicyConfig</span><span class="o">=</span><span class="p">{</span> <span class="sh">"</span><span class="s">piiEntitiesConfig</span><span class="sh">"</span><span class="p">:</span> <span class="p">[</span> <span class="p">{</span><span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">:</span> <span class="n">t</span><span class="p">,</span> <span class="sh">"</span><span class="s">action</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">ANONYMIZE</span><span class="sh">"</span><span class="p">}</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">config</span><span class="p">.</span><span class="n">pii_redaction_types</span> <span class="p">]</span> <span class="p">},</span> <span class="n">wordPolicyConfig</span><span class="o">=</span><span class="p">{</span> <span class="sh">"</span><span class="s">wordsConfig</span><span class="sh">"</span><span class="p">:</span> <span class="p">[{</span><span class="sh">"</span><span class="s">text</span><span class="sh">"</span><span class="p">:</span> <span class="n">w</span><span class="p">}</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="n">config</span><span class="p">.</span><span class="n">blocked_words</span><span class="p">]</span> <span class="p">},</span> <span class="n">groundingPolicyConfig</span><span class="o">=</span><span class="p">{</span> <span class="sh">"</span><span class="s">filtersConfig</span><span class="sh">"</span><span class="p">:</span> <span class="p">[</span> <span class="p">{</span><span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">GROUNDING</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">threshold</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">grounding_threshold</span><span class="p">},</span> <span class="p">{</span><span class="sh">"</span><span class="s">type</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">RELEVANCE</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">threshold</span><span class="sh">"</span><span class="p">:</span> <span class="n">config</span><span class="p">.</span><span class="n">grounding_threshold</span><span class="p">},</span> <span class="p">]</span> <span class="p">}</span> <span class="k">if</span> <span class="n">config</span><span class="p">.</span><span class="n">enable_grounding_check</span> <span class="k">else</span> <span class="p">{},</span> <span class="p">)</span> <span class="k">return</span> <span class="n">response</span><span class="p">[</span><span class="sh">"</span><span class="s">guardrailId</span><span class="sh">"</span><span class="p">]</span> </code></pre> </div> <p>Attach the guardrail ID to the <code>BedrockModel</code> and every request, input AND output, is automatically screened.</p> <h2> Step 6- Deploy to Production with AgentCore Runtime </h2> <p>AgentCore Runtime is a serverless execution environment for agents. It handles auto-scaling, session management, health checks, and observability out of the box.</p> <p><a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra2o1jnt26p8crrod2ys.png" class="article-body-image-wrapper"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra2o1jnt26p8crrod2ys.png" alt=" " width="800" height="264"></a><br> The deployment config lives in <code>agentcore.json</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight json"><code><span class="p">{</span><span class="w"> </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"financial-advisor-agent"</span><span class="p">,</span><span class="w"> </span><span class="nl">"runtime"</span><span class="p">:</span><span class="w"> </span><span class="s2">"python3.12"</span><span class="p">,</span><span class="w"> </span><span class="nl">"handler"</span><span class="p">:</span><span class="w"> </span><span class="s2">"main.handler"</span><span class="p">,</span><span class="w"> </span><span class="nl">"model"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"provider"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bedrock"</span><span class="p">,</span><span class="w"> </span><span class="nl">"model_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"us.anthropic.claude-3-5-sonnet-20241022-v2:0"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"memory"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"> </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"agentcore"</span><span class="p">,</span><span class="w"> </span><span class="nl">"session_ttl_days"</span><span class="p">:</span><span class="w"> </span><span class="mi">90</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"guardrails"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"> </span><span class="nl">"guardrail_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"financial-advisor-guardrail"</span><span class="p">,</span><span class="w"> </span><span class="nl">"apply_to"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"input"</span><span class="p">,</span><span class="w"> </span><span class="s2">"output"</span><span class="p">]</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"scaling"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"min_instances"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nl">"max_instances"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="nl">"target_concurrency"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"observability"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"tracing"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xray"</span><span class="p">,</span><span class="w"> </span><span class="nl">"metrics"</span><span class="p">:</span><span class="w"> </span><span class="s2">"cloudwatch"</span><span class="p">,</span><span class="w"> </span><span class="nl">"log_level"</span><span class="p">:</span><span class="w"> </span><span class="s2">"INFO"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre> </div> <p>Three CLI commands take you from code to production:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code><span class="c"># Develop locally with hot-reload</span> agentcore dev <span class="c"># → Local agent running at http://localhost:8080</span> <span class="c"># Deploy to Amazon Bedrock AgentCore Runtime</span> agentcore deploy <span class="c"># → Packaging agent... done</span> <span class="c"># → Provisioning CDK stack... done</span> <span class="c"># → Attaching guardrails... done</span> <span class="c"># → Configuring AgentCore Memory... done</span> <span class="c"># → Deployed! Endpoint: https://bedrock-agentcore.us-east-1.amazonaws.com/agents/fa-demo</span> <span class="c"># Invoke the deployed agent</span> agentcore invoke <span class="s2">"What is the portfolio value for client ABC123?"</span> <span class="nt">--stream</span> </code></pre> </div> <h2> Putting It All Together- Running the Demo </h2> <p>Clone the repo and run the demo locally (no AWS credentials required):<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code>git clone https://github.com/awslabs/agentcore-samples <span class="nb">cd </span>agentcore-samples/financial-advisor pip <span class="nb">install</span> <span class="nt">-r</span> requirements.txt <span class="c"># Local demo with mock data</span> python main.py <span class="c"># Full AWS mode with real Bedrock, Memory, and Guardrails</span> python main.py <span class="nt">--use-aws</span> <span class="nt">--enable-guardrails</span> <span class="c"># Interactive REPL</span> python main.py <span class="nt">--interactive</span> </code></pre> </div> <p>The scripted demo walks through six representative turns:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code>[1/6] What is the total portfolio value for client ABC123? → Portfolio Specialist retrieves holdings + P&L [2/6] What are the current prices for AAPL, GOOGL, and MSFT? → Market Data Specialist fetches live prices + 52w range [3/6] What's the latest news about Apple and Microsoft? → News Analyst returns headlines + sentiment scores [4/6] What's the risk level of my current portfolio? → Portfolio Specialist runs risk decomposition [5/6] Based on everything, should I rebalance? → Orchestrator calls all three specialists + synthesises [6/6] Given what I told you about my risk preference earlier, any concerns? → Memory-powered: agent recalls previous turns and personalises </code></pre> </div> <h2> Key Takeaways </h2> <p>The financial advisor demo shows how modern agent patterns come together in a coherent production architecture:</p> <p><strong>Strands SDK makes agents simple.</strong> The <code>@tool</code> decorator, <code>Agent</code> class, and <code>BedrockModel</code> eliminate most boilerplate. You describe your tools in plain Python; the SDK handles the rest.</p> <p><strong>Specialisation beats monoliths.</strong> Breaking the system into focused sub-agents — each with its own system prompt and tool set — produces sharper, more reliable answers than a single agent trying to do everything.</p> <p><strong>The agent-as-tool pattern is powerful.</strong> Wrapping sub-agents as <code>@tool</code> functions lets the orchestrator's model reason about delegation using the same mechanism it uses for everything else. No custom routing logic required.</p> <p><strong>Guardrails are infrastructure, not code.</strong> Attaching a Bedrock Guardrail to <code>BedrockModel</code> protects every single request- input AND output — without any changes to your agent logic. Compliance becomes a deployment concern, not a development one.</p> <p><strong>Memory makes agents personal.</strong> Injecting past conversations into the system prompt at runtime is simple but transformative. The agent genuinely remembers- and users notice immediately.</p> <p><strong><code>agentcore deploy</code> is production-ready.</strong> Serverless execution, auto-scaling, integrated tracing, and health management are all included. Going from local dev to a live endpoint is three CLI commands.</p> <h2> Resources </h2> <ul> <li> <strong>Demo code:</strong> <a href="https://github.com/awslabs/agentcore-samples" rel="noopener noreferrer">github.com/awslabs/agentcore-samples</a> </li> <li> <strong>Strands Agents SDK:</strong> <a href="https://github.com/strands-agents/sdk-python" rel="noopener noreferrer">github.com/strands-agents/sdk-python</a> </li> <li> <strong>Amazon Bedrock AgentCore docs:</strong> <a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html" rel="noopener noreferrer">docs.aws.amazon.com/bedrock-agentcore</a> </li> <li> <strong>Amazon Bedrock Guardrails:</strong> <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html" rel="noopener noreferrer">docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html</a> </li> <li> <strong>AWS Summit 2025 session:</strong> <em>Use Agent Strategies to Streamline Complex Business Tasks</em> </li> </ul> <p><em>Built with ❤️ using open-source tools and AWS. Questions or feedback? Drop them in the comments below.</em></p>
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。