デモで動くAIエージェントを作るのは簡単です。しかし、プロダクション環境で確実に動作するものを作るのは、まったく別のレベルのエンジニアリング課題です。
プロダクションシステムは、障害が起きたときに、実ユーザー・実データ・実際の影響(結果)を扱わなければなりません。
これが、Brainfy AI と Navlyt の両方で私が使っているプロダクション向けエージェントのアーキテクチャであり、実際のコードパターンと、私が周辺で設計する失敗モードも含まれます。
デモ用エージェントとプロダクション用エージェントが異なる理由
デモ用エージェントは「うまくいく道(ハッピーパス)」の最適化を行います。
プロダクション用エージェントは、次を処理する必要があります:
実データのばらつき
プロダクションの入力はごちゃごちゃしていて、曖昧で、さまざまなエッジケースで満ちています。同時実行
共有状態を持ちながら、複数のエージェントインスタンスが同時に動作します。長時間タスク
エージェントは、数分または数時間かかる可能性があり、そのため耐久性のある実行状態が必要です。コスト管理
混乱したエージェントが不要なツール呼び出しを繰り返すと、すぐに高額になり得ます。観測可能性(Observability)
エージェントが何を、なぜ決めたのかを、正確に理解できる必要があります。
コアアーキテクチャ:耐久性のあるエージェント状態
最も重要なプロダクション上の判断:
エージェントの状態はメモリではなくデータベースに保持する。
メモリ内の状態:
- サーバーとともに消える
- 水平方向にスケールできない
- 監査できない
データベースの状態:
- 再起動後も残る
- 水平スケーリングを可能にする
- 観測可能性を提供する
- デバッグを可能にする
例のスキーマ:
-- エージェント実行状態テーブル
CREATE TABLE agent_executions (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id UUID REFERENCES auth.users NOT NULL,
agent_type TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
CONSTRAINT valid_status CHECK (
status IN (
'pending',
'running',
'completed',
'failed',
'cancelled',
'awaiting_review'
)
),
input_data JSONB NOT NULL,
state JSONB DEFAULT '{}',
result JSONB,
error TEXT,
step_count INTEGER DEFAULT 0,
token_count INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
completed_at TIMESTAMPTZ
);
-- 観測可能性のためのツール呼び出しログ
CREATE TABLE agent_tool_calls (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
execution_id UUID REFERENCES agent_executions NOT NULL,
step_number INTEGER NOT NULL,
tool_name TEXT NOT NULL,
tool_input JSONB NOT NULL,
tool_output JSONB,
status TEXT NOT NULL DEFAULT 'pending',
latency_ms INTEGER,
error TEXT,
called_at TIMESTAMPTZ DEFAULT NOW()
);
本番環境での安全策付きのエージェントループ
プロダクション用エージェントには厳格な上限が必要です。
例の安全策:
- ステップ数の上限
- トークン数の上限
- タイムアウトの上限
- 失敗条件
例のTypeScriptループ:
// lib/agents/production-agent.ts
const AGENT_LIMITS = {
maxSteps: 25,
maxTokens: 50_000,
stepTimeoutMs: 30_000,
totalTimeoutMs: 300_000
};
export async function runAgent(
executionId: string,
supabase: SupabaseClient
): Promise<void> {const startTime = Date.now()
let execution = await loadExecution(
executionId,
supabase
)
await updateStatus(
executionId,
'running',
supabase
)
while (true) {
const elapsed =
Date.now() - startTime
if (execution.step_count >= AGENT_LIMITS.maxSteps){
await failWithReason(
executionId,
'MAX_STEPS_EXCEEDED',
supabase
)
return
}
if (execution.token_count >= AGENT_LIMITS.maxTokens){
await failWithReason(
executionId,
'MAX_TOKENS_EXCEEDED',
supabase
)
return
}
if (elapsed >= AGENT_LIMITS.totalTimeoutMs){
await failWithReason(
executionId,
'TOTAL_TIMEOUT',
supabase
)
return
}
const response =
await callModel(messages, TOOLS)
execution.step_count++
execution.token_count +=
response.usage?.total_tokens ?? 0
await persistState(
executionId,
execution,
supabase
)
}
人間の関与(Human-in-the-Loop)のゲート
取り消しが難しいアクションについては、人間の承認を要求します。
エージェント:
- アクションを準備する
- ステータスをawaiting_reviewに設定する
- 実行を停止する
- 承認を待つ
例:
const APPROVAL_REQUIRED_TOOLS = [
'send_email',
'update_customer_record',
'generate_compliance_document',
'submit_to_regulator'
]
async function executeToolCall(
toolCall,
executionId,
supabase
){
if(APPROVAL_REQUIRED_TOOLS.includes(name)){
await updateStatus(
executionId,
'awaiting_review',
supabase
)
throw new AgentPausedError(
'Human approval required'
)
}
return await callTool(name,args)
}
監視:本番環境で私が追跡すること
監視する指標:
- ステップ効率
- ツールの成功率
- 人間のレビューへのエスカレーション率
- 完了あたりのトークンコスト
- 完了率
ヘルスクエリの例:
const { data } =
await supabase.rpc(
'agent_health_metrics',
{
agent_type:
'compliance_document_generator',
since:
new Date(
Date.now() -
7 * 24 * 60 * 60 * 1000
).toISOString()
}
)
典型的な結果:
- 完了率: 94%
- 平均ステップ数: 8.3
- 人間のレビュー率: 3.1%
重要な学び
プロダクションエージェントには、次が必要です:
- 耐久性のある状態
- 厳格な実行制限
- 可観測性
- コスト管理
- 人間による承認のゲート
ほとんどの失敗は、モデルの品質不足ではなく、保護策の欠落によって起こります。
著者について
Tilak Raj
Founder & CEO — Brainfy AI
コンプライアンス、不動産、農業、航空分野にまたがる垂直型AI SaaSを構築しています。
Webサイト: https://www.tilakraj.info
プロジェクト: https://www.tilakraj.info/projects
プロダクションエージェントについての質問は?コメントしてください—すべてに返信します。