AIToday
Large Language ModelsAI Coding AssistantsOpen-Source AIHacker NewsPublished: Aug 14, 2026, 04:01 JST7 min read

Agent tooling expands beyond Python to Clojure, Elixir

Agent tooling expands beyond Python to Clojure, Elixir

Key takeaway

  • An exploration of building LLM agents in Python, Clojure, and Elixir reveals that while Python dominates the AI ecosystem with frameworks like LangChain and AutoGen, Clojure and Elixir offer distinct production advantages.

  • Clojure's immutable data structures enable deterministic testing and state replay without mocking libraries, while Elixir's lightweight processes and built-in supervision trees (inherited from Erlang/OTP) handle parallel processing, fault recovery, and distributed deployment without external infrastructure—allowing organizations already using JVM or Erlang runtimes to build agents without switching languages.

3 Key Points

  1. What happened

    A functional programming team built LLM agent systems in Clojure and Elixir, comparing them directly with Python implementations to show how each language handles the core agent loop (where an LLM examines available tools, decides whether to call them, and feeds results back into the conversation).

  2. Why it matters

    Most agent frameworks (LangChain, AutoGen, CrewAI, LangGraph) are Python-first, forcing organizations running JVM or Erlang/OTP infrastructure to choose between moving agents to Python or building them in their existing runtime. This work demonstrates concrete trade-offs: Python offers the largest AI ecosystem and ready frameworks; Clojure provides immutable state that can be diffed and replayed for testing; Elixir's Actor Model (lightweight processes with supervision) handles fault tolerance and distribution natively, features Python requires external tools like Kubernetes or Celery to achieve.

  3. What to watch

    The comparison shows that Elixir's process-based model maps directly to agent workflows—prompt chaining becomes message-passing between processes, routing becomes a classifier process dispatching to specialized agents, and orchestration becomes spawning and managing worker processes. For teams already operating Erlang/OTP systems, the functional approach eliminates boilerplate versus Python frameworks and simplifies concurrent agent deployment.

In Depth

Read the full story

Most LLM agent frameworks—LangChain, AutoGen, CrewAI, and LangGraph—target Python first. While Python is the second-most-popular programming language and works well for teams already using it, organizations operating JVM infrastructure or Erlang/OTP systems have had to choose between adopting Python or building agents in their existing runtime. A team of functional programming advocates set out to build agents in Clojure and Elixir to compare how each handles production agent requirements.

An LLM agent combines a language model with the ability to call functions. The core loop, called ReAct (Reasoning and Acting), works as follows: the LLM examines the conversation and available tools, decides whether to call a tool or respond, and if it calls a tool, the result gets fed back into the conversation. This loop continues until the agent produces a final answer or hits a step limit. Anthropic distinguishes workflows (LLMs orchestrated through predefined code paths) from agents (LLMs that dynamically direct their own processes), though both follow the same basic loop structure.

In Python, developers can use ready-made frameworks like LangChain, where tools are `Tool` class instances and state and trace are accessed through framework APIs. Alternatively, developers can write agents from scratch: tools are dictionaries, state is a dictionary, and the control flow is visible. The trade-off is that Python's mutable data structures mean that a tool function can modify state through a reference without that modification showing up in the trace—a property to manage rather than a language flaw.

Clojure represents agents as data transformations on immutable maps. Tool definitions use Malli, which defines schemas as data structures rather than classes or decorators, making schemas programmable, serializable, and transformable—useful when converting to the JSON format that LLM APIs expect. Each agent iteration takes a state and returns a new state without modifying the original. This allows developers to diff two states to see what a specific iteration changed, serialize the full state to EDN (Extensible Data Notation), save it, and replay execution later. During development, the REPL lets developers call individual agent steps with a captured state and step through execution manually. Testing is straightforward: you call a function and assert on the returned map, with a stub LLM making behavior deterministic—no mocking libraries are needed because there are no framework internals to mock.

Elixir models each agent as a process using the Actor Model. Processes are lightweight (kilobytes of memory), communicate through message passing, and are supervised for fault recovery. An agent is implemented as a GenServer—Elixir's generic server process—with tools stored as function references and state as an isolated map. The message-passing model maps directly to standard agent workflow patterns: prompt chaining is processes passing messages forward, routing is a classifier process dispatching to specialized agent processes, and orchestration is an orchestrator process spawning and managing worker processes. Multiple agent processes run concurrently by default because that's Elixir's core offering. If one agent process crashes due to bad LLM output, an API timeout, or a malformed tool result, a supervisor restarts it; the other agent processes are unaffected. This supervision tree approach has been standard in Erlang/OTP systems since the 1980s.

For parallel processing, Python uses `asyncio`, threading, or multiprocessing, though the GIL limits CPU-bound parallelism. Clojure has concurrency primitives (atoms, refs, agents, core.async) and runs on JVM threads. Elixir runs lightweight processes on the BEAM VM with preemptive scheduling—a single machine can run millions of processes distributed across all CPU cores with no special setup.

In state management, Python state is mutable by default and traceability depends on logging discipline. Clojure state is immutable, allowing states to be diffed, serialized, stored, and replayed. Elixir processes have isolated state that other processes cannot directly access, preventing accidental corruption across agents.

For fault tolerance, Python provides try/except and manual retry logic. Clojure inherits JVM exception handling but lacks native supervision. Elixir has supervision trees as a core runtime feature. For distribution, Python requires external infrastructure like Kubernetes, Celery, or Ray. Clojure can use JVM clustering solutions. Elixir inherits Erlang's clustering—message passing between processes works identically whether they are on the same machine or different machines, allowing code developed on one machine to scale to a cluster without changes.

Python has the largest AI ecosystem: every major LLM provider ships a Python SDK, and agent frameworks, embedding libraries, vector store integrations, and evaluation tools are all Python-first. Clojure has a smaller ecosystem for AI-specific libraries; developers must often write wrapper code. Elixir has an emerging AI ecosystem—Nx for numerical computing, Bumblebee for model inference, Instructor for structured outputs—but integrations are less comprehensive than Python's.

Context & Analysis

The article addresses a practical gap in the agentic AI ecosystem: most tooling assumes Python, but many production organizations run on the JVM (Clojure) or Erlang/OTP (Elixir). The comparison is grounded in a real constraint—whether to adopt Python or build agents in the infrastructure already in place—rather than a theoretical exploration.

Python's advantage is well-established: the largest AI ecosystem, ready-to-use frameworks (LangChain, AutoGen, CrewAI, LangGraph), and first-party SDKs from every major LLM provider. However, Python's mutable data structures and reliance on external tools (Kubernetes, Celery, Ray) for distribution and fault tolerance come with operational costs that matter at scale.

Clojure's functional model eliminates a class of bugs entirely: because state is immutable, tool functions cannot corrupt state through hidden references, and the REPL allows developers to inspect and replay any intermediate state during development. Testing requires no mocking libraries because there are no framework internals to mock. The trade-off is a smaller AI-specific ecosystem; integrations must often be written by hand.

Elixir's inheritance of Erlang/OTP patterns (supervision trees, clustering, preemptive scheduling of lightweight processes) means that production requirements that Python must solve with external infrastructure are solved in the runtime itself. A single machine can run millions of concurrent agents by default, and distribution across machines requires no code changes. This is particularly valuable for teams already operating Erlang/OTP systems, where the agentic model maps directly to existing patterns (orchestrator processes, supervisor trees, message-passing).

FAQ

What is an LLM agent?
An LLM agent combines a language model with the ability to call functions. The core loop, known as ReAct (Reasoning and Acting), works like this: the LLM examines the conversation and available tools, decides whether to call a tool or respond, and if it calls a tool, the result gets fed back into the conversation. The loop continues until the agent produces a final answer or hits a step limit.
Why does it matter that most agent frameworks are Python-first?
Organizations running JVM infrastructure or Erlang/OTP systems face the choice of either moving agents to Python or building them in the runtime they already operate. Python's largest AI ecosystem (every major LLM provider ships a Python SDK) makes it convenient for some teams, but other teams can avoid the operational cost of adopting Python by building agents in their existing runtime, where Clojure and Elixir offer different production strengths.
What are the key differences in how Clojure and Elixir handle agent state?
Clojure represents agents as data transformations on immutable maps: each agent iteration produces a new state without modifying the previous one, allowing states to be diffed, serialized, stored, and replayed. Elixir models each agent as a lightweight process using the Actor Model, where each process maintains isolated state that other processes cannot directly access, preventing accidental state corruption across agents and allowing the BEAM VM to run millions of processes with preemptive scheduling.

Get the latest Large Language Models news every morning

AI-summarized, only the topics you pick — one digest a day via Email, Slack, or Discord.

Free · takes 30 seconds · unsubscribe anytime

Ask AI

Ask AI anything about this article. Q&As are published on this page for other readers too.

Related Articles

Next articleOpenAI replaces revenue chief after 9 months, hires Wiz COO Rajic

The AI news that matters, in one minute each morning.

Sign up free