本番環境で実際に機能するAIエージェントを構築する:私の技術的アプローチ

Dev.to / 2026/3/26

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical Usage

要点

  • デモではうまく動くAIエージェントが、本番環境では失敗しがちな理由として、現実のデータの混沌、並行性、長時間実行タスク、コスト制約、そして観測可能性(オブザーバビリティ)の必要性を挙げています。
  • 記事では、プロダクション向けの中核となるアーキテクチャ上の判断として、メモリではなくデータベースに耐久性のあるエージェントの状態を保存し、再起動に耐えられるようにしつつ、水平スケーリングを可能にし、監査/デバッグも行えるようにすることを示します。
  • 著者が設計する重要な本番上の懸念事項として、想定外の入力エッジケースへの対応や、複数のエージェント実行が同時に走る際の共有状態の管理が説明されています。
  • 本番環境のエージェントには追跡可能性(トレーサビリティ)が不可欠だと強調しており、チームはエージェントが何を、なぜ判断したのかを正確に把握できる必要があり、それにより失敗の診断と信頼性の改善につなげます。

デモで動く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

プロダクションエージェントについての質問は?コメントしてください—すべてに返信します。