golm

package module
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Mar 17, 2025 License: MIT Imports: 8 Imported by: 1

README

Go-LM

Go bindings and API for popular LLM services.

go get github.com/a-novel-kit/golm

GitHub Actions Workflow Status codecov Go Report Card

GitHub go.mod Go version GitHub repo file or directory count GitHub code size in bytes

Coverage graph

Chat completion

Available bindings:

Configure a binding

You can use bindings available from this repository to configure your Groq client.

package main

import (
	"os"

	"github.com/a-novel-kit/golm/bindings/groq"
	"github.com/a-novel-kit/golm/bindings/groq/models"
)

func main() {
	binding := groq.New(os.Getenv("GROQ_TOKEN"), models.ModelLlama3370BVersatile)
}

Once you have a binding configured, you can use it to initialize a new chat instance.

package main

import (
	"github.com/a-novel-kit/golm"
)

func main() {
	chat := golm.NewChat(binding)
}

Make a simple completion request

package main

import (
	"log"

	"github.com/a-novel-kit/golm"
)

func main() {
	chat := golm.NewChat(binding)

	message := golm.NewUserMessage("Count from 1 to ten.")

	resp, _ := chat.Completion(context.Background(), message, golm.CompletionParams{})

	// [Assistant]:
	// Here is a list of numbers from 1 to 10:
	// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
	log.Println(resp)
}

You can set a system message to bias the behavior of the completion.

package main

import (
	"log"

	"github.com/a-novel-kit/golm"
)

func main() {
	chat := golm.NewChat(binding)

	chat.SetSystem(golm.NewSystemMessage(
		"You are a counter. Just count. Return your answer as a list of " +
			"numbers separated by commas. Example: 1,2,3",
    ))

	message := golm.NewUserMessage("Count from 1 to ten.")

	resp, _ := chat.Completion(context.Background(), message, golm.CompletionParams{})

	// [Assistant]:
	// 1,2,3,4,5,6,7,8,9,10
	log.Println(resp)
}

JSON response

You can instruct your model to return JSON, and let the binding parse it for you.

Smaller models might have trouble returning proper JSON, and it might not be supported well by all APIs.

package main

import (
	"context"
	"log"

	"github.com/a-novel-kit/golm"
)

func main() {
	chat := golm.NewChat(binding)

	// Most models will require you to specify the JSON format,
	// somewhere in the chat history.
	chat.SetSystem(golm.NewSystemMessage(
		"You are a counter. Just count. Return your answer as a JSON array of " +
			"numbers, separated by commas. Wrap your array in the key \"count\". " +
			"Example: { \"count\": [1,2,3] }",
	))

	message := golm.NewUserMessage("Count from 1 to ten.")

	var jsonOutput struct {
		Count int `json:"count"`
	}

	_ = chat.CompletionJSON(context.Background(), message, golm.CompletionParams{}, &jsonOutput)

	// { "count": [1,2,3,4,5,6,7,8,9,10] }
	log.Println(jsonOutput)
}

Streaming

package main

import (
	"context"
	"log"
	"time"

	"github.com/a-novel-kit/golm"
)

func main() {
	chat := golm.NewChat(binding)

	chat.SetSystem(golm.NewSystemMessage(
		"You are a counter. Just count. Return your answer as a list of " +
			"numbers separated by commas. Example: 1,2,3",
	))

	message := golm.NewUserMessage("Count from 1 to ten.")

	// Make sure to have some security to prevent the request from
	// hanging. The chat implementation should support cancelable
	// contexts.
	timedCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	outC, terminate := chat.CompletionStream(timedCtx, message, golm.CompletionParams{})

	var output string

	for elem := range outC {
		output += elem
	}

	if err := terminate(); err != nil {
        panic(err)
    }

	// 1,2,3,4,5,6,7,8,9,10
	log.Println(output)
}

Manipulating history

When you call the completion API, the message history is automatically updated.

package main

import (
	"log"

	"github.com/a-novel-kit/golm"
)

func main() {
	chat := golm.NewChat(binding)

	message := golm.NewUserMessage("Count from 1 to ten.")

	_, _ = chat.Completion(context.Background(), message, golm.CompletionParams{})

	// This query is aware of the previous request / answer.
	message = golm.NewUserMessage("Keep counting up to 20")
	resp, _ := chat.Completion(context.Background(), message, golm.CompletionParams{})

	// [Assistant]:
	// 11,12,13,14,15,16,17,18,19,20
	log.Println(resp)
}

You can change this history / add messages manually.

package main

import (
	"context"
	"log"

	"github.com/a-novel-kit/golm"
)

func main() {
	chat := golm.NewChat(binding)

	chat.PushHistory(
		golm.NewUserMessage("Count from 1 to ten."),
		golm.NewAssistantMessage("one, two, three, four, five, six, seven, eight, nine, ten"),
	)

	message := golm.NewUserMessage("Keep counting up to 20")
	resp, _ := chat.Completion(context.Background(), message, golm.CompletionParams{})

	// [Assistant]:
	// eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty
	log.Println(resp)
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WithContext added in v0.1.1

func WithContext[Req, Res, Stream any](ctx context.Context, binding ChatBinding[Req, Res, Stream]) context.Context

WithContext associates a new Chat instance with the current context, from the provided binding.

Types

type AssistantMessage

type AssistantMessage struct {
	Content string
}

func NewAssistantMessage

func NewAssistantMessage(content string) AssistantMessage

func NewAssistantMessageF added in v0.1.4

func NewAssistantMessageF(format string, args ...interface{}) AssistantMessage

func NewAssistantMessageT added in v0.1.4

func NewAssistantMessageT(t *template.Template, tName string, data any) (AssistantMessage, error)

func (AssistantMessage) GetContent

func (message AssistantMessage) GetContent() string

func (AssistantMessage) Role

func (message AssistantMessage) Role() MessageRole

func (AssistantMessage) String

func (message AssistantMessage) String() string

type Chat

type Chat[RawRequest, RawResponse any] interface {
	ChatBase
	ChatRaw[RawRequest, RawResponse]
}

func ContextWithRaw added in v0.1.1

func ContextWithRaw[Req, Res any](ctx context.Context) Chat[Req, Res]

func NewChat

func NewChat[Req, Res, Stream any](binding ChatBinding[Req, Res, Stream]) Chat[Req, Res]

NewChat returns a new Chat instance based on the provided binding.

Since a chat instance maintains its own history, it is recommended to create a new chat instance for each new process.

type ChatBase

type ChatBase interface {
	// SetHistory replaces the current history with the provided one.
	SetHistory(history ChatHistory)
	// GetHistory returns the current history.
	//
	// The returned history is a copy of the one used internally, so you can modify it without affecting the interna
	// state.
	GetHistory() ChatHistory
	// PushHistory adds the provided messages to the history.
	PushHistory(messages ...MessageWithRole)
	// SetSystem replaces the current system message with the provided one.
	SetSystem(system *SystemMessage)

	// Completion returns the LLM response to the provided message, based on user history.
	//
	// The LLM response is automatically added to history.
	Completion(
		ctx context.Context, message UserMessage, options CompletionParams,
	) (response *AssistantMessage, err error)
	// CompletionJSON ets the LLM response to the provided message, and attempts to parse it into the desired
	// destination.
	//
	// You might need to instruct your model to return JSON depending on the selected binding.
	//
	// The LLM response is automatically added to history.
	CompletionJSON(ctx context.Context, message UserMessage, options CompletionParams, dest any) (err error)
	// CompletionStream returns a channel that will be filled with the LLM response to the provided message, as
	// data bits are received from the LLM. The channel must be automatically closed by the implementation, so you
	// just have to worry about reading from it.
	//
	// The LLM response is automatically added to history. If the stream is closed early, then the already read bits
	// might form an incomplete response in the history.
	CompletionStream(
		ctx context.Context, message UserMessage, options CompletionParams,
	) (response <-chan string, wait utils.StreamWaitFn)
}

func Context added in v0.1.1

func Context(ctx context.Context) ChatBase

type ChatBinding

type ChatBinding[RawRequest, RawResponse, StreamResponse any] interface {
	RawQuery(ctx context.Context, request RawRequest, history ChatHistory) (response RawResponse, err error)
	Completion(
		ctx context.Context, message UserMessage, options CompletionParams, history ChatHistory,
	) (response *AssistantMessage, err error)
	CompletionStream(
		ctx context.Context, message UserMessage, options CompletionParams, history ChatHistory,
	) (response <-chan StreamResponse, wait utils.StreamWaitFn)
	StreamResponseToMessage(response StreamResponse) (message string)
}

ChatBinding represents the minimum set of methods that a binding should implement, for it to be turned into a Chat instance.

type ChatHistory

type ChatHistory struct {
	System  *SystemMessage
	History []MessageWithRole
}

func (*ChatHistory) GetHistory

func (chatHistory *ChatHistory) GetHistory() ChatHistory

func (*ChatHistory) PushHistory

func (chatHistory *ChatHistory) PushHistory(messages ...MessageWithRole)

func (*ChatHistory) SetHistory

func (chatHistory *ChatHistory) SetHistory(history ChatHistory)

func (*ChatHistory) SetSystem

func (chatHistory *ChatHistory) SetSystem(system *SystemMessage)

func (*ChatHistory) String

func (chatHistory *ChatHistory) String() string

type ChatRaw

type ChatRaw[RawRequest, RawResponse any] interface {
	RawQuery(ctx context.Context, request RawRequest) (response RawResponse, err error)
}

ChatRaw is an interface used to access the raw implementation of a LLM binding. It lets you tinkle with all the options offered by the binding, with the downside of letting you in charge of parsing the response and managing messages history.

type ChatWithBinding

type ChatWithBinding[RawRequest, RawResponse, StreamResponse any] struct {
	ChatHistory
	// contains filtered or unexported fields
}

func (*ChatWithBinding[RawRequest, RawResponse, StreamResponse]) Completion

func (chat *ChatWithBinding[RawRequest, RawResponse, StreamResponse]) Completion(
	ctx context.Context, message UserMessage, options CompletionParams,
) (*AssistantMessage, error)

func (*ChatWithBinding[RawRequest, RawResponse, StreamResponse]) CompletionJSON

func (chat *ChatWithBinding[RawRequest, RawResponse, StreamResponse]) CompletionJSON(
	ctx context.Context, message UserMessage, options CompletionParams, dest any,
) error

func (*ChatWithBinding[RawRequest, RawResponse, StreamResponse]) CompletionStream

func (chat *ChatWithBinding[RawRequest, RawResponse, StreamResponse]) CompletionStream(
	ctx context.Context, message UserMessage, options CompletionParams,
) (<-chan string, utils.StreamWaitFn)

func (*ChatWithBinding[RawRequest, RawResponse, StreamResponse]) RawQuery

func (chat *ChatWithBinding[RawRequest, RawResponse, StreamResponse]) RawQuery(
	ctx context.Context, request RawRequest,
) (RawResponse, error)

type CompletionParams

type CompletionParams struct {
	Temperature     *float64
	MaxOutputLength int
	User            string
	JSON            bool
}

type MessageRole

type MessageRole string
const (
	MessageRoleUser      MessageRole = "user"
	MessageRoleAssistant MessageRole = "assistant"
)

type MessageWithRole

type MessageWithRole interface {
	Role() MessageRole
	GetContent() string
	fmt.Stringer
}

type SystemMessage

type SystemMessage struct {
	Content string
}

func NewSystemMessage

func NewSystemMessage(content string) *SystemMessage

func NewSystemMessageF added in v0.1.4

func NewSystemMessageF(format string, args ...interface{}) *SystemMessage

func NewSystemMessageT added in v0.1.4

func NewSystemMessageT(t *template.Template, tName string, data any) (*SystemMessage, error)

func (SystemMessage) String

func (message SystemMessage) String() string

type UserMessage

type UserMessage struct {
	Content string
}

func NewUserMessage

func NewUserMessage(content string) UserMessage

func NewUserMessageF added in v0.1.4

func NewUserMessageF(format string, args ...interface{}) UserMessage

func NewUserMessageT added in v0.1.4

func NewUserMessageT(t *template.Template, tName string, data any) (UserMessage, error)

func (UserMessage) GetContent

func (message UserMessage) GetContent() string

func (UserMessage) Role

func (message UserMessage) Role() MessageRole

func (UserMessage) String

func (message UserMessage) String() string

Directories

Path Synopsis
bindings

Jump to

Keyboard shortcuts

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