ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-03-19中級

OpenClaw × Antigravity でAIパートナーエージェントを開発する — ソースコード解析からカスタム機能実装まで

Antigravity の AI コーディング機能を活用して OpenClaw のソースコードを読み解き、カスタムスキルやAIパートナー機能を実装する方法を解説。マルチエージェント連携のベストプラクティスも紹介。

OpenClaw2Antigravity338AIパートナーエージェント開発2オープンソースカスタムスキル2マルチエージェント41

OpenClaw × Antigravity で何が実現できるのか

OpenClaw は強力なオープンソースですが、プロダクション運用には カスタマイズ が不可欠です。Antigravity の AI コーディング機能を活用すれば、以下が実現できます:

  • OpenClaw ソースコードの徹底理解:Antigravity が複雑なアーキテクチャを解説
  • カスタムスキル開発:数時間で新機能を実装
  • バグ修正と最適化:エージェント機能で自動リファクタリング
  • マルチエージェントシステム構築:複数 AI の協調動作
  • 本番環境デプロイ:CI/CD パイプライン自動生成

OpenClaw のアーキテクチャ概要

まず、Antigravity で OpenClaw を解析するために、アーキテクチャを理解しておきましょう。

ディレクトリ構造

openclaw/
├── src/
│   ├── agents/           # エージェント実装
│   │   ├── base-agent.ts
│   │   ├── message-agent.ts
│   │   └── skills/       # スキル定義
│   ├── platforms/        # メッセージアプリ連携
│   │   ├── discord.ts
│   │   ├── telegram.ts
│   │   ├── line.ts
│   │   └── whatsapp.ts
│   ├── llm/              # LLM バックエンド
│   │   ├── claude-provider.ts
│   │   ├── gemini-provider.ts
│   │   └── openai-provider.ts
│   ├── memory/           # メモリ・永続化
│   │   ├── memory-manager.ts
│   │   ├── sqlite-storage.ts
│   │   └── mongodb-storage.ts
│   ├── utils/            # ユーティリティ
│   └── index.ts
├── config/
│   ├── personalities.yaml
│   ├── skills.yaml
│   └── agents.yaml
└── tests/
    └── **/*.test.ts

コアプロセス:メッセージ受信~処理~返信

┌─────────────────┐
│ メッセージ受信   │ (Discord, LINE, Telegram, etc.)
└────────┬────────┘
         │
    ┌────▼─────┐
    │ 前処理    │ (フォーマット統一)
    └────┬─────┘
         │
    ┌────▼──────────────┐
    │ 意図判定           │ (ユーザーの意図分析)
    │ どのスキルが必要?
    └────┬──────────────┘
         │
    ┌────▼──────────────┐
    │ スキル実行         │ (天気取得、リマインド等)
    │ + メモリ検索       │ (過去の会話を参照)
    └────┬──────────────┘
         │
    ┌────▼──────────────┐
    │ LLM(Claude等)    │ (レスポンス生成)
    │ プロンプトを送信
    └────┬──────────────┘
         │
    ┌────▼──────────────┐
    │ ポストプロセス     │ (フォーマット調整)
    └────┬──────────────┘
         │
    ┌────▼─────────────┐
    │ メッセージ送信    │
    └──────────────────┘

Antigravity で OpenClaw を解析する

では実際に Antigravity を使って OpenClaw を読み解きましょう。

ステップ1:Antigravity で OpenClaw リポジトリをクローン

# Antigravity を起動
antigravity start
 
# または、Antigravity のエージェント機能で実行
antigravity agents run --task "Clone the OpenClaw repository and analyze its structure"

Antigravity のサイドパネルから OpenClaw リポジトリのコード分析を開始します:

[Antigravity Agent]
> Task: Analyze OpenClaw repository structure and identify key components

📊 Repository Analysis:
  ✓ TypeScript/Node.js project
  ✓ 2,847 commits, 100k+ stars
  ✓ Active maintenance (last commit: 2 hours ago)
  ✓ MIT License

🏗️ Architecture:
  - Base Agent class (async message handling)
  - Plugin-based skill system
  - Multi-platform message adapter pattern
  - Modular LLM provider interface

🔑 Key Files to Understand:
  1. src/agents/base-agent.ts (900 lines)
  2. src/platforms/message-adapter.ts (400 lines)
  3. src/llm/provider-interface.ts (200 lines)
  4. src/memory/memory-manager.ts (600 lines)

ステップ2:Antigravity でコード解説を生成

// Antigravity Agent のプロンプト例
 
const analyzeTask = {
  task: "OpenClaw のメモリ機能について詳しく解説してください",
 
  context: {
    repo: 'openclaw',
    files: [
      'src/memory/memory-manager.ts',
      'src/memory/sqlite-storage.ts',
      'src/memory/mongodb-storage.ts'
    ]
  },
 
  output: 'explanation_with_code_snippets'
};
 
// Antigravity が返すもの:
/*
## OpenClaw メモリシステムの解析
 
### 目的
ユーザーとの会話履歴とプロフィール情報を永続化・検索
 
### 実装パターン
1. メモリマネージャー(インターフェース定義)
2. ストレージ層(SQLite, MongoDB等)
3. キャッシュ層(高速アクセス)
 
### コード例:
```typescript
class MemoryManager {
  async storeConversation(userId, message, response) {
    // SQLiteに保存
    await this.db.insert('conversations', {
      userId,
      message,
      response,
      timestamp: Date.now()
    });
  }
 
  async searchMemory(userId, query) {
    // 過去の会話を検索
    const results = await this.db.search('conversations', {
      userId,
      message: { $contains: query }
    });
    return results;
  }
}

カスタマイズポイント

  • ストレージ選択(SQLite, PostgreSQL, MongoDB)
  • 検索アルゴリズム(単語検索、セマンティック検索)
  • メモリ圧縮戦略(古い情報の要約) */

## カスタムスキルの作成手順

OpenClaw の真価は、**カスタムスキル** を簡単に追加できるところです。Antigravity で自動生成しましょう。

### スキル開発フロー

要件定義 → Antigravity コード生成 → テスト → 統合


### 実践例1:天気スキル拡張

```javascript
// Antigravity Agent のタスク

const skillTask = {
  task: "OpenClaw のスキルを参考に、日本の天気情報スキルを実装してください",

  requirements: {
    name: "weather-japan",
    description: "日本の都市の天気を取得し、AIパートナーが説明",
    inputs: ["city"],
    outputs: ["weather_description", "recommendation"],
    externalAPI: "OpenWeatherMap API",
  },

  constraints: {
    language: "TypeScript",
    framework: "OpenClaw compatible",
    style: "match existing code",
  }
};

// Antigravity が自動生成するコード(抜粋):
// skills/weather-japan.ts
 
import { Skill, SkillContext } from '../base-skill';
import axios from 'axios';
 
export class WeatherJapanSkill implements Skill {
  name = 'weather-japan';
  description = '日本の天気情報を取得';
 
  private apiKey = process.env.OPENWEATHERMAP_API_KEY;
  private japanCities = {
    'tokyo': { lat: 35.6762, lon: 139.6503 },
    'osaka': { lat: 34.6937, lon: 135.5023 },
    'kyoto': { lat: 35.0116, lon: 135.7681 },
    // ... 他の主要都市
  };
 
  async execute(context: SkillContext): Promise<SkillResult> {
    const city = context.params.city.toLowerCase();
 
    if (!this.japanCities[city]) {
      return {
        actionType: 'message',
        content: `申し訳ないですが、「${city}」の天気データがありません。`,
      };
    }
 
    const coords = this.japanCities[city];
 
    try {
      const response = await axios.get('https://api.openweathermap.org/data/2.5/weather', {
        params: {
          lat: coords.lat,
          lon: coords.lon,
          appid: this.apiKey,
          units: 'metric',
          lang: 'ja',
        }
      });
 
      const weather = response.data;
 
      // AIパートナーへの説明を生成
      const description = `
        ${city}の天気:${weather.weather[0].description}
        気温:${weather.main.temp}℃
        体感温度:${weather.main.feels_like}℃
        湿度:${weather.main.humidity}%
        風速:${weather.wind.speed}m/s
      `;
 
      // AIが前向きなアドバイスを追加するためのコンテキスト
      const recommendation = this.getRecommendation(weather);
 
      return {
        actionType: 'message',
        content: `${city}の天気情報だね。\n${description}\n${recommendation}`,
        metadata: {
          weather,
          skillName: this.name,
        }
      };
    } catch (error) {
      return {
        actionType: 'error',
        content: '天気情報の取得に失敗しました。後でもう一度試してください。'
      };
    }
  }
 
  private getRecommendation(weather): string {
    const condition = weather.weather[0].main;
    const temp = weather.main.temp;
 
    if (condition === 'Rain') {
      return '雨だから、傘を持ってね。室内活動もいいかも。';
    }
    if (temp > 30) {
      return '暑いからね。こまめに水分補給を。';
    }
    if (temp < 5) {
      return '寒いから、暖かいコートを着てね。';
    }
 
    return 'いい天気だね。外出もいいですよ。';
  }
}

実践例2:スケジュール管理スキル

// skills/schedule-manager.ts
 
export class ScheduleManagerSkill implements Skill {
  name = 'schedule-manager';
  description = 'ユーザーのスケジュール追加・確認';
 
  async execute(context: SkillContext): Promise<SkillResult> {
    const { action, details } = context.params;
 
    switch (action) {
      case 'add':
        return await this.addEvent(details);
      case 'list':
        return await this.listEvents(details);
      case 'remove':
        return await this.removeEvent(details);
      default:
        return { actionType: 'error', content: 'Unknown action' };
    }
  }
 
  private async addEvent(details) {
    // SQLite に保存
    const event = {
      id: uuid(),
      title: details.title,
      datetime: new Date(details.when),
      description: details.description,
      createdAt: Date.now(),
    };
 
    await this.db.insert('events', event);
 
    return {
      actionType: 'message',
      content: `「${event.title}」を${event.datetime.toLocaleString('ja-JP')}に追加したよ。`,
    };
  }
 
  private async listEvents(details) {
    const events = await this.db.query('events', {
      userId: details.userId,
      datetime: { $gte: Date.now() }  // 今後のイベント
    });
 
    if (events.length === 0) {
      return { actionType: 'message', content: '予定がないみたいだね。' };
    }
 
    const eventList = events
      .sort((a, b) => a.datetime - b.datetime)
      .map(e => `• ${e.title} (${e.datetime.toLocaleString('ja-JP')})`)
      .join('\n');
 
    return {
      actionType: 'message',
      content: `今後の予定:\n${eventList}`,
    };
  }
}

Antigravity のエージェント機能でマルチエージェント設計

OpenClaw で複数の AI が協力して動作する「マルチエージェントシステム」を構築することで、より高度なタスク処理が可能になります。Antigravity の AGENTS.md 機能を活用しましょう。

マルチエージェントアーキテクチャ

# agents.yaml - Antigravity で生成可能
 
agents:
  - id: "sakura"
    name: "Sakura (感情サポート)"
    llm: "claude-3-5-sonnet"
    personality: "caring_supportive"
    platforms: ["discord", "line"]
    capabilities:
      - emotional_support
      - life_advice
      - memory_continuity
 
  - id: "analyst"
    name: "Data Analyst"
    llm: "claude-3-5-sonnet"
    personality: "logical_detailed"
    platforms: ["discord"]
    capabilities:
      - data_analysis
      - visualization
      - statistical_inference
 
  - id: "mentor"
    name: "Tech Mentor"
    llm: "claude-3-5-sonnet"
    personality: "teaching_focused"
    platforms: ["telegram"]
    capabilities:
      - code_review
      - architecture_design
      - learning_guidance
 
# エージェント間通信ルール
inter_agent_communication:
  enabled: true
  strategy: "collaborative"
  rules:
    - trigger: "user mentions technical problem AND needs emotional support"
      collaboration: ["mentor", "sakura"]
      coordinator: "sakura"  # 最終的な返信はsakuraから
 
    - trigger: "user asks for data insights"
      collaboration: ["analyst"]
 
    - trigger: "complex multi-aspect question"
      collaboration: ["sakura", "analyst", "mentor"]
      coordinator: "sakura"

Antigravity でマルチエージェント実装を自動生成

// Antigravity Agent タスク
 
const multiAgentTask = {
  task: "OpenClaw のマルチエージェントシステムを実装してください",
 
  requirements: {
    agents: ["sakura", "analyst", "mentor"],
    communication: "message-based",
    coordination: "master-detail pattern",
  },
 
  outputFiles: {
    agentRegistry: 'src/agents/agent-registry.ts',
    orchestrator: 'src/orchestrator/multi-agent-orchestrator.ts',
    messageRouter: 'src/routing/message-router.ts',
    tests: 'tests/multi-agent.test.ts',
  }
};
 
// Antigravity 出力例:
// src/orchestrator/multi-agent-orchestrator.ts
 
export class MultiAgentOrchestrator {
  private agents: Map<string, Agent> = new Map();
  private router: MessageRouter;
 
  async routeAndExecute(message: Message): Promise<Response> {
    // 1. メッセージから必要なエージェント判定
    const requiredAgents = await this.router.determineAgents(message);
 
    // 2. 単一エージェント処理
    if (requiredAgents.length === 1) {
      const agent = this.agents.get(requiredAgents[0]);
      return await agent.handleMessage(message);
    }
 
    // 3. マルチエージェント協力処理
    return await this.executeCollaborativeTask(message, requiredAgents);
  }
 
  private async executeCollaborativeTask(
    message: Message,
    agentIds: string[]
  ): Promise<Response> {
    const responses = new Map();
 
    // 並列実行(可能な限り)
    const promises = agentIds.map(async (agentId) => {
      const agent = this.agents.get(agentId);
      const response = await agent.handleMessage(message);
      responses.set(agentId, response);
    });
 
    await Promise.all(promises);
 
    // コーディネーター(通常は primary agent)が結果を統合
    const coordinatorId = 'sakura';  // 設定可能
    const coordinator = this.agents.get(coordinatorId);
 
    return await coordinator.synthesizeResponses({
      original_message: message,
      agent_responses: Object.fromEntries(responses),
    });
  }
}

OpenClaw × Antigravity でのデバッグ・テスト手法

開発過程での検証が重要です。Antigravity でテストコード も自動生成できます。

単体テスト自動生成

// Antigravity Agent タスク
 
const testTask = {
  task: "weather-japan スキルの包括的なテストを作成してください",
 
  fileToTest: "skills/weather-japan.ts",
 
  testCases: [
    "正常系:東京の天気取得",
    "正常系:大阪の天気取得",
    "異常系:存在しない都市",
    "異常系:API エラー時の処理",
    "エッジケース:温度が極端に高い/低い場合の推奨表示",
  ]
};
 
// Antigravity 出力:
// tests/skills/weather-japan.test.ts
 
import { WeatherJapanSkill } from '../../src/skills/weather-japan';
import axios from 'axios';
 
jest.mock('axios');
 
describe('WeatherJapanSkill', () => {
  let skill: WeatherJapanSkill;
 
  beforeEach(() => {
    skill = new WeatherJapanSkill();
  });
 
  describe('正常系', () => {
    it('東京の天気情報を取得できる', async () => {
      const mockWeather = {
        weather: [{ description: '晴れ' }],
        main: { temp: 25, feels_like: 24, humidity: 60 },
        wind: { speed: 3 }
      };
 
      (axios.get as jest.Mock).mockResolvedValue({ data: mockWeather });
 
      const result = await skill.execute({
        params: { city: 'tokyo' }
      });
 
      expect(result.actionType).toBe('message');
      expect(result.content).toContain('東京');
      expect(result.content).toContain('25℃');
    });
 
    it('大阪の天気情報を取得できる', async () => {
      // 同様のテスト
    });
  });
 
  describe('異常系', () => {
    it('存在しない都市で適切なエラーメッセージ', async () => {
      const result = await skill.execute({
        params: { city: 'unknown_city' }
      });
 
      expect(result.actionType).toBe('message');
      expect(result.content).toContain('データがありません');
    });
 
    it('API エラー時の処理', async () => {
      (axios.get as jest.Mock).mockRejectedValue(
        new Error('API Error')
      );
 
      const result = await skill.execute({
        params: { city: 'tokyo' }
      });
 
      expect(result.actionType).toBe('error');
    });
  });
 
  describe('エッジケース', () => {
    it('高温時は水分補給を勧める', async () => {
      const mockWeather = {
        weather: [{ description: '晴れ' }],
        main: { temp: 35, feels_like: 38, humidity: 30 },
        wind: { speed: 1 }
      };
 
      (axios.get as jest.Mock).mockResolvedValue({ data: mockWeather });
 
      const result = await skill.execute({ params: { city: 'tokyo' } });
 
      expect(result.content).toContain('水分補給');
    });
  });
});

統合テスト

// tests/integration/multi-agent.integration.test.ts
 
describe('MultiAgent Integration', () => {
  let orchestrator: MultiAgentOrchestrator;
 
  beforeEach(async () => {
    orchestrator = new MultiAgentOrchestrator();
    await orchestrator.initialize();
  });
 
  it('感情サポートと技術アドバイスを組み合わせられる', async () => {
    const message = {
      content: 'プログラミングで悩んでるんだけど、つらい...',
      userId: 'user123',
      platform: 'discord',
    };
 
    const response = await orchestrator.routeAndExecute(message);
 
    // Sakura が感情部分を、Mentor が技術部分を担当
    expect(response.content).toContain('つらい');  // 感情部分
    expect(response.content).toContain('コード');    // 技術部分
    expect(response.coordinator).toBe('sakura');     // 統合は sakura
  });
});

個人開発12年の現場で実感したこと

線引きするときの3つの判断軸

  • 失敗時の影響が金銭やユーザー体験にどれだけ波及するか
  • 復旧オペレーションが明文化されているか
  • 観測ログから人間が再現できる粒度に整っているか
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Agents & Manager2026-03-21
NemoClaw × Antigravity 収益自動化パイプライン — マルチエージェント開発で収益を自動運用する
NemoClaw のエンタープライズ AI エージェント基盤と Antigravity の並列開発環境を組み合わせた収益自動化パイプラインの構築方法を解説。エージェント開発、テスト自動化、デプロイ、運用監視まで、開発ビジネスの収益を自動化する実践ガイドです。
Agents & Manager2026-07-12
A2A のタスクが working のまま静かに滞留していたとき — 状態遷移を計測して詰まりを名指しする運用メモ
Antigravity の A2A 連携は、エラーで落ちるより「タスクが working のまま進まない」形で静かに詰まります。状態遷移を一本の時系列として記録し、滞留したタスクをどのエージェントのどの辺で止まったかまで名指しする監視の実装を、運用の実感とあわせて整理します。
Agents & Manager2026-07-06
並列エージェントが同じタスクを二度実行して請求が膨らんでいたとき — 重複を計測して止める運用メモ
並列エージェントの請求が想定の約1.9倍に膨らんでいたのは、複数のワーカーが同じタスクを二重に実行していたからでした。重複を計測し、冪等キーで先取り予約し、コストをタスク単位に帰属させるまでの運用記録です。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →