mcpField
A
ai-agent

ai-agent

github.com/zavudevエージェントワークフロー1234 回インストール1 日前に更新
リポジトリ

ai-agent について

API 呼び出しやダッシュボードから Zavu の AI エージェントを設定するスキルです。メッセージチャネル、会話フロー、ツール、ナレッジベース、音声通話を扱い、新規連携では通常 `functions` スキルが推奨されています。

主な機能

  1. 01API によるエージェントの作成と更新
  2. 02プロバイダー、モデル、プロンプトの設定
  3. 03送信元とチャネル接続の管理
  4. 04フロー、ツール、ナレッジベースの設定
  5. 05音声の有効化と通話管理

活用シーン

  1. 01バックエンドスクリプトからサポートエージェントを作成
  2. 02ダッシュボードでエージェント設定を更新
  3. 03キーワード起点のメッセージフローを設定
  4. 04着信または発信に対応するエージェントを設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zavudev/zavu-skills --skill ai-agent

インストール後、Claude Code で/ai-agentを入力して読み込まれたか確認します。

詳細

AI エージェント

使用するタイミング

ユーザーがAPI 呼び出しで AI エージェントを設定したい場合(ソースファイルもデプロイ手順も不要)に、このスキルを使用します。通常は、ダッシュボードまたはエージェントを命令的に作成・更新するバックエンドスクリプトから設定します。

ユーザーが TypeScript でカスタムツールハンドラーを備えたコードファーストのエージェントを作成し、zavu CLI でデプロイしたい場合は、代わりに functions スキルに案内してください。こちらの方法はより使いやすく、バージョン管理に対応しており、デプロイとデバッグの機能が組み込まれています。

簡単な振り分け:

ユーザーの発言…使用するスキル
「エージェントのツールからデータベースにクエリしたい」/「ツールハンドラーをコードで書きたい」/defineTool/npx zavudev deployfunctions スキル
「サーバー上の Webhook を呼び出すエージェントを設定したい」/「ダッシュボードから設定したい」/「API 経由でエージェントを作成したい」このスキル
「ゼロから始めて、最も簡単な方法を使いたい」functions スキル(デフォルトとして推奨)

ここで説明する命令型 API は完全にサポートされており、廃止される予定はありませんが、新しい連携のほとんどでは Functions を推奨します。

Sender とアカウント(1 段落)

Sender は、Zavu-Sender として渡す API ハンドルです。アカウント(WhatsApp Business Account、Facebook ページ、Telegram ボット、電話番号)は、Sender がルーティングする接続先であり、課金対象です。Sender は無料です。ダッシュボードでアカウントに接続すると、その Sender が自動作成されます。GET /v1/senders で見つけ、その Sender が送信できる内容は channels 配列を参照してください。全体像については channel-setup スキルを参照してください。

アーキテクチャ

Inbound message -> Flow check (keyword match, or an `always` flow?)
                     -> YES: Execute flow steps
                     -> NO: LLM call with system prompt + context + KB
                -> Agent generates response -> Send reply

作成方法は 2 つ

defineAgent を使ったコードとしての作成。 エージェントは呼び出すツールとともに Zavu Function 内に配置され、npx zavudev deploy によって調整されます。エージェントがツールを持つ場合、プルリクエストでレビューできるようにしたい場合、またはすでにデプロイしているアプリの一部である場合は、こちらを選んでください。詳しい形式については functions スキルを参照してください。

import { defineAgent, defineTool } from "@zavudev/functions"

export const support = defineAgent({
  name: "Customer Support",
  senderId: process.env.SENDER_ID!,
  provider: "zavu",
  model: "openai/gpt-5.6-luna",
  // `prompt` here, `systemPrompt` over the REST API. The two paths name this
  // field differently and only `prompt` compiles against @zavudev/functions.
  prompt: "You are a helpful support agent for Acme Corp. Be concise.",
  tools: [orderStatus],
})

npx zavudev deploy でデプロイします。調整結果には、作成または更新されたすべてのエージェントとツールが表示されます。デプロイが成功しても宣言の同期に失敗する場合があり、その際は結果に記載されるため、決めつけずに必ず確認してください。

以下に示す API を使った作成。 一度限りの設定、構築中のダッシュボードから管理するエージェント、またはエージェントを紐付ける Function がない場合は、こちらを選んでください。

どちらの方法でも、エージェントは無効の状態で作成されます。有効にするまで応答しません。

エージェントを作成する

各 Sender に設定できるエージェントは 1 つです。すでにエージェントで応答している Sender(その Sender 上で作成された場合、または POST /v1/agents/{agentId}/senders で接続された場合)に 2 つ目のエージェントを作成すると、409 conflict が返されます。

const result = await zavu.senders.agent.create({
  senderId: "snd_abc123",
  name: "Customer Support",
  provider: "openai",
  model: "gpt-4o-mini",
  systemPrompt: "You are a helpful customer support agent for Acme Corp. Be friendly, concise, and helpful. If you don't know the answer, say so.",
  apiKey: process.env.PROVIDER_API_KEY,
  contextWindowMessages: 10,
  includeContactMetadata: true,
  triggerOnChannels: ["*"],
  triggerOnMessageTypes: ["text"],
});
console.log(result.agent.id); // agent_xxx

Python:

result = zavu.senders.agent.create(
    sender_id="snd_abc123",
    name="Customer Support",
    provider="openai",
    model="gpt-4o-mini",
    system_prompt="You are a helpful customer support agent...",
    api_key=os.environ["PROVIDER_API_KEY"],
)

Go:

result, err := client.Senders.Agent.Create(context.TODO(), zavudev.AgentCreateParams{
    SenderID:     zavudev.String("snd_abc123"),
    Name:         zavudev.String("Customer Support"),
    Provider:     zavudev.String("openai"),
    Model:        zavudev.String("gpt-4o-mini"),
    SystemPrompt: zavudev.String("You are a helpful customer support agent..."),
    APIKey:       zavudev.String(os.Getenv("PROVIDER_API_KEY")),
})

Ruby:

result = client.senders.agent.create(
    sender_id: "snd_abc123",
    name: "Customer Support",
    provider: "openai",
    model: "gpt-4o-mini",
    system_prompt: "You are a helpful customer support agent...",
    api_key: ENV["PROVIDER_API_KEY"],
)

PHP:

$result = $client->senders->agent->create([
    'senderId' => 'snd_abc123',
    'name' => 'Customer Support',
    'provider' => 'openai',
    'model' => 'gpt-4o-mini',
    'systemPrompt' => 'You are a helpful customer support agent...',
    'apiKey' => getenv('PROVIDER_API_KEY'),
]);

プロバイダーとモデルの選択

プロバイダーモデルAPI キーが必要
openaigpt-4o、gpt-4o-mini、gpt-4-turboはい
anthropicclaude-3-5-sonnet-latest、claude-3-5-haiku-latestはい
googlegemini-2.5-pro、gemini-2.5-flash、gemini-2.5-flash-liteはい
mistralmistral-large、mistral-smallはい
zavuZavu ホスト型モデルいいえ(含まれています)

エージェントの更新と切り替え

// Update configuration
await zavu.senders.agent.update({
  senderId: "snd_abc123",
  systemPrompt: "Updated prompt...",
  temperature: 0.7,
  maxTokens: 500,
});

// Enable/disable
await zavu.senders.agent.update({
  senderId: "snd_abc123",
  enabled: false,
});

プロバイダーを切り替える場合は、新しいプロバイダーのキーが必要です。 保存されたプロバイダーキーは、1 つのプロバイダーに対応します。エージェントに別のプロバイダーのキーが設定されている状態で provider を openai、anthropic、google、または mistral に変更する更新は、400 invalid_request(「この API キーは anthropic 用ですが、エージェントは openai を使用しています。」)で拒否されます。最初のメッセージで失敗するエージェントが保存されることはありません。同じリクエストに provider と apiKey を含めてください。PATCH /v1/senders/{senderId}/agent と PATCH /v1/agents/{agentId} のどちらも apiKey を受け付けます。zavu への切り替えにキーは不要です。

音声

エージェントは、Zavu の同じ場所に配置された音声ネットワーク(音声認識、エージェントの LLM、音声合成、リアルタイムの割り込み処理)を通じて、電話をかけたり受けたりすることもできます。systemPrompt、ツール、ナレッジベースはすべて通話中にも適用されます。音声では、その上に音声チャネルが追加されるだけです。TypeScript で宣言するコードファーストの音声エージェントには、代わりに functions スキルを使用してください。

要件

  • エージェントの voice.enabled: true が必要です。
  • 送信元で音声チャネルが有効になっている必要があります。 通話を受けられない送信元で音声を有効にしても、設定済みのように見えるだけで着信音は鳴りません。送信元には、プロジェクトが所有する電話番号と enableVoice が必要です。
    npx zavudev senders update snd_abc123 --enable-voice
    
    npx zavudev senders get snd_abc123 で確認してください。channels に voice が含まれている必要があります。この配列は送信元の実際の設定から算出されるため、保存されたフラグではなく、こちらが正しい値です。
  • テストモードのキーでは利用できません。ライブキー(zv_live_...)を使用してください。
  • 通話料金は接続時間(分)ごとの料金に電話料金が加算され、プリペイド残高から差し引かれます。
エージェントで音声を有効にする

音声は、POST/PATCH /v1/senders/{senderId}/agent のエージェントの voice オブジェクトに設定します。SDK ではまだ voice フィールドが型定義されていないため、REST 経由で設定してください。

curl -X PATCH https://api.zavu.dev/v1/senders/snd_abc123/agent \
  -H "Authorization: Bearer $ZAVU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "voice": {
      "enabled": true,
      "greeting": "Hi, thanks for calling Acme. How can I help you today?",
      "language": "en",
      "ttsVoiceId": "aura-2-thalia-en",
      "interruptible": true,
      "maxCallDurationMinutes": 15,
      "maxIdleSeconds": 30,
      "voicemailAction": "hangup",
      "transferPhoneNumber": "+14155551234"
    }
  }'
フィールド説明
enabledエージェントが通話に対応するかどうかです。必須です。false の場合、その番号には応答せず、発信通話も拒否されます。
greeting通話がつながったときに流す最初のメッセージです(最大 1000 文字)。省略すると、エージェントは発信者が先に話すまで待機します。
language認識と合成に使用する BCP-47 コードです(例:en、es、pt-BR)。省略すると、相手の情報から自動検出されます。
ttsVoiceId音声合成に使用する音声です。npx zavudev agents voices(または GET /v1/agents/voices)で ID の一覧を確認できます。一覧にない名前は無視されます。省略すると中立的な音声が使用されます。
interruptibleエージェントが話している最中に、発信者が割り込めるかどうかです。デフォルトは true です。
maxCallDurationMinutes通話時間の上限です。1~120 分に設定できます。デフォルトは 15 分です。
maxIdleSecondsエージェントが通話を終了するまでの無音時間です。5~300 秒に設定できます。デフォルトは 30 秒です。
voicemailAction留守番電話の場合(発信時)の動作です。hangup または leave_message を指定します。デフォルトは hangup です。
voicemailMessagevoicemailAction が leave_message の場合に流す音声メッセージです(最大 1000 文字)。省略すると greeting が使用されます。
transferPhoneNumberエージェントが通話を転送できる E.164 番号です。これを設定すると、エージェントに転送ツールが追加されます。

有効にすると、送信元の番号は着信に自動応答します。

発信する

@zavudev/sdk 0.56.0 以降、SDK で calls リソースを使用できます。必須フィールドは to のみです。senderId を省略すると、プロジェクトのデフォルト送信元(エージェントで音声が有効になっている必要があります)が使用されます。

const { call } = await zavu.calls.create({
  to: "+56912345678",
  senderId: "snd_abc123",
  greeting: "Hi, this is Acme calling about your appointment.",
  maxDurationMinutes: 10,
  metadata: { campaign: "appointment_reminders" },
})

REST 経由(または古い SDK)の場合:

curl -X POST https://api.zavu.dev/v1/calls \
  -H "Authorization: Bearer $ZAVU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+56912345678",
    "senderId": "snd_abc123",
    "greeting": "Hi, this is Acme calling about your appointment.",
    "maxDurationMinutes": 10,
    "metadata": { "campaign": "appointment_reminders" }
  }'

ダイヤルを開始すると、通話オブジェクトとともに 202 が返されます。greeting と maxDurationMinutes は、この通話に限りエージェントの設定を上書きします。

通話と文字起こしを取得する

SDK:zavu.calls.retrieve(callId)(文字起こしを含む)、zavu.calls.list({ status, direction })(自動ページネーション)、zavu.calls.hangup(callId)。REST 経由の場合:

# Single call, including the ordered transcript
curl https://api.zavu.dev/v1/calls/call_abc123 \
  -H "Authorization: Bearer $ZAVU_API_KEY"

# List recent calls (filter by status / direction)
curl "https://api.zavu.dev/v1/calls?direction=outbound&status=completed&limit=50" \
  -H "Authorization: Bearer $ZAVU_API_KEY"

# Hang up an active (queued, ringing or in-progress) call; an ended call answers 409
curl -X POST https://api.zavu.dev/v1/calls/call_abc123/hangup \
  -H "Authorization: Bearer $ZAVU_API_KEY"

文字起こしはターンのリストで、各要素は { seq, role, text } です。role は user、assistant、tool のいずれかです。個別の通話を取得すると含まれますが、一覧には含まれません。通話終了後に durationSeconds、endReason、turnCount、cost が設定されます。

エージェントへのアクセス

ツール、フロー、ナレッジベースには2通りの方法でアクセスでき、どちらも同じリソースです。

/v1/senders/{senderId}/agent/tools     via the sender that answers with it
/v1/agents/{agentId}/tools             via the agent itself

エージェントにまだ送信者がいない場合は、エージェントのスコープ付きの形式を使用してください。POST /v1/agents で作成するエージェントがこれに該当します。POST /v1/agents/{agentId}/senders で送信者を接続すると、送信者のスコープ付きルートからもアクセスできます。POST /v1/agents は、送信者のスコープ付きの作成と同様に apiKey を受け取るため、単独のエージェントでも zavu だけでなく openai、anthropic、google、mistral を使用できます。送信者のスコープ付きの形式ではアクセスできないため、単独で構築するように指示されたエージェントは、これまで構築できませんでした。

AGENT=$(curl -s -X POST https://api.zavu.dev/v1/agents \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY" \
  -d '{"name":"Ada","provider":"zavu","model":"openai/gpt-5.6-luna","systemPrompt":"..."}' \
  | jq -r .agent.id)

curl -X POST https://api.zavu.dev/v1/agents/$AGENT/tools -d '{...}'
curl -X POST https://api.zavu.dev/v1/agents/$AGENT/knowledge-bases -d '{...}'
curl -X POST https://api.zavu.dev/v1/agents/$AGENT/senders -d "{\"senderId\":\"$SENDER_ID\"}"
curl -X PATCH https://api.zavu.dev/v1/agents/$AGENT -d '{"enabled":true}'

会話フロー

フローは、構造化された会話(キーワードによるトリガー、データ収集など)を処理します。

const result = await zavu.senders.agent.flows.create({
  senderId: "snd_abc123",
  name: "Lead Capture",
  description: "Capture lead information from interested prospects",
  trigger: {
    type: "keyword",
    keywords: ["info", "pricing", "demo"],
  },
  steps: [
    {
      id: "welcome",
      type: "message",
      config: { text: "Thanks for your interest! Let me get some info." },
      nextStepId: "ask_name",
    },
    {
      id: "ask_name",
      type: "collect",
      config: { variable: "name", prompt: "What's your name?" },
      nextStepId: "ask_email",
    },
    {
      id: "ask_email",
      type: "collect",
      config: { variable: "email", prompt: "What's your email?" },
      nextStepId: "confirm",
    },
    {
      id: "confirm",
      type: "message",
      config: { text: "Thanks {{name}}! We'll reach out at {{email}}." },
    },
  ],
  enabled: true,
  priority: 10,
});

リクエストで enabled: true が送信されない限り、フローは無効の状態で作成されます。フローとツールの一覧エンドポイントでは、?enabled= に指定できるのは true または false のみです。それ以外の値を指定すると 400 が返されます。

トリガーの種類
TypeDescription
keywordメッセージ内の特定のキーワードに一致します(大文字と小文字を区別しない部分文字列)
intentメッセージが trigger.intent で説明された意図を表しているかを、単語ではなく意味に基づいて判定します
alwaysフロー内にいる場合を除き、受信するすべてのメッセージで実行します

intent には、連絡相手が何を求めているかを任意の言語で平易な一文で記述します。例:{ type: "intent", intent: "asks where their order is" }。どのフローを開始するかを決めるルールは次のとおりです。

  • keyword または always のフローの priority が高い場合、意図を考慮せずにそのフローが優先されます。意図フローの優先度にはより大きな数値を設定してください。意図フローより上位に always フローがあると、意図フローは開始されません。
  • 意図フローが開始されるのは、明確に一致した場合のみです。それ以外の場合は、優先度順で次の keyword または always フローが開始されます。該当するフローがなければ、エージェントが回答します。
  • 1 件のメッセージについて検討される意図フローは最大 12 件です(優先度の高い 12 件)。意図の文字数は 300 文字で切り詰められます。
  • 分類器を利用できない場合、意図に一致しなかったものとしてメッセージが処理されます。連絡相手には引き続き回答が届き、フローは開始されません。
  • 「STOP」や注文番号などの完全一致トークンには意図がありません。keyword を使ってください。

フローが何も返さない場合。 開始メッセージを処理するステップで、返信せずに終了したフローは、そのメッセージをエージェントに引き渡し、エージェントが回答します。意図的に無応答となるケースは次の 3 つです。transfer ステップ(message が空の場合も含む)、返信しないことを選択した llm ステップ、連絡相手にすでに何かを送信したフローです。

  • 担当者が連絡相手に対応している間、エージェントを無応答にするには、フローを transfer ステップで終了します。誰かが受信トレイまたは API から連絡相手にメッセージを送るまで、その連絡相手に対するエージェントの応答は停止します。
  • 返信する always フローはすべてのメッセージを処理するため、その後ろにいるエージェントは回答しません。フローのみで動作するボットには使用できますが、エージェントの前段に置くゲートとしては使わないでください。
  • defaultGoto がない場合、condition を最初のステップにすることはできません。API は 400 invalid_request を返します。まだ何も収集されていないため、条件の結果はどのメッセージでも同じになります。
  • {{ }} から参照できるのは、同じフロー内で先に収集された変数(collect またはツールステップの storeResultAs)のみです。連絡先のフィールドとメタデータは利用できません。{{contact.plan}} は置換されず、条件にも一致しません。名前にドットは使えないため、{{lead.status}} も保存されたオブジェクトの中身にはアクセスできません。値を参照するには、プレーンな値(文字列、数値、ブール値)を返す tool ステップで取得し、それと比較してください。

manual は API で受け付けられ、フローに保存されますが、何も開始しません。これを指定して作成したフローはトリガーされず、そのことも通知されません。

transfer ステップはメッセージを送信してセッションを引き継ぎ済みにし、担当者が回答するまでその連絡相手に対するエージェントの応答を停止します。連絡相手のメッセージは引き続き届き、受信トレイにも表示されますが、エージェントは応答を停止します。連絡相手に送信メッセージを送ると引き継ぎが終了し、エージェントが再び応答します。ただし、通知は行われません。notifyWebhook と reason は受け付けられますが、読み取られることはありません。チームへの通知が必要な場合は、transfer の前に tool ステップを配置してください。

collect ステップの date 検証は、tomorrow を含むあらゆるテキストを受け付けます。日付を制限するには choice を使うか、独自のツールで検証してください。

フローセッションの有効期限はありません。途中で返信をやめた連絡相手が再びメッセージを送信すると、変数を保持したまま同じステップから再開します。

ステップの種類
TypeDescription
messageメッセージを送信します
collectユーザー入力を変数に収集します
condition条件に基づいて分岐します
toolWebhook ツールを呼び出します
llmLLM を呼び出します
transfer人間のエージェントに引き継ぎます
tool ステップと、IDのように見えるフィールド
{
  id: "save_lead",
  type: "tool",
  config: {
    toolName: "create_lead",   // the tool's name, or its id
    action: "call",
    params: { email: "{{email}}", source: "whatsapp" },
    storeResultAs: "lead",
  },
  nextStepId: "confirm",
}

config.toolId は以前から使われている表記で、今も動作します。どちらのフィールドも受け付けられ、どちらにもツール名または ID を指定できます。ダッシュボードが実際の ID を書き込む一方で、toolId は長い間名前として読み取られていたため、実際には両方の形式が存在し、どちらでも解決できます。

{{ }} で囲まれた値は、フロー内でそれ以前に収集されたデータに置き換えられます。それ以外はすべて、そのまま渡されます。引数を取らないツールでは params を省略してください。フローの実行前に、そのツールがエージェントに追加されている必要があります。

エージェントが持っていないツールを参照するステップがあると、セッションは放棄済みとして終了し、設定ミスがログに記録されます。完了したフローとしてはカウントされません。フローがまだ何も発話していなければ、通常のエージェントがそのメッセージに回答します。それ以外の場合は、次のメッセージから会話を再開します。

フローの操作
// List flows
const flows = await zavu.senders.agent.flows.list({ senderId: "snd_abc123" });

// Update flow
await zavu.senders.agent.flows.update({
  senderId: "snd_abc123",
  flowId: "flow_abc123",
  enabled: false,
});

// Duplicate flow
await zavu.senders.agent.flows.duplicate({
  senderId: "snd_abc123",
  flowId: "flow_abc123",
  newName: "Lead Capture (Copy)",
});

// Delete flow
await zavu.senders.agent.flows.delete({
  senderId: "snd_abc123",
  flowId: "flow_abc123",
});

自分で構築する必要のない予約スキル

check_availability と book_meeting は Zavu がホストしているため、エンドポイントもホスティングもシークレットも必要ありません。プロジェクトごとに 1 つのカレンダー(Cal.com または Google Calendar)を読み書きし、通話でもスレッドでも同じように動作します。

これらはダッシュボードのエージェントの Tools タブにある Library から、カレンダー接続とあわせて追加します。現時点では REST や SDK のインターフェースがないため、API で追加するようユーザーに案内しないでください。

予約エージェントがこれらを使用する際に重要なのは、book_meeting はカレンダーが予約を受け付けた場合にのみ、予約が確定したと報告することです。確認を必須とする Cal.com のイベントタイプでは pending が返され、スキルはエージェントに、時間は確保されたものの確定していないと伝えるよう指示します。ツールの結果が返る前に確定を知らせるよう指示するプロンプトは、決して作成しないでください。

Webhook ツール

ツールを使うと、エージェントは会話中にバックエンドを呼び出せます。

ツールを呼び出すチャネル:すべてです。 ツールは音声、プレーンテキスト(WhatsApp、SMS、Telegram、メール)、フローの tool ステップでモデルに提供されます。いずれも同じ実行処理を通るため、チャネルごとにツールの動作を変えることはできません。モデルは 1 回の返信で最大 5 ラウンドまでツールを連続して呼び出せます。ループ全体で使用したトークンに対して課金されます。

テキストではツールを呼び出せないからではなく、手順を確実に実行する必要があるときにフローを使用してください。テキストからでもツールを呼び出せます。

思い込みではなく、実行ごとに確認してください。ツールを持つエージェントで toolCalls: 0 となっている場合、ツールを呼び出さずに回答したことを意味します。「確認します」と言ったのに何も起きなかった場合がこれに当たります。

const result = await zavu.senders.agent.tools.create({
  senderId: "snd_abc123",
  name: "get_order_status",
  description: "Get the current status of a customer order",
  webhookUrl: "https://api.example.com/webhooks/order-status",
  webhookSecret: process.env.WEBHOOK_SECRET,
  parameters: {
    type: "object",
    properties: {
      order_id: { type: "string", description: "The order ID to look up" },
    },
    required: ["order_id"],
  },
});

// Test tool
await zavu.senders.agent.tools.test({
  senderId: "snd_abc123",
  toolId: "tool_abc123",
  testParams: { order_id: "ORD-12345" },
});

ナレッジベース(RAG)

ドキュメントを添付せずに「ドキュメントから返された内容だけを述べる」とプロンプトで指示しても、回答を拒否するのではなく、情報を作り出してしまいます。ドキュメントを添付してから agents test で検証してください。実際に取得したチャンク数が表示されます。

CLI から実行する場合:

npx zavudev agents knowledge-bases create --sender snd_abc123 --name "Product docs"
npx zavudev agents knowledge-bases documents add --sender snd_abc123 --kb <kbId> \
  --title "Pricing" --content-file ./pricing.md
npx zavudev agents knowledge-bases documents list --sender snd_abc123 --kb <kbId>

処理には数秒かかります。isProcessed が true に切り替わり、chunkCount に値が設定されます。

検索拡張生成でエージェントが参照できるように、ドキュメントを追加します:

// Create knowledge base
const kb = await zavu.senders.agent.knowledgeBases.create({
  senderId: "snd_abc123",
  name: "Product FAQ",
  description: "Frequently asked questions about our products",
});

// Add document
await zavu.senders.agent.knowledgeBases.documents.create({
  senderId: "snd_abc123",
  kbId: kb.knowledgeBase.id,
  title: "Return Policy",
  content: "Our return policy allows returns within 30 days of purchase...",
});

// List documents
const docs = await zavu.senders.agent.knowledgeBases.documents.list({
  senderId: "snd_abc123",
  kbId: kb.knowledgeBase.id,
});

モニタリング

// Get agent stats
const stats = await zavu.senders.agent.stats({ senderId: "snd_abc123" });
console.log(`Invocations: ${stats.totalInvocations}`);
console.log(`Tokens: ${stats.totalTokensUsed}`);
console.log(`Cost: $${stats.totalCost}`);
// successCount, errorCount and avgLatencyMs cover the 100 most recent
// executions, `filtered` ones excluded. avgLatencyMs is null when there are none.
console.log(stats.successCount, stats.errorCount, stats.avgLatencyMs);

// List executions
const executions = await zavu.senders.agent.executions.list({
  senderId: "snd_abc123",
  status: "error",
  limit: 20,
});
for (const exec of executions.items) {
  console.log(exec.id, exec.status, exec.errorMessage);
}
実行ステータス
ステータス説明
successエージェントが正常に応答を生成しました
error実行に失敗しました(LLM エラー、ツールエラーなど)
filteredエージェントが回答する前にメッセージが除外されました(チャネルまたはタイプがトリガーに含まれていない、グループ返信の上限)。またはエージェントが NO_REPLY と回答し、何も送信されませんでした。理由は errorMessage に記載されます。
rate_limitedプロバイダーのレート制限を超過しました
balance_insufficient処理に必要なアカウント残高が不足しています

エージェントは独自の ID で指定します

エージェントは独立したオブジェクトです。複数の送信元に応答でき、構築中は送信元が紐付いていない状態でも存在できます。

npx zavudev agents list                 # every agent in the project, with ids
npx zavudev agents list --json
id                                name        kind   enabled  senders  model
qd75detym58c6has4sfrye3vws8b6ygt  Atlas       voice  yes      1        openai/gpt-5.6-luna
qd7ck28evcskdc3xx4wzevtmeh8b6bcm  Pizza Desk  text   no       0        gpt-4o-mini

REST の場合:

GET /v1/agents送信元がないエージェントも含めて一覧表示
POST /v1/agents送信元なしでエージェントを単独作成
GET /v1/agents/{agentId}エージェントを 1 件取得
PATCH /v1/agents/{agentId}エージェントを更新
DELETE /v1/agents/{agentId}エージェントを削除
POST /v1/agents/{agentId}/testエージェントを実行し、返信を返します。配信はしません

以前からある /v1/senders/{senderId}/agent ルートも引き続き使用できます。これらは送信元を、そこに応答する 1 つのエージェントに解決します。対象は、その送信元上で作成されたエージェント、または POST /v1/agents/{agentId}/senders で送信元に接続されたエージェントです。送信元のないエージェントにはアクセスできません。エージェントが紐付いていない送信元に対する GET /v1/senders/{senderId}/agent は 404 を返します。

エージェント全体ではなく、1 つのツールを実行するには:

POST /v1/senders/{senderId}/agent/tools/{toolId}/test指定したパラメーターでツールを呼び出し、応答を返します
GET /v1/senders/{senderId}/agent/tools/{toolId}/test-runs最近の実行を新しい順に表示します

CLI の場合:

npx zavudev agents tools test <toolId> --sender <senderId> --params '{"orderId":"ORD-4417"}'
npx zavudev agents tools test-runs <toolId> --sender <senderId>

テストは同期的に実行され、ツールのステータス、本文、実行時間を返すため、結果からツールが実行されたことを確認できます。エラーを返すツールの場合、run.success: false となりますが、エンドポイントは引き続き 200 を返します。ステータスではなく、このフィールドを確認してください。実際の Webhook が呼び出されるため、ツールが持つ副作用も発生します。

test-runs に記録されるのは手動テストのみです。実際の会話中にエージェントが呼び出したツールはここには表示されません。その場合は、agents executions で各返信が呼び出したツールの数を確認できます。

送信元の接続
npx zavudev agents senders connect    --agent <agentId> --sender <senderId>
npx zavudev agents senders disconnect --agent <agentId> --sender <senderId>

POST /v1/agents/{agentId}/senders に {"senderId": "..."} を指定し、DELETE /v1/agents/{agentId}/senders/{senderId} を実行します。

送信元が応答できるエージェントは最大 1 つです。 すでに使用中の送信元を接続しようとすると、割り当てているエージェント名を示す 400 が返されます。別の方法では、接続されているように見えるのにメッセージを一切受信しないエージェントが生じてしまうためです。

何も送信せずにエージェントをテストする

npx zavudev agents test --agent <agentId> --message "where is order ORD-001?"

実際のプロンプト、モデル、ナレッジベースを使用して実行し、エージェントが返信する内容に加えて、トークン数、レイテンシ、使用したナレッジチャンク数を表示します。配信は行われず、実行ログにも記録されません。

テスト実行にも実際の返信と同様の料金が発生します。 zavu プロバイダーを使用するエージェントでは、トークンあたり同じ料金(レスポンスの cost)が残高から請求され、残高が 0 の場合は 402 insufficient_balance で拒否されます。独自の API キーを使用するエージェントの場合は、プロバイダーに料金が発生します。実行はプロジェクトごとにレート制限されます(429)。テストモードのキーにも同じ料金が発生し、executeTools を指定すると、実際のハンドラーが呼び出され、実際のメモリが書き込まれます。

モデルにはエージェントのツールが提示されますが、ツールは実行されません。モデルがツールを選んだ場合、返信はそこで停止し、選択したツールと引数が plannedToolCalls に示されます。実際にツールを実行するには executeTools を渡してください。これにより実際のハンドラーが呼び出されます。

また、ドライランでは確認できない点についても警告します。無効化されたエージェント、エージェントがトリガーするチャネルを持たない送信元、そして実際の稼働時には存在するものの、ここでは存在しない連絡先メタデータです。これらの警告も結果の一部として扱ってください。

複数ターンと、プロンプトを検索処理から切り離す方法:

npx zavudev agents test --agent <agentId> \
  --turn "I need to change my booking" --turn "Sure — which one?" \
  --message "the one on Friday"

npx zavudev agents test --agent <agentId> --message "what do you cost?" --no-knowledge

エージェントを削除する

await zavu.senders.agent.delete({ senderId: "snd_abc123" });

エージェントが応答するチャネル

triggerOnChannels は許可リストであり、完成しているように見えるのにエージェントが無応答になる最も一般的な原因です。チャネルがリストに含まれていない受信メッセージは、エージェントの実行前に破棄されます。返信もエラーも発生しませんが、ダッシュボードの Playground はフィルターを迂回するため、引き続き応答します。GET /v1/senders/{senderId}/agent/executions で確認してください。破棄されたメッセージは status: "filtered" として表示され、errorMessage には受信したチャネルとエージェントが受信するチャネルが記載されます。

["*"] は送信元が扱うすべてのチャネルを意味し、デフォルトとして最適です。意図的にチャネルを除外する場合にのみ、対象を絞り込んでください。また、後から送信元にチャネルを追加しても、ここには追加されないことに注意してください。不明な文字列も受け入れられますが、どのチャネルにも一致しないため、タイプミスは除外するつもりだったチャネルとまったく同じように動作します。

無応答にする:NO_REPLY

エージェントの回答全体をトリミングした結果が正確に NO_REPLY であれば、何も送信されません。これはすべてのチャネルと、フローの llm ステップにも適用されます。実行は status: "filtered" として記録され、errorMessage にはエージェントが返信しないことを選択した旨が記載されます。使用したトークンは引き続き課金され、カウントされます。

エージェントのプロンプトで、どのような場合に NO_REPLY と回答するかを伝えて使用します(「メッセージがお礼である場合、または回答が不要な場合は、NO_REPLY と返信してください」)。判断するのはモデルであり、会話のほかの要素は変わりません。

制約

  • 送信元ごとにエージェントは1つです。 その送信元がすでにエージェントで応答している場合、POST /v1/senders/{senderId}/agent は 409 conflict を返します。使用中の送信元を接続しようとすると、400 が返されます。どの読み取りでも、送信元に解決されるエージェントは必ず1つです。
  • ツール名はエージェントごとに一意です。 同じ名前のツールを2つ目として作成すると、409 conflict が返されます。
  • システムプロンプト:最大10,000文字
  • コンテキストウィンドウ:1~50件のメッセージ
  • 温度:0~2
  • 最大トークン数:1~4,096
  • ツール名:最大100文字
  • ツールの説明:最大500文字
  • ドキュメントの内容:最大100,000文字
  • ナレッジベース名:最大100文字
  • プロバイダー zavu は API キーを必要としません(Zavu がホストするモデルを使用)
  • それ以外のすべてのプロバイダーでは、ご自身の API キーが必要です

コメント