Lesson 3 - Introduction to Google's ADK - Part II

Hello!

I have a question about the "3.3.4. Interact with the Agent Team"
When I look at the call stack I can see we never return to the “root agent”. At the end of the first step, we are inside “greeting_subagent_v1” and its delegate to “farewell_subagent_v1” when we send the second message “Thanks bye” by using the internal Google ADK tool “transfer_to_agent”.

I understand each agent have access to ALL agents description, so “greeting_subagent_v1” knows he could delegate to “farewell_subagent_v1” but the decision criteria is unclear for me. The “root agent” have the instruction to delegate either to “greeting_subagent_v1” or “farewell_subagent_v1” depending on the task. But the “greeting_subagent_v1” do not have this instruction. So can he decides to delegate? If it based only on the “description” of other agent et his description, it could works here because it is simple enough.

We should always return to the root agent so HE decides to which agents delegate no? It seems to me it is a bettern pattern. And I don’t really get how the pattern offers in the lesson could world in a more complex environnements.

Am I right ? Is there something I am missing?

>>> User Query: Hello I'm ABK
  [Event] Author: friendly_agent_team_v1, Type: Event, Final: False, Content: parts=[Part(
  function_call=FunctionCall(
    args={
      'agent_name': 'greeting_subagent_v1'
    },
    id='call_d07q8VQroo00DRFvnchUm9OT',
    name='transfer_to_agent'
  )
)] role='model'
  [Event] Author: friendly_agent_team_v1, Type: Event, Final: False, Content: parts=[Part(
  function_response=FunctionResponse(
    id='call_d07q8VQroo00DRFvnchUm9OT',
    name='transfer_to_agent',
    response={
      'result': None
    }
  )
)] role='user'
  [Event] Author: greeting_subagent_v1, Type: Event, Final: False, Content: parts=[Part(
  function_call=FunctionCall(
    args={
      'person_name': 'ABK'
    },
    id='call_EUNCz49nh8SiGId3Vc2GAsI7',
    name='say_hello'
  )
)] role='model'
  [Event] Author: greeting_subagent_v1, Type: Event, Final: False, Content: parts=[Part(
  function_response=FunctionResponse(
    id='call_EUNCz49nh8SiGId3Vc2GAsI7',
    name='say_hello',
    response={
      'query_result': [
        {
          'reply': 'Hello to you, ABK'
        },
      ],
      'status': 'success'
    }
  )
)] role='user'
  [Event] Author: greeting_subagent_v1, Type: Event, Final: True, Content: parts=[Part(
  text='Hello to you, ABK!'
)] role='model'
<<< Agent Response: Hello to you, ABK!

>>> User Query: Thanks, bye!
  [Event] Author: greeting_subagent_v1, Type: Event, Final: False, Content: parts=[Part(
  function_call=FunctionCall(
    args={
      'agent_name': 'farewell_subagent_v1'
    },
    id='call_NPMikzDH2c33WCQdMiQZaq5l',
    name='transfer_to_agent'
  )
)] role='model'
  [Event] Author: greeting_subagent_v1, Type: Event, Final: False, Content: parts=[Part(
  function_response=FunctionResponse(
    id='call_NPMikzDH2c33WCQdMiQZaq5l',
    name='transfer_to_agent',
    response={
      'result': None
    }
  )
)] role='user'
  [Event] Author: farewell_subagent_v1, Type: Event, Final: False, Content: parts=[Part(
  function_call=FunctionCall(
    args={},
    id='call_xv95pUtdkYwFlPJ5ArilbOsc',
    name='say_goodbye'
  )
)] role='model'
  [Event] Author: farewell_subagent_v1, Type: Event, Final: False, Content: parts=[Part(
  function_response=FunctionResponse(
    id='call_xv95pUtdkYwFlPJ5ArilbOsc',
    name='say_goodbye',
    response={
      'query_result': [
        {
          'farewell': 'Goodbye from Cypher!'
        },
      ],
      'status': 'success'
    }
  )
)] role='user'
  [Event] Author: farewell_subagent_v1, Type: Event, Final: True, Content: parts=[Part(
  text='Goodbye from Cypher!'
)] role='model'
<<< Agent Response: Goodbye from Cypher!

I just got the answer in the lesson “Schema proposal for structured data”.
The key differences:

The root agent have two subagent, say hello and say goodbye. In this configuration, there are no coordinator. Each agent could call others agents with the tool “transfer_to_agent” built-in inside google adk framework.

If we want to keep the root agent as a coordinator, we should define say_hello and say_goobye" as tools. When define as tools agents have no access to other agents. A tool is just in/out and we get back to the main agent after.

Other point of attention, LlmAgent/Agent class are agent with the ability to “think” and this is why they can use autonomously tools and sub_agents.

1 Like

The reason this tool agent is more using an interface based type response because of the kind of task being handled, as transfer to agent allows the correct agent to recall the function based on the prompt or query recieved.

I still didn’t get what is your doubt with your main query topic, although based on description you are understanding the tool agent interaction precisely @Kaline

I didn’t understand why the agents “root” was not the coordinator and why say_hello could call directly say_goodbye without going through root @Deepti_Prasad

can you share the root agent snippet here, so I can explain you how with each time subagent are working based on user prompt query.

I understood how it works :slight_smile: just I had trouble with agent tool vs sub agent

the agentic tool main function here would be related to recalling api key calls which diverts to subagents to perform the task based on the user based prompt query, handling multi-agent system especially in higher complexity task like research based query task or planning a travel iternary.