A Primer to building AI Agents in Go with Google ADK
Learn how to build AI agents in Go with Google ADK, from setting up your environment to creating your first agent and exploring advanced capabilities.
Yogesh Bhutkar
Software Engineer
What's Google ADK?
As per Google, "Agent Development Kit (ADK) is a flexible and modular framework for developing and deploying AI agents. While optimized for Gemini and the Google ecosystem, ADK is model-agnostic, deployment-agnostic, and is built for compatibility with other frameworks." You can read more about it in the official documentation.
Long story short: it’s a seriously powerful way to build AI agents — and it doesn’t make you commit to one model like it’s a long-term relationship. It’s completely model-agnostic, so you can plug in whatever model you like. (But, there's a catch!)
What are AI agents?
Again, as per ADK's official docs, "An Agent is a self-contained execution unit designed to act autonomously to achieve specific goals. Agents can perform tasks, interact with users, utilize external tools, and coordinate with other agents."
In simpler terms, an AI agent is a software entity that can perform tasks on its own, interact with users, and use tools to achieve specific goals. It’s like having a digital assistant that can do things for you without needing constant supervision.
Building an AI agent in Go with Google ADK
In this section, we'll go through the foundational steps to build an AI agent in Go using Google ADK. We'll understand agents better, and the way to create them with custom tools.
Step 1: We'll need a model
To build an AI agent, a language model is essential to provide its core functionality. While Google ADK is model-agnostic, it currently lacks first-party support for models like OpenAI's or Anthropic's.
Creating a Gemini model in ADK is straightforward. Here’s how you can do it:
1import (
2 "google.golang.org/adk/agent/llmagent"
3 "google.golang.org/adk/model/gemini"
4 "google.golang.org/genai"
5)
6
7modelFlash, err := gemini.NewModel(ctx, "gemini-2.0-flash", &genai.ClientConfig{})
8if err != nil {
9 log.Fatalf("failed to create model: %v", err)
10}If you require a model other than Gemini, you'll likely need to implement a custom solution. For instance, to use OpenAI's model, you can leverage a publicly available Go package, as demonstrated below:
1import adkopenai "github.com/huytd/adk-openai-go"
2
3model := adkopenai.NewModel("gpt-5-mini", &adkopenai.Config{
4 APIKey: apiKey,
5})Refer to the ADK documentation for more details on creating and using models.
Step 2: Create an agent
Once you have your model set up, you can create an agent. Here’s a simple example of how to create an agent in Go using Google ADK:
1agentGeminiFlash, err := llmagent.New(llmagent.Config{
2 Model: modelFlash,
3 Name: "super_handsome_agent",
4 Instruction: "You are a fast and helpful Gemini assistant.",
5})
6
7if err != nil {
8 log.Fatalf("failed to create agent: %v", err)
9}Step 3: Add tools to your agent (optional)
Tools are a powerful way to extend the capabilities of your AI agent. They allow your agent to perform specific tasks or access external resources. Here’s an example of a tool that can read the contents of a file in your file system:
1package tools
2
3import (
4 "log"
5 "os"
6 "path/filepath"
7
8 "google.golang.org/adk/tool"
9 "google.golang.org/adk/tool/functiontool"
10)
11
12type readFileArgs struct {
13 FilePath string `json:"file_path" jsonschema:"The absolute path of the file to read."`
14}
15
16type readFileResult struct {
17 Status string `json:"status"`
18 Content string `json:"content"`
19}
20
21func ReadFile(ctx tool.Context, args readFileArgs) (*readFileResult, error) {
22 basepath, err := os.Getwd()
23 if err != nil {
24 log.Printf("🚨 Error getting current working directory: %v", err)
25 return &readFileResult{Status: "error", Content: ""}, err
26 }
27
28 relativePath, err := filepath.Rel(basepath, args.FilePath)
29 if err != nil {
30 log.Printf("🚨 Error getting relative path for file %s: %v", args.FilePath, err)
31 return &readFileResult{Status: "error", Content: ""}, err
32 }
33
34 content, err := os.ReadFile(args.FilePath)
35 if err != nil {
36 log.Printf("🚨 Error reading file %s: %v", relativePath, err)
37 return &readFileResult{Status: "error", Content: ""}, err
38 }
39
40 log.Printf("📁 Successfully read file %s", relativePath)
41 return &readFileResult{Status: "success", Content: string(content)}, nil
42}
43
44func ReadFileTool() (tool.Tool, error) {
45 return functiontool.New(
46 functiontool.Config{
47 Name: "read_file",
48 Description: "Reads the content of a file given its absolute path and returns the content as a string",
49 },
50 ReadFile,
51 )
52}When creating tools, it's important to follow best practices to ensure they are effective and reliable. Use descriptive names that clearly convey the tool's purpose, and provide detailed descriptions to make their functionality easy to understand. Incorporate status indicators to signal success or failure, enabling the agent to make informed decisions based on the tool's output. Additionally, handle errors gracefully to ensure the agent can recover from unexpected situations and maintain smooth operation.
You can refer to the ADK documentation to understand more about tools and how to create custom tools for your agents.
Step 4: Add the tool to your agent
Once you have your tool created, you can add it to your agent like this:
1read_file_tool, err := tools.ReadFileTool()
2if err != nil {
3 log.Fatalf("🚨 Error creating read_file tool: %v", err)
4}
5
6agentGeminiFlash, err := llmagent.New(llmagent.Config{
7 Model: modelFlash,
8 Name: "super_handsome_agent",
9 Instruction: "You are a fast and helpful Gemini assistant.",
10 Tools: []tool.Tool{
11 read_file_tool,
12 },
13})Step 5: Setup a runner and execute the agent
To execute your agent, you need to set up a runner. The runner is responsible for managing the execution of the agent and its interactions with tools. Here's how you can set up a runner and execute your agent:
1sessionService := session.InMemoryService()
2runner, err := runner.New(runner.Config{
3 AppName: "readme_generator",
4 Agent: agent,
5 SessionService: sessionService,
6})
7if err != nil {
8 log.Fatal(err)
9}
10
11session, err := sessionService.Create(ctx, &session.CreateRequest{
12 AppName: "readme_generator",
13 UserID: defaultUserId,
14})
15if err != nil {
16 log.Fatal(err)
17}
18
19run(ctx, runner, session.Session.ID(), prompts.ReadmeGeneratorInitialPrompt)Here's how the run function looks like:
1func run(ctx context.Context, r *runner.Runner, sessionID string, prompt string) {
2 events := r.Run(
3 ctx,
4 defaultUserId,
5 sessionID,
6 genai.NewContentFromText(prompt, genai.RoleUser),
7 agent.RunConfig{
8 StreamingMode: agent.StreamingModeNone,
9 },
10 )
11
12 for _, err := range events {
13 if err != nil {
14 // Handle errors.
15 }
16 }
17}Final thoughts
Building AI agents in Go with Google ADK has been a truly enjoyable experience. The framework streamlines many complex tasks, making development significantly more efficient. Inspired by this, I developed a simple CLI tool that utilizes an agent and custom tools to generate a README file for a project. You can explore it here.
That said, I can’t help but wish for broader support for models from other providers, like OpenAI and Anthropic, directly out of the box. While it would make development much easier, it seems unlikely to happen anytime soon. Additionally, there are several features available in other languages that are missing in Go. For instance, the Python implementation of Google ADK supports LiteLLM, but this functionality isn’t available in Go. While there are third-party Go ports for LangChain, such as this one, their agent implementations are still quite limited too.
At the time of writing this article, Python remains my preferred language for building AI agents, especially when paired with tools like LangChain, LangGraph, and their ecosystems. However, Google ADK is an excellent choice if you’re working within the Gemini ecosystem. It offers a wide range of built-in tools that make it incredibly powerful.
I’d love to hear your thoughts on this article! If you have any questions or suggestions, feel free to share them in the comments.