-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Context
We are using a sub-agent as a tool inside a larger agent orchestration flow.
This sub-agent must always rely on an external structured source as its single source of truth. However, in some cases, the sub-agent produces responses without calling its tool, resulting in hallucinated outputs being returned to the root agent.
To prevent this, we attempted to force tool usage via GenerateContentConfig and FunctionCallingConfig.
tool_config = types.ToolConfig(
function_calling_config=types.FunctionCallingConfig(
mode="ANY",
allowed_function_names=["external_search_tool"]
)
)
SubAgent = LlmAgent(
model=MODEL_NAME,
name="SubAgent",
description="Sub-agent used as a tool that must always rely on an external source.",
instruction=return_agent_instruction(),
tools=[external_search_tool],
generate_content_config=types.GenerateContentConfig(
tool_config=tool_config,
),
planner=BuiltInPlanner(
thinking_config=types.ThinkingConfig(
include_thoughts=True,
thinking_budget=1024,
)
)
)
Expected Behavior
• The sub-agent should call the tool at least once before responding.
• After receiving the tool result, it should produce a final response and exit.
• The sub-agent should not be able to answer without using the tool.
Observed Behavior
• When mode="ANY" is enabled, the sub-agent enters an infinite loop of tool calls.
• The same tool is repeatedly invoked, even when the previous result is sufficient.
• No final response is produced.
• Removing FunctionCallingConfig avoids the loop, but the original hallucination issue returns.
Environment
• google-adk == 1.21.0
Questions
• Is this infinite loop expected behavior when using mode="ANY" with sub-agents used as tools?
• Is there a recommended way in ADK to:
• enforce mandatory tool usage
• limit the number of tool calls
• guarantee a single tool call followed by a final response?