L1D-06 工具调用与外部集成:让 Agent 安全使用 API

保姆级教程 · 面向想把现有工具接进工作流的创作者和开发者

项目 信息
课程系列 AI 创作入门 · L1-D 智能体/自动化
课程编号 L1D-06
难度等级 ★★★★☆
适用人群 已会搭工作流,准备接入搜索、图片、TTS、表格或自有 API 的人
预计学时 90-120 分钟
前置课程 L1D-03、L1D-05;参考 L1B-07 语音工程化、L1C-07 联动工作流
更新日期 2026 年 8 月
内容声明 工具调用会产生真实数据读写和费用。密钥、权限、输入校验和人工审核必须先于自动执行。

学习目标

学完本教程后,你将能够:

  1. 理解 Function Calling 的工具描述、参数传递和结果返回的完整流程。
  2. 搜索、图片、TTS 和数据库工具设计最小接口,知道每类工具的风险等级。
  3. 把现有 HTTP API 包装为 Agent 可调用的工具,包含鉴权、校验、超时和日志。
  4. 识别 MCP 这类标准化工具接入协议的作用和局限。
  5. 为工具设置鉴权、限流、日志和人工确认边界,确保安全可控。
  6. 独立完成把 vbox 对外 TTS API 封装成 Agent 工具的设计,包含请求/响应流程和验收。

前置准备

你需要什么

你不需要什么


一、模型为什么能"调用工具"

1.1 核心流程

模型不会凭空执行函数。完整的工具调用流程是:

用户问题:"帮我把这段文案配成语音"
  │
  ▼
模型判断:需要调用 TTS 工具
  → 输出结构化调用请求:
    { "tool": "synthesize_voice",
      "parameters": { "text": "...", "voice_id": "narrator" } }
  │
  ▼
你的程序校验:
  → 参数合法?(text 不为空,voice_id 在白名单内)
  → 权限足够?(当前用户有 TTS 调用权限)
  → 预算足够?(本次调用费用在预算内)
  │
  ▼
程序执行:真正调用 TTS API
  → 返回结构化结果:
    { "status": "success",
      "task_id": "tts-001",
      "audio_path": "/audio/tts-001.wav",
      "duration": 15.3 }
  │
  ▼
模型收到结果,生成下一步回答:
  "已生成语音,时长 15.3 秒,文件保存在 /audio/tts-001.wav。
   需要我播放或下载吗?"

1.2 关键认知:程序永远是守门人

程序永远是工具的守门人。 不能因为模型请求格式正确,就跳过权限和业务校验。

模型的角色是"判断需要什么工具、填什么参数"。程序的角色是"校验请求、执行调用、返回结果"。这两个角色不能混为一谈:

角色 职责 不能做什么
模型 判断需要调什么工具、填什么参数 不能直接执行、不能接触密钥
程序 校验、执行、返回结果 不能跳过校验直接执行

1.3 工具描述的作用

模型靠"工具描述"判断该不该用某个工具。描述写得好,模型选对工具;描述写得差,模型可能乱选或漏选。

{
  "name": "search_topics",
  "description": "在已授权的资料源中搜索与账号定位相关的主题",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {"type": "string", "description": "搜索关键词"},
      "limit": {"type": "integer", "minimum": 1, "maximum": 20, "description": "返回数量上限"}
    },
    "required": ["query"]
  }
}

好描述的三要素:

  1. 名字准确:search_topicssearch 更清楚(搜什么?搜选题)。
  2. 说明清楚:描述里写明"在已授权的资料源中搜索",限制范围。
  3. 参数有约束:limit 有最小值和最大值,防止模型填一个离谱的数字。

二、工具接口怎么设计

2.1 好工具的四个标准

一个好工具做到四点:名字准确、参数少而清楚、结果结构稳定、失败信息可处理。

2.2 窄接口 vs 宽接口

❌ 宽接口(危险):
  execute_any_api(url, method, headers, body)
  → 模型可以访问任意 URL,包括内部系统

✅ 窄接口(安全):
  synthesize_voice(text, voice_id, format)
  → 只能做语音合成,不能做其他

不要提供"执行任意 SQL""访问任意 URL""删除任意文件"这种过宽工具。 工具越宽,模型误判造成的后果越大。

2.3 参数设计原则

  1. 先提供完成任务必需的最小字段:复杂选项由固定配置控制,不暴露给模型。
  2. 每个参数有类型和约束:字符串有长度限制,整数有范围限制,枚举有白名单。
  3. 必填参数最少:只把真正必须的设为 required,可选的给合理默认值。
  4. 参数名自解释:voice_idid 好,output_formatfmt 好。

三、四类常见工具

3.1 搜索工具

作用:让 Agent 能搜索信息。

设计要点:

工具名:search_topics
输入:query(关键词,1-50字), limit(1-20)
输出:
  results: [
    { title, summary, url, date, fetch_status }
  ]
拒绝:空 query、超长 query、非白名单域名

3.2 图片与 TTS 工具

图片生成工具:

TTS 工具:

工具名:synthesize_voice
输入:text(1-2000字), voice_id(白名单), format(wav/mp3)
输出:task_id, status, audio_path, duration, voice_version
拒绝:空文本、未授权音色、超长文本、未知格式

3.3 表格与数据库工具

设计要点:

工具名:read_content_library
输入:status(枚举:draft/approved/published), limit(1-50)
输出:rows: [ { id, title, status, updated_at } ]
拒绝:无权限的表、非只读操作的默认拒绝

工具名:write_content_record(需要人工确认)
输入:id, title, status
输出:task_id, write_status, affected_rows
拒绝:无写入权限、字段不合法
人工确认:是(写入前必须人工确认)

3.4 通知和发布工具

设计要点:

工具名:create_draft(可自动)
输入:platform, title, content, images
输出:draft_id, preview_url
拒绝:字段不完整

工具名:publish_draft(必须人工确认)
输入:draft_id
输出:published_url, published_at
拒绝:未审核的 draft_id
人工确认:是(发布前必须人工确认)

四、把 vbox 对外 API 封装成 Agent 工具

本节是本课的重点实战内容:把本项目 vbox 的对外 TTS API 封装成一个 Agent 可调用的"配音工具节点"。

4.1 vbox 对外 API 的基本认知

本项目 vbox 提供两套鉴权体系:

Agent 工具应该用对外 API,不要用 JWT 内部接口。 API Key 可以独立管理、限额和撤销,比 JWT 更适合工具调用场景。

重要:接入前必须先读当前 server/app/controller/open_api.py 和接口文档,确认请求字段、状态码、超时和错误结构。不要把 JWT 当成对外 API Key 使用。对外 API 的响应格式(数字型 status)与内部接口(字符串型 status)不同,不要混用。

4.2 封装为窄接口

推荐封装为窄接口:

synthesize_voice(text, voice_id, format)

而不是把整个 HTTP 请求透传给模型。封装层负责:

  1. 从环境变量读取 Key:不把凭证放进提示词或代码仓库。
  2. 校验文本长度、音色 ID 和格式白名单:在调用外部服务前拦截非法参数。
  3. 设置超时、有限重试和调用预算:网络问题重试,参数错误不重试。
  4. 记录任务 ID、文本摘要、音色版本和结果路径:方便追踪和复盘。
  5. 失败时返回可读错误:不泄露密钥和完整内部堆栈。

4.3 最小请求/响应流程示意

┌──────────────────────────────────────────────────────┐
│         vbox TTS 工具调用流程                          │
├──────────────────────────────────────────────────────┤
│                                                      │
│  1. Agent 决定调用 synthesize_voice                   │
│     参数: text="欢迎收听本期节目",                     │
│           voice_id="narrator_warm",                   │
│           format="wav"                                │
│                                                      │
│  2. 封装层校验                                        │
│     - text 长度: 10 字,在 1-2000 范围内 ✓            │
│     - voice_id: 在白名单内 ✓                          │
│     - format: "wav" 在白名单内 ✓                     │
│     - 预算检查: 本周调用次数未超限 ✓                  │
│                                                      │
│  3. 封装层发起 HTTP 请求                              │
│     POST /api/open/v1/tts                             │
│     Headers:                                          │
│       Authorization: Bearer <API_KEY>                 │
│       (或 X-API-Key: <API_KEY>)                       │
│     Body:                                             │
│       { "text": "欢迎收听本期节目",                   │
│         "voice_id": "narrator_warm",                  │
│         "format": "wav" }                             │
│                                                      │
│  4. vbox 服务处理                                     │
│     - 鉴权(API Key 校验)                             │
│     - 调用 TTS 引擎合成                               │
│     - 记录 API 用量(ApiUsage)                        │
│     - 返回结果                                        │
│                                                      │
│  5. 封装层收到响应                                     │
│     成功:                                             │
│       { "status": 1,                                  │
│         "task_id": "tts-20260820-001",                │
│         "audio_url": "/cdn/audio/tts-001.wav",        │
│         "duration": 3.2 }                             │
│     失败(示例):                                      │
│       { "status": 0,                                  │
│         "error": "voice_not_found",                   │
│         "message": "音色 ID 不存在" }                  │
│                                                      │
│  6. 封装层返回给 Agent                                 │
│     成功:                                             │
│       { "status": "success",                          │
│         "task_id": "tts-20260820-001",                │
│         "audio_path": "/cdn/audio/tts-001.wav",       │
│         "duration": 3.2,                              │
│         "voice_version": "narrator_warm_v2" }         │
│     失败:                                             │
│       { "status": "error",                            │
│         "error_code": "voice_not_found",              │
│         "message": "音色 ID 不存在,请检查白名单" }     │
│                                                      │
│  7. Agent 生成回答                                    │
│     "已生成语音,时长 3.2 秒。                        │
│      音色版本 narrator_warm_v2。                      │
│      文件保存在 /cdn/audio/tts-001.wav。"             │
│                                                      │
└──────────────────────────────────────────────────────┘

4.4 工具契约文档

把这份契约文档保存下来,作为工具接入的规范:

┌──────────────────────────────────────────────────────┐
│         vbox TTS 工具契约 v1.0                        │
├──────────────────────────────────────────────────────┤
│ 工具名:synthesize_voice                               │
│ 用途:将文本合成为语音音频                              │
│                                                      │
│ 输入参数:                                             │
│   text    (string, 必填) 1-2000 字                   │
│   voice_id (string, 必填) 音色白名单内的 ID            │
│   format  (string, 可选) wav 或 mp3,默认 wav         │
│                                                      │
│ 输出:                                                 │
│   task_id       (string) 任务唯一标识                 │
│   status        (string) success / error             │
│   audio_path    (string) 音频文件路径                 │
│   duration      (float)  音频时长(秒)                │
│   voice_version (string) 音色版本号                   │
│   error_code    (string) 失败时的错误码               │
│   message       (string) 失败时的可读信息             │
│                                                      │
│ 拒绝条件:                                             │
│   - 空文本                                             │
│   - 未授权的 voice_id                                 │
│   - 超过 2000 字的文本                                 │
│   - 未知格式                                           │
│   - 超出预算或调用次数上限                              │
│                                                      │
│ 人工确认:                                             │
│   - 发布前试听                                         │
│   - 声音授权确认                                       │
│   - 最终剪辑确认                                       │
│                                                      │
│ 安全措施:                                             │
│   - API Key 从环境变量读取                             │
│   - 超时 30 秒,最多重试 2 次(间隔递增)              │
│   - 调用日志不记录完整文本和 Key                       │
│   - 每次 API 用量被 vbox 记录到 ApiUsage 表            │
└──────────────────────────────────────────────────────┘

4.5 单角色与多角色配音

vbox 的 TTS API 支持单角色和多角色配音。在封装成 Agent 工具时:

工具接口可以设计为两个:

工具 1:synthesize_single_voice(text, voice_id, format)
  → 单角色配音

工具 2:synthesize_multi_voice(script, voice_mapping, format)
  → 多角色配音
  script 格式:【角色名】对白内容
  voice_mapping: { "旁白": "voice_1", "男主": "voice_2" }

两种模式的调用细节以当前 vbox 对外 API 文档为准。封装层负责把角色标签解析为正确的请求格式。


五、MCP 协议入门

5.1 MCP 是什么

MCP(Model Context Protocol)可以理解为一套让 AI 客户端发现和调用外部工具的标准化约定。它解决的是"工具怎样描述、怎样暴露、怎样被客户端发现"的协作问题。

打个比方:以前每个工具都要写自己的接入文档,每个 AI 客户端都要适配不同的接入方式。MCP 像一个"标准插座"——只要工具按 MCP 标准暴露,任何支持 MCP 的客户端都能直接用。

5.2 MCP 解决什么和不解决什么

MCP 解决 MCP 不解决
工具如何标准化描述 权限管理(仍需自己做)
工具如何被客户端发现 数据合规(仍需自己确认)
工具调用的基本协议 结果质量(仍需自己验证)
多个工具的统一接入 成本控制(仍需自己设限)

5.3 接入 MCP 服务的检查清单

接入任何 MCP 服务前,逐项确认:

关键认知:MCP 解决接入标准,不替你解决安全和合规。一个 MCP 服务接入再方便,如果权限不明、数据去向不清,也不要用。


六、实战:安全接入语音生成工具

6.1 测试顺序

按以下顺序测试,每一步通过后再进下一步:

第 1 步:正常调用

第 2 步:参数校验

第 3 步:超时与重试

第 4 步:幂等性

第 5 步:日志检查

6.2 验收表

项目 合格标准 通过?
参数校验 非法值在调用外部服务前被拦截
鉴权 凭证来自环境变量,不在提示词或代码中
超时重试 有上限(30 秒超时,最多 2 次),避免重复副作用
输出 字段稳定,包含 status 和 task_id
日志 能追踪,不泄露密钥和敏感文本
人工节点 发布前可暂停,试听和授权确认
成本 能统计单次和周期调用量
幂等 重复调用不产生重复结果
错误处理 失败时返回可读错误,不暴露内部堆栈

七、工具接入完整验收表

不管你接入什么工具,用这张表做最终验收:

项目 合格标准
参数校验 非法值在调用外部服务前被拦截
鉴权 凭证来自安全配置,最小权限
超时重试 有上限,避免重复副作用
输出 字段稳定,包含状态和任务 ID
日志 能追踪,不泄露秘密
人工节点 发布和不可逆动作前可暂停
成本 能统计单次和周期调用量
幂等 重试不产生重复结果
错误处理 失败时可读,不暴露内部信息
白名单 域名、参数值、工具范围有白名单
回滚 有问题可以禁用工具而不影响其他流程

FAQ:常见问题

Q1:工具调用失败,是模型的问题吗?

不一定。可能是参数错误、鉴权失败、网络超时、限流或服务端错误。日志应区分这些原因,不能笼统重试所有错误。

排查顺序:

  1. 看日志中的错误码:是参数问题还是网络问题?
  2. 参数问题 → 修工具描述或校验逻辑,不重试。
  3. 网络问题 → 有限重试(最多 2-3 次,间隔递增)。
  4. 鉴权失败 → 检查 Key 是否过期或被撤销,不重试。
  5. 限流 → 等待后重试,或降低调用频率。

Q2:可以让模型自己拼接任意 URL 吗?

不建议。限制域名、路径和请求方法,并对返回内容做大小和格式限制,防止访问不该访问的资源。模型可能因为用户引导而访问恶意 URL,你的程序必须做好防护。

Q3:MCP 接上就能自动获得所有能力吗?

不能。MCP 只是接入约定,具体能力由服务暴露;权限、审核、限流和数据条款仍要自己确认。MCP 让"接入"变简单,但"安全使用"仍然是你的责任。

Q4:一个 Agent 应该接多少个工具?

第一个版本接 2-3 个就够。工具越多,模型越容易选错工具或乱调。等流程稳定后,再根据明确需求逐步增加。每个新工具都要走完整的测试顺序。

Q5:工具调用的费用怎么控制?

三层控制:

  1. 单次上限:每次调用的最大费用(如文本长度限制)。
  2. 周期上限:每天/每周的调用次数或总费用。
  3. 告警:接近上限时通知,超限自动暂停。

进阶避坑指南

坑 1:接口参数过多

现象:工具描述里有 20 个参数,模型经常填错或漏填。

原因:参数过多会增加模型误填概率。模型需要在多个参数之间做判断,参数越多,出错率越高。

处理:先提供完成任务必需的最小字段(3-5 个),复杂选项由固定配置控制。比如 TTS 工具只需要 textvoice_idformat 三个参数,语速、音调等高级参数用默认值,不由模型决定。

坑 2:工具结果返回大段原始内容

现象:搜索工具返回了 5000 字的网页全文,模型拿到后"迷失"在大量信息中,回答质量反而下降。

原因:模型处理超长上下文时,注意力会分散,关键信息容易被淹没。

处理:限制结果大小,返回摘要、状态、来源和可追踪 ID;原始大文件放在受控存储中,需要时再按 ID 取。比如搜索工具返回 title + summary(200字) + url,不返回全文。

坑 3:所有工具共享一个高权限 Key

现象:用一个万能 API Key 接所有工具,某个工具的配置泄露后,所有工具的权限都暴露了。

原因:没有按工具、环境和成员拆分凭证。

处理:


最重要的三句话

  1. 模型提出调用请求,程序负责校验和执行——程序永远是守门人。
  2. 窄接口、最小权限、稳定结果,比"万能工具"更可靠。
  3. MCP 解决接入标准,不替你解决安全和合规;接入再方便,权限不明也不用。

下一站预告

工具接入后,下一篇《L1D-07 自动化生产管线:从内容母稿到可监控交付》会把文字、图片、视频、配音和人工审核串成一条完整管线。你会学到如何把 vbox TTS 和远程图片 API 作为可替换的远程服务节点,以及如何在成本、质量和速度之间做权衡。


教程版本:v1.0 最后更新:2026-08 内容时效:API、MCP 服务和平台鉴权方式会变化,部署前请以当前官方文档和组织安全要求为准。vbox 对外 API 的具体字段和错误码以当前 server/app/controller/open_api.py 和接口文档为准。