Skip to content
Published on

AIハーネスとは何か:Skills、Context、Hooks、PermissionsでAIを制御するオーケストレーションアーキテクチャ

Authors

1. AIハーネスとは? — なぜLLMだけでは不十分なのか

Raw LLMの限界(げんかい)

GPT-4o、Claude Sonnet、Gemini Proのような大規模言語モデル(LLM)は驚異的(きょういてき)な能力を持っています。しかし、モデル単体では実用的なAIシステムを作ることはできません。

Raw LLMに「プロジェクトのPRをレビューして」と頼むとどうなるでしょうか?

  • プロジェクトコードを読めません(ツールなし)
  • どのコーディング規約に従うべきか知りません(コンテキストなし)
  • git diffを実行できません(権限なし)
  • 以前のレビュー履歴を覚えていません(記憶なし)
  • レビュー後に自動でコメントを付けられません(ワークフローなし)

LLMは強力なエンジンですが、エンジンだけでは自動車にはなりません。

馬(うま)にハーネスを装着(そうちゃく)する

「Harness(ハーネス)」とは、元々馬に装着する馬具(ばぐ)を意味します。野生の馬は巨大な力を持っていますが、ハーネスなしではその力を望む方向に使うことができません。ハーネスを装着してこそ、馬車を引き、畑を耕し、荷物を運ぶことができます。

AIハーネスも同じ原理です:

  • 野生馬(やせいば) = Raw LLM(GPT-4、Claude、Gemini)
  • 馬具(ばぐ) = AIハーネス(システムプロンプト、ツール、権限、スキル、フック)
  • 馬車(ばしゃ)・畑(はたけ) = 実際の業務(コードレビュー、データ分析、カスタマーサポート)

馬具がよく設計されていれば馬の力を最大限に活用でき、設計が悪ければ馬がとんでもない方向に走ったり、危険な行動をとったりします。

Raw LLM vs Harnessed LLMの比較(ひかく)

項目Raw LLMHarnessed LLM
ツールアクセスなしファイル読み書き、API呼び出し、DBクエリ
コンテキスト会話内容のみプロジェクト構造、コードベース、ドキュメント
権限無制限(またはゼロ)きめ細かい権限制御
記憶セッション内の会話のみ長期記憶、プロジェクト履歴
ワークフローなしスキル、フック、パイプライン
安全装置モデル自体の安全性のみガードレール、権限モデル、入出力検証
一貫性プロンプトに依存システムプロンプトで安定化

2025年AIエンジニアリングの重心移動(じゅうしんいどう)

2023年まで、AIエンジニアリングの核心はモデル訓練でした。より大きく、より賢いモデルを作ることが目標でした。

2025年、重心は完全に移動しました:モデルオーケストレーションが核心です。

その理由:

  1. 基盤モデルが十分に強力になった — Claude Sonnet 4やGPT-4oは大半のタスクに十分な知能を持っています
  2. 差別化はハーネスで起こる — 同じモデルを使ってもハーネスの設計によって結果が大きく異なります
  3. エンタープライズ要件 — セキュリティ、監査、権限管理、コスト追跡が必須になりました
  4. 自律エージェントの台頭 — Devin、Claude Code、GitHub Copilot Agentなどすべてが精巧なハーネスを使用しています

AIハーネスは2025-2026年AIエンジニアリングの最も重要な概念です。


2. ハーネスの7つの構成要素(こうせいようそ)

AIハーネスは7つの核心的な構成要素で成り立っています。それぞれを深く見ていきましょう。

2-1. System Prompt(基本ルール)

システムプロンプトはAIの**憲法(けんぽう)**です。AIがどんな役割を担い、どんなルールに従い、どんな制約を守るべきかを最上位レベルで定義します。

システムプロンプトの構成要素

  1. 役割定義: AIが何であり、どんな専門性を持つか
  2. 行動ルール: どのように応答し行動すべきか
  3. 制約事項: 絶対にしてはいけないこと
  4. 出力形式: 応答の形態と構造
  5. 安全ルール: セキュリティ、プライバシー、著作権に関するルール

Claude Codeのシステムプロンプト構造

Claude Codeは非常に精巧なシステムプロンプトを使用しています:

You are Claude Code, Anthropic's official CLI for Claude.
Given the user's message, you should use the tools available
to complete the task.

Your strengths:
- Searching for code across large codebases
- Analyzing multiple files to understand architecture
- Investigating complex questions
- Performing multi-step research tasks

Guidelines:
- For file searches: search broadly when you don't know
  where something lives
- NEVER create files unless absolutely necessary
- ALWAYS prefer editing existing files

ポイントは役割(CLIツール)、強み(コード検索、分析)、ルール(ファイル作成最小化)が明確に分離されていることです。

システムプロンプト作成ベストプラクティス

# 良いシステムプロンプトの構造

## 1. 役割宣言 (Who)
あなたはシニアバックエンドエンジニアです。
Java/Spring Boot専門で、10年以上の経験があります。

## 2. 行動ルール (How)
- コードレビュー時はセキュリティ脆弱性を最優先で確認してください
- パフォーマンスの問題がある場合はBig-O分析とともに指摘してください
- 改善提案は必ずコード例とともに提示してください

## 3. 制約事項 (Boundaries)
- コードを直接修正しないでください、提案のみしてください
- 外部ライブラリの追加を推奨しないでください
- 既存のアーキテクチャパターンに従ってください

## 4. 出力形式 (Format)
レビュー結果は以下の形式で作成してください:
- [深刻度]: 説明 + 提案

実践例:役割別システムプロンプト

コードレビュアー:

You are a senior code reviewer specializing in security
and performance. Review every PR with these priorities:
1. Security vulnerabilities (SQL injection, XSS, CSRF)
2. Performance bottlenecks (N+1 queries, memory leaks)
3. Code maintainability (naming, structure, SOLID)
Never approve code with critical security issues.

データアナリスト:

You are a data analyst with expertise in Python, SQL,
and statistical analysis. When analyzing data:
1. Always validate data quality first
2. Provide confidence intervals for estimates
3. Visualize results with appropriate charts
4. Explain findings in business-friendly language

2-2. Tools(ツール)

ツールはAIが外部世界とやり取りするインターフェースです。LLM自体はテキストを生成することしかできませんが、ツールを通じてファイルを読み、コマンドを実行し、APIを呼び出すことができます。

Function Callingの動作(どうさ)の仕組み

AIのツール使用は以下のプロセスを経ます:

  1. ユーザーがリクエストを送信
  2. AIがどのツールを使うか決定(推論)
  3. AIがツール呼び出しを生成(JSON形式)
  4. ハーネスが実際にツールを実行
  5. 結果をAIに返却
  6. AIが結果を解釈し次のアクションを決定

ツール定義の構造

ツールはJSON Schemaで定義されます:

{
  "name": "read_file",
  "description": "Reads a file from the local filesystem. Supports text files, images, and PDFs.",
  "input_schema": {
    "type": "object",
    "properties": {
      "file_path": {
        "type": "string",
        "description": "The absolute path to the file to read"
      },
      "offset": {
        "type": "number",
        "description": "The line number to start reading from"
      },
      "limit": {
        "type": "number",
        "description": "The number of lines to read"
      }
    },
    "required": ["file_path"]
  }
}

核心原則:

  • 名前: 動詞 + 名詞(read_file、search_code、run_command)
  • 説明: AIがいつこのツールを使うべきかを明確に
  • パラメータ: JSON Schemaで強い型付け、required/optionalを区分

Claude Codeの核心ツール

ツール用途
Bashシェルコマンド実行git status、npm test
Readファイル読み取りソースコード、設定ファイル
Writeファイル作成新しいファイル作成
Editファイル修正既存コードの修正
Grepパターン検索コードベース内の検索
Globファイル検索ファイル名パターンマッチング
WebSearchWeb検索最新ドキュメント、APIリファレンス
WebFetchWebページ取得URLコンテンツの読み取り

MCP(Model Context Protocol)でツール拡張(かくちょう)

MCPは、AIエージェントが外部ツールやデータソースにアクセスするための標準プロトコルです。USB-Cがさまざまなデバイスを1つのインターフェースで接続するように、MCPはさまざまなサービスをAIに接続します。

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "ghp_xxxxxxxxxxxx"
      }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "postgresql://user:pass@localhost/db"
      }
    }
  }
}

MCPサーバーを追加すると、AIはGitHub Issueの管理、データベースのクエリ、Slackメッセージの送信などの新しいツールを獲得します。

ツール設計の5原則(げんそく)

  1. 単一責任: 1つのツールは1つのことだけを行う
  2. 明確な説明: AIがいつ使うべきかを理解できること
  3. 強い型付けパラメータ: JSON Schemaで入力を厳密に検証
  4. 失敗処理: ツール実行失敗時に意味のあるエラーメッセージを返す
  5. 副作用の最小化: 読み取りは安全に、書き込みは確認後に実行

2-3. Context(コンテキスト)

コンテキストは、AIが現在の状況を理解するために必要なすべての情報です。同じ質問でもコンテキストによって完全に異なる回答が必要です。

CLAUDE.md:プロジェクト別の指示文

CLAUDE.mdはプロジェクトの**取扱説明書(とりあつかいせつめいしょ)**です。AIがそのプロジェクトでどのように行動すべきかを定義します。

# Project Guidelines

## Build Commands

- npm run dev: 開発サーバー起動
- npm run build: プロダクションビルド
- npm test: テスト実行

## Code Conventions

- TypeScript strict mode使用
- 関数コンポーネントのみ使用(クラスコンポーネント禁止)
- CSS-in-JSの代わりにTailwind CSSを使用

## Architecture

- src/components: 再利用可能なUIコンポーネント
- src/hooks: カスタムフック
- src/lib: ユーティリティ関数
- src/app: Next.js App Routerページ

CLAUDE.mdは階層的にロードされます:

  1. ホームディレクトリのCLAUDE.md(グローバル設定)
  2. プロジェクトルートのCLAUDE.md(プロジェクト設定)
  3. サブディレクトリのCLAUDE.md(モジュール別設定)

下位ディレクトリの設定が上位をオーバーライドします。

コードベースインデキシング

AIハーネスはプロジェクトのファイル構造、依存関係、アーキテクチャをインデックス化します:

プロジェクト構造分析:
- package.json → 依存関係、スクリプト
- tsconfig.json → TypeScript設定
- .eslintrc → コードスタイルルール
- .gitignore → 除外ファイルパターン
- ディレクトリ構造 → アーキテクチャパターンの推論

Memory:セッション間の記憶(きおく)

.remember/ディレクトリはAIの長期記憶ストレージです:

.remember/
  core-memories.md   # プロジェクトの核心情報
  now.md             # 現在の作業状態
  today.md           # 今日の作業記録
  recent.md          # 最近の作業履歴
  archive.md         # 古い記録のアーカイブ

コンテキストウィンドウ管理戦略(かんりせんりゃく)

Claudeのコンテキストウィンドウは200Kトークン(最大1M)ですが、効率的に管理する必要があります:

  1. 要約(ようやく): 長いファイルから核心のみ抽出
  2. チャンキング: 必要な部分のみ選択的にロード
  3. 優先順位: 現在のタスクとの関連性が高い情報を優先
  4. 動的ロード: 必要に応じて追加コンテキストを取得
  5. サブエージェント委任: 独立タスクは別のコンテキストで処理

2-4. Skills(スキル)

スキルは再利用可能なドメイン知識とワークフローのバンドルです。プロンプトテンプレートに似ていますが、トリガー条件、ツール活用指示、段階的ワークフローを含むより豊かな概念です。

SKILL.mdファイルの構造

---
trigger: 'when user asks to review a PR'
description: 'Comprehensive code review workflow'
---

# Code Review Skill

## Step 1: Gather Information

- Read the PR description and diff
- Identify changed files and their purposes
- Check the PR against project conventions (CLAUDE.md)

## Step 2: Security Review

- Check for SQL injection, XSS, CSRF vulnerabilities
- Verify input validation on all user inputs
- Ensure secrets are not hardcoded

## Step 3: Performance Review

- Identify N+1 query patterns
- Check for unnecessary re-renders (React)
- Verify proper indexing for DB queries

## Step 4: Generate Review

- Use structured format: severity + description + suggestion
- Include code examples for each suggestion
- Summarize with overall assessment

Claude Codeの組み込みスキル例

Claude Codeにはいくつかの組み込みスキルがあります:

  • commit: gitステータス確認、変更分析、コミットメッセージ作成、コミット実行
  • review-pr: PR分析、コードレビュー、コメント作成
  • test-driven-development: テストを先に書く、実装、リファクタリング
  • brainstorming: アイデア発散、構造化、優先順位決定

スキル vs プロンプトテンプレート

項目プロンプトテンプレートスキル
トリガー手動選択自動検知
ツール活用なしツール使用指示を含む
ワークフロー単一プロンプト多段階ワークフロー
コンテキスト静的動的コンテキストロード
学習なし結果フィードバック反映可能

スキル作成ガイド

良いスキルを作る核心原則:

  1. 明確なトリガー: どの状況でアクティブになるかを正確に定義
  2. 段階的分解: 複雑なタスクを小さなステップに分解
  3. ツールマッピング: 各ステップでどのツールを使用するかを明示
  4. 例外処理: 失敗シナリオと代替パスを定義
  5. 出力形式: 成果物の形態を具体的に定義

2-5. Hooks(フック)

フックはAIのツール使用の前後に自動実行されるスクリプトです。GitのpreCommit、postCommitフックのように、AIの行動に自動化された検証と処理を追加します。

フックの4つのタイプ

  1. PreToolUse: ツール使用前に実行

    • 用途: 入力検証、権限確認、パラメータ変換
    • 例: Write呼び出し前にファイルパスを検証
  2. PostToolUse: ツール使用後に実行

    • 用途: 結果検証、フォーマッティング、リント、テスト
    • 例: ファイル保存後に自動でESLintを実行
  3. Notification: 通知前に実行

    • 用途: 通知内容の加工、フィルタリング
  4. Stop: エージェント停止時に実行

    • 用途: クリーンアップ作業、状態保存

設定例:settings.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "echo 'File modification detected'"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "/bin/sh -c 'cd PROJECT_DIR && npx eslint --fix FILE_PATH 2>/dev/null || true'"
      },
      {
        "matcher": "Bash",
        "command": "/bin/sh -c 'if echo TOOL_INPUT | grep -q \"git commit\"; then cd PROJECT_DIR && npm test; fi'"
      }
    ],
    "Notification": [
      {
        "matcher": "",
        "command": "/bin/sh -c 'echo NOTIFICATION_CONTENT >> /tmp/ai-notifications.log'"
      }
    ]
  }
}

実践的なフックシナリオ

シナリオ1:ファイル保存後の自動フォーマット

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "command": "/bin/sh -c 'npx prettier --write FILE_PATH'"
      }
    ]
  }
}

シナリオ2:コミット前の自動テスト

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "/bin/sh -c 'if echo TOOL_INPUT | grep -q \"git commit\"; then npm test || exit 1; fi'"
      }
    ]
  }
}

シナリオ3:危険なコマンドのブロック

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "/bin/sh -c 'if echo TOOL_INPUT | grep -qE \"rm -rf|drop table|format\"; then echo \"BLOCKED: Dangerous command detected\" && exit 1; fi'"
      }
    ]
  }
}

2-6. Permissions(権限)

権限モデルはAIが実行できる操作の範囲を定義するセキュリティレイヤーです。最小権限の原則(さいしょうけんげんのげんそく)をAIに適用します。

アクションのリスク分類(ぶんるい)

リスクレベルアクション種別ポリシー
安全読み取りファイル読み取り、検索、照会自動許可
注意書き込みファイル修正、作成確認後に許可
危険削除/実行ファイル削除、デプロイ明示的な承認が必要
禁止システム変更OS設定、アカウント変更常にブロック

allowedToolsとdisallowedTools

{
  "permissions": {
    "allowedTools": [
      "Read",
      "Glob",
      "Grep",
      "Bash(git status)",
      "Bash(git diff)",
      "Bash(npm test)"
    ],
    "disallowedTools": [
      "Bash(rm *)",
      "Bash(sudo *)",
      "Bash(curl * | sh)",
      "Write(/etc/*)",
      "Write(/usr/*)"
    ]
  }
}

Sandboxモード vs エージェントモード

Sandboxモード:

  • ネットワークアクセスブロック
  • ファイルシステム読み取り専用
  • シェルコマンド制限
  • 安全な実験環境

エージェントモード:

  • ネットワークアクセス許可
  • ファイルシステム読み書き可能
  • シェルコマンド許可(パターンベースのフィルタリング)
  • 実際の作業実行環境

最小権限の原則の適用

AIエージェントに最小権限の原則を適用するステップ:

  1. 必要なツールのみ提供: コードレビューにデプロイツールは不要
  2. ファイル範囲の制限: プロジェクトディレクトリ外へのアクセスをブロック
  3. コマンドのホワイトリスト: 許可されたシェルコマンドのみ実行可能
  4. 時間制限: 長時間実行の防止
  5. コスト制限: 最大トークン使用量の設定

2-7. Memory(記憶)

メモリはAIが過去のやり取りや学習内容を保持するメカニズムです。

短期記憶(たんききおく)vs 長期記憶(ちょうききおく)

短期記憶:

  • 現在の会話セッションのコンテキスト
  • コンテキストウィンドウ内のすべてのメッセージ
  • セッション終了時に消失

長期記憶:

  • .remember/ディレクトリにファイルとして保存
  • セッション間で持続
  • プロジェクトレベルまたはユーザーレベル

記憶ファイルの構造

# core-memories.md

- このプロジェクトはNext.js 14 + TypeScript + Tailwind CSSを使用しています
- デプロイはVercelで行います
- DBはPostgreSQL(Supabase)です

# now.md

現在のタスク:ユーザー認証モジュールのリファクタリング中
進捗:NextAuth.jsからLucia Authへの移行進行中
ブロッカー:ソーシャルログインのコールバックURL設定の問題

# today.md

- 09:30 認証モジュル分析完了
- 10:15 Lucia Auth設定ファイル作成
- 11:00 セッション管理ロジック移行
- 14:00 ソーシャルログイン統合開始

エピソード記憶 vs セマンティック記憶

エピソード記憶(事象ベース):

  • 「昨日ユーザーが認証バグの修正を依頼した」
  • 「先週データベーススキーマを変更した」
  • 具体的な事象と時間情報を含む

セマンティック記憶(知識ベース):

  • 「このプロジェクトはREST APIを使用している」
  • 「チームのコーディング規約はAirbnbスタイルだ」
  • 一般的な事実とルール

メモリ管理戦略

  1. 自動要約: 長い会話からキーポイントのみ抽出して保存
  2. 重要度ベースの整理: 頻繁に参照される記憶は維持、不要な記憶はアーカイブ
  3. 階層的構造: コア記憶 > 最近の記憶 > アーカイブ
  4. 競合解決: 新しい情報が既存の記憶と矛盾する場合は更新
  5. プライバシー: 機密情報は暗号化するか保存しない

3. Claude Codeハーネスアーキテクチャ深掘(ふかぼ)り

3-1. エージェントループ(Agent Loop)

Claude Codeの核心はエージェントループです。単純な質問と回答ではなく、ツールを使い、結果を観察し、再び行動する反復サイクルです。

エージェントループの流れ:

1. User Input(ユーザーリクエスト)
      |
2. System Prompt + Contextのロード
      |
3. LLM推論(どのアクションを取るか決定)
      |
4. Tool Call決定
      |
5. Hook(PreToolUse)実行
      |  (検証失敗時 → 3に戻る)
      |
6. Tool実行
      |
7. Hook(PostToolUse)実行
      |
8. 結果の観察(Observation)
      |
9. 追加アクションが必要? → Yes → 3に戻る
      |                       No
      |
10. 最終応答の生成

このループはmax_turns制限に到達するか、AIが「タスク完了」と判断するまで続きます。

実践例:PRレビューループ

Turn 1: git diff実行(Bashツール)
   → 変更されたファイルリストとdiffを取得

Turn 2: 変更されたファイルを読み取り(Readツール)
   → 全体コンテキストの把握

Turn 3: CLAUDE.mdを読み取り(Readツール)
   → プロジェクト規約の確認

Turn 4: 関連テストファイルの検索(Grepツール)
   → テストカバレッジの確認

Turn 5: npm test実行(Bashツール)
   → テスト合格の確認

Turn 6: レビュー結果の生成(最終応答)
   → セキュリティ、パフォーマンス、保守性の観点からレビュー

3-2. サブエージェントアーキテクチャ

複雑なタスクは1つのエージェントで処理するのが困難です。Claude Codeはサブエージェントアーキテクチャを使用します。

メインエージェントとサブエージェント

メインエージェント(Orchestrator)
    |
    +--- サブエージェントA:「src/ディレクトリの分析」
    |       (独立コンテキスト、ファイル読み取り/検索ツール)
    |
    +--- サブエージェントB:「tests/ディレクトリの分析」
    |       (独立コンテキスト、テスト実行ツール)
    |
    +--- サブエージェントC:「ドキュメント更新」
            (独立コンテキスト、ファイル書き込みツール)

メインエージェント:各サブエージェントの結果を統合して最終応答を生成

サブエージェントの核心的な特徴:

  • 独立コンテキスト: メインエージェントのコンテキストを汚染しない
  • 並列実行: 独立したタスクは同時に実行可能
  • 結果統合: メインエージェントが結果を収集して総合

バックグラウンドエージェント vs フォアグラウンドエージェント

  • フォアグラウンドエージェント: ユーザーと直接対話するメインエージェント
  • バックグラウンドエージェント: 独立して作業を行う非同期エージェント

バックグラウンドエージェントの使用シナリオ:

  • 大規模リファクタリング作業
  • 多数のファイルにわたるテスト実行
  • ドキュメントの自動生成

Worktree分離(ぶんり)

Git Worktreeを活用した分離:

メインプロジェクト(mainブランチ)
    |
    +--- .claude/worktrees/feature-auth/
    |       (独立ブランチ、独立作業ディレクトリ)
    |
    +--- .claude/worktrees/fix-bug-123/
            (独立ブランチ、独立作業ディレクトリ)

各Worktreeは独立したファイルシステムを持つため、互いの作業に影響を与えません。

3-3. settings.json完全解剖(かいぼう)

Claude Codeの設定はsettings.jsonで管理されます。

グローバル設定 vs プロジェクト設定

設定場所(優先順位順):
1. プロジェクト/.claude/settings.json(最優先)
2. ホームディレクトリ/.claude/settings.json(グローバル)
3. デフォルト値

完全な設定構造

{
  "permissions": {
    "allowedTools": ["Read", "Glob", "Grep"],
    "disallowedTools": ["Bash(rm *)"]
  },
  "hooks": {
    "PreToolUse": [],
    "PostToolUse": [],
    "Notification": [],
    "Stop": []
  },
  "env": {
    "NODE_ENV": "development",
    "DEBUG": "true"
  },
  "model": "claude-sonnet-4-20250514",
  "theme": "dark"
}

設定の優先順位

最も高い ← プロジェクト設定 ← グローバル設定 ← デフォルト値 → 最も低い

プロジェクト設定がグローバル設定をオーバーライドするため、プロジェクトごとに異なる権限とフックを設定できます。


4. Claude Agent SDKでカスタムハーネスを作る

4-1. Python SDK

AnthropicのClaude Agent SDKはカスタムAIエージェントを構築するためのフレームワークです。

基本的なエージェント作成

import anthropic
from typing import Any

# Anthropicクライアントの初期化
client = anthropic.Anthropic()

# ツール定義
tools = [
    {
        "name": "read_file",
        "description": "Read the contents of a file at the given path",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {
                    "type": "string",
                    "description": "Absolute file path to read"
                }
            },
            "required": ["path"]
        }
    },
    {
        "name": "list_directory",
        "description": "List files and directories at the given path",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {
                    "type": "string",
                    "description": "Directory path to list"
                }
            },
            "required": ["path"]
        }
    },
    {
        "name": "search_code",
        "description": "Search for a pattern in the codebase",
        "input_schema": {
            "type": "object",
            "properties": {
                "pattern": {
                    "type": "string",
                    "description": "Regex pattern to search for"
                },
                "file_type": {
                    "type": "string",
                    "description": "File extension filter (e.g., py, ts)"
                }
            },
            "required": ["pattern"]
        }
    }
]


def execute_tool(name: str, input_data: dict) -> str:
    """ツールを実行して結果を返します。"""
    import os
    import subprocess

    if name == "read_file":
        try:
            with open(input_data["path"], "r") as f:
                return f.read()
        except FileNotFoundError:
            return f"Error: File not found: {input_data['path']}"

    elif name == "list_directory":
        try:
            entries = os.listdir(input_data["path"])
            return "\n".join(entries)
        except FileNotFoundError:
            return f"Error: Directory not found: {input_data['path']}"

    elif name == "search_code":
        try:
            cmd = ["grep", "-rn", input_data["pattern"], "."]
            if "file_type" in input_data:
                cmd.extend(["--include", f"*.{input_data['file_type']}"])
            result = subprocess.run(cmd, capture_output=True, text=True)
            return result.stdout or "No matches found"
        except Exception as e:
            return f"Error: {str(e)}"

    return f"Unknown tool: {name}"


def run_agent(user_message: str, max_turns: int = 10) -> str:
    """エージェントループを実行します。"""
    system_prompt = """You are an expert code reviewer.
    Analyze code for security vulnerabilities, performance issues,
    and maintainability problems. Use the provided tools to
    explore the codebase before giving your review."""

    messages = [{"role": "user", "content": user_message}]

    for turn in range(max_turns):
        # LLM呼び出し
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=4096,
            system=system_prompt,
            tools=tools,
            messages=messages,
        )

        # 応答の処理
        if response.stop_reason == "end_turn":
            for block in response.content:
                if hasattr(block, "text"):
                    return block.text
            return "Agent completed without text response"

        # ツール呼び出しの処理
        if response.stop_reason == "tool_use":
            messages.append({
                "role": "assistant",
                "content": response.content,
            })

            tool_results = []
            for block in response.content:
                if block.type == "tool_use":
                    result = execute_tool(block.name, block.input)
                    tool_results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": result,
                    })

            messages.append({
                "role": "user",
                "content": tool_results,
            })

    return "Agent reached maximum turns without completing"


# 実行
if __name__ == "__main__":
    review = run_agent("Review the authentication module in src/auth/")
    print(review)

権限モデルの追加

class PermissionModel:
    """AIエージェントの権限を管理します。"""

    def __init__(self):
        self.allowed_paths = ["/project/src/", "/project/tests/"]
        self.blocked_commands = ["rm", "sudo", "chmod"]
        self.max_file_size = 1_000_000  # 1MB

    def check_file_access(self, path: str) -> bool:
        """ファイルアクセス権限を確認します。"""
        return any(path.startswith(p) for p in self.allowed_paths)

    def check_command(self, command: str) -> bool:
        """コマンド実行権限を確認します。"""
        return not any(cmd in command for cmd in self.blocked_commands)

    def validate_tool_call(self, tool_name: str, input_data: dict) -> tuple:
        """ツール呼び出しの有効性を検証します。
        Returns (is_allowed, reason)"""
        if tool_name == "read_file":
            path = input_data.get("path", "")
            if not self.check_file_access(path):
                return False, f"Access denied: {path}"

        if tool_name == "execute_command":
            cmd = input_data.get("command", "")
            if not self.check_command(cmd):
                return False, f"Blocked command: {cmd}"

        return True, "Allowed"

イベント処理とモニタリング

import time
from dataclasses import dataclass, field
from typing import Optional


@dataclass
class AgentEvent:
    """エージェントの行動を記録するイベントです。"""
    event_type: str  # tool_call, tool_result, llm_response, error
    timestamp: float = field(default_factory=time.time)
    tool_name: Optional[str] = None
    input_data: Optional[dict] = None
    output_data: Optional[str] = None
    tokens_used: int = 0
    duration_ms: float = 0


class AgentMonitor:
    """エージェントの行動を監視します。"""

    def __init__(self):
        self.events: list[AgentEvent] = []
        self.total_tokens = 0
        self.total_cost = 0.0

    def log_event(self, event: AgentEvent):
        self.events.append(event)
        self.total_tokens += event.tokens_used

    def get_summary(self) -> dict:
        return {
            "total_events": len(self.events),
            "total_tokens": self.total_tokens,
            "tool_calls": sum(
                1 for e in self.events if e.event_type == "tool_call"
            ),
            "errors": sum(
                1 for e in self.events if e.event_type == "error"
            ),
            "total_duration_ms": sum(
                e.duration_ms for e in self.events
            ),
        }

4-2. TypeScript SDK

TypeScriptでも同じパターンでハーネスを構築できます。

import Anthropic from '@anthropic-ai/sdk'

// ツール定義
const tools: Anthropic.Tool[] = [
  {
    name: 'query_database',
    description: 'Execute a SQL query against the analytics database',
    input_schema: {
      type: 'object' as const,
      properties: {
        query: {
          type: 'string',
          description: 'SQL query to execute (SELECT only)',
        },
        database: {
          type: 'string',
          description: 'Database name',
          enum: ['analytics', 'users', 'products'],
        },
      },
      required: ['query', 'database'],
    },
  },
  {
    name: 'create_chart',
    description: 'Create a data visualization chart',
    input_schema: {
      type: 'object' as const,
      properties: {
        chart_type: {
          type: 'string',
          enum: ['bar', 'line', 'pie', 'scatter'],
        },
        data: {
          type: 'string',
          description: 'JSON string of chart data',
        },
        title: {
          type: 'string',
          description: 'Chart title',
        },
      },
      required: ['chart_type', 'data', 'title'],
    },
  },
]

// 権限モデル
class QueryPermissions {
  private readonly blockedPatterns = [
    /DROP\s/i,
    /DELETE\s/i,
    /UPDATE\s/i,
    /INSERT\s/i,
    /ALTER\s/i,
    /TRUNCATE\s/i,
  ]

  validateQuery(query: string): { allowed: boolean; reason: string } {
    for (const pattern of this.blockedPatterns) {
      if (pattern.test(query)) {
        return {
          allowed: false,
          reason: 'Blocked: destructive operation detected',
        }
      }
    }
    return { allowed: true, reason: 'Query is safe' }
  }
}

// ツール実行
async function executeTool(name: string, input: Record<string, unknown>): Promise<string> {
  const permissions = new QueryPermissions()

  if (name === 'query_database') {
    const query = input.query as string
    const validation = permissions.validateQuery(query)
    if (!validation.allowed) {
      return `Permission denied: ${validation.reason}`
    }
    // シミュレーションされたDBクエリ
    return JSON.stringify({
      columns: ['date', 'revenue', 'users'],
      rows: [
        ['2025-01', 150000, 12000],
        ['2025-02', 165000, 13500],
        ['2025-03', 180000, 15000],
      ],
    })
  }

  if (name === 'create_chart') {
    return `Chart created: ${input.title} (${input.chart_type})`
  }

  return `Unknown tool: ${name}`
}

// エージェントループ
async function runDataAnalysisAgent(question: string): Promise<string> {
  const client = new Anthropic()

  const systemPrompt = `You are a data analyst agent.
    Analyze data by querying databases and creating visualizations.
    Always validate data before making conclusions.
    Provide insights in clear, business-friendly language.`

  const messages: Anthropic.MessageParam[] = [{ role: 'user', content: question }]

  const maxTurns = 10

  for (let turn = 0; turn < maxTurns; turn++) {
    const response = await client.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 4096,
      system: systemPrompt,
      tools,
      messages,
    })

    if (response.stop_reason === 'end_turn') {
      for (const block of response.content) {
        if (block.type === 'text') {
          return block.text
        }
      }
      return 'Agent completed'
    }

    if (response.stop_reason === 'tool_use') {
      messages.push({
        role: 'assistant',
        content: response.content,
      })

      const toolResults: Anthropic.ToolResultBlockParam[] = []
      for (const block of response.content) {
        if (block.type === 'tool_use') {
          const result = await executeTool(block.name, block.input as Record<string, unknown>)
          toolResults.push({
            type: 'tool_result',
            tool_use_id: block.id,
            content: result,
          })
        }
      }

      messages.push({
        role: 'user',
        content: toolResults,
      })
    }
  }

  return 'Agent reached maximum turns'
}

// 実行
async function main() {
  const result = await runDataAnalysisAgent('What was the revenue trend in Q1 2025?')
  console.log(result)
}

main().catch(console.error)

5. 他のAIハーネスフレームワークとの比較

フレームワーク比較表

フレームワーク言語核心概念ハーネスレベル学習曲線
Claude Agent SDKPython/TSツール、権限、イベント最も完全
LangGraphPythonグラフベースのワークフロー
CrewAIPythonマルチエージェント協業
AutoGenPythonエージェント会話
Semantic KernelC#/PythonMSエコシステム統合
DSPyPythonプロンプト最適化

Claude Agent SDK

強み:

  • Anthropicモデルとの最適な互換性
  • 組み込みの権限モデル、ツール使用、イベントシステム
  • プロダクションレベルの安定性

ハーネスの実装(じっそう):

  • System Prompt + Tools + PermissionsがSDKレベルで統合
  • エージェントループが組み込みで、別途実装不要

LangGraph

強み:

  • 複雑なワークフローをグラフで可視化
  • 状態管理、条件分岐、並列実行のサポート
  • チェックポイントとロールバック機能

ハーネスの実装:

from langgraph.graph import StateGraph, END
from typing import TypedDict


class ReviewState(TypedDict):
    code_diff: str
    security_issues: list
    performance_issues: list
    review_summary: str


def analyze_security(state: ReviewState) -> ReviewState:
    """セキュリティ脆弱性を分析します。"""
    state["security_issues"] = ["SQL injection in login.py:42"]
    return state


def analyze_performance(state: ReviewState) -> ReviewState:
    """パフォーマンスの問題を分析します。"""
    state["performance_issues"] = ["N+1 query in users.py:87"]
    return state


def generate_review(state: ReviewState) -> ReviewState:
    """最終レビューを生成します。"""
    issues = state["security_issues"] + state["performance_issues"]
    state["review_summary"] = f"Found {len(issues)} issues"
    return state


# グラフの構成
workflow = StateGraph(ReviewState)
workflow.add_node("security", analyze_security)
workflow.add_node("performance", analyze_performance)
workflow.add_node("review", generate_review)

workflow.set_entry_point("security")
workflow.add_edge("security", "performance")
workflow.add_edge("performance", "review")
workflow.add_edge("review", END)

app = workflow.compile()

CrewAI

強み:

  • 直感的なマルチエージェントモデル(ロールベース)
  • 「Agent = Role + Goal + Backstory」パターン
  • エージェント間の自然な協業

ハーネスの実装:

from crewai import Agent, Task, Crew

security_reviewer = Agent(
    role="Security Reviewer",
    goal="Find all security vulnerabilities in the code",
    backstory="You are a senior security engineer with 15 years "
              "of experience in application security.",
    tools=[],
)

performance_reviewer = Agent(
    role="Performance Reviewer",
    goal="Identify performance bottlenecks and optimization opportunities",
    backstory="You are a performance engineering specialist "
              "who has optimized systems serving millions of users.",
    tools=[],
)

review_task = Task(
    description="Review the authentication module for security issues",
    agent=security_reviewer,
    expected_output="List of security vulnerabilities with severity ratings",
)

crew = Crew(
    agents=[security_reviewer, performance_reviewer],
    tasks=[review_task],
)

result = crew.kickoff()

6. ハーネス設計パターン

AIハーネスを設計する際に活用できる主要なパターンを見ていきましょう。

6-1. Routerパターン(ラウターパターン)

入力を分析して適切な専門エージェントにルーティングするパターンです。

ユーザー入力
    |
    v
[Router Agent] → 「コードレビュー依頼」 → Code Review Agent
               → 「データ分析依頼」     → Data Analysis Agent
               → 「ドキュメント作成依頼」 → Documentation Agent
               → 「一般的な質問」       → General Assistant

適した状況:

  • 多様なタイプのリクエストを処理する必要がある場合
  • 専門エージェントが各ドメインに最適化されている場合
  • 単一エージェントではすべてのドメインをカバーできない場合

6-2. Orchestrator-Workerパターン

中央のオーケストレーターがタスクを分割してワーカーに配分するパターンです。

[Orchestrator]
    |
    +--- 「ファイルAをレビュー」 → [Worker 1] → 結果A
    |
    +--- 「ファイルBをレビュー」 → [Worker 2] → 結果B
    |
    +--- 「ファイルCをレビュー」 → [Worker 3] → 結果C
    |
    v
[Orchestrator] → 結果A + B + Cを統合 → 最終レビュー

適した状況:

  • 大規模タスクを並列処理する必要がある場合
  • タスクを独立した単位に分割できる場合
  • 結果を統合するロジックが必要な場合

6-3. Pipelineパターン(パイプラインパターン)

順次的に処理するパターンです。各段階の出力が次の段階の入力になります。

[分析Agent] → コード分析結果
    |
    v
[計画Agent] → リファクタリング計画
    |
    v
[実行Agent] → コード修正
    |
    v
[検証Agent] → テスト実行 + 結果確認

適した状況:

  • タスクに明確な順序がある場合
  • 各段階が前の段階の結果に依存する場合
  • 段階別の品質検証が必要な場合

6-4. Evaluator-Optimizerパターン(評価者-最適化パターン)

結果を評価し基準未達の場合は再試行するパターンです。

[Generator Agent] → 初稿の生成
    |
    v
[Evaluator Agent] → 品質評価(1-10点)
    |
    +--- スコア >= 8 → 完了
    |
    +--- スコア < 8 → フィードバックとともにGeneratorに再依頼
                         |
                         v
                    [Generator Agent] → 修正版の生成
                         |
                         v
                    [Evaluator Agent] → 再評価
                         ...

適した状況:

  • 出力品質が重要な場合
  • 品質を客観的に測定できる場合
  • 反復による改善が可能な場合

6-5. Guardrailsパターン(ガードレールパターン)

入出力の検証で安全なAI行動を保証するパターンです。

ユーザー入力
    |
    v
[Input Guardrail] → 有害コンテンツのフィルタリング
    |                 プロンプトインジェクション検知
    |                 入力の正規化
    v
[AI Agent] → タスクの実行
    |
    v
[Output Guardrail] → PIIマスキング
    |                  幻覚(ハルシネーション)の検知
    |                  フォーマット検証
    v
最終応答

実装例:

class InputGuardrail:
    """入力を検証して浄化します。"""

    def validate(self, user_input: str) -> tuple:
        # プロンプトインジェクションの検知
        injection_patterns = [
            "ignore previous instructions",
            "system prompt",
            "you are now",
            "disregard all",
        ]
        for pattern in injection_patterns:
            if pattern.lower() in user_input.lower():
                return False, "Potential prompt injection detected"

        # 入力長の制限
        if len(user_input) > 10000:
            return False, "Input too long"

        return True, "Valid input"


class OutputGuardrail:
    """出力を検証して浄化します。"""

    def validate(self, output: str) -> str:
        # PIIマスキング
        import re
        # メールアドレスのマスキング
        output = re.sub(
            r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
            "[EMAIL_REDACTED]",
            output,
        )
        # 電話番号のマスキング
        output = re.sub(
            r"\b\d{3}[-.]?\d{4}[-.]?\d{4}\b",
            "[PHONE_REDACTED]",
            output,
        )
        return output

7. 実践:自分だけのコードレビューハーネスを作る

実際に動作するコードレビューハーネスを最初から最後まで作ってみましょう。

7-1. プロジェクト構造

code-review-harness/
  src/
    agent.py          # エージェントループ
    tools.py           # ツール定義と実行
    permissions.py     # 権限モデル
    guardrails.py      # 入出力検証
    memory.py          # 記憶管理
    monitor.py         # モニタリング
  skills/
    code-review.md     # コードレビュースキル
    security-audit.md  # セキュリティ監査スキル
  config/
    settings.json      # 設定ファイル
  tests/
    test_agent.py      # エージェントテスト
  README.md
  requirements.txt

7-2. システムプロンプトの設計

You are an expert code reviewer specializing in Python
and TypeScript applications.

## Your Responsibilities
1. Security: Find vulnerabilities (injection, XSS, auth issues)
2. Performance: Identify bottlenecks (N+1 queries, memory leaks)
3. Maintainability: Check code quality (naming, structure, SOLID)
4. Testing: Verify test coverage and quality

## Rules
- NEVER modify code directly. Only suggest changes.
- Always explain WHY something is an issue, not just WHAT.
- Provide code examples for every suggestion.
- Rate issues by severity: Critical, High, Medium, Low.

## Output Format
For each issue found:
[SEVERITY] file:line - Description
Suggestion: How to fix it
Example: Code snippet showing the fix

7-3. ツールの実装

# tools.py
import subprocess
import os


def git_diff(base_branch: str = "main") -> str:
    """現在のブランチとベースブランチのdiffを取得します。"""
    result = subprocess.run(
        ["git", "diff", f"{base_branch}...HEAD"],
        capture_output=True,
        text=True,
    )
    return result.stdout


def read_file(path: str) -> str:
    """ファイルの内容を行番号付きで読み取ります。"""
    try:
        with open(path, "r") as f:
            lines = f.readlines()
        numbered = [f"{i+1}: {line}" for i, line in enumerate(lines)]
        return "".join(numbered)
    except FileNotFoundError:
        return f"File not found: {path}"


def search_pattern(pattern: str, directory: str = ".") -> str:
    """コードベースでパターンを検索します。"""
    result = subprocess.run(
        ["grep", "-rn", pattern, directory,
         "--include=*.py", "--include=*.ts",
         "--include=*.tsx", "--include=*.js"],
        capture_output=True,
        text=True,
    )
    return result.stdout or "No matches found"


def run_tests(test_path: str = "") -> str:
    """テストスイートを実行します。"""
    cmd = ["python", "-m", "pytest", "-v"]
    if test_path:
        cmd.append(test_path)
    result = subprocess.run(cmd, capture_output=True, text=True)
    return f"STDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"


def get_file_history(path: str, count: int = 5) -> str:
    """ファイルのgit履歴を取得します。"""
    result = subprocess.run(
        ["git", "log", f"-{count}", "--oneline", "--", path],
        capture_output=True,
        text=True,
    )
    return result.stdout

7-4. スキルの定義

# skills/code-review.md

---

trigger: "when user asks to review code or a PR"
description: "Comprehensive code review workflow"

---

## Code Review Workflow

### Step 1: Gather Context

1. Run git diff to see all changes
2. Read the changed files completely
3. Check project conventions (CLAUDE.md, .eslintrc)
4. Identify the purpose of the changes

### Step 2: Security Analysis

Check for these common vulnerabilities:

- SQL injection (raw queries, string interpolation)
- XSS (unescaped user input in HTML)
- Authentication issues (weak tokens, missing checks)
- Authorization issues (missing role checks)
- Sensitive data exposure (API keys, passwords in code)

### Step 3: Performance Analysis

Check for these common issues:

- N+1 database queries
- Missing database indexes
- Unnecessary re-renders (React)
- Memory leaks (unclosed resources)
- Blocking operations in async code

### Step 4: Code Quality Analysis

Check for these issues:

- Unclear naming conventions
- Functions exceeding 50 lines
- Missing error handling
- Duplicated code
- SOLID principle violations

### Step 5: Generate Review Report

Format each issue as:
[SEVERITY] file:line - Description
Use severity levels: Critical, High, Medium, Low, Info

7-5. 権限モデル

# permissions.py

class ReviewPermissions:
    """コードレビューエージェントの権限を定義します。"""

    # 読み取り専用 - コード修正不可
    ALLOWED_TOOLS = [
        "git_diff",
        "read_file",
        "search_pattern",
        "run_tests",
        "get_file_history",
    ]

    BLOCKED_TOOLS = [
        "write_file",
        "delete_file",
        "execute_command",
        "deploy",
    ]

    ALLOWED_PATHS = [
        "src/",
        "tests/",
        "lib/",
        "config/",
    ]

    BLOCKED_PATHS = [
        ".env",
        "secrets/",
        "credentials/",
        ".git/",
    ]

    def is_tool_allowed(self, tool_name: str) -> bool:
        if tool_name in self.BLOCKED_TOOLS:
            return False
        return tool_name in self.ALLOWED_TOOLS

    def is_path_allowed(self, path: str) -> bool:
        for blocked in self.BLOCKED_PATHS:
            if blocked in path:
                return False
        return any(path.startswith(p) for p in self.ALLOWED_PATHS)

8. ハーネスの評価とモニタリング

ハーネス品質メトリクス

AIハーネスの品質を測定する主要メトリクス:

メトリクス説明目標値
ツール使用正確度正しいツールを正しいパラメータで呼び出す割合95%以上
タスク完了率ユーザーリクエストを正常に完了する割合90%以上
安全違反頻度ガードレール迂回や権限違反の頻度0%
平均ターン数タスク完了までの平均エージェントループ反復回数5以下
コスト効率タスクあたりの平均トークン使用量とAPIコストタスクにより異なる

LLM-as-Judge

別のLLMを使用してエージェントの出力品質を評価する方法:

def evaluate_review_quality(
    original_code: str,
    review_output: str,
    evaluator_model: str = "claude-sonnet-4-20250514"
) -> dict:
    """LLMを使用してコードレビュー品質を評価します。"""
    evaluation_prompt = f"""
    Evaluate this code review on a scale of 1-10 for each criterion:

    1. Accuracy: Are the identified issues real problems?
    2. Completeness: Were important issues missed?
    3. Actionability: Are suggestions specific and implementable?
    4. Communication: Is the review clear and constructive?

    Original Code:
    {original_code}

    Review Output:
    {review_output}

    Respond in JSON format:
    accuracy, completeness, actionability, communication, overall, feedback
    """

    # LLMを呼び出して評価を実行
    # ...(実際のAPI呼び出しコード)
    return evaluation_result

A/Bテスト

プロンプトやツール変更時にA/Bテストで比較します:

  1. ベースラインの設定: 現在のハーネスのパフォーマンスを測定
  2. 変更の適用: 新しいシステムプロンプト、ツール、スキルを適用
  3. 同一入力でテスト: 同じテストケースで両バージョンを実行
  4. メトリクスの比較: 正確度、完了率、コストを比較
  5. 統計的有意性の確認: 差異が偶然でないことを検証

コスト追跡(ついせき)

class CostTracker:
    """エージェントのAPI呼び出しコストを追跡します。"""

    PRICING = {
        "claude-sonnet-4-20250514": {
            "input": 0.003 / 1000,
            "output": 0.015 / 1000,
        },
        "claude-opus-4-20250514": {
            "input": 0.015 / 1000,
            "output": 0.075 / 1000,
        },
    }

    def __init__(self):
        self.total_input_tokens = 0
        self.total_output_tokens = 0
        self.model = "claude-sonnet-4-20250514"

    def add_usage(self, input_tokens: int, output_tokens: int):
        self.total_input_tokens += input_tokens
        self.total_output_tokens += output_tokens

    def get_total_cost(self) -> float:
        pricing = self.PRICING[self.model]
        return (
            self.total_input_tokens * pricing["input"]
            + self.total_output_tokens * pricing["output"]
        )

    def get_report(self) -> str:
        cost = self.get_total_cost()
        return (
            f"Input tokens: {self.total_input_tokens:,}\n"
            f"Output tokens: {self.total_output_tokens:,}\n"
            f"Total cost: ${cost:.4f}"
        )

9. 2025-2026年ハーネスのトレンド

Model-Nativeツール呼び出し

初期のLLMはツール使用法をプロンプトで教える必要がありました。2025年の最新モデルは**学習過程でツール使用法を内在化(ないざいか)**しています。Claude Sonnet 4やGPT-4oはFunction Callingをネイティブにサポートします。

ハーネスへの影響:

  • 簡潔なツール説明でも正確に使用
  • 複雑なツールの組み合わせを自律的に計画
  • エラー回復能力の向上

自律(じりつ)エージェントの台頭(たいとう)

2025年は自律エージェントの元年です:

  • Devin: CognitionのAIソフトウェアエンジニア
  • Claude Code: AnthropicのCLIベースのコーディングエージェント
  • OpenAI Codex(CLI): OpenAIのコーディングエージェント
  • GitHub Copilot Agent Mode: GitHubのエージェントモード

これらはすべて精巧なハーネスを使用しています。差別化を生むのはモデルの能力ではなく、ハーネスの設計です。

マルチモーダルハーネス

テキストのみを処理していたハーネスが画像、音声、動画に拡張されます:

  • スクリーンショット分析: UIバグ検出、デザインレビュー
  • ダイアグラム理解: アーキテクチャ図をコードに変換
  • 音声インターフェース: 音声でコーディング指示
  • 動画分析: ユーザーセッション録画の分析

Agent-to-Agentプロトコル

MCP(Model Context Protocol)がAIエージェント間の標準通信プロトコルとして進化しています:

  • エージェントAがエージェントBのツールを使用
  • エージェント間のタスク委任と結果共有
  • 異種エージェント(Claude + GPT + Gemini)間の協業

ハーネスの標準化(ひょうじゅんか)

現在はフレームワークごとにハーネスの実装方法が異なりますが、標準化の動きが始まっています:

  • MCP: ツール接続標準
  • Agent Protocol: エージェントインターフェース標準
  • OpenAPI for Agents: APIベースのエージェント定義

2026年には「ハーネス標準」が登場し、どのフレームワークでも同一の構成要素を使用できるようになると見込まれています。


10. クイズ

Q1: AIハーネスの比喩で「野生馬」に相当するものは何ですか?

正解:Raw LLM(GPT-4、Claude、Geminiなどの基盤モデル)

野生馬は巨大な力(知能)を持っていますが、ハーネス(馬具)なしではその力を望む方向に使えません。Raw LLMも同様に、ツール、コンテキスト、権限、スキルなどのハーネスなしでは実用的なタスクを実行するのが困難です。

Q2: ハーネスの7つの構成要素をすべて挙げてください。

正解:

  1. System Prompt(システムプロンプト)
  2. Tools(ツール)
  3. Context(コンテキスト)
  4. Skills(スキル)
  5. Hooks(フック)
  6. Permissions(権限)
  7. Memory(記憶)

この7つが結合してRaw LLMを実用的なAIエージェントに変換します。

Q3: PreToolUseフックとPostToolUseフックの違いは何ですか?

正解:

  • PreToolUse: ツール使用に実行されます。入力検証、権限確認、危険なコマンドのブロックなどの用途で使用されます。検証失敗時にはツール実行を中断できます。
  • PostToolUse: ツール使用に実行されます。結果検証、自動フォーマット(prettier、eslint)、自動テストなどの用途で使用されます。

Gitフックのpre-commit(コミット前の検証)とpost-commit(コミット後の通知)に似た概念です。

Q4: Orchestrator-WorkerパターンとPipelineパターンの違いは何ですか?

正解:

  • Orchestrator-Workerパターン: 中央のオーケストレーターがタスクを分割し、複数のワーカーに並列で配分します。各ワーカーは独立して作業し、オーケストレーターが結果を統合します。例:複数のファイルを同時にレビュー。
  • Pipelineパターン: タスクが順次的に処理されます。各段階の出力が次の段階の入力になります。例:分析 → 計画 → 実行 → 検証。

核心的な違いは並列実行(Orchestrator-Worker)vs 順次実行(Pipeline)です。

Q5: 2025年のAIエンジニアリングの重心は「モデル訓練」から何に移動しましたか?その理由は?

正解:モデルオーケストレーション(Model Orchestration)

理由:

  1. 基盤モデルが十分に強力になり、大半のタスクに別途の訓練が不要になりました
  2. 同じモデルを使ってもハーネスの設計によって結果が大きく異なります
  3. エンタープライズでセキュリティ、監査、権限管理、コスト追跡が必須になりました
  4. DevinやClaude Codeなどの自律エージェントが精巧なハーネス設計で差別化を図っています

したがって、「どのモデルを使うか?」よりも「モデルをどうラップして制御するか?」が核心的な問いになりました。


11. 参考資料(さんこうしりょう)

  1. Anthropic, "Claude Agent SDK Documentation," 2025
  2. Anthropic, "Model Context Protocol (MCP) Specification," 2025
  3. Anthropic, "Claude Code: An Agentic Coding Tool," 2025
  4. Harrison Chase, "LangGraph: Building Stateful Agent Workflows," LangChain Blog, 2025
  5. CrewAI, "Multi-Agent Orchestration Framework Documentation," 2025
  6. Microsoft, "AutoGen: Enabling Next-Gen LLM Applications," 2025
  7. Microsoft, "Semantic Kernel Documentation," 2025
  8. OpenAI, "Function Calling Guide," 2025
  9. Anthropic, "Building Effective Agents," Research Blog, 2025
  10. Lilian Weng, "LLM Powered Autonomous Agents," OpenAI Blog, 2024
  11. Shunyu Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models," ICLR, 2023
  12. Andrew Ng, "Agentic Design Patterns," DeepLearning.AI, 2025
  13. Simon Willison, "Building AI-Powered Tools with LLMs," Blog, 2025
  14. Chip Huyen, "Building LLM Applications for Production," 2025
  15. Devin AI, "How Devin Works: Architecture and Design," Cognition Blog, 2025
  16. GitHub, "Copilot Agent Mode: Architecture Deep Dive," GitHub Blog, 2025