main.go
Overview
This file demonstrates a practical approach to creating a composite AI agent system capable of handling multiple tool types within a single agent context. Due to limitations in the underlying genai API, which restricts the use of diverse tool types (e.g., Google Search and custom functions) directly in one agent, this file implements a workaround by wrapping agents specialized for different toolsets into sub-agents. These sub-agents are then managed collectively by a root agent, allowing diversified capabilities such as web search and poem generation to coexist seamlessly.
The main functionality includes:
Initialization of a Gemini language model.
Creation of two distinct sub-agents:
A search agent utilizing a Google Search tool.
A poem generation agent exposing a custom function tool.
Composition of these sub-agents into a root agent with an instruction set that delegates tasks to the appropriate sub-agent.
Launching the root agent via a command-line launcher.
This approach supports modular AI agent design, enabling flexible multi-tool integration despite API constraints.
Detailed Explanation
Package Import and Setup
The file imports essential packages for context management, logging, and environment variable access, alongside multiple specialized packages from Google's AI Development Kit (adk), including:
genaiandgeminifor model instantiation.llmagent,agenttool,functiontool, andgeminitoolfor agent and tool creation.launcherandfullfor CLI launch support.
Main Function
func main()
Purpose: Entry point for the program; orchestrates the initialization and composition of agents and tools, then launches the agent runtime.
Parameters: None.
Returns: None.
Step 1: Model Initialization
model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
APIKey: os.Getenv("GOOGLE_API_KEY"),
})
Creates a Gemini model instance named
"gemini-2.5-flash".Uses the API key from the environment variable
GOOGLE_API_KEY.The model is used across all agents to generate responses.
On failure, logs fatal error and exits.
Step 2: Search Agent Creation
searchAgent, err := llmagent.New(llmagent.Config{
Name: "search_agent",
Model: model,
Description: "Does google search.",
Instruction: "You're a specialist in Google Search.",
Tools: []tool.Tool{
geminitool.GoogleSearch{},
},
})
Instantiates an LLM agent named
"search_agent".Uses the Gemini model for responses.
Equipped with the
GoogleSearchtool from thegeminitoolpackage.Instruction guides the agent to specialize in Google Search.
Handles queries requiring web information retrieval.
Step 3: Poem Generator Tool and Agent
type Input struct {
LineCount int `json:"lineCount"`
}
type Output struct {
Poem string `json:"poem"`
}
handler := func(ctx tool.Context, input Input) (Output, error) {
return Output{
Poem: strings.Repeat("A line of a poem,", input.LineCount) + "\n",
}, nil
}
poemTool, err := functiontool.New(functiontool.Config{
Name: "poem",
Description: "Returns poem",
}, handler)
Defines a simple custom function tool named
"poem"that generates a poem by repeating a line a given number of times.Uses JSON-serializable structs for input and output.
The handler function takes an input struct and returns an output struct with the generated poem string.
Created using
functiontool.Newwhich wraps Go functions as callable tools.
poemAgent, err := llmagent.New(llmagent.Config{
Name: "poem_agent",
Model: model,
Description: "returns poem",
Instruction: "You return poems.",
Tools: []tool.Tool{
poemTool,
},
})
Creates an LLM agent
"poem_agent"that uses the custom poem tool.Instruction directs it to focus on poem generation.
Step 4: Root Agent Composition
a, err := llmagent.New(llmagent.Config{
Name: "root_agent",
Model: model,
Description: "You can do a google search and generate poems.",
Instruction: "Answer questions about weather based on google search unless asked for a poem," +
" for a poem generate it with a tool.",
Tools: []tool.Tool{
agenttool.New(searchAgent, nil), agenttool.New(poemAgent, nil),
},
})
The root agent
"root_agent"combines the two sub-agents as tools usingagenttool.New.It uses instructions to decide when to delegate to the search agent or poem agent.
This composition enables multi-tool interaction transparently.
Step 5: Agent Launcher Setup and Execution
config := &launcher.Config{
AgentLoader: agent.NewSingleLoader(a),
}
l := full.NewLauncher()
if err = l.Execute(ctx, config, os.Args[1:]); err != nil {
log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax())
}
Creates a launcher configuration loading the root agent.
Executes the launcher with command-line arguments.
On failure, logs error and shows command usage.
Classes, Functions, and Methods
llmagent.New(config llmagent.Config) (*llmagent.Agent, error)
Constructs a new LLM agent instance.
Requires configuration including:
Name: Agent identifier.Model: Language model to use.Description: Text description of agent capabilities.Instruction: Prompt instructions for agent behavior.Tools: Slice oftool.Toolinterfaces the agent can invoke.
Returns an LLM agent or error.
gemini.NewModel(ctx context.Context, modelName string, config *genai.ClientConfig) (*gemini.Model, error)
Creates a Gemini language model client.
modelNamespecifies the Gemini model version.configcontains API key and client settings.Returns a model instance or error.
functiontool.New(config functiontool.Config, handler interface{}) (tool.Tool, error)
Wraps a Go function as a tool callable by agents.
handleris a function matching signature(context.Context, InputType) (OutputType, error).Provides automatic JSON schema inference for input/output.
agenttool.New(agent agent.Agent, options interface{}) tool.Tool
Wraps an existing agent as a tool to enable agent composition.
Allows an agent to delegate tasks to sub-agents.
launcher.Config
Holds configuration for agent launchers.
Includes the agent loader, command-line options, and execution parameters.
full.NewLauncher()
Creates a launcher that supports the full command-line interface for running agents.
Implementation Details and Algorithms
Agent Composition Workaround: Because
genaiAPI does not support multiple tool types in a single agent directly, the file implements a composite pattern using sub-agents wrapped as tools (agenttool.New). This design enables delegation and encapsulates different functionalities cleanly.Custom Function Tool: The poem generation tool is implemented as a Go function wrapped by
functiontool.New, showcasing the extensibility of the tool framework to include arbitrary logic.Instruction-Based Delegation: The root agent uses carefully crafted instructions to route requests to the appropriate sub-agent based on user intent (e.g., search queries vs. poems).
Robust Error Handling: Throughout initialization, errors are logged and cause termination, ensuring that the runtime does not proceed with invalid configurations.
Interaction with Other System Components
Gemini Model (
geminipackage): Provides the foundational language model for all agent instances.Tools (
geminitool.GoogleSearch,functiontool): Represent callable functionalities that agents use to respond to queries.Agents (
llmagentpackage): Encapsulate LLM-based behavior, instructions, and tools.Agent Composition (
agenttool): Enables using agents as tools, facilitating hierarchical agent design.Launcher (
launcher/full): Provides the runtime environment and CLI for starting and managing agents.Environment Variables: The API key for the Gemini model is sourced from
GOOGLE_API_KEY, integrating secure configuration.
Usage Example
To run the root agent, execute the compiled binary with optional CLI arguments. The agent will:
Respond to queries requiring Google Search by invoking the search agent.
Generate poems when prompted, using the poem agent.
Handle errors gracefully with logs.
Visual Diagram
flowchart TD
Main -->|Creates| GeminiModel[Gemini Model]
GeminiModel -->|Used by| SearchAgent[Search Agent]
GeminiModel -->|Used by| PoemAgent[Poem Agent]
SearchAgent -->|Uses| GoogleSearchTool[Google Search Tool]
PoemAgent -->|Uses| PoemTool[Poem Function Tool]
RootAgent[Root Agent]
SearchAgent -->|Wrapped as Tool| RootAgent
PoemAgent -->|Wrapped as Tool| RootAgent
Main -->|Creates| RootAgent
RootAgent -->|Managed by| Launcher[Launcher]
Launcher -->|Executes| RootAgent
This flowchart represents the primary structure and relationships:
The Gemini model is instantiated once and shared.
Two sub-agents (search and poem) are created, each with their respective tools.
These sub-agents are wrapped as tools and combined into the root agent.
The root agent is launched and managed via the command-line launcher.
This documentation references concepts from LLM Integration and Agents, Function Tools, and Agent Tools related to agent construction, tool wrapping, and multi-agent composition. It also leverages the launcher framework detailed in REST API and Web Launchers for runtime execution.