I released RubyLLM 1.0 today. It's a library that makes working with AI in Ruby feel natural, elegant, and enjoyable.
Why This Matters
AI should be accessible to Ruby developers without ceremony or complexity. When building Chat with Work, I wanted to simply write:
chat = RubyLLM.chat chat.ask "What's the best way to learn Ruby?"
And have it work - regardless of which model I'm using, whether I'm streaming responses, or which provider I've chosen. The API should get out of the way and let me focus on building my product.
The RubyLLM Philosophy
Beautiful interfaces matter. Ruby has always been about developer happiness. Your AI code should reflect that same elegance:
# Global methods for core operations - simple and expressive chat = RubyLLM.chat embedding = RubyLLM.embed("Ruby is elegant") image = RubyLLM.paint("a sunset over mountains") # Method chaining that reads like English chat.with_model('gpt-4o-mini') .with_temperature(0.7) .ask("What's your favorite gem?")
Convention over configuration. You shouldn't need to think about providers or remember multiple APIs:
# Don't care which model? We'll use a sensible default chat = RubyLLM.chat # Want a specific model? Just say so chat = RubyLLM.chat(model: 'claude-3-5-sonnet') # Switch to GPT mid-conversation? Just as easy chat.with_model('gpt-4o-mini')
Practical tools for real work. Function calling should be Ruby-like, not JSON Schema gymnastics:
class Search < RubyLLM::Tool description "Searches our knowledge base" param :query, desc: "Search query" param :limit, type: :integer, desc: "Max results", required: false def execute(query:, limit: 5) Document.search(query).limit(limit).map(&:title) end end # Clean, practical, Ruby-like chat.with_tool(Search).ask "Find our product documentation"
Streaming done right. No need to parse different formats for different providers:
chat.ask "Write a story about Ruby" do |chunk| # No provider-specific parsing - we handle that for you print chunk.content end
Token tracking by default. Cost management should be built-in:
response = chat.ask "Explain Ruby modules" puts "This cost #{response.input_tokens + response.output_tokens} tokens"
Meaningful error handling. Production apps need proper error types:
begin chat.ask "Question" rescue RubyLLM::RateLimitError puts "Rate limited - backing off" rescue RubyLLM::UnauthorizedError puts "API key issue - check configuration" end
Rails as a first-class citizen. Because most of us are building Rails apps:
class Chat < ApplicationRecord acts_as_chat end chat = Chat.create!(model_id: 'gemini-2.0-flash') chat.ask "Hello" # Everything persisted automatically
Built for Real Applications
RubyLLM supports the features you actually need in production:
# Vision chat.ask "What's in this image?", with: { image: "photo.jpg" } # PDFs chat.ask "Summarize this document", with: { pdf: "contract.pdf" } # Audio chat.ask "Transcribe this recording", with: { audio: "meeting.wav" } # Multiple files chat.ask "Compare these diagrams", with: { image: ["chart1.png", "chart2.png"] }
Minimal Dependencies
Just Faraday, Zeitwerk, and a tiny event parser. No dependency hell.
Used in Production Today
RubyLLM powers Chat with Work in production. It's battle-tested with real-world AI integrations and built for serious applications.
Give it a try today: gem install ruby_llm
More details at rubyllm.com
Top comments (5)
Love it!
This is a great Ruby gem
thank you!
the model is cloud based or i have to download locallly?
Hi, this is not a model, it's library to talk with models.