We are using OpenAI API using the fantastic RubyLLM gem from @paolino.
The Ruby AI framework
Build AI features the Ruby way: models, tools, agents, sandboxed code, evaluations, and Rails conventions, designed together, with one consistent API.
Build AI features the Ruby way: models, tools, agents, sandboxed code, evaluations, and Rails conventions, designed together, with one consistent API.
Build with the models you want. Move between hosted and local providers without rewriting your application, or connect an OpenAI-compatible endpoint.
chat = RubyLLM.chat(model: "claude-opus-5")
chat.ask "Hello!"
40 shared features, from chat and tools to media, files, and batches, checked against each provider's own documentation.
See what each provider supports · Browse models and pricing · Track usage and costs
Scaffold a provider gem with the same infrastructure as RubyLLM: configuration, tests, release setup, and a model registry that plugs into RubyLLM at runtime. Reuse a supported protocol without writing protocol code.
Provider gem guideBuild agents, run code safely, evaluate results, and track usage with shared Ruby and Rails conventions.
The model writes Ruby, Python, JavaScript, or shell to calculate and make files. Each run happens in a sandbox on your servers that cannot read your application or its secrets. The files it makes come back as attachments.
Code execution guideDescribe wider sandboxes as Ruby classes and list the ones the model may ask for. A call that needs one waits for a person to approve it, runs once, and never turns into standing access.
Sandboxes guideWrite skills in the open Agent Skills format: instructions, scripts, and reference files in a folder. The model loads a skill only when a task needs it and runs its scripts in the sandbox.
Skills guideDescribe each MCP server as a Ruby class in app/mcp. Inputs pass in the current user, only picks the tools the model sees, and OAuth credentials are stored encrypted in your database.
A saved conversation is the agent's whole state. Any job can pick it up and continue, after a crash, a deploy, or a wait for approval.
Durable agents guideKeep questions and expected answers in a dataset next to an evaluation class in app/evals. RubyLLM checks each answer for correctness. Run the same evaluation from RSpec, Minitest, or Rake, and fail CI when a case fails.
class IssueRefund < RubyLLM::Tool
description "Issues a refund for an order"
requires_approval
def execute(order_id:) = Refunds.issue!(order_id)
end
RubyLLM.chat(model: "gpt-6-luna")
.with_fallbacks("claude-sonnet-5")
.ask "Explain Ruby blocks"
chat = RubyLLM.chat(model: "claude-sonnet-5")
.with_caching
chat.with_instructions(File.read("review.md"), cache_until_here: true)
chat.ask "Review this diff", with: "changes.patch"
SupportAgent.new.with_owner(current_account).ask "Where is order 42?"
current_account.ruby_llm_usages.sum(:total_cost)
OpenTelemetry::SDK.configure
RubyLLM::OpenTelemetry.enable
SupportAgent.new.ask "Where is order 42?"
# chat → execute_tool lookup_order → chat
RubyLLM.workflow("Write article") do |workflow|
notes = workflow.step("Research") do
ResearchAgent.new.ask(topic).content
end
workflow.step("Draft") do
WriterAgent.new.ask(notes).content
end
end
documents = ["Ruby is expressive", "Go is fast"]
embeddings = RubyLLM.embed(documents)
ranked = RubyLLM.rerank("Ruby language", documents,
model: "rerank-v3.5")
response = RubyLLM.chat
.with_provider_tools(:web_search)
.ask "What's the latest Ruby release?"
response.citations
class Urgency < RubyLLM::Judge
model "jev-latest"
probability :urgent, "Needs action today?"
end
judgment = Urgency.judge("My account is locked!")
judgment.urgent.probability
chats = documents.map do |doc|
RubyLLM.chat(model: "claude-sonnet-5")
.with_instructions("Summarize in one line.")
.ask_later(doc.text)
end
batch = RubyLLM.batch(chats)
document = RubyLLM.ocr "scanned-contract.pdf"
puts document.markdown
transcript = RubyLLM.transcribe "meeting.wav"
RubyLLM.speak(transcript.text).save "transcript.mp3"
RubyLLM.paint "a watercolor sunset over mountains"
RubyLLM.animate "a paper boat in a rainy gutter"
RubyLLM.moderate(comment.body).flagged?
Give agents memory. Use separate configurations for each tenant and retries when requests fail, or explore community gems for monitoring dashboards.
Save conversations with Active Record and stream replies with Hotwire. The generators give you a working chat UI. Watch the two-minute demo.
class Chat < ApplicationRecord
acts_as_chat
end
chat = Chat.create! model: "claude-opus-5"
chat.ask "What's in this file?", with: "report.pdf"
chat.messages.last.content
app/
├── agents/ support_agent.rb
├── tools/ issue_refund.rb
├── schemas/ product_schema.rb
├── prompts/ support_agent/
├── skills/ invoices/SKILL.md
├── sandboxes/ workspace_sandbox.rb
├── mcp/ linear.rb
├── evals/ support_evaluation.rb
└── judges/ urgency_judge.rb
Generators create each piece where Rails expects it. Store files with Active Storage and write your prompts in ERB templates. Use Turbo Streams to show replies and Active Job to run agents in the background, one process per chat, with questions and approvals that survive restarts.
Everything above is built on one chat API. Follow it from your first question to your first agent.
Ask a question, then ask again. The chat keeps the conversation history, so every follow-up has context.
Chat guidePass a block to display the response as it arrives, in your terminal or a Rails view.
Streaming guideAsk about an image, a recording, or a PDF. Pass local paths, URLs, or several files at once with with: and RubyLLM prepares them for the model.
Describe a tool in a Ruby class and implement execute. RubyLLM runs the tool calls and sends the results back to the model.
Define the fields you want in a Ruby schema. Read the result as a Hash with response.parsed.
Give an agent its model, instructions, and tools in a Ruby class. In Rails, it saves its conversation, and find picks it up again in any request or job.
The RubyLLM gem includes a skill for your coding agent. Give it the API, examples, and Rails conventions that match your application.
Run this from your application after installing RubyLLM. --agents coding installs it for the coding assistants your project uses, and keeps it out of your app's app/skills.
Skill setup and updates
Used in production by the teams behind these products.
Using RubyLLM? Get featured or Sponsor us
Their support helps fund RubyLLM's development. Thank you for investing in AI for Ruby.
We are using OpenAI API using the fantastic RubyLLM gem from @paolino.
Our Langgraph agent was failing. I took a gamble and rebuilt it using RubyLLM. Not only was it far simpler, it performed better.
It feels natural. At Yuma, serving over 100,000 end users, our unified AI interface had accumulated so much cruft. RubyLLM is so much nicer than all of that.
We got our proof of concept up in one day and the first beta in about a week. Really impressive.
Most tools add layers. This one removes them. It keeps the mental load low.
The speed of development and the closest thing to the AI SDK in JavaScript land. Easiest Rails integration.
Multi-provider support. Agentic loop support. Can we sponsor?
I replaced my internal provider implementation with RubyLLM and it just worked nicely. Deleted a lot of code.
Ruby-esque DSL and the right level of abstraction: composable, flexible on architecture, opinionated on lower-level implementation.
Love deleting code when adding a library, and love the thought that goes into the gem.
RubyLLM is pretty much the devise of this generation. Adding it to any application is pretty much a no-brainer.
Love how Ruby-like it feels. The DSL is incredibly intuitive and follows all the conventions I would expect.
RubyLLM is awesome, easy and intuitive. You should try it, even if you don’t work with Ruby.
If you can find a better Ruby AI library than RubyLLM, I will only write JavaScript for the rest of the year!
We built our own quick and dirty wrapper, then your project came up and rocked it.
Implementation-agnostic access to models helps us simplify our flow and experiment with agentic systems.
When a tool removes noise instead of adding it, you get to stay focused on the real work.
Super easy way to start adding magic to our app. Love the speed of improvements.
Just having a framework to structure all our LLM processes is gigantic value. Tool integration works like a charm.
It just works. I do not want to keep dealing with wrappers and fast-moving provider changes.
I delivered a lot of value to my customers because of your work.
Letting someone else manage the fast-moving infrastructure of the LLM API landscape allowed me to focus on applications.
Really solid overall, well thought out, and seamless across Rails model-backed chats and one-off chats.
My clients and my clients' clients are very happy because we can iterate and improve our system quickly.
RubyLLM made the future of Ruby and AI feel easier, more accessible, and completely within reach.
Foundational tooling for working with AI in Ruby and Rails applications.
I’m kinda fitting RubyLLM into all of my projects.
Using RubyLLM? Share your story! Takes 5 minutes.