Skip to content

Latest commit

 

History

History
198 lines (147 loc) · 6.19 KB

README.md

File metadata and controls

198 lines (147 loc) · 6.19 KB

RubyLLM

A delightful Ruby way to work with AI. No configuration madness, no complex callbacks, no handler hell – just beautiful, expressive Ruby code.

OpenAI      Anthropic      Google      DeepSeek

Gem Version Ruby Style Guide Gem Downloads codecov

🤺 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.

Features

  • 💬 Chat with OpenAI, Anthropic, Gemini, and DeepSeek models
  • 👁️ Vision and Audio understanding
  • 📄 PDF Analysis for analyzing documents
  • 🖼️ Image generation with DALL-E and other providers
  • 📊 Embeddings for vector search and semantic analysis
  • 🔧 Tools that let AI use your Ruby code
  • 🚂 Rails integration to persist chats and messages with ActiveRecord
  • 🌊 Streaming responses with proper Ruby patterns

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}&current=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)"

Installation

# In your Gemfile
gem 'ruby_llm'

# Then run
bundle install

# Or install it yourself
gem install ruby_llm

Configure with your API keys:

RubyLLM.configure do |config|
  config.openai_api_key = ENV['OPENAI_API_KEY']
  config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
  config.gemini_api_key = ENV['GEMINI_API_KEY']
  config.deepseek_api_key = ENV['DEEPSEEK_API_KEY']
end

Have great conversations

# Start a chat with the default model (GPT-4o-mini)
chat = RubyLLM.chat

# Or specify what you want
chat = RubyLLM.chat(model: 'claude-3-7-sonnet-20250219')

# Simple questions just work
chat.ask "What's the difference between attr_reader and attr_accessor?"

# Multi-turn conversations are seamless
chat.ask "Could you give me an example?"

# Stream responses in real-time
chat.ask "Tell me a story about a Ruby programmer" do |chunk|
  print chunk.content
end

# Understand content in multiple forms
chat.ask "Compare these diagrams", with: { image: ["diagram1.png", "diagram2.png"] }
chat.ask "Summarize this document", with: { pdf: "contract.pdf" }
chat.ask "What's being said?", with: { audio: "meeting.wav" }

# Need a different model mid-conversation? No problem
chat.with_model('gemini-2.0-flash').ask "What's your favorite algorithm?"

Rails integration that makes sense

# app/models/chat.rb
class Chat < ApplicationRecord
  acts_as_chat

  # Works great with Turbo
  broadcasts_to ->(chat) { "chat_#{chat.id}" }
end

# app/models/message.rb
class Message < ApplicationRecord
  acts_as_message
end

# app/models/tool_call.rb
class ToolCall < ApplicationRecord
  acts_as_tool_call
end

# In your controller
chat = Chat.create!(model_id: "gpt-4o-mini")
chat.ask("What's your favorite Ruby gem?") do |chunk|
  Turbo::StreamsChannel.broadcast_append_to(
    chat,
    target: "response",
    partial: "messages/chunk",
    locals: { chunk: chunk }
  )
end

# That's it - chat history is automatically saved

Creating tools is a breeze

class Search < RubyLLM::Tool
  description "Searches a knowledge base"

  param :query, desc: "The search query"
  param :limit, type: :integer, desc: "Max results", required: false

  def execute(query:, limit: 5)
    # Your search logic here
    Document.search(query).limit(limit).map(&:title)
  end
end

# Let the AI use it
chat.with_tool(Search).ask "Find documents about Ruby 3.3 features"

Learn more

Check out the guides at https://rubyllm.com for deeper dives into conversations with tools, streaming responses, embedding generations, and more.

License

Released under the MIT License.