Skip to main content
AI & Full-Stack·14 min read

Building Production Multi-Agent Workflows with the OpenAI Agents SDK in TypeScript (2026 Guide)

A practical, production-oriented guide to the OpenAI Agents SDK for TypeScript. Learn agents, tools, handoffs, agents-as-tools, guardrails, and how to orchestrate reliable multi-agent systems for Next.js and Node.js applications.

By Mussawar Hayat

Why Multi-Agent Systems Matter in 2026

Single-prompt LLM calls are no longer enough for serious software work. Gartner lists multiagent systems among the top strategic technology trends for 2026, and engineering teams are moving from one general-purpose agent to specialised agents that hand work to each other. The OpenAI Agents SDK for TypeScript gives you a small, production-ready set of primitives to do exactly that without inventing your own orchestration layer.

This guide walks through the current SDK (v0.16+), shows real TypeScript patterns that fit Next.js and Node.js backends, and covers the production concerns that usually get skipped: guardrails, deterministic vs LLM orchestration, error handling, and observability.

What You Will Learn

  • Core primitives: Agent, tools, handoffs, and agents-as-tools
  • When to use LLM-driven routing versus code-driven pipelines
  • Production-ready examples with Zod validation and structured outputs
  • Input, output, and tool guardrails that actually stop bad behaviour
  • Security, cost, and common mistakes when shipping multi-agent systems

1. What the OpenAI Agents SDK Actually Provides

The SDK is the production successor to the experimental Swarm library. It is deliberately small:

  • Agents — an LLM plus instructions, tools, guardrails, and optional handoffs
  • Sandbox agents — agents paired with an isolated filesystem and shell (beta)
  • Realtime agents — low-latency voice agents
  • Handoffs — transfer the conversation to a specialist agent
  • Agents as tools — call a specialist as a tool while the manager keeps control
  • Guardrails — input, output, and tool-level validation that can tripwire
  • Tracing — built-in visibility into every tool call and handoff

Installation is straightforward:

npm install @openai/agents zod

Requires Node.js 22+, Deno, or Bun. Set OPENAI_API_KEY in the environment (or use the config helpers).

2. First Agent and Basic Tools

Start with a plain text agent:

import { Agent, run, tool } from '@openai/agents';
import { z } from 'zod';

const getWeather = tool({
  name: 'get_weather',
  description: 'Get current weather for a city',
  parameters: z.object({ city: z.string() }),
  execute: async ({ city }) => {
    // Replace with a real weather API in production
    return "Weather in " + city + ": 22°C, clear";
  },
});

const assistant = new Agent({
  name: 'Assistant',
  instructions: 'You are a helpful assistant. Use tools when you need facts.',
  tools: [getWeather],
});

const result = await run(assistant, 'What is the weather in Berlin?');
console.log(result.finalOutput);

The tool() helper turns any TypeScript function into a model-callable tool with automatic Zod schema generation and strict validation. Non-string return values are serialised for the model.

3. Multi-Agent Orchestration Patterns

There are two primary patterns. Choose deliberately.

3.1 Handoffs (specialist takes over)

Use handoffs when the specialist should own the rest of the conversation and speak directly to the user.

import { Agent, run } from '@openai/agents';

const historyTutor = new Agent({
  name: 'History Tutor',
  instructions: 'Explain historical events clearly with context and dates.',
});

const mathTutor = new Agent({
  name: 'Math Tutor',
  instructions: 'Solve math problems step by step and show reasoning.',
});

const triage = Agent.create({
  name: 'Triage',
  instructions: 'Route the user question to the correct specialist.',
  handoffs: [historyTutor, mathTutor],
});

const result = await run(triage, 'When did the Roman Empire fall?');
console.log(result.finalOutput);
console.log('Handled by:', result.lastAgent?.name);

Agent.create keeps TypeScript types aligned across handoff graphs. The runner automatically transfers conversation context to the chosen specialist.

3.2 Agents as tools (manager stays in control)

Use this when you want one agent to own the final answer and combine results from specialists without giving them the user-facing conversation.

import { Agent, run } from '@openai/agents';

const researcher = new Agent({
  name: 'Researcher',
  instructions: 'Find concise, factual answers. Prefer primary sources.',
});

const writer = new Agent({
  name: 'Writer',
  instructions: 'Turn research notes into clear technical prose.',
});

const manager = new Agent({
  name: 'Manager',
  instructions: 'Coordinate research and writing. Always return a polished final answer.',
  tools: [
    researcher.asTool({
      toolName: 'research',
      toolDescription: 'Research a technical topic and return key facts',
    }),
    writer.asTool({
      toolName: 'write',
      toolDescription: 'Turn research notes into a short technical article section',
    }),
  ],
});

const result = await run(
  manager,
  'Write a short section explaining why multi-agent systems improve reliability over a single general agent.'
);
console.log(result.finalOutput);

You can mix both patterns: a triage agent hands off to a specialist, and that specialist still uses other agents as tools for bounded subtasks.

4. Production Patterns for Next.js / Node.js

In a real backend you almost never run agents from a client component. Keep the orchestration on the server.

Route Handler example (App Router)

// app/api/agents/route.ts
import { Agent, run } from '@openai/agents';
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

const BodySchema = z.object({
  message: z.string().min(1).max(4000),
});

const supportAgent = new Agent({
  name: 'Support',
  instructions: 'Answer product questions briefly and accurately. Escalate if unsure.',
});

export async function POST(req: NextRequest) {
  const json = await req.json();
  const parsed = BodySchema.safeParse(json);
  if (!parsed.success) {
    return NextResponse.json({ error: 'Invalid body' }, { status: 400 });
  }

  const result = await run(supportAgent, parsed.data.message);
  return NextResponse.json({
    output: result.finalOutput,
    agent: result.lastAgent?.name,
  });
}

Code-driven pipelines for determinism

When latency, cost, or auditability matter more than open-ended reasoning, orchestrate in code:

  • Use structured outputs (Zod schemas on agents) to classify intent.
  • Chain agents: research → outline → draft → critique → revise.
  • Run independent specialists in parallel with Promise.all.
  • Loop an evaluator agent until a quality threshold is met.

These patterns appear in the official examples/agent-patterns directory and give you predictable token spend and easier testing.

5. Guardrails That Belong in Production

Guardrails are first-class. They prevent expensive or dangerous runs before (or while) the main agent executes.

import {
  Agent,
  run,
  InputGuardrail,
  InputGuardrailTripwireTriggered,
} from '@openai/agents';
import { z } from 'zod';

const guardrailAgent = new Agent({
  name: 'Safety check',
  instructions: 'Detect requests for disallowed topics (e.g. credential dumping).',
  outputType: z.object({
    isDisallowed: z.boolean(),
    reason: z.string(),
  }),
});

const safetyGuardrail = {
  name: 'Safety',
  runInParallel: false, // block the main model until the check finishes
  execute: async ({ input, context }) => {
    const result = await run(guardrailAgent, input, { context });
    return {
      outputInfo: result.finalOutput,
      tripwireTriggered: result.finalOutput?.isDisallowed ?? false,
    };
  },
};

const agent = new Agent({
  name: 'Support',
  instructions: 'Help users with product questions only.',
  inputGuardrails: [safetyGuardrail],
});

Key rules:

  • Input guardrails run only on the first agent in a chain.
  • Output guardrails run only on the agent that produces the final answer.
  • Tool guardrails attach to individual tool() definitions and run on every invocation.
  • Prefer runInParallel: false for high-risk checks so you do not spend tokens on a request that will be rejected.

6. Security, Cost, and Observability

Security

  • Never expose your OpenAI API key to the browser. Create ephemeral tokens server-side for realtime agents.
  • Treat every tool as untrusted input. Validate arguments with Zod and keep side-effecting tools behind human-in-the-loop approval when the risk is high.
  • Sandbox agents (beta) give you an isolated filesystem and shell — use them for any code-execution or file-write workflows.
  • Log the full run result (including tool calls) for audit trails; the SDK’s tracing already records the graph.

Cost control

  • Specialist agents with focused instructions and smaller models reduce tokens.
  • Code-driven pipelines are usually cheaper than open-ended LLM orchestration for fixed workflows.
  • Guardrails that run before the main model prevent wasted spend on blocked requests.

Observability

Every run produces a trace visible in the OpenAI dashboard. Use it to see which agent handled the request, which tools were called, and where handoffs occurred. For production, also emit your own structured logs around run() so you can alert on error rates and latency.

7. Real Use Cases for Full-Stack Teams

  • Support triage — route billing, technical, and account questions to specialised agents with different tools and knowledge bases.
  • Code-adjacent workflows — a manager agent that calls a research agent, a code-review agent, and a documentation agent, then synthesises a PR description.
  • Internal tools — agents that query your Postgres via a carefully scoped DAL tool, never receiving raw connection strings.
  • Content pipelines — research → outline → draft → SEO critique → final polish, each step an agent with a strict output schema.

8. FAQ

Is the OpenAI Agents SDK only for OpenAI models?

No. The core is provider-agnostic. The default package wires OpenAI, but lower-level packages let you plug in other providers.

Should I use handoffs or agents-as-tools?

Handoffs when the specialist should speak to the user and own the conversation. Agents-as-tools when a manager must stay in control and combine multiple specialist results.

Can I use this inside a Next.js Server Action?

Yes, as long as the action runs on the server and you keep the API key server-side. Prefer Route Handlers for longer-running or streaming agent work.

How do I keep context across turns?

Pass result.history back into the next run(), attach a Session, or use OpenAI server-managed conversation state. See the running-agents and sessions guides.

Are sandbox agents ready for production?

They are marked beta. Prefer them for development and carefully scoped workloads; keep production file and shell access behind your own review gates until the API stabilises further.

9. Summary

The OpenAI Agents SDK gives TypeScript teams a clean, small surface for multi-agent systems: agents, tools, handoffs, agents-as-tools, and guardrails. Use LLM orchestration for open-ended tasks and code orchestration when you need determinism, cost control, and auditability. Always put the orchestration on the server, validate every tool argument, and treat guardrails as mandatory rather than optional.

Key Takeaway

Start with a triage or manager agent, give specialists focused instructions and minimal tools, enforce guardrails on input and high-risk tools, and keep the final human review step for anything that touches production data or code.


Need help designing multi-agent systems for a Next.js or Node.js product?

I help teams ship production React, Next.js, TypeScript, and full-stack applications that incorporate modern AI agents safely and reliably. Get in touch or explore full-stack and AI development services.

Related reading: Agent Skills for TypeScript & Next.js and Claude Code Auto Mode Production Guide.