Skip to content

Commit 04b9f02

Browse files
Fix/learn track workshop model issues (#294)
1 parent 824a7dc commit 04b9f02

20 files changed

Lines changed: 233 additions & 127 deletions

File tree

python/01-learn/03-model-providers/01-ollama-model/ollama-file-ops-agent.ipynb

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"| Information | Details |\n",
2626
"|:-----------------------|:-----------------------------------------------|\n",
2727
"| Agent structure | Single agent |\n",
28-
"| Model | `qwen3.5:4b` (any tool-capable model you pull with Ollama) |\n",
29-
"| Runs on | Your local machine (via Ollama) |\n",
28+
"| Model | `qwen2.5:1.5b` (any tool-capable model you pull with Ollama) |\n",
29+
"| Runs on | Your local machine or a CPU-only cloud environment (via Ollama) |\n",
3030
"| Strands model provider | `OllamaModel` |\n",
3131
"| Custom tools | file_read, file_write, list_directory |"
3232
]
@@ -53,7 +53,7 @@
5353
"metadata": {},
5454
"outputs": [],
5555
"source": [
56-
"!pip install -r requirements.txt"
56+
"!pip install -q -r requirements.txt"
5757
]
5858
},
5959
{
@@ -70,7 +70,7 @@
7070
"\n",
7171
"1. Installed Ollama: [https://ollama.com/download](https://ollama.com/download)\n",
7272
"2. Started the Ollama server: `ollama serve`\n",
73-
"3. Downloaded a model with Ollama: `ollama pull qwen3.5:4b`\n",
73+
"3. Downloaded a model with Ollama: `ollama pull qwen2.5:1.5b`\n",
7474
"\n",
7575
"Refer to the [Ollama model provider documentation](https://strandsagents.com/docs/user-guide/concepts/model-providers/ollama/) for detailed instructions.\n",
7676
"\n",
@@ -94,7 +94,14 @@
9494
"outputs": [],
9595
"source": [
9696
"import subprocess\n",
97-
"subprocess.Popen(['ollama', 'serve'])"
97+
"\n",
98+
"# Start the Ollama server in the background. Redirect its output so the\n",
99+
"# server logs do not fill the notebook\n",
100+
"ollama_proc = subprocess.Popen(\n",
101+
" [\"ollama\", \"serve\"],\n",
102+
" stdout=subprocess.DEVNULL,\n",
103+
" stderr=subprocess.DEVNULL,\n",
104+
")"
98105
]
99106
},
100107
{
@@ -105,7 +112,7 @@
105112
},
106113
"outputs": [],
107114
"source": [
108-
"!ollama pull qwen3.5:4b"
115+
"!ollama pull qwen2.5:1.5b"
109116
]
110117
},
111118
{
@@ -289,7 +296,7 @@
289296
"\"\"\"\n",
290297
"\n",
291298
"model_id = (\n",
292-
" \"qwen3.5:4b\" # You can change this to any tool-capable model you have pulled with Ollama.\n",
299+
" \"qwen2.5:1.5b\" # You can change this to any tool-capable model you have pulled with Ollama.\n",
293300
")"
294301
]
295302
},
@@ -300,7 +307,7 @@
300307
"### Configure the Ollama model\n",
301308
"Make sure the Ollama service is running at http://localhost:11434 and your `model_id` appears in the list of models printed above.\n",
302309
"\n",
303-
"This notebook uses `qwen3.5:4b`, which supports tool calling. The agent needs that to invoke the file tools. Any tool-capable Ollama model works; a recent Ollama version is recommended so it can pull current models."
310+
"This notebook uses `qwen2.5:1.5b`, which supports tool calling. The agent needs that to invoke the file tools. Any tool-capable Ollama model works; a recent Ollama version is recommended so it can pull current models."
304311
]
305312
},
306313
{
@@ -312,9 +319,10 @@
312319
"ollama_model = OllamaModel(\n",
313320
" model_id=model_id,\n",
314321
" host=\"http://localhost:11434\",\n",
315-
" max_tokens=4096, # Adjust based on your model's capabilities\n",
322+
" max_tokens=4096, # Maximum tokens to generate in the response\n",
316323
" temperature=0.7, # Lower for more deterministic responses, higher for more creative\n",
317324
" top_p=0.9, # Nucleus sampling parameter\n",
325+
" options={\"num_ctx\": 16384}, # Input context window; widen it so long inputs are not truncated\n",
318326
")\n",
319327
"\n",
320328
"# Create the agent\n",

python/01-learn/04-streaming/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ uv
33
strands-agents
44
strands-agents-tools
55
uvicorn
6-
pydantic
6+
pydantic
7+
httpx

python/01-learn/04-streaming/streaming.ipynb

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"* AWS account\n",
6161
"* Anthropic Claude Sonnet 4.5 enabled on Amazon Bedrock\n",
6262
"\n",
63-
"Let's now install the requirement packages for our Strands Agent Agent"
63+
"Let's now install the required packages for our Strands Agent"
6464
]
6565
},
6666
{
@@ -107,15 +107,33 @@
107107
"source": [
108108
"### Creating and invoking agent with stream_async\n",
109109
"\n",
110-
"Let's now create our agent with a built-in calculator tool and no `callback_handler`. We will use the `stream_async` method to iteract over the streamed agent events"
110+
"Let's now create our agent with a built-in calculator tool and no `callback_handler`. We will use the `stream_async` method to iterate over the streamed agent events"
111111
]
112112
},
113113
{
114114
"cell_type": "code",
115115
"execution_count": null,
116116
"metadata": {},
117117
"outputs": [],
118-
"source": "# Initialize our agent without a callback handler\nagent = Agent(\n model=\"us.anthropic.claude-sonnet-4-5-20250929-v1:0\", # Optional: Specify the model ID\n tools=[calculator], \n callback_handler=None)\n\n# Async function that iterators over streamed agent events\n\n\nasync def process_streaming_response():\n agent_stream = agent.stream_async(\"Calculate 2+2\")\n async for event in agent_stream:\n print(event)\n\n\n# Run the agent\nawait process_streaming_response()"
118+
"source": [
119+
"# Initialize our agent without a callback handler\n",
120+
"agent = Agent(\n",
121+
" model=\"us.anthropic.claude-sonnet-4-5-20250929-v1:0\", # Optional: Specify the model ID\n",
122+
" tools=[calculator], \n",
123+
" callback_handler=None)\n",
124+
"\n",
125+
"# Async function that iterates over streamed agent events\n",
126+
"\n",
127+
"\n",
128+
"async def process_streaming_response():\n",
129+
" agent_stream = agent.stream_async(\"Calculate 2+2\")\n",
130+
" async for event in agent_stream:\n",
131+
" print(event)\n",
132+
"\n",
133+
"\n",
134+
"# Run the agent\n",
135+
"await process_streaming_response()"
136+
]
119137
},
120138
{
121139
"cell_type": "markdown",
@@ -146,7 +164,46 @@
146164
}
147165
},
148166
"outputs": [],
149-
"source": "# Async function that iterators over streamed agent events\n\n\nasync def process_streaming_response():\n agent_stream = agent.stream_async(\"What is the capital of France and what is 42+7?\")\n async for event in agent_stream:\n # Track event loop lifecycle\n if event.get(\"init_event_loop\", False):\n print(\"🔄 Event loop initialized\")\n elif event.get(\"start_event_loop\", False):\n print(\"▶️ Event loop cycle starting\")\n elif event.get(\"start\", False):\n print(\"📝 New cycle started\")\n elif \"message\" in event:\n print(f\"📬 New message created: {event['message']['role']}\")\n elif event.get(\"force_stop\", False):\n print(\n f\"🛑 Event loop force-stopped: {event.get('force_stop_reason', 'unknown reason')}\"\n )\n\n # Track tool usage\n if \"current_tool_use\" in event and event[\"current_tool_use\"].get(\"name\"):\n tool_name = event[\"current_tool_use\"][\"name\"]\n print(f\"🔧 Using tool: {tool_name}\")\n\n # Show only a snippet of text to keep output clean\n if \"data\" in event:\n # Only show first 20 chars of each chunk for demo purposes\n data_snippet = event[\"data\"][:20] + (\n \"...\" if len(event[\"data\"]) > 20 else \"\"\n )\n print(f\"📟 Text: {data_snippet}\")\n\n return event[\"result\"]\n\n\n# Run the agent\nawait process_streaming_response()"
167+
"source": [
168+
"# Async function that iterates over streamed agent events\n",
169+
"\n",
170+
"\n",
171+
"async def process_streaming_response():\n",
172+
" agent_stream = agent.stream_async(\"What is the capital of France and what is 42+7?\")\n",
173+
" async for event in agent_stream:\n",
174+
" # Track event loop lifecycle\n",
175+
" if event.get(\"init_event_loop\", False):\n",
176+
" print(\"🔄 Event loop initialized\")\n",
177+
" elif event.get(\"start_event_loop\", False):\n",
178+
" print(\"▶️ Event loop cycle starting\")\n",
179+
" elif event.get(\"start\", False):\n",
180+
" print(\"📝 New cycle started\")\n",
181+
" elif \"message\" in event:\n",
182+
" print(f\"📬 New message created: {event['message']['role']}\")\n",
183+
" elif event.get(\"force_stop\", False):\n",
184+
" print(\n",
185+
" f\"🛑 Event loop force-stopped: {event.get('force_stop_reason', 'unknown reason')}\"\n",
186+
" )\n",
187+
"\n",
188+
" # Track tool usage\n",
189+
" if \"current_tool_use\" in event and event[\"current_tool_use\"].get(\"name\"):\n",
190+
" tool_name = event[\"current_tool_use\"][\"name\"]\n",
191+
" print(f\"🔧 Using tool: {tool_name}\")\n",
192+
"\n",
193+
" # Show only a snippet of text to keep output clean\n",
194+
" if \"data\" in event:\n",
195+
" # Only show first 20 chars of each chunk for demo purposes\n",
196+
" data_snippet = event[\"data\"][:20] + (\n",
197+
" \"...\" if len(event[\"data\"]) > 20 else \"\"\n",
198+
" )\n",
199+
" print(f\"📟 Text: {data_snippet}\")\n",
200+
"\n",
201+
" return event[\"result\"]\n",
202+
"\n",
203+
"\n",
204+
"# Run the agent\n",
205+
"await process_streaming_response()"
206+
]
150207
},
151208
{
152209
"cell_type": "markdown",
@@ -186,7 +243,11 @@
186243
"@app.post(\"/stream\")\n",
187244
"async def stream_response(request: PromptRequest):\n",
188245
" async def generate():\n",
189-
" agent = Agent(tools=[calculator, weather_forecast], callback_handler=None)\n",
246+
" agent = Agent(\n",
247+
" model=\"us.anthropic.claude-sonnet-4-5-20250929-v1:0\", # Specify the model ID; do not rely on the SDK default, which can reach end of life\n",
248+
" tools=[calculator, weather_forecast],\n",
249+
" callback_handler=None,\n",
250+
" )\n",
190251
" try:\n",
191252
" async for event in agent.stream_async(request.prompt):\n",
192253
" if \"data\" in event:\n",
@@ -292,7 +353,7 @@
292353
"source": [
293354
"### Congratulations!\n",
294355
"\n",
295-
"In this notebook you learned how to stream your agents outputs using async iteractors and callback handlers. "
356+
"In this notebook you learned how to stream your agents outputs using async iterators and callback handlers. "
296357
]
297358
}
298359
],

python/01-learn/05-guardrails/bedrock_guardrails_sample.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"\n",
1414
"Amazon Bedrock Guardrails provides configurable safeguards to help safely build generative AI applications at scale. With a consistent and standard approach used across a wide range of foundation models (FMs) including FMs supported in Amazon Bedrock, fine-tuned models, and models hosted outside of Amazon Bedrock, Guardrails delivers industry-leading safety protections. \n",
1515
"\n",
16-
"With Strands Agents, you can add Amazon Bedrock Guardrails directly to you Amazon Bedrock models. If you are not using Amazon Bedrock Models, you can use the [Apply Guardrail API](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-use-independent-api.html) to safeguard any model. In this case, you need to build the pipelines using the advance processing capabilities you just learned.\n",
16+
"With Strands Agents, you can add Amazon Bedrock Guardrails directly to your Amazon Bedrock models. If you are not using Amazon Bedrock Models, you can use the [Apply Guardrail API](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails-use-independent-api.html) to safeguard any model. In this case, you need to build the pipelines using the advance processing capabilities you just learned.\n",
1717
"\n",
1818
"\n",
1919
"## Agent Details\n",
@@ -144,7 +144,7 @@
144144
"cell_type": "markdown",
145145
"metadata": {},
146146
"source": [
147-
"You can now use the `create_guardrail` method to create the `no-investment-advice` guardrail that will be used in our application. In this example, our guardrail will include a topic deny for `Fiduciary Advice` that will block our agent to provide any fiduciary advice. The guardrail will also contain some basic content policy to filter innapropriated content and a word policy configuration to detect specific pre-defined words."
147+
"You can now use the `create_guardrail` method to create the `no-investment-advice` guardrail that will be used in our application. In this example, our guardrail will include a topic deny for `Fiduciary Advice` that will block our agent to provide any fiduciary advice. The guardrail will also contain some basic content policy to filter inappropriate content and a word policy configuration to detect specific pre-defined words."
148148
]
149149
},
150150
{
@@ -471,7 +471,7 @@
471471
"metadata": {},
472472
"outputs": [],
473473
"source": [
474-
"# Test with user input in which guadrail is intervened and input is redacted with custom message \n",
474+
"# Test with user input in which guardrail is intervened and input is redacted with custom message \n",
475475
"agent(\"How should I allocate my 401(k) investments?\")"
476476
]
477477
},

python/01-learn/05-guardrails/customer_profile_tools.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def get_customer_profile(customer_id: str = None, email: str = None) -> Dict:
1818
dict: Customer profile information or error message
1919
"""
2020
if not customer_id and not email:
21-
return {"Either customer_id or email must be provided"}
21+
return {"error": "Either customer_id or email must be provided"}
2222

2323
profile = None
2424
if customer_id:
@@ -27,7 +27,7 @@ def get_customer_profile(customer_id: str = None, email: str = None) -> Dict:
2727
profile = profile_manager.get_profile_by_email(email)
2828

2929
if not profile:
30-
return {"Customer profile not found"}
30+
return {"error": "Customer profile not found"}
3131

3232
return profile.to_dict()
3333

@@ -45,7 +45,7 @@ def list_customer_purchases(customer_id: str = None, email: str = None) -> List[
4545
list: List of customer purchases or error message
4646
"""
4747
if not customer_id and not email:
48-
return {"Either customer_id or email must be provided"}
48+
return {"error": "Either customer_id or email must be provided"}
4949

5050
profile = None
5151
if customer_id:
@@ -55,7 +55,7 @@ def list_customer_purchases(customer_id: str = None, email: str = None) -> List[
5555
profile = profile_manager.get_profile_by_email(email)
5656

5757
if not profile:
58-
return {"Customer profile not found"}
58+
return {"error": "Customer profile not found"}
5959

6060
return profile.purchase_history
6161

@@ -73,7 +73,7 @@ def list_customer_tickets(customer_id: str = None, email: str = None) -> List[Di
7373
list: List of customer support tickets or error message
7474
"""
7575
if not customer_id and not email:
76-
return {"Either customer_id or email must be provided"}
76+
return {"error": "Either customer_id or email must be provided"}
7777

7878
profile = None
7979
if customer_id:
@@ -82,7 +82,7 @@ def list_customer_tickets(customer_id: str = None, email: str = None) -> List[Di
8282
profile = profile_manager.get_profile_by_email(email)
8383

8484
if not profile:
85-
return {"Customer profile not found"}
85+
return {"error": "Customer profile not found"}
8686

8787
return profile.support_tickets
8888

@@ -101,6 +101,6 @@ def update_customer_profile(customer_id: str, updates: Dict) -> Dict:
101101
"""
102102
profile = profile_manager.update_profile(customer_id, updates)
103103
if not profile:
104-
return {"Customer profile not found"}
104+
return {"error": "Customer profile not found"}
105105

106106
return profile.to_dict()

python/01-learn/06-memory/personal_agent_with_memory.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@
240240
"Capabilities:\n",
241241
"- You can store information using the mem0_memory tool (action=\"store\").\n",
242242
"- You can retrieve relevant memories using the mem0_memory tool (action=\"retrieve\").\n",
243-
"- You can use duckduckgo_search to find information on the web.\n",
243+
"- You can use the websearch tool to find information on the web.\n",
244244
"\n",
245245
"Key Rules:\n",
246246
"- Be conversational and natural in your responses.\n",
@@ -492,4 +492,4 @@
492492
},
493493
"nbformat": 4,
494494
"nbformat_minor": 5
495-
}
495+
}

python/01-learn/06-memory/personal_agent_with_memory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
Capabilities:
5555
- Store information with mem0_memory (action="store")
5656
- Retrieve memories with mem0_memory (action="retrieve")
57-
- Search the web with duckduckgo_search
57+
- Search the web with the websearch tool
5858
5959
Key Rules:
6060
- Be conversational and natural

0 commit comments

Comments
 (0)