Skip to content

Commit f247ec6

Browse files
committed
fix(skills): prevent empty responses after load_skill
The skill system instruction's rule 2 told the model to follow loaded skill instructions "before replying to the user". Some models (notably Gemini) read this as license to treat the load_skill tool call as the entire turn and stop with no visible output, producing empty responses. This was most acute for tool-heavy skills, whose next correct action after load_skill is to call more tools rather than reply. Two changes to _build_skill_system_instruction: - Reword rule 2 to drop the "before replying" framing. - Add rule 7 stating that 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. Verified in a production environment: the empty-response rate for Gemini after skill loading dropped substantially with this guidance. Adds tests asserting the new prompt guarantees on both the default and prefixed system instruction.
1 parent 9e3b43f commit f247ec6

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

src/google/adk/tools/skill_toolset.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ def _build_skill_system_instruction(prefix: str | None = None) -> str:
8080
f'the `{p}load_skill` tool with `skill_name="<SKILL_NAME>"` to read '
8181
"its full instructions before proceeding.\n"
8282
"2. Once you have read the instructions, follow them exactly as "
83-
"documented before replying to the user. For example, If the "
84-
"instruction lists multiple steps, please make sure you complete all "
85-
"of them in order.\n"
83+
"documented. For example, if the instruction lists multiple steps, "
84+
"please make sure you complete all of them in order, and only then "
85+
"reply to the user.\n"
8686
f"3. The `{p}load_skill_resource` tool is for viewing files within a "
8787
"skill's directory (e.g., `references/*`, `assets/*`, `scripts/*`). "
8888
"It is ONLY for skill-bundled files — do NOT use it to access "
@@ -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: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,36 @@ 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_system_instruction_rule_2_avoids_before_replying_framing():
1773+
"""Rule 2 must not say to follow instructions "before replying".
1774+
1775+
That framing is read as license to end the turn after load_skill, which is
1776+
the original trigger for the empty-response regression.
1777+
"""
1778+
assert (
1779+
"before replying"
1780+
not in skill_toolset.DEFAULT_SKILL_SYSTEM_INSTRUCTION
1781+
)
1782+
1783+
1784+
def test_prefixed_system_instruction_includes_continue_after_load_rule():
1785+
"""The prefixed builder variant must also carry rule 7 (with the prefix)."""
1786+
instruction = skill_toolset._build_skill_system_instruction(prefix="my")
1787+
assert "does NOT complete your turn" in instruction
1788+
assert "my_load_skill" in instruction
1789+
1790+
17611791
# ── Finding 2: empty files are mounted (not silently dropped) ──
17621792

17631793

0 commit comments

Comments
 (0)