Go Artificial Intelligence (GAI) helps you work with foundational models, large language models, and other AI models.
Pronounced like "guy".
go get maragu.dev/gai
Made with ✨sparkles✨ by maragu.
Does your company depend on this project? Contact me at markus@maragu.dk to discuss options for a one-time or recurring invoice to ensure its continued thriving.
Evals will only run with go test -run TestEval ./...
and otherwise be skipped.
Eval a mocked model, construct a sample, score it with a lexical similarity scorer and a semantic similarity scorer, and log the results.
package examples_test
import (
"context"
"math/rand/v2"
"testing"
"maragu.dev/gai"
"maragu.dev/gai/eval"
)
// TestEvalPing evaluates pinging the model.
// All evals must be prefixed with "TestEval".
func TestEvalPing(t *testing.T) {
// Evals only run if "go test" is being run with "-test.run=TestEval", e.g.: "go test -test.run=TestEval ./..."
eval.Run(t, "answers with a pong", func(t *testing.T, e *eval.E) {
// Initialize our intensely powerful in-memory foundation model,
// which can do both chat completion and embedding.
model := &powerfulModel{response: "plong", dimensions: 3}
// Send our input message to the model and get a streaming output back.
input := "ping"
res, err := model.ChatComplete(t.Context(), gai.ChatCompleteRequest{
Messages: []gai.Message{
gai.NewUserTextMessage(input),
},
})
if err != nil {
t.Fatal(err)
}
// The output is streamed and accessible through an iterator via the Parts() method.
var output string
for part, err := range res.Parts() {
if err != nil {
t.Fatal(err)
}
output += part.Text()
}
// Create a sample to pass to the scorer.
sample := eval.Sample{
Input: input,
Output: output,
Expected: "pong",
}
// Score the sample using a lexical similarity scorer with the Levenshtein distance.
lexicalSimilarityResult := e.Score(sample, eval.LexicalSimilarityScorer(eval.LevenshteinDistance))
// Also score with a semantic similarity scorer based on embedding vectors and cosine similarity.
semanticSimilarityResult := e.Score(sample, eval.SemanticSimilarityScorer(t, model, eval.CosineSimilarity))
// Log the sample, results, and timing information.
e.Log(sample, lexicalSimilarityResult, semanticSimilarityResult)
})
}
type powerfulModel struct {
dimensions int
response string
}
// ChatComplete satisfies [gai.ChatCompleter].
func (m *powerfulModel) ChatComplete(ctx context.Context, req gai.ChatCompleteRequest) (gai.ChatCompleteResponse, error) {
return gai.NewChatCompleteResponse(func(yield func(gai.MessagePart, error) bool) {
if !yield(gai.TextMessagePart(m.response), nil) {
return
}
}), nil
}
var _ gai.ChatCompleter = (*powerfulModel)(nil)
// Embed satisfies [gai.Embedder].
func (m *powerfulModel) Embed(ctx context.Context, req gai.EmbedRequest) (gai.EmbedResponse[float64], error) {
var embedding []float64
for range m.dimensions {
embedding = append(embedding, rand.Float64())
}
return gai.EmbedResponse[float64]{Embedding: embedding}, nil
}
var _ gai.Embedder[float64] = (*powerfulModel)(nil)