Skip to content

Commit

Permalink
Merge pull request #3 from StacklokLabs/rem-config
Browse files Browse the repository at this point in the history
Remove config and logging
  • Loading branch information
lukehinds authored Oct 2, 2024
2 parents 252099f + c2edf53 commit b24444a
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 436 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Main
on:
push:
branches:
- main
paths-ignore:
- 'docs/**'
permissions:
contents: read
packages: write

jobs:
test:
name: Unit testing
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Run tests
run: go test -cover ./...
- name: Lint code
run: golangci-lint run
103 changes: 103 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
run:
issues-exit-code: 1
timeout: 5m

linters-settings:
lll:
line-length: 130
gocyclo:
min-complexity: 15
gci:
sections:
- standard
- default
- prefix(github.com/stackloklabs/gollm)
revive:
# see https://github.com/mgechev/revive#available-rules for details.
ignore-generated-header: true
severity: warning
errorCode: 0
warningCode: 0
rules:
- name: blank-imports
severity: warning
- name: context-as-argument
- name: context-keys-type
- name: duplicated-imports
- name: error-naming
# - name: error-strings #BDG: This was enabled for months, but it suddenly started working on 3/2/2022.. come to find out we have TONS of error messages starting with capital... disabling for now(ever?)
- name: error-return
- name: exported
severity: error
- name: if-return
# - name: get-return // BDG: We have a lot of API endpoint handlers named like getFoos but write to response vs return... maybe later can figure that out
- name: identical-branches
- name: indent-error-flow
- name: import-shadowing
- name: package-comments
# NOTE: range-val-address and range-val-in-closure are irrelevant in Go 1.22 and later
- name: redefines-builtin-id
- name: struct-tag
- name: unconditional-recursion
- name: unnecessary-stmt
- name: unreachable-code
- name: unused-parameter
- name: unused-receiver
- name: unhandled-error
disabled: true
gosec:
excludes:
- G114 # for the moment we need to use listenandserve that has no support for timeouts
- G404 # use unsafe random generator until logic change is discussed
- G307 # Deferring unsafe method "Close" on type "io.ReadCloser"
- G601 # Irrelevant for Go 1.22 and later, see: https://github.com/securego/gosec/issues/1099

depguard:
rules:
prevent_unmaintained_packages:
list-mode: lax # allow unless explicitely denied
files:
- $all
- "!$test"
deny:
- pkg: "log"
desc: "We should use zerolog instead"
- pkg: io/ioutil
desc: "this is deprecated"

linters:
disable-all: true
enable:
- lll
- exhaustive
- depguard
- goconst
- gocyclo
- gofmt
- gosec
- gci
- unparam
- gosimple
- govet
- ineffassign
- paralleltest
- promlinter
- revive
- staticcheck
- unused
- thelper
- tparallel

issues:
exclude-use-default: false
exclude-rules:
- path: '(.+)_test\.go'
linters:
- lll

output:
formats:
- format: colored-line-number
print-issued-lines: true
print-linter-name: true
sort-results: true
44 changes: 6 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Gollm: Go Interface for LLM development 📜
# Gollm: Go Interface for LLM development with RAG 📜

[![Go Report Card](https://goreportcard.com/badge/github.com/stackloklabs/gollm)](https://goreportcard.com/report/github.com/stackloklabs/gollm)
[![License](https://img.shields.io/github/license/stackloklabs/gollm)](LICENSE)
Expand All @@ -19,13 +19,12 @@ Language Model backends including [Ollama](https://ollama.com) and [OpenAI](http

### 1. Installation

First, make sure you have Go installed. Then, add Gollm to your project:
First, make sure you have Go installed. Then, add gollm to your project:

```bash
go get github.com/stackloklabs/gollm
```


## 2. Setting Up Ollama

You'll need to have an Ollama server running and accessible.
Expand All @@ -35,59 +34,28 @@ Install Ollama Server: Download the server from the [official Ollama website](ht
Pull and run a model

```bash
ollama run qwen2.5
ollama run llama3
```

Ollama should run on port `11434` and `localhost`, if you change this, don't
forget to update your config.

## 3. OpenAI

You'll need an OpenAI API key to use the OpenAI backend, which can be be
set within the config as below.
You'll need an OpenAI API key to use the OpenAI backend.

## 4. Configuration

Gollm uses Viper to manage configuration settings.

Backends are configured for either generation or embeddings, and can be set to either Ollama or OpenAI.

For each backend Models is set. Note that for Ollama you will need to
have this as running model, e.g. `ollama run qwen2.5` or `ollama run mxbai-embed-large`.

Finally, in the case of RAG embeddings, a database URL is required.

Currently Postgres is supported, and the database should be created before running the application, with the schena provided in `db/init.sql`
Currently Postgres is supported, and the database should be created before
running the application, with the schena provided in `db/init.sql`

Should you wish, the docker-compose will automate the setup of the database.

```bash
cp examples/config-example.yaml ./config.yaml
```

```yaml
backend:
embeddings: "ollama" # or "ollama"
generation: "ollama" # or "openai"
ollama:
host: "http://localhost:11434"
gen_model: "qwen2.5"
emb_model: "mxbai-embed-large"
openai:
api_key: "your-key"
gen_model: "gpt-3.5-turbo"
emb_model: "text-embedding-ada-002"
database:
url: "postgres://user:password@localhost:5432/dbname?sslmode=disable"
log_level: "info"
```
# 🛠️ Usage

Best bet is to see `/examples/main.go` for reference, this explains how to use
the library with full examples for generation, embeddings and implementing RAG.


# 📝 Contributing

We welcome contributions! Please submit a pull request or raise an issue if
Expand Down
14 changes: 0 additions & 14 deletions examples/config-example.yaml

This file was deleted.

111 changes: 30 additions & 81 deletions examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,45 @@ package main

import (
"context"
"fmt"
"log"

"time"

"github.com/google/uuid"

"github.com/stackloklabs/gollm/pkg/backend"
"github.com/stackloklabs/gollm/pkg/config"
"github.com/stackloklabs/gollm/pkg/db"
"github.com/stackloklabs/gollm/pkg/logger"
)

var (
ollamaHost = "http://localhost:11434"
ollamaEmbModel = "mxbai-embed-large"
ollamaGenModel = "llama3"
databaseURL = "postgres://user:password@localhost:5432/dbname?sslmode=disable"
)

func main() {
// Initialize Config
cfg := config.InitializeViperConfig("config", "yaml", ".")

logger.InitLogger()

// Select backends based on config
var embeddingBackend backend.Backend
var generationBackend backend.Backend

// Choose the backend for embeddings based on the config
switch cfg.Get("backend.embeddings") {
case "ollama":
embeddingBackend = backend.NewOllamaBackend(cfg.Get("ollama.host"), cfg.Get("ollama.emb_model"))
case "openai":
embeddingBackend = backend.NewOpenAIBackend(cfg.Get("openai.api_key"), cfg.Get("openai.emb_model"))
default:
logger.Fatal("Invalid embeddings backend specified")
}

logger.Info(fmt.Sprintf("Embeddings backend: %s", cfg.Get("backend.embeddings")))
embeddingBackend = backend.NewOllamaBackend(ollamaHost, ollamaEmbModel)

// Choose the backend for generation based on the config
switch cfg.Get("backend.generation") {
case "ollama":
generationBackend = backend.NewOllamaBackend(cfg.Get("ollama.host"), cfg.Get("ollama.gen_model"))
case "openai":
generationBackend = backend.NewOpenAIBackend(cfg.Get("openai.api_key"), cfg.Get("openai.gen_model"))
default:
logger.Fatal("Invalid generation backend specified")
}
log.Printf("Embedding backend LLM: %s", ollamaEmbModel)

logger.Info(fmt.Sprintf("Generation backend: %s", cfg.Get("backend.generation")))
// Choose the backend for generation based on the config
generationBackend = backend.NewOllamaBackend(ollamaHost, ollamaGenModel)

// Initialize database connection for pgvector
dbConnString := cfg.Get("database.url")
log.Printf("Generation backend: %s", ollamaGenModel)

// Initialize the vector database
vectorDB, err := db.NewPGVector(dbConnString)
vectorDB, err := db.NewPGVector(databaseURL)
if err != nil {
logger.Fatalf("Failed to initialize vector database: %v", err)
log.Fatalf("Error initializing vector database: %v", err)
}
logger.Info("Vector database initialized")
log.Println("Vector database initialized")

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
Expand All @@ -69,79 +53,44 @@ func main() {
// Embed the query using OpenAI
embedding, err := embeddingBackend.Embed(ctx, ragContent)
if err != nil {
logger.Fatalf("Error generating embedding: %v", err)
log.Fatalf("Error generating embedding: %v", err)
}

// Check 1536 is the expected Dimensions value (1536 is the OpenAI default)
// expectedDimensions := 1536
// if len(embedding) != expectedDimensions {
// logger.Fatalf("Error: embedding dimensions mismatch. Expected %d, got %d", expectedDimensions, len(embedding))
// }
log.Println("Embedding generated")

// Insert the document into the vector store
err = insertDocument(vectorDB, ctx, ragContent, embedding)
err = db.InsertDocument(ctx, vectorDB, ragContent, embedding)
if err != nil {
logger.Fatalf("Failed to insert document into vectorDB: %v", err)
log.Fatalf("Error inserting document: %v", err)
}
log.Println("Vector Document generated")

// Embed the query using the specified embedding backend
queryEmbedding, err := embeddingBackend.Embed(ctx, query)
if err != nil {
logger.Fatalf("Error generating query embedding: %v", err)
log.Fatalf("Error generating query embedding: %v", err)
}
log.Println("Vector embeddings generated")

// Retrieve relevant documents for the query embedding
retrievedDocs, err := vectorDB.QueryRelevantDocuments(ctx, queryEmbedding, cfg.Get("backend.embeddings"))
retrievedDocs, err := vectorDB.QueryRelevantDocuments(ctx, queryEmbedding, "ollama")
if err != nil {
logger.Fatalf("Error retrieving documents: %v", err)
log.Fatalf("Error retrieving relevant documents: %v", err)
}

// Log the retrieved documents to see if they include the inserted content
for _, doc := range retrievedDocs {
logger.Infof("RAG Retrieved Document ID: %s, Content: %v", doc.ID, doc.Metadata["content"])
log.Printf("Retrieved Document: %v", doc)
}

// Augment the query with retrieved context
augmentedQuery := combineQueryWithContext(query, retrievedDocs)
logger.Infof("Augmented query Constructed using Prompt: %s", query)

// logger.Infof("Augmented Query: %s", augmentedQuery)
augmentedQuery := db.CombineQueryWithContext(query, retrievedDocs)
log.Printf("LLM Prompt: %s", query)

// Generate response with the specified generation backend
response, err := generationBackend.Generate(ctx, augmentedQuery)
if err != nil {
logger.Fatalf("Failed to generate response: %v", err)
log.Fatalf("Failed to generate response: %v", err)
}

logger.Infof("Output from LLM model %s:", response)
}

// combineQueryWithContext combines the query and retrieved documents' content to provide context for generation.
func combineQueryWithContext(query string, docs []db.Document) string {
var context string
for _, doc := range docs {
// Cast doc.Metadata["content"] to a string
if content, ok := doc.Metadata["content"].(string); ok {
context += content + "\n"
}
}
return fmt.Sprintf("Context: %s\nQuery: %s", context, query)
}

// Example code to insert a document into the vector store
func insertDocument(vectorDB *db.PGVector, ctx context.Context, content string, embedding []float32) error {
// Generate a unique document ID (for simplicity, using a static value for testing)
docID := fmt.Sprintf("doc-%s", uuid.New().String())

// Create metadata
metadata := map[string]interface{}{
"content": content,
}

// Save the document and its embedding into the vector store
err := vectorDB.SaveEmbedding(ctx, docID, embedding, metadata)
if err != nil {
return fmt.Errorf("error saving embedding: %v", err)
}
return nil
log.Printf("Retrieval-Augmented Generation influenced output from LLM model: %s", response)
}
Loading

0 comments on commit b24444a

Please sign in to comment.