Skip to content

Commit 663b28b

Browse files
committed
fix(skills): prevent empty responses after load_skill
The skill system instruction does not tell the model what to do after a load_skill call returns. Some models (notably Gemini) treat the load_skill tool call as the entire turn and stop with no visible output, producing empty responses. This is most acute for tool-heavy skills, whose next correct action after load_skill is to call more tools rather than reply. Add rule 7 to _build_skill_system_instruction: load_skill only retrieves instructions and does NOT complete the turn; the model must continue in the same turn (calling whatever tools the skill requires) and never end with an empty response right after loading a skill. The rule uses the {prefix} substitution like the other rules, so both the default and prefixed system instructions carry it. Verified in a production environment: appending this guidance dropped the empty-response rate for Gemini after skill loading substantially. Adds tests asserting rule 7 is present in both the default and prefixed system instruction.
1 parent 9e3b43f commit 663b28b

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

src/google/adk/tools/skill_toolset.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ def _build_skill_system_instruction(prefix: str | None = None) -> str:
9797
f"6. If `{p}run_skill_script` returns an error (for example "
9898
f"`SCRIPT_NOT_FOUND`), do not retry the same script or guess a "
9999
"different script path. Report the error to the user and stop.\n"
100+
f"7. Loading a skill only retrieves its instructions; it does NOT "
101+
f"complete your turn. After a `{p}load_skill` call returns, continue "
102+
"in the SAME turn: call whatever tools the skill's steps require "
103+
"(search, data retrieval, render), then write your reply. Never end "
104+
"your turn with an empty response right after loading a skill.\n"
100105
)
101106

102107

tests/unittests/tools/test_skill_toolset.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,24 @@ def test_system_instruction_references_run_skill_script():
17581758
)
17591759

17601760

1761+
def test_system_instruction_marks_load_skill_as_non_terminal():
1762+
"""Rule 7 must tell the model load_skill does not complete the turn.
1763+
1764+
Without it, some models (notably Gemini) treat the load_skill tool call as
1765+
the entire turn and stop with no visible output, producing empty responses.
1766+
"""
1767+
instruction = skill_toolset.DEFAULT_SKILL_SYSTEM_INSTRUCTION
1768+
assert "does NOT complete your turn" in instruction
1769+
assert "empty response" in instruction
1770+
1771+
1772+
def test_prefixed_system_instruction_includes_continue_after_load_rule():
1773+
"""The prefixed builder variant must also carry rule 7 (with the prefix)."""
1774+
instruction = skill_toolset._build_skill_system_instruction(prefix="my")
1775+
assert "does NOT complete your turn" in instruction
1776+
assert "my_load_skill" in instruction
1777+
1778+
17611779
# ── Finding 2: empty files are mounted (not silently dropped) ──
17621780

17631781

0 commit comments

Comments
 (0)