ドラフト エージェント設計パターン - 推論技術

agentic-designreasoninglangchainlanggraphaitypescript
By sko X opus 4.19/21/202513 min read

LangChain、LangGraph、TypeScriptを使用してサーバーレス環境でChain-of-Thought(CoT)、Tree-of-Thought(ToT)、Graph-of-Thought(GoT)、セルフリフレクションパターンなどの高度な推論技術を実装する方法を学びます。

メンタルモデル:交響楽団

推論技術を交響楽団として考えてみましょう。異なるセクション(推論パターン)が協力して複雑な調和(ソリューション)を生み出します。指揮者(LangGraph)が複数の楽器(エージェント)を調整します - 弦楽器は線形推論(CoT)を処理し、木管楽器は変化を探求し(ToT)、金管楽器はフィードバックを提供し(セルフリフレクション)、打楽器はリズム(状態管理)を維持します。音楽家がソロまたはアンサンブルで演奏できるように、エージェントも独立して推論したり、より豊かな結果のために協力したりできます。

基本例:Chain-of-Thought推論

1. 基本的なCoTエージェントのセットアップ

// app/agents/cot-agent/route.ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { StateGraph, Annotation } from "@langchain/langgraph";
import { HumanMessage, AIMessage, BaseMessage } from "@langchain/core/messages";
import { z } from "zod";
import { map, reduce } from "es-toolkit";

// 推論状態を定義
const ReasoningState = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (x, y) => x.concat(y),
    default: () => [],
  }),
  reasoning_steps: Annotation<string[]>({
    reducer: (x, y) => x.concat(y),
    default: () => [],
  }),
  final_answer: Annotation<string>({
    reducer: (_, y) => y,
    default: () => "",
  }),
});

// 推論チェーンを作成
const model = new ChatGoogleGenerativeAI({
  modelName: "gemini-pro",
  temperature: 0.7,
});

// CoT推論ノード
async function reasoningNode(state: typeof ReasoningState.State) {
  const cotPrompt = `あなたは推論エージェントです。問題を段階的に分解してください。

問題: ${state.messages[state.messages.length - 1].content}

これを段階的に考えてください:
1. まず、解決しようとしているものを特定する
2. より小さな部分に分解する
3. 各部分を解決する
4. ソリューションを組み合わせる

応答を以下の形式でフォーマットしてください:
ステップ 1: [推論]
ステップ 2: [推論]
...
最終回答: [答え]`;

  const response = await model.invoke([
    new HumanMessage(cotPrompt)
  ]);

  // レスポンスを解析
  const content = response.content as string;
  const steps = content.match(/ステップ \d+: (.+)/g) || [];
  const finalAnswer = content.match(/最終回答: (.+)/)?.[1] || "";

  return {
    messages: [response],
    reasoning_steps: steps,
    final_answer: finalAnswer,
  };
}

// グラフを構築
const workflow = new StateGraph(ReasoningState)
  .addNode("reason", reasoningNode)
  .addEdge("__start__", "reason")
  .addEdge("reason", "__end__");

const app = workflow.compile();

// APIルートハンドラー
export async function POST(request: Request) {
  const { question } = await request.json();

  const result = await app.invoke({
    messages: [new HumanMessage(question)],
  });

  return Response.json({
    reasoning_steps: result.reasoning_steps,
    final_answer: result.final_answer,
  });
}

基本的なCoTエージェントは問題を順次推論ステップに分解します。各ステップは前のステップを基に構築され、論理的な思考の連鎖を作成します。

2. React Queryを使用したフロントエンド統合

// app/components/ReasoningAgent.tsx
'use client';

import { useMutation } from '@tanstack/react-query';
import { useState } from 'react';
import { map } from 'es-toolkit';

interface ReasoningResponse {
  reasoning_steps: string[];
  final_answer: string;
}

async function queryReasoning(question: string): Promise<ReasoningResponse> {
  const response = await fetch('/agents/cot-agent', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ question }),
  });
  return response.json();
}

export function ReasoningAgent() {
  const [question, setQuestion] = useState('');

  const mutation = useMutation({
    mutationFn: queryReasoning,
  });

  return (
    <div className="card bg-base-100 shadow-xl">
      <div className="card-body">
        <h2 className="card-title">Chain-of-Thought推論</h2>

        <textarea
          className="textarea textarea-bordered"
          placeholder="複雑な質問をしてください..."
          value={question}
          onChange={(e) => setQuestion(e.target.value)}
        />

        <button
          className="btn btn-primary"
          onClick={() => mutation.mutate(question)}
          disabled={mutation.isPending}
        >
          {mutation.isPending ? '推論中...' : '推論を開始'}
        </button>

        {mutation.isSuccess && (
          <div className="mt-4 space-y-2">
            <div className="text-sm opacity-70">推論ステップ:</div>
            {map(mutation.data.reasoning_steps, (step, idx) => (
              <div key={idx} className="p-2 bg-base-200 rounded">
                {step}
              </div>
            ))}
            <div className="divider"></div>
            <div className="alert alert-success">
              <span>{mutation.data.final_answer}</span>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

React Queryは非同期状態管理を処理し、UIは推論ステップを段階的に表示します。

高度な例:ToTとセルフリフレクションによるマルチエージェント推論

1. 並列探索を使用したTree-of-Thought

// app/agents/advanced-reasoning/tree-of-thought.ts
import { StateGraph, Annotation, Send } from "@langchain/langgraph";
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { BaseMessage, HumanMessage, AIMessage } from "@langchain/core/messages";
import { z } from "zod";
import { maxBy, sortBy, filter, map, chunk } from "es-toolkit";
import { RunnableConfig } from "@langchain/core/runnables";

// 思考ノード構造を定義
const ThoughtSchema = z.object({
  id: z.string(),
  content: z.string(),
  score: z.number(),
  parent_id: z.string().optional(),
  depth: z.number(),
});

type Thought = z.infer<typeof ThoughtSchema>;

// 思考ツリーを持つ状態定義
const ToTState = Annotation.Root({
  problem: Annotation<string>(),
  thoughts: Annotation<Thought[]>({
    reducer: (x, y) => [...x, ...y],
    default: () => [],
  }),
  current_depth: Annotation<number>({
    reducer: (_, y) => y,
    default: () => 0,
  }),
  best_solution: Annotation<string>({
    reducer: (_, y) => y,
    default: () => "",
  }),
  exploration_paths: Annotation<string[][]>({
    reducer: (x, y) => [...x, ...y],
    default: () => [],
  }),
});

const model = new ChatGoogleGenerativeAI({
  modelName: "gemini-pro",
  temperature: 0.8,
});

// 複数の思考を並列生成
async function generateThoughts(
  state: typeof ToTState.State,
  config: RunnableConfig
): Promise<Partial<typeof ToTState.State>> {
  const parentThoughts = filter(
    state.thoughts,
    (t) => t.depth === state.current_depth - 1
  );

  // 親の思考がない場合は、元の問題を使用
  const prompts = parentThoughts.length > 0
    ? map(parentThoughts, (parent) => ({
        parent_id: parent.id,
        prompt: `この推論ステップを踏まえて:"${parent.content}"
        ${state.problem}を解決するための3つの異なる方法を生成してください。
        創造的になり、異なるアプローチを探索してください。`,
      }))
    : [{
        parent_id: "root",
        prompt: `問題:${state.problem}
        この問題を解決するための3つの異なる初期アプローチを生成してください。`,
      }];

  // 思考を並列生成
  const thoughtPromises = map(prompts, async ({ parent_id, prompt }) => {
    const response = await model.invoke([new HumanMessage(prompt)]);
    const content = response.content as string;

    // レスポンスから複数の思考を解析
    const thoughtTexts = content.split('\n').filter(line => line.trim());

    return map(thoughtTexts.slice(0, 3), (text, idx) => ({
      id: `${parent_id}-${state.current_depth}-${idx}`,
      content: text,
      score: 0,
      parent_id,
      depth: state.current_depth,
    }));
  });

  const allThoughts = (await Promise.all(thoughtPromises)).flat();

  return {
    thoughts: allThoughts,
  };
}

// 品質に基づいて思考をスコアリング
async function scoreThoughts(
  state: typeof ToTState.State
): Promise<Partial<typeof ToTState.State>> {
  const currentThoughts = filter(
    state.thoughts,
    (t) => t.depth === state.current_depth && t.score === 0
  );

  const scoringPrompt = `問題「${state.problem}」に対するこれらのソリューションアプローチを評価してください
  以下に基づいて0-10でスコアを付けてください:
  - 論理的一貫性
  - ソリューションへの進展
  - 創造性

  アプローチ:
  ${map(currentThoughts, (t, i) => `${i + 1}. ${t.content}`).join('\n')}

  スコアを次のように返してください:[score1, score2, ...]`;

  const response = await model.invoke([new HumanMessage(scoringPrompt)]);
  const scores = JSON.parse((response.content as string).match(/\[[\d,\s]+\]/)?.[0] || "[]");

  const scoredThoughts = map(currentThoughts, (thought, idx) => ({
    ...thought,
    score: scores[idx] || 0,
  }));

  // スコア付けされた思考のみを更新
  const updatedThoughts = map(state.thoughts, (t) => {
    const scored = scoredThoughts.find(st => st.id === t.id);
    return scored || t;
  });

  return {
    thoughts: updatedThoughts,
  };
}

// 低スコアのブランチを剪定
async function pruneThoughts(
  state: typeof ToTState.State
): Promise<Partial<typeof ToTState.State>> {
  const currentThoughts = filter(
    state.thoughts,
    (t) => t.depth === state.current_depth
  );

  // 思考の上位40%を保持
  const sorted = sortBy(currentThoughts, [(t) => -t.score]);
  const keepCount = Math.max(2, Math.floor(sorted.length * 0.4));
  const keepIds = new Set(map(sorted.slice(0, keepCount), t => t.id));

  const prunedThoughts = filter(state.thoughts, (t) =>
    t.depth < state.current_depth || keepIds.has(t.id)
  );

  return {
    thoughts: prunedThoughts,
  };
}

// 探索を続けるかどうかをチェック
function shouldContinue(state: typeof ToTState.State): "expand" | "synthesize" {
  const MAX_DEPTH = 3;
  return state.current_depth < MAX_DEPTH ? "expand" : "synthesize";
}

// 最良のパスから最終的なソリューションを合成
async function synthesizeSolution(
  state: typeof ToTState.State
): Promise<Partial<typeof ToTState.State>> {
  // 最良のリーフノードを見つける
  const leafThoughts = filter(
    state.thoughts,
    (t) => t.depth === state.current_depth
  );

  const bestLeaf = maxBy(leafThoughts, (t) => t.score);

  if (!bestLeaf) {
    return { best_solution: "ソリューションが見つかりません" };
  }

  // ルートまで辿る
  const path: Thought[] = [];
  let current: Thought | undefined = bestLeaf;

  while (current) {
    path.unshift(current);
    current = state.thoughts.find(t => t.id === current?.parent_id);
  }

  const synthesisPrompt = `この推論パスから完全なソリューションを合成してください:
  ${map(path, (t, i) => `ステップ ${i + 1}: ${t.content}`).join('\n')}

  ${state.problem}に対する明確で包括的な答えを提供してください`;

  const response = await model.invoke([new HumanMessage(synthesisPrompt)]);

  return {
    best_solution: response.content as string,
    exploration_paths: [map(path, t => t.content)],
  };
}

// Tree-of-Thoughtワークフローを構築
export function createToTWorkflow() {
  const workflow = new StateGraph(ToTState)
    .addNode("generate", generateThoughts)
    .addNode("score", scoreThoughts)
    .addNode("prune", pruneThoughts)
    .addNode("synthesize", synthesizeSolution)
    .addEdge("__start__", "generate")
    .addEdge("generate", "score")
    .addEdge("score", "prune")
    .addConditionalEdges(
      "prune",
      shouldContinue,
      {
        expand: "generate",
        synthesize: "synthesize",
      }
    )
    .addEdge("synthesize", "__end__");

  return workflow.compile();
}

Tree-of-Thoughtは複数の推論パスを並列に探索し、最適なソリューションを見つけるためにスコアリングと剪定を行います。

2. ソリューション改良のためのセルフリフレクションエージェント

// app/agents/advanced-reasoning/self-reflection.ts
import { StateGraph, Annotation } from "@langchain/langgraph";
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { BaseMessage, HumanMessage } from "@langchain/core/messages";
import { z } from "zod";
import { reduce, filter, last } from "es-toolkit";

// 批評履歴を持つリフレクション状態
const ReflectionState = Annotation.Root({
  problem: Annotation<string>(),
  current_solution: Annotation<string>({
    reducer: (_, y) => y,
  }),
  critiques: Annotation<Array<{
    critique: string;
    suggestions: string[];
    score: number;
  }>>({
    reducer: (x, y) => [...x, ...y],
    default: () => [],
  }),
  iteration: Annotation<number>({
    reducer: (_, y) => y,
    default: () => 0,
  }),
  final_solution: Annotation<string>({
    reducer: (_, y) => y,
    default: () => "",
  }),
});

const model = new ChatGoogleGenerativeAI({
  modelName: "gemini-pro",
  temperature: 0.7,
});

// アクター:初期ソリューションを生成
async function generateSolution(
  state: typeof ReflectionState.State
): Promise<Partial<typeof ReflectionState.State>> {
  const lastCritique = last(state.critiques);

  const prompt = lastCritique
    ? `問題:${state.problem}

      前のソリューション:${state.current_solution}

      批評:${lastCritique.critique}
      提案:${lastCritique.suggestions.join(', ')}

      これらのポイントに対処する改善されたソリューションを生成してください。`
    : `この問題を解決してください:${state.problem}

      明確な推論を持つ詳細なソリューションを提供してください。`;

  const response = await model.invoke([new HumanMessage(prompt)]);

  return {
    current_solution: response.content as string,
    iteration: state.iteration + 1,
  };
}

// エバリュエーター:ソリューションを批評
async function evaluateSolution(
  state: typeof ReflectionState.State
): Promise<Partial<typeof ReflectionState.State>> {
  const critiquePrompt = `このソリューションを批判的に評価してください:

  問題:${state.problem}
  ソリューション:${state.current_solution}

  提供してください:
  1. 弱点を特定する詳細な批評
  2. 改善のための具体的な提案
  3. 0-10のスコア

  JSON形式で:{
    "critique": "...",
    "suggestions": ["...", "..."],
    "score": 0
  }`;

  const response = await model.invoke([new HumanMessage(critiquePrompt)]);

  try {
    const evaluation = JSON.parse(response.content as string);

    return {
      critiques: [evaluation],
    };
  } catch {
    // JSON解析が失敗した場合のフォールバック
    return {
      critiques: [{
        critique: response.content as string,
        suggestions: [],
        score: 5,
      }],
    };
  }
}

// ソリューションが十分良いかチェック
function shouldContinueReflection(
  state: typeof ReflectionState.State
): "reflect" | "finalize" {
  const MAX_ITERATIONS = 3;
  const GOOD_SCORE = 8;

  const lastCritique = last(state.critiques);

  if (state.iteration >= MAX_ITERATIONS) {
    return "finalize";
  }

  if (lastCritique && lastCritique.score >= GOOD_SCORE) {
    return "finalize";
  }

  return "reflect";
}

// 最良のソリューションを最終化
async function finalizeSolution(
  state: typeof ReflectionState.State
): Promise<Partial<typeof ReflectionState.State>> {
  return {
    final_solution: state.current_solution,
  };
}

// セルフリフレクションワークフローを構築
export function createReflectionWorkflow() {
  const workflow = new StateGraph(ReflectionState)
    .addNode("generate", generateSolution)
    .addNode("evaluate", evaluateSolution)
    .addNode("finalize", finalizeSolution)
    .addEdge("__start__", "generate")
    .addEdge("generate", "evaluate")
    .addConditionalEdges(
      "evaluate",
      shouldContinueReflection,
      {
        reflect: "generate",
        finalize: "finalize",
      }
    )
    .addEdge("finalize", "__end__");

  return workflow.compile();
}

セルフリフレクションは批評と改良サイクルを通じてソリューションを反復的に改善します。

3. 複数の推論パターンのオーケストレーション

// app/agents/advanced-reasoning/orchestrator.ts
import { StateGraph, Annotation, Send } from "@langchain/langgraph";
import { createToTWorkflow } from "./tree-of-thought";
import { createReflectionWorkflow } from "./self-reflection";
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { HumanMessage } from "@langchain/core/messages";
import { z } from "zod";
import { maxBy, map } from "es-toolkit";

// マスターオーケストレーター状態
const OrchestratorState = Annotation.Root({
  problem: Annotation<string>(),
  problem_type: Annotation<string>({
    reducer: (_, y) => y,
    default: () => "unknown",
  }),
  tot_result: Annotation<{
    solution: string;
    paths: string[][];
  }>(),
  reflection_result: Annotation<{
    solution: string;
    iterations: number;
  }>(),
  final_answer: Annotation<string>({
    reducer: (_, y) => y,
    default: () => "",
  }),
  reasoning_method: Annotation<string>({
    reducer: (_, y) => y,
    default: () => "",
  }),
});

const model = new ChatGoogleGenerativeAI({
  modelName: "gemini-pro",
  temperature: 0.3,
});

// 推論戦略を選択するために問題を分類
async function classifyProblem(
  state: typeof OrchestratorState.State
): Promise<Partial<typeof OrchestratorState.State>> {
  const classificationPrompt = `最適な推論アプローチを決定するためにこの問題を分類してください:

  問題:${state.problem}

  カテゴリ:
  - "exploratory":複数のソリューションパスが必要な問題(Tree-of-Thoughtを使用)
  - "refinement":反復的な改善が必要な問題(セルフリフレクションを使用)
  - "hybrid":探索と改良の両方が必要な複雑な問題

  カテゴリ名のみを返してください。`;

  const response = await model.invoke([new HumanMessage(classificationPrompt)]);
  const problemType = (response.content as string).toLowerCase().trim();

  return {
    problem_type: problemType,
  };
}

// Tree-of-Thought推論を実行
async function runToT(
  state: typeof OrchestratorState.State
): Promise<Partial<typeof OrchestratorState.State>> {
  const totWorkflow = createToTWorkflow();

  const result = await totWorkflow.invoke({
    problem: state.problem,
    thoughts: [],
    current_depth: 0,
  });

  return {
    tot_result: {
      solution: result.best_solution,
      paths: result.exploration_paths,
    },
    reasoning_method: "Tree-of-Thought",
  };
}

// セルフリフレクション推論を実行
async function runReflection(
  state: typeof OrchestratorState.State
): Promise<Partial<typeof OrchestratorState.State>> {
  const reflectionWorkflow = createReflectionWorkflow();

  const result = await reflectionWorkflow.invoke({
    problem: state.problem,
    current_solution: "",
    critiques: [],
    iteration: 0,
  });

  return {
    reflection_result: {
      solution: result.final_solution,
      iterations: result.iteration,
    },
    reasoning_method: "セルフリフレクション",
  };
}

// 複数の推論方法から結果を統合
async function synthesizeResults(
  state: typeof OrchestratorState.State
): Promise<Partial<typeof OrchestratorState.State>> {
  let solutions = [];

  if (state.tot_result) {
    solutions.push({
      method: "Tree-of-Thought",
      solution: state.tot_result.solution,
    });
  }

  if (state.reflection_result) {
    solutions.push({
      method: "セルフリフレクション",
      solution: state.reflection_result.solution,
    });
  }

  if (solutions.length === 1) {
    return {
      final_answer: solutions[0].solution,
    };
  }

  // 複数のソリューションがある場合、それらを統合
  const synthesisPrompt = `これらのソリューションを包括的な答えに統合してください:

  問題:${state.problem}

  ${map(solutions, s => `${s.method}ソリューション:\n${s.solution}`).join('\n\n')}

  各アプローチからの最良の洞察を組み合わせた最終的な答えを作成してください。`;

  const response = await model.invoke([new HumanMessage(synthesisPrompt)]);

  return {
    final_answer: response.content as string,
    reasoning_method: "ハイブリッド(ToT + セルフリフレクション)",
  };
}

// 問題タイプに基づいてルーティング
function routeReasoning(state: typeof OrchestratorState.State): string | string[] {
  switch (state.problem_type) {
    case "exploratory":
      return "tot";
    case "refinement":
      return "reflection";
    case "hybrid":
      return ["tot", "reflection"];
    default:
      return "tot"; // デフォルトのフォールバック
  }
}

// マスターオーケストレーターを作成
export function createReasoningOrchestrator() {
  const workflow = new StateGraph(OrchestratorState)
    .addNode("classify", classifyProblem)
    .addNode("tot", runToT)
    .addNode("reflection", runReflection)
    .addNode("synthesize", synthesizeResults)
    .addEdge("__start__", "classify")
    .addConditionalEdges(
      "classify",
      routeReasoning,
      {
        tot: "tot",
        reflection: "reflection",
      }
    )
    .addEdge("tot", "synthesize")
    .addEdge("reflection", "synthesize")
    .addEdge("synthesize", "__end__");

  return workflow.compile();
}

// ストリーミングを使用したAPIルートハンドラー
export async function POST(request: Request) {
  const { problem } = await request.json();

  const orchestrator = createReasoningOrchestrator();

  // ストリーミングレスポンスを作成
  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      try {
        // イベントが発生したらストリーミング
        for await (const event of orchestrator.streamEvents(
          { problem },
          { version: "v2" }
        )) {
          if (event.event === "on_chain_stream") {
            const chunk = encoder.encode(
              `data: ${JSON.stringify({
                type: "progress",
                node: event.name,
                data: event.data,
              })}\n\n`
            );
            controller.enqueue(chunk);
          }
        }

        // 最終結果を取得
        const result = await orchestrator.invoke({ problem });

        const finalChunk = encoder.encode(
          `data: ${JSON.stringify({
            type: "complete",
            answer: result.final_answer,
            method: result.reasoning_method,
            tot_result: result.tot_result,
            reflection_result: result.reflection_result,
          })}\n\n`
        );

        controller.enqueue(finalChunk);
        controller.close();
      } catch (error) {
        controller.error(error);
      }
    },
  });

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

オーケストレーターは問題の特性に基づいて推論戦略を賢く選択し、組み合わせます。

4. リアルタイムストリーミングを使用したフロントエンド

// app/components/AdvancedReasoningAgent.tsx
'use client';

import { useState, useCallback } from 'react';
import { useMutation } from '@tanstack/react-query';
import { map, groupBy } from 'es-toolkit';

interface StreamEvent {
  type: 'progress' | 'complete';
  node?: string;
  data?: any;
  answer?: string;
  method?: string;
  tot_result?: any;
  reflection_result?: any;
}

export function AdvancedReasoningAgent() {
  const [problem, setProblem] = useState('');
  const [events, setEvents] = useState<StreamEvent[]>([]);
  const [isStreaming, setIsStreaming] = useState(false);

  const startReasoning = useCallback(async () => {
    setIsStreaming(true);
    setEvents([]);

    try {
      const response = await fetch('/agents/advanced-reasoning/orchestrator', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ problem }),
      });

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

      if (!reader) throw new Error('リーダーが利用できません');

      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));
            setEvents(prev => [...prev, data]);
          }
        }
      }
    } catch (error) {
      console.error('ストリーミングエラー:', error);
    } finally {
      setIsStreaming(false);
    }
  }, [problem]);

  const completeEvent = events.find(e => e.type === 'complete');
  const progressEvents = events.filter(e => e.type === 'progress');

  return (
    <div className="max-w-4xl mx-auto p-6 space-y-6">
      <div className="card bg-base-100 shadow-xl">
        <div className="card-body">
          <h2 className="card-title">高度なマルチエージェント推論</h2>

          <textarea
            className="textarea textarea-bordered h-32"
            placeholder="深い推論が必要な複雑な問題を入力してください..."
            value={problem}
            onChange={(e) => setProblem(e.target.value)}
          />

          <button
            className={`btn btn-primary ${isStreaming ? 'loading' : ''}`}
            onClick={startReasoning}
            disabled={isStreaming || !problem}
          >
            {isStreaming ? '推論中...' : '高度な推論を開始'}
          </button>
        </div>
      </div>

      {progressEvents.length > 0 && (
        <div className="card bg-base-200">
          <div className="card-body">
            <h3 className="font-semibold">推論の進行状況</h3>
            <div className="space-y-2">
              {map(progressEvents, (event, idx) => (
                <div key={idx} className="flex items-center gap-2">
                  <div className="badge badge-primary">{event.node}</div>
                  <span className="text-sm opacity-70">処理中...</span>
                </div>
              ))}
            </div>
          </div>
        </div>
      )}

      {completeEvent && (
        <div className="space-y-4">
          <div className="card bg-success text-success-content">
            <div className="card-body">
              <h3 className="card-title">最終回答</h3>
              <p className="whitespace-pre-wrap">{completeEvent.answer}</p>
              <div className="card-actions justify-end">
                <div className="badge badge-outline">
                  方法:{completeEvent.method}
                </div>
              </div>
            </div>
          </div>

          {completeEvent.tot_result && (
            <div className="card bg-base-100">
              <div className="card-body">
                <h4 className="font-semibold">Tree-of-Thought探索</h4>
                <div className="text-sm space-y-1">
                  {map(completeEvent.tot_result.paths[0], (step, idx) => (
                    <div key={idx} className="pl-4 border-l-2 border-primary">
                      ステップ {idx + 1}: {step}
                    </div>
                  ))}
                </div>
              </div>
            </div>
          )}

          {completeEvent.reflection_result && (
            <div className="card bg-base-100">
              <div className="card-body">
                <h4 className="font-semibold">セルフリフレクションプロセス</h4>
                <p className="text-sm opacity-70">
                  {completeEvent.reflection_result.iterations}回の反復により洗練
                </p>
              </div>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

フロントエンドは推論プロセスのリアルタイムフィードバックを段階的な更新で提供します。

パフォーマンス最適化

// app/lib/reasoning-cache.ts
import { LRUCache } from 'lru-cache';
import { createHash } from 'crypto';

// 推論結果のセマンティックキャッシング
const reasoningCache = new LRUCache<string, any>({
  max: 100,
  ttl: 1000 * 60 * 60, // 1時間
  updateAgeOnGet: true,
});

export function getCacheKey(problem: string, method: string): string {
  return createHash('sha256')
    .update(`${problem}-${method}`)
    .digest('hex');
}

export async function withCache<T>(
  key: string,
  fn: () => Promise<T>
): Promise<T> {
  const cached = reasoningCache.get(key);
  if (cached) {
    console.log(`キーのキャッシュヒット:${key}`);
    return cached;
  }

  const result = await fn();
  reasoningCache.set(key, result);
  return result;
}

// 並列処理ヘルパー
export async function parallelReasoning<T>(
  tasks: Array<() => Promise<T>>,
  maxConcurrency: number = 3
): Promise<T[]> {
  const results: T[] = [];
  const executing: Promise<void>[] = [];

  for (const task of tasks) {
    const promise = task().then(result => {
      results.push(result);
    });

    executing.push(promise);

    if (executing.length >= maxConcurrency) {
      await Promise.race(executing);
      executing.splice(executing.findIndex(p => p === promise), 1);
    }
  }

  await Promise.all(executing);
  return results;
}

キャッシングと並列処理により、レイテンシとコストを大幅に削減します。

まとめ

推論技術はエージェントを単純な応答者から賢い問題解決者に変換します。線形の問題に対しては基本的なChain-of-Thoughtから始め、探索のためにTree-of-Thought、改良のためにセルフリフレクションを段階的に追加します。オーケストレーターパターンにより、問題の特性に基づいて推論戦略を動的に選択できます。本番環境のパフォーマンスのために、キャッシング、ストリーミング、並列処理を実装することを忘れないでください。これらのパターンは、LangGraphのステートフル管理とTypeScriptの型安全性と組み合わせることで、サーバーレス環境で複雑な実世界の問題に取り組むことができる堅牢な推論システムを作成します。