Tontuno: A sophisticated Retrieval-Augmented Generation (RAG) system built in Kotlin that combines document storage, semantic search, and intelligent response generation.
Warning
This is a example project to learn and practice Don't use in real applications or real environments
- Multiple Embedding Options: Support for Simple, Sentence Transformers API, ONNX local models, and OpenAI embeddings
- Vector Storage: In-memory vector database with cosine similarity search
- Async Processing: Built with Kotlin coroutines for non-blocking operations
- Fallback System: Automatic fallback to simple embedder if API services fail
- Type Safety: Full Kotlin type safety with comprehensive error handling
- Testing: Complete test suite included
-
Clone and build:
./gradlew build
-
Run the demo:
./gradlew run
Set these environment variables to configure different embedders:
# Embedder type (SIMPLE, SENTENCE_TRANSFORMERS_API, ONNX_SENTENCE_TRANSFORMERS, OPENAI)
export RAG_EMBEDDER_TYPE=SENTENCE_TRANSFORMERS_API
# API keys
export HUGGINGFACE_API_KEY=your_hf_token_here
export OPENAI_API_KEY=your_openai_key_here
# Model configuration
export RAG_EMBEDDER_DIMENSIONS=384
export RAG_EMBEDDER_MODEL=text-embedding-3-small
# ONNX local model paths
export RAG_MODEL_PATH=/path/to/model.onnx
export RAG_TOKENIZER_PATH=/path/to/tokenizer.json// Using factory
val embedder = EmbedderFactory.createEmbedder(
EmbedderFactory.EmbedderType.SENTENCE_TRANSFORMERS_API,
mapOf(
"apiKey" to "your_api_key",
"dimensions" to "384"
)
)
// Or from environment
val embedder = EmbedderFactory.createFromEnvironment()val embedder = EmbedderFactory.createFromEnvironment()
val vectorStore = InMemoryVectorStore()
val ragAgent = RagAgent(embedder, vectorStore)
// Add documents
ragAgent.addDocument(Document("1", "Kotlin is a modern programming language"))
// Query
val response = ragAgent.query("What is Kotlin?")
println(response)
// Cleanup
ragAgent.close()val documents = listOf(
Document("1", "Kotlin documentation content"),
Document("2", "Java interoperability guide"),
Document("3", "Coroutines tutorial")
)
ragAgent.addDocuments(documents)
val response = ragAgent.query("How does Kotlin work with Java?")┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ RagAgent │ │ Embedder │ │ VectorStore │
│ │────│ │ │ │
│ - addDocument() │ │ - embed() │ │ - store() │
│ - query() │ │ - getDimensions │ │ - search() │
│ - getStats() │ │ - close() │ │ - clear() │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ ┌─────────────────┐ │
└──────────────│ ResponseGen │──────────────┘
│ │
│ - generateResp │
└─────────────────┘
- Kotlin Coroutines: Async processing
- Ktor Client: HTTP API calls
- ONNX Runtime: Local model inference
- HuggingFace Tokenizers: Text tokenization
- Kotlin Serialization: JSON handling
Run tests:
./gradlew test- Simple Embedder: Fastest, good for prototyping
- API Embedders: High quality, requires network
- ONNX Local: Good balance, requires model files
- Vector Search: O(n) linear search, consider specialized DBs for large datasets
- Fork the repository
- Create feature branch
- Add tests for new features
- Ensure all tests pass
- Submit pull request