Production-ready Rails engine for building, managing, and monitoring LLM-powered AI agents
Build intelligent AI agents in Ruby with a clean DSL, automatic execution tracking, cost analytics, budget controls, and a beautiful real-time dashboard. Supports OpenAI GPT-4, Anthropic Claude, Google Gemini, and more through RubyLLM.
- Rails-Native - Seamlessly integrates with your Rails app: models, jobs, caching, and Hotwire
- Production-Ready - Built-in retries, model fallbacks, circuit breakers, and budget limits
- Full Observability - Track every execution with costs, tokens, duration, and errors
- Zero Lock-in - Works with any LLM provider supported by RubyLLM
# Template agent — structured input via .call
class SearchIntentAgent < ApplicationAgent
model "gpt-4o"
temperature 0.0
system "You are a search intent analyzer. Extract structured data from queries."
user "Extract search intent from: {query}"
assistant '{"refined_query":' # Force JSON output
returns do
string :refined_query, description: "Cleaned search query"
array :filters, of: :string, description: "Extracted filters"
end
end
result = SearchIntentAgent.call(query: "red summer dress under $50")
result.content # => { refined_query: "red dress", filters: ["color:red", "price:<50"] }
result.total_cost # => 0.00025
result.total_tokens # => 150
result.duration_ms # => 850# Conversational agent — freeform input via .ask
class RubyExpert < ApplicationAgent
model "claude-sonnet-4-5-20250929"
system "You are a senior Ruby developer with 20 years of experience."
end
result = RubyExpert.ask("What's the difference between proc and lambda?")
puts result.content
# Stream the response
RubyExpert.ask("Explain metaprogramming") { |chunk| print chunk.content }# Resilient agents with automatic retries and fallbacks
class ReliableAgent < ApplicationAgent
model "gpt-4o"
user "{query}"
on_failure do
retries times: 3, backoff: :exponential
fallback to: ["gpt-4o-mini", "claude-3-5-sonnet"]
circuit_breaker after: 10, within: 60, cooldown: 5.minutes
timeout 30
end
end# Vector embeddings for semantic search and RAG
# app/agents/embedders/document_embedder.rb
module Embedders
class DocumentEmbedder < ApplicationEmbedder
model "text-embedding-3-small"
dimensions 512
cache_for 1.week
end
end
result = Embedders::DocumentEmbedder.call(text: "Hello world")
result.vector # => [0.123, -0.456, ...]
result.dimensions # => 512
# Batch embedding
result = Embedders::DocumentEmbedder.call(texts: ["Hello", "World", "Ruby"])
result.vectors # => [[...], [...], [...]]# Message classification and routing
class SupportRouter < ApplicationAgent
include RubyLLM::Agents::Routing
model "gpt-4o-mini"
temperature 0.0
cache_for 1.hour
route :billing, "Billing, charges, refunds, payments"
route :technical, "Bugs, errors, crashes, technical issues"
route :sales, "Pricing, plans, upgrades, discounts"
default_route :general
end
result = SupportRouter.call(message: "I was charged twice")
result.route # => :billing
result.total_cost # => 0.00008# Text-to-speech and speech-to-text
# app/agents/audio/podcast_speaker.rb
module Audio
class PodcastSpeaker < ApplicationSpeaker
model "tts-1"
voice "onyx"
speed 0.95
output_format :aac
streaming true
end
end
result = Audio::PodcastSpeaker.call(text: "Welcome to the show!")
result.audio # => Binary audio data
result.duration # => 1.5
result.save_to("episode.aac")
# Speech-to-text transcription
result = Audio::MeetingTranscriber.call(audio: "standup.mp3")
result.text # => "Good morning everyone..."
result.word_count # => 5432# Image generation, analysis, and pipelines
# app/agents/images/logo_generator.rb
module Images
class LogoGenerator < ApplicationImageGenerator
model "gpt-image-1"
size "1024x1024"
quality "hd"
style "vivid"
template "Professional logo design: {prompt}. Minimalist, scalable."
end
end
result = Images::LogoGenerator.call(prompt: "tech startup logo")
result.url # => "https://..."
result.save("logo.png")# Evaluate agent quality with built-in scoring
class SupportRouter::Eval < RubyLLM::Agents::Eval::EvalSuite
agent SupportRouter
test_case "billing", input: { message: "charged twice" }, expected: "billing"
test_case "technical", input: { message: "500 error" }, expected: "technical"
test_case "greeting", input: { message: "hello" }, expected: "general"
end
run = SupportRouter::Eval.run!
puts run.summary
# SupportRouter eval: 3/3 passed (score: 1.0)| Feature | Description | Docs |
|---|---|---|
| Agent DSL | Declarative configuration with model, temperature, parameters, description | Agent DSL |
| Execution Tracking | Automatic logging with token usage, cost analytics, and fallback tracking | Tracking |
| Cost Analytics | Track spending by agent, model, tenant, and time period | Analytics |
| Reliability | Automatic retries, model fallbacks, circuit breakers with block DSL | Reliability |
| Budget Controls | Daily/monthly limits with hard and soft enforcement | Budgets |
| Multi-Source Pricing | 7-source pricing cascade with caching for all model types | Pricing |
| Multi-Tenancy | Per-tenant API keys, budgets, circuit breakers, and execution isolation | Multi-Tenancy |
| Async/Fiber | Concurrent execution with Ruby fibers for high-throughput workloads | Async |
| Dashboard | Real-time Turbo-powered monitoring UI | Dashboard |
| Streaming | Real-time response streaming with TTFT tracking | Streaming |
| Conversation History | Multi-turn conversations with message history | Conversation History |
| Attachments | Images, PDFs, and multimodal support | Attachments |
| Embeddings | Vector embeddings with batching, caching, and preprocessing | Embeddings |
| Image Operations | Generation, analysis, editing, pipelines with cost tracking | Images |
| Routing | Message classification and routing with auto-generated prompts, inline classify | Routing |
| Audio | Text-to-speech (OpenAI, ElevenLabs), speech-to-text, dynamic pricing, 28+ output formats, dashboard audio playback | Audio |
| Agent Composition | Use agents as tools in other agents with automatic hierarchy tracking | Tools |
| Queryable Agents | Query execution history from agent classes with stats, replay, and cost breakdown | Querying |
| Evaluation | Test agent quality with exact match, contains, LLM judge, and custom scorers | Evaluation |
| Alerts | Slack, webhook, and custom notifications | Alerts |
| AS::Notifications | 11 instrumentation events across execution, cache, budget, and reliability | Events |
| Custom Middleware | Inject custom middleware globally or per-agent with positioning control | Middleware |
# Gemfile
gem "ruby_llm-agents"bundle install
rails generate ruby_llm_agents:install
rails db:migrateConfigure all provider API keys in one place (v2.1+):
# config/initializers/ruby_llm_agents.rb
RubyLLM::Agents.configure do |config|
config.openai_api_key = ENV["OPENAI_API_KEY"]
config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
config.gemini_api_key = ENV["GOOGLE_API_KEY"]
endOr use environment variables directly (auto-detected by RubyLLM):
# .env
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_API_KEY=...rails generate ruby_llm_agents:agent SearchIntent query:requiredThis creates app/agents/search_intent_agent.rb with the agent class ready to customize.
# config/routes.rb
mount RubyLLM::Agents::Engine => "/agents"![]() |
![]() |
![]() |
![]() |
AI Agents: For comprehensive documentation optimized for AI consumption, see LLMS.txt
Note: Wiki content lives in the
wiki/folder. To sync changes to the GitHub Wiki, run./scripts/sync-wiki.sh.
| Guide | Description |
|---|---|
| Getting Started | Installation, configuration, first agent |
| Agent DSL | All DSL options: model, temperature, params, caching, description |
| Reliability | Retries, fallbacks, circuit breakers, timeouts, reliability block |
| Budget Controls | Spending limits, alerts, enforcement |
| Pricing | Multi-source pricing cascade, caching, configuration |
| Multi-Tenancy | Per-tenant budgets, isolation, configuration |
| Async/Fiber | Concurrent execution with Ruby fibers |
| Testing Agents | RSpec patterns, mocking, dry_run mode |
| Evaluation | Score agent quality with built-in and custom scorers |
| Error Handling | Error types, recovery patterns |
| Routing | Message classification, routing DSL, inline classify |
| Embeddings | Vector embeddings, batching, caching, preprocessing |
| Image Generation | Text-to-image, templates, pipelines, cost tracking |
| Dashboard | Setup, authentication, analytics |
| Production | Deployment best practices, background jobs |
| API Reference | Complete class documentation |
| Examples | Real-world use cases and patterns |
- Ruby >= 3.1.0
- Rails >= 7.0
- RubyLLM >= 1.12.0
Bug reports and pull requests are welcome at GitHub.
- Fork the repository
- Create your feature branch (
git checkout -b my-feature) - Commit your changes (
git commit -am 'Add feature') - Push to the branch (
git push origin my-feature) - Create a Pull Request
The gem is available as open source under the MIT License.
Built with love by Adham Eldeeb
Powered by RubyLLM



