AWS Builder Center
Building a Bot: Using Strands SDK to create a League of Legends Agent

Building a Bot: Using Strands SDK to create a League of Legends Agent

Work on building an interactive agent with the Strands SDK. Learn memory management, tool interactions, and other engagement patterns.

AWS Solutions Archtiect
Welcome to Day 5 of Challenge #2ย ! Today, you'll move beyond simple RAG queries to create an autonomous agent capable of sophisticated analysis, conversation management, and multi-step reasoning about your League of Legends match data.

What You Will Need

๐Ÿ’ป Your AWS account with Bedrock access
๐Ÿง  Your existing Knowledge Base from previous setup
โš™๏ธ Python 3.10+ development environment
โฐ About 60 minutes
๐Ÿ“š Basic understanding of Python and AWS services

What You Will Accomplish Today

โœ… Set up the Strands SDK development environment
โœ… Create an AI agent connected to your Bedrock Knowledge Base
โœ… Implement custom tools and autonomous behaviors
โœ… Configure agent memory and conversation handling
โœ… Deploy your agent with proper monitoring and security
โœ… Test multi-step analytical workflows

Step 1: Understanding Strands Agents ๐Ÿค”

What is an AI Agent?

An AI agent is an AI system that can:
  • Maintain conversation context and memory
  • Use multiple tools and services autonomously
  • Make independent decisions based on context
  • Execute complex multi-step workflows
  • Self-reflect and correct mistakes
Diagram showing agent behavior, retrieveing a prompt, interacting with knowledge and tools, then generating a result
Strands Agents is an open source SDK that takes a model-driven approach to building and running AI agents in just a few lines of code . Unlike simple RAG implementations, Strands supports sophisticated patterns including multi-agent orchestration, semantic search for managing thousands of tools, and advanced reasoning capabilities.

Key Features of Strands Agents

Strands Agents includes the following capabilities:
  • Model-first design: Built around the concept that the foundation model is the core of agent intelligence, enabling sophisticated autonomous reasoning
  • AWS service integration: Seamless connection to Amazon Bedrock, AWS Lambda, AWS Step Functions, and other AWS services
  • Foundation model selection: Supports various models including Anthropic Claude, Amazon Nova models on Amazon Bedrock
  • Multimodal capabilities: Support for text, speech, and image processing
  • Tool ecosystem: Rich set of tools for AWS service interaction with extensibility for custom tools

Step 2: Setting Up Your Development Environment ๐Ÿ› ๏ธ

Install Required Packages

1
2
pip install strands-agents
pip install boto3

Configure AWS Credentials

Ensure your AWS credentials are properly configured with Bedrock access (if working locally)
1
aws configure
Make sure your IAM user or execution role has the necessary Bedrock permissions to invoke models and access your Knowledge Base, as well as utilize agent features:
Example IAM Policy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BedrockFullAccess",
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
"bedrock:Retrieve",
"bedrock:RetrieveAndGenerate",
"bedrock:InvokeAgent",
"bedrock:GetAgent",
"bedrock:ListAgents"
],
"Resource": "*"
},
{
"Sid": "BasicLogging",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}

Step 3: Initialize Your Basic Agent Structure

Create a new Python file league_analytics_agent.py, or create a new Jupyter notebook in SageMaker Studio:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import os
from strands import Agent, tool
from strands.models import BedrockModel
from strands.memory import ConversationMemory

# Configuration - Replace with your actual values
KNOWLEDGE_BASE_ID = "your-kb-id-here" # From Day 4 setup
REGION = "us-east-1" # Your AWS region
MODEL_ID = "anthropic.claude-sonnet-4-20250514-v1:0" #or whatever model you like

# Initialize Bedrock model
model = BedrockModel(
model_id=MODEL_ID,
region_name=REGION,
)

# Create the basic agent
agent = Agent(
model=model,
system_prompt="""You are a League of Legends analytics expert. You have access to match data
through a knowledge base and can perform sophisticated analysis of champion performance,
meta trends, and gameplay patterns. Always provide specific data-driven insights and
cite your sources when making claims about game statistics."""

)

Step 4: Adding Knowledge Base Integration Tool

Now let's create a custom tool that integrates with your Bedrock Knowledge Base:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import boto3
from typing import Dict, Any

# Initialize Bedrock client
bedrock_client = boto3.client('bedrock-agent-runtime', region_name=REGION)

@tool
def query_match_data(query: str, max_results: int = 5) -> str:
"""
Query the League of Legends match data knowledge base for specific information.

Args:
query: The question about match data, champion performance, or meta analysis
max_results: Number of relevant documents to retrieve (default: 5)

Returns:
Detailed analysis based on the match data
"""

try:
response = bedrock_client.retrieve_and_generate(
input={'text': query},
retrieveAndGenerateConfiguration={
'type': 'KNOWLEDGE_BASE',
'knowledgeBaseConfiguration': {
'knowledgeBaseId': KNOWLEDGE_BASE_ID,
'modelArn': MODEL_ID,
'retrievalConfiguration': {
'vectorSearchConfiguration': {
'numberOfResults': max_results
}
}
}
}
)

# Extract the generated answer
answer = response.get('output', {}).get('text', '')

# Get source citations for transparency
citations = []
for citation in response.get('citations', []):
for ref in citation.get('retrievedReferences', []):
citations.append({
'content_snippet': ref.get('content', {}).get('text', '')[:200] + '...',
'metadata': ref.get('metadata', {})
})

result = f"Analysis: {answer}\n\nSources: {len(citations)} match data references used"
return result

except Exception as e:
return f"Error querying match data: {str(e)}"

# Add the tool to the agent
agent.tools.append(query_match_data)

Step 5: Implementing Advanced Analysis Tools

Let's add specialized tools for different types of League of Legends analysis, specifically, champion-based analysis.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
@tool
def analyze_champion_performance(champion_name: str, role: str = None, rank_tier: str = None) -> str:
"""
Analyze detailed performance metrics for a specific champion.

Args:
champion_name: Name of the champion to analyze
role: Specific role/position (optional)
rank_tier: Rank tier to filter by (optional)

Returns:
Comprehensive champion performance analysis
"""

query_parts = [f"champion performance analysis for {champion_name}"]

if role:
query_parts.append(f"in the {role} role")
if rank_tier:
query_parts.append(f"in {rank_tier} ranked games")

query_parts.extend([
"including win rate, KDA ratios, item build success rates,",
"pick rate trends, ban rate, and comparison to other champions in the same role"
])

full_query = " ".join(query_parts)
return query_match_data(full_query, max_results=8)

@tool
def analyze_meta_trends(patch_version: str = None, time_period: str = "last 30 days") -> str:
"""
Analyze current meta trends and shifts in champion popularity.

Args:
patch_version: Specific patch to analyze (optional)
time_period: Time period for trend analysis

Returns:
Meta trend analysis with rising/falling champions
"""

query_parts = ["meta trends analysis showing"]

if patch_version:
query_parts.append(f"changes in patch {patch_version}")
else:
query_parts.append(f"trends over the {time_period}")

query_parts.extend([
"including champion pick rate changes, win rate shifts,",
"emerging strategies, item build evolution, and role meta shifts"
])

full_query = " ".join(query_parts)
return query_match_data(full_query, max_results=10)

@tool
def compare_team_compositions(comp1_description: str, comp2_description: str) -> str:
"""
Compare the effectiveness of different team compositions.

Args:
comp1_description: Description of first team composition
comp2_description: Description of second team composition

Returns:
Comparative analysis of team composition effectiveness
"""

query = f"""
Compare team composition effectiveness between:
Composition 1: {comp1_description}
Composition 2: {comp2_description}

Include win rates, synergy analysis, power spikes, team fight effectiveness,
objective control, and matchup considerations
"""


return query_match_data(query, max_results=12)

# Add specialized tools to agent
agent.tools.extend([analyze_champion_performance, analyze_meta_trends, compare_team_compositions])

Step 6: Configure Memory and Context Management ๐Ÿง 

Implement simple but effective memory management using Strands SDK:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from strands.memory import ConversationMemory

# Configure conversation memory for context retention
memory = ConversationMemory(
memory_size=10, # Keep last 10 exchanges
include_system_messages=True
)

# Update agent with memory capabilities
agent = Agent(
model=model,
memory=memory,
system_prompt="""You are a League of Legends analytics expert with conversation memory.
Remember previous questions and analyses within our conversation to provide contextual responses.
Reference past discussions when relevant and build upon previous insights."""
,
tools=[query_match_data, analyze_champion_performance, analyze_meta_trends, compare_team_compositions]
)

# Simple context-aware message handler
@agent.on_message
async def handle_message_with_memory(message: str):
"""Process messages with conversation context"""

# Get recent conversation for context
recent_messages = agent.memory.get_recent_messages(limit=3)

# Check for follow-up patterns
if any(word in message.lower() for word in ["that champion", "this build", "same", "also"]):
message += " (Reference previous discussion context)"

print(f"Processing query with memory context: {message[:100]}...")
return await agent.process_message(message)

Step 7: Adding Agent Behaviors and Error Handling

Configure intelligent behaviors and robust error handling:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Add conversation handlers
@agent.on_message
async def handle_message(message: str):
"""Pre-process user input for better analysis"""
# Log the interaction
print(f"Processing query: {message[:100]}...")

# Enhance queries with context
if "champion" in message.lower() and "vs" in message.lower():
message += " Include matchup statistics and win rate comparisons."
elif "meta" in message.lower():
message += " Focus on recent trends and statistical significance."

return await agent.process_message(message)

@agent.on_error
async def handle_error(error: Exception):
"""Handle errors gracefully with helpful suggestions"""
error_msg = str(error)

if "knowledge base" in error_msg.lower():
return {
"error": "Unable to access match data",
"suggestion": "Please verify your Knowledge Base is active and try a more specific query"
}
elif "timeout" in error_msg.lower():
return {
"error": "Query took too long to process",
"suggestion": "Try breaking your question into smaller, more focused queries"
}
else:
return {
"error": f"Analysis error: {error_msg}",
"suggestion": "Please rephrase your question or try a different approach"
}

Step 8: Testing Your Agent ๐Ÿงช

Let's verify everything works with comprehensive testing :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
async def test_agent():
"""Test the agent with various League of Legends queries"""

test_queries = [
"What are the most successful item builds for Jinx in ranked games?",
"Show me the current meta trends for ADC champions",
"Compare the effectiveness of engage supports versus enchanter supports",
"Which champions have the highest win rate in Diamond+ games?",
"Analyze the performance of Azir in mid lane during the current patch"
]

print("๐Ÿงช Testing League Analytics Agent...")

for i, query in enumerate(test_queries, 1):
try:
print(f"\n--- Test {i}: {query} ---")
response = await agent.process_message(query)
print(f"โœ… Response: {response[:200]}...")
metrics.log_query(True)
except Exception as e:
print(f"โŒ Error: {str(e)}")
metrics.log_query(False)

print(f"\n๐Ÿ“Š Test Summary: {metrics.successful_queries}/{metrics.query_count} successful")

# Run tests
if __name__ == "__main__":
import asyncio
asyncio.run(test_agent())

Checklist โœ…

Verify you've completed all key components:
  • โœ… Basic agent setup with Bedrock model
  • โœ… Knowledge Base tool integration
  • โœ… Custom analysis tools for League data
  • โœ… Memory management implementation
  • โœ… Comprehensive testing
BONUS OPPORTUNITY: Comment a unique prompt you gave to your agent and what the output was!

Next Steps: Production Deployment ๐Ÿš€

Tomorrow, we'll take your Strands agent from development to a public endpoint. You'll learn how to:
โœ… Create a serverless API using API Gateway and Lambda
โœ… Configure proper authentication and authorization
โœ… Set up request/response handling for your agent
โœ… ...and more!
This deployment will make your agent accessible via HTTP endpoints, enabling integration with web applications, chat interfaces, or any systems that can make API requests. Happy Hacking!
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article