gollm

repository·main·Indexed 20 days ago

https://github.com/teilomillet/gollm

A Go package providing a unified interface for interacting with Large Language Model (LLM) providers including OpenAI, Anthropic, Ollama, Groq, Mistral, and OpenRouter. It includes a testing framework for prompt engineering and model comparison, support for structured and flattened conversation memory, and advanced features like prompt caching, JSON schema enforcement, and tool calling.

Tokens
22.3K
Snippets
69
Records
88
Agent score
70%

What's inside gollm

  1. Use structured messages for prompt caching

    main

    When using memory, gollm uses structured messages by default. This is highly compatible with providers like Anthropic that support prompt caching. You can explicitly control cache behavior using AddStructuredMessage.

    Use the cache_control parameter (e.g., "ephemeral") to mark specific messages for caching, which reduces token costs and improves latency for repeated context.

    // Add a message with cache control
    // "ephemeral" caching is recommended for most use cases
    llm.AddStructuredMessage("user", "Here is a long document to analyze...", "ephemeral")
    
    // Generate - subsequent requests with the same context will use cached tokens
    response, err := llm.Generate(ctx, gollm.NewPrompt("Summarize the key points"))
  2. How the Gollm provider system works

    main

    Gollm uses a provider system to connect to different LLM APIs through a consistent interface. Providers are categorized by their API format:

    • OpenAI-compatible: Uses the OpenAI chat completion API format (e.g., OpenAI, Azure OpenAI, Groq, DeepSeek).
    • Anthropic-compatible: Uses the Anthropic Claude API format (e.g., Anthropic, Claude).
    • Custom: Requires a unique implementation for non-standard API formats.

    The system uses a registry to manage providers. When you request a provider, the system either uses a built-in implementation or creates a GenericProvider based on a ProviderConfig.

  3. Configure OpenRouter model fallbacks and auto-routing

    main

    OpenRouter supports model fallback and automatic model selection:

    • Model Fallbacks: Specify a list of models to use if the primary model fails using llm.SetOption("fallback_models", []string{...}).
    • Auto-Routing: Use the special model name openrouter/auto to let OpenRouter automatically select the best model for your prompt.
    // Fallbacks
    llm.SetOption("fallback_models", []string{"openai/gpt-4o", "gryphe/mythomax-l2-13b"})
    
    // Auto-routing
    llm, err := gollm.NewLLM(
        gollm.SetProvider("openrouter"),
        gollm.SetAPIKey(apiKey),
        gollm.SetModel("openrouter/auto"),
    )
  4. Use Cache Control with Structured Messages

    main

    When using structured messages, you can optimize message processing by applying cache control instructions to individual messages. This is particularly useful for reducing latency and costs with APIs that support prompt caching.

    Use the AddStructuredMessage method to specify a cache control option:

    • "ephemeral": The message can be cached but may be evicted if space is needed.
    • "persistent": The message should be kept in cache indefinitely.
    • "" (empty string): No special caching instruction.
    // Add message with cache control
    memLLM.AddStructuredMessage("user", "Hello, who are you?", "ephemeral")
  5. Structured vs Flattened Messages in gollm

    main

    gollm supports two ways of handling conversation history in memory:

    1. Structured Messages (Default): Each message is preserved as a separate object with its own metadata. This is more efficient for caching (especially with providers like Anthropic) and preserves conversation structure better.
    2. Flattened Messages (Legacy): Conversations are flattened into a single text string.

    By default, all newly created LLMWithMemory instances use structured messages. You can revert to the flattened approach by calling SetUseStructuredMessages(false).

  6. Extend an existing provider

    main

    If a provider is similar to an existing one (e.g., a slightly modified OpenAI implementation), you can extend the existing provider struct. This allows you to reuse most of the logic while overriding specific methods like Name() or Endpoint().

    To register the extended provider, use GetDefaultRegistry().Register within an init() function.

    package providers
    
    // MyProvider extends the OpenAI provider
    type MyProvider struct {
        OpenAIProvider
    }
    
    // Create a new instance
    func NewMyProvider(apiKey, model string, extraHeaders map[string]string) Provider {
        provider := &MyProvider{
            OpenAIProvider: *NewOpenAIProvider(apiKey, model, extraHeaders).(*OpenAIProvider),
        }
        return provider
    }
    
    // Override any methods that need customization
    func (p *MyProvider) Name() string {
        return "my-provider"
    }
    
    func (p *MyProvider) Endpoint() string {
        return "https://custom-endpoint.com/api"
    }
    
    // Register the provider
    func init() {
        GetDefaultRegistry().Register("my-provider", NewMyProvider)
    }
  7. Create an LLM with Memory and Structured Messages

    main

    To use memory, first create a base LLM instance, then wrap it using NewLLMWithMemory. The resulting instance uses structured messages by default. You may need to type-assert the result to *llm.LLMWithMemory to access memory-specific methods.

    // Create base LLM instance
    baseLLM, err := llm.NewLLM(cfg, logger, registry)
    if err != nil {
        log.Fatalf("Failed to create LLM: %v", err)
    }
    
    // Create LLM with memory (uses structured messages by default)
    memoryLLM, err := llm.NewLLMWithMemory(baseLLM, 4000, cfg.Model)
    if err != nil {
        log.Fatalf("Failed to create LLM with memory: %v", err)
    }
    
    // Cast to access specific methods
    memLLM := memoryLLM.(*llm.LLMWithMemory)
  8. Use the OpenRouter provider with GoLLM

    main

    To use OpenRouter, initialize an LLM instance using gollm.NewLLM with the gollm.SetProvider("openrouter") option. You must provide an API key via gollm.SetAPIKey(apiKey) and specify a model using gollm.SetModel("model-name") (e.g., anthropic/claude-3-5-sonnet).

    Prerequisites:

    llm, err := gollm.NewLLM(
        gollm.SetProvider("openrouter"),
        gollm.SetAPIKey(apiKey),
        gollm.SetModel("anthropic/claude-3-5-sonnet"),
        gollm.SetTemperature(0.7),
        gollm.SetMaxTokens(1000),
    )
    
    prompt := gollm.NewPrompt("What are the main features of OpenRouter?")
    response, err := llm.Generate(ctx, prompt)
  9. Set up environment variables for Azure OpenAI

    main

    To use the Azure OpenAI provider with Gollm, you must provide your credentials and resource details via environment variables. Ensure you have an Azure OpenAI Service account and a deployed model (e.g., GPT-4) before proceeding.

    export AZURE_OPENAI_API_KEY="your-api-key"
    export AZURE_OPENAI_RESOURCE_NAME="your-resource-name"
    export AZURE_OPENAI_DEPLOYMENT_NAME="your-deployment-name"
    export AZURE_OPENAI_API_VERSION="2023-05-15"
  10. Use Azure OpenAI with Gollm

    main

    You can integrate Azure OpenAI by using the azure-openai provider. Because Azure uses a specific endpoint structure, you must construct the endpoint URL manually using your resource name, deployment name, and API version, then pass it to gollm.NewLLM via config.SetExtraHeaders using the azure_endpoint key. Note that for Azure, the model parameter should be set to your deployment name.

    package main
    
    import (
    	"context"
    	"fmt"
    	"os"
    
    	"github.com/teilomillet/gollm"
    	"github.com/teilomillet/gollm/config"
    )
    
    func main() {
    	// Get configuration from environment
    	apiKey := os.Getenv("AZURE_OPENAI_API_KEY")
    	resourceName := os.Getenv("AZURE_OPENAI_RESOURCE_NAME")
    	deploymentName := os.Getenv("AZURE_OPENAI_DEPLOYMENT_NAME")
    	apiVersion := os.Getenv("AZURE_OPENAI_API_VERSION")
    	
    	if apiKey == "" || resourceName == "" || deploymentName == "" {
    		fmt.Println("Error: Missing required environment variables")
    		fmt.Println("Please set: AZURE_OPENAI_API_KEY, AZURE_OPENAI_RESOURCE_NAME, AZURE_OPENAI_DEPLOYMENT_NAME")
    		os.Exit(1)
    	}
    	
    	if apiVersion == "" {
    		apiVersion = "2023-05-15" // Default value
    	}
    	
    	// Create the endpoint URL
    	endpoint := fmt.Sprintf(
    		"https://%s.openai.azure.com/openai/deployments/%s/chat/completions?api-version=%s", 
    		resourceName, deploymentName, apiVersion,
    	)
    	
    	// Create the LLM instance
    	llm, err := gollm.NewLLM(
    		config.SetProvider("azure-openai"),
    		config.SetAPIKey(apiKey),
    		config.SetModel(deploymentName),
    		config.SetExtraHeaders(map[string]string{
    			"azure_endpoint": endpoint,
    		}),
    	)
    	
    	if err != nil {
    		fmt.Printf("Error creating LLM: %v\n", err)
    		os.Exit(1)
    	}
    	
    	// Create a prompt
    	ctx := context.Background()
    	prompt := gollm.NewPrompt("Explain what Azure OpenAI Service is in 3 sentences.")
    	
    	// Generate a response
    	response, err := llm.Generate(ctx, prompt)
    	if err != nil {
    		fmt.Printf("Error generating response: %v\n", err)
    		os.Exit(1)
    	}
    	
    	// Print the response
    	fmt.Println("Response from Azure OpenAI:")
    	fmt.Println(response)
    }
  11. Run OpenRouter integration tests

    main

    To verify the OpenRouter provider, you can run integration tests that make actual API calls.

    Note: These tests consume credits from your OpenRouter account.

    Option 1: Via main.go

    export OPENROUTER_API_KEY="your_api_key_here"
    go run main.go -test
    # OR
    go run main.go -test -key="your_api_key_here"

    Option 2: Via go test

    export OPENROUTER_API_KEY="your_api_key_here"
    go test -v ./providers -run TestOpenRouterIntegration
  12. Use Azure OpenAI

    main

    To use Azure OpenAI, use the azure-openai provider. You must construct the endpoint URL using your resource name, deployment name, and API version, then pass it via config.SetExtraHeaders using the azure_endpoint key. Note that in Azure, the deploymentName is used as the model name.

    import (
        "context"
        "fmt"
        "github.com/teilomillet/gollm"
        "github.com/teilomillet/gollm/config"
    )
    
    // Get Azure details
    resourceName := "your-resource-name"
    deploymentName := "your-deployment-name"
    apiVersion := "2023-05-15"
    
    // Create the endpoint URL
    endpoint := fmt.Sprintf(
        "https://%s.openai.azure.com/openai/deployments/%s/chat/completions?api-version=%s", 
        resourceName, deploymentName, apiVersion
    )
    
    // Use the built-in azure-openai provider
    llm, err := gollm.NewLLM(
        config.SetProvider("azure-openai"),
        config.SetAPIKey("your-azure-api-key"),
        config.SetModel(deploymentName), // Azure uses deployment name as model
        config.SetExtraHeaders(map[string]string{
            "azure_endpoint": endpoint,
        }),
    )
    
    // Use it
    ctx := context.Background()
    prompt := gollm.NewPrompt("What are the key features of Go?")
    response, err := llm.Generate(ctx, prompt)