9 ms·
RubyLLM: A delightful Ruby way to work with AI
- jatins 2y agoSuch a breath of fresh air compared to poor DX libraries like langchain
- nullpoint420 2y agoI’ve found the Ruby community really cares about DUX. Not sure why it’s not in other language communities
- choxi 2y agoMatz said he designed Ruby to optimize for developer happiness, it’s just a core principle of the language since it was created
- kuboble 2y agoHappiness of a developer writing code can be a misery of a one having to read / debug it. I worked in ruby for a couple years around 2009 and having to deal with a code that implemented most of its logic via method missing is still one of the strongest negative memories I have about coding.
- viraptor 2y agoAnother annoying one from that category is Ruby's forwarded methods. Since they're created via generated, injected code, you can't query which method it forwards to at runtime. Or not easily anyway.
- MatthiasPortzel 2y ago`binding.irb` and `show_source` have been magical in my Ruby debugging experience. `binding.irb` to trigger a breakpoint, and `show_source` will find the source code for a method name, even in generated code somehow.
- richjdsmith 2y ago… I’ve been using Ruby for years and never thought to use show_source like this in a debugger. Thanks kind stranger, you just made my day!
- RangerScience 2y agoYep yep, that's the whole "sharp knives" thing. What I advise (and aim for) is only pulling out the sharp knives for "library" code, but application code should stay "simple" (and this much more easily navigable). Otherwise you can absolutely make a bloody mess!
- toasterlovin 2y agoI don’t really mean this to be derogatory toward people who enjoy other things, but Ruby is a language and ecosystem by and for people who have taste.
- continuational 2y agoCertainly a taste for global state, it seems.
- atemerev 2y agoDogmatically rejecting global state even if it simplifies things in some particular case _is_ poor taste. Even a goto can be elegant sometimes.
- zelphirkalt 2y agoUsually though it just creates long term issues, putting off important work to later.
- bmacho 2y agoSometimes later never comes, so it's a net win compared to languages where you are forced do this important work now.
- lolinder 2y agoBut when later does come, it can take dev-years to fully disentangle the global state and allow code reuse. Did you gain dev-years in productivity by using it in the first place? Probably not. If you have good reason to believe that an app will stick around for more than a year, be maintained by more than 3 people, or grow to more than 500k lines of code (sub in whatever metrics make sense to you), don't put off removing global state for later. You will regret it eventually, and it doesn't cost much to do it right the first time. (Also, no mainstream language I'm aware of forces you to not use global state. Even Java, famed for its rigidity, has global state readily available if you really do need it.)
- rochak 2y agoUmm, doesn’t Go do so as well? Personally, I’ve had a better experience working with Go tooling.
- jatins 2y agoGo ecosystem is generally good. However, given that Go as a language doesn't have any "fancy" (for the lack of a better word) syntactical features you can't create DSL's like this though Ruby's expressiveness comes at a cost and I'd personally stick with Go in a team but use something like RubyLLM for personal projects
- lolinder 2y agoI'm wary of equating "ability to create dsls like this" with "prioritizing developer experience". Ruby and go each prioritize different parts of the developer experience. Ruby prioritizes the experience of the author of the initial code at the expense of the experience of the maintainer who comes later. Go prioritizes the experience of a maintainer over the experience of the initial author. Both prioritize a developer, both de-prioritize a different developer, and which one makes more sense really depends on the ratio of time spent on writing greenfield code versus maintaining something another human wrote years ago who's long gone.
- smw 2y agoI disagree with the idea that Go prioritizes the maintainer. More lines of code typically makes maintenance more difficult. Go is easy to read line by line, but the verbosity makes it more challenging to understand the bigger picture. I find changes in existing Go software often end up spreading far deeper into the app than you'd expect. The runtime is fantastic, though, so I don't see it losing it's popularity anytime soon.
- danenania 2y ago> More lines of code typically makes maintenance more difficult. That’s kind of just the surface level of maintenance though. Go is not so much focused on making it easy to read a single file, but on minimizing the chains of abstraction and indirection you need to follow to understand exactly how things work. It’s much more likely that all the logic and config to do something is right there in that file, or else just one or two “Go to definition” clicks away. You end up with way more boilerplate and repetition, but also looser coupling between files, functions, and components. Contrast that to a beautiful DSL in Ruby. It’s lovely until it breaks or you need to extend it, and you realize that a small change will require refactoring call sites across a dozen different files. Oh and now this other thing that reused that logic is broken, and we’ve got to update most of the test suite, and so on.
- RangerScience 2y agoEvery language prioritizes something (or somethings) because every language was made by a person (or people) with a reason; python and correctness; Java and splitting up work; Go and something like "simplicity" (not that these are the only priorities for each language). As another comment points out, Matz prioritized developer happiness. My favorite example of this is the amazing useful and amazing whack Ruby array arithmetic; subtraction (`arr1 - arr2`) is element-wise removal, but addition (`arr1 + arr2`) is a simple append. These are almost always exactly what you want to do when you reach for them, but they're completely "incorrect" mathematically.
- okeuro49 2y ago> python and correctness I thought it was Python and readability and "one way of doing things".
- ekianjo 2y agolangchain and llamaindex are such garbage libraries: not only they never document half of the features they have, but they keep breaking their APIs from one version to the next.
- brokegrammer 2y agoI was about to mention those. I decided a while ago to build everything myself instead of relying on these libraries. We could use a PythonLLM over here because it seems like nobody cares about developer experience in the Python space.
- olegp 2y agoWould anyone happen to know of a similar library with as good DX but for JavaScript or TypeScript?
- someothherguyy 2y agoWhat about it is a breath of fresh air? What do the other libraries do that this doesn't?
- jasongill 2y agoI was an early contributor to Langchain and it was great at first - keep in mind, that's before chat models even existed, not to mention tools, JSON mode, etc. Langchain really, I think, pushed the LLM makers forward toward adding those features but unfortunately it got left in the dust and became somewhat of a zombie. Simultaneously, the foundational LLM providers kept adding things to turn them more into a walled garden, where you no longer needed to connect multiple things (like scraping websites with one tool, feeding that into the LLM, then storing in a vector datastore - now that's all built in). I think Langchain has tried to pivot (more than once perhaps) but had they not taken investor $$ early on (and good for them) I suspect that it would have just dried up and the core team would have gone on to work at OpenAI, Anthropic, etc.
- SkyPuncher 2y agoIMO, the samples look great because they're ridiculously simple. It doesn't deal with any of the hard problems you'll routine face with implementation.
- earcar 2y agoThank you! This is what the Ruby community has always prioritized - developer experience. Making complex things simple and joyful to use isn't just aesthetic preference, it's practical engineering. When your interface matches how developers think about the problem domain, you get fewer bugs and more productivity.
- freen 2y agoWow. So thoughtful. Ruby: late to the party, brought a keg.
- dismalaf 2y agoRuby has a bunch of tools to interact with LLMs already. Also has had bindings to stuff like Torch and Tensorflow for years.
- wtf242 2y agobeen using https://github.com/alexrudall/ruby-openai https://github.com/alexrudall/ruby-openai for years with no issues which is a fine gem and works great.
- strudey 2y agoaw thanks, glad you like it! more good Ruby AI libraries is a good thing IMO
- someothherguyy 2y agoWhat about it is so thoughtful?
- ilrwbwrkhv 2y agoOh just beautiful. Ruby is so expressive and concise. If you see the typescript options it's like giving yourself a water boarding session through your own volition.
- gedy 2y agoIs it really Ruby or they just made a nice interface? I don't see why a hypothetical TypeScript example would be all that different. // Just ask questions const chat: Chat = LLM.chat; chat.ask("What's the best way to learn TypeScript?"); // Analyze images chat.ask("What's in this image?", { image: "ts_conf.jpg" }); // Generate images LLM.paint("a sunset over mountains in watercolor style"); // Create vector embeddings LLM.embed("TypeScript is powerful and scalable"); // Let AI use your code class Calculator { description = "Performs calculations"; params = { expression: { type: "string", desc: "Math expression to evaluate" }, }; execute(args: { expression: string }): string { return eval(args.expression).toString(); } } chat.withTool(new Calculator()).ask("What's 123 * 456?");
- williamcotton 2y agoIt's the extra parens, semi-colons, keywords and type annotations. Ruby makes the tradeoff for legibility above all else. Yes, you can obviously read the TypeScript, but there's an argument to be made that it takes more effort to scan the syntax as well as to write the code. Also: const chat: Chat = LLM.chat; ...is not instantiating a class, where Ruby is doing so behind the scenes. You'd need yet another pair of parens to make a factory! This is mainly a matter of syntactic style!
- maleldil 2y agochat = RubyLLM.chat Is ambiguous, though. You can't know if it's an assignment or creating a new object. I don't think that's more readable.
- 2y ago
- ketzo 2y agoIs this gonna be the thing that finally makes me tried Rails? Ruby syntax really is just nice.
- drdaeman 2y agoI think it's the very nice-looking and clean high-level API that should be a pleasure to use (when it fits the job, of course). I'm pretty sure this API semantics (instance builder to configure, and then it's ask/paint/embed with language-native way to handle streaming and declarative tools) would look beautiful and easy to use in many other languages, e.g. I can imagine a similar API - save, of course, for the Rails stuff - in Python, C# or Erlang. While this level of API may be not perfectly sufficient for all possible LLM use cases, it should certainly speed up development time when this level of API is all that's possible needed.
- Multiplayer 2y agoSaw this gem of a gem on reddit earlier today and there were some trollish comments about no one using ruby anymore blah blah blah which quietly bummed me out. Surprised and Delighted to see it as #1 here on HN tonight!
- adamtaylor_13 2y agoThere’s a lot of folks who get immense schadenfreude talking about things they know nothing about to strangers on the internet who also don’t know anything. Don’t let it bum you out.
- someothherguyy 2y ago> some trollish comments about no one using ruby anymore It is somewhat objectively true: https://octoverse.github.com/2022/top-programming-languages https://octoverse.github.com/2022/top-programming-languages https://github.blog/wp-content/uploads/2024/10/GitHub-Octoverse-2024-top-programming-languages.png?w=1200 https://github.blog/wp-content/uploads/2024/10/GitHub-Octove... It doesn't mean much, and this library can be reproduced in any of those top 10 languages from what I can tell.
- nextos 2y agoIs position #10 in https://octoverse.github.com/2022/top-programming-languages https://octoverse.github.com/2022/top-programming-languages bad? It ranks right after Shell (#8) and C (#9). Ruby is still a mainstream language, and it's fairly easy to find a Ruby job. Compare that to Clojure or Haskell.
- someothherguyy 2y agoIt has dropped in popularity and has never regained the popularity it once held. Of the many developers who used to write Ruby (myself included), I would wager not many of those same people still do.
- vidarh 2y ago
- ksec 2y agoInteresting cause I submitted this some time ago and I just did another one on https://news.ycombinator.com/item?id=43369977 https://news.ycombinator.com/item?id=43369977 But it seems hashnode.dev as a domain is blocked entirely. Hopefully Ruby gets another chance in AI era.
- init0 2y agoOne of the most concise APIs to interact with an llm! Keep going! Happy to see ollama support PR in draft.
- aguynamedben 2y agoRuby is alive and well!
- someothherguyy 2y agoWhy does this say it was posted four hours ago on the front page, four days ago on Agolia, 3 days ago on /from and the comments are all from minutes to hours ago here?
- noodletheworld 2y agoThe threads have presumably been merged; look at the submitters in the history. > 166 points|ksec|4 days ago|21 comments > 168 points by ksec 4 hours ago But yes; it’s a bit dodgy to resurface old news like this imo and pretend it’s new news. I’d go as far as to say that being at #1, under the circumstances, means it’s been artificially boosted somehow. I haven’t the foggiest why anyone would bother though.
- deleted 2y ago[deleted]
- thinkingemote 2y agoat least 2 ways. 1. Moderators can re-submit interesting stories from a second chance pool https://news.ycombinator.com/pool https://news.ycombinator.com/pool (This might happen automatically from time to time?) When this happens some of the timestamps get updated but others dont. 2. Moderators can invite users via email to re-submit stories. https://news.ycombinator.com/invited https://news.ycombinator.com/invited
- ripped_britches 2y agoThis is an obviously fishy post!
- neuroelectron 2y agoWhat's fishy about wrapping a bunch of APIs?
- ripped_britches 2y agoNothing about the library but there was clearly artificial boosting when it was first posted
- Finbarr 2y agoThis is a beautiful API. Thanks for the work. Here's hoping for a nice ruby agent framework in the near future too!
- armenarmen 2y agosaw this the other day: https://github.com/activeagents/activeagent https://github.com/activeagents/activeagent haven't tried it yet though
- jiangplus 2y agoI am writing some LLM-based app scripts, this feels like a breeze!
- ultimoo 2y agonice job! i miss using ruby.
- makuchaku 2y agoAbut time that someone built this in ruby! You rock!
- continuational 2y agoWhy is it using a global variable for this?
- t-writescode 2y agoIt's not. The method, RubyLLM.chat creates a new instance of the Chat object, as has been copied here: module RubyLLM class Error < StandardError; end class << self def chat(model: nil) Chat.new(model: model) end https://github.com/crmne/ruby_llm/blob/9825f4fea089b1b9749611ba0fb476cc12bae630/lib/ruby_llm.rb#L29 https://github.com/crmne/ruby_llm/blob/9825f4fea089b1b974961... If you're wondering about module RubyLLM. That's just how Ruby is often written. Addendum: Ruby does not require you to put the opening and closing parenthesis on a function to run that function, and it's not always put there when you have zero or 1 parameter (I find it to be cleaner when you have a parameter, but have no opinion when there isn't a parameter) In the example code from the link itself, you'll see: chat.ask "What's the best way to learn Ruby?" which is the same as chat.ask("What's the best way to learn Ruby?")
- bmacho 2y ago> Ruby does not require you to put the opening and closing parenthesis on a function to run that function, and it's not always put there when you have zero or 1 parameter mind = blown I always liked how functionName denotes the function and functionName() calls the function, and then it denotes the result e.g. in JavaScript or in math. But just saying functionName to call a function makes the code read more like English. Code that reads like English > code that reads like math. (And you can still talk about functions of course.)
- viraptor 2y agoIt comes with the downside that if you want to pass the function itself around, you need to do f=something.method(:the_function), and then f.call(args). It's not a huge deal, but... meh.
- 2y ago
- kjgkjhfkjf 2y agoWhat are some similarly ergonomic packages for other languages?
- tw1984 2y agostone age LLM.
- skavi 2y ago[flagged]
- viraptor 2y agoIt's not that slow really. Also, there's yjit included https://speed.yjit.org/ https://speed.yjit.org/ We're running a few very popular services on rails and it's really not a problem in any way.
- FailMore 2y agoThis looks amazing, is there anything one can do to change the system prompt where it is available?
- antirez 2y agoThe best Ruby always surpasses the elegance of the best Python... Unfortunately for practical means at this point I go for Python: more libraries, less problems with the C implementation of the interpreter (had issues with the GC in the past), better LLMs understanding of the code.
- deleted 2y ago[deleted]
- drdaeman 2y agoSurely you can have the same API elegancy and overall semantics in Python? chat = python_llm.Chat() _ = chat.ask"What's the best way to learn Python?") # Analyze images _ = chat.ask("What's in this image?", image="python_conf.jpg") # Generate images _ = python_llm.paint("a sunset over mountains in watercolor style") # Stream responses for chunk in chat.ask("Tell me a story about a Python programmer"): print(chunk.content) # Can be a class if necessary, but for this weather thingy we can probably do with a simple callable # Requires Python 3.9+ for typing.Annotated def get_weather( latitude: Annotated[Decimal, "Latitude of the location"], longitude: Annotated[Decimal, "Longitude of the location"] ) -> str: """ Gets current weather for a location. """ ... _ = chat.with_tool(get_weather).ask("What's the weather in Berlin? (52.5200, 13.4050)") (The `_ =` bits are mine, to emphasize we have a meaningful result and we're knowingly and willingly discarding it. Just a habit, I hope it doesn't bug people.) Ruby has significantly more capable metaprogramming facilities, but they aren't used in RubyLLM, it's all just objects and methods (biggest difference being use of iterable in Python vs providing a block in Ruby, as I felt an iterable would be more Pythonic here), which is nothing Ruby-specific. And IMHO advanced metaprogramming should be used carefully, as it may make code pretty but really hard to comprehend and analyze. My largest issue with Rails is difficulty to tell where things are coming from and what's available (lack of implicit imports and ability to re-open any class or module and inject more stuff in there so there's no single place that defines it is a double-edged sword that may lead to chaos if wielded carelessly - YMMV, of course, I'm merely stating my personal preferences here).
- tommica 2y agoWow the syntax is beautiful!
- nextaccountic 2y agoThat's my takeaway from Ruby - syntax matters, and good syntax makes programmers happier
- dkobia 2y agoI support software in many languages and ruby has to be the most syntactically stimulating.
- brink 2y agoYou're confusing beautiful with simple. There's a lot of complexity and magic that's hidden behind the curtains of that "beautiful" syntax. Great for scripts and small programs, and an absolute nightmare on large projects. It's too simple.
- the_gastropod 2y agoAs a general rule of thumb, don’t yuck someone else’s yum. Plenty of people like the trade offs Ruby makes. And plenty of absolutely huge businesses use it quite successfully (e.g., Shopify, GitHub, GitLab, Airbnb, Stripe). If you don’t like it, don’t use it.
- deedubaya 2y agoLooks useful. Allowing ai to eval() code or execute any sql statement would scare the crap outta me personally.
- xcskier56 2y agoFrom searching the codebase, I can only find eval() used in the markdown and the specs. You’re totally right that eval()’ing unknown code is terrible but it doesn’t look like the gem itself is doing that. The usage of eval() is in a user written tool in the docs. Definitely a bd example and should probably be changed
- deedubaya 2y agoYes, that’s exactly what I was referring to. Folks (or llms!) never copy/paste doc examples, right?
- hartator 2y agoSuper interesting gem! `Document.search(query).limit(limit).map(&:title)` how do you defined the documents to search on?
- breckenedge 2y agoThat’s an example of what your code could look like. For example, you might have a Rails app with a Document model and have added search to that model via Searchkick. Then this code is called by the library to execute a search.
- kyledrake 2y agoThis interface needs to have a better relationship with streaming, there is always a lag in response and a lot of people are going to want to stream the response in non blocking threads instead of hanging the process waiting for the response. Its possible this is just a documentation issue, but either way streaming is a first class citizen on anything that takes more than a couple seconds to finish and uses IO. Aside from that the DSL is quite excellent.
- joevandyk 2y agoFrom https://rubyllm.com/#have-great-conversations https://rubyllm.com/#have-great-conversations # Stream responses in real-time chat.ask "Tell me a story about a Ruby programmer" do |chunk| print chunk.content end
- jupp0r 2y agoThis will synchronously block until ‘chat.ask’ returns though. Be prepared to be paying for the memory of your whole app tens/low hundreds of MB of memory being held alive doing nothing (other than handling new chunks) until whatever streaming API this is using under the hood is finished streaming.
- andrewmutz 2y agoThreads?
- jupp0r 2y agoRails is a hot ball of global mutable state. Good luck with threads.
- andrewmutz 2y agoThe default rails application server is puma and it uses threads
- ichiwells 2y agoI run engineering for a venture backed AI-first startup and we use Ruby/Rails. For us, it made sense to leverage one of the best domain modeling and ORM frameworks out there. Most of our inference is http calls to foundational models, but we can still fine tune and host models on GPUs using Python. Inference matters, but part of building an effective user platform are the same old SaaS problems we’ve had before, and Rails just works. Inbound and outbound email done in a day. Turning an OCR’d title from ALL CAPS into Title Case is one method call and not a whole custom algorithm, etc. A lot of people seem to think Ruby is slow for some reason but it’s as fast as Python, and with falcon as fast as node for async behavior. Safe to say the application language taking 0.03 seconds instead of 0.003 seconds when you have to wait 3 seconds for first token is absolutely not the bottleneck with LLM heavy workflows, anyway. And yes, metaprogramming is a powerful tool with which you can easily shoot yourself in the foot. We culturally just don’t write any code that’s not greppable so don’t use method_missing kinds of things unless it’s in a robust gem like active record. Pretty trivial problem to solve really. PS - We’re hiring, if that philosophy aligns with you!
- mattmcknight 2y agoIn terms of LLM code generation as well, the well structured nature of a Rails application, where there is a place for everything, a structure for tests to be added, really helps from the perspective of getting a comprehensible application out of it that is easy to modify. In addition to the existence of well tested component for most normal web application tasks, maybe it helps that a lot of Rails has already been based on old-fashioned code generation for 20 years.
- cootsnuck 2y agoI have this same suspicion. I dusted off a hobby Rails app from two years ago I was making with Cursor. I decided to try completely changing the main functionality of the app with the much better LLMs of today and was shocked how well it did with one-shot. Now compare that to my recent experience with having Cursor help me work on a preexisting Node/React app...geez. What a pain. (It doesn't help that I wasn't the one that originally created the React app though.)
- gregmolnar 2y agoBe careful with the examples though: https://github.com/crmne/ruby_llm/issues/25 https://github.com/crmne/ruby_llm/issues/25
- maleldil 2y agoI understand it's a Ruby thing, `chat = RubyLLM.chat` looks odd. How do I know whether it's a function call returning an object or just an assignment? Why not just use `RubyLLM.chat()` and eliminate the ambiguity?
- duckworth 2y agoIn Ruby, chat = RubyLLM.chat is a method call since Ruby doesn't have properties, only methods. Dropping parentheses is standard Ruby style, familiar to Ruby developers. While adding parentheses is allowed, it doesn't match Ruby's readability. The library aims for a clean style consistent with Ruby conventions.
- abid786 2y agoBecause everything in Ruby is an object and everything is a passing messages (ie a method call).
- RKFADU_UOFCCLEL 2y ago[flagged]
- deleted 2y ago[deleted]
- strudey 2y agoThere's a channel for this on the Ruby AI Builders Discord: https://discord.gg/HZTsjFKyy3 https://discord.gg/HZTsjFKyy3
- jupp0r 2y agoThe API looks nice on the surface, but this will be expensive to operate due to Ruby and Rails’ lack of support for concurrency. Everything is blocking, which is not a great match for the async nature of interacting with these models.
- RangerScience 2y agoRuby isn't dead and like all alive things, it grows and changes; your expectation is out of date. https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/ https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-rele...
- jupp0r 2y agoUnfortunately, 5 years after the release you linked, almost none of this has made it to Rails or even to relatively new libraries this post is about. The reason (imho) are unfortunate design choices in how the language incorporates concurrency - it’s just not well done.
- igravious 2y agohttps://ruby-concurrency.github.io/concurrent-ruby/1.1.5/Concurrent/Async.html https://ruby-concurrency.github.io/concurrent-ruby/1.1.5/Con... https://thoughtbot.com/blog/my-adventure-with-async-ruby https://thoughtbot.com/blog/my-adventure-with-async-ruby First two hits on Google.
- jupp0r 2y agoWell instead of looking at the two first hits of Google I spent several years on a platform team of a multi billion dollar company using mostly Rails and worked on solving real world problems caused by Ruby/Rails’ design choices which lead me to believe that Ruby concurrency as of today is hot garbage. They need fundamental breaking changes to the language to fix this, which means people won’t be able to use their beloved pile of 438 gems that haven’t seen a commit in 7 years. If I had to bet, I’d say the language is dead. It might still be a nice niche language for easy prototyping, but the world has moved on to async/await (js/python/Rust/C++) or stackful coroutines (Go).
- Alifatisk 2y agoAm I dreaming?
- desireco42 2y agoI am really impressed and delighted how simple this library is. I agree that waiting for response can be an issue. I don't think this is meant to be for such purposes, but for tools that would process and create artifacts based on inputs. I love Mistral and local LLMs, so this would probably the thing I would like to add.
- soheil 2y agoFeels more useful for something like cli where you want to run one-off commands to test something instead of running it in production given how non-deterministic the behavior can be for example for something like chat.ask "What's being said?", with: { audio: "meeting.wav" } definitely don't want users to get a valid response only 75% of the times, maybe?
- agnishom 2y agoCan somebody explain to me what is so great about this package? It just seems to be making API calls. I am not critical, I am just genuinely curious since I don't understand the landscape.
- VladVladikoff 2y ago>delightful >ruby Pick one
- hijp 2y agoAny plans on adding prompt caching and message batches? I saved a lot of money with claude using both. Was making http calls in ruby. Love this project!
- kakasoo 2y ago[dead]