📗 That is the sequence on creating net functions with generative AI integration. Half 1 targeted on explaining the AI stack and why the appliance layer is the very best place within the stack to be. Examine it out here.
Desk of Contents
Introduction
It’s not typically that you simply hear the Ruby language talked about when discussing AI.
Python, after all, is the king on this world, and for good cause. The neighborhood has coalesced across the language. Most mannequin coaching is finished in PyTorch or TensorFlow today. Scikit-learn and Keras are additionally very talked-about. RAG frameworks akin to LangChain and LlamaIndex cater primarily to Python.
Nevertheless, in relation to constructing net functions with AI integration, I imagine Ruby is the higher language.
Because the co-founder of an agency devoted to constructing MVPs with generative AI integration, I incessantly hear potential shoppers complaining about two issues:
- Functions take too lengthy to construct
- Builders are quoting insane costs to construct customized net apps
These complaints have a typical supply: complexity. Trendy net apps have much more complexity in them than within the good ol’ days. However why is that this? Are the advantages introduced by complexity price the associated fee?
I assumed spas had been purported to be stress-free?
One large piece of the puzzle is the current rise of single-page functions (SPAs). The preferred stack used right this moment in constructing trendy SPAs is MERN (MongoDB, Categorical.js, React.js, Node.js). The stack is well-liked for a couple of causes:
- It’s a JavaScript-only stack, throughout each front-end and back-end. Having to solely code in just one language is fairly good!
- SPAs can supply dynamic designs and a “clean” consumer expertise. Easy right here implies that when some piece of information adjustments, solely part of the location is up to date, versus having to reload the entire web page. In fact, should you don’t have a contemporary smartphone, SPAs gained’t really feel so clean, as they are usually fairly heavy. All that JavaScript begins to tug down the efficiency.
- There’s a giant ecosystem of libraries and builders with expertise on this stack. That is fairly round logic: is the stack well-liked due to the ecosystem, or is there an ecosystem due to the recognition? Both method, this level stands.
React was created by Meta. - Numerous cash and energy has been thrown on the library, serving to to shine and promote the product.
Sadly, there are some downsides of working within the MERN stack, essentially the most vital being the sheer complexity.
Conventional net growth was carried out utilizing the Mannequin-View-Controller (MVC) paradigm. In MVC, all the logic managing a consumer’s session is dealt with within the backend, on the server. One thing like fetching a consumer’s knowledge was carried out through operate calls and SQL statements within the backend. The backend then serves totally constructed HTML and CSS to the browser, which simply has to show it. Therefore the identify “server”.
In a SPA, this logic is dealt with on the consumer’s browser, within the frontend. SPAs should deal with UI state, utility state, and generally even server state all within the browser. API calls should be made to the backend to fetch consumer knowledge. There’s nonetheless fairly a little bit of logic on the backend, primarily exposing knowledge and performance by APIs.
For instance the distinction, let me use the analogy of a industrial kitchen. The client would be the frontend and the kitchen would be the backend.
Conventional MVC apps are like eating at a full-service restaurant. Sure, there’s quite a lot of complexity (and yelling, if The Bear is to be believed) within the backend. However the frontend expertise is easy and satisfying: all the client has to do is decide up a fork and eat their meals.
SPAs are like consuming at a buffet-style eating restaurant. There’s nonetheless fairly a little bit of complexity within the kitchen. However now the client additionally has to determine what meals to seize, easy methods to mix them, easy methods to prepare them on the plate, the place to place the plate when completed, and many others.
Andrej Karpathy had a tweet lately discussing his frustration with trying to construct net apps in 2025. It may be overwhelming for these new to the house.
In an effort to construct MVPs with AI integration quickly, our company has determined to forgo the SPA and as an alternative go together with the normal MVC strategy. Particularly, now we have discovered Ruby on Rails (typically denoted as Rails) to be the framework greatest suited to rapidly creating and deploying high quality apps with AI integration. Ruby on Rails was developed by David Heinemeier Hansson in 2004 and has lengthy been generally known as an important net framework, however I might argue it has lately made leaps in its capacity to include AI into apps, as we are going to see.
Django is the preferred Python net framework, and in addition has a extra conventional sample of growth. Sadly, in our testing we discovered Django was merely not as full-featured or “batteries included” as Rails is. As a easy instance, Django has no built-in background job system. Practically all of our apps incorporate background jobs, so to not embody this was disappointing. We additionally want how Rails emphasizes simplicity, with Rails 8 encouraging builders to easily self-host their apps as an alternative of going by a supplier like Heroku. In addition they lately launched a stack of instruments meant to exchange exterior services like Redis.
“However what concerning the clean consumer expertise?” you may ask. The reality is that trendy Rails consists of a number of methods of crafting SPA-like experiences with out all the heavy JavaScript. The first device is Hotwire, which bundles instruments like Turbo and Stimulus. Turbo allows you to dynamically change items of HTML in your webpage with out writing customized JavaScript. For the instances the place you do want to incorporate customized JavaScript, Stimulus is a minimal JavaScript framework that permits you to just do that. Even if you wish to use React, you are able to do so with the react-rails gem. So you possibly can have your cake, and eat it too!
SPAs should not the one cause for the rise in complexity, nonetheless. One other has to do with the appearance of the microservices structure.
Microservices are for Macrocompanies
As soon as once more, we discover ourselves evaluating the straightforward previous with the complexity of right this moment.
Previously, software program was primarily developed as monoliths. A monolithic utility implies that all of the totally different components of your app — such because the consumer interface, enterprise logic, and knowledge dealing with — are developed, examined, and deployed as one single unit. The code is all sometimes housed in a single repo.
Working with a monolith is easy and satisfying. Operating a growth setup for testing functions is straightforward. You might be working with a single database schema containing your entire tables, making queries and joins easy. Deployment is easy, because you simply have one container to take a look at and modify.
Nevertheless, as soon as your organization scales to the dimensions of a Google or Amazon, actual issues start to emerge. With lots of or hundreds of builders contributing concurrently to a single codebase, coordinating adjustments and managing merge conflicts turns into more and more troublesome. Deployments additionally grow to be extra advanced and dangerous, since even minor adjustments can blow up the complete utility!
To handle these points, giant corporations started to coalesce across the microservices structure. It is a fashion of programming the place you design your codebase as a set of small, autonomous companies. Every service owns its personal codebase, knowledge storage, and deployment pipelines. As a easy instance, as an alternative of stuffing your entire logic relating to an OpenAI shopper into your important app, you possibly can transfer that logic into its personal service. To name that service, you’d then sometimes make REST calls, versus operate calls. This ups the complexity, however resolves the merge battle and deployment points, since every group within the group will get to work on their very own island of code.
One other profit to utilizing microservices is that they permit for a polyglot tech stack. Which means every group can code up their service utilizing no matter language they like. If one group prefers JavaScript whereas one other likes Python, that is no concern. After we first started our company, this concept of a polyglot stack pushed us to make use of a microservices structure. Not as a result of we had a big group, however as a result of we every wished to make use of the “greatest” language for every performance. This meant:
- Utilizing Ruby on Rails for net growth. It’s been battle-tested on this space for many years.
- Utilizing Python for the AI integration, maybe deployed with one thing like FastAPI. Severe AI work requires Python, I used to be led to imagine.
Two totally different languages, every targeted on its space of specialty. What might go mistaken?
Sadly, we discovered the method of growth irritating. Simply organising our dev atmosphere was time-consuming. Having to wrangle Docker compose information and handle inter-service communication made us want we might return to the sweetness and ease of the monolith. Having to make a REST name and arrange the suitable routing in FastAPI as an alternative of creating a easy operate name sucked.
“Certainly we are able to’t develop AI apps in pure Ruby,” I assumed. After which I gave it a strive.
And I’m glad I did.
I discovered the method of creating an MVP with AI integration in Ruby very satisfying. We had been in a position to dash the place earlier than we had been jogging. I beloved the emphasis on magnificence, simplicity, and developer happiness within the Ruby neighborhood. And I discovered the state of the AI ecosystem in Ruby to be surprisingly mature and getting higher day by day.
If you’re a Python programmer and are scared off by studying a brand new language like I used to be, let me consolation you by discussing the similarities between the Ruby and Python languages.
Ruby and Python: Two Sides of the Identical Coin
I think about Python and Ruby to be like cousins. Each languages incorporate:
- Excessive-level Interpretation: This implies they summary away quite a lot of the complexity of low-level programming particulars, akin to reminiscence administration.
- Dynamic Typing: Neither language requires you to specify if a variable is an
int
,float
,string
, and many others. The categories are checked at runtime. - Object-Oriented Programming: Each languages are object-oriented. Each assist lessons, inheritance, polymorphism, and many others. Ruby is extra “pure”, within the sense that actually all the things is an object, whereas in Python a couple of issues (akin to
if
andfor
statements) should not objects. - Readable and Concise Syntax: Each are thought-about straightforward to study. Both is nice for a first-time learner.
- Large Ecosystem of Packages: Packages to do all types of cool issues can be found in each languages. In Python they’re referred to as libraries, and in Ruby they’re referred to as gems.
The first distinction between the 2 languages lies of their philosophy and design ideas. Python’s core philosophy could be described as:
There must be one — and ideally just one — apparent technique to do one thing.
In principle, this could emphasize simplicity, readability, and readability. Ruby’s philosophy could be described as:
There’s at all times multiple technique to do one thing. Maximize developer happiness.
This was a shock to me after I converted from Python. Take a look at this easy instance emphasizing this philosophical distinction:
# A combat over philosophy: iterating over an array
# Pythonic method
for i in vary(1, 6):
print(i)
# Ruby method, choice 1
(1..5).every do |i|
places i
finish
# Ruby method, choice 2
for i in 1..5
places i
finish
# Ruby method, choice 3
5.instances do |i|
places i + 1
finish
# Ruby method, choice 4
(1..5).every places i
One other distinction between the 2 is syntax fashion. Python primarily makes use of indentation to indicate code blocks, whereas Ruby makes use of do…finish
or {…}
blocks. Most embody indentation inside Ruby blocks, however that is fully non-obligatory. Examples of those syntactic variations could be seen within the code proven above.
There are quite a lot of different little variations to study. For instance, in Python string interpolation is finished utilizing f-strings: f"Good day, {identify}!"
, whereas in Ruby they’re carried out utilizing hashtags: "Good day, #{identify}!"
. Inside a couple of months, I feel any competent Python programmer can switch their proficiency over to Ruby.
Current AI-based Gems
Regardless of not being within the dialog when discussing AI, Ruby has had some current developments on the planet of gems. I’ll spotlight among the most spectacular current releases that now we have been utilizing in our company to construct AI apps:
RubyLLM (link) — Any GitHub repo that will get greater than 2k stars inside a couple of weeks of launch deserves a point out, and RubyLLM is unquestionably worthy. I’ve used many clunky implementations of LLM suppliers from libraries like LangChain and LlamaIndex, so utilizing RubyLLM was like a breath of recent air. As a easy instance, let’s check out a tutorial demonstrating multi-turn conversations:
require 'ruby_llm'
# Create a mannequin and provides it directions
chat = RubyLLM.chat
chat.with_instructions "You're a pleasant Ruby professional who loves to assist learners."
# Multi-turn dialog
chat.ask "Hello! What does attr_reader do in Ruby?"
# => "Ruby creates a getter methodology for every image...
# Stream responses in actual time
chat.ask "Might you give me a brief instance?" do |chunk|
print chunk.content material
finish
# => "Positive!
# ```ruby
# class Particular person
# attr...
Merely superb. Multi-turn conversations are dealt with routinely for you. Streaming is a breeze. Examine this to the same implementation in LangChain:
from langchain_openai import ChatOpenAI
from langchain_core.schema import SystemMessage, HumanMessage, AIMessage
from langchain_core.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
SYSTEM_PROMPT = "You're a pleasant Ruby professional who loves to assist learners."
chat = ChatOpenAI(streaming=True, callbacks=[StreamingStdOutCallbackHandler()])
historical past = [SystemMessage(content=SYSTEM_PROMPT)]
def ask(user_text: str) -> None:
"""Stream the reply token-by-token and maintain the context in reminiscence."""
historical past.append(HumanMessage(content material=user_text))
# .stream yields message chunks as they arrive
for chunk in chat.stream(historical past):
print(chunk.content material, finish="", flush=True)
print() # newline after the reply
# the ultimate chunk has the total message content material
historical past.append(AIMessage(content material=chunk.content material))
ask("Hello! What does attr_reader do in Ruby?")
ask("Nice - might you present a brief instance with attr_accessor?")
Yikes. And it’s essential to notice that this can be a grug implementation. Need to understand how LangChain actually expects you to handle reminiscence? Examine out these links, however seize a bucket first; you could get sick.
Neighbors (link) — This is a superb library to make use of for nearest-neighbors search in a Rails utility. Very helpful in a RAG setup. It integrates with Postgres, SQLite, MySQL, MariaDB, and extra. It was written by Andrew Kane, the identical man who wrote the pgvector extension that permits Postgres to behave as a vector database.
Async (link) — This gem had its first official launch again in December 2024, and it has been making waves within the Ruby neighborhood. Async is a fiber-based framework for Ruby that runs non-blocking I/O duties concurrently whereas letting you write easy, sequential code. Fibers are like mini-threads that every have their very own mini name stack. Whereas not strictly a gem for AI, it has helped us create options like net scrapers that run blazingly quick throughout hundreds of pages. We now have additionally used it to deal with streaming of chunks from LLMs.
Torch.rb (link) — If you’re serious about coaching deep studying fashions, then absolutely you have got heard of PyTorch. Nicely, PyTorch is constructed on LibTorch, which basically has quite a lot of C/C++ code beneath the hood to carry out ML operations rapidly. Andrew Kane took LibTorch and made a Ruby adapter over it to create Torch.rb, basically a Ruby model of PyTorch. Andrew Kane has been a hero within the Ruby AI world, authoring dozens of ML gems for Ruby.
Abstract
In brief: constructing an online utility with AI integration rapidly and cheaply requires a monolithic structure. A monolith calls for a monolingual utility, which is critical in case your finish purpose is high quality apps delivered with pace. Your important choices are both Python or Ruby. If you happen to go together with Python, you’ll in all probability use Django on your net framework. If you happen to go together with Ruby, you may be utilizing Ruby on Rails. At our company, we discovered Django’s lack of options disappointing. Rails has impressed us with its characteristic set and emphasis on simplicity. We had been thrilled to seek out virtually no points on the AI facet.
In fact, there are occasions the place you’ll not wish to use Ruby. If you’re conducting analysis in AI or coaching machine studying fashions from scratch, then you’ll doubtless wish to follow Python. Analysis virtually by no means entails constructing Web Applications. At most you’ll construct a easy interface or dashboard in a pocket book, however nothing production-ready. You’ll doubtless need the newest PyTorch updates to make sure your coaching runs rapidly. You might even dive into low-level C/C++ programming to squeeze as a lot efficiency as you possibly can out of your {hardware}. Possibly you’ll even strive your hand at Mojo.
But when your purpose is to combine the newest LLMs — both open or closed supply — into net functions, then we imagine Ruby to be the far superior choice. Give it a shot yourselves!
Partially three of this sequence, I’ll dive right into a enjoyable experiment: simply how easy can we make an online utility with AI integration? Keep tuned.
🔥 If you happen to’d like a customized net utility with generative AI integration, go to losangelesaiapps.com