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 を組み合わせて使用します。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 ツール | - | 呼び出し側のツール。プロンプト 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: '導入部に焦点を当ててください。' } ]
} );
メッセージは初期プロンプトメッセージ(およびメッセージストア履歴)の後に追加されます。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 または stream に直接制御が必要な場合は、stream() を使用します。generate() と同じ messages、abortSignal、toolChoice に加えて onChunk、onEnd、onError を受け付けます:
const stream = await agent.stream();
for await ( const chunk of stream.textStream ) {
process.stdout.write( chunk );
}
streamText と同様に、ストリーム結果は textStream と stream の反復可能オブジェクト、および完了時に解決するプロミスベースのプロパティ(text、usage、finishReason)を提供します。
stream() は finishReason が 'error' でない場合、ラップされた onEnd でメッセージストアにメッセージを追加します。ストリーミングとエラーハンドリングのガイダンスは output-dev-llm-streaming を参照してください。
aiSdk.Output.object() を使用して型付きの応答を取得します:
const reviewSchema = z.object( {
issues: z.array( z.string() ).describe( '見つかった問題のリスト' ),
suggestions: z.array( z.string() ).describe( '実行可能な改善案' ),
score: z.number().describe( '品質スコア 0-100' ),
summary: z.string().describe( '簡潔な全体評価' )
} );
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 }
スキーマフィールドでは .min()/.max() ではなく .describe() を使用して、数値の制約を指定してください。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: 'こんにちは、Output について教えてください。' } ]
} );
// r1.text: "Output は AI フレームワークで..."
const r2 = await chatbot.generate( {
messages: [ { role: 'user', content: 'リトライはどのように処理されますか?' } ]
} );
// r2 は r1 の全履歴を確認します
MessageStore は以下の通りです:
interface MessageStore {
getMessages(): ModelMessage[] | Promise<ModelMessage[]>;
addMessages( messages: ModelMessage[] ): void | Promise<void>;
}
ModelMessage は aiSdk 名前空間を通じて、または ai からのインポートで利用可能な AI SDK 型です。組み込みストアはありません。単一プロセス用にメモリ内でインターフェースを実装するか、永続的な履歴をデータベースで実装してください。
ワークフロー ステップでは、呼び出しごとに新しい Agent を構築してください。変数はステップの入力から取得されます:
import { step, z } from '@outputai/core';
import { Agent, aiSdk } from '@outputai/llm';
const reviewSchema = z.object( {
summary: z.string().describe( '簡潔な評価' ),
issues: z.array( z.string() ).describe( '見つかった問題' ),
suggestions: z.array( z.string() ).describe( '改善点' ),
score: z.number().describe( '品質スコア 0-100' )
} );
export const reviewContent = step( {
name: 'reviewContent',
description: 'Agent を使用して技術コンテンツをレビューし、構造化出力を生成',
inputSchema: z.object( {
content: z.string().describe( 'レビュー対象のコンテンツ' ),
content_type: z.string().describe( 'コンテンツタイプ' ),
focus: z.string().describe( 'レビュー焦点エリア' )
} ),
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 を設定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 uses an internal AI SDK ToolLoopAgent through composition with Output prompt files and the skills system. It does not inherit from ToolLoopAgent. 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 stream is required. It accepts the same messages, abortSignal, and toolChoice as generate(), plus onChunk, onEnd, 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 stream iterables, plus promise-based properties (text, usage, finishReason) that resolve on completion.
stream() appends messages to the message store in its wrapped onEnd 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 available through the aiSdk namespace or as an import from 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 による自動翻訳です。