Across the AI Divide: Unifying Models with ai-manager and Go

Davin Hills
3 min readApr 3, 2024

--

Embarking on an adventure with multiple AI models, have you ever felt like you’re lost in a labyrinth of code, repeating the same spells over and over? Fear not, fellow coder! Your quest for efficiency and power in the realm of modern Large Language Models (LLMs) is about to become a legend, thanks to a magical tool called ai-manager. Grab your virtual capes, because we’re about to dive into a story of innovation, simplification, and coding wizardry — all of which are documented in the sacred halls of GitHub.

Of course, an AI rewrote the text of this article for me and made it silly — Davin

The Spark of Inspiration ✨

As I delved into the mysteries of various text completion engines, I found myself conjuring the same incantations repeatedly. “Enough!” I declared. With a vision to unify my interactions with the LLMs, I set forth to create ai-manager. This is my tale and the chronicle of how it came to be.

The First Puzzle: Uniting the Different 🔗

Peering into the depths of pre-built libraries provided by AI vendors, the differences between them seemed as vast as the ocean. Yet, as I began to invoke their REST APIs, patterns emerged like constellations in the night sky.

Consider these fragments from the Gemini and OpenAI message structures:

// Gemini message fragment
type Content struct {
Role string `json:"role"`
Parts []Part `json:"parts"`
}

type Part struct {
Text string `json:"text"`
}

// openAI message fragment
type MessageFrag struct {
Role string `json:"role,omitempty"`
Content string `json:"content,omitempty"`
}

Here, my fellow travelers lies our first enchantment: a universal message and conversation format. Whether they are called ‘user’ or ‘assistant’, these roles are the voices in our AI-powered dialogues.

package aimsg

// Conversation is the ongoing interaction with a model
type Conversation []Message

// Message represents a single interaction
type Message struct {
Role string
Text string
}

The Second Enigma: Invocation of AI Spirits 🧞

Each AI spirit demands an offering: an API key, a chosen model, and a conversation to engage in. Alongside these, I devised a charm to allow for AI-specific functionality through key-value pairs.

package aigen 

type Generator func(model, apikey string,
conversation aimsg.Conversation,
meta ...aimsg.Meta) (aimsg.Message, error)

Crafting a Generator for each AI became as simple as a wave of a wand:

package openai

func Generator(model, apiKey string, conversation aimsg.Conversation, _ ...aimsg.Meta) (aimsg.Message, error) {
// Convert generic conversation to OpenAI format
frags := []MessageFrag{}
for _, m := range conversation {
frags = append(frags, MessageFrag{Role: m.Role, Content: m.Text})
}

... Build Request
... Create json
... Call API

// Convert OpenAI specific message to general form
msg := aimsg.Message{
Role: roleAssistant,
Text: resp.Choices[0].Message.Content,
}

return msg, nil
}

The Grand Assembly: Conversing with AI Entities 🧙

With the power of ai-manager, our conversations with various AI models became as effortless as a gentle breeze.

package ai

type Manager struct {}

func (ai *Manager) RegisterGenerator(aiName, apiKey string,
models []string, generator aigen.Generator)

The Spellbook: How to Weave Magic with ai-manager 📜

Let the incantations begin! Here’s how we bind our AI spirits into service:

package main

import (
"ai-manager/ai"
"ai-manager/aigen/openai"
"fmt"
)

const (
openAIKey = "<YOUR OpenAI API Key>"
)

var openAIModels = []string{"gpt-4", "gpt-3.5-turbo", "gpt-4-turbo-preview"}

func main() {

// Summon the ai-manager
aimgr := ai.New(nil)

// Register our generators
aimgr.RegisterGenerator(openai.AIName, openAIKey, openAIModels, openai.Generator)

// Start casting
aimgr.NewThread(openai.AIName, "gpt-3.5-turbo")

// Engage the Oracle
output := make(chan string)
go aimgr.CurrentThread().Generate(output,
"Write a story about a superhero cat named Bitty")
}

Epilogue: A Call to Fellow Magicians 🌟

The ai-manager is open for all to use and enhance. Visit the sacred GitHub repository at ai-manager to partake in the shared knowledge. It possesses even more arcane secrets than revealed in this tale.

Find within its pages the OpenAI Generator, the Gemini Generator, the Mistral Generator, and the Basic Serializer, each a potent tool in the hands of a coding sorcerer.

Join me in this ever-evolving quest, contribute your spells, and let us together shape the future of how we interact with the sentient scripts of AI! 🧙‍♂️🔮

--

--

Davin Hills
Davin Hills

Written by Davin Hills

30+ years of experience in software engineering and architecture.

No responses yet