From the article: """ Agents typically have a number of shared characteristics when they start to scale (read: have actual users):
They are long-running — anywhere from seconds to minutes to hours.
Each execution is expensive — not just the LLM calls, but the nature of the agent is to replace something that would typically require a human operator. Development environments, browser infrastructure, large document processing — these all cost $$$.
They often involve input from a user (or another agent!) at some point in their execution cycle.
They spend a lot of time awaiting i/o or a human.
"""No. 1 doesn't really point to one language over another, and all the rest show that execution speed and server-side efficiency is not very relevant. People ask agents a question and do something else while the agent works. If the agent takes a couple seconds longer because you've written it in Python, I doubt that anyone would care (in the majority of cases at least).
I'd argue Python is a better fit for agents, mostly because of the mountain of AI-related libraries and support that it has.
> Contrast this with Python: library developers need to think about asyncio, multithreading, multiprocessing, eventlet, gevent, and some other patterns...
Agents aren't that hard to make work, and you can get most of the use (and paying users) without optimizing every last thing. And besides, the mountain of support you have for whatever workflow you're building means that someone has probably already tried building at least part of what you're working on, so you don't have to go in blind.
(I think you can effectively write an agent in any language and I think Javascript is probably the most popular choice. Now, generating code, regardless of whether it's an agent or a CLI tool or a server --- there, I think Go and LLM have a particularly nice chemistry.)
You can safely swap out agents without redeploying the application, the concurrency is way below the scale BEAM was built for, and creating stateful or ephemeral agents is incredibly easy.
My plan is to set up a base agent in Python, Typescript, and Rust using MCP servers to allow users to write more complex agents in their preferred programming language too.
[0]: https://github.com/extism/extism [1]: https://github.com/extism/elixir-sdk
In my experience the performance of the language runtime rarely matters.
If there ever was a language feature that matters for agent performance and scale, it's actually the performance of JSON serialization and deserialization.
I've found that TypeScript is an excellent glue language for all kinds of AI. Python, followed by TS enjoy broad library support from vendors. I personally prefer it over Python because the type system is much more expressive and mature. Python is rapidly improving though.
> It turns out, cancelling long-running work in Node.js and Python is incredibly difficult for multiple reasons:
Evidence is lacking for this claim. Almost all tools out there support cancellations, and they're mostly either Python or JS.
These platforms store an event history of the functions which have run as part of the same workflow, and automatically replay those when your function gets interrupted.
I imagine synchronizing memory contents at the language level would be much more overhead than synchronizing at the output level.
The death knell for variety in AI languages was when Google rug-pulled TensorFlow for Swift.
Beneath all the jargon, it’s good to remember that an “agent” is ultimately just a bunch of http requests and streams that need to be coordinated—some serially and some concurrently. And while that sounds pretty simple at a high level, there are many subtle details to pay attention to if you want to make this kind of system robust and scalable. Timeouts, retries, cancellation, error handling, thread pools, thread safety, and so on.
This stuff is Go’s bread and butter. It’s exactly what it was designed for. It’s not going to get you an MVP quite as fast as node or python, but as the codebase grows and edge cases accumulate, the advantages of Go become more and more noticeable.
But outside of that - ML in go is basically impossible. Trying to integrate with the outside ecosystem of go is really difficult - and my experience has been that Claude Code is far less effective with Go then it is with Python, or even Swift.
I ditched a project I was writing in Go and replaced it with Swift (this was mostly prompt based anyways). It was remarkably how much better the first pass of the code generation was.
Frankly, anything that has a compiler and supports doing asynchronous stuff decently probably does the job. Which of course describes a wide range of languages. And since agents inherently involve a lot (some would say mostly) prompt engineering, it helps if the language is good at things like multi line strings, templated strings, and just generally manipulating strings.
As for the async stuff, it's nice if a language can do async things. But is that enough? Agentic systems essentially reach out to other systems over the network. Some of the tasks may be long lived. Minutes, hours, or even days. A lot can happen in such long time. IMHO the model of some system keeping all that state in a long running process is probably not ideal. We might want something more robust and long running and less dependent on a some stateful process running somewhere for days on end.
There is an argument to be made for externalizing related state from the language and maybe using some middleware optimized for this sort of thing. I've seen a few things that go in that direction but not a lot yet. It seems that people are still busy reinventing wheels and not fully realizing yet that a lot of those wheels don't need reinventing. There's a lot of middleware out there that is really great at async job scheduling, processing, fan out, and all the other stuff that people eventually will figure out is needed here.
1. If you make your agents/workflows serializable you can run/load them from a config file or add/remove them from a decoupled frontend. You can also hash them to make versioning easy to track/immutable.
2. If you decouple the stateful object from the agent/workflow object you can just store that through sufficient logging then you can rebuild any flow at any state and have branching by allowing traces to build on one another. You can also restart/rerun a flow starting at any location.
3. You can allow for serializable tools by having a standard HttpRequestTool then setup cloudflare workers/any external endpoints for the actual toolcall logic. Removing primary server load and making it possible to add/remove tools without rebuilding/restarting.
Given this system in golang you can have a single server which supports tens of thousands of concurrent agent workflows.
The biggest problem is there isn't that many people who are working on it. So even if you can make agents 100x more efficient by running in Go it doesn't really matter if cost isn't the biggest factor for the final implementations.
The actual compute/server/running costs for big AI Agent implementation contracts is <1%, so making it 100x more efficient doesn't really matter.
Along these lines, I'm building Dive:
https://github.com/diveagents/dive
When building a SaaS with a Go backend, it's nice to be able to have the option of the agents and workflows being in the same process. And being confident in the ability of that to scale well.
While it's true that Go lacks good ML libraries, for some this isn't too consequential if your app is primarily using Anthropic or OpenAI and a database that offers semantic or hybrid search for RAG. The ML is done elsewhere. Plus it could be that you can leverage MCP servers and at that point you're language agnostic.
Regarding the concurrency model approach with Go and agents, I initially baked a message based approach (a la the Actor model, with one goroutine per agent) into Dive Agents, but eventually found that this would be better implemented as another layer. So currently in Dive it's the user's choice on how to implement concurrency and whether to use messaging. But I anticipate building that back in as an optional layer.
Some of the things are just more natural in python being a dynamic language. Eg decorator to quickly convert methods into tool calls, iterating over tool functions to create list of tools, packages to quickly convert them into json schema etc.
Consuming many incoming triggers, eg from user input as well as incoming emails from gmail, or messages from slack which would trigger new agent run was lot more natural in go with channels and switch for loop vs in python where had to create many queues and threading etc
> Share memory by communicating
> Centralized cancellation mechanism with context.Context
> Expansive standard library
> Profiling
> Bonus: LLMs are good at writing Go code
I think profiling is probably the lowest value good here, but would be willing to hear out stories of AI middleware applications that found value in that.
Cancelling tasks is probably the highest value good here, but I think the contending runtimes (TS/Python) all prefer using 3P libraries to handle this kind of stuff, so probably not the biggest deal.
Being able to write good Go code is pretty cool though; I don't write enough to make a judgement there.
The language of agents doesn't matter much in the long run as it's just a thin shell of tool definitions and API calls to the backing LLM.
You need a DSL either supported in the language or through configuration. These are features you get for free in python and secondly JavaScript. You have to write most of this yourself in go
So every discussion about the "best" programming language is really you telling the world about your favorite language.
Use Go. Use Python. Use JavaScript. Use whatever the hell else you want. They are all good enough for the job. If you are held back it won't be because of the language itself.
The issue with Go, is as soon as you need to do actual machine learning it falls down.
The issue with Python is that you often want concurrency in agents. Although this may be solved with Pythons new threading.
Why is Rust great? It interops very well with Python, so you can write any concurrent pieces into that and simply import it into py, without needing to sacrifice any ML work.
I'll be honest Go is a bit of an odd fit in the world of AI, and if thats the future I'm not sure Go has a big part to play outside of some infra stuff.
by that logic Elixir is even better for agents.
also the link at the bottom of the page is pretty much why I ditched Go: https://go.dev/blog/error-syntax
The AI landscape moves so fast, and this conservative, backwards looking mindset of the new Go dev team doesn't match the forward looking LLM engineering mindset.
pretty please :P
we all yearn for a good static language, and most of us would kill for "something like Rust (good type system, syntax, tools) but without ownership / linear-typing - just a good GC, all-on-the-heap and a dash of nice immutable datastructs"...