Every AI agent is made of six primitives — model, tool, memory, loop, spec, and deploy. Learn them once and every new framework becomes a 30-minute exercise, not a month-long investment.

Read once, bookmark as a reference. Use the six primitives to triage any new agent framework you run into this year.
I've built agents on Vercel AI SDK, Claude Agent SDK, OpenAI Agents SDK, Google ADK, Oracle ADK, n8n, Notion AI, Dify, LangGraph, and three internal enterprise stacks at Oracle. The frameworks look different. They are not different.
Every production agent I've shipped is made of six primitives:
Learn these six, and the next framework you pick up is a 30-minute exercise — not a month-long investment. The syntax changes; the primitives don't. That's the whole argument of this post, and it's the curriculum spine of the Build Your First AI Agent workshop.
The model is the reasoning substrate. Claude Sonnet 4.6, GPT-5, Gemini 2.5 Pro, an open-weight Llama, a local Ollama — they are all candidates. What matters for your agent is how well the model follows tool-use protocols and how cleanly it produces structured output.
The naive view: "a model is where the AI lives." The architectural view: a model is a pluggable component behind an interface. In the Vercel AI SDK starter repo, that interface is five lines:
import { anthropic } from '@ai-sdk/anthropic'
import { openai } from '@ai-sdk/openai'
import { google } from '@ai-sdk/google'
export function getModel() {
const name = process.env.AGENT_PROVIDER ?? 'anthropic'
if (name === 'anthropic') return anthropic('claude-sonnet-4-6')
if (name === 'openai') return openai('gpt-5')
return google('gemini-2.5-pro')
}
That's the whole model primitive. One function. Swap providers with an env var. The rest of the agent doesn't know, doesn't care, doesn't need to.
The test: can you replace your model with a different provider in under 60 seconds without touching any other part of the agent? If yes, your model primitive is clean. If no, you have a leaky abstraction and your next framework migration will hurt.
A tool is a typed function the agent can call. That's it. The tool has:
web_search, calculate, fetch_user_profile)Here's a tool in Vercel AI SDK:
import { tool } from 'ai'
import { z } from 'zod'
export const webSearch = tool({
description: 'Search the web for up-to-date information.',
parameters: z.object({
query: z.string().min(3),
maxResults: z.number().int().min(1).max(5).default(3),
}),
execute: async ({ query, maxResults }) => {
const results = await searchApi(query, maxResults)
return { results }
},
})
Same tool in Claude Agent SDK, OpenAI Agents, or Google ADK has different ceremony but the same four parts. The parameter schema is the contract — if you define your tools with zod or JSON Schema, you can port them across frameworks with a 5-line adapter.
The test: can you describe your tool in four fields — name, description, params, execute — without referencing the framework that hosts it? If yes, clean. If no, your tool has bled into the loop primitive and you'll have trouble reusing it.
"Memory" is three different things wearing the same word.
runAgent invocation.Beginners conflate them and end up with a chat history so long every token is burned on remembering what the user had for breakfast. Production agents have clear boundaries: session memory for context, long-term memory for facts the user has explicitly asked to persist, working memory for mid-task state.
In the workshop starter:
// Session memory — in-process Map, swap for Vercel KV in production
const conversations = new Map<string, CoreMessage[]>()
export function getHistory(sessionId: string): CoreMessage[] {
return conversations.get(sessionId) ?? []
}
That's session memory, done. Working memory is the stack inside runAgent. Long-term memory doesn't exist in the starter because a 90-minute workshop agent doesn't need it — but when you add it, it gets its own primitive with its own interface. Don't overload session memory with long-term facts.
The test: can you pin down, for any given piece of state, which of the three memory types it lives in? If yes, your memory primitive is architected. If no, you have a bug waiting to happen.
The loop is the orchestrator. Its job is one sentence: keep the model and the tools talking until the agent has an answer or gives up.
In the crudest form, a loop is a while that runs until the model stops calling tools:
let messages = [{ role: 'user', content: question }]
while (true) {
const response = await model.generate(messages, tools)
messages.push({ role: 'assistant', content: response })
if (response.finishReason === 'stop') return response
if (response.toolCalls) {
for (const call of response.toolCalls) {
const result = await tools[call.name].execute(call.args)
messages.push({ role: 'tool', content: result })
}
}
if (messages.length > 50) throw new Error('loop overrun')
}
Most agent frameworks wrap this loop so you don't write the while yourself. But most agent bugs are loop bugs — loops that never terminate, loops that swallow errors, loops that re-call the same tool ten times in a row. Understanding the loop is how you debug agents.
In Vercel AI SDK, generateObject gives you a structured-output loop in one function:
const result = await generateObject({
model,
system: SYSTEM_PROMPT,
messages,
schema: ResearchSchema,
tools: { web_search: webSearch },
maxSteps: 5, // ← loop termination guard
})
maxSteps: 5 is the guard. Without it, a misbehaving model + a misbehaving tool could loop forever and burn your API budget before you notice.
The test: can you state, in one sentence, what makes your loop stop? ("Either the model returns a final answer, or we hit 5 steps, or a tool returns an unrecoverable error.") If yes, you own your loop. If no, you will debug a runaway loop in production.
The spec is the contract. Who is this agent? What can it do? How do other agents or clients talk to it?
Two specs worth knowing:
The Google Agent-to-Agent (A2A) protocol defines an "Agent Card" — a JSON document describing identity, capabilities, and skills. It's served at /.well-known/agent.json on your agent's domain. Any A2A-compatible client can discover your agent and know what to do with it.
Here's the Agent Card from the workshop starter:
{
"name": "First Agent — Research Assistant",
"description": "A minimal research-assistant agent...",
"url": "https://first-agent-vercel-aisdk.vercel.app",
"provider": { "name": "Frank Riemer", "url": "https://frankx.ai" },
"version": "0.1.0",
"capabilities": { "streaming": false },
"skills": [
{
"id": "research-with-sources",
"name": "Research with sources",
"description": "Given a question, searches the web, synthesizes an answer...",
"tags": ["research", "search", "summarization"],
"examples": ["What changed in the Vercel AI SDK v5 release?"]
}
]
}
BCG's enterprise agent playbook references this spec as the discovery contract between agents in a multi-agent mesh. It is the industry-standard way to describe an agent to other systems.
The Oracle Open Agent Specification (OAS) goes further: a portable YAML definition that describes the whole agent — not just its external interface but its tools, memory, and workflows. A single OAS file can generate stacks for Oracle ADK, LangGraph, or roll-your-own — the way an OpenAPI spec generates client libraries across languages.
In the workshop, OAS gets a 90-second mention. In the enterprise branch of the workshop, it earns a full module — because once you're shipping agents into a regulated environment, defining the agent in a portable spec that other stacks can consume is the difference between "one more codebase to maintain" and "a single definition that compiles to multiple targets."
The test: can another system discover your agent and know how to talk to it, without reading your source code? If yes, you have a spec. If no, your agent is a private tool, not a component in a larger system.
An agent running on your laptop is not an agent. It's a demo. The deploy primitive is what turns a demo into a system.
Deploy means four things:
In the workshop starter, deploy is literally vercel --prod. That gets you the URL. The other three are exercises for the reader — and they're the exercises that matter in production.
The naive instinct is to deploy and then add observability later. The architectural instinct is to wire observability into the loop before you deploy. One log line per tool call, one trace per runAgent, one cost counter per session. In Vercel AI SDK, the onStepFinish callback gives you a hook for all of this:
await generateObject({
model,
system: SYSTEM_PROMPT,
messages,
schema: ResearchSchema,
tools: { web_search: webSearch },
maxSteps: 5,
onStepFinish: ({ toolCalls, usage }) => {
log.info({ toolCalls, usage }) // ← observability
},
})
Adding this before deploy means the first minute your agent is live, you already know what it's doing.
The test: if your agent misbehaved right now, could you tell what it did from the logs? If yes, you deployed. If no, you published.
I've seen longer lists. "Planner," "reflector," "evaluator," "router." They're all specializations of the loop. A planner is a loop that decomposes before executing. A reflector is a loop that reviews its own output. A router is a loop that picks from multiple agents. If you collapse them into "the loop is where orchestration logic lives," you keep the mental model simple.
I've also seen shorter lists. "Prompt, tool, memory" skips the spec and the deploy, which is fine for a demo and insufficient for a product.
Six is the minimum that covers building and shipping. Anything less and you'll ship a demo and call it an agent. Anything more and you're cataloging, not architecting.
You can evaluate any new agent framework — LangGraph, AgentKit, Haystack, Voyage, whatever ships next quarter — by asking: how does it spell each of the six?
langgraph's StateGraph map to my loop? Yes.langchain.tools.Tool map to my tool primitive? Yes, with adapter.Twenty minutes of this and you know whether to invest a month in the framework. That's the payoff.
The six primitives are the map. The workshop is the trip. The starter repo is the receipt.
Want this as an 8-page handout + 10-day email primer course? Get the free Six Primitives Primer — no card, no fluff. We follow up with one short, opinionated email per day for ten days, each teaching one primitive with code samples. Unsubscribe in one click whenever.
Step-by-step guide to setting up ACOS, creating your first agent, and shipping real products with AI.
Start buildingDownload AI architecture templates, multi-agent blueprints, and prompt engineering patterns.
Browse templatesConnect with creators and architects shipping AI products. Weekly office hours, shared resources, direct access.
Join the circleRead on FrankX.AI — AI Architecture, Music & Creator Intelligence
Weekly field notes on AI systems, production patterns, and builder strategy.

A straight comparison of Vercel AI SDK, Claude Agent SDK, OpenAI Agents SDK, Google ADK, and no-code options. The central path for your first agent — and why it isn't a Vercel ad.
Read article
How I built a fantasy civilization with 5 Eldrian characters, 10 Gates, and a living world-state — using Claude Code, Gemini, and agentic workflows.
Read article
The open-source AI agent with 247K GitHub stars. How it works, what NVIDIA added with NemoClaw, and what it means for personal AI agents in 2026.
Read article