ドラフト エージェント設計パターン - ゴール設定

agentic-designailangchainlanggraphtypescriptvercelgoal-setting
By sko X opus 4.19/20/202513 min read

複雑な目標を自律的に分解し、進捗を追跡し、戦略を適応させる知的エージェントを構築 - すべてVercelのサーバーレスインフラ上で効率的に動作

メンタルモデル:プロジェクトマネージャーエージェント

ゴール設定エージェントは、高レベルな目標を受け取り、それを実行可能なタスクに分解する専門のプロジェクトマネージャーのように考えてください。PMが「新製品をローンチする」をスプリント、タスク、サブタスクに分解し、進捗を監視して計画を調整するように、私たちのエージェントは目標を階層構造に分解し、実行状態を追跡し、進捗に基づいて戦略を適応させます - すべてTypeScriptとLangGraphのグラフベースオーケストレーションを通じて。

基本例:シンプルなゴール分解エージェント

1. ゴールエージェントの状態を定義

// app/agents/goal/state.ts
import { Annotation } from "@langchain/langgraph";
import { BaseMessage } from "@langchain/core/messages";

export const GoalAgentState = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (current, update) => current.concat(update),
    default: () => []
  }),
  currentGoal: Annotation<string>({
    reducer: (current, update) => update || current,
    default: () => ""
  }),
  subGoals: Annotation<string[]>({
    reducer: (current, update) => {
      if (Array.isArray(update)) return update;
      return current.concat(update);
    },
    default: () => []
  }),
  completedSubGoals: Annotation<string[]>({
    reducer: (current, update) => current.concat(update),
    default: () => []
  }),
  goalStatus: Annotation<"planning" | "executing" | "completed" | "failed">({
    reducer: (current, update) => update || current,
    default: () => "planning"
  })
});

この状態スキーマは、LangGraphの型安全なAnnotationシステムを使用して、ゴール階層と実行ステータスを追跡します。

2. ゴール分解ノードを作成

// app/agents/goal/nodes/decompose.ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { HumanMessage, AIMessage } from "@langchain/core/messages";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { map, chunk } from "es-toolkit";

const SubGoalsSchema = z.object({
  subGoals: z.array(z.object({
    task: z.string().describe("具体的で実行可能なタスク"),
    priority: z.number().min(1).max(5).describe("優先度レベル1-5"),
    dependencies: z.array(z.string()).describe("先に完了すべきタスク")
  }))
});

export async function decomposeGoal(state: typeof GoalAgentState.State) {
  const model = new ChatGoogleGenerativeAI({
    modelName: "gemini-pro",
    temperature: 0.3
  });

  const prompt = `この目標を具体的で実行可能なサブタスクに分解してください:
目標: ${state.currentGoal}

タスク間の依存関係を考慮し、優先度を割り当ててください。`;

  const response = await model.invoke([
    new HumanMessage(prompt)
  ], {
    functions: [{
      name: "decompose_goal",
      description: "目標をサブタスクに分解する",
      parameters: zodToJsonSchema(SubGoalsSchema)
    }],
    function_call: { name: "decompose_goal" }
  });

  const functionCall = response.additional_kwargs.function_call;
  const decomposition = JSON.parse(functionCall?.arguments || "{}");

  // 優先度と依存関係でソート
  const sortedGoals = decomposition.subGoals
    .sort((a: any, b: any) => {
      if (a.dependencies.length === 0 && b.dependencies.length > 0) return -1;
      if (b.dependencies.length === 0 && a.dependencies.length > 0) return 1;
      return b.priority - a.priority;
    });

  const subGoalTasks = map(sortedGoals, (goal: any) => goal.task);

  return {
    messages: [response],
    subGoals: subGoalTasks,
    goalStatus: "executing" as const
  };
}

分解ノードは構造化出力を使用して、優先度付けされ依存関係を考慮したサブタスクに目標を分解します。

3. ゴールエージェントグラフを構築

// app/agents/goal/graph.ts
import { StateGraph, END } from "@langchain/langgraph";
import { GoalAgentState } from "./state";
import { decomposeGoal } from "./nodes/decompose";
import { executeSubGoal } from "./nodes/execute";
import { evaluateProgress } from "./nodes/evaluate";

export function createGoalAgent() {
  const workflow = new StateGraph(GoalAgentState)
    .addNode("decompose", decomposeGoal)
    .addNode("execute", executeSubGoal)
    .addNode("evaluate", evaluateProgress)
    .addEdge("decompose", "execute")
    .addEdge("execute", "evaluate")
    .addConditionalEdges(
      "evaluate",
      async (state) => {
        if (state.goalStatus === "completed") return "end";
        if (state.subGoals.length > state.completedSubGoals.length) return "execute";
        return "end";
      },
      {
        execute: "execute",
        end: END
      }
    );

  return workflow.compile();
}

グラフは完了まで、ゴール分解、実行、進捗評価をループで調整します。

4. APIルートハンドラー

// app/api/agent/goal/route.ts
import { NextRequest, NextResponse } from "next/server";
import { createGoalAgent } from "@/agents/goal/graph";
import { HumanMessage } from "@langchain/core/messages";

export async function POST(req: NextRequest) {
  const { goal } = await req.json();

  const agent = createGoalAgent();

  const result = await agent.invoke({
    messages: [new HumanMessage(`目標を達成する: ${goal}`)],
    currentGoal: goal
  });

  return NextResponse.json({
    goal,
    subGoals: result.subGoals,
    completedSubGoals: result.completedSubGoals,
    status: result.goalStatus
  });
}

サーバーレス環境でゴール処理をトリガーするシンプルなAPIエンドポイント。

5. フロントエンド統合

// app/components/GoalTracker.tsx
"use client";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { groupBy } from "es-toolkit";

export function GoalTracker() {
  const [goal, setGoal] = useState("");

  const goalMutation = useMutation({
    mutationFn: async (goal: string) => {
      const res = await fetch("/api/agent/goal", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ goal })
      });
      return res.json();
    }
  });

  return (
    <div className="card bg-base-100 shadow-xl">
      <div className="card-body">
        <h2 className="card-title">ゴール設定エージェント</h2>

        <input
          type="text"
          placeholder="目標を入力してください..."
          className="input input-bordered w-full"
          value={goal}
          onChange={(e) => setGoal(e.target.value)}
        />

        <button
          className="btn btn-primary"
          onClick={() => goalMutation.mutate(goal)}
          disabled={goalMutation.isPending}
        >
          {goalMutation.isPending ? "処理中..." : "目標を設定"}
        </button>

        {goalMutation.data && (
          <div className="mt-4">
            <div className="badge badge-outline">
              {goalMutation.data.status}
            </div>

            <div className="divider">サブゴール</div>

            <ul className="space-y-2">
              {goalMutation.data.subGoals.map((subGoal: string, idx: number) => (
                <li key={idx} className="flex items-center gap-2">
                  <input
                    type="checkbox"
                    className="checkbox checkbox-sm"
                    checked={goalMutation.data.completedSubGoals.includes(subGoal)}
                    readOnly
                  />
                  <span className="text-sm">{subGoal}</span>
                </li>
              ))}
            </ul>
          </div>
        )}
      </div>
    </div>
  );
}

ゴール提出と進捗追跡のためのTanStack Queryを使用したReactコンポーネント。

高度な例:自律ゴール監視システム

1. 監視メトリクスを含む拡張状態

// app/agents/advanced-goal/state.ts
import { Annotation } from "@langchain/langgraph";
import { BaseMessage } from "@langchain/core/messages";

interface GoalMetrics {
  startTime: number;
  estimatedCompletion: number;
  actualProgress: number;
  blockers: string[];
  adjustments: number;
}

export const AdvancedGoalState = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (current, update) => current.concat(update),
    default: () => []
  }),
  currentGoal: Annotation<string>(),
  subGoals: Annotation<Array<{
    id: string;
    task: string;
    status: "pending" | "in_progress" | "completed" | "failed";
    progress: number;
    dependencies: string[];
    estimatedHours: number;
    actualHours: number;
  }>>({
    reducer: (current, update) => {
      if (Array.isArray(update)) return update;
      // 既存のサブゴールの更新をマージ
      return current.map(goal => {
        const updateItem = update.find((u: any) => u.id === goal.id);
        return updateItem ? { ...goal, ...updateItem } : goal;
      });
    },
    default: () => []
  }),
  metrics: Annotation<GoalMetrics>({
    reducer: (current, update) => ({ ...current, ...update }),
    default: () => ({
      startTime: Date.now(),
      estimatedCompletion: 0,
      actualProgress: 0,
      blockers: [],
      adjustments: 0
    })
  }),
  strategy: Annotation<"waterfall" | "parallel" | "adaptive">({
    default: () => "adaptive"
  }),
  humanApproval: Annotation<boolean>({
    default: () => false
  })
});

高度な状態には詳細なメトリクス、戦略選択、ヒューマン・イン・ザ・ループフラグが含まれます。

2. 依存関係を考慮した知的ゴール計画

// app/agents/advanced-goal/nodes/planner.ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { z } from "zod";
import { partition, sortBy, filter } from "es-toolkit";
import { v4 as uuidv4 } from "uuid";

const PlanSchema = z.object({
  plan: z.object({
    approach: z.string(),
    reasoning: z.string(),
    subGoals: z.array(z.object({
      task: z.string(),
      estimatedHours: z.number(),
      dependencies: z.array(z.string()),
      skills: z.array(z.string()),
      priority: z.enum(["critical", "high", "medium", "low"])
    })),
    risks: z.array(z.string()),
    successCriteria: z.array(z.string())
  })
});

export async function createExecutionPlan(state: typeof AdvancedGoalState.State) {
  const model = new ChatGoogleGenerativeAI({
    modelName: "gemini-pro",
    temperature: 0.2
  });

  const planningPrompt = `この目標の詳細な実行計画を作成してください:
目標: ${state.currentGoal}

分析して以下を提供してください:
1. 全体的なアプローチと理由付け
2. 時間見積もり付きの詳細なサブタスク
3. タスクの依存関係(他のタスクの前に完了すべきタスク)
4. 各タスクに必要なスキル/リソース
5. 潜在的なリスクと阻害要因
6. 明確な成功基準

並列実行の機会とクリティカルパス最適化を考慮してください。`;

  const response = await model.withStructuredOutput(PlanSchema).invoke([
    { role: "system", content: "あなたは目標分解と実行戦略を専門とする専門的なプロジェクトプランナーです。" },
    { role: "user", content: planningPrompt }
  ]);

  // 計画を実行可能なサブゴールに変換
  const subGoals = response.plan.subGoals.map((goal, idx) => ({
    id: uuidv4(),
    task: goal.task,
    status: "pending" as const,
    progress: 0,
    dependencies: goal.dependencies,
    estimatedHours: goal.estimatedHours,
    actualHours: 0,
    priority: goal.priority
  }));

  // 推定完了時間を計算
  const criticalPath = calculateCriticalPath(subGoals);
  const estimatedCompletion = Date.now() + (criticalPath * 60 * 60 * 1000);

  // 最適戦略を決定
  const [independent, dependent] = partition(
    subGoals,
    g => g.dependencies.length === 0
  );

  const strategy = independent.length > dependent.length ? "parallel" : "waterfall";

  return {
    subGoals,
    metrics: {
      estimatedCompletion,
      actualProgress: 0,
      blockers: response.plan.risks,
      adjustments: 0
    },
    strategy,
    messages: [{
      role: "assistant",
      content: `計画作成完了: ${response.plan.approach}\n戦略: ${strategy}`
    }]
  };
}

function calculateCriticalPath(goals: any[]): number {
  // シンプルなクリティカルパス計算
  const goalMap = new Map(goals.map(g => [g.task, g]));

  const calculatePath = (goalId: string, visited = new Set()): number => {
    if (visited.has(goalId)) return 0;
    visited.add(goalId);

    const goal = goalMap.get(goalId);
    if (!goal) return 0;

    const depTimes = goal.dependencies.map((d: string) =>
      calculatePath(d, visited)
    );

    return goal.estimatedHours + Math.max(0, ...depTimes);
  };

  return Math.max(...goals.map(g => calculatePath(g.task)));
}

高度なプランナーは依存関係分析とクリティカルパス最適化を含む詳細な実行計画を作成します。

3. 監視を伴う並列実行

// app/agents/advanced-goal/nodes/executor.ts
import { Send } from "@langchain/langgraph";
import { filter, map, take } from "es-toolkit";

export async function parallelExecutor(state: typeof AdvancedGoalState.State) {
  // 実行可能なサブゴールを見つける(保留中の依存関係がない)
  const executableGoals = filter(state.subGoals, goal => {
    if (goal.status !== "pending") return false;

    const deps = goal.dependencies;
    if (deps.length === 0) return true;

    return deps.every(depTask => {
      const depGoal = state.subGoals.find(g => g.task === depTask);
      return depGoal?.status === "completed";
    });
  });

  if (executableGoals.length === 0) {
    return { goalStatus: "blocked" };
  }

  // 最大3つのゴールを並列実行
  const toExecute = take(executableGoals, 3);

  // 並列実行にSend APIを使用
  return toExecute.map(goal =>
    new Send("execute_single", {
      goalId: goal.id,
      task: goal.task,
      parentGoal: state.currentGoal
    })
  );
}

export async function executeSingleGoal({ goalId, task, parentGoal }: any) {
  // 進捗更新を伴うゴール実行をシミュレート
  const steps = 5;
  const updates = [];

  for (let i = 1; i <= steps; i++) {
    await new Promise(resolve => setTimeout(resolve, 100)); // 作業をシミュレート

    updates.push({
      id: goalId,
      progress: (i / steps) * 100,
      actualHours: (i / steps) * 2
    });
  }

  return {
    subGoals: [{
      id: goalId,
      status: "completed",
      progress: 100
    }],
    messages: [{
      role: "assistant",
      content: `完了: ${task}`
    }]
  };
}

並列実行者は独立したタスクを特定し、LangGraphのSend APIを使用して同時に実行します。

4. リアルタイム監視と適応

// app/agents/advanced-goal/nodes/monitor.ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { mean, sum, filter } from "es-toolkit";

export async function monitorAndAdapt(state: typeof AdvancedGoalState.State) {
  const model = new ChatGoogleGenerativeAI({ modelName: "gemini-pro" });

  // 進捗メトリクスを計算
  const completedCount = filter(state.subGoals, g => g.status === "completed").length;
  const totalCount = state.subGoals.length;
  const overallProgress = (completedCount / totalCount) * 100;

  // 遅延を確認
  const actualHours = sum(state.subGoals.map(g => g.actualHours));
  const estimatedHours = sum(state.subGoals.map(g => g.estimatedHours));
  const scheduleVariance = ((actualHours - estimatedHours) / estimatedHours) * 100;

  // 阻害要因を特定
  const stuckGoals = filter(state.subGoals,
    g => g.status === "in_progress" && g.progress < 30
  );

  // 適応戦略調整
  if (scheduleVariance > 20 || stuckGoals.length > 0) {
    const adaptationPrompt = `現在のゴール進捗:
- 全体: ${overallProgress.toFixed(1)}%
- スケジュール乖離: ${scheduleVariance.toFixed(1)}%
- ブロックされたタスク: ${stuckGoals.map(g => g.task).join(", ")}

軌道修正のための戦略調整を提案してください。`;

    const response = await model.invoke([
      { role: "system", content: "あなたはプロジェクト復旧の専門家です。" },
      { role: "user", content: adaptationPrompt }
    ]);

    // 必要に応じて再計画をトリガー
    if (scheduleVariance > 50) {
      return {
        strategy: "adaptive" as const,
        metrics: {
          adjustments: state.metrics.adjustments + 1,
          actualProgress: overallProgress
        },
        messages: [response],
        humanApproval: true // 大きな変更には人間の承認を要求
      };
    }
  }

  return {
    metrics: {
      actualProgress: overallProgress
    },
    goalStatus: overallProgress === 100 ? "completed" : "executing"
  };
}

監視機能は継続的に進捗を追跡し、ボトルネックを特定し、必要に応じて適応的な再計画をトリガーします。

5. 長期実行ゴールのための永続化レイヤー

// app/agents/advanced-goal/persistence.ts
import { kv } from "@vercel/kv";
import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";

export class GoalPersistence {
  private checkpointer: SqliteSaver;

  constructor() {
    this.checkpointer = new SqliteSaver("/tmp/goals.db");
  }

  async saveGoalState(goalId: string, state: any) {
    // 高速アクセスのためVercel KVに保存
    await kv.hset(`goal:${goalId}`, {
      currentGoal: state.currentGoal,
      status: state.goalStatus,
      progress: state.metrics.actualProgress,
      subGoals: JSON.stringify(state.subGoals),
      lastUpdated: Date.now()
    });

    // 30日間の有効期限を設定
    await kv.expire(`goal:${goalId}`, 30 * 24 * 60 * 60);
  }

  async getGoalState(goalId: string) {
    const state = await kv.hgetall(`goal:${goalId}`);
    if (state && state.subGoals) {
      state.subGoals = JSON.parse(state.subGoals as string);
    }
    return state;
  }

  async getActiveGoals(userId: string) {
    const pattern = `goal:${userId}:*`;
    const keys = await kv.keys(pattern);

    const goals = await Promise.all(
      keys.map(key => kv.hgetall(key))
    );

    return goals.filter(g => g && g.status !== "completed");
  }
}

永続化レイヤーは状態ストレージにVercel KVを使用し、サーバーレス関数の呼び出し間でのゴール追跡を可能にします。

6. ヒューマン・イン・ザ・ループを含む完全なグラフ

// app/agents/advanced-goal/graph.ts
import { StateGraph, END } from "@langchain/langgraph";
import { AdvancedGoalState } from "./state";
import { createExecutionPlan } from "./nodes/planner";
import { parallelExecutor, executeSingleGoal } from "./nodes/executor";
import { monitorAndAdapt } from "./nodes/monitor";

export function createAdvancedGoalAgent() {
  const workflow = new StateGraph(AdvancedGoalState)
    .addNode("plan", createExecutionPlan)
    .addNode("parallel_execute", parallelExecutor)
    .addNode("execute_single", executeSingleGoal)
    .addNode("monitor", monitorAndAdapt)
    .addNode("human_review", async (state) => {
      // 人間の入力のための中断
      return interrupt({
        message: "計画調整が必要です",
        currentPlan: state.subGoals,
        suggestedChanges: state.messages[state.messages.length - 1]
      });
    });

  // エッジを定義
  workflow
    .addEdge("plan", "parallel_execute")
    .addEdge("execute_single", "monitor")
    .addEdge("parallel_execute", "monitor")
    .addConditionalEdges(
      "monitor",
      async (state) => {
        if (state.humanApproval) return "human_review";
        if (state.goalStatus === "completed") return "end";
        if (state.goalStatus === "blocked") return "plan";
        return "parallel_execute";
      },
      {
        human_review: "human_review",
        plan: "plan",
        parallel_execute: "parallel_execute",
        end: END
      }
    )
    .addEdge("human_review", "plan");

  return workflow.compile({
    checkpointer: new SqliteSaver("/tmp/advanced_goals.db")
  });
}

完全なグラフは計画、並列実行、監視、必要に応じた人間の介入を調整します。

7. リアルタイムストリーミングAPI

// app/api/agent/advanced-goal/stream/route.ts
import { NextRequest } from "next/server";
import { createAdvancedGoalAgent } from "@/agents/advanced-goal/graph";
import { GoalPersistence } from "@/agents/advanced-goal/persistence";

export async function POST(req: NextRequest) {
  const { goal, userId } = await req.json();
  const goalId = `${userId}:${Date.now()}`;
  const persistence = new GoalPersistence();

  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      const agent = createAdvancedGoalAgent();

      // イベントが発生するたびにストリーミング
      for await (const event of agent.stream({
        currentGoal: goal,
        messages: []
      }, {
        streamMode: "updates",
        configurable: { thread_id: goalId }
      })) {
        // 進捗更新を送信
        const update = {
          type: "progress",
          goalId,
          data: event
        };

        controller.enqueue(
          encoder.encode(`data: ${JSON.stringify(update)}\n\n`)
        );

        // 定期的に状態を保存
        if (event.monitor) {
          await persistence.saveGoalState(goalId, event.monitor);
        }
      }

      controller.close();
    }
  });

  return new Response(stream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      "Connection": "keep-alive",
    },
  });
}

ストリーミングAPIは、進捗追跡UIに最適な、ゴールが処理される際のリアルタイム更新を提供します。

8. 高度なフロントエンドダッシュボード

// app/components/AdvancedGoalDashboard.tsx
"use client";
import { useState, useEffect } from "react";
import { useQuery, useMutation } from "@tanstack/react-query";
import { groupBy, sortBy, filter } from "es-toolkit";

interface Goal {
  id: string;
  task: string;
  status: string;
  progress: number;
  dependencies: string[];
}

export function AdvancedGoalDashboard() {
  const [goalInput, setGoalInput] = useState("");
  const [streamData, setStreamData] = useState<any[]>([]);

  const startGoal = useMutation({
    mutationFn: async (goal: string) => {
      const response = await fetch("/api/agent/advanced-goal/stream", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ goal, userId: "user123" })
      });

      if (!response.body) throw new Error("ストリームなし");

      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        const chunk = decoder.decode(value);
        const lines = chunk.split("\n");

        for (const line of lines) {
          if (line.startsWith("data: ")) {
            const data = JSON.parse(line.slice(6));
            setStreamData(prev => [...prev, data]);
          }
        }
      }
    }
  });

  // ステータス別にゴールをグループ化
  const latestUpdate = streamData[streamData.length - 1];
  const subGoals = latestUpdate?.data?.monitor?.subGoals || [];
  const goalsByStatus = groupBy(subGoals, (g: Goal) => g.status);

  return (
    <div className="container mx-auto p-4">
      <div className="card bg-base-100 shadow-xl mb-6">
        <div className="card-body">
          <h2 className="card-title text-2xl">高度なゴール設定・監視</h2>

          <div className="form-control">
            <div className="input-group">
              <input
                type="text"
                placeholder="目標を入力してください..."
                className="input input-bordered flex-1"
                value={goalInput}
                onChange={(e) => setGoalInput(e.target.value)}
              />
              <button
                className="btn btn-primary"
                onClick={() => startGoal.mutate(goalInput)}
                disabled={startGoal.isPending}
              >
                {startGoal.isPending ? (
                  <span className="loading loading-spinner"></span>
                ) : (
                  "ゴール開始"
                )}
              </button>
            </div>
          </div>
        </div>
      </div>

      {subGoals.length > 0 && (
        <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
          {/* 保留中のタスク */}
          <div className="card bg-base-200">
            <div className="card-body">
              <h3 className="card-title text-lg">
                保留中 ({goalsByStatus.pending?.length || 0})
              </h3>
              <div className="space-y-2">
                {(goalsByStatus.pending || []).map((goal: Goal) => (
                  <div key={goal.id} className="bg-base-100 p-3 rounded">
                    <div className="text-sm font-medium">{goal.task}</div>
                    {goal.dependencies.length > 0 && (
                      <div className="text-xs text-base-content/60 mt-1">
                        待機中: {goal.dependencies.join(", ")}
                      </div>
                    )}
                  </div>
                ))}
              </div>
            </div>
          </div>

          {/* 実行中 */}
          <div className="card bg-warning/20">
            <div className="card-body">
              <h3 className="card-title text-lg">
                実行中 ({goalsByStatus.in_progress?.length || 0})
              </h3>
              <div className="space-y-2">
                {(goalsByStatus.in_progress || []).map((goal: Goal) => (
                  <div key={goal.id} className="bg-base-100 p-3 rounded">
                    <div className="text-sm font-medium">{goal.task}</div>
                    <progress
                      className="progress progress-warning w-full mt-2"
                      value={goal.progress}
                      max="100"
                    />
                    <div className="text-xs text-right mt-1">
                      {goal.progress}%
                    </div>
                  </div>
                ))}
              </div>
            </div>
          </div>

          {/* 完了 */}
          <div className="card bg-success/20">
            <div className="card-body">
              <h3 className="card-title text-lg">
                完了 ({goalsByStatus.completed?.length || 0})
              </h3>
              <div className="space-y-2">
                {(goalsByStatus.completed || []).map((goal: Goal) => (
                  <div key={goal.id} className="bg-base-100 p-3 rounded">
                    <div className="text-sm font-medium line-through">
                      {goal.task}
                    </div>
                    <div className="badge badge-success badge-sm mt-1">
                      完了
                    </div>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>
      )}

      {/* ライブ更新フィード */}
      {streamData.length > 0 && (
        <div className="card bg-base-100 shadow-xl mt-6">
          <div className="card-body">
            <h3 className="card-title">ライブ更新</h3>
            <div className="h-48 overflow-y-auto space-y-1">
              {streamData.slice(-10).reverse().map((update, idx) => (
                <div key={idx} className="text-sm">
                  <span className="badge badge-ghost badge-sm mr-2">
                    {new Date().toLocaleTimeString()}
                  </span>
                  <span className="text-base-content/80">
                    {update.type}: {JSON.stringify(update.data).slice(0, 100)}...
                  </span>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

リアルタイムストリーミング更新、かんばん風のタスク可視化、進捗追跡を備えた本格的なダッシュボード。

結論

エージェント設計パターンにおけるゴール設定は、静的な目標を動的で自己管理するシステムに変換します。LangGraphのグラフベースオーケストレーション、TypeScriptの型安全性、Vercelのサーバーレスインフラを活用することで、目標を自律的に分解し、進捗を追跡し、戦略を適応させる本番対応のエージェントを構築できます。このパターンの力は、構造化された計画と適応的な実行を組み合わせることにあります - 最高のプロジェクトマネージャーのように、私たちのエージェントは徹底的に計画し、効率的に実行し、必要に応じて方向転換することができ、すべて完全な可観測性と人間の監視機能を維持しながら実現します。