Visitar URL original
feat(skills): let a classifier load the skill for a turn before the model's first step · Issue #8107 · google/adk-python · GitHub
Skip to content

feat(skills): let a classifier load the skill for a turn before the model's first step #8107

Description

@lwangverizon

** Please make sure you read the contribution guide and file the issues in the right place. **
Contribution guide.

🔴 Required Information

Is your feature request related to a specific problem?

With SkillToolset, every turn that needs a skill spends a full model step only
to decide which skill applies and call load_skill; the model reads the
instructions on the next step. In the default LAZY discovery mode it can spend
another step on list_skills first. Each of those steps re-sends the whole
prompt to the agent's (usually large) model, which adds latency and cost to the
most common skill turns.

ADK already ships typed classifiers (google.adk.labs.classifiers), but they
are only wired into workflow routing through ClassifierNode. Picking a skill
is the same kind of single-label decision.

Describe the Solution You'd Like

An opt-in classification_config on SkillToolset:

from google.adk.labs.classifiers import LlmClassifier
from google.adk.tools.skill_toolset import SkillClassificationConfig
from google.adk.tools.skill_toolset import SkillToolset

toolset = SkillToolset(
    skills=skills,
    classification_config=SkillClassificationConfig(
        classifier=LlmClassifier(model="gemini-flash-lite-latest"),
        threshold=0.7,
    ),
)

Before the model's first step of a turn, the classifier answers one Choice
question over the local skills (labels are skill names described by their
descriptions, plus a "no skill" label). When it picks a skill that is not
already active with at least threshold probability, the toolset loads it
through its own load_skill tool, recorded as a normal call and response in
the session. The model's first step then already has the skill's instructions
and its adk_additional_tools. Any other outcome, including a classifier error,
leaves the turn exactly as it is today.

Impact on your work

We run ADK skill agents in a latency-sensitive customer chat product. Most
turns load exactly one skill, so removing the routing step is a direct
per-turn latency and cost reduction.

Willingness to contribute

Yes. I have an implementation with tests and a guide update ready to open as a
PR.


🟡 Recommended Information

Describe Alternatives You've Considered

  • SkillDiscoveryMode.EAGER: removes the list_skills step, but the model
    still spends a step on load_skill.
  • SkillToolset.load_skill(ctx, name) from a callback: activates the tools
    but, by design, does not put the instructions in the conversation, so the
    model still needs to load the skill to know what to do.
  • SkillToolset.process_llm_request: cannot persist the activation, because
    the state delta of the context built there is discarded with the request.
  • Routing with a ClassifierNode in a Workflow: works only for agents built
    as graphs, and does not integrate with the skill lifecycle.

Proposed API / Implementation

  • SkillClassificationConfig(classifier, threshold=0.5, instructions=None), a
    frozen dataclass alongside SkillLifecycleConfig.
  • A new request processor skill_classification in SingleFlow, placed after
    request_confirmation and before contents. It runs only when the last
    event of the branch is the user's unanswered message for this invocation (and
    never under run_live), and asks each SkillToolset on the agent to
    preload.
  • The preload emits a load_skill function call (with
    SKIP_THOUGHT_SIGNATURE_VALIDATOR, as ReflectAndRetryModelPlugin does for
    its synthesized calls) and runs it through
    functions.handle_function_calls_async, so tool callbacks, plugins,
    lifecycle modes, pruning, revalidation and telemetry treat it like a
    model-made load. The call event records the classifier's choice and
    probability under custom_metadata["adk_skill_classification"].

Open question for maintainers: the processor is skill-specific, like the
agent-transfer and code-execution processors. A generic "toolset may emit
events before the model call" hook on BaseToolset is an alternative if you
prefer.

Additional Context

Scope deliberately kept small: local skills only (registry skills still go
through search_skills), only the latest user message is classified, and at
most one skill is loaded per turn.

Activity

  1. sanketpatil06 commented on Nov 13, 2026

    @sanketpatil06

    Hi @lwangverizon, thanks for bringing this and taking time to raise a PR. Your request is currently being reviewed, and we will let you know if anything further is needed. We appreciate your contribution.

  2. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    tools[Component] This issue is related to tools
    on Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

needs review[Status] The PR/issue is awaiting review from the maintainertools[Component] This issue is related to tools

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions