|
18 | 18 | "\n", |
19 | 19 | "We can implement the multi-agent architecture by simply registering subordinate agents as tools with a higher-level agent. To be able to use an agent as tool, the agent must have a `name` and a `description`. Providing an `input_schema` is optional, but can be used to signal to the supervisor agent that it should send certain fields to the subordinate agent.\n", |
20 | 20 | "\n", |
21 | | - "In the example here we just have a 2-level hierarchy: one supervisor, and 2 subordinate agents. You could add more levels if you want; one of the subordinate agents could itself be a supervisor to its own set of subordinate agents." |
| 21 | + "In the example here we just have a 2-level hierarchy: one supervisor, and 2 subordinate agents. You could add more levels if you want; one of the subordinate agents could itself be a supervisor to its own set of subordinate agents.\n" |
22 | 22 | ] |
23 | 23 | }, |
24 | 24 | { |
|
39 | 39 | "id": "00d4232c", |
40 | 40 | "metadata": {}, |
41 | 41 | "source": [ |
42 | | - "## Weather agent" |
| 42 | + "## Weather agent\n" |
43 | 43 | ] |
44 | 44 | }, |
45 | 45 | { |
|
75 | 75 | "id": "b8a8e867", |
76 | 76 | "metadata": {}, |
77 | 77 | "source": [ |
78 | | - "## Events agent" |
| 78 | + "## Events agent\n" |
79 | 79 | ] |
80 | 80 | }, |
81 | 81 | { |
|
130 | 130 | "id": "415af9d9", |
131 | 131 | "metadata": {}, |
132 | 132 | "source": [ |
133 | | - "## Supervisor agent" |
| 133 | + "## Supervisor agent\n" |
134 | 134 | ] |
135 | 135 | }, |
136 | 136 | { |
|
178 | 178 | "source": [ |
179 | 179 | "## Chat with the supervisor agent\n", |
180 | 180 | "\n", |
181 | | - "The supervisor agent will use the subordinate agents to help the user:" |
| 181 | + "The supervisor agent will use the subordinate agents to help the user:\n" |
182 | 182 | ] |
183 | 183 | }, |
184 | 184 | { |
|
202 | 202 | "source": [ |
203 | 203 | "## Tracing\n", |
204 | 204 | "\n", |
205 | | - "Each agent has its own set of traces that you can inspect" |
| 205 | + "### All traces from supervisor (includes subagent traces)\n", |
| 206 | + "\n", |
| 207 | + "The supervisor's traces include all traces from subagent invocations:\n" |
206 | 208 | ] |
207 | 209 | }, |
208 | 210 | { |
|
216 | 218 | "supervisor_ui.launch()" |
217 | 219 | ] |
218 | 220 | }, |
| 221 | + { |
| 222 | + "cell_type": "markdown", |
| 223 | + "id": "subcontext_explanation", |
| 224 | + "metadata": {}, |
| 225 | + "source": [ |
| 226 | + "### Accessing individual subagent traces\n", |
| 227 | + "\n", |
| 228 | + "When agents are used as tools, each invocation gets its own **subcontext ID** to maintain separate conversational memory. This enables:\n", |
| 229 | + "\n", |
| 230 | + "- **Parallel invocations**: The supervisor could call both agents simultaneously, each with separate memory\n", |
| 231 | + "- **Sequential invocations without memory carryover**: Calling the weather agent twice won't leak context between invocations\n", |
| 232 | + "- **Follow-up messages**: You can send additional messages to a specific subagent invocation by reusing its subcontext ID\n", |
| 233 | + "\n", |
| 234 | + "To view traces for a specific subagent invocation, we need to:\n", |
| 235 | + "\n", |
| 236 | + "1. Extract the subcontext ID from the supervisor's traces\n", |
| 237 | + "2. Set the correct conversation ID and subcontext ID on the subagent\n", |
| 238 | + "3. Then access the subagent's traces\n", |
| 239 | + "\n", |
| 240 | + "First, let's add a helper function to extract subcontext IDs:\n" |
| 241 | + ] |
| 242 | + }, |
| 243 | + { |
| 244 | + "cell_type": "code", |
| 245 | + "execution_count": null, |
| 246 | + "id": "helper_function", |
| 247 | + "metadata": {}, |
| 248 | + "outputs": [], |
| 249 | + "source": [ |
| 250 | + "from collections import defaultdict\n", |
| 251 | + "\n", |
| 252 | + "\n", |
| 253 | + "def get_subagent_subcontext_ids(traces):\n", |
| 254 | + " \"\"\"\n", |
| 255 | + " Extract subcontext IDs used for each subagent invocation from traces.\n", |
| 256 | + "\n", |
| 257 | + " Returns a dict mapping subagent name -> set of subcontext IDs used\n", |
| 258 | + " \"\"\"\n", |
| 259 | + " result = defaultdict(set)\n", |
| 260 | + "\n", |
| 261 | + " for trace in traces:\n", |
| 262 | + " if (\n", |
| 263 | + " trace.attributes.get(\"ai.trace.type\") == \"tool-invocation\"\n", |
| 264 | + " and \"ai.tool.subagent.subcontext.id\" in trace.attributes\n", |
| 265 | + " and \"ai.tool.name\" in trace.attributes\n", |
| 266 | + " ):\n", |
| 267 | + " subagent_name = trace.attributes[\"ai.tool.name\"]\n", |
| 268 | + " subcontext_id = trace.attributes[\"ai.tool.subagent.subcontext.id\"]\n", |
| 269 | + " result[subagent_name].add(subcontext_id)\n", |
| 270 | + "\n", |
| 271 | + " return result" |
| 272 | + ] |
| 273 | + }, |
| 274 | + { |
| 275 | + "cell_type": "markdown", |
| 276 | + "id": "weather_agent_traces_explanation", |
| 277 | + "metadata": {}, |
| 278 | + "source": [ |
| 279 | + "Now let's access the weather agent's traces for this specific invocation:\n" |
| 280 | + ] |
| 281 | + }, |
219 | 282 | { |
220 | 283 | "cell_type": "code", |
221 | 284 | "execution_count": null, |
222 | 285 | "id": "995050bc", |
223 | 286 | "metadata": {}, |
224 | 287 | "outputs": [], |
225 | 288 | "source": [ |
| 289 | + "# Store the conversation ID\n", |
| 290 | + "conversation_id = supervisor.conversation_id\n", |
| 291 | + "\n", |
| 292 | + "# Extract subcontext IDs from the supervisor's traces\n", |
| 293 | + "subcontext_ids = get_subagent_subcontext_ids(supervisor.traces)\n", |
| 294 | + "\n", |
| 295 | + "# Get the specific subcontext_id used for weather_agent\n", |
| 296 | + "weather_subcontext_id = subcontext_ids[\"transfer_to_weather_agent\"].pop()\n", |
| 297 | + "\n", |
| 298 | + "# Set the weather agent to the correct conversation and subcontext\n", |
| 299 | + "weather_agent.set_conversation_id(conversation_id, subcontext_id=weather_subcontext_id)\n", |
| 300 | + "\n", |
| 301 | + "# Now weather_agent.traces returns the correct traces for this invocation\n", |
| 302 | + "print(f\"Weather agent subcontext ID: {weather_subcontext_id}\")\n", |
| 303 | + "print(f\"Number of traces: {len(weather_agent.traces)}\")\n", |
| 304 | + "\n", |
226 | 305 | "weather_agent_ui = traces_ui(weather_agent.traces)\n", |
227 | 306 | "weather_agent_ui.launch()" |
228 | 307 | ] |
229 | 308 | }, |
| 309 | + { |
| 310 | + "cell_type": "markdown", |
| 311 | + "id": "events_agent_traces_explanation", |
| 312 | + "metadata": {}, |
| 313 | + "source": [ |
| 314 | + "And the events agent's traces:\n" |
| 315 | + ] |
| 316 | + }, |
230 | 317 | { |
231 | 318 | "cell_type": "code", |
232 | 319 | "execution_count": null, |
233 | 320 | "id": "bc2a53db", |
234 | 321 | "metadata": {}, |
235 | 322 | "outputs": [], |
236 | 323 | "source": [ |
| 324 | + "# Get the specific subcontext_id used for events_agent\n", |
| 325 | + "events_subcontext_id = subcontext_ids[\"transfer_to_events_agent\"].pop()\n", |
| 326 | + "\n", |
| 327 | + "# Set the events agent to the correct conversation and subcontext\n", |
| 328 | + "events_agent.set_conversation_id(conversation_id, subcontext_id=events_subcontext_id)\n", |
| 329 | + "\n", |
| 330 | + "# Now events_agent.traces returns the correct traces for this invocation\n", |
| 331 | + "print(f\"Events agent subcontext ID: {events_subcontext_id}\")\n", |
| 332 | + "print(f\"Number of traces: {len(events_agent.traces)}\")\n", |
| 333 | + "\n", |
237 | 334 | "events_agent_ui = traces_ui(events_agent.traces)\n", |
238 | 335 | "events_agent_ui.launch()" |
239 | 336 | ] |
240 | 337 | } |
241 | 338 | ], |
242 | 339 | "metadata": { |
243 | 340 | "kernelspec": { |
244 | | - "display_name": ".venv", |
| 341 | + "display_name": "generative-ai-toolkit", |
245 | 342 | "language": "python", |
246 | 343 | "name": "python3" |
247 | 344 | }, |
|
0 commit comments