取り組みの背景 — ローコードツールの限界が見えてきた
Zapier、Make.com、n8n といったローコード・ノーコードのワークフローツールは、シンプルな自動化には非常に便利です。しかしLLM時代のAIエージェント運用において、以下のような限界が顕在化しています。
- カスタムロジックの制約: 複雑な条件分岐やエラーハンドリングをGUIで表現しきれない
- 長時間実行の不安定さ: 数時間にわたるAI推論タスクがタイムアウトする
- スケーラビリティの壁: 同時実行数やAPIコール回数の上限に達する
- コストの非効率: 実行回数課金モデルが、高頻度のAIエージェント処理と相性が悪い
Trigger.dev とは何か
Trigger.dev は、TypeScript/JavaScript で記述したバックグラウンドジョブを、信頼性の高いインフラ上で実行するためのプラットフォームです。
コア機能
- Durable Execution(耐久性のある実行): タスクが途中で失敗しても、チェックポイントから再開できます。数時間にわたるAI推論も安定して処理可能
- Durable Cron: cron スケジュールをコード内で宣言的に定義。外部のスケジューラに依存しない
- Webhook対応: 外部イベントをトリガーとしてタスクを即座に起動
- セルフホスティング対応: Docker Compose でローカル環境やプライベートクラウドに展開可能
- AI SDK統合: Anthropic Claude、Google Gemini、OpenAI などのSDKをTypeScriptで直接利用
なぜTypeScriptなのか
AIエージェントの処理をコードで書く最大のメリットは、完全な制御と再現性です。
// Trigger.dev のタスク定義(基本形)
import { task } from "@trigger.dev/sdk/v3";
export const myAiAgent = task({
id: "ai-research-agent",
// 最大実行時間: 4時間
maxDuration: 14400,
run: async (payload: { topic: string }) => {
// Step 1: 情報収集
const searchResults = await searchWeb(payload.topic);
// Step 2: AI分析
const analysis = await analyzeWithClaude(searchResults);
// Step 3: レポート生成
const report = await generateReport(analysis);
// Step 4: 通知
await sendSlackNotification(report);
return { status: "completed", report };
}
});
GUIでは表現しにくい「検索結果が不十分なら別のキーワードでリトライ」のようなロジックも、TypeScript なら自然に書けます。
ローコードツールとの比較
Zapier との違い
- 実行時間: Zapier は15分(Premiumで30分)で制限。Trigger.dev は数時間の実行に対応
- カスタムロジック: Zapier のCode by Zapier はNode.js/Pythonをサポートするが、外部パッケージの利用が制限されます。Trigger.dev はnpmの全パッケージを利用可能
- コスト: Zapier は実行回数(タスク数)課金。Trigger.dev はセルフホスティングなら固定費のみ
Make.com との違い
- 複雑なフロー: Make.com のシナリオビルダーは直感的ですが、20以上のモジュールを連結すると管理が困難に。コードなら関数分割で整理可能
- エラーハンドリング: Make.com のエラーハンドラはシナリオ単位。Trigger.dev はtry/catch で任意の粒度で制御
n8n との違い
- セルフホスティング: n8n もセルフホスティング対応だが、ワークフローの定義がJSON。Trigger.dev はTypeScriptで記述するため、IDEの補完・型チェック・テストの恩恵を受けられる
- バージョン管理: n8n のワークフローJSONをGitで管理するのは可能ですが、差分の読みやすさではTypeScriptコードが圧倒的に有利
実装: 自律AIリサーチエージェント
プロジェクトセットアップ
# Trigger.dev プロジェクトの初期化
npx create-trigger@latest ai-research-agent
cd ai-research-agent
# 依存パッケージのインストール
npm install @anthropic-ai/sdk @trigger.dev/sdk
Durable Cronによる定期実行
import { schedules } from "@trigger.dev/sdk/v3";
// 毎日午前9時にリサーチを実行
export const dailyResearch = schedules.task({
id: "daily-ai-research",
cron: "0 9 * * *",
maxDuration: 7200, // 最大2時間
run: async () => {
const topics = await fetchTodayTopics();
for (const topic of topics) {
// 各トピックを並列で処理
await myAiAgent.trigger({ topic });
}
}
});
多段階AI推論の実装
import { task, wait } from "@trigger.dev/sdk/v3";
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic();
export const multiStepResearch = task({
id: "multi-step-research",
maxDuration: 14400,
run: async (payload: { query: string; depth: number }) => {
const results: string[] = [];
// Phase 1: 初回調査
const initialResearch = await anthropic.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 4096,
messages: [{
role: "user",
content: `以下のトピックについて調査し、さらに深掘りすべきサブトピックを3つ提案してください: ${payload.query}`
}]
});
results.push(initialResearch.content[0].type === "text"
? initialResearch.content[0].text : "");
// Phase 2: サブトピックの深掘り(再帰的に実行可能)
if (payload.depth > 0) {
const subtopics = extractSubtopics(results[0]);
for (const subtopic of subtopics) {
// 各サブトピックを独立したタスクとして実行
const subResult = await multiStepResearch.triggerAndWait({
query: subtopic,
depth: payload.depth - 1
});
results.push(JSON.stringify(subResult));
}
}
// Phase 3: 統合レポート生成
const finalReport = await anthropic.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 8192,
messages: [{
role: "user",
content: `以下の調査結果を統合し、包括的なレポートを作成してください:\n${results.join("\n---\n")}`
}]
});
return {
query: payload.query,
report: finalReport.content[0].type === "text"
? finalReport.content[0].text : "",
depth: payload.depth,
subtopicCount: results.length - 1
};
}
});
function extractSubtopics(text: string): string[] {
// テキストからサブトピックを抽出するロジック
const lines = text.split("\n").filter(l => l.match(/^\d+\./));
return lines.slice(0, 3).map(l => l.replace(/^\d+\.\s*/, ""));
}
Webhook によるイベント駆動
import { task } from "@trigger.dev/sdk/v3";
// 外部イベント(GitHub Issue作成など)をトリガー
export const onNewIssue = task({
id: "github-issue-analyzer",
run: async (payload: { title: string; body: string; repo: string }) => {
// Issue の内容をAIで分析
const analysis = await anthropic.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
messages: [{
role: "user",
content: `以下のGitHub Issueを分析し、優先度・カテゴリ・推奨対応を提案してください:\nTitle: ${payload.title}\nBody: ${payload.body}`
}]
});
// 分析結果をSlackに通知
await sendSlackMessage({
channel: "#dev-alerts",
text: analysis.content[0].type === "text"
? analysis.content[0].text : "Analysis failed"
});
return { analyzed: true };
}
});
セルフホスティング構成
Docker Compose による構築
# docker-compose.yml
version: "3.8"
services:
trigger-dev:
image: ghcr.io/triggerdotdev/trigger.dev:latest
ports:
- "3030:3030"
environment:
- DATABASE_URL=postgresql://trigger:password@postgres:5432/trigger
- REDIS_URL=redis://redis:6379
- SECRET_KEY=your-secret-key
depends_on:
- postgres
- redis
postgres:
image: postgres:16
environment:
- POSTGRES_USER=trigger
- POSTGRES_PASSWORD=password
- POSTGRES_DB=trigger
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
# 起動
docker compose up -d
# ダッシュボードにアクセス
# http://localhost:3030
本番環境のベストプラクティス
- リソース監視: PostgreSQL と Redis のメモリ使用量を監視し、タスクキューの肥大化を防ぐ
- ログの外部保存: タスク実行ログを CloudWatch や Grafana Loki に転送する
- バックアップ: PostgreSQL の定期バックアップを設定する(タスク定義と実行履歴が保存されている)
- Tailscale連携: リモートアクセスが必要な場合、Tailscale でセキュアなメッシュVPNを構成する
運用アーキテクチャの全体像
24時間自律運用を実現するためのアーキテクチャを整理します。
┌─ MacBook / サーバー ─────────────────────────┐
│ │
│ [Trigger.dev (Docker)] │
│ │ │
│ ├── Durable Cron → 定期タスク実行 │
│ ├── Webhook → イベント駆動タスク │
│ └── Manual → オンデマンド実行 │
│ │
│ [AI SDKs] │
│ ├── Anthropic Claude │
│ ├── Google Gemini │
│ └── その他LLM │
│ │
│ [外部連携] │
│ ├── Slack(通知) │
│ ├── GitHub(Issue/PR監視) │
│ └── データベース(結果永続化) │
│ │
│ [Tailscale] ← リモートアクセス │
└──────────────────────────────────────────────┘
個人開発者の視点から(実体験メモ)
ここまでの要点
AIエージェントの自律運用において、ローコードツールの限界を超えるには「コードで徹底的に管理する」アプローチが合理的です。Trigger.dev は、TypeScript による表現力、Durable Execution による信頼性、セルフホスティングによるコスト最適化の3つを兼ね備えたプラットフォームです。