---
title: "Doubling Down on Agents"
linkTitle: "Doubling Down on Agents"
date: 2026-06-10
description: "Go Micro made services easy by being opinionated, batteries-included, and pluggable. We're applying the same model to agents — a model, memory, and tools that compose like a service does."
category:
- opinion
tags:
- AI
- agents
aliases:
  - /blog/20
---
Go Micro made microservices easy by having an opinion. You called `micro.New`, and it composed the pieces a service needs — service discovery, RPC, pub/sub, config, storage — behind one interface, with defaults that worked out of the box. You could test an endpoint in minutes, and when you needed to, you swapped any piece: mDNS for etcd, HTTP for gRPC, in-memory for Postgres. Opinionated, batteries-included, and pluggable. That combination is why people used it.

Agents need the same thing, and right now most of them don't have it.

## What an agent is made of

Strip an agent down and it composes a small set of pieces, the same way a service does:

- a **model** that reasons,
- **memory** so it carries context across turns,
- **tools** it can call to act,
- and **guardrails** so it stops where you want it to.

Today most agent code wires these together by hand, per project, with whatever libraries happen to be nearby. That's where microservices were before frameworks: every team re-solving discovery, load balancing, and retries in their own way. The work isn't building the model — the model is a given. The work is everything around it.

So we're doing for agents what Go Micro did for services: compose those pieces, with defaults, behind one interface, and keep every piece swappable.

```go
agent := micro.NewAgent("assistant",
    micro.AgentProvider("anthropic"),            // model
    micro.AgentMemory(micro.NewInMemory(50)),    // memory — default is store-backed and durable
    micro.AgentTool("weather", "Get the weather",
        map[string]any{"city": map[string]any{"type": "string"}},
        func(ctx context.Context, in map[string]any) (string, error) {
            return getWeather(in["city"].(string))
        }),
    micro.AgentMaxSteps(8),                       // guardrails
)
```

Nothing here is required. `micro.NewAgent("assistant")` gives you a working agent with a default model, durable store-backed memory, your services as tools, and the built-in `plan` and `delegate` tools. The options are there for when you outgrow the defaults — which is exactly how the service side has always worked.

## The pieces we just made pluggable

Two of these were hardcoded until now, and both are the kind of thing the framework should own:

**Memory.** An agent's conversation is now behind a `Memory` interface. The default is store-backed, so memory is durable across restarts on whatever store you already use — file, Postgres, NATS KV — the same pluggable `store` that backs your services. Supply your own implementation when you want in-process, a database, or a semantic store. Memory is to an agent what the store is to a service: a first-class, swappable dependency, not something you bolt on.

**Tools beyond services.** An agent's tools were its registered services, reached over RPC. That's powerful, and it stays the default — but an agent often needs a plain function, a local computation, an external API. `AgentTool` registers any function as a tool the model can call, alongside the services it discovers. Agents are no longer limited to orchestrating RPC.

These join what's already there: the `plan` and `delegate` built-in tools, and the `MaxSteps` and `ApproveTool` guardrails. The model, memory, tools, and guardrails now compose the way registry, broker, and store compose for a service.

## Microagents

People are going to build large, monolithic agents — one brain with a hundred tools, holding everything in one context. It will work for a while, and then it will hit the same wall the monolith hit: one unit that knows a little about everything and can't hold the full context of anything.

The answer is the same one microservices gave. If there's an agent for everything, those are microagents — each scoped to a domain, each small enough to reason well about its own services, each independently deployable and composable. We already have the mechanics: an agent is a service, agents reach each other over RPC, and `delegate` lets one hand work to another. Distributing the intelligence is the same move as distributing the services, and it's available now.

## Services, agents, workflows

That leaves three primitives, and they compose:

- a **service** is a capability — endpoints, data, business logic;
- an **agent** is intelligence pointed at capabilities — it reasons, remembers, and acts through tools;
- a **workflow** is a deterministic trigger — when an event happens, run a known path, or hand off to an agent.

All three are Go code, all three register, all three communicate over RPC, all three deploy the same way. You can build a system out of any combination of them. That's the point: these aren't three products, they're three primitives on one substrate, and together they're enough to build the foundation of most platforms you'd want to build.

## What's still missing

I'd rather be plain about the gaps than pretend they're filled. An agent framework that matches what the service framework offers still needs:

- **Knowledge / retrieval** — a pluggable way to ground an agent in a corpus, the way memory grounds it in its own history.
- **Streaming** — the model interface has it stubbed; agents want token streaming for real interfaces.
- **An explicit reasoning loop** — the loop is functional today but lives inside the providers; making it a first-class, inspectable piece (without turning it into a graph DSL) is the right next step.

These are the next pieces to make pluggable. The principle holds for each: a working default, behind an interface, swappable.

## The same foundation

I started Go Micro because building microservices in Go was harder than it should have been, and the fix was an opinionated framework that got out of your way. Building agents is harder than it should be for the same reasons, and the fix is the same. Services were the foundation for a generation of distributed systems. Agents — built on those same services, with the same opinionated and pluggable model — are the foundation for the next one.

This is the direction now. Services, agents, workflows, one substrate.
