首页
/ OpenMontage 语音智能体工具开发指南:ElevenLabs Agent 的 Webhook、Client 与系统内置工具

OpenMontage 语音智能体工具开发指南:ElevenLabs Agent 的 Webhook、Client 与系统内置工具

2026-09-05 15:08:37作者:羿妍玫Ivan

在 OpenMontage 的智能体技能体系中,.agents/skills/agents/ 技能负责指导开发者使用 ElevenLabs Conversational AI 平台构建实时语音智能体(语音助手、客服机器人、交互式语音角色等),而本文聚焦其中的 Client Tools 参考文档:讲清楚如何用三类工具——服务端 Webhook 工具、浏览器端 Client 工具、平台内置 System 工具——扩展语音 Agent 的能力边界。读完本文,你可以独立设计一个能查数据库、调 API、操作前端 UI 并能优雅挂断/转接的语音智能体,并掌握工具描述编写、错误处理与超时配置的实战要点。

工具类型总览

ElevenLabs 的智能体工具体系分为三种类型,执行位置与典型用途各不相同:

类型 执行位置 典型用途
Webhook 服务端(通过 HTTP) 数据库查询、API 调用、需要保密凭证的安全操作
Client 浏览器端 JavaScript UI 更新、localStorage 读写、页面导航
System ElevenLabs 内置 结束通话、转接人工、标准动作

选型原则:涉及密钥、数据库或需要审计的操作放在 Webhook 端;纯前端交互(弹卡片、跳转页面)放在 Client 端;通话生命周期控制(挂断、转接)交给内置工具,无需自己实现。

工具定义的位置

三类工具都定义在智能体的 conversation_config.agent.prompt 中,但放置位置不同:Webhook 与 Client 工具放入 tools 数组,System 工具放入 built_in_tools 对象:

conversation_config={
    "agent": {
        "prompt": {
            "prompt": "You are helpful.",
            "llm": "gemini-2.0-flash",
            "tools": [...],            # Webhook 和 client 工具
            "built_in_tools": {...}     # System 工具(end_call、transfer 等)
        }
    }
}

这一点很关键:如果把内置工具误放进 tools 数组,平台不会按预期行为处理;反之,自定义工具不能出现在 built_in_tools 中。完整的 conversation_config 结构(包括 ttsasrturnvad 等兄弟字段)可在 Agent Configuration 参考 中查阅。

Webhook 工具:让 Agent 调用你自己的服务端逻辑

Webhook 工具在 Agent 需要外部数据或动作时触发,由 ElevenLabs 服务端向你的 HTTP 端点发起请求。

基本 Webhook 定义

下面通过 Python SDK 创建一个带天气查询 Webhook 的 Agent,展示 api_schema 的完整字段(URL、方法、请求头、请求体 JSON Schema):

agent = client.conversational_ai.agents.create(
    name="Weather Assistant",
    conversation_config={
        "agent": {
            "prompt": {
                "prompt": "You are a helpful assistant that can check the weather.",
                "llm": "gemini-2.0-flash",
                "tools": [{
                    "type": "webhook",
                    "name": "get_weather",
                    "description": "Get current weather for a city. Use when user asks about weather.",
                    "api_schema": {
                        "url": "https://api.example.com/weather",
                        "method": "POST",
                        "request_headers": {
                            "Authorization": "Bearer {{API_KEY}}"
                        },
                        "request_body_schema": {
                            "type": "object",
                            "properties": {
                                "city": {
                                    "type": "string",
                                    "description": "City name, e.g., 'San Francisco'"
                                },
                                "units": {
                                    "type": "string",
                                    "enum": ["celsius", "fahrenheit"],
                                    "description": "Temperature units"
                                }
                            },
                            "required": ["city"]
                        }
                    }
                }]
            }
        },
        "tts": {"voice_id": "JBFqnCBsd6RMkjVDRZzb"}
    }
)

注意 description 中写明了触发时机("Use when user asks about weather"),这是引导 LLM 正确选择工具的核心手段,详见后文最佳实践。

Webhook 请求格式

当 Agent 调用 Webhook 工具时,ElevenLabs 会向你配置的 URL 发送如下 JSON:

{
  "tool_call_id": "call_abc123",
  "tool_name": "get_weather",
  "parameters": {
    "city": "San Francisco",
    "units": "fahrenheit"
  },
  "conversation_id": "conv_xyz789"
}

tool_call_id 用于在你的服务端日志中追踪单次调用,conversation_id 可用来把工具结果与会话上下文关联。

Webhook 响应格式

你的服务端只需返回 result 字段,支持两种形态:

  • 直接返回自然语言字符串,Agent 可基于其组织回复:
{
  "result": "The weather in San Francisco is 68°F and sunny."
}
  • 返回结构化数据,交由 Agent 自行理解:
{
  "result": {
    "temperature": 68,
    "condition": "sunny",
    "humidity": 45
  }
}

带认证的 Webhook

通过 request_headers 传递 Bearer Token 或自定义业务头,并用 response_timeout_secs 控制超时:

# 位于 conversation_config.agent.prompt.tools 内
{
    "type": "webhook",
    "name": "lookup_order",
    "description": "Look up order status by order ID",
    "response_timeout_secs": 10,
    "api_schema": {
        "url": "https://api.mystore.com/orders/lookup",
        "method": "POST",
        "request_headers": {
            "Authorization": "Bearer {{ORDER_API_KEY}}",
            "X-Store-ID": "store_123"
        },
        "request_body_schema": {
            "type": "object",
            "properties": {
                "order_id": {
                    "type": "string",
                    "description": "Order ID (e.g., ORD-12345)"
                }
            },
            "required": ["order_id"]
        }
    }
}

用工作区环境变量管理多环境配置

为了让同一份服务端工具配置在 staging 与 production 间复用,可以使用工作区(workspace)环境变量:

  • {{system_env__label}} 语法可用于工具 URL;
  • 机密环境变量(secret env var)可填充 request_headers
  • 认证连接(auth-connection)环境变量可填充 api_schema.auth_connection
{
  "api_schema": {
    "url": "https://{{system_env__api_host}}.example.com/orders",
    "method": "GET",
    "request_headers": {
      "X-Api-Key": { "env_var_label": "orders_api_key" }
    },
    "auth_connection": { "env_var_label": "orders_oauth" }
  }
}

工作区认证连接支持 OAuth2 client credentials、OAuth2 JWT、Private Key JWT、Basic Auth、Bearer Auth 以及自定义 Header 认证。此外,系统动态变量也可用在工具参数和 Header 中:{{system__conversation_history}} 会把完整对话上下文以惰性求值的 JSON 历史对象(含 user、agent、tool 条目)传给 Webhook 或子 Agent,适合需要全量会话上下文的场景。同样的环境变量解析机制也适用于 MCP 服务器连接配置。

Webhook 工具可选参数

字段 类型 默认值 说明
response_timeout_secs int 20 超时秒数,取值范围 5–120
disable_interruptions bool false 工具执行期间禁止用户打断
execution_mode string "immediate" immediatepost_tool_speechasync
tool_call_sound string - 执行期间播放的声音:typingelevator1elevator4
force_pre_tool_speech bool false 强制 Agent 在执行工具前先说话(如"稍等,我查一下")
tool_error_handling_mode string "auto" autosummarizedpassthroughhide

注意api_schema.method 的默认值是 GET。凡是带请求体的 Webhook 工具,必须显式设置 "method": "POST",否则请求体会被丢弃。

服务端实现:Node.js

app.post("/webhook/get_weather", async (req, res) => {
  const { parameters, conversation_id } = req.body;
  const { city, units = "fahrenheit" } = parameters;

  // 从你的数据源获取天气
  const weather = await weatherService.get(city, units);

  res.json({
    result: `It's ${weather.temp}°${units === "celsius" ? "C" : "F"} and ${weather.condition} in ${city}.`,
  });
});

服务端实现:Python

@app.post("/webhook/get_weather")
async def get_weather(request: Request):
    data = await request.json()
    city = data["parameters"]["city"]
    units = data["parameters"].get("units", "fahrenheit")

    # 从你的数据源获取天气
    weather = weather_service.get(city, units)

    return {
        "result": f"It's {weather['temp']}°{'C' if units == 'celsius' else 'F'} and {weather['condition']} in {city}."
    }

Client 工具:在用户浏览器中执行 JavaScript

Client 工具在用户的浏览器里执行 JavaScript,适合 UI 更新、页面导航和访问浏览器 API(localStorage、摄像头、位置等)。

注册 Client 工具

Client 工具的实际函数体在启动会话时通过 clientTools 传入,而不是写在 Agent 配置里:

import { Conversation } from "@elevenlabs/client";

const conversation = await Conversation.startSession({
  agentId: "your-agent-id",
  clientTools: {
    show_product: async ({ productId }) => {
      // 更新 UI 展示商品
      const modal = document.getElementById("product-modal");
      modal.innerHTML = await fetchProductCard(productId);
      modal.showModal();
      return { success: true, message: "Showing product" };
    },

    navigate_to: async ({ page }) => {
      // 页面跳转
      window.location.href = `/${page}`;
      return { success: true };
    },

    save_preference: async ({ key, value }) => {
      // 存入 localStorage
      localStorage.setItem(key, value);
      return { saved: true };
    },
  },
});

在 Agent 配置中声明 Client 工具

Agent 需要通过 conversation_config.agent.prompt.tools 知晓有哪些 Client 工具及其参数结构(工具名与 clientTools 中的键一一对应):

agent = client.conversational_ai.agents.create(
    name="Shopping Assistant",
    conversation_config={
        "agent": {
            "prompt": {
                "prompt": """You are a shopping assistant.
When users want to see a product, use show_product.
When users want to go somewhere, use navigate_to.""",
                "llm": "gemini-2.0-flash",
                "tools": [
                    {
                        "type": "client",
                        "name": "show_product",
                        "description": "Display a product card to the user",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "productId": {
                                    "type": "string",
                                    "description": "Product ID to display"
                                }
                            },
                            "required": ["productId"]
                        }
                    },
                    {
                        "type": "client",
                        "name": "navigate_to",
                        "description": "Navigate user to a different page",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "page": {
                                    "type": "string",
                                    "enum": ["cart", "checkout", "account", "home"],
                                    "description": "Page to navigate to"
                                }
                            },
                            "required": ["page"]
                        }
                    }
                ]
            }
        },
        "tts": {"voice_id": "JBFqnCBsd6RMkjVDRZzb"}
    }
)

这里体现了 Client 工具的两段式设计:服务端只声明"契约"(名称、描述、参数 Schema),浏览器侧才提供具体实现。对 page 参数使用 enum 约束取值,能显著降低 LLM 产生非法值导致的跳转失败。

Client 工具可选参数

字段 类型 默认值 说明
expects_response bool false 工具是否向 Agent 返回数据

Client 工具的返回值

expects_response 为真时,浏览器函数的返回值会作为工具结果回传给 Agent,供其组织后续对话:

clientTools: {
  check_cart: async () => {
    const cart = JSON.parse(localStorage.getItem("cart") || "[]");
    return {
      itemCount: cart.length,
      total: cart.reduce((sum, item) => sum + item.price, 0),
      items: cart.map((item) => item.name),
    };
  };
}

Agent 收到该数据后可以回应:"You have 3 items in your cart totaling $45.99."。

系统工具:built_in_tools

系统工具由 ElevenLabs 平台内置提供,配置在 conversation_config.agent.prompt.built_in_tools 中(不要放进 tools 数组)。基础用法:

"built_in_tools": {
    "end_call": {},
    "transfer_to_number": {...},
    "transfer_to_agent": {...},
    "language_detection": {},
    "skip_turn": {},
    "voicemail_detection": {...},
    "play_keypad_touch_tone": {}
}

当前 API Schema 中,built_in_tools 还额外暴露了 agent_prompt_changememory_entry_creatememory_entry_deletememory_entry_searchmemory_entry_update,可用于动态调整 Agent 指令并管理长期记忆条目。

end_call:结束当前会话

"built_in_tools": {
    "end_call": {}
}

启用后,Agent 可以先说"Goodbye!"再程序化地结束通话,保证对话有礼貌的收尾。

transfer_to_number:转接电话号码

转接电话需要配套的电信(telephony)集成,通过 transfers 数组声明目标号码与触发条件:

"built_in_tools": {
    "transfer_to_number": {
        "transfers": [{
            "transfer_destination": {"type": "phone", "phone_number": "+1234567890"},
            "condition": "User asks to speak with a human agent"
        }]
    }
}

transfer_to_agent:转接另一个 ElevenLabs Agent

用于多 Agent 协作场景(如销售咨询转销售专员),condition 字段描述 LLM 判定转接的语义条件:

"built_in_tools": {
    "transfer_to_agent": {
        "transfers": [{
            "agent_id": "other-agent-id",
            "condition": "User asks about sales"
        }]
    }
}

最佳实践

1. 工具描述要具体可执行

LLM 依赖 description 决定何时调用工具,写得含糊会导致漏调或误调:

# 好 - 具体且可执行
"description": "Look up order status. Use when customer asks about their order, delivery, or shipping."

# 差 - 含糊
"description": "Order tool"

2. 参数描述帮助 LLM 提取正确值

在参数描述中给出格式示例(如订单号格式、用途说明),可提升抽取准确率:

"parameters": {
    "type": "object",
    "properties": {
        "order_id": {
            "type": "string",
            "description": "Order ID in format ORD-XXXXX (e.g., ORD-12345)"
        },
        "email": {
            "type": "string",
            "description": "Customer email address for verification"
        }
    }
}

3. 错误处理:tool_error_handling_mode

通过该字段控制工具错误如何传递给 Agent:

模式 行为
auto 由 ElevenLabs 自动决定错误处理方式
summarized 错误先被摘要,再发送给 Agent
passthrough 完整错误细节直接传给 Agent
hide 错误对 Agent 隐藏

同时,服务端应返回有帮助的错误信息而非空响应,让 Agent 能向用户解释问题:

// 服务端 Webhook 示例
app.post("/webhook/lookup_order", async (req, res) => {
  const { order_id } = req.body.parameters;

  const order = await db.orders.find(order_id);

  if (!order) {
    return res.json({
      result: {
        error: true,
        message: `Order ${order_id} not found. Please verify the order ID.`,
      },
    });
  }

  res.json({ result: order });
});

4. 超时设置要匹配真实耗时

response_timeout_secs 为 Webhook 设置合理超时(5–120 秒,默认 20 秒):

{
    "type": "webhook",
    "name": "slow_operation",
    "description": "Run a slow operation",
    "response_timeout_secs": 30,
    "api_schema": {
        "url": "https://api.example.com/slow-operation",
        "method": "POST"
    }
}

慢操作调大超时、并配合 tool_call_sound 播放等待音效、force_pre_tool_speech 让 Agent 先口头告知用户"正在查询",可以显著改善体验。

完整示例:电商客服 Agent

下面把三类工具组合在一起,创建一个电商支持助手(服务端查订单 + 浏览器展示商品 + 内置挂断与转人工):

agent = client.conversational_ai.agents.create(
    name="E-commerce Assistant",
    conversation_config={
        "agent": {
            "first_message": "Hi! How can I help you today?",
            "language": "en",
            "prompt": {
                "prompt": """You are an e-commerce support assistant.

Available actions:
- lookup_order: Check order status
- show_product: Display products to customer
- end_call: End conversation politely
- transfer_to_number: Transfer to human support

Always verify order ID before lookup. Offer transfer for complex issues.""",
                "llm": "gemini-2.0-flash",
                "tools": [
                    # Webhook:服务端订单查询
                    {
                        "type": "webhook",
                        "name": "lookup_order",
                        "description": "Look up order status by order ID or email",
                        "api_schema": {
                            "url": "https://api.mystore.com/orders/lookup",
                            "method": "POST",
                            "request_headers": {"Authorization": "Bearer {{API_KEY}}"},
                            "request_body_schema": {
                                "type": "object",
                                "properties": {
                                    "order_id": {"type": "string"},
                                    "email": {"type": "string"}
                                }
                            }
                        }
                    },
                    # Client:浏览器端商品展示
                    {
                        "type": "client",
                        "name": "show_product",
                        "description": "Display product details to the customer",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "product_id": {"type": "string"}
                            },
                            "required": ["product_id"]
                        }
                    }
                ],
                "built_in_tools": {
                    "end_call": {},
                    "transfer_to_number": {
                        "transfers": [{
                            "transfer_destination": {"type": "phone", "phone_number": "+1234567890"},
                            "condition": "User asks for human support"
                        }]
                    }
                }
            }
        },
        "tts": {"voice_id": "JBFqnCBsd6RMkjVDRZzb", "model_id": "eleven_flash_v2_5"}
    }
)

几个值得注意的细节:

  • 系统提示词中显式列出可用动作并要求"查订单前先核对订单号",这是对工具调用的软性护栏;
  • Webhook 工具用了 {{API_KEY}} 占位符,实际密钥由工作区环境变量解析,避免把真实凭证硬编码进 Agent 配置;
  • tts.model_id 指定了 eleven_flash_v2_5 低延迟语音模型,适合实时对话场景。

在 OpenMontage 技能体系中的位置与延伸阅读

本文所述内容来自 OpenMontage 仓库中随 Agent 技能分发的参考文档 .agents/skills/agents/references/client-tools.md。该技能的主入口 .agents/skills/agents/SKILL.md 给出了创建 Agent 的完整快速上手(CLI elevenlabs agents init/add/push 工作流、Python/JavaScript SDK、cURL 三种方式、LLM 提供商与模型目录、常见语音 ID),并在 "Tools" 一节以压缩示例引向本文档作为完整工具参考。围绕同一主题,仓库中还有以下配套文档可以继续深入:

  • 安装指南:CLI 与 SDK 的安装和鉴权设置;
  • Agent 配置参考conversation_config 全字段说明(ttsasrturnvad 等)与 Agent CRUD 示例;
  • Widget 嵌入参考<elevenlabs-convai> 网页嵌入组件的定制属性;
  • 外呼参考:基于 Twilio 的主动外呼、动态变量与配置覆盖。

需要说明的适用前提:本文所有配置项、字段默认值与行为描述均以仓库内这份参考文档记载的 ElevenLabs Conversational AI API 为准;实际接入时请以你账号对应的 API 版本与官方文档核对字段可用性,并准备好 ELEVENLABS_API_KEY 环境变量(技能元数据中声明了该要求)。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384