It tries to strike a balance between working out of the box and being flexible... which has its challenges, still nice overall.
One big real-life pain I experienced is that caches don't always work, e.g. for xAI, since it only supports completions API and thought signatures are returned wrong.
Responses API is now implemented and it's coming in RubyLLM 2.0
https://github.com/crmne/ruby_llm/blob/main/lib/ruby_llm/pro...
Agreed with another commenter on the frustration with the responses API not being naively supported; that seems like a huge miss. There is a connector from another dev, but it's buggy and not as high quality as the main gem.
Really looking forward to future development and especially 2.0!
Edit: Just saw that responses API is now native? I will definitely check that out.
Since a few mentioned Responses API: the reason why it wasn't implemented in 1.x is because RubyLLM 1.x effectively assumes a 1:1 mapping between provider and protocol. That assumption no longer holds since OpenAI has 2 protocols with different capabilities, and to access all VertexAI models we need to support a bunch under that single provider.
Therefore, a major refactoring to split Protocols and from Providers was needed, as well as a way to route different models to different Protocols under the same Provider, transparently.
That's one of the many things that's gonna ship with RubyLLM 2.0.
If you're curious: https://github.com/crmne/ruby_llm/commit/d398354da493570b050... https://github.com/crmne/ruby_llm/commit/0875ce2dfeae9d28a3a...
Rails-style instrumentation landed in 1.16.0.
To put it differently, is this more like choosing between Fog and aws-sdk-s3, or choosing between Active Storage and aws-sdk-s3?
Some of the things I like about RubyLLM: 1. the DSL - You can chain methods like ActiveRecord. 2. the Structure - If gives a way to organize agents, tools & prompts 3. the Portability - The costs of AI usage, will one day be an issue for any successful product. Being able to easily test and move from Anthropic to DeepSeek cut my bill down by over 90%. Knowing how easy RubyLLM makes it, ignoring this eventuality feels reckless to me. 4. ActiveRecord Integration - With a simple `bin/rails generate ruby_llm:install `, you can save each chat to your database. 5. Agent Training - This is a side benefit of the above, but has been a huge unlock for me. Since I have all my chats saved, I will regularly pull down that history and give it to claude code to refine my agent instructions.
You can always build multiple clients however. It could be one thorough integration with one API, and a simpler backup via RubyLLM.
Unless of course RubyLLM supports all of the above, but even then, are they going to be able to keep up as much as a native client in the long term?
The answer is almost always that a native client for a more critical integration is the right call. You can always add another if you need it.
I love how MINASWAN Hacker News is when talking about Ruby!
I also liked how they run the issue tracker. If you select "Feature Request", it makes you explain how you explored workarounds, why you believe it belongs in RubyLLM etc to prevent scope creep.
> Error: You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits. To monitor your current usage, head to: https://ai.dev/rate-limit. * Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_free_tier_requests, limit: 20, model: gemini-2.5-flash Please retry in 41.543129369s.
I'm not sure where you got that.
`chat.with_temperature(0.2)`
https://rubyllm.com/chat/#controlling-response-behavior
`chat.with_thinking(effort: :high, budget: 8000)`
https://rubyllm.com/thinking/#controlling-extended-thinking
Max tokens is the only one of your list that require provider specific params:
https://rubyllm.com/chat/#provider-specific-parameters
I'm one guy doing it for free. Happy to see your contribution!
I will have a deep dive into which things I felt we needed to adapt per provider.
I didn't mean to imply that you have to solve all of our wants of course.
One thing we did do was monkey-patch the spot where tool_calls are performed by RubyLLM. We had our own mechanism for that and were able to skip RubyLLM's and still extract the tool calls and run them through our own tool harness. That all worked beautifully. I don't know if that type of stuff is something you want PRs on or that you want to keep steering towards the route that does everything within RubyLLM classes. Happy to contribute some of that.
You work your arse off for free and the guy who made the disparaging comment didn't even bother to research to see if he had the details right.
Hat's off to you Carmine for all your work. Many people really do appreciate it.
I think it is fair to list limitations from using a library that provides an abstraction; it can suggest why a tool isn't right for a person's use cases.
But it also sounds like this API handles those pretty well.
You can build high quality software with dynamically typed languages, and Ruby is an absolute dream to read and write.
I was on team dynamic typing for about 12 years, and Ruby was a big part of that. I still think dynamic languages can be wonderful to read and write.
But after using modern statically typed languages with good inference, I changed my mind. Many of my old objections were really objections to verbose type systems, not static typing itself. With inference, you can keep a lot of the readability while gaining safer refactoring, better tooling, and earlier feedback.
That doesn’t mean dynamic languages can’t produce high-quality software. They obviously can. But I don’t think appreciating modern static typing is just evangelism.
And yes, I understand what this library is about, it's for "beautiful" easy to use interface to AI providers for Ruby apps. It's the popular play nowadays with litellm, bifrost, gomodel and vercel gateway. We have at least couple AI gateways, libraries like that every week on HN.
Why did people switch to these languages in the first place and what's driving the current back-to-typed-languages trend?