
IN A NUTSHELL
-
Discover how to extend your AI’s capabilities beyond simple conversation by enabling it to interact with your application’s unique data and features.
-
Learn the foundational steps and code structure for crafting custom tools that empower your AI to perform specific, intelligent actions within your Rails app.
-
Gain crucial insights into securing your AI’s interactions, ensuring your custom tools operate safely and effectively in a production environment.
In my last post I showed you how to build a basic AI chat for a Rails app using the RubyLLM gem. While having a conversation with an AI can be useful, the real magic of AI comes when you let it interact with your application data. This is where the Tools in the RubyLLM gem come in.
Tools let an AI perform specific tasks using your application’s features and data. You can think of tools as special functions that the AI can call when it needs to do things like search your database, calculate prices, or create records.
How tools work in RubyLLM
The ToolCall model we created last time is the magic behind the scenes. We’ll go into detail of the setup shortly, but here’s how it all comes together:
-
First, you add a tool to your chat
-
When you send a message, RubyLLM packages the tool’s description and parameters into the payload it sends to the LLM
-
The LLM analyzes your message and decides if the tool would help it respond
-
If the tool is needed, the LLM requests to use it with the parameters that it determined would help
-
RubyLLM executes the tool with those parameters and feeds the result back to the LLM
-
Finally, the LLM incorporates the result in its response to you
Creating your first tool
First, we need to define a tool. To define a tool we simply extend the RubyLLM::Tool class and implement 3 key elements:
-
Description - Explains what the tool does so the LLM can decide if it needs to use it or not
-
Parameters - Defines and describes the inputs that the tool accepts so the LLM can use them as needed
-
execute method - the code that runs and returns the result the LLM is looking for
Now let’s create a simple tool that lets our AI search for users. I’ve chosen to put my tools in the services folder but you can put them wherever you like:
# app/services/tools/user_search.rb
module Tools
class UserSearch < RubyLLM::Tool
description "Search for users by email or name"
param :query, type: :string, desc: "The search term (email or name)"
def execute(query:)
users = User.where("email_address ILIKE ? OR name ILIKE ?", "%#{query}%", "%#{query}%")
if users.any?
users.map { |user| { id: user.id, email: user.email_address, name: user.name } }
else
"No users found matching '#{query}'"
end
rescue => e
{ error: e.message }
end
end
end
Next, we need to register this tool with our Chat. This is as simple as using the with_tool (or with_tools for multiple) on your chat instance. Note: Make sure your model supports function calling/tools. You can check with RubyLLM.models.find(‘your-model-id’).supports_functions?. So we only need to add one line to the background job we setup last time:
# app/jobs/generate_ai_response_job.rb
# ... existing code ...
chat = Chat.find(chat_id)
chat.with_tool(Tools::UserSearch) # Add this line
thinking = true
chat.ask(user_message) do |chunk|
# ... existing code ...
Done! Now you can ask your chat to find users in your app. Obviously, this is a very simple example which only retrieves data, you could implement a much more complex tool which can perform updates such as creating an order for a specific user.
Security considerations
Of course, there are several security aspects we need to consider before deploying our tools to production:
-
Access control: Make sure tools can only access data and perform updates that the current user is allowed to
-
Input validation: Always validate the params from the LLM as you would any user input. Never use methods like eval, system, send, or direct SQL interpolation with raw arguments from the AI
-
Rate limiting: Add limits to prevent abuse of your tools
-
Logging: Log all tool usage for auditing and debugging
You May Also Like:
Adding an AI chat to your Ruby on Rails application
Ps. if you have any questions
Ask here