メインコンテンツへスキップ

概要

エージェントAPIは、LLMオーケストレーションなしで単一目的エージェント (「クイックツール」とも呼ばれる) の直接実行を提供します。各エージェントは特定のツールをラップし、構造化された結果を返します。 タスクAPIとの主な違い:
  • エージェントAPI: 直接的なツール実行、AIオーケストレーションなし、同期的な結果
  • タスクAPI: 複数ステップのワークフロー、LLMプランニング、非同期実行
すべてのエージェント実行は、エージェントが単一の操作を実行する場合でも非同期です (task_idを返します)。結果を取得するには タスクステータスAPI を使用します。

ベースURL

http://localhost:8080/api/v1/agents
本番環境: https://api-dev.shannon.run/api/v1/agents

認証

必須: はい ヘッダーにAPIキーを含めます:
X-API-Key: sk_your_api_key
開発デフォルト: GATEWAY_SKIP_AUTH=1 が設定されている場合、認証は無効になります。

エンドポイント

エージェントをリスト

GET /api/v1/agents スキーマとメタデータを含む、利用可能なすべてのエージェントを返します。

リクエスト

curl http://localhost:8080/api/v1/agents \
  -H "X-API-Key: sk_test_123456"

レスポンス

{
  "agents": [
    {
      "id": "serp-ads",
      "name": "SERP広告抽出",
      "description": "指定されたキーワードでGoogle検索結果から有料広告を抽出",
      "category": "ads_research",
      "tool": "ads_serp_extract",
      "input_schema": {
        "required": ["keywords"],
        "properties": {
          "keywords": {
            "type": "string",
            "description": "広告を検索するキーワード"
          },
          "country": {
            "type": "string",
            "default": "us",
            "description": "国コード (us, jp, uk, など)"
          }
        }
      },
      "cost_per_call": 0.015
    }
  ],
  "count": 16
}

レスポンスフィールド

フィールド説明
agentsarrayエージェント定義のリスト
countintegerエージェントの総数
エージェントオブジェクト:
フィールド説明
idstringエージェント識別子 (実行エンドポイントで使用)
namestring人間が読める名前
descriptionstringエージェントが行うこと
categorystringエージェントカテゴリ (ads_research、financialなど)
toolstring基礎となるツール名
input_schemaobject入力検証のためのJSONスキーマ
cost_per_callnumber実行あたりの推定コスト (USD)

エージェント詳細を取得

GET /api/v1/agents/ 入力スキーマを含む、特定のエージェントの詳細を返します。

リクエスト

curl http://localhost:8080/api/v1/agents/serp-ads \
  -H "X-API-Key: sk_test_123456"

レスポンス

{
  "id": "serp-ads",
  "name": "SERP広告抽出",
  "description": "指定されたキーワードでGoogle検索結果から有料広告を抽出",
  "category": "ads_research",
  "tool": "ads_serp_extract",
  "input_schema": {
    "required": ["keywords"],
    "properties": {
      "keywords": {
        "type": "string",
        "description": "広告を検索するキーワード"
      },
      "country": {
        "type": "string",
        "default": "us"
      },
      "device": {
        "type": "string",
        "enum": ["desktop", "mobile", "tablet"],
        "default": "desktop"
      }
    }
  },
  "cost_per_call": 0.015
}

エラーレスポンス

404 Not Found - エージェントが存在しません:
{
  "error": "Agent not found: invalid-agent-id"
}

エージェントを実行

POST /api/v1/agents/ 提供された入力で特定のエージェントを実行します。すぐにタスクIDを返し、エージェントは非同期で実行されます。

リクエストヘッダー

ヘッダー必須説明
X-API-KeyはいAPI認証キー
Content-Typeはいapplication/json でなければなりません

リクエストボディ

パラメータ必須説明
inputobjectはいエージェント固有の入力パラメータ (input_schema に対して検証)
session_idstringいいえ追跡のためのセッション識別子 (省略した場合は自動生成)
streambooleanいいえストリーミングを有効化 (将来の使用のために予約)

例: SERP広告エージェントの実行

curl -X POST http://localhost:8080/api/v1/agents/serp-ads \
  -H "X-API-Key: sk_test_123456" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "user-session-123",
    "input": {
      "keywords": "クレジットカード おすすめ",
      "country": "jp",
      "device": "desktop"
    }
  }'

レスポンス

ステータス: 202 Accepted ヘッダー:
  • X-Workflow-ID: Temporalワークフロー識別子
  • X-Session-ID: セッション識別子
ボディ:
{
  "task_id": "task-abc123",
  "agent_id": "serp-ads",
  "status": "STATUS_CODE_OK",
  "created_at": "2026-02-15T10:30:00Z"
}

結果を取得

返された task_idタスクステータス取得 エンドポイントを使用します:
curl http://localhost:8080/api/v1/tasks/task-abc123 \
  -H "X-API-Key: sk_test_123456"
完了時のレスポンス:
{
  "task_id": "task-abc123",
  "status": "TASK_STATUS_COMPLETED",
  "result": "{\"keywords\":\"クレジットカード おすすめ\",\"total_ads\":5,\"ads\":[...]}",
  "response": {
    "keywords": "クレジットカード おすすめ",
    "total_ads": 5,
    "ads": [
      {
        "position": 1,
        "title": "2026年おすすめクレジットカード",
        "description": "トップのクレジットカードを比較...",
        "link": "https://example.com/cards",
        "domain": "example.com"
      }
    ],
    "cost_usd": 0.015,
    "timestamp": "2026-02-15T10:30:00Z"
  },
  "model_used": "claude-sonnet-4-20250514",
  "provider": "anthropic",
  "usage": {
    "total_tokens": 1250,
    "input_tokens": 800,
    "output_tokens": 450,
    "estimated_cost": 0.018
  }
}

エラーレスポンス

400 Bad Request - 無効な入力:
{
  "error": "input validation failed: missing required field: keywords"
}
404 Not Found - エージェントが存在しません:
{
  "error": "Agent not found: invalid-agent"
}
429 Too Many Requests - レート制限を超過:
{
  "error": "Rate limit exceeded"
}

入力検証

すべてのエージェント入力は実行前にエージェントの input_schema に対して検証されます。 検証ルール:
  1. 必須フィールド は存在し、nullでない必要があります
  2. 型チェック - 文字列、整数、ブール値、配列、オブジェクト
  3. 列挙型検証 - 値は許可されたリストにある必要があります
  4. 未知のフィールド - セキュリティのために拒否 (スキーマにない)
スキーマ例:
{
  "required": ["keywords"],
  "properties": {
    "keywords": {
      "type": "string",
      "description": "検索キーワード"
    },
    "device": {
      "type": "string",
      "enum": ["desktop", "mobile", "tablet"],
      "default": "desktop"
    },
    "max_results": {
      "type": "integer",
      "default": 10
    }
  }
}
有効な入力:
{
  "keywords": "最高のシューズ",
  "device": "mobile",
  "max_results": 5
}
無効な入力 (必須フィールドの欠落):
{
  "device": "mobile"
}
エラー: "input validation failed: missing required field: keywords" 無効な入力 (未知のフィールド):
{
  "keywords": "シューズ",
  "unknown_field": "value"
}
エラー: "input validation failed: unknown field: unknown_field (not defined in agent schema)"

利用可能なエージェント

Shannonは複数のカテゴリにわたって16以上の専門エージェントを提供します。 詳細なスキーマと例を含む利用可能なエージェントの完全なカタログについては、以下を参照してください:

カテゴリ別クイックリファレンス

広告リサーチ (10エージェント):
  • serp-ads - Google有料広告を抽出
  • yahoo-jp-ads - Yahoo Japanスポンサー広告を抽出
  • meta-ad-library - Meta広告ライブラリ (Facebook/Instagram) を検索
  • competitor-discover - 競合広告主を見つける
  • ads-transparency - マルチプラットフォーム広告透明性データ
  • lp-visual-analyze - ランディングページをスクリーンショットして分析
  • lp-batch-analyze - 複数のランディングページをバッチ分析
  • ad-creative-analyze - 広告コピーパターンを分析
  • keyword-extract - テキストから検索キーワードを抽出
  • browser-screenshot - Webページのスクリーンショットをキャプチャ
金融ツール (4エージェント):
  • sec-filings - SEC EDGAR提出書類検索
  • twitter-sentiment - xAI経由のX/Twitter感情
  • alpaca-news - Alpaca Marketsからの株式ニュース
  • news-aggregator - マルチソースニュース集約

統合タスクAPIの代替

context.agent パラメータを使用して、統合タスクAPI を通じてエージェントを実行することもできます:
curl -X POST http://localhost:8080/api/v1/tasks \
  -H "X-API-Key: sk_test_123456" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "NVDA",
    "session_id": "user-session-123",
    "context": {
      "agent": "sec-filings",
      "agent_input": {
        "ticker": "NVDA",
        "days_back": 90
      }
    }
  }'
両方のアプローチは同等です:
  • 専用エンドポイント: POST /api/v1/agents/{id}
  • 統合エンドポイント: context.agent を持つ POST /api/v1/tasks

ベストプラクティス

1. 送信前に入力を検証

GETエンドポイントを使用してエージェントのスキーマを取得し、クライアント側で入力を検証します:
import httpx

# スキーマを取得
agent = httpx.get(
    "http://localhost:8080/api/v1/agents/serp-ads",
    headers={"X-API-Key": "sk_test_123456"}
).json()

# 必須フィールドを検証
required = agent["input_schema"]["required"]
input_data = {"keywords": "シューズ", "device": "mobile"}

for field in required:
    if field not in input_data:
        raise ValueError(f"Missing required field: {field}")

2. 非同期結果を処理

すべてのエージェントはすぐにタスクIDを返します。結果をポーリングします:
import time

# エージェントを実行
response = httpx.post(
    "http://localhost:8080/api/v1/agents/serp-ads",
    headers={"X-API-Key": "sk_test_123456"},
    json={"input": {"keywords": "シューズ"}}
).json()

task_id = response["task_id"]

# 完了をポーリング
while True:
    status = httpx.get(
        f"http://localhost:8080/api/v1/tasks/{task_id}",
        headers={"X-API-Key": "sk_test_123456"}
    ).json()

    if status["status"] == "TASK_STATUS_COMPLETED":
        print(status["response"])
        break

    time.sleep(2)

3. コンテキストにセッションを使用

関連するエージェント呼び出し間で session_id を再利用します:
session_id = "user-123-analysis"

# 最初のエージェント呼び出し
httpx.post(..., json={
    "session_id": session_id,
    "input": {"keywords": "シューズ"}
})

# 2番目のエージェント呼び出し (同じセッション)
httpx.post(..., json={
    "session_id": session_id,
    "input": {"urls": ["https://example.com"]}
})

4. コスト見積もりを確認

高価なエージェントを実行する前に cost_per_call を確認します:
agent = httpx.get(
    "http://localhost:8080/api/v1/agents/twitter-sentiment",
    headers={"X-API-Key": "sk_test_123456"}
).json()

if agent["cost_per_call"] > 0.10:
    print(f"警告: 高コストのエージェント (${agent['cost_per_call']})")

コード例

httpxを使ったPython

import httpx

# すべてのエージェントをリスト
agents = httpx.get(
    "http://localhost:8080/api/v1/agents",
    headers={"X-API-Key": "sk_test_123456"}
).json()

print(f"{agents['count']} エージェントが見つかりました")

# 特定のエージェントを実行
response = httpx.post(
    "http://localhost:8080/api/v1/agents/serp-ads",
    headers={
        "X-API-Key": "sk_test_123456",
        "Content-Type": "application/json"
    },
    json={
        "session_id": "my-session",
        "input": {
            "keywords": "ランニングシューズ",
            "country": "jp",
            "device": "mobile"
        }
    }
).json()

print(f"タスクID: {response['task_id']}")

JavaScript/Node.js

const axios = require('axios');

// エージェント詳細を取得
const agent = await axios.get(
  'http://localhost:8080/api/v1/agents/serp-ads',
  {
    headers: { 'X-API-Key': 'sk_test_123456' }
  }
);

console.log('エージェントスキーマ:', agent.data.input_schema);

// エージェントを実行
const response = await axios.post(
  'http://localhost:8080/api/v1/agents/serp-ads',
  {
    session_id: 'my-session',
    input: {
      keywords: 'ランニングシューズ',
      country: 'jp'
    }
  },
  {
    headers: {
      'X-API-Key': 'sk_test_123456',
      'Content-Type': 'application/json'
    }
  }
);

console.log('タスクID:', response.data.task_id);

Go

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type AgentExecuteRequest struct {
    SessionID string                 `json:"session_id,omitempty"`
    Input     map[string]interface{} `json:"input"`
}

func executeAgent(agentID string, input map[string]interface{}) (string, error) {
    req := AgentExecuteRequest{
        SessionID: "my-session",
        Input:     input,
    }

    body, _ := json.Marshal(req)

    httpReq, _ := http.NewRequest(
        "POST",
        fmt.Sprintf("http://localhost:8080/api/v1/agents/%s", agentID),
        bytes.NewBuffer(body),
    )

    httpReq.Header.Set("X-API-Key", "sk_test_123456")
    httpReq.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(httpReq)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()

    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)

    return result["task_id"].(string), nil
}

func main() {
    taskID, _ := executeAgent("serp-ads", map[string]interface{}{
        "keywords": "ランニングシューズ",
        "country":  "jp",
    })

    fmt.Printf("タスクID: %s\n", taskID)
}

関連エンドポイント