A delightful Ruby way to work with AI through a unified interface to Anthropic, AWS Bedrock Anthropic, DeepSeek, Ollama, OpenAI, Gemini, OpenRouter, and any OpenAI-compatible API.
ðĪš Battle tested at ðŽ Chat with Work
The problem with AI libraries
Every AI provider comes with its own client library, its own response format, its own conventions for streaming, and its own way of handling errors. Want to use multiple providers? Prepare to juggle incompatible APIs and bloated dependencies.
RubyLLM fixes all that. One beautiful API for everything. One consistent format. Minimal dependencies â just Faraday and Zeitwerk. Because working with AI should be a joy, not a chore.
What makes it great
# Just ask questions
chat = RubyLLM.chat
chat.ask "What's the best way to learn Ruby?"
# Analyze images
chat.ask "What's in this image?", with: { image: "ruby_conf.jpg" }
# Analyze audio recordings
chat.ask "Describe this meeting", with: { audio: "meeting.wav" }
# Analyze documents
chat.ask "Summarize this document", with: { pdf: "contract.pdf" }
# Stream responses in real-time
chat.ask "Tell me a story about a Ruby programmer" do |chunk|
print chunk.content
end
# Generate images
RubyLLM.paint "a sunset over mountains in watercolor style"
# Create vector embeddings
RubyLLM.embed "Ruby is elegant and expressive"
# Let AI use your code
class Weather < RubyLLM::Tool
description "Gets current weather for a location"
param :latitude, desc: "Latitude (e.g., 52.5200)"
param :longitude, desc: "Longitude (e.g., 13.4050)"
def execute(latitude:, longitude:)
url = "https://api.open-meteo.com/v1/forecast?latitude=#{latitude}&longitude=#{longitude}¤t=temperature_2m,wind_speed_10m"
response = Faraday.get(url)
data = JSON.parse(response.body)
rescue => e
{ error: e.message }
end
end
chat.with_tool(Weather).ask "What's the weather in Berlin? (52.5200, 13.4050)"
Core Capabilities
- ðŽ Unified Chat: Converse with models from OpenAI, Anthropic, Gemini, Bedrock, OpenRouter, DeepSeek, Ollama, or any OpenAI-compatible API using
RubyLLM.chat
. - ðïļ Vision: Analyze images within chats.
- ð Audio: Transcribe and understand audio content.
- ð PDF Analysis: Extract information and summarize PDF documents.
- ðžïļ Image Generation: Create images with
RubyLLM.paint
. - ð Embeddings: Generate text embeddings for vector search with
RubyLLM.embed
. - ð§ Tools (Function Calling): Let AI models call your Ruby code using
RubyLLM::Tool
. - ð Rails Integration: Easily persist chats, messages, and tool calls using
acts_as_chat
andacts_as_message
. - ð Streaming: Process responses in real-time with idiomatic Ruby blocks.
Installation
Add to your Gemfile:
gem 'ruby_llm'
Then bundle install
.
Configure your API keys (using environment variables is recommended):
# config/initializers/ruby_llm.rb or similar
RubyLLM.configure do |config|
config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
# Add keys ONLY for providers you intend to use
# config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY', nil)
# ... see Configuration guide for all options ...
end
See the Installation Guide for full details.
Rails Integration
Add persistence to your chat models effortlessly:
# app/models/chat.rb
class Chat < ApplicationRecord
acts_as_chat # Automatically saves messages & tool calls
# ... your other model logic ...
end
# app/models/message.rb
class Message < ApplicationRecord
acts_as_message
# ...
end
# app/models/tool_call.rb (if using tools)
class ToolCall < ApplicationRecord
acts_as_tool_call
# ...
end
# Now interacting with a Chat record persists the conversation:
chat_record = Chat.create!(model_id: "gpt-4.1-nano")
chat_record.ask("Explain Active Record callbacks.") # User & Assistant messages saved
Check the Rails Integration Guide for more.
Learn More
Dive deeper with the official documentation:
- Installation
- Configuration
- Guides:
Contributing
We welcome contributions! Please see CONTRIBUTING.md for details on setup, testing, and contribution guidelines.
License
Released under the MIT License.