mcpField
A
ai-agent

ai-agent

github.com/zavudevAgent 工作流1234 次安装今天更新
代码仓库

关于 ai-agent

用于通过 API 或仪表板配置 Zavu AI Agent 的技能,适合以命令式方式创建和更新 Agent。涵盖消息渠道、对话流程、工具、知识库及语音通话;新集成通常推荐使用 functions 技能。

主要功能

  1. 01通过 API 创建和更新 Agent
  2. 02配置提供方、模型和提示词
  3. 03管理消息发送方及渠道连接
  4. 04设置对话流程、工具和知识库
  5. 05启用语音并管理电话通话

适用场景

  1. 01从后台脚本创建客服 Agent
  2. 02通过仪表板更新 Agent 配置
  3. 03为消息渠道配置关键词触发流程
  4. 04设置可接听或拨出电话的 Agent

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/ai-agent确认已加载。

详细介绍

AI Agent

使用时机

当用户希望通过API 调用配置 AI Agent(无需源文件,也无需部署步骤)时,请使用此技能——通常是在控制面板或后端脚本中以命令式方式创建或更新 Agent。

如果用户希望使用 TypeScript 编写以代码为先、带自定义工具处理程序的 Agent,并通过 zavu CLI 部署,请引导他们使用 functions 技能。该方式更便捷、支持版本控制,并内置部署和调试功能。

快速判断:

用户说……使用
“我希望 Agent 的工具能查询我的数据库” / “我想用代码编写工具处理程序” / defineTool / npx zavudev deployfunctions 技能
“设置一个能调用我服务器上 webhook 的 Agent” / “从控制面板配置” / “通过 API 创建 Agent”此技能
“我从零开始,希望选择最简单的方式”functions 技能(默认推荐)

此处介绍的命令式 API 完全受支持,不会弃用,但对于大多数新的集成,我们推荐使用 Functions。

发送方与账户(一段说明)

**发送方(Sender)**是你作为 Zavu-Sender 传入的 API 标识;账户(WhatsApp Business Account、Facebook Page、Telegram 机器人、电话号码)则是它路由到的连接,也是产生费用的对象。发送方免费。在控制面板中连接账户时,会自动创建其发送方;使用 GET /v1/senders 查找,并依据其 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

创建 Agent 的两种方式

以代码方式使用 defineAgent。 Agent 位于 Zavu Function 中,与它调用的工具并列,由 npx zavudev deploy 进行同步。若 Agent 带有工具、需要在拉取请求中接受审查,或属于你已部署的应用,请优先选择此方式。完整结构请参阅 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 部署。同步输出会列出创建或更新的每个 Agent 和工具,因此请仔细阅读,不要想当然:即使声明未能同步,部署也可能成功;发生这种情况时,输出会明确说明。

通过 API,如下所示。若用于一次性设置、由你正在构建的控制面板管理的 Agent,或没有可附加 Agent 的 Function,请优先选择此方式。

无论选择哪种方式,创建的 Agent 默认都处于禁用状态。启用之前,它不会回复任何消息。

创建 Agent

每个发送方只能有一个 Agent。如果某个发送方已有 Agent 回复消息(在该发送方上创建,或通过 POST /v1/agents/{agentId}/senders 连接到该发送方),再创建第二个 Agent 会返回 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 托管的模型否(已包含)

更新与切换 Agent

// 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,
});

切换提供商时,需要提供新提供商的密钥。 已存储的提供商密钥仅属于一个提供商。如果 Agent 当前持有的密钥属于其他提供商,而更新操作要将 provider 切换为 openai、anthropic、google 或 mistral,请求会被拒绝并返回 400 invalid_request(“This API key is for anthropic, but the agent uses openai.”),而不会保存一个在收到第一条消息时就会失败的 Agent。在同一个请求中同时发送 provider 和 apiKey;PATCH /v1/senders/{senderId}/agent 和 PATCH /v1/agents/{agentId} 都接受 apiKey。切换到 zavu 无需密钥。

语音

Agent 还可以通过 Zavu 的集成语音网络(语音识别、Agent 的 LLM、语音合成以及实时打断处理)接听和拨打电话。通话中同样适用 systemPrompt、工具和知识库——语音只是在此基础上增加了一个语音渠道。如需用 TypeScript 声明以代码为先的语音 Agent,请改用 functions 技能。

要求

  • Agent 必须设置 voice.enabled: true。
  • 发送方必须启用语音渠道。 如果发送方无法接听电话,即使 Agent 已启用语音,也会显得配置正常,却始终不会响铃。发送方需要一个由项目所有的电话号码,并设置 enableVoice:
    npx zavudev senders update snd_abc123 --enable-voice
    
    运行 npx zavudev senders get snd_abc123 确认:channels 中必须包含 voice。该数组根据发送方的实际配置计算得出,因此应以它为准,而不是某个存储的标志。
  • 测试模式密钥不可用——请使用正式环境密钥(zv_live_...)。
  • 通话费用按接通分钟数和电信费用计费,并从预付余额中扣除。
在 Agent 上启用语音

语音配置位于 POST/PATCH /v1/senders/{senderId}/agent 的 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"
    }
  }'
字段描述
enabledAgent 是否处理电话。必填。设为 false 时,不会接听拨打到其号码的电话,且会拒绝外拨电话。
greeting接通时说出的开场白(最多 1000 个字符)。省略时,Agent 会等待来电者先说话。
language用于识别和合成的 BCP-47 代码(例如 en、es、pt-BR)。省略时会根据接收方自动检测。
ttsVoiceId用于合成的语音。使用 npx zavudev agents voices(或 GET /v1/agents/voices)列出 ID;不在列表中的名称会被忽略。省略时使用默认中性语音。
interruptible来电者可以在 Agent 说话时插话。默认值为 true。
maxCallDurationMinutes通话时长上限,范围为 1-120 分钟。默认值为 15。
maxIdleSecondsAgent 结束通话前的静音时长,范围为 5-300 秒。默认值为 30。
voicemailAction遇到应答机时(外拨):hangup 或 leave_message。默认值为 hangup。
voicemailMessage当 voicemailAction 为 leave_message 时播放(最多 1000 个字符)。未设置时使用 greeting。
transferPhoneNumberAgent 可以将通话转接到的 E.164 号码。设置后,Agent 会获得一个转接工具。

启用后,发送方的号码会自动接听来电。

拨打外拨电话

从 @zavudev/sdk 0.56.0 开始,SDK 提供 calls 资源。to 是唯一必填字段;senderId 默认使用项目的默认发送方(其 Agent 必须已启用语音)。

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 仅对本次通话覆盖 Agent 的配置。

获取通话及其转录文本

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。

寻址 Agent

工具、流程和知识库可以通过两种方式访问,它们指向同一个 资源:

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

当 Agent 还没有发送方时,请使用 Agent 作用域形式,这是 POST /v1/agents 创建的状态。使用 POST /v1/agents/{agentId}/senders 将发送方连接到 Agent 后,也可以通过 发送方作用域路由访问它。POST /v1/agents 和发送方作用域的创建接口一样接受 apiKey,因此独立 Agent 也可以使用 openai、anthropic、google 或 mistral,而不只是 zavu。发送方作用域形式无法寻址该 Agent,因此,过去无法组装被要求独立组装的 Agent。

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。

触发类型
类型描述
keyword匹配消息中的特定关键词(不区分大小写的子字符串)
intent消息表达了 trigger.intent 中描述的意图,按含义而非字面用词判断
always对每条尚未进入某个流程的入站消息运行

对于 intent,用一句简单的话描述联系人想要什么,语言不限:{ type: "intent", intent: "asks where their order is" }。决定启动哪个流程的规则:

  • 优先级更高的 keyword 或 always 流程会直接胜出,不考虑意图。为意图流程设置更高的优先级数值;否则,优先级高于它们的 always 流程会导致它们永远不会启动。
  • 意图流程只有在明确匹配时才会启动。否则,按优先级顺序启动下一个 keyword 或 always 流程;如果没有,则由 Agent 回复。
  • 每条消息最多考虑 12 个意图流程(优先级最高的 12 个)。意图内容会截断至 300 个字符。
  • 如果分类器不可用,系统会按没有匹配意图处理:联系人仍会收到回复,但流程不会启动。
  • “STOP” 或订单号等精确匹配的词项不代表意图。请使用 keyword。

流程未发送回复时。 如果流程在启动它的消息上结束,且没有回复,就会将该消息交给 Agent,由 Agent 回复。以下三种情况是有意保持静默:transfer 步骤(即使 message 为空)、选择不回复的 llm 步骤,以及此前已向联系人发送过内容的流程。

  • 要在有人处理联系人期间让 Agent 保持安静,请以 transfer 步骤结束流程。该步骤会让 Agent 对该联系人保持静默,直到有人通过收件箱或 API 向其发送消息。
  • 会发送回复的 always 流程会接管每条消息,因此其后的 Agent 永远不会回复。仅当机器人完全由流程组成时才使用它,不要将其用作 Agent 前面的拦截环节。
  • 除非 condition 有 defaultGoto,否则不能将它作为第一步:API 会返回 400 invalid_request。此时还没有收集任何内容,因此每条消息的条件结果都会相同。
  • {{ }} 只读取同一流程中先前收集的变量(通过 collect,或工具步骤的 storeResultAs)。无法读取联系人字段和元数据:{{contact.plan}} 不会被替换,条件也永远不会匹配。变量名不能包含点,因此 {{lead.status}} 也无法读取已存储对象中的字段。请在返回简单值(字符串、数字或布尔值)的 tool 步骤中查询该值,然后再进行比较。

API 接受 manual 并将其存储在流程中,但不会启动它:使用此触发类型创建的流程永远不会触发,也不会报告任何相关信息。

transfer 步骤会发送其消息、将会话标记为已转接,并让 Agent 对该联系人保持静默,直到有人回复。联系人的消息仍会收到并显示在收件箱中,只是 Agent 不再回复。向联系人发送任何出站消息都会结束转接,Agent 随后恢复回复。不过,系统不会替你通知任何人:notifyWebhook 和 reason 虽然会被接受,但不会被读取;如果团队需要收到提醒,请在转接前添加一个 tool 步骤。

collect 步骤的 date 验证接受任何文本,包括 tomorrow。请使用 choice 限定日期,或在自己的工具中验证。

流程会话不会过期。联系人如果中途不再回复,下次发消息时会从同一步骤继续,并保留已有变量。

步骤类型
类型描述
message发送消息
collect将用户输入收集到变量中
condition根据条件分支
tool调用 webhook 工具
llm发起 LLM 调用
transfer转接给人工 Agent
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:长期以来,toolId 一直被当作名称读取,但仪表板会将真正的 ID 写入其中,因此实际使用中这两种形式都存在,也都能正确解析。

用 {{ }} 包裹的值会被之前流程中收集的数据替换;其他内容则按原样传递。对于不需要参数的工具,请省略 params。流程运行前,该工具必须已添加到 Agent。

如果某个步骤指向 Agent 不具备的工具,会话会以 abandoned 状态结束,并记录配置错误。该会话不会计为已完成的流程。如果流程此前还没有说过任何内容,普通 Agent 会回答这条消息;否则,它会在用户发送下一条消息时继续对话。

流程操作
// 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 托管:无需端点、托管服务或密钥。它们会读取和写入每个项目的一个日历(Cal.com 或 Google Calendar),在通话和聊天线程中的表现完全相同。

可在仪表板中通过 Agent 的 Tools 标签页下的 Library 添加这些技能,并在此处连接日历。目前它们尚无 REST 或 SDK 接口,因此不要告知用户通过 API 添加。

预约 Agent 使用这些技能时,需注意:只有日历接受预约后,book_meeting 才会报告预约成功。需要确认的 Cal.com 活动类型会返回 pending,技能会告知 Agent,时间已暂时保留,但尚未确认。绝不要在提示词中指示 Agent 在工具结果确认之前就宣布预约已确认。

Webhook 工具

工具可让 Agent 在对话过程中调用你的后端。

哪些渠道会调用工具:全部渠道。 在语音、纯文本(WhatsApp、SMS、Telegram、电子邮件)以及流程的 tool 步骤中,工具都会提供给模型。三者都通过同一个执行器分发,因此工具无法因渠道不同而表现不同。模型在一次回复中最多可以连续执行五轮工具调用,而你需要为整个循环所用的 Token 付费。

只有在必须确保执行顺序时才使用流程,不要因为认为文本对话无法调用工具而使用流程。它可以调用。

请逐次执行进行验证,而不要想当然:如果 Agent 已配置工具,但 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)

如果没有附加文档,提示词即使要求“只陈述文档返回的内容”,Agent 也不会拒答,而是会编造内容。请先附加文档,然后使用 agents test 验证;该命令会报告实际检索到的分块数量。

从命令行运行:

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 会填入数量。

添加文档,供 Agent 通过检索增强生成进行参考:

// 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);
}
执行状态
状态描述
successAgent 成功生成了回复
error执行失败(大模型错误、工具错误等)
filtered在 Agent 回复前,消息被丢弃(渠道或类型不在其触发条件内、群组回复达到上限),或者 Agent 回复了 NO_REPLY,因此没有发送任何内容。errorMessage 会说明原因。
rate_limited超出提供商的速率限制
balance_insufficient账户余额过低,无法处理

Agent 使用自身 ID 寻址

Agent 是独立对象。它可以通过多个发送方作答,并且在构建期间也可以不存在任何发送方。

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列出 Agent,包括没有发送方的 Agent
POST /v1/agents创建独立 Agent——无需发送方
GET /v1/agents/{agentId}获取一个 Agent
PATCH /v1/agents/{agentId}更新
DELETE /v1/agents/{agentId}删除
POST /v1/agents/{agentId}/test运行 Agent,返回回复,不发送任何内容

旧版 /v1/senders/{senderId}/agent 路由仍然可用。它们会将发送方解析为在该发送方上作答的唯一一个 Agent:在该发送方上创建的 Agent,否则就是通过 POST /v1/agents/{agentId}/senders 与其关联的 Agent。它们无法访问没有发送方的 Agent。对于没有 Agent 的发送方,GET /v1/senders/{senderId}/agent 会返回 404。

要测试单个工具,而不是整个 Agent:

POST /v1/senders/{senderId}/agent/tools/{toolId}/test使用你的参数调用工具,并返回它的响应
GET /v1/senders/{senderId}/agent/tools/{toolId}/test-runs最近的运行记录,按时间从新到旧排列

通过命令行:

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 仅包含手动测试。Agent 在真实对话中调用的工具不会列在其中;要查看这类调用,请使用 agents executions 查看每条回复调用了多少个工具。

连接发送方
npx zavudev agents senders connect    --agent <agentId> --sender <senderId>
npx zavudev agents senders disconnect --agent <agentId> --sender <senderId>

使用 {"senderId": "..."} 调用 POST /v1/agents/{agentId}/senders,并调用 DELETE /v1/agents/{agentId}/senders/{senderId}。

一个发送方最多只能由一个 Agent 作答。 如果连接的发送方已被使用,操作会返回 400,并指出占用它的 Agent——否则 Agent 看起来已经连接,却永远收不到消息。

测试 Agent,但不发送任何内容

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

运行真实的提示词、模型和知识库,并打印 Agent 本会给出的回复,以及令牌数、延迟和使用的知识片段数。不会发送任何内容,也不会记录执行。

测试运行的计费方式与实时回复相同。 对于使用 zavu 提供方的 Agent,费用会按相同的每令牌价格(响应中的 cost)从余额中扣除;余额为零时会返回 402 insufficient_balance。对于使用自带密钥的 Agent,费用由你的提供方收取。每个项目的运行次数都有限制(429)。测试模式的密钥也按相同方式计费;使用此类密钥调用 executeTools 仍会触达你的真实处理程序,并写入真实记忆。

模型可以使用 Agent 的工具,但不会运行任何工具:如果它选择了某个工具,回复就会在此处停止,而 plannedToolCalls 会列出选择的工具及其参数。传入 executeTools 即可实际运行这些工具——这会触达你的处理程序。

它还会提示干跑无法验证的内容:已禁用的 Agent、没有 Agent 所触发渠道的发送方,以及仅在实时场景中才会存在的联系人元数据。请将这些警告视为结果的一部分。

多轮测试,以及将提示词与检索隔离:

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

删除 Agent

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

Agent 回复的渠道

triggerOnChannels 是一个白名单,也是最常见的导致 Agent 看起来配置完成却不回复的原因。若入站消息的渠道不在列表中,该消息会在 Agent 运行前被丢弃:既没有回复,也没有错误;而控制面板中的 Playground 仍会正常回复,因为它会绕过此筛选器。可在 GET /v1/senders/{senderId}/agent/executions 中查看,丢弃的消息会显示为 status: "filtered",且 errorMessage 会指出收到的渠道以及 Agent 监听的渠道。

["*"] 表示发送方承载的所有渠道,是合适的默认值。只有在有意排除某个渠道时才缩小范围;并且请记住,之后向发送方添加渠道不会将其自动添加到此处。系统会接受未知字符串,但它们不会匹配任何渠道,因此拼写错误的效果与有意排除某个渠道完全相同。

保持静默:NO_REPLY

如果 Agent 的完整回复去除首尾空白后恰好为 NO_REPLY,则不会发送任何内容。此规则适用于所有渠道,也适用于工作流的 llm 步骤。执行记录会显示为 status: "filtered",且 errorMessage 会说明 Agent 选择不回复;使用的令牌仍会计费并计数。

可在提示词中告诉 Agent 何时回复 NO_REPLY(“如果消息是在表示感谢,或不需要回复,请回复 NO_REPLY”)。由模型决定;对话中的其他内容不会因此改变。

约束

  • 每个发送方只能有一个 Agent。 当发送方已由 Agent 回复时,POST /v1/senders/{senderId}/agent 会返回 409 conflict;连接正在使用中的发送方则会返回 400。每次读取都会将发送方解析为唯一一个 Agent。
  • 每个 Agent 的工具名称必须唯一。 创建同名的第二个工具会返回 409 conflict。
  • 系统提示词:最多 10,000 个字符
  • 上下文窗口:1–50 条消息
  • 温度:0–2
  • 最大令牌数:1–4,096
  • 工具名称:最多 100 个字符
  • 工具描述:最多 500 个字符
  • 文档内容:最多 100,000 个字符
  • 知识库名称:最多 100 个字符
  • 提供商 zavu 无需 API 密钥(使用 Zavu 托管的模型)
  • 其他所有提供商均需要你自己的 API 密钥

评论

支持 Markdown