{"slug": "ax-google-s-open-agentic-orchestrator-explained-building-production-ai-agent", "title": "AX: Google's Open Agentic Orchestrator Explained — Building Production AI Agent Workflows", "summary": "A developer published a technical breakdown of AX, Google's open-source agentic orchestrator, which models AI agents as stateful graphs with explicit transitions, retries, and checkpoints rather than prompt-chaining sequences. The writeup details AX's core primitives, a TypeScript/Node.js implementation using a Redis state store, and a feature comparison against LangChain and CrewAI, positioning AX as a production workflow engine for multi-step agent tasks.", "body_md": "*Originally published at [adityarawas.in](https://adityarawas.in/blog/ax-googles-open-agentic-orchestrator-explained-building-production-ai-agent-workflows)*\n\nEvery framework promising to \"orchestrate agents\" eventually collapses into the same three problems: state management across long-running tasks, tool-call reliability, and observability when something silently breaks at 3am. AX — Google's open agentic orchestrator — is the first framework in this space that treats those three problems as first-class citizens instead of afterthoughts bolted onto a prompt-chaining library. If you've shipped anything with LangChain or a homegrown agent loop, you already know why that matters.\n\nThis is a practical breakdown of what AX actually does, how it's architected, and how to wire it into a real Node.js/TypeScript backend with Docker for deployment.\n\nAX is an open-source orchestration layer for AI agents that sits between your LLM calls and your application logic. Unlike prompt-chaining libraries that treat agents as a sequence of function calls, AX models agents as **stateful graphs** with explicit transitions, retries, and checkpoints.\n\nThe core primitives:\n\nThis is closer to a workflow engine (think Temporal or AWS Step Functions) than a chatbot SDK — which is exactly the gap it fills. Most agent frameworks are great for demos and terrible for anything that needs to survive a network blip or a rate-limited API three steps into a 20-step task.\n\nIf you're building agentic features into a product — not a research notebook — you care about things AX explicitly designs for:\n\nThat last point is the sleeper feature. You don't need to rewrite your Go microservices in Python to make them agent-callable — AX treats any HTTP/gRPC endpoint as a valid executor.\n\n```\nnpm install @google/ax-orchestrator\nnpm install @google/ax-store-redis\n```\n\nA minimal agent graph in TypeScript:\n\n``` js\nimport { Graph, Executor, RetryPolicy } from '@google/ax-orchestrator';\nimport { RedisStateStore } from '@google/ax-store-redis';\n\nconst store = new RedisStateStore({\n  url: process.env.REDIS_URL!,\n});\n\nconst fetchData: Executor = {\n  id: 'fetch-user-data',\n  type: 'tool',\n  run: async (ctx) => {\n    const res = await fetch(`https://api.internal/users/${ctx.input.userId}`);\n    if (!res.ok) throw new Error(`Upstream failed: ${res.status}`);\n    return res.json();\n  },\n  policy: RetryPolicy.exponentialBackoff({ maxAttempts: 3, baseMs: 500 }),\n};\n\nconst summarize: Executor = {\n  id: 'summarize-with-llm',\n  type: 'llm',\n  model: 'gemini-2.5-pro',\n  prompt: (ctx) => `Summarize this user profile in 2 sentences:\\n${JSON.stringify(ctx.state.fetchData)}`,\n};\n\nconst graph = new Graph({ store })\n  .addNode(fetchData)\n  .addNode(summarize)\n  .connect('fetch-user-data', 'summarize-with-llm');\n\nexport async function runAgent(userId: string) {\n  const run = await graph.start({ input: { userId } });\n  return run.result;\n}\n```\n\nNotice there's no manual `try/catch` retry loop, no ad-hoc `setTimeout` backoff — that's the whole point. The policy is declared once, attached to the node, and the orchestrator enforces it.\n\n| Feature | AX | LangChain | CrewAI | \n|---|---|---|---|\n| State persistence | Durable, pluggable store | In-memory by default | In-memory by default | \n| Crash recovery | Resumes from checkpoint | Restarts from scratch | Restarts from scratch | \n| Retry policies | Per-node, declarative | Manual wrapping | Limited | \n| Language interop | Any HTTP/gRPC service | Python/JS SDKs only | Python only | \n| Observability | Built-in trace export (OpenTelemetry) | Requires LangSmith | Minimal | \n| Deployment model | Stateless orchestrator + external store | Embedded in app process | Embedded in app process | \n| Best fit | Production multi-step workflows | Prototyping, RAG pipelines | Role-based agent teams | \n\nThe architectural bet AX makes is that **agents are workflows, not chat sessions**. That reframing is why it plugs so cleanly into existing DevOps tooling — checkpoints are just rows in Postgres, traces are just OTel spans, and scaling is just adding more orchestrator replicas behind a load balancer.\n\nReal-world use cases rarely involve a single LLM call. Here's a research-and-report pipeline with conditional branching:\n\n``` js\nimport { Graph, Executor, Condition } from '@google/ax-orchestrator';\n\nconst searchWeb: Executor = {\n  id: 'search-web',\n  type: 'tool',\n  run: async (ctx) => searchAPI(ctx.input.query),\n};\n\nconst validateResults: Executor = {\n  id: 'validate-results',\n  type: 'llm',\n  model: 'gemini-2.5-flash',\n  prompt: (ctx) => `Are these search results relevant to \"${ctx.input.query}\"? Answer YES or NO.\\n${JSON.stringify(ctx.state.searchWeb)}`,\n};\n\nconst draftReport: Executor = {\n  id: 'draft-report',\n  type: 'llm',\n  model: 'gemini-2.5-pro',\n  prompt: (ctx) => `Write a report using:\\n${JSON.stringify(ctx.state.searchWeb)}`,\n};\n\nconst refineQuery: Executor = {\n  id: 'refine-query',\n  type: 'llm',\n  model: 'gemini-2.5-flash',\n  prompt: (ctx) => `Rewrite this search query to be more specific: \"${ctx.input.query}\"`,\n};\n\nconst graph = new Graph()\n  .addNode(searchWeb)\n  .addNode(validateResults)\n  .addNode(draftReport)\n  .addNode(refineQuery)\n  .connect('search-web', 'validate-results')\n  .connectConditional('validate-results', {\n    onTrue: 'draft-report',\n    onFalse: 'refine-query',\n  })\n  .connect('refine-query', 'search-web'); // loop back\n```\n\nThis loop-back edge is where most naive agent implementations fall apart — infinite loops without a cap. AX solves it with built-in **cycle guards**:\n\n``` js\nconst graph = new Graph({\n  maxCycles: 5,\n  onCycleLimitExceeded: 'fail-with-partial-result',\n});\n```\n\nAX ships OpenTelemetry instrumentation out of the box. Every node execution emits a span with input/output/token-usage metadata:\n\n``` js\nimport { AXTracer } from '@google/ax-orchestrator';\n\nconst tracer = new AXTracer({\n  exporter: 'otlp',\n  endpoint: process.env.OTEL_COLLECTOR_URL,\n});\n\ngraph.attachTracer(tracer);\n```\n\nPipe that into Grafana/Tempo and you get a flame graph of your agent's decision tree — which node retried, how many tokens each LLM call burned, and where latency actually lives. This is the difference between debugging an agent by re-reading chat transcripts versus debugging it like you'd debug a distributed system, because that's what it is.\n\nBecause the orchestrator is stateless, containerizing it is straightforward:\n\n```\nFROM node:20-alpine AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci\nCOPY . .\nRUN npm run build\n\nFROM node:20-alpine\nWORKDIR /app\nENV NODE_ENV=production\nCOPY --from=builder /app/dist ./dist\nCOPY --from=builder /app/node_modules ./node_modules\nEXPOSE 3000\nCMD [\"node\", \"dist/server.js\"]\n```\n\n`docker-compose.yml` for local development with Redis as the state store:\n\n```\nversion: \"3.9\"\nservices:\n  ax-orchestrator:\n    build: .\n    ports:\n      - \"3000:3000\"\n    environment:\n      - REDIS_URL=redis://redis:6379\n      - OTEL_COLLECTOR_URL=http://otel-collector:4318\n    depends_on:\n      - redis\n  redis:\n    image: redis:7-alpine\n    ports:\n      - \"6379:6379\"\n  otel-collector:\n    image: otel/opentelemetry-collector:latest\n    ports:\n      - \"4318:4318\"\n```\n\nScale horizontally by just increasing replicas — since state lives in Redis/Postgres, any orchestrator instance can pick up a checkpointed run.\n\n```\ndocker compose up --scale ax-orchestrator=3\n```\n\nThe pattern that separates toy agents from production agents is explicit failure handling per node:\n\n``` js\nconst paymentExecutor: Executor = {\n  id: 'process-payment',\n  type: 'tool',\n  run: async (ctx) => chargeCard(ctx.state.amount, ctx.state.cardToken),\n  policy: {\n    retry: { maxAttempts: 2, baseMs: 1000 },\n    onFailure: 'compensate',\n    compensate: async (ctx) => {\n      await refundIfCharged(ctx.state.transactionId);\n    },\n  },\n};\n```\n\nThat `compensate` hook is essentially the Saga pattern from distributed transactions, applied to agent workflows. If you've built payment or booking systems, this should feel immediately familiar — because it's solving the same problem.\n\nAX is overkill for:\n\nIt earns its complexity when you have:\n\n| Store | Best for | Tradeoff | \n|---|---|---|\n| Redis | Low-latency, ephemeral workflows | No long-term durability guarantees without persistence config | \n| Postgres | Audit trails, long-running workflows (days) | Higher write latency per checkpoint | \n| GCS/S3 | Very large state payloads (large documents, embeddings) | Higher latency, not ideal for high-frequency checkpoints | \n\nPick based on workflow duration and payload size — don't default to Postgres for a workflow that completes in under 10 seconds; Redis will save you real latency.\n\n`compensate` hook makes AX suitable for workflows with real side effects like payments or bookings.", "url": "https://wpnews.pro/news/ax-google-s-open-agentic-orchestrator-explained-building-production-ai-agent", "canonical_source": "https://dev.to/rawas_aditya/ax-googles-open-agentic-orchestrator-explained-building-production-ai-agent-workflows-4710", "published_at": "2026-09-21 08:15:06+00:00", "updated_at": "2026-09-21 08:24:04.319912+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-infrastructure", "mlops"], "entities": ["Google", "AX", "LangChain", "CrewAI", "Redis", "TypeScript", "Node.js", "OpenTelemetry"], "alternates": {"html": "https://wpnews.pro/news/ax-google-s-open-agentic-orchestrator-explained-building-production-ai-agent", "markdown": "https://wpnews.pro/news/ax-google-s-open-agentic-orchestrator-explained-building-production-ai-agent.md", "text": "https://wpnews.pro/news/ax-google-s-open-agentic-orchestrator-explained-building-production-ai-agent.txt", "jsonld": "https://wpnews.pro/news/ax-google-s-open-agentic-orchestrator-explained-building-production-ai-agent.jsonld"}}