🧠🤖 DeepAgents for Ruby
Using an LLM to call tools in a loop is the simplest form of an agent. This architecture, however, can yield agents that are "shallow" and fail to plan and act over longer, more complex tasks. Applications like "Deep Research", "Manus", and "Claude Code" have gotten around this limitation by implementing a combination of four things: a planning tool, sub agents, access to a file system, and a detailed prompt.
deepagents
is a Ruby gem that implements these in a general purpose way so that you can easily create a Deep Agent for your application.
Acknowledgements: This project was inspired by the Python deepagents library and is a Ruby implementation of its functionality.
Installation
Add this line to your application's Gemfile:
gem 'deepagents'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install deepagents
Usage
Basic Usage
require 'deepagents'
require 'anthropic'
# Initialize the Anthropic client
anthropic_client = Anthropic::Client.new(api_key: ENV['ANTHROPIC_API_KEY'])
# Define a search tool
def internet_search(query, max_results: 5, topic: 'general', include_raw_content: false)
# In a real implementation, this would call a search API
# For example, you could use a Ruby wrapper for Tavily or another search API
"Search results for: #{query}"
end
# Create a tool object
search_tool = DeepAgents::Tool.new(
"internet_search",
"Run a web search"
) do |query, max_results: 5, topic: 'general', include_raw_content: false|
internet_search(query, max_results: max_results, topic: topic, include_raw_content: include_raw_content)
end
# Prompt prefix to steer the agent to be an expert researcher
research_instructions = <<~INSTRUCTIONS
You are an expert researcher. Your job is to conduct thorough research, and then write a polished report.
You have access to a few tools.
## `internet_search`
Use this to run an internet search for a given query. You can specify the number of results, the topic, and whether raw content should be included.
INSTRUCTIONS
# Create the agent using built-in model adapters
agent = DeepAgents.create_deep_agent(
[search_tool],
research_instructions,
model: DeepAgents.claude_model() # or DeepAgents.openai_model()
)
# Invoke the agent
result = agent.invoke({
messages: [{role: "user", content: "what is Ruby on Rails?"}]
})
# Access the agent's response
puts result.messages.last[:content]
Using with langchainrb and langgraph_rb
require 'deepagents'
require 'langchainrb'
require 'langgraph_rb'
# Create a search tool using langchainrb's tool system
search_tool = Langchain::Tool.new(
name: "internet_search",
description: "Run a web search",
function: ->(query:, max_results: 5) {
# In a real implementation, this would call a search API
"Search results for: #{query}"
}
)
# Convert to DeepAgents tool
deep_search_tool = DeepAgents::Tool.from_langchain(search_tool)
# Create a deep agent with langchainrb integration
agent = DeepAgents.create_deep_agent(
[deep_search_tool],
"You are an expert researcher. Your job is to conduct thorough research.",
model: "claude-3-sonnet-20240229" # Will automatically create appropriate model adapter
)
# Run the agent
result = agent.run("What is Ruby on Rails?")
puts result
Creating a custom deep agent
There are three parameters you can pass to create_deep_agent
to create your own custom deep agent.
tools
(Required)
The first argument to create_deep_agent
is tools
.
This should be an array of tool objects created using DeepAgents::Tool.new
.
The agent (and any subagents) will have access to these tools.
instructions
(Required)
The second argument to create_deep_agent
is instructions
.
This will serve as part of the prompt of the deep agent.
Note that there is a built-in system prompt as well, so this is not the entire prompt the agent will see.
model
(Optional)
By default, deepagents
uses a simple placeholder model. You should provide your own model implementation that interfaces with an LLM API like Anthropic's Claude or OpenAI.
Your model class should implement a generate
method that takes a prompt and messages array and returns a response string.
subagents
(Optional)
A keyword parameter to create_deep_agent
is subagents
.
This can be used to specify any custom subagents this deep agent will have access to.
subagents
should be an array of DeepAgents::SubAgent
objects, where each has:
- name: The name of the subagent, and how the main agent will call the subagent
- description: The description of the subagent that is shown to the main agent
- prompt: The prompt used for the subagent
- tools: The list of tools that the subagent has access to (optional)
To use it looks like:
research_sub_agent = DeepAgents::SubAgent.new(
name: "research-agent",
description: "Used to research more in depth questions",
prompt: sub_research_prompt
)
agent = DeepAgents.create_deep_agent(
tools,
prompt,
subagents: [research_sub_agent]
)
Integration with langchainrb and langgraph_rb
DeepAgents now integrates with the popular Ruby gems langchainrb
and langgraph_rb
to provide enhanced functionality and compatibility with the broader LLM ecosystem.
langchainrb Integration
The langchainrb
integration provides:
-
Model Compatibility: All DeepAgents model adapters can be converted to langchainrb models using the
to_langchain_model
method - Tool Interoperability: Convert between DeepAgents tools and langchainrb tools
- Vector Database Access: Leverage langchainrb's vector database integrations for RAG applications
- Prompt Management: Use langchainrb's prompt templates with DeepAgents
langgraph_rb Integration
The langgraph_rb
integration enables:
- Stateful Agents: Build agents that maintain state across interactions
- Directed Graphs: Create complex agent workflows with directed graph structures
- Multi-Actor Systems: Coordinate multiple agents working together
- Checkpointing: Save and restore agent state
Deep Agent Details
The below components are built into deepagents
and help make it work for deep tasks off-the-shelf.
Planning Tool
deepagents
comes with a built-in planning tool. This planning tool is very simple and is based on ClaudeCode's TodoWrite tool.
This tool doesn't actually do anything - it is just a way for the agent to come up with a plan, and then have that in the context to help keep it on track.
File System Tools
deepagents
comes with four built-in file system tools: ls
, edit_file
, read_file
, write_file
.
These do not actually use a file system - rather, they mock out a file system using the agent's state object.
Right now the "file system" will only be one level deep (no sub directories).
These files can be passed in (and also retrieved) by using the files
key in the agent's state.
agent = DeepAgents.create_deep_agent(...)
result = agent.invoke({
messages: [...],
# Pass in files to the agent using this key
# files: {"foo.txt" => "foo", ...}
})
# Access any files afterwards like this
result.files
Sub Agents
deepagents
comes with the built-in ability to call sub agents.
It has access to a general-purpose
subagent at all times - this is a subagent with the same instructions as the main agent and all the tools that it has access to.
You can also specify custom sub agents with their own instructions and tools.
Sub agents are useful for "context quarantine" (to help not pollute the overall context of the main agent) as well as custom instructions.
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.