Building an AI Agent in Go with Inferable

Nadeesha Cabral

In this tutorial, we'll build a simple AI agent that manages inventory operations using Go and Inferable. Our agent will be able to check stock levels, process orders, and restock items - all through natural language commands.

Prerequisites

Before we begin, make sure you have:

  • Go 1.20 or later installed
  • Basic familiarity with Go
  • Inferable CLI installed (npm install -g @inferablehq/inferable)

Authenticate with Inferable

inf auth login

Setting Up the Project

First, let's create a new Go project and install the Inferable SDK:

inf bootstrap go

This will run you through the steps of creating a new Go project and installing the Inferable SDK.

The project will contain some boilerplate code to get you started. Let's remove that because we'll be starting from scratch.

rm -rf main.go

Creating Our Inventory System

Let's start by defining our basic inventory types and a simple in-memory store:

package main

import (
    "fmt"
    "sync"

    "github.com/inferablehq/inferable-go"
)

// Item represents a product in our inventory
type Item struct {
    ID       string  `json:"id"`
    Name     string  `json:"name"`
    Price    float64 `json:"price"`
    Quantity int     `json:"quantity"`
}

// Store is our simple in-memory inventory
type Store struct {
    items map[string]Item
    mu    sync.RWMutex
}

// NewStore creates a new inventory store
func NewStore() *Store {
    return &Store{
        items: make(map[string]Item),
    }
}

// Initialize with some sample data
func (s *Store) Initialize() {
    s.items = map[string]Item{
        "LIGHT-1": {ID: "LIGHT-1", Name: "Lightsaber", Price: 199.99, Quantity: 5},
        "DROID-1": {ID: "DROID-1", Name: "Astromech Droid", Price: 2499.99, Quantity: 2},
        "FORCE-1": {ID: "FORCE-1", Name: "Force Crystal", Price: 99.99, Quantity: 10},
    }
}

Implementing Inventory Functions

Now, let's create the functions that our AI agent will use:

// CheckStockInput represents the input for checking stock
type CheckStockInput struct {
    ItemID string `json:"itemId" jsonschema:"required"`
}

// OrderInput represents the input for placing an order
type OrderInput struct {
    ItemID   string `json:"itemId" jsonschema:"required"`
    Quantity int    `json:"quantity" jsonschema:"minimum=1"`
}

// CheckStock returns the current stock level of an item
func (s *Store) CheckStock(input CheckStockInput) (*Item, error) {
    s.mu.RLock()
    defer s.mu.RUnlock()

    item, exists := s.items[input.ItemID]
    if !exists {
        return nil, fmt.Errorf("item not found: %s", input.ItemID)
    }

    return &item, nil
}

// ProcessOrder handles a new order
func (s *Store) ProcessOrder(input OrderInput) (*Item, error) {
    s.mu.Lock()
    defer s.mu.Unlock()

    item, exists := s.items[input.ItemID]
    if !exists {
        return nil, fmt.Errorf("item not found: %s", input.ItemID)
    }

    if item.Quantity < input.Quantity {
        return nil, fmt.Errorf("insufficient stock: requested %d, available %d",
            input.Quantity, item.Quantity)
    }

    item.Quantity -= input.Quantity
    s.items[input.ItemID] = item

    return &item, nil
}

Creating the Inferable Agent

Now comes the exciting part - connecting our inventory system to Inferable:

func main() {
    // Initialize our store
    store := NewStore()
    store.Initialize()

    // Create Inferable client
    client, err := inferable.New(inferable.InferableOptions{
        APISecret: os.Getenv("INFERABLE_API_SECRET"),
    })
    if err != nil {
        log.Fatal(err)
    }

    // Register our inventory service
    service := client.Default

    // Register the CheckStock function
    err = service.RegisterFunc(inferable.Function{
        Name:        "checkStock",
        Description: "Check the current stock level of an item",
        Func: func(input CheckStockInput) (*Item, error) {
            return store.CheckStock(input)
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    // Register the ProcessOrder function
    err = service.RegisterFunc(inferable.Function{
        Name:        "processOrder",
        Description: "Process an order for an item",
        Func: func(input OrderInput) (*Item, error) {
            return store.ProcessOrder(input)
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    // Start the service
    err = service.Start()
    if err != nil {
        log.Fatal(err)
    }

    // Keep the application running
    select {}
}

Using our multi-agent system

To run the agent, use the inf app command from within the project directory.

inf app

With our agent running, we can now interact with it through natural language using the Inferable platform. Here are some example interactions:

  1. Checking stock:

    "What's the current stock level of lightsabers?"
    
  2. Processing an order:

    "I'd like to order 2 lightsabers please"
    

The agent will understand these natural language requests and automatically:

  1. Parse the intent
  2. Map to the appropriate function
  3. Extract the required parameters
  4. Execute the function
  5. Return the results in a user-friendly format

How It Works

Behind the scenes, Inferable:

  1. Uses LLMs to understand the natural language input
  2. Maps the intent to our registered functions
  3. Validates the input against our JSON schemas
  4. Executes the functions in our Go service
  5. Formats the response for the user

The agent can handle complex queries and even multi-step operations. For example, it can check stock before processing an order, all from a single natural language request.

Security and Control

One of the best parts about this implementation is that all the actual inventory operations run in your own machine. Inferable never has direct access to your data - it only orchestrates the function calls based on the natural language input.

Next Steps

You can extend this basic agent in several ways:

  1. Add more complex inventory operations
  2. Implement persistent storage
  3. Add approval workflows for large orders
  4. Integrate with real inventory systems
  5. Add data masking for sensitive information

Conclusion

We've built a simple but powerful AI agent that can manage inventory operations through natural language. The Inferable Go SDK made it easy to connect our existing Go code to an AI interface, while maintaining full control over our business logic and data.