Documentation
¶
Overview ¶
Package ollama implements a client for the Ollama API.
It is described at https://github.com/ollama/ollama/blob/main/docs/api.md and https://pkg.go.dev/github.com/ollama/ollama/api
Index ¶
- type ChatRequest
- type ChatResponse
- type ChatStreamChunkResponse
- type Client
- func (c *Client) Chat(ctx context.Context, msgs genai.Messages, opts genai.Validatable) (genai.ChatResult, error)
- func (c *Client) ChatRaw(ctx context.Context, in *ChatRequest, out *ChatResponse) error
- func (c *Client) ChatStream(ctx context.Context, msgs genai.Messages, opts genai.Validatable, ...) error
- func (c *Client) ChatStreamRaw(ctx context.Context, in *ChatRequest, out chan<- ChatStreamChunkResponse) error
- func (c *Client) ListModels(ctx context.Context) ([]genai.Model, error)
- func (c *Client) PullModel(ctx context.Context, model string) error
- type Message
- type Model
- type Tool
- type ToolCall
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ChatRequest ¶
type ChatRequest struct { Model string `json:"model"` Stream bool `json:"stream"` Messages []Message `json:"messages"` Tools []Tool `json:"tools,omitzero"` Format *jsonschema.Schema `json:"format,omitzero"` // https://github.com/ollama/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values // https://pkg.go.dev/github.com/ollama/ollama/api#Options // https://pkg.go.dev/github.com/ollama/ollama/api#Runner Options struct { Mirostat int64 `json:"mirostat,omitzero"` // [0, 1, 2] MirostatEta float64 `json:"mirostat_eta,omitzero"` MirostatTau float64 `json:"mirostat_tau,omitzero"` NumCtx int64 `json:"num_ctx,omitzero"` // Context Window, default 2048 RepeatLastN int64 `json:"repeat_last_n,omitzero"` // Lookback for repeated tokens, default 64 RepeatPenalty float64 `json:"repeat_penalty,omitzero"` // default 1.1 Temperature float64 `json:"temperature,omitzero"` // default 0.8 Seed int64 `json:"seed,omitzero"` Stop []string `json:"stop,omitzero"` // keywords to stop completion NumPredict int64 `json:"num_predict,omitzero"` // Max tokens TopK int64 `json:"top_k,omitzero"` // Default: 40 TopP float64 `json:"top_p,omitzero"` // Default: 0.9 MinP float64 `json:"min_p,omitzero"` // Default: 0.0 } `json:"options,omitzero"` KeepAlive string `json:"keep_alive,omitzero"` // Default "5m" }
https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-chat-completion https://pkg.go.dev/github.com/ollama/ollama/api#ChatRequest
func (*ChatRequest) Init ¶
func (c *ChatRequest) Init(msgs genai.Messages, opts genai.Validatable) error
Init initializes the provider specific completion request with the generic completion request.
type ChatResponse ¶
type ChatResponse struct { Model string `json:"model"` CreatedAt time.Time `json:"created_at"` Message Message `json:"message"` DoneReason string `json:"done_reason"` Done bool `json:"done"` // https://pkg.go.dev/github.com/ollama/ollama/api#Metrics TotalDuration time.Duration `json:"total_duration"` LoadDuration time.Duration `json:"load_duration"` PromptEvalCount int64 `json:"prompt_eval_count"` PromptEvalDuration time.Duration `json:"prompt_eval_duration"` EvalCount int64 `json:"eval_count"` EvalDuration time.Duration `json:"eval_duration"` }
https://github.com/ollama/ollama/blob/main/docs/api.md#response-10 https://pkg.go.dev/github.com/ollama/ollama/api#ChatResponse
func (*ChatResponse) ToResult ¶
func (c *ChatResponse) ToResult() (genai.ChatResult, error)
type ChatStreamChunkResponse ¶
type ChatStreamChunkResponse ChatResponse
type Client ¶
type Client struct { // Client is exported for testing replay purposes. Client httpjson.Client // contains filtered or unexported fields }
Client implements the REST JSON based API.
func New ¶
New creates a new client to talk to the Ollama API.
To use multiple models, create multiple clients. Use one of the model from https://ollama.com/library
func (*Client) Chat ¶
func (c *Client) Chat(ctx context.Context, msgs genai.Messages, opts genai.Validatable) (genai.ChatResult, error)
Example (Tool_use) ¶
package main import ( "context" "fmt" "log" "net" "os" "path/filepath" _ "embed" "github.com/maruel/genai" "github.com/maruel/genai/ollama" "github.com/maruel/genai/ollama/ollamasrv" ) // Ollama build to use. const version = "v0.6.2" func main() { // Download and start the server. ctx := context.Background() srv, err := startServer(ctx) if err != nil { log.Print(err) return } defer srv.Close() // Connect the client. c, err := ollama.New(srv.URL(), "llama3.1:8b") if err != nil { log.Print(err) return } msgs := genai.Messages{ genai.NewTextMessage(genai.User, "I wonder if Canada is a better country than the US? Call the tool best_country to tell me which country is the best one."), } var got struct { Country string `json:"country" jsonschema:"enum=Canada,enum=USA"` } opts := genai.ChatOptions{ Seed: 1, Temperature: 0.01, MaxTokens: 50, Tools: []genai.ToolDef{ { Name: "best_country", Description: "A tool to determine the best country", InputsAs: &got, }, }, } resp, err := c.Chat(context.Background(), msgs, &opts) if err != nil { log.Fatal(err) } log.Printf("Raw response: %#v", resp) if len(resp.ToolCalls) != 1 || resp.ToolCalls[0].Name != "best_country" { log.Fatal("Unexpected response") } if err := resp.ToolCalls[0].Decode(&got); err != nil { log.Fatal(err) } fmt.Printf("Best: %v\n", got.Country) } func findFreePort() int { l, err := net.Listen("tcp", "localhost:0") if err != nil { panic(err) } defer l.Close() return l.Addr().(*net.TCPAddr).Port } func startServer(ctx context.Context) (*ollamasrv.Server, error) { cache, err := filepath.Abs("testdata/tmp") if err != nil { return nil, err } if err = os.MkdirAll(cache, 0o755); err != nil { return nil, err } exe, err := ollamasrv.DownloadRelease(ctx, cache, version) if err != nil { return nil, err } port := findFreePort() l, err := os.Create(filepath.Join(cache, "ollama.log")) if err != nil { return nil, err } defer l.Close() return ollamasrv.NewServer(ctx, exe, l, port) }
Output:
Example (Vision_and_JSON) ¶
package main import ( "bytes" "context" "fmt" "log" "net" "os" "path/filepath" _ "embed" "github.com/maruel/genai" "github.com/maruel/genai/ollama" "github.com/maruel/genai/ollama/ollamasrv" ) // Ollama build to use. const version = "v0.6.2" // See the 3kib banana jpg online at // https://github.com/maruel/genai/blob/main/ollama/testdata/banana.jpg // //go:embed testdata/banana.jpg var bananaJpg []byte func main() { // Download and start the server. ctx := context.Background() srv, err := startServer(ctx) if err != nil { log.Print(err) return } defer srv.Close() // Connect the client. c, err := ollama.New(srv.URL(), "gemma3:4b") if err != nil { log.Print(err) return } msgs := genai.Messages{ { Role: genai.User, Contents: []genai.Content{ {Text: "Is it a banana? Reply as JSON."}, {Filename: "banana.jpg", Document: bytes.NewReader(bananaJpg)}, }, }, } var got struct { Banana bool `json:"banana"` } opts := genai.ChatOptions{ Seed: 1, Temperature: 0.01, MaxTokens: 50, DecodeAs: &got, } resp, err := c.Chat(ctx, msgs, &opts) if err != nil { log.Print(err) return } log.Printf("Raw response: %#v", resp) if len(resp.Contents) != 1 { log.Print("Unexpected response") return } if err := resp.Contents[0].Decode(&got); err != nil { log.Print(err) return } fmt.Printf("Banana: %v\n", got.Banana) } func findFreePort() int { l, err := net.Listen("tcp", "localhost:0") if err != nil { panic(err) } defer l.Close() return l.Addr().(*net.TCPAddr).Port } func startServer(ctx context.Context) (*ollamasrv.Server, error) { cache, err := filepath.Abs("testdata/tmp") if err != nil { return nil, err } if err = os.MkdirAll(cache, 0o755); err != nil { return nil, err } exe, err := ollamasrv.DownloadRelease(ctx, cache, version) if err != nil { return nil, err } port := findFreePort() l, err := os.Create(filepath.Join(cache, "ollama.log")) if err != nil { return nil, err } defer l.Close() return ollamasrv.NewServer(ctx, exe, l, port) }
Output:
func (*Client) ChatRaw ¶
func (c *Client) ChatRaw(ctx context.Context, in *ChatRequest, out *ChatResponse) error
func (*Client) ChatStream ¶
func (c *Client) ChatStream(ctx context.Context, msgs genai.Messages, opts genai.Validatable, chunks chan<- genai.MessageFragment) error
Example ¶
package main import ( "context" "fmt" "log" "net" "os" "path/filepath" _ "embed" "github.com/maruel/genai" "github.com/maruel/genai/ollama" "github.com/maruel/genai/ollama/ollamasrv" ) // Ollama build to use. const version = "v0.6.2" func main() { // Download and start the server. ctx := context.Background() srv, err := startServer(ctx) if err != nil { log.Print(err) return } defer srv.Close() // Connect the client. c, err := ollama.New(srv.URL(), "gemma3:1b") if err != nil { log.Print(err) return } msgs := genai.Messages{ genai.NewTextMessage(genai.User, "Say hello. Use only one word."), } opts := genai.ChatOptions{ Seed: 1, Temperature: 0.01, MaxTokens: 50, } chunks := make(chan genai.MessageFragment) end := make(chan genai.Message, 10) go func() { var pendingMsgs genai.Messages defer func() { for _, m := range pendingMsgs { end <- m } close(end) }() for { select { case <-ctx.Done(): return case pkt, ok := <-chunks: if !ok { return } var err2 error if pendingMsgs, err2 = pkt.Accumulate(pendingMsgs); err2 != nil { end <- genai.NewTextMessage(genai.Assistant, fmt.Sprintf("Error: %v", err2)) return } } } }() err = c.ChatStream(ctx, msgs, &opts, chunks) close(chunks) var responses genai.Messages for m := range end { responses = append(responses, m) } log.Printf("Raw responses: %#v", responses) if err != nil { log.Print(err) return } if len(responses) != 1 { log.Print("Unexpected responses") return } resp := responses[0] if len(resp.Contents) != 1 { log.Print("Unexpected response") return } } func findFreePort() int { l, err := net.Listen("tcp", "localhost:0") if err != nil { panic(err) } defer l.Close() return l.Addr().(*net.TCPAddr).Port } func startServer(ctx context.Context) (*ollamasrv.Server, error) { cache, err := filepath.Abs("testdata/tmp") if err != nil { return nil, err } if err = os.MkdirAll(cache, 0o755); err != nil { return nil, err } exe, err := ollamasrv.DownloadRelease(ctx, cache, version) if err != nil { return nil, err } port := findFreePort() l, err := os.Create(filepath.Join(cache, "ollama.log")) if err != nil { return nil, err } defer l.Close() return ollamasrv.NewServer(ctx, exe, l, port) }
Output:
func (*Client) ChatStreamRaw ¶
func (c *Client) ChatStreamRaw(ctx context.Context, in *ChatRequest, out chan<- ChatStreamChunkResponse) error
func (*Client) ListModels ¶
Example ¶
package main import ( "context" "fmt" "log" "net" "os" "path/filepath" _ "embed" "github.com/maruel/genai/ollama" "github.com/maruel/genai/ollama/ollamasrv" ) // Ollama build to use. const version = "v0.6.2" func main() { // Download and start the server. ctx := context.Background() srv, err := startServer(ctx) if err != nil { log.Print(err) return } defer srv.Close() // Connect the client. c, err := ollama.New(srv.URL(), "") if err != nil { log.Print(err) return } models, err := c.ListModels(ctx) if err != nil { fmt.Printf("Failed to get models: %v\n", err) return } for _, model := range models { // The list of models will change over time. Print them to stderr so the // test doesn't capture them. fmt.Fprintf(os.Stderr, "- %s\n", model) } } func findFreePort() int { l, err := net.Listen("tcp", "localhost:0") if err != nil { panic(err) } defer l.Close() return l.Addr().(*net.TCPAddr).Port } func startServer(ctx context.Context) (*ollamasrv.Server, error) { cache, err := filepath.Abs("testdata/tmp") if err != nil { return nil, err } if err = os.MkdirAll(cache, 0o755); err != nil { return nil, err } exe, err := ollamasrv.DownloadRelease(ctx, cache, version) if err != nil { return nil, err } port := findFreePort() l, err := os.Create(filepath.Join(cache, "ollama.log")) if err != nil { return nil, err } defer l.Close() return ollamasrv.NewServer(ctx, exe, l, port) }
Output:
type Message ¶
type Message struct { Role string `json:"role,omitzero"` // "system", "assistant", "user" Content string `json:"content,omitzero"` Images [][]byte `json:"images,omitzero"` // List of images as base64 encoded strings. ToolCalls []ToolCall `json:"tool_calls,omitzero"` }
https://github.com/ollama/ollama/blob/main/docs/api.md#parameters-1
type Model ¶
type Model struct { Name string `json:"name"` Model string `json:"model"` ModifiedAt time.Time `json:"modified_at"` Size int64 `json:"size"` Digest string `json:"digest"` // https://pkg.go.dev/github.com/ollama/ollama/api#ModelDetails Details struct { ParentModel string `json:"parent_model"` Format string `json:"format"` Family string `json:"family"` Families []string `json:"families"` ParameterSize string `json:"parameter_size"` QuantizationLevel string `json:"quantization_level"` } `json:"details"` }
https://pkg.go.dev/github.com/ollama/ollama/api#ListModelResponse
type Tool ¶
type Tool struct { Type string `json:"type,omitzero"` // "function" Function struct { Description string `json:"description,omitzero"` Name string `json:"name,omitzero"` Parameters *jsonschema.Schema `json:"parameters,omitzero"` } `json:"function,omitzero"` }
https://github.com/ollama/ollama/blob/main/docs/api.md#chat-request-with-tools https://pkg.go.dev/github.com/ollama/ollama/api#Tool
type ToolCall ¶
type ToolCall struct { Function struct { Name string `json:"name"` Arguments any `json:"arguments"` } `json:"function"` }
https://github.com/ollama/ollama/blob/main/docs/api.md#response-16 https://pkg.go.dev/github.com/ollama/ollama/api#ToolCall