You need to enable JavaScript to run this app.
文档中心
火山方舟

火山方舟

复制全文
下载 pdf
Managed Agent
[基础] Custom Tool 使用教程
复制全文
下载 pdf
[基础] Custom Tool 使用教程
Managed Agent(MA)支持内置工具、Custom Tool 和 MCP 工具。工具类型和基础配置请参见 Tools。​
内置工具适合在托管 sandbox 中执行文件读写、命令执行、网页检索等操作;Custom Tool 适合将少量业务函数交给 Agent 调用;MCP 工具适合接入已经按 MCP 协议封装的外部能力。​
在企业应用中,开发者通常还需要让 Agent 调用业务系统中的专用操作,例如查询订单、创建工单、调用库存系统、访问内网风控接口,或触发企业已有的图像、视频、数据处理服务。如果这些能力都通过 MCP server 接入,需要额外部署服务、维护 HTTP endpoint 和鉴权链路;如果让 Agent 直接通过命令行调用内部接口,则缺少稳定的参数 schema、权限边界和结果格式约束。​
Custom Tool 用于解决这类“将少量业务函数交给 Agent 调用”的场景。开发者只需要在 Agent 中声明工具名称、用途和输入 schema,运行时由业务侧接收工具调用事件、执行真实业务逻辑,并将工具结果回传给 Session。Agent 可以基于工具结果继续推理和回复用户。​
本文介绍 Custom Tool 的通用接入流程,并通过 4 个多媒体示例说明如何声明工具、触发调用和回传结果:​
  • Custom Tool 生图​
  • 多图 Base64 回传​
  • 使用 File ID 作为参考素材生视频​
  • 查询视频任务并理解视频内容​
前提条件​
您需要准备:​
  • 已开通 Managed Agent,并已获取可用的 API Key。​
  • 已准备 Agent 使用的模型。​
  • 已明确需要暴露给 Agent 的业务操作,包括操作名称、用途、输入参数、返回结果和错误处理方式。​
  • 已准备业务侧执行逻辑。该逻辑可以运行在您的服务端、内部系统或任务队列中,用于接收工具调用事件、执行实际操作,并向 Session 回传工具结果。​
  • 如果工具需要访问内部系统,请提前配置鉴权、权限控制、审计日志和超时策略。​
使用流程​
使用 Custom Tool 的一般流程如下:​
  1. 声明工具:创建 Agent 时,在 tools 中添加 type: custom 的工具,填写 name、description 和 input_schema。​
  1. 创建 Session:基于该 Agent 创建 Session。​
  1. 发送用户消息:向 Session 发送 user.message。​
  1. 接收工具调用事件:当 Agent 判断需要调用自定义工具时,Session 事件流中会出现 agent.custom_tool_use 事件。该事件包含工具名称、工具输入参数和事件 ID。​
  1. 等待 Session 暂停:Session 随后进入 idle,并发出 session.status_idle 事件。该事件的 stop_reason.type 为 requires_action,stop_reason.event_ids 中包含需要业务侧处理的事件 ID。​
  1. 执行业务逻辑:业务侧根据 agent.custom_tool_use 的 name 和 input 执行对应操作。​
  1. 回传工具结果:业务侧发送 user.custom_tool_result 事件,使用 custom_tool_use_id 关联第 4 步中的工具调用事件 ID。​
  1. 继续运行:所有阻塞事件处理完成后,Session 从 idle 切回 running,Agent 基于工具结果继续生成回复。​
如果 stop_reason.event_ids 中包含多个事件 ID,需要为每个阻塞事件回传结果。建议将同一轮阻塞事件对应的多个 user.custom_tool_result 放在同一个 events 数组中发送。​
声明自定义工具​
自定义工具通过 Agent 的 tools 字段声明。每个工具至少包含以下字段:​
​
字段​
类型​
说明​
type​
String​
固定为 custom。​
name​
String​
工具名称。建议使用英文字母、数字、下划线或连字符,便于模型稳定引用。​
description​
String​
工具用途、适用条件和限制。模型会根据该描述判断何时调用工具。​
input_schema​
Object​
定义模型生成工具入参时参考的 JSON Schema。​
​
声明工具时,建议遵循以下原则:​
  • description 明确说明工具应该在什么场景下使用,以及不应该在什么场景下使用。​
  • input_schema 只暴露业务必要参数,不暴露 API Key、内部服务地址等敏感配置。​
  • 对枚举值、数字范围、必填字段和 additionalProperties 做明确约束。​
  • 工具返回值保持结构化,便于 Agent 判断是否成功、是否需要重试,以及如何向用户解释结果。​
以下示例响应仅展示与流程相关的关键字段,实际响应字段以 API 返回为准。​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/agents" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"name": "CustomToolDemo",​
"model": {​
"id": "doubao-seed-2-1-pro-260628"​
},​
"system": "你是一个可以调用业务工具的助手。需要外部业务能力时,调用已声明的 custom tool。不要编造工具结果。",​
"tools": [​
{​
"type": "custom",​
"name": "query_order",​
"description": "根据订单 ID 查询订单状态。仅当用户要求查询订单信息时使用。",​
"input_schema": {​
"type": "object",​
"properties": {​
"order_id": {​
"type": "string",​
"description": "订单 ID。"​
}​
},​
"required": ["order_id"],​
"additionalProperties": false​
}​
}​
]​
}'​
​
响应示例:​
​
{​
"id": "agent-20260729153010-****",​
"object": "agent",​
"created_at": "2026-07-29T15:30:10Z",​
"name": "CustomToolDemo",​
"model": {​
"id": "doubao-seed-2-1-pro-260628"​
}​
}​
​
创建 Session​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"agent": "agent-20260729153010-****",​
"environment_id": "env-20260729152900-****",​
"title": "Custom Tool 演示"​
}'​
​
响应示例:​
​
{​
"id": "sesn-20260729153122-****",​
"object": "session",​
"agent": "agent-20260729153010-****",​
"environment_id": "env-20260729152900-****",​
"status": "idle"​
}​
​
场景一:Custom Tool 生图​
本场景演示如何通过 Custom Tool 接入企业已有的生图服务。完整链路包括:声明 generate_image 工具、创建 Agent 和 Session、发送用户消息、接收工具调用事件、执行生图逻辑并回传图片结果。​
创建 Agent 时,在 tools 中声明生图工具:​
​
{​
"type": "custom",​
"name": "generate_image",​
"description": "调用业务侧生图服务生成图片。当用户明确要求创建、绘制或生成图片时使用;不要用于回答纯文本问题。prompt 需要描述主体、场景、风格和关键约束;size 决定输出尺寸;n 决定返回图片数量。",​
"input_schema": {​
"type": "object",​
"properties": {​
"prompt": {​
"type": "string",​
"description": "完整的生图提示词。"​
},​
"size": {​
"type": "string",​
"description": "输出尺寸,例如 2048x2048。"​
},​
"watermark": {​
"type": "boolean",​
"description": "是否添加水印。"​
},​
"n": {​
"type": "integer",​
"minimum": 1,​
"maximum": 4,​
"description": "返回图片数量。"​
}​
},​
"required": ["prompt"],​
"additionalProperties": false​
}​
}​
​
创建包含该工具的 Agent 并创建 Session 后,发送生图请求:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.message",​
"content": [​
{​
"type": "text",​
"text": "生成一张 2048x2048 的产品海报:一只透明玻璃咖啡杯放在木质桌面上,清晨自然光,背景有浅景深绿植,干净商业摄影风格。"​
}​
]​
}​
]​
}'​
​
模型产生 agent.custom_tool_use:​
​
{​
"id": "sevt-20260729153201-****",​
"type": "agent.custom_tool_use",​
"name": "generate_image",​
"input": {​
"prompt": "透明玻璃咖啡杯放在木质桌面上,清晨自然光,背景有浅景深绿植,干净商业摄影风格,产品海报构图",​
"size": "2048x2048",​
"watermark": true,​
"n": 1​
}​
}​
​
随后 Session 进入 idle,stop_reason.type 为 requires_action:​
​
{​
"id": "sevt-20260729153202-****",​
"type": "session.status_idle",​
"stop_reason": {​
"type": "requires_action",​
"event_ids": [​
"sevt-20260729153201-****"​
]​
}​
}​
​
业务侧执行器调用生图服务,并回传工具结果:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.custom_tool_result",​
"custom_tool_use_id": "sevt-20260729153201-****",​
"is_error": false,​
"content": [​
{​
"type": "text",​
"text": "{\"ok\":true,\"image_count\":1,\"delivery\":\"base64\",\"request_id\":\"req-20260729153215-****\",\"usage\":{\"generated_images\":1}}"​
},​
{​
"type": "image",​
"source": {​
"type": "base64",​
"media_type": "image/png",​
"data": "iVBORw0KGgoAAAANSUhEUgAA...****"​
}​
}​
]​
}​
]​
}'​
​
模型拿到结果后即可回复用户,例如:​
​
{​
"type": "agent.message",​
"content": [​
{​
"type": "text",​
"text": "图片已生成,画面为清晨自然光下的玻璃咖啡杯产品海报。"​
}​
]​
}​
​
场景二:多图 Base64 回传​
本场景演示一个工具调用返回多个多模态内容块。可以复用场景一中的 generate_image 工具声明,但需要在 input_schema 中为 n 设置合理范围,例如 minimum: 1、maximum: 4。​
创建包含该工具的 Agent 和 Session 后,用户可以要求一次生成多张图片:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.message",​
"content": [​
{​
"type": "text",​
"text": "为同一个智能音箱生成 3 张电商主图,分别展示正面、45 度角和使用场景。"​
}​
]​
}​
]​
}'​
​
Agent 生成的工具调用事件示例如下:​
​
{​
"id": "sevt-20260729154001-****",​
"type": "agent.custom_tool_use",​
"name": "generate_image",​
"input": {​
"prompt": "同一个智能音箱的 3 张电商主图,白色背景,柔和阴影,分别展示正面、45 度角和使用场景",​
"size": "2048x2048",​
"watermark": true,​
"n": 3​
}​
}​
​
回传结果时,文本块只放机器可读摘要,不重复塞入 Base64;每张图独立使用一个 image/base64 内容块:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.custom_tool_result",​
"custom_tool_use_id": "sevt-20260729154001-****",​
"is_error": false,​
"content": [​
{​
"type": "text",​
"text": "{\"ok\":true,\"image_count\":3,\"delivery\":\"base64\",\"request_ids\":[\"req-20260729154011-****\",\"req-20260729154018-****\",\"req-20260729154025-****\"],\"usage\":{\"generated_images\":3}}"​
},​
{​
"type": "image",​
"source": {​
"type": "base64",​
"media_type": "image/png",​
"data": "iVBORw0KGgoAAAANSUhEUgAA...image_1...****"​
}​
},​
{​
"type": "image",​
"source": {​
"type": "base64",​
"media_type": "image/png",​
"data": "iVBORw0KGgoAAAANSUhEUgAA...image_2...****"​
}​
},​
{​
"type": "image",​
"source": {​
"type": "base64",​
"media_type": "image/png",​
"data": "iVBORw0KGgoAAAANSUhEUgAA...image_3...****"​
}​
}​
]​
}​
]​
}'​
​
这种结构有两个好处:​
  • 文本 JSON 便于 Agent 判断工具是否成功、生成了几张图、是否需要重试。​
  • 原生 image 内容块便于模型直接消费图像模态,不需要从文本中解析大段 Base64。​
场景三:File ID 参考生视频​
本场景演示如何让 Custom Tool 接收 File ID,并由业务侧把文件解析为视频生成服务可读取的参考素材。适用于参考图、参考视频、参考音频等素材已经通过 Files API 上传的场景。​
创建 Agent 时,声明 generate_video 工具:​
​
{​
"type": "custom",​
"name": "generate_video",​
"description": "提交异步生视频任务。当用户要求生成视频、基于参考素材生成视频或图生视频时使用。调用成功只表示任务已提交;需要通过 get_video_task 查询完成状态。",​
"input_schema": {​
"type": "object",​
"properties": {​
"prompt": {​
"type": "string",​
"description": "视频提示词,描述主体、动作、场景、镜头和风格。"​
},​
"model": {​
"type": "string",​
"description": "生视频模型 ID 或 Endpoint ID。"​
},​
"reference_image_sources": {​
"type": "array",​
"items": {​
"type": "object",​
"properties": {​
"type": {​
"type": "string",​
"enum": ["url", "file", "tos"]​
},​
"url": {​
"type": "string"​
},​
"file_id": {​
"type": "string"​
},​
"tos_uri": {​
"type": "string"​
}​
},​
"required": ["type"],​
"additionalProperties": false​
},​
"description": "参考图片来源列表。"​
},​
"duration": {​
"type": "integer",​
"description": "视频时长,单位秒。"​
},​
"ratio": {​
"type": "string",​
"description": "画面比例,例如 16:9、9:16、1:1。"​
},​
"wait_for_completion": {​
"type": "boolean",​
"description": "是否等待任务完成后再回传工具结果。"​
}​
},​
"additionalProperties": false​
}​
}​
​
创建包含该工具的 Agent 和 Session 后,用户可以在消息中引用 File ID:​
用户请求:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.message",​
"content": [​
{​
"type": "text",​
"text": "用 file-20260729160108-**** 这张参考图生成一个 5 秒 16:9 视频:杯子旁边的蒸汽缓慢升起,镜头轻微推进,清晨暖光。"​
}​
]​
}​
]​
}'​
​
模型调用 generate_video:​
​
{​
"id": "sevt-20260729160130-****",​
"type": "agent.custom_tool_use",​
"name": "generate_video",​
"input": {​
"model": "doubao-seedance-2-0-260128",​
"prompt": "参考图中的杯子保持主体一致,蒸汽缓慢升起,镜头轻微推进,清晨暖光,商业摄影质感",​
"reference_image_sources": [​
{​
"type": "file",​
"file_id": "file-20260729160108-****"​
}​
],​
"duration": 5,​
"ratio": "16:9",​
"wait_for_completion": false​
}​
}​
​
业务侧执行器可以把 File ID 解析为视频生成服务可访问的素材,再提交异步任务。首次回传通常只表示任务已受理:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.custom_tool_result",​
"custom_tool_use_id": "sevt-20260729160130-****",​
"is_error": false,​
"content": [​
{​
"type": "text",​
"text": "{\"ok\":true,\"task_id\":\"cgt-20260729160142-****\",\"model\":\"doubao-seedance-2-0-260128\",\"status\":\"queued\",\"video_url\":null}"​
}​
]​
}​
]​
}'​
​
用户稍后查询任务:​
​
{​
"id": "sevt-20260729160810-****",​
"type": "agent.custom_tool_use",​
"name": "get_video_task",​
"input": {​
"task_id": "cgt-20260729160142-****",​
"model": "doubao-seedance-2-0-260128"​
}​
}​
​
任务完成时的回传示例:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.custom_tool_result",​
"custom_tool_use_id": "sevt-20260729160810-****",​
"is_error": false,​
"content": [​
{​
"type": "text",​
"text": "{\"ok\":true,\"task_id\":\"cgt-20260729160142-****\",\"model\":\"doubao-seedance-2-0-260128\",\"status\":\"succeeded\",\"video_url\":\"https://example-cdn.volces.com/video/cgt-20260729160142-****.mp4\",\"usage\":{\"duration\":5}}"​
}​
]​
}​
]​
}'​
​
视频结果建议以文本 JSON 返回 video_url。当前不要把 MP4 二进制作为 document/base64 塞回 Tool Result;这会显著放大事件体积,也可能无法被模型消费层按视频模态解析。​
场景四:查询并理解视频​
本场景演示如何把异步任务查询和后续视频理解串联起来。查询任务和理解视频内容是两个动作:​
  1. get_video_task 负责确认任务状态,并拿到 video_url。​
  1. 内置多模态或视频理解工具负责读取 video_url 并总结画面内容。​
创建 Agent 时,声明任务查询工具:​
​
{​
"type": "custom",​
"name": "get_video_task",​
"description": "查询异步视频任务。当用户要求查看视频生成进度、确认任务是否完成或获取视频结果时使用。任务未完成时只能说明仍在生成;任务成功且包含 video_url 时,才能说明视频已完成。",​
"input_schema": {​
"type": "object",​
"properties": {​
"task_id": {​
"type": "string",​
"description": "视频任务 ID。"​
},​
"model": {​
"type": "string",​
"description": "创建任务时使用的模型 ID,可省略。"​
}​
},​
"required": ["task_id"],​
"additionalProperties": false​
}​
}​
​
创建包含该工具的 Agent 和 Session 后,用户请求查询并理解视频:​
​
curl -X POST "https://ark.cn-beijing.volces.com/api/v3/sessions/sesn-20260729153122-****/events" \​
-H "Authorization: Bearer $ARK_API_KEY" \​
-H "Content-Type: application/json" \​
-d '{​
"events": [​
{​
"type": "user.message",​
"content": [​
{​
"type": "text",​
"text": "查询任务 cgt-20260729160142-****。如果视频已经完成,请理解视频内容并总结镜头、主体动作和视觉风格。"​
}​
]​
}​
]​
}'​
​
模型先调用 get_video_task:​
​
{​
"id": "sevt-20260729162000-****",​
"type": "agent.custom_tool_use",​
"name": "get_video_task",​
"input": {​
"task_id": "cgt-20260729160142-****",​
"model": "doubao-seedance-2-0-260128"​
}​
}​
​
业务侧执行器回传视频 URL:​
​
{​
"events": [​
{​
"type": "user.custom_tool_result",​
"custom_tool_use_id": "sevt-20260729162000-****",​
"is_error": false,​
"content": [​
{​
"type": "text",​
"text": "{\"ok\":true,\"task_id\":\"cgt-20260729160142-****\",\"model\":\"doubao-seedance-2-0-260128\",\"status\":\"succeeded\",\"video_url\":\"https://example-cdn.volces.com/video/cgt-20260729160142-****.mp4\"}"​
}​
]​
}​
]​
}​
​
接下来,Agent 应使用环境中可用的内置视频理解能力读取该 video_url。如果您的环境把该能力暴露为内置工具,可以在 Agent 的 system prompt 中明确要求:​
​
当 get_video_task 返回 status=succeeded 且包含 video_url,并且用户要求理解视频内容时,继续调用环境中可用的内置多模态或视频理解工具读取 video_url;不要仅凭 prompt 或 task_id 猜测视频内容。​
​
最终回复示例:​
​
{​
"type": "agent.message",​
"content": [​
{​
"type": "text",​
"text": "任务已完成。视频主体是一只透明玻璃咖啡杯,蒸汽从杯口缓慢升起;镜头从中景轻微推进到近景,背景绿植保持浅景深虚化,整体是清晨暖光下的干净商业摄影风格。"​
}​
]​
}​
​
如果当前环境没有视频理解内置工具,Agent 应说明只能确认 video_url 已生成,不能声称已经理解视频画面。​
业务侧执行器参考逻辑​
业务侧执行器需要维护一个待处理工具调用表。收到 agent.custom_tool_use 时先记录事件;收到 session.status_idle 且 stop_reason.type 为 requires_action 时,按 event_ids 找到对应工具调用,执行并批量回传。​
​
pending = {}​
​
def process_event(event):​
event_type = event.get("type")​
​
if event_type == "agent.custom_tool_use":​
pending[event["id"]] = event​
return​
​
if event_type != "session.status_idle":​
return​
​
stop_reason = event.get("stop_reason") or {}​
if stop_reason.get("type") != "requires_action":​
return​
​
results = []​
for event_id in stop_reason.get("event_ids", []):​
tool_event = pending.pop(event_id)​
result = execute_custom_tool(tool_event)​
results.append({​
"type": "user.custom_tool_result",​
"custom_tool_use_id": event_id,​
"is_error": not result["ok"],​
"content": to_tool_result_content(result),​
})​
​
post_session_events({"events": results})​
​
常见问题​
input_schema 是否可以传字符串?​
不可以。input_schema 必须以 JSON 对象传入,且顶层 type 仅支持 object。​
Custom Tool 名称有什么限制?​
建议使用 1 到 64 位的英文字母、数字、下划线或连字符,例如 generate_image、get_video_task。同一个 Agent 最多配置 8 个 Custom Tool。​
为什么视频结果只返回 video_url?​
视频生成通常是异步任务,MP4 体积较大,直接作为 Tool Result 回传不适合。推荐返回文本 JSON,让 Agent、前端或后续内置视频理解工具通过 video_url 继续处理。​
多个 Custom Tool 同时触发时怎么回传?​
以 stop_reason.event_ids 为准。该数组里的所有工具调用都完成后,放在同一个 events 数组中批量发送:​
​
{​
"events": [​
{​
"type": "user.custom_tool_result",​
"custom_tool_use_id": "sevt-20260729163001-****",​
"is_error": false,​
"content": [​
{​
"type": "text",​
"text": "{\"ok\":true,\"value\":\"alpha\"}"​
}​
]​
},​
{​
"type": "user.custom_tool_result",​
"custom_tool_use_id": "sevt-20260729163002-****",​
"is_error": false,​
"content": [​
{​
"type": "text",​
"text": "{\"ok\":true,\"value\":\"beta\"}"​
}​
]​
}​
]​
}​
​
调试建议​
  • 业务侧执行器启动后先订阅或轮询 Session 事件,再发送用户消息,避免错过 requires_action。​
  • 工具执行失败时也要回传 user.custom_tool_result,并设置 is_error: true。​
  • 不要在日志或文档中打印真实 API Key、完整签名 URL、完整 Base64 或未脱敏资源 ID。​
  • 生图和生视频后端建议使用独立的最小权限 API Key,便于审计和轮换。​
​
最近更新时间:2026.10.05 11:50:12
这个页面对您有帮助吗?
有用
有用
无用
无用