gollum

package module
v0.0.0-...-c3fa2bf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 8, 2025 License: MIT Imports: 3 Imported by: 0

README

GOLLuM

Production-grade LLM tooling. At least, in theory -- stuff changes fast so don't expect stability from this library so much as ideas for your own apps.

Features

  • Sane LLM provider abstraction.
  • Automated function dispatch
    • Parses arbitrary Go structs into JSONSchema for OpenAI - and validates when unmarshaling back to your structs
    • Simplified API to generate results from a single prompt or template
  • Highly performant vector store solution with exact search
    • SIMD acceleration for 10x better perf than naive approach, constant memory usage
    • Drop-in integration with OpenAI and other embedding providers
    • Carefully mocked, tested, and benchmarked.
  • Implementation of HyDE (hypothetical documents embeddings) for enhanced retrieval
  • MIT License

Examples

Dispatch

Function dispatch is a highly simplified and easy way to generate filled structs via an LLM.

type dinnerParty struct {
	Topic       string   `json:"topic" jsonschema:"required" jsonschema_description:"The topic of the conversation"`
	RandomWords []string `json:"random_words" jsonschema:"required" jsonschema_description:"Random words to prime the conversation"`
}
completer := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
d := gollum.NewOpenAIDispatcher[dinnerParty]("dinner_party", "Given a topic, return random words", completer, nil)
output, _ := d.Prompt(context.Background(), "Talk to me about dinosaurs")

The result should be a filled `dinnerParty`` struct.

expected := dinnerParty{
		Topic:       "dinosaurs",
		RandomWords: []string{"dinosaur", "fossil", "extinct"},
	}

Some similar libraries / ideas:

Parsing

Simplest

Imagine you have a function GetWeather --

type getWeatherInput struct {
	Location string `json:"location" jsonschema_description:"The city and state, e.g. San Francisco, CA" jsonschema:"required"`
	Unit     string `json:"unit,omitempty" jsonschema:"enum=celsius,enum=fahrenheit" jsonschema_description:"The unit of temperature"`
}

type getWeatherOutput struct {
    // ...
}

// GetWeather does something, this dosctring is annoying but theoretically possible to get
func GetWeather(ctx context.Context, inp getWeatherInput) (out getWeatherOutput, err error) {
    return out, err
}

This is a common pattern for API design, as it is eay to share the getWeatherInput struct (well, imagine if it were public). See, for example, the GRPC service definitions, or the Connect RPC implementation. This means we can simplify the logic greatly by assuming a single input struct.

Now, we can construct the responses:

type getWeatherInput struct {
	Location string `json:"location" jsonschema_description:"The city and state, e.g. San Francisco, CA" jsonschema:"required"`
	Unit     string `json:"unit,omitempty" jsonschema:"enum=celsius,enum=fahrenheit" jsonschema_description:"The unit of temperature"`
}

fi := gollum.StructToJsonSchema("weather", "Get the current weather in a given location", getWeatherInput{})

chatRequest := openai.ChatCompletionRequest{
    Model: "gpt-3.5-turbo-0613",
    Messages: []openai.ChatCompletionMessage{
        {
            Role:    "user",
            Content: "Whats the temperature in Boston?",
        },
    },
    MaxTokens:   256,
    Temperature: 0.0,
    Tools:       []openai.Tool{{Type: "function", Function: openai.FunctionDefinition(fi)}},
    ToolChoice:  "weather",
}

ctx := context.Background()
resp, err := api.SendRequest(ctx, chatRequest)
parser := gollum.NewJSONParser[getWeatherInput](false)
input, err := parser.Parse(ctx, resp.Choices[0].Message.ToolCalls[0].Function.Arguments)

This example steps through all that, end to end. Some of this is 'sort of' pseudo-code, as the OpenAI clients I use haven't implemented support yet for functions, but it should also hopefully show that minimal modifications are necessary to upstream libraries.

It is also possible to go from just the function definition to a fully formed OpenAI FunctionCall. Reflection gives name of the function for free, godoc parsing can get the function description too. I think in practice though that it's fairly unlikely that you need to change the name/description of the function that often, and in practice the inputs change more often. Using this pattern and compiling once makes the most sense to me.

We should be able to chain the call for the single input and for the ctx + single input case and return it easily.

Recursion on arbitrary structs without explicit definitions

Say you have a struct that has JSON tags defined.

fi := gollum.StructToJsonSchema("ChatCompletion", "Call the OpenAI chat completion API", chatCompletionRequest{})

chatRequest := chatCompletionRequest{
    ChatCompletionRequest: openai.ChatCompletionRequest{
        Model: "gpt-3.5-turbo-0613",
        Messages: []openai.ChatCompletionMessage{
            {
                Role:    openai.ChatMessageRoleSystem,
                Content: "Construct a ChatCompletionRequest to answer the user's question, but using Kirby references. Do not answer the question directly using prior knowledge, you must generate a ChatCompletionRequest that will answer the question.",
            },
            {
                Role:    openai.ChatMessageRoleUser,
                Content: "What is the definition of recursion?",
            },
        },
        MaxTokens:   256,
        Temperature: 0.0,
    },
    Tools: []openai.Tool{
        {
            Type: "function",
            Function: fi,
        }
    }
}
parser := gollum.NewJSONParser[openai.ChatCompletionRequest](false)
input, err := parser.Parse(ctx, resp.Choices[0].Message.ToolCalls[0].Function.Arguments)

On the first try, this yielded the following result:

 {
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "system", "content": "You are Kirby, a friendly virtual assistant."},
    {"role": "user", "content": "What is the definition of recursion?"}
  ]
}

That's really sick considering that no effort was put into manually creating a new JSON struct, and the original struct didn't have any JSONSchema tags - just JSON serdes comments.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ChatCompleter deprecated

type ChatCompleter interface {
	CreateChatCompletion(context.Context, openai.ChatCompletionRequest) (openai.ChatCompletionResponse, error)
}

Deprecated: use packages/llm/llm.go implementation

type Completer deprecated

type Completer interface {
	CreateCompletion(context.Context, openai.CompletionRequest) (openai.CompletionResponse, error)
}

Deprecated: who even uses this anymore?

type Document

type Document struct {
	ID        string                 `json:"id"`
	Content   string                 `json:"content,omitempty"`
	Embedding []float32              `json:"embedding,omitempty"`
	Metadata  map[string]interface{} `json:"metadata,omitempty"`
}

func NewDocumentFromString

func NewDocumentFromString(content string) Document

type Embedder

type Embedder interface {
	CreateEmbeddings(context.Context, openai.EmbeddingRequest) (openai.EmbeddingResponse, error)
}

type Moderator

type Moderator interface {
	Moderations(context.Context, openai.ModerationRequest) (openai.ModerationResponse, error)
}

Directories

Path Synopsis
internal
mocks
Package mock_gollum is a generated GoMock package.
Package mock_gollum is a generated GoMock package.
packages
llm
llm/internal/mocks
Package mock_llm is a generated GoMock package.
Package mock_llm is a generated GoMock package.
llm/providers/vertex
Package vertex implements the Vertex AI api it is largely similar to the Google "ai studio" provider but uses a different library...
Package vertex implements the Vertex AI api it is largely similar to the Google "ai studio" provider but uses a different library...
syncpool
Package syncpool provides a generic wrapper around sync.Pool Copied from https://github.com/mkmik/syncpool
Package syncpool provides a generic wrapper around sync.Pool Copied from https://github.com/mkmik/syncpool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL