Agent クラスを使用する場合: 複数ステップのツール処理ループ、会話履歴、処理進捗の配信(リアルタイム表示)、再利用可能なLLMエージェント(言語モデルを活用した自動実行プログラム)を必要とするとき。スキルを持つエージェントの構築、出力形式の指定、状態を保つ会話機能、またはコールバック(処理完了時に実行される関数)を通じた進捗通知が必要な場合に適しています。
Use the Agent class for multi-step tool loops, conversation history, streaming progress, and reusable LLM agents. Use when building agents with skills, structured output, stateful conversations, or streaming callbacks.
Agent クラスは、AI SDK の ToolLoopAgent を拡張し、出力プロンプトファイルとスキルシステムを統合したものです。複数ステップのツール実行、会話履歴、または再利用可能なエージェントインスタンスが必要な場合に使用してください。ツールを使わない単一の LLM 呼び出しの場合は、generateText の方がシンプルです。
aiSdk.Output.object() で構造化出力を持つエージェントを作成する場合messageStore で会話状態を保持する場合onChunk でエージェントの進捗をストリーミング配信する場合Agent と generateText の使い分けを判断する場合import { Agent, aiSdk } from '@outputai/llm';
import type { MessageStore } from '@outputai/llm';
import { z } from '@outputai/core';
Agent は @outputai/llm からインポートしてください。構造化出力には aiSdk.Output を使用します。z は @outputai/core からインポートしてください(直接 zod からはインポートしない)。MessageStore は、プラグイン可能な getMessages / addMessages ストアの型であり、自分で実装する必要があります。
プロンプトファイルはコンストラクタ時に読み込まれてレンダリングされます。変数とツールはコンストラクタで固定されます。スキルと maxSteps はプロンプトファイルから取得されます。エージェントは generate()、generateWithStreaming()、または stream() をすぐに呼び出せる状態です。
const agent = new Agent( {
prompt: 'writing_assistant@v1',
variables: {
content_type: input.contentType,
focus: input.focus,
content: input.content
},
output: aiSdk.Output.object( { schema: reviewSchema } )
} );
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
prompt |
string |
必須 | プロンプトファイル名(例:'writing_assistant@v1') |
promptDir |
string |
- | スタック解決されたプロンプトディレクトリをオーバーライド |
variables |
PromptVariables |
- | コンストラクタ時にレンダリングされるテンプレート変数 |
tools |
AI SDK tools | - | 呼び出し元のツール。プロンプト YAML のツールとマージ(load_skill は最後) |
stopWhen |
関数または関数配列 | - | カスタム停止条件(ツールが存在する場合、プロンプトの maxSteps をオーバーライド) |
output |
aiSdk.Output |
- | 構造化出力の仕様(例:aiSdk.Output.object({ schema })) |
messageStore |
MessageStore |
- | 複数ターンの履歴用プラグイン可能なストア |
エージェントを実行して完了時に戻ります:
const result = await agent.generate();
console.log( result.text ); // 生成されたテキスト
console.log( result.output ); // 構造化出力(aiSdk.Output.object 使用時)
console.log( result.usage ); // トークン使用量
結果は generateText と同じ形式です:text、result(text のエイリアス)、output、usage、finishReason、toolCalls など。
会話を拡張してメッセージを追加します:
const result = await agent.generate( {
messages: [ { role: 'user', content: 'Focus on the introduction section.' } ]
} );
メッセージは初期プロンプトメッセージ(とメッセージストアの履歴)の後に追加されます。abortSignal と toolChoice も渡せます。
進捗コールバックと完全な結果が必要な場合は generateWithStreaming() を使用してください:
const result = await agent.generateWithStreaming( {
onChunk( { chunk } ) {
if ( chunk.type === 'text-delta' ) {
process.stdout.write( chunk.text );
}
}
} );
このメソッドは内部でストリーミングを使用しながら generate() と同じように動作します。完全な応答を返し、ストリーム エラーで拒否し、設定されたメッセージストアにメッセージを自動的に追加します。generate() と同じ messages、abortSignal、toolChoice に加えて onChunk を受け付けます。Temporal ワークフロー ステップ内では、ストリーム結果への直接アクセスが必要でない限り stream() より優先してください。
textStream または fullStream の直接制御が必要な場合は stream() を使用してください。generate() と同じ messages、abortSignal、toolChoice に加えて onChunk、onFinish、onError を受け付けます:
const stream = await agent.stream();
for await ( const chunk of stream.textStream ) {
process.stdout.write( chunk );
}
streamText と同様に、ストリーム結果は textStream と fullStream イテラブル、完了時に解決するプロミスベースのプロパティ(text、usage、finishReason)を提供します。
stream() は、finishReason が 'error' でない場合、ラップされた onFinish でメッセージストアにメッセージを追加します。詳細は output-dev-llm-streaming を参照してください。
aiSdk.Output.object() を使用して型付きの応答を取得してください:
const reviewSchema = z.object( {
issues: z.array( z.string() ).describe( 'List of issues found' ),
suggestions: z.array( z.string() ).describe( 'Actionable suggestions' ),
score: z.number().describe( 'Quality score 0-100' ),
summary: z.string().describe( 'Brief overall assessment' )
} );
const agent = new Agent( {
prompt: 'writing_assistant@v1',
variables: { content_type: 'documentation', focus: 'clarity', content: markdownContent },
output: aiSdk.Output.object( { schema: reviewSchema } )
} );
const { output } = await agent.generate();
// output: { issues: string[], suggestions: string[], score: number, summary: string }
スキーマフィールドには .describe() を使用し、数値制約には .min()/.max() を使用しないでください。Anthropic はツール定義では minimum/maximum JSON スキーマ制約をサポートしていません。
デフォルトでは Agent はステートレスです。各 generate() 呼び出しは初期プロンプトメッセージのみで最初から始まります。呼び出し全体で履歴を保持する場合は messageStore を渡してください:
import { Agent } from '@outputai/llm';
import type { MessageStore } from '@outputai/llm';
const messages: Parameters<MessageStore['addMessages']>[0] = [];
const messageStore: MessageStore = {
getMessages: () => messages,
addMessages: incoming => {
messages.push( ...incoming );
}
};
const chatbot = new Agent( {
prompt: 'chatbot@v1',
messageStore
} );
const r1 = await chatbot.generate( {
messages: [ { role: 'user', content: 'Hello, tell me about Output.' } ]
} );
// r1.text: "Output is an AI framework for..."
const r2 = await chatbot.generate( {
messages: [ { role: 'user', content: 'How does it handle retries?' } ]
} );
// r2 は r1 からの完全な履歴を確認できます
MessageStore は以下のインターフェースです:
interface MessageStore {
getMessages(): ModelMessage[] | Promise<ModelMessage[]>;
addMessages( messages: ModelMessage[] ): void | Promise<void>;
}
ModelMessage は AI SDK の型(aiSdk / ai)です。組み込みストアはありません。単一プロセスではインメモリで、永続的な履歴についてはデータベースで実装してください。
ワークフローステップでは、呼び出しごとに新しい Agent を構築してください。変数はステップの入力から取得されます:
import { step, z } from '@outputai/core';
import { Agent, aiSdk } from '@outputai/llm';
const reviewSchema = z.object( {
summary: z.string().describe( 'Brief assessment' ),
issues: z.array( z.string() ).describe( 'Problems found' ),
suggestions: z.array( z.string() ).describe( 'Improvements' ),
score: z.number().describe( 'Quality score 0-100' )
} );
export const reviewContent = step( {
name: 'reviewContent',
description: 'Review technical content using Agent with structured output',
inputSchema: z.object( {
content: z.string().describe( 'The content to review' ),
content_type: z.string().describe( 'Type of content' ),
focus: z.string().describe( 'Review focus areas' )
} ),
outputSchema: reviewSchema,
fn: async input => {
const agent = new Agent( {
prompt: 'writing_assistant@v1',
variables: input,
output: aiSdk.Output.object( { schema: reviewSchema } )
} );
const { output } = await agent.generate();
return output;
}
} );
これが標準的なパターンです。各ステップ呼び出しは独立しており、Agent 構築は軽量です。
プロンプトのフロントマター(ファイルの先頭メタデータ)にスキルパスを記載します。詳細は output-dev-skill-file を参照してください。
generateText |
Agent |
|
|---|---|---|
| 最適な用途 | 単一の LLM 呼び出し | 複数ステップのツールループ |
| ツール | サポート | サポート |
| スキル | サポート | サポート |
| 会話履歴 | 手動 | messageStore で組み込み |
| 再利用可能なインスタンス | いいえ(関数呼び出し) | はい(一度構築して複数回呼び出し) |
| 構造化出力 | aiSdk.Output.object() |
aiSdk.Output.object() |
generateText から始めてください。会話状態または固定設定を持つ再利用可能なインスタンスが必要になったら Agent に移行してください。
import { generateText } from '@outputai/llm';
const { result } = await generateText( {
prompt: 'generate_summary@v1',
variables: {
company_name: input.name,
website_content: input.websiteContent
}
} );
Agent を @outputai/llm からインポート(ai から直接ではない)z を @outputai/core からインポート(zod からではない)prompts/ フォルダに存在する{{ variable }} プレースホルダと一致maxSteps を設定(スキルまたはツールに 10 以外の上限が必要な場合)aiSdk.Output.object({ schema }) で数値に .min()/.max() ではなく .describe() を使用messageStore は複数ターンの履歴が必要な場合にのみ使用fn 内で構築(モジュールレベルではない)stream() より generateWithStreaming() を優先output-dev-skill-file - エージェント用スキルファイルの作成output-dev-llm-streaming - ストリーミング進捗と Temporal 安全なエラー処理output-dev-prompt-file - エージェントが使用する .prompt ファイルの作成output-dev-step-function - ステップ関数でのエージェント使用output-dev-types-file - 構造化出力用 Zod スキーマの定義output-dev-workflow-function - エージェント駆動型ステップのオーケストレーションThe Agent class extends AI SDK's ToolLoopAgent with Output prompt files and the skills system. Use it when you need multi-step tool execution, conversation history, or a reusable agent instance. For single-shot LLM calls without tools, generateText is simpler.
aiSdk.Output.object()messageStoreonChunkAgent and generateTextimport { Agent, aiSdk } from '@outputai/llm';
import type { MessageStore } from '@outputai/llm';
import { z } from '@outputai/core';
Agent comes from @outputai/llm. Use aiSdk.Output for structured output. Import z from @outputai/core (never from zod directly). MessageStore is the type for a pluggable getMessages / addMessages store; implement it yourself.
The prompt file is loaded and rendered at construction time. Variables and tools are fixed at construction. Skills and maxSteps come from the prompt file. The agent is ready to call generate(), generateWithStreaming(), or stream() immediately.
const agent = new Agent( {
prompt: 'writing_assistant@v1',
variables: {
content_type: input.contentType,
focus: input.focus,
content: input.content
},
output: aiSdk.Output.object( { schema: reviewSchema } )
} );
| Option | Type | Default | Description |
|---|---|---|---|
prompt |
string |
(required) | Prompt file name (e.g. 'writing_assistant@v1') |
promptDir |
string |
- | Override the stack-resolved prompt directory |
variables |
PromptVariables |
- | Template variables rendered at construction |
tools |
AI SDK tools | - | Caller tools; merged with prompt YAML tools (load_skill last) |
stopWhen |
function or function[] | - | Custom stop condition (overrides prompt maxSteps when tools exist) |
output |
aiSdk.Output |
- | Structured output spec (e.g. aiSdk.Output.object({ schema })) |
messageStore |
MessageStore |
- | Pluggable store for multi-turn history |
Run the agent and return when complete:
const result = await agent.generate();
console.log( result.text ); // Generated text
console.log( result.output ); // Structured output (when using aiSdk.Output.object)
console.log( result.usage ); // Token counts
The result has the same shape as generateText: text, result (alias for text), output, usage, finishReason, toolCalls, etc.
Extend the conversation with extra messages:
const result = await agent.generate( {
messages: [ { role: 'user', content: 'Focus on the introduction section.' } ]
} );
Messages are appended after the initial prompt messages (and any message-store history). You can also pass abortSignal and toolChoice.
Use generateWithStreaming() when you need progress callbacks and a complete result:
const result = await agent.generateWithStreaming( {
onChunk( { chunk } ) {
if ( chunk.type === 'text-delta' ) {
process.stdout.write( chunk.text );
}
}
} );
The method behaves like generate() while using streaming internally. It returns the complete response, rejects on stream errors, and automatically appends messages to the configured message store. It accepts the same messages, abortSignal, and toolChoice as generate(), plus onChunk. Prefer it over stream() in Temporal activity steps unless direct access to the stream result is required.
Use stream() when direct control over textStream or fullStream is required. It accepts the same messages, abortSignal, and toolChoice as generate(), plus onChunk, onFinish, and onError:
const stream = await agent.stream();
for await ( const chunk of stream.textStream ) {
process.stdout.write( chunk );
}
Like streamText, the stream result provides textStream and fullStream iterables, plus promise-based properties (text, usage, finishReason) that resolve on completion.
stream() appends messages to the message store in its wrapped onFinish when finishReason is not 'error'. See output-dev-llm-streaming for streaming and error-handling guidance.
Use aiSdk.Output.object() to get typed responses:
const reviewSchema = z.object( {
issues: z.array( z.string() ).describe( 'List of issues found' ),
suggestions: z.array( z.string() ).describe( 'Actionable suggestions' ),
score: z.number().describe( 'Quality score 0-100' ),
summary: z.string().describe( 'Brief overall assessment' )
} );
const agent = new Agent( {
prompt: 'writing_assistant@v1',
variables: { content_type: 'documentation', focus: 'clarity', content: markdownContent },
output: aiSdk.Output.object( { schema: reviewSchema } )
} );
const { output } = await agent.generate();
// output: { issues: string[], suggestions: string[], score: number, summary: string }
Use .describe() on schema fields instead of .min()/.max() for number constraints. Anthropic does not support minimum/maximum JSON Schema constraints in tool definitions.
By default, Agent is stateless. Each generate() call starts fresh with only the initial prompt messages. Pass a messageStore to maintain history across calls:
import { Agent } from '@outputai/llm';
import type { MessageStore } from '@outputai/llm';
const messages: Parameters<MessageStore['addMessages']>[0] = [];
const messageStore: MessageStore = {
getMessages: () => messages,
addMessages: incoming => {
messages.push( ...incoming );
}
};
const chatbot = new Agent( {
prompt: 'chatbot@v1',
messageStore
} );
const r1 = await chatbot.generate( {
messages: [ { role: 'user', content: 'Hello, tell me about Output.' } ]
} );
// r1.text: "Output is an AI framework for..."
const r2 = await chatbot.generate( {
messages: [ { role: 'user', content: 'How does it handle retries?' } ]
} );
// r2 sees the full history from r1
MessageStore is:
interface MessageStore {
getMessages(): ModelMessage[] | Promise<ModelMessage[]>;
addMessages( messages: ModelMessage[] ): void | Promise<void>;
}
ModelMessage is an AI SDK type (aiSdk / ai). There is no built-in store. Implement the interface in memory for a single process, or with your database for durable history.
In workflow steps, construct a new Agent per invocation. Variables come from the step input:
import { step, z } from '@outputai/core';
import { Agent, aiSdk } from '@outputai/llm';
const reviewSchema = z.object( {
summary: z.string().describe( 'Brief assessment' ),
issues: z.array( z.string() ).describe( 'Problems found' ),
suggestions: z.array( z.string() ).describe( 'Improvements' ),
score: z.number().describe( 'Quality score 0-100' )
} );
export const reviewContent = step( {
name: 'reviewContent',
description: 'Review technical content using Agent with structured output',
inputSchema: z.object( {
content: z.string().describe( 'The content to review' ),
content_type: z.string().describe( 'Type of content' ),
focus: z.string().describe( 'Review focus areas' )
} ),
outputSchema: reviewSchema,
fn: async input => {
const agent = new Agent( {
prompt: 'writing_assistant@v1',
variables: input,
output: aiSdk.Output.object( { schema: reviewSchema } )
} );
const { output } = await agent.generate();
return output;
}
} );
This is the standard pattern. Each step invocation is independent, and Agent construction is cheap.
List skill paths in the prompt frontmatter. See output-dev-skill-file for the full skills guide.
generateText |
Agent |
|
|---|---|---|
| Best for | Single-shot LLM calls | Multi-step tool loops |
| Tools | Supported | Supported |
| Skills | Supported | Supported |
| Conversation history | Manual | Built-in with messageStore |
| Reusable instance | No (function call) | Yes (construct once, call many) |
| Structured output | aiSdk.Output.object() |
aiSdk.Output.object() |
Start with generateText. Move to Agent when you need conversation state or a reusable instance with a fixed configuration.
import { generateText } from '@outputai/llm';
const { result } = await generateText( {
prompt: 'generate_summary@v1',
variables: {
company_name: input.name,
website_content: input.websiteContent
}
} );
Agent from @outputai/llm (not from ai directly)z from @outputai/core (never from zod)prompts/ folder{{ variable }} placeholders in the promptmaxSteps when skills or tools need a ceiling other than 10aiSdk.Output.object({ schema }) uses .describe() not .min()/.max() on numbersmessageStore is only used when multi-turn history is neededfn (not at module level) for workflow stepsgenerateWithStreaming() when callbacks are sufficientoutput-dev-skill-file - Creating skill files for agentsoutput-dev-llm-streaming - Streaming progress and Temporal-safe error handlingoutput-dev-prompt-file - Creating .prompt files used by agentsoutput-dev-step-function - Using agents in step functionsoutput-dev-types-file - Defining Zod schemas for structured outputoutput-dev-workflow-function - Orchestrating agent-powered steps原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。