梦兽编程
AI_SUITE

Skills for Agents: Agent Skill Extension

Detailed explanation of Skills concept and usage in ADK Go—mounting preset skills to Agent, letting it do more professional tasks.

If Tools are the Agent’s “hands and feet”—letting it perform concrete actions such as querying a database, calling an API, or sending an email—then Skills are the Agent’s “professional knowledge base”—giving it systematic thinking frameworks, best practices, and domain language in a specific field. The Skill mechanism is the core architectural component in ADK Go for making Agents specialized, modular, and reusable.

From Tool to Skill: Upgrading Capability Abstraction

Understanding the difference between Skills and Tools is crucial for using ADK Go correctly:

DimensionToolSkill
Abstraction levelAtomic operation (single function call)Capability module (contains reasoning chain, multi-step workflow)
State managementUsually statelessCan maintain internal state and context
ComplexitySimple, single responsibilityComplex, domain-specific
Reuse styleCalled as a functionMounted as a module
Examplesquery_database, send_emaildata_analysis, code_review, contract_review

A Skill is essentially a pre-orchestrated Agent behavior template. It may include:

  • Domain-specific system instructions
  • Recommended Tool combinations
  • Preset chain-of-thought templates
  • Output-format specifications
  • Error handling and fallback strategies

For example, the “Data Analysis Skill” not only includes the Tool for calling a Python interpreter, but also the complete thinking framework of “understand data distribution → choose appropriate chart → generate insights.”

In-Depth Look at Built-in ADK Go Skills

ADK Go provides several built-in Skills, each deeply optimized for a specific scenario.

Code Interpreter Skill

This is one of the most commonly used built-in Skills. It gives the Agent the ability to execute code. Unlike simply exposing an exec_python Tool, the Code Interpreter Skill encapsulates a complete code-execution sandbox, error handling, and result-formatting logic.

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    "google.golang.org/adk/agent"
    "google.golang.org/adk/llm"
    "google.golang.org/adk/skill"
)

func main() {
    ctx := context.Background()

    model, err := llm.NewGeminiModel(ctx, llm.GeminiConfig{
        APIKey: os.Get...Y"),
        Model:  "gemini-2.0-pro",
    })
    if err != nil {
        log.Fatalf("Failed to initialize model: %v", err)
    }

    // Configure the Code Interpreter Skill
    codeSkill := skill.CodeInterpreter(
        skill.WithTimeout(30*time.Second),        // code execution timeout
        skill.WithMaxMemory(512*1024*1024),       // memory limit 512 MB
        skill.WithAllowedImports([]string{        // allowed package whitelist
            "numpy", "pandas", "matplotlib", "json", "math",
        }),
        skill.WithForbiddenPatterns([]string{     // forbidden dangerous operations
            `os\.system`, `subprocess\.call`, `eval\(`, `exec\(`,
        }),
    )

    agent, err := agent.New(agent.Config{
        Name:  "data-analyst",
        Model: model,
        Instruction: `You are a data analyst. When a user uploads data or asks data-related questions:
1. First understand the data structure and types
2. Use the Code Interpreter for exploratory data analysis (EDA)
3. Generate visualizations to aid explanation
4. Provide data-driven insights and recommendations
5. All analysis must be based on actual code execution results; never fabricate data`,
        Skills: []skill.Skill{codeSkill},
    })
    if err != nil {
        log.Fatalf("Failed to create Agent: %v", err)
    }

    resp, err := agent.Run(ctx, "Analyze the trend of this sales data:
Month,Sales
Jan,15000
Feb,18000
Mar,22000
Apr,19000
May,25000")
    if err != nil {
        log.Fatalf("Execution failed: %v", err)
    }

    fmt.Println(resp.Text)
}

Production Notes:

  1. Sandbox isolation: The Code Interpreter must run in a fully isolated environment. We recommend adding extra security layers with gVisor, Firejail, or container technology.

  2. Resource limits: Unrestricted code execution can exhaust CPU or memory. Always set MaxMemory and Timeout.

  3. Network isolation: By default, the code-execution environment should block network access to prevent data exfiltration or malicious downloads.

  4. State persistence: If you need to preserve variable state across multiple calls, use the Session storage mechanism provided by the Skill rather than global variables.

Web Search Skill

The Web Search Skill encapsulates the complete workflow of search-engine invocation, result filtering, content extraction, and credibility scoring. Its difference from Grounding is that Grounding is implicit, automatic search augmentation, while the Web Search Skill is an explicit, actively invoked research capability of the Agent.

webSearchSkill := skill.WebSearch(
    skill.WithSearchProvider(skill.GoogleSearchProvider{
        APIKey: os.Get...Y"),
        CX:     os.Getenv("GOOGLE_SEARCH_CX"),
    }),
    skill.WithResultLimit(10),
    skill.WithContentExtractor(skill.ReadabilityExtractor{}),  // extract body with Readability algorithm
    skill.WithCredibilityScorer(skill.DomainCredibilityScorer{
        // Bonus points for trusted domains
        TrustedDomains: []string{"arxiv.org", "github.com", "wikipedia.org"},
        // Penalty points for low-quality domains
        BlockedDomains: []string{"spam-site.com"},
    }),
)

Data Analysis Skill

The Data Analysis Skill is a higher-level wrapper over the Code Interpreter Skill, specifically optimized for structured-data analysis scenarios. It includes:

  • Data cleaning and preprocessing templates
  • Common statistical-test methods
  • Automatic chart-type recommendation (choosing the most suitable visualization based on data characteristics)
  • Outlier detection and handling strategies
dataSkill := skill.DataAnalysis(
    skill.WithVisualizationBackend(skill.MatplotlibBackend{
        OutputFormat: "png",
        DPI:          150,
    }),
    skill.WithStatisticalTests([]string{"t-test", "chi-square", "anova"}),
)

Custom Skills: Building Domain-Expert Agents

Built-in Skills cover general scenarios, but enterprise applications often require custom Skills for specific business domains. Below is a complete implementation of a custom Skill for the “intelligent contract review” scenario:

package contract

import (
    "context"
    "fmt"
    "regexp"
    "strings"

    "google.golang.org/adk/skill"
    "google.golang.org/adk/tool"
)

// ContractReviewSkill encapsulates professional contract-review capabilities
type ContractReviewSkill struct {
    riskRules       []RiskRule
    templateLibrary TemplateLibrary
    complianceDB    ComplianceDatabase
}

// RiskRule defines a risk-identification rule
type RiskRule struct {
    Name        string
    Severity    string  // critical, high, medium, low
    Pattern     *regexp.Regexp
    Description string
    Suggestion  string
}

// NewContractReviewSkill creates a contract-review Skill
func NewContractReviewSkill(db ComplianceDatabase) *ContractReviewSkill {
    return &ContractReviewSkill{
        riskRules: []RiskRule{
            {
                Name:        "Unlimited Liability Clause",
                Severity:    "critical",
                Pattern:     regexp.MustCompile(`(?i)unlimited liability`),
                Description: "The contract contains an unlimited liability clause, which may cause uncontrollable legal risk",
                Suggestion:  "Change to 'limited liability' and clarify a cap on compensation",
            },
            {
                Name:        "Automatic Renewal Clause",
                Severity:    "high",
                Pattern:     regexp.MustCompile(`(?i)automatic.*renewal|tacit.*renewal`),
                Description: "An automatic-renewal mechanism exists; the contract may renew without awareness",
                Suggestion:  "Add an explicit renewal notice period (e.g., 30 days written notice)",
            },
            {
                Name:        "Unilateral Modification Right",
                Severity:    "high",
                Pattern:     regexp.MustCompile(`(?i)unilateral.*modification`),
                Description: "One party has the right to modify contract terms unilaterally",
                Suggestion:  "Change to 'modification only after mutual agreement'",
            },
        },
        complianceDB: db,
    }
}

func (s *ContractReviewSkill) Name() string {
    return "contract-review"
}

func (s *ContractReviewSkill) Description() string {
    return "Professional contract risk-review capability that identifies legal risks, clause loopholes, and compliance issues"
}

func (s *ContractReviewSkill) Instructions() string {
    return `You are a professional contract-review legal assistant. When a user submits a contract text, you must:

1. **Structural analysis**: Identify the contract type (procurement, service, labor, lease, etc.) and main clauses
2. **Risk scanning**: Use the built-in rule library to scan high-risk clauses
3. **Compliance check**: Check compliance against the latest laws and regulations
4. **Clause recommendations**: Propose modifications for vague, unfair, or missing clauses
5. **Generate report**: Output a structured review report containing risk level, issue description, and modification suggestions

Review principles:
- Prioritize the client's interests
- Focus on enforceability (whether the clause will be supported by a court in a real dispute)
- Pay attention to timeliness (validity period, notice period, etc.)
- Remain objective and neutral, neither exaggerating risks nor overlooking issues`
}

func (s *ContractReviewSkill) Tools() []tool.Tool {
    return []tool.Tool{
        &ClauseExtractorTool{},
        &ComplianceCheckTool{DB: s.complianceDB},
        &RiskCalculatorTool{},
    }
}

func (s *ContractReviewSkill) BeforeRun(ctx context.Context, input string) (string, error) {
    // Preprocessing: normalize contract text
    normalized := strings.ReplaceAll(input, "
", "
")
    normalized = regexp.MustCompile(`\n{3,}`).ReplaceAllString(normalized, "

")
    return normalized, nil
}

func (s *ContractReviewSkill) AfterRun(ctx context.Context, output string) (string, error) {
    // Post-processing: ensure uniform report format
    if !strings.Contains(output, "## Review Conclusion") {
        output += "

## Review Conclusion

The above risks were identified in this contract. The client is advised to confirm with the legal department before signing."
    }
    return output, nil
}

// Register the Skill
func init() {
    skill.Register("contract-review", func(config map[string]interface{}) (skill.Skill, error) {
        db, ok := config["compliance_db"].(ComplianceDatabase)
        if !ok {
            return nil, fmt.Errorf("contract-review skill requires compliance_db configuration")
        }
        return NewContractReviewSkill(db), nil
    })
}

Using a Custom Skill

import "your-module/contract"

func main() {
    db := initComplianceDB()
    contractSkill := contract.NewContractReviewSkill(db)

    agent, err := agent.New(agent.Config{
        Name:   "legal-assistant",
        Model:  model,
        Skills: []skill.Skill{contractSkill},
    })
    // ...
}

Skill Composition and Orchestration

Complex business scenarios often require multiple Skills to work together. ADK Go supports Skill composition patterns, allowing you to build “Skill pipelines” or “Skill routers.”

Skill Pipeline Pattern

Data flows sequentially through multiple Skills, each performing specific processing:

pipeline := skill.NewPipeline(
    skill.DataExtractionSkill{},      // step 1: extract data from unstructured text
    skill.DataValidationSkill{},      // step 2: validate data integrity and accuracy
    skill.DataAnalysisSkill{},        // step 3: analyze patterns and trends
    skill.ReportGenerationSkill{},    // step 4: generate analysis report
)

agent, err := agent.New(agent.Config{
    Name:   "data-pipeline-agent",
    Skills: []skill.Skill{pipeline},
})

Skill Router Pattern

Dynamically select the most appropriate Skill based on input type:

router := skill.NewRouter()
router.Register("code", skill.CodeInterpreter())
router.Register("data", skill.DataAnalysis())
router.Register("image", skill.ImageAnalysis())
router.SetDefault(skill.GeneralConversation())

agent, err := agent.New(agent.Config{
    Name:   "multi-skill-agent",
    Skills: []skill.Skill{router},
})

Production Skill Management

Skill Version Control

As a core capability component of the Agent, Skill changes require strict version management:

type VersionedSkill struct {
    skill.Skill
    Version     string
    Changelog   string
    Deprecated  bool
    ReplacedBy  string  // if deprecated, points to the replacement version
}

func (v *VersionedSkill) ValidateCompatibility(other skill.Skill) error {
    // Check Skill version compatibility
    // For example, does v2 Skill remain compatible with v1 Agent configuration?
}

Skill Hot Reloading

In production, you do not want to restart the entire Agent service to update a Skill. You can implement a hot-reload mechanism:

type HotReloadableSkill struct {
    current atomic.Value  // stores *skill.Skill
    watcher *fsnotify.Watcher
}

func (h *HotReloadableSkill) Load(path string) error {
    // Watch the Skill definition file for changes
    h.watcher.Add(path)
    go func() {
        for event := range h.watcher.Events {
            if event.Op&fsnotify.Write == fsnotify.Write {
                newSkill, err := loadSkillFromFile(path)
                if err != nil {
                    log.Printf("Skill hot reload failed: %v", err)
                    continue
                }
                h.current.Store(newSkill)
                log.Printf("Skill hot updated: %s", newSkill.Name())
            }
        }
    }()
    return nil
}

func (h *HotReloadableSkill) Current() skill.Skill {
    return h.current.Load().(skill.Skill)
}

Skill Performance Monitoring

Every Skill’s call latency, success rate, and resource consumption should be monitored:

func (s *MonitoredSkill) Execute(ctx context.Context, input string) (string, error) {
    start := time.Now()

    result, err := s.inner.Execute(ctx, input)

    duration := time.Since(start)
    metrics.RecordHistogram("skill_latency", float64(duration.Milliseconds()),
        metrics.Tag{"skill", s.Name()})

    if err != nil {
        metrics.IncrementCounter("skill_errors",
            metrics.Tag{"skill", s.Name()})
    }

    return result, err
}

Common Pitfalls and Best Practices

Pitfall 1: Skill Over-Coupling

Stuffing too much logic into one Skill makes maintenance difficult and reuse low. Follow the single-responsibility principle: one Skill should only be responsible for one clear domain.

Pitfall 2: Blurred Boundary Between Skill and Tool

If a “Skill” simply wraps a single Tool call without extra domain logic or thinking framework, it should be a Tool, not a Skill.

Pitfall 3: Ignoring Skill Context-Window Consumption

Complex Skill instructions consume a large context window. Monitor the instruction length of each Skill, and split long instructions into core instructions plus loadable reference documents when necessary.

Pitfall 4: State Conflicts Between Skills

When multiple Skills are active at the same time, they may produce conflicting instructions or compete for Tool calls. Use clear priority mechanisms and conflict-resolution strategies.

Next Steps

Skills give Agents specialized domain capabilities, upgrading them from general assistants to industry experts. Next we will explore Callbacks and Plugins—the most powerful extension mechanism in ADK Go, letting you insert custom logic at every key point in the Agent lifecycle for true deep customization.

Artifacts | Callbacks & Plugins →


Want to learn more Go ADK hands-on? Follow the “Full-Stack Peak — Mengshou Programming” WeChat account for weekly Go / AI programming practice updates.

Frequently Asked Questions

What is the difference between a Skill and a Tool?

A Tool is an atomic single operation, while a Skill is a capability module that includes reasoning chains, multi-step workflows, and domain knowledge.

Why mount Skills on an Agent?

Skills give the Agent systematic thinking frameworks and best practices in a specific domain, enabling it to complete more professional tasks.

Which built-in Skills does ADK Go provide?

Common built-in Skills include Code Interpreter, Web Search, and Data Analysis.

How do I build a custom Skill?

Define the Skill's description, input/output schema, and execution logic, then mount it on the target Agent.

How do Skills improve Agent modularity and reusability?

Encapsulating domain capabilities into independent modules allows them to be reused across different Agents or projects, reducing duplicate development costs.