ツール開発

Gemini CLI の機能を拡張するカスタムツールを作成します。AI 会話とシームレスに統合するツールの設計、実装、テスト、デプロイ方法を学びます。

開発プロセス

カスタムツール作成のステップバイステップガイド

1

ツールインターフェースを定義

パラメータと説明を含むツール定義を作成

例:

const toolDefinition = {
  name: 'calculate_age',
  description: 'Calculate age based on birth date',
  parameters: {
    type: 'object',
    properties: {
      birthDate: {
        type: 'string',
        format: 'date',
        description: 'Birth date in YYYY-MM-DD format'
      },
      currentDate: {
        type: 'string',
        format: 'date',
        description: 'Current date (optional, defaults to today)'
      }
    },
    required: ['birthDate']
  }
};
2

ツールロジックを実装

ツールのタスクを実行する実行関数を書く

例:

const executeFunction = async ({ birthDate, currentDate }) => {
  try {
    const birth = new Date(birthDate);
    const current = currentDate ? new Date(currentDate) : new Date();
    
    if (birth > current) {
      throw new Error('Birth date cannot be in the future');
    }
    
    const ageMs = current.getTime() - birth.getTime();
    const ageYears = Math.floor(ageMs / (1000 * 60 * 60 * 24 * 365.25));
    
    return `Age: ${ageYears} years old`;
  } catch (error) {
    return `Error: ${error.message}`;
  }
};
3

ツールを登録

ツールをGemini CLIのツールレジストリに追加

例:

import { GeminiCLI } from '@google/generative-ai-cli';

const cli = new GeminiCLI();

// Create complete tool
const ageTool = {
  ...toolDefinition,
  execute: executeFunction
};

// Register the tool
cli.registerTool(ageTool);

// Verify registration
console.log('Registered tools:', cli.listTools().map(t => t.name));
4

ツールをテスト

ツールが正しく動作することを確認するためにテスト

例:

// Test the tool directly
const result = await cli.executeTool('calculate_age', {
  birthDate: '1990-05-15'
});
console.log(result); // "Age: 34 years old"

// Test with AI
const response = await cli.ask(
  "How old would someone born on May 15, 1990 be today?",
  { tools: ['calculate_age'] }
);

ツールテンプレート

このテンプレートを使用してカスタムツール開発を素早く開始

基本ツールテンプレート

このテンプレートをコピーして、ニーズに応じて変更してください。名前、説明、パラメータ、実行ロジックを更新することを確認してください。

import { Tool, ToolDefinition } from '@google/generative-ai-cli';

export const myCustomTool: ToolDefinition = {
  name: 'my_custom_tool',
  description: 'Description of what this tool does',
  parameters: {
    type: 'object',
    properties: {
      // Define your parameters here
      input: {
        type: 'string',
        description: 'Input parameter description'
      }
    },
    required: ['input']
  },
  execute: async (params) => {
    try {
      // Your tool logic here
      const { input } = params;
      
      // Process the input
      const result = processInput(input);
      
      // Return the result
      return result;
    } catch (error) {
      // Handle errors gracefully
      return `Error: ${error.message}`;
    }
  }
};

function processInput(input: string): string {
  // Your processing logic
  return `Processed: ${input}`;
}

ベストプラクティス

高品質で信頼性の高いツールを作成するためのガイドラインに従ってください

ツール設計

  • ツールを単一の責任に集中させる
  • 明確で説明的な名前と説明を使用
  • 包括的なパラメータスキーマを定義
  • パラメータ説明に例を含める
  • エッジケースを優雅に処理

エラー処理

  • 実行を常にtry-catchブロックで囲む
  • 意味のあるエラーメッセージを返す
  • 入力パラメータを検証
  • ネットワークタイムアウトと失敗を処理
  • デバッグのためにエラーをログ

パフォーマンス

  • 非同期操作を適切に実装
  • 長時間の操作にタイムアウト処理を追加
  • 適切な場合に結果をキャッシュ
  • 外部依存関係を最小化
  • 大きなレスポンスにストリーミングを使用

セキュリティ

  • すべての入力を検証・サニタイズ
  • 任意のコード実行を避ける
  • ファイルシステムアクセスを制限
  • セキュアなAPIエンドポイントを使用
  • 機密データを慎重に処理

ツールをテスト

デプロイ前にツールが正しく動作することを確認

ユニットテスト

// Test tool execution directly
import { myCustomTool } from './my-tool';

describe('myCustomTool', () => {
  test('should process input correctly', async () => {
    const result = await myCustomTool.execute({
      input: 'test data'
    });

    expect(result).toBe('Processed: test data');
  });

  test('should handle errors gracefully', async () => {
    const result = await myCustomTool.execute({
      input: null
    });

    expect(result).toMatch(/Error:/);
  });
});

統合テスト

// Test tool with Gemini CLI
import { GeminiCLI } from '@google/generative-ai-cli';

const cli = new GeminiCLI();
cli.registerTool(myCustomTool);

// Test tool registration
const tools = cli.listTools();
expect(tools.find(t => t.name === 'my_custom_tool')).toBeDefined();

// Test tool execution
const result = await cli.executeTool('my_custom_tool', {
  input: 'test'
});
expect(result).toBeDefined();

テストとデバッグ

ツールが確実に動作するためのヒント

テスト戦略

  • ツール関数を単独でテスト
  • 様々な入力パラメータでテスト
  • エラー条件とエッジケースをテスト
  • AIとの統合を検証

デバッグのヒント

  • 詳細なログ記録を追加
  • デバッグにconsole.logを使用
  • パラメータ検証をチェック
  • パフォーマンスメトリクスを監視

一般的なツールパターン

異なるタイプのツール用の再利用可能なパターン

API統合ツール

外部APIと統合するツールのパターン

const apiTool = {
  name: 'api_call',
  description: 'Make API calls to external services',
  parameters: {
    type: 'object',
    properties: {
      endpoint: { type: 'string', description: 'API endpoint URL' },
      method: { type: 'string', enum: ['GET', 'POST'], default: 'GET' },
      data: { type: 'object', description: 'Request payload' }
    },
    required: ['endpoint']
  },
  execute: async ({ endpoint, method = 'GET', data }) => {
    try {
      const response = await fetch(endpoint, {
        method,
        headers: { 'Content-Type': 'application/json' },
        body: data ? JSON.stringify(data) : undefined
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      return await response.json();
    } catch (error) {
      return `API Error: ${error.message}`;
    }
  }
};

データ処理ツール

データを処理・変換するツールのパターン

const processingTool = {
  name: 'data_processor',
  description: 'Process and transform data',
  parameters: {
    type: 'object',
    properties: {
      data: { type: 'array', description: 'Data to process' },
      operation: {
        type: 'string',
        enum: ['sort', 'filter', 'map', 'reduce'],
        description: 'Operation to perform'
      },
      criteria: { type: 'string', description: 'Processing criteria' }
    },
    required: ['data', 'operation']
  },
  execute: async ({ data, operation, criteria }) => {
    try {
      switch (operation) {
        case 'sort':
          return data.sort();
        case 'filter':
          return data.filter(item => item.includes(criteria));
        case 'map':
          return data.map(item => `${criteria}: ${item}`);
        case 'reduce':
          return data.reduce((acc, item) => acc + item, '');
        default:
          throw new Error(`Unknown operation: ${operation}`);
      }
    } catch (error) {
      return `Processing Error: ${error.message}`;
    }
  }
};

関連リソース

ツール開発とAPI統合についてより深く学ぶ