`WorkflowAgent`

WorkflowAgent

워크플로 안에서 사용할 수 있는, 재개 가능한(durable, resumable) AI 에이전트를 만들어요. WorkflowAgent는 에이전트 루프, 워크플로 스텝 경계를 넘나드는 도구 스키마 직렬화, 그리고 내장된 도구 승인 흐름을 처리해요.

ai 패키지의 ToolLoopAgent와 달리, WorkflowAgent는 프로세스 재시작을 견디도록 설계됐고, 사람의 승인을 위해 일시 정지하며, Workflow DevKit의 스텝 메커니즘과 통합돼요.

WorkflowAgent는 공유 에이전트 상태를 위한 runtimeContext와 도구별 컨텍스트를 위한 toolsContext를 지원해요. 이 값들은 워크플로와 스텝 경계를 넘나들 수 있으므로 직렬화 가능한 내구성 데이터로 유지하세요. ToolLoopAgent와 달리 컨텍스트에 함수, 클래스 인스턴스, 심볼, 데이터베이스 클라이언트, SDK 클라이언트를 넣지 말고, 식별자나 설정을 전달하고 비직렬화 가능한 리소스는 스텝 함수 안에서 다시 생성하세요.

import { WorkflowAgent } from '@ai-sdk/workflow';
import { tool } from 'ai';
import { z } from 'zod';

const agent = new WorkflowAgent({
  model: 'anthropic/claude-sonnet-5',
  instructions: 'You are a helpful assistant.',
  tools: {
    weather: tool({
      description: 'Get the weather in a location',
      inputSchema: z.object({
        location: z.string(),
      }),
      execute: async ({ location }) => ({
        location,
        temperature: 72,
      }),
    }),
  },
});

const result = await agent.stream({
  messages: [
    {
      role: 'user',
      content: [{ type: 'text', text: 'What is the weather in NYC?' }],
    },
  ],
});

console.log(result.messages);

WorkflowAgent가 실제로 동작하는 모습을 보려면 이 예시들을 확인해 보세요.

출처: 문서

본문

Import

import { WorkflowAgent } from "@ai-sdk/workflow"

생성자 (Constructor)

파라미터 (Parameters)

이름 타입 필수 설명
id string 선택 에이전트의 id.
model LanguageModel 필수 사용할 언어 모델. Vercel AI Gateway 호환 문자열(예: 'anthropic/claude-sonnet-5') 또는 provider 인스턴스(예: openai('gpt-6-astra')).
instructions Instructions 선택 에이전트 지침. 시스템 프롬프트로 사용돼요. SystemModelMessage 형식을 쓰면 provider별 옵션(예: 캐싱)을 지원해요.
tools Record<string, Tool> 선택 에이전트가 호출할 수 있는 도구 집합. 키는 도구 이름이에요. 도구는 워크플로 스텝 경계를 넘어 JSON Schema로 직렬화되고 런타임에 Ajv로 검증돼요.
toolChoice ToolChoice 선택 도구 호출 선택 전략. 옵션: 'auto' | 'none' | 'required' | { type: 'tool', toolName: string }. 기본값: 'auto'.
stopWhen StopCondition | StopCondition[] 선택 에이전트 루프의 기본 종료 조건. 생략하면 WorkflowAgent는 최대 스텝 수가 없고 자연 완료까지 계속돼요. isStepCount()로 실행을 제한하세요. 스트림별 값이 이 기본값을 덮어써요.
activeTools ActiveTools<TTools> 선택 기본 활성 도구 집합. 도구 호출과 결과 타입을 바꾸지 않고 모델이 호출할 수 있는 도구를 제한해요. 스트림별 값이 기본값을 덮어써요.
output OutputSpecification 선택 기본 구조화 출력 명세. 스트림별 값이 이 기본값을 덮어써요.
repairToolCall ToolCallRepairFunction 선택 파싱에 실패한 도구 호출을 복구하는 기본 함수. 스트림별 값이 이 기본값을 덮어써요.
experimental_download DownloadFunction 선택 URL용 기본 커스텀 다운로드 함수. 스트림별 값이 이 기본값을 덮어써요.
experimental_sandbox Experimental_SandboxSession 선택 도구 설명과 실행에 experimental_sandbox로 전달되고 prepareStep에 노출되는 기본 샌드박스 세션. 스트림별 값이 이 기본값을 덮어써요.
experimental_toolApprovalSecret WorkflowToolApprovalSecret 선택 도구 승인 요청을 HMAC 서명하고 도구 실행 전 승인된 메시지 기록을 검증하는 데 쓰는 시크릿을 담은 환경 변수에 대한 워크플로 안전 참조. 워크플로 경계를 넘는 것은 환경 변수 이름뿐이고, 시크릿은 서명·검증 스텝 안에서 읽어요. 스트림별 값이 기본값을 덮어써요.
prepareStep PrepareStepCallback 선택 에이전트 루프의 각 스텝 전에 호출되는 콜백. 설정 수정, 컨텍스트 관리, 메시지 동적 주입, 현재 스텝의 experimental_sandbox 재정의에 사용해요. 스텝 번호, 이전 스텝, 메시지, 컨텍스트, 샌드박스를 받아요.
prepareCall PrepareCallCallback 선택 에이전트 루프 시작 전에 한 번 호출되는 콜백. 런타임 컨텍스트에 따라 모델, 지침, 도구 설정 등을 변환하는 데 사용해요. tools는 재정의할 수 없어요(타입 안전성을 위해 생성 시점에 바인딩됨).
runtimeContext Context 선택 모든 스트림 호출의 기본 공유 런타임 컨텍스트. prepareStep, 수명주기 콜백, 스텝 결과를 통해 흘러가요. 스트림별 값이 이 기본값을 덮어써요. 워크플로에서 사용할 때는 직렬화 가능해야 해요.
toolsContext InferToolSetContext<TTools> 선택 모든 스트림 호출의 기본 도구별 컨텍스트 맵. 각 도구는 검증된 자기 항목만 context로 받아요. 스트림별 값이 이 기본값을 덮어써요. 워크플로에서 사용할 때는 직렬화 가능해야 해요.
telemetry TelemetryOptions 선택 텔레메트리 활성화/비활성화 옵션, 함수 ID 설정, 입력/출력 기록 옵션이 있는 텔레메트리 구성.
onStart WorkflowAgentOnStartCallback 선택 에이전트가 스트리밍을 시작할 때, LLM 호출 전에 호출되는 콜백. 모델, 메시지, 런타임 컨텍스트, 도구 컨텍스트를 받아요. stream()에도 지정하면 둘 다 호출돼요(생성자 먼저). 생성자에서 둘 다 제공할 때 experimental_onStart보다 우선해요.
experimental_onStart WorkflowAgentOnStartCallback 선택 onStart의 deprecated 별칭. 생성자에 onStart가 없을 때만 사용돼요.
onStepStart WorkflowAgentOnStepStartCallback 선택 각 스텝(LLM 호출)이 시작되기 전에 호출되는 콜백. 스텝 번호, 모델, 메시지, 이전 스텝, 런타임 컨텍스트, 도구 컨텍스트를 받아요.
experimental_onStepStart WorkflowAgentOnStepStartCallback 선택 onStepStart의 deprecated 별칭. 생성자에 onStepStart가 없을 때만 사용돼요.
onToolExecutionStart WorkflowAgentOnToolExecutionStartCallback 선택 도구의 execute 함수가 실행되기 직전에 호출되는 콜백. 실험적(patch 릴리스에서 깨질 수 있음).
onToolExecutionEnd WorkflowAgentOnToolExecutionEndCallback 선택 도구의 execute 함수가 완료되거나 오류가 난 직후 호출되는 콜백. success로 output 또는 error 사용 가능 여부를 확인하세요. 실험적(patch 릴리스에서 깨질 수 있음).
onStepEnd WorkflowAgentOnStepEndCallback 선택 각 에이전트 스텝이 완료된 후 호출되는 콜백.
onStepFinish WorkflowAgentOnStepFinishCallback 선택 deprecated. onStepEnd를 사용하세요. 이 별칭은 onStepEnd가 제공되지 않을 때만 폴백으로 사용돼요.
onEnd WorkflowAgentOnEndCallback 선택 모든 에이전트 스텝이 끝나고 응답이 완료되면 호출되는 콜백. 스텝, 메시지, 텍스트, 종료 이유, 총 사용량, 컨텍스트를 받아요.
maxOutputTokens number 선택 모델이 생성할 수 있는 최대 토큰 수.
temperature number 선택 샘플링 온도. 무작위성을 제어해요.
topP number 선택 Top-p(nucleus) 샘플링 파라미터.
topK number 선택 Top-k 샘플링 파라미터.
presencePenalty number 선택 presence penalty 파라미터.
frequencyPenalty number 선택 frequency penalty 파라미터.
stopSequences string[] 선택 모델 출력을 중지시키는 커스텀 토큰 시퀀스.
seed number 선택 결정적 생성을 위한 시드(지원 시).
maxRetries number 선택 재시도 가능한 모델 호출 실패를 몇 번 재시도할지. 0이면 재시도 비활성화. Retry-After 응답 헤더를 존중하고, 내구성 워크플로 스텝 재시도는 중첩되지 않아요. 기본값: 2.
headers Record<string, string | undefined> 선택 요청과 함께 보낼 추가 HTTP 헤더. HTTP 기반 provider에만 적용돼요.
providerOptions ProviderOptions 선택 추가 provider별 구성.

속성 (Properties)

이름 타입 설명
id string | undefined 에이전트의 id. 텔레메트리 식별에 사용돼요. 읽기 전용.
tools Record<string, Tool> 이 에이전트에 구성된 도구 집합. 읽기 전용.

메서드 (Methods)

stream()

에이전트 루프를 실행하고 응답을 스트리밍하며 필요에 따라 도구 호출을 실행해요. WorkflowAgentStreamResult로 resolve되는 promise를 반환해요.

const result = await agent.stream({
  messages: [{ role: 'user', content: [{ type: 'text', text: 'Hello' }] }],
});
이름 타입 선택 설명
prompt string | Array<ModelMessage> 프롬프트 문자열 또는 메시지 목록. prompt 또는 messages 중 하나만 쓸 수 있어요.
messages Array<ModelMessage> 처리할 대화 메시지. prompt 또는 messages 중 하나만 쓸 수 있어요.
writable WritableStream<ModelCallStreamPart> 선택 원시 모델 스트림 파트를 실시간으로 받는 쓰기 가능한 스트림. 응답 경계에서 createModelCallToUIChunkTransform()로 UI 메시지 청크로 변환하세요.
instructions Instructions 선택 이 호출에 대한 에이전트 지침을 재정의해요.
system string 선택 deprecated. instructions를 사용하세요.
stopWhen StopCondition | StopCondition[] 선택 에이전트 루프 종료 조건. 생략하고 생성자 수준 조건도 없으면 WorkflowAgent는 최대 스텝 수가 없고 자연 완료까지 계속돼요. isStepCount()로 실행을 제한하세요.
toolChoice ToolChoice 선택 이 호출의 도구 선택 전략을 재정의해요. 기본값: 'auto'.
activeTools ActiveTools<TTools> 선택 도구 호출과 결과 타입을 바꾸지 않고 이 호출에서 사용 가능한 도구 하위 집합을 제한해요.
output OutputSpecification 선택 구조화 출력 명세. 타입 있는 객체는 Output.object({ schema }), 텍스트는 Output.text()를 사용하세요.
timeout number 선택 밀리초 단위 타임아웃. 주어진 시간 후 작업을 중단하는 AbortSignal을 만들어요.
sendFinish boolean 선택 스트리밍 완료 시 쓰기 가능한 스트림에 'finish' 청크를 보낼지. 기본값: true.
preventClose boolean 선택 스트리밍 완료 후 쓰기 가능한 스트림이 닫히는 것을 막을지. 기본값: false.
includeRawChunks boolean 선택 provider의 처리되지 않은 원시 청크를 스트림에 포함할지. 기본값: false.
repairToolCall ToolCallRepairFunction 선택 도구 호출을 파싱할 수 없을 때 자동 복구를 시도하는 콜백.
experimental_transform StreamTextTransform | Array<StreamTextTransform> 선택 순서대로 적용되는 스트림 변환. 스트림 구조를 유지해야 해요.
experimental_download DownloadFunction 선택 파일/URL 가져오기용 커스텀 다운로드 함수.
experimental_sandbox Experimental_SandboxSession 선택 도구 설명과 실행에 experimental_sandbox로 전달되고 prepareStep에 노출되는 샌드박스 세션. 생성자 기본값을 덮어써요.
experimental_toolApprovalSecret WorkflowToolApprovalSecret 선택 도구 승인 요청 HMAC 서명과 도구 실행 전 승인된 메시지 기록 검증에 쓰는 시크릿을 담은 환경 변수의 워크플로 안전 참조. 환경 변수 이름만 워크플로 경계를 넘어요. 생성자 기본값을 덮어써요.
telemetry TelemetryOptions 선택 호출별 텔레메트리 구성.
runtimeContext Context 선택 이 스트림 호출의 공유 런타임 컨텍스트. 생성자 기본값을 덮어쓰고 prepareStep, 수명주기 콜백, 스텝 결과를 통해 흘러가요. 워크플로에서 사용할 때는 직렬화 가능해야 해요.
toolsContext InferToolSetContext<TTools> 선택 이 스트림 호출의 도구별 컨텍스트 맵. 생성자 기본값을 덮어써요. 각 도구는 검증된 자기 항목만 context로 받아요. 직렬화 가능해야 해요.
prepareStep PrepareStepCallback 선택 호출별 prepareStep 재정의. 현재 스텝 상태와 함께 초기 지침과 메시지를 받아요.
onStart WorkflowAgentOnStartCallback 선택 호출별 onStart 콜백. 생성자에도 지정하면 둘 다 호출돼요(생성자 먼저).
experimental_onStart WorkflowAgentOnStartCallback 선택 호출별 onStart 콜백의 deprecated 별칭. 이 호출에 onStart가 없을 때만 사용돼요.
onStepStart WorkflowAgentOnStepStartCallback 선택 호출별 onStepStart 콜백.
experimental_onStepStart WorkflowAgentOnStepStartCallback 선택 호출별 onStepStart 콜백의 deprecated 별칭.
onToolExecutionStart WorkflowAgentOnToolExecutionStartCallback 선택 호출별 onToolExecutionStart 콜백.
onToolExecutionEnd WorkflowAgentOnToolExecutionEndCallback 선택 호출별 onToolExecutionEnd 콜백.
onStepEnd WorkflowAgentOnStepEndCallback 선택 호출별 onStepEnd 콜백.
onStepFinish WorkflowAgentOnStepFinishCallback 선택 deprecated. onStepEnd를 사용하세요. 이 별칭은 onStepEnd가 없을 때만 폴백으로 사용돼요.
onEnd WorkflowAgentOnEndCallback 선택 호출별 onEnd 콜백.
onError WorkflowAgentOnErrorCallback 선택 스트리밍 중 오류가 발생하면 호출되는 콜백.
onAbort WorkflowAgentOnAbortCallback 선택 작업이 중단될 때 호출되는 콜백. 이전에 끝난 모든 스텝을 받아요.
반환 (Returns)

다음 속성을 가진 Promise<WorkflowAgentStreamResult>를 반환해요:

이름 타입 설명
messages Array<ModelMessage> 모든 도구 호출과 결과를 포함한 최종 메시지.
steps Array<StepResult> 에이전트가 취한 모든 스텝의 세부 정보.
toolCalls Array<ToolCall> 마지막 스텝의 도구 호출. 승인이 필요한 도구처럼 실행되지 않은 호출도 포함해요.
toolResults Array<ToolResult> 마지막 스텝의 도구 결과. 실행된 도구의 결과만 포함해요.
error unknown | undefined 모델 스트림 오류 파트의 원래 값. 오류 파트가 emit되면 값이 undefined여도 속성이 존재해요. 'error' in result로 구분하세요.
output OUTPUT output 명세가 제공된 경우 구조화 출력.

유틸리티 (Utilities)

createModelCallToUIChunkTransform(options?)

에이전트가 writable 스트림에 쓴 원시 ModelCallStreamPart 청크를 클라이언트 소비용 UIMessageChunk 객체로 변환하는 TransformStream을 만들어요.

import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';

return createUIMessageStreamResponse({
  stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
});

WorkflowChatTransport 커서로 재개할 때는 원시 워크플로 스트림을 인덱스 0부터 재생하고 음수가 아닌 UI 청크 인덱스를 변환에 전달하세요:

const readable = run
  .getReadable({ startIndex: 0 })
  .pipeThrough(createModelCallToUIChunkTransform({ uiStartIndex: startIndex }));

uiStartIndex는 음수가 아닌 안전 정수여야 해요. 원시 모델 스트림 파트와 UI 메시지 청크는 1:1이 아니므로 getReadable에 UI 청크 인덱스를 전달하지 마세요. 음수 tail 인덱스는 이미 UIMessageChunk 객체를 저장하는 내구성 스트림이 필요해요.

toUIMessageChunk()

단일 ModelCallStreamPart를 UIMessageChunk로 변환해요. UI 청크로 매핑되지 않는 파트는 undefined를 반환해요.

import { toUIMessageChunk } from '@ai-sdk/workflow';

const uiChunk = toUIMessageChunk(modelCallPart);

타입 (Types)

ActiveTools

type ActiveTools<TTools extends ToolSet> =
  | ReadonlyArray<keyof TTools & string>
  | undefined;

워크플로 에이전트 호출을 나열된 도구 이름으로 제한해요. undefined는 도구 제한이 없음을 의미해요.

InferWorkflowAgentUIMessage

WorkflowAgent 인스턴스의 UI 메시지 타입을 추론해요. 선택적으로 커스텀 메시지 메타데이터를 위한 두 번째 타입 인자를 받아요.

import { WorkflowAgent, InferWorkflowAgentUIMessage } from '@ai-sdk/workflow';

const agent = new WorkflowAgent({
  model: 'anthropic/claude-sonnet-5',
  tools: { weather: weatherTool },
});

type MyAgentUIMessage = InferWorkflowAgentUIMessage<typeof agent>;

InferWorkflowAgentTools

WorkflowAgent 인스턴스의 도구 집합 타입을 추론해요.

import { WorkflowAgent, InferWorkflowAgentTools } from '@ai-sdk/workflow';

type MyTools = InferWorkflowAgentTools<typeof myAgent>;

예시 (Examples)

도구가 있는 기본 에이전트 (Basic Agent with Tools)

import { WorkflowAgent } from '@ai-sdk/workflow';
import { tool } from 'ai';
import { z } from 'zod';

const agent = new WorkflowAgent({
  model: 'anthropic/claude-sonnet-5',
  instructions: 'You are a helpful assistant.',
  tools: {
    weather: tool({
      description: 'Get weather for a location',
      inputSchema: z.object({
        location: z.string(),
      }),
      execute: async ({ location }) => ({
        location,
        temperature: 72,
        condition: 'sunny',
      }),
    }),
  },
});

const result = await agent.stream({
  messages: [
    {
      role: 'user',
      content: [{ type: 'text', text: 'What is the weather in NYC?' }],
    },
  ],
});

console.log(result.messages);
console.log(result.steps);

내구성 도구가 있는 워크플로 에이전트 (Agent in a Workflow with Durable Tools)

import { WorkflowAgent, type ModelCallStreamPart } from '@ai-sdk/workflow';
import { convertToModelMessages, tool, type UIMessage } from 'ai';
import { getWritable } from 'workflow';
import { z } from 'zod';

// Tool execute functions marked with 'use step' become durable workflow steps
// with automatic retries and persistence
async function searchFlightsStep(input: {
  origin: string;
  destination: string;
}) {
  'use step';
  const response = await fetch(`https://api.flights.example/search?...`);
  return response.json();
}

export async function chat(messages: UIMessage[]) {
  'use workflow';

  const modelMessages = await convertToModelMessages(messages);

  const agent = new WorkflowAgent({
    model: 'anthropic/claude-sonnet-5',
    instructions: 'You are a flight booking assistant.',
    tools: {
      searchFlights: tool({
        description: 'Search for available flights',
        inputSchema: z.object({
          origin: z.string(),
          destination: z.string(),
        }),
        execute: searchFlightsStep,
      }),
    },
  });

  const result = await agent.stream({
    messages: modelMessages,
    writable: getWritable<ModelCallStreamPart>(),
  });

  return { messages: result.messages };
}
import { createModelCallToUIChunkTransform } from '@ai-sdk/workflow';
import { createUIMessageStreamResponse, type UIMessage } from 'ai';
import { start } from 'workflow/api';
import { chat } from '@/workflow/agent-chat';

export async function POST(request: Request) {
  const { messages }: { messages: UIMessage[] } = await request.json();

  const run = await start(chat, [messages]);

  return createUIMessageStreamResponse({
    stream: run.readable.pipeThrough(createModelCallToUIChunkTransform()),
  });
}

구조화 출력이 있는 에이전트 (Agent with Structured Output)

import { WorkflowAgent, Output } from '@ai-sdk/workflow';
import { z } from 'zod';

const analysisAgent = new WorkflowAgent({
  model: 'anthropic/claude-sonnet-5',
});

const result = await analysisAgent.stream({
  messages: [
    {
      role: 'user',
      content: [
        {
          type: 'text',
          text: 'Analyze: "The product exceeded my expectations!"',
        },
      ],
    },
  ],
  output: Output.object({
    schema: z.object({
      sentiment: z.enum(['positive', 'negative', 'neutral']),
      score: z.number(),
      summary: z.string(),
    }),
  }),
});

console.log(result.output);
// { sentiment: 'positive', score: 9, summary: '...' }

도구 승인이 있는 에이전트 (Agent with Tool Approval)

WorkflowAgent에서는 도구 승인이 도구 정의의 needsApproval로 구성돼요. generateText, streamText, ToolLoopAgent에서는 대신 toolApproval을 사용하세요.

import { WorkflowAgent } from '@ai-sdk/workflow';
import { tool } from 'ai';
import { z } from 'zod';

const agent = new WorkflowAgent({
  model: 'anthropic/claude-sonnet-5',
  experimental_toolApprovalSecret: {
    environmentVariable: 'TOOL_APPROVAL_SECRET',
  },
  tools: {
    bookFlight: tool({
      description: 'Book a flight',
      inputSchema: z.object({
        flightId: z.string(),
        passengerName: z.string(),
      }),
      needsApproval: true, // Pauses the agent until user approves
      execute: bookFlightStep,
    }),
  },
});

experimental_toolApprovalSecret이 구성되면 각 승인 요청이 승인 ID, 도구 호출 ID, 도구 이름, 검증된 입력에 대해 서명돼요. 서명이 없거나 유효하지 않은 재생된 승인은 도구를 실행하지 않아요. 서명은 내구성 스트림과 UI 메시지 기록에 보존되고, 환경 변수 이름만 워크플로 경계를 넘어요. 서명·검증 스텝은 로컬 환경에서 원시 시크릿을 읽고 이를 직렬화하지 않아요. 스트림 레벨 참조가 생성자 값을 덮어써요.

수명주기 콜백이 있는 에이전트 (Agent with Lifecycle Callbacks)

import { WorkflowAgent } from '@ai-sdk/workflow';

const agent = new WorkflowAgent({
  model: 'anthropic/claude-sonnet-5',
  tools: { weather: weatherTool },

  // Agent-wide callbacks
  onStepEnd({ usage }) {
    console.log('Tokens used:', usage.totalTokens);
  },
});

const result = await agent.stream({
  messages,

  // Per-call callbacks (both fire)
  onStepEnd({ usage }) {
    await trackUsage(usage);
  },

  onEnd({ steps, totalUsage }) {
    console.log(
      `Done in ${steps.length} steps, ${totalUsage.totalTokens} tokens`,
    );
  },
});

더 알아보기 (Learn more)