mikehostetler

mikehostetler

ReqLLM - Composable LLM client built on Req

Hey everyone!

I’m excited to share ReqLLM - a new approach to LLM interactions in Elixir that I’ve been working on. After building agent systems with various LLM clients, I kept running into the same frustrations: they either lacked Elixir’s composability principles or didn’t integrate well with existing HTTP pipelines.

Why Another LLM Client?

While building out Jido features, I needed a lower-level API for making LLM requests. ReqLLM is built on Req, with each Provider built as a Req plugin that handles provider-specific wire formats. It’s designed to compose naturally with your existing Req-based applications.

Core Architecture

Plugin-Based Providers: Each LLM provider (Anthropic, OpenAI, Google, etc.) is a composable Req plugin.

Typed Data Structures: Every interaction uses proper structs (Context, Message, StreamChunk, Tool, ContentPart) that implement Jason.Encoder - no more wrestling with nested maps.

Two Client Layers: High-level helpers for quick wins (generate_text/3, stream_text/3, generate_object/4, etc) plus low-level Req plugin access when you need full control.

Built-in Observability: Usage and cost tracking on every response based on metadata sync’d from https://models.dev

Quick Example

# Simple approach
ReqLLM.put_key(:anthropic_api_key, "sk-ant-...")
{:ok, text} = ReqLLM.generate_text!("anthropic:claude-3-sonnet", "Hello")

# Tool calling with structured responses
weather_tool = ReqLLM.tool(
  name: "get_weather", 
  description: "Get weather for a location",
  parameter_schema: [location: [type: :string, required: true]],
  callback: fn args -> {:ok, "Sunny, 72°F"} end
)

{:ok, response} = ReqLLM.generate_text(
  "anthropic:claude-3-sonnet", 
  "What's the weather in Paris?",
  tools: [weather_tool]
)

Current Status

ReqLLM 1.0-rc is available on Hex with 45+ providers and 665+ models (auto-synced from models.dev). I’m using it in production for Jido agent systems and it’s been solid. Planning to add Ollama/LocalAI support and enhanced streaming soon.

Resources

I’d love to hear your thoughts and see what you build with it! The plugin architecture makes it pretty straightforward to add new providers if there’s one you need.

Most Liked

mikehostetler

mikehostetler

ReqLLM 1.0.0-rc.7 Released

I’ve published the 1.0.0-rc.7 release of ReqLLM with Elixir 1.19 support on Hex.

It’s been a journey to build this package. LLM Providers are all over the place - but with this release, I’ve been able to successfully prove that the high level API now supports 136 models via a custom fixture testing system I developed.

Several companies and projects have already begun integrating and battle testing this package. With this release, I’m now focused on getting to a stable 1.0 release.

What’s New

Test Coverage: 136 models validated across 10 providers with fixture-based testing against 10 scenarios:

  • Core: basic generation, streaming, token limits, usage metrics
  • Capabilities: multi-tool calling, tool round-trip, tool avoidance, object generation (streaming/non-streaming), reasoning tokens

Providers: Added Amazon Bedrock (streaming, multi-model, AWS SigV4 auth) and Z.AI (GLM-4.5/4.6, 204K context).

Architecture: Simplified tool call handling with ReqLLM.ToolCall helpers, provider normalize_model_id/1 callback, improved Context API with append/2 and prepend/2.

Examples: Full agent implementation and 16+ runnable scripts covering embeddings, multimodal analysis, tool calling, object generation, reasoning tokens, context reuse.

Validation: Run mix mc to see coverage status. Use REQ_LLM_FIXTURES_MODE=record to test against live APIs.

Links

josevalim

josevalim

Creator of Elixir

This is fantastic! Elixir does come with many of the building blocks for rolling your own agentic system but the “talking to different LLMs” is definitely one of the more time consuming bits. I also like that you have a purely data driven API for defining tools.

My only request would be to make the bit where providers automatically fetch keys optional (either opt-in or opt-out), as turning that on/off would be important for folks writing services where you BYOK (like Tidewave).

Also have you implemented the APIs for dealing with reasoning tokens? OpenAI, Anthropic, OpenRouter, etc all have different APIs for them, which is also annoying to deal with.

PS: You forgot to make Credo a dev-only dependency. :slight_smile:

mikehostetler

mikehostetler

Thanks!

jido_ai will be moving to use ReqLLM very shortly - and we will be dropping support for Langchain and Instructor.

API’s will be maintained - so you should be good to start and not worry too much about things changing.

LLM API’s are pretty dynamic, so I can’t promise 100% - but we’re doing our best to build a solid foundation for the Elixir community.

mikehostetler

mikehostetler

PS: You forgot to make Credo a dev-only dependency.

Thanks for the catch! So tough to pull the trigger on a release :slight_smile:

My only request would be to make the bit where providers automatically fetch keys optional (either opt-in or opt-out), as turning that on/off would be important for folks writing services where you BYOK (like Tidewave).

Absolutely, I had similar ideas - implemented it twice - didn’t feel right yet. Agree this is necessary.

Also have you implemented the APIs for dealing with reasoning tokens?

Yes, this is currently unreleased - I hit another weird snag and pulled back - but it will be there by the formal 1.0.

mikehostetler

mikehostetler

Great question - and I agree - I’ll make a PR

This is only due to my eyes glazing over after sprinting on this for a week!!!

Where Next?

Popular in Announcing Top

zachdaniel
Hey folks! AshEvents Release We’ve just released the first version of AshEvents, an Event Sourcing tool for Ash Framework apps. Check o...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
isaias-dias-machado
IEx’s h macro is great but it lacks a pager, so I built a small tool that caches documentation and lets you fuzzy search through it in yo...
New
rodloboz
I’ve started working on a new library to run SQL queries and do basic business intelligence. Think “Blazer for Elixir.” Currently it fe...
New
Schultzer
Hey there, I wrote this low-level library recently, its goal is simply to lower the barrier between Elixir and SQL, and it does that by p...
New
zachdaniel
:smiling_face_with_sunglasses: New package usage_rules released! Just place a usage-rules.md file in your package and users can sync it t...
#ai
New
bradley
I’ve been working with Claude Code extensively and absolutely love it. However, I’ve come across the challenge of managing configuration ...
New
murrgelb
Efx is a library to define and test side effects declaratively. It is basically a very focused mocking framework, reducing implementation...
New
sevensidedmarble
Announcing Live Toast: a replacement toast/flash component for Phoenix LiveView, heavily inspired by the look of Sonner (the amazing toas...
New
sodapopcan
I’ve heard that if you’re not embarrassed by v1 of your product Vim plugin then you’ve released too late. I’ve been sitting on this the ...
New

Other popular topics Top

chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement