AI Providers Integration Guide
This guide explains how to integrate the Prescient gem into an existing Rails AI application.
For the canonical public API and runnable scripts, see the README and examples guide.
Integration Steps
1. Update Your Gemfile
# Add to your Gemfile
gem 'prescient', path: './prescient_gem' # Local development
# OR when published:
# gem 'prescient', '~> 0.5.0'
2. Replace Existing AI Service
Before (Original OllamaService):
# app/services/ollama_service.rb
class OllamaService
def (text)
# Direct Ollama API calls
end
def generate_response(prompt, context_items)
# Direct Ollama API calls
end
end
After (Using Prescient):
# app/services/ai_service.rb
class AIService
def self.client(provider = nil)
@clients ||= {}
provider_name = provider || Rails.application.config.default_ai_provider
@clients[provider_name] ||= Prescient.client(provider_name)
end
def self.(text, provider: nil)
client(provider).(text)
rescue Prescient::Error => e
Rails.logger.error "AI embedding generation failed: #{e.}"
raise
end
def self.generate_response(prompt, context_items = [], provider: nil, **)
client(provider).generate_response(prompt, context_items, **)
rescue Prescient::Error => e
Rails.logger.error "AI response generation failed: #{e.}"
raise
end
def self.health_check(provider: nil)
client(provider).health_check
rescue Prescient::Error => e
{ status: 'unhealthy', error: e. }
end
end
3. Configuration
Create initializer:
# config/initializers/prescient.rb
Prescient.configure do |config|
config.default_provider = Rails.env.production? ? :openai : :ollama
config.timeout = 60
config.retry_attempts = 3
config.retry_delay = 1.0
# Ollama (Local/Development)
config.add_provider(:ollama, Prescient::Provider::Ollama,
url: ENV.fetch('OLLAMA_URL', 'http://localhost:11434'),
embedding_model: ENV.fetch('OLLAMA_EMBEDDING_MODEL', 'nomic-embed-text'),
chat_model: ENV.fetch('OLLAMA_CHAT_MODEL', 'llama3.2:3b'),
timeout: 120
)
# OpenAI (Production)
if ENV['OPENAI_API_KEY'].present?
config.add_provider(:openai, Prescient::Provider::OpenAI,
api_key: ENV['OPENAI_API_KEY'],
embedding_model: ENV.fetch('OPENAI_EMBEDDING_MODEL', 'text-embedding-3-small'),
chat_model: ENV.fetch('OPENAI_CHAT_MODEL', 'gpt-4.1-mini')
)
end
# Anthropic (Alternative)
if ENV['ANTHROPIC_API_KEY'].present?
config.add_provider(:anthropic, Prescient::Provider::Anthropic,
api_key: ENV['ANTHROPIC_API_KEY'],
model: ENV.fetch('ANTHROPIC_MODEL', 'claude-sonnet-4-20250514')
)
end
# HuggingFace (Research/Open Source)
if ENV['HUGGINGFACE_API_KEY'].present?
config.add_provider(:huggingface, Prescient::Provider::HuggingFace,
api_key: ENV['HUGGINGFACE_API_KEY'],
embedding_model: ENV.fetch('HUGGINGFACE_EMBEDDING_MODEL', 'sentence-transformers/all-MiniLM-L6-v2'),
chat_model: ENV.fetch('HUGGINGFACE_CHAT_MODEL', 'google/gemma-2-2b-it')
)
end
end
# Set default provider for Rails
Rails.application.config.default_ai_provider = :ollama
For YAML-based deployments, use the versioned configuration format and keep credentials in environment variables:
Prescient.load_configuration('prescient.yml')
Configuration precedence is CLI overrides, environment defaults and
references, YAML values, then built-in defaults. The generated
prescient config example file includes the current JSON Schema URL.
4. Update Environment Variables
# .env or environment configuration
# Ollama (Local)
OLLAMA_URL=http://localhost:11434
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
OLLAMA_CHAT_MODEL=llama3.2:3b
# OpenAI (Production)
OPENAI_API_KEY=your_openai_api_key
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
OPENAI_CHAT_MODEL=gpt-4.1-mini
# Anthropic (Alternative)
ANTHROPIC_API_KEY=your_anthropic_api_key
ANTHROPIC_MODEL=claude-sonnet-4-20250514
# HuggingFace (Research)
HUGGINGFACE_API_KEY=your_huggingface_api_key
HUGGINGFACE_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
HUGGINGFACE_CHAT_MODEL=google/gemma-2-2b-it
5. Update Controllers
Before:
class Api::V1::AiQueriesController < ApplicationController
def create
= OllamaService.new.(params[:query])
# ... rest of the logic
end
end
After:
class Api::V1::AiQueriesController < ApplicationController
def create
# Use default provider or specify one
= AIService.(params[:query])
# Or use specific provider
# embedding = AIService.generate_embedding(params[:query], provider: :openai)
# ... rest of the logic remains the same
end
private
def generate_ai_response(query, context_items)
# Automatically uses configured provider with fallback
response = AIService.generate_response(
query,
context_items,
max_tokens: 2000,
temperature: 0.7
)
response[:response]
rescue Prescient::Error => e
Rails.logger.error "AI response failed: #{e.}"
"I apologize, but I'm currently unable to generate a response. Please try again later."
end
end
6. Health Check Integration
# app/controllers/api/v1/system/health_controller.rb
class Api::V1::System::HealthController < ApplicationController
def show
health_status = {
database: database_health,
prescient: prescient_health,
overall: 'healthy'
}
# Set overall status based on critical components
if health_status[:prescient][:primary][:status] != 'healthy'
health_status[:overall] = 'degraded'
end
render json: health_status
end
private
def prescient_health
providers = {}
# Check primary provider
primary_provider = Rails.application.config.default_ai_provider
providers[:primary] = {
name: primary_provider,
**AIService.health_check(provider: primary_provider)
}
# Check backup providers
backup_providers = [:openai, :anthropic, :huggingface] - [primary_provider]
providers[:backups] = backup_providers.map do |provider|
{
name: provider,
**AIService.health_check(provider: provider)
}
end
providers
end
def database_health
ActiveRecord::Base.connection.execute('SELECT 1')
{ status: 'healthy' }
rescue StandardError => e
{ status: 'unhealthy', error: e. }
end
end
7. Migration Strategy
-
Phase 1: Side-by-side deployment
- Keep existing OllamaService
- Add Prescient alongside
- Test thoroughly in development
-
Phase 2: Gradual migration
- Update one controller at a time
- Use feature flags to switch between old/new systems
- Monitor performance and error rates
-
Phase 3: Complete migration
- Remove old OllamaService
- Update all controllers to use AIService
- Clean up unused code
8. Testing Updates
# test/services/ai_service_test.rb
class AIServiceTest < ActiveSupport::TestCase
setup do
Prescient.configure do |config|
config.add_provider(:test, Prescient::Provider::Ollama,
url: 'http://localhost:11434',
embedding_model: 'test-embed',
chat_model: 'test-chat'
)
config.default_provider = :test
end
end
test 'generate_embedding returns an embedding vector' do
Prescient.stub(:generate_embedding, [0.1, 0.2, 0.3]) do
result = Prescient.('test text', provider: :test, enable_fallback: false)
assert_equal [0.1, 0.2, 0.3], result
end
end
end
9. Monitoring and Logging
# config/initializers/prescient_monitoring.rb
class PrescientMonitoring
def self.setup!
ActiveSupport::Notifications.subscribe('prescient.request') do |name, start, finish, id, payload|
duration = finish - start
Rails.logger.info "AI Provider Request: #{payload[:provider]} - #{payload[:operation]} - #{duration.round(3)}s"
# Send metrics to your monitoring system
# StatsD.increment('prescient.requests', tags: [
# "provider:#{payload[:provider]}",
# "operation:#{payload[:operation]}",
# "status:#{payload[:status]}"
# ])
end
end
end
PrescientMonitoring.setup! if Rails.env.production?
10. Performance Optimization
# app/services/ai_service.rb (enhanced)
class AIService
# Connection pooling for providers
def self.client(provider = nil)
@clients ||= {}
provider_name = provider || Rails.application.config.default_ai_provider
@clients[provider_name] ||= begin
# Use connection pooling for high-traffic applications
Prescient.client(provider_name)
end
end
# Caching for embeddings (optional)
def self.(text, provider: nil)
cache_key = "ai_embedding:#{ Digest::SHA256.hexdigest(text)}:#{ provider}"
Rails.cache.fetch(cache_key, expires_in: 1.hour) do
client(provider).(text)
end
rescue Prescient::Error => e
Rails.logger.error "AI embedding generation failed: #{e.}"
raise
end
end
Benefits of Migration
- Provider Flexibility: Easy switching between AI providers
- Fallback Support: Automatic fallback to backup providers
- Better Error Handling: Comprehensive error classification
- Monitoring: Built-in health checks and metrics
- Testing: Easier mocking and testing
- Scalability: Better support for different deployment scenarios
- Cost Optimization: Use local models for development, cloud for production
Rollback Plan
If issues arise, quickly rollback by:
- Revert initializer changes
- Switch controllers back to OllamaService
- Deploy previous version
- Debug issues separately
The gem structure allows for easy rollback since it's designed as a drop-in replacement.