AI 构建指南
Bird 的 API 接口天然适合代理:每个工具对应一个操作,输入输出均为 JSON,结果可由机器校验。但可靠的代理仍需要正确的外围模式。以下五个模式覆盖了破坏代理集成的常见故障:把接受当作投递、缺乏上下文地重试、以及解析文本而非结构化数据。无论你的代理驱动的是 MCP 服务器还是 bird CLI,每个模式的工作方式都相同。下面的示例使用邮件,因为邮件的发送工具链最完整,而这些模式可以原封不动地迁移到 SMS 和 WhatsApp:发送时相同的 202、相同的已接受到最终状态的事件序列、相同的错误响应。唯一的例外是模式 3,其魔法地址属于邮件沙箱。
模式 1:每次循环只执行一个操作
Bird 的工具刻意保持细粒度:发送消息、获取消息、列出域名或创建 webhook 端点。每个工具都返回结构化的 JSON,其字段可供下一步检查。构建循环时,让每一步的退出条件来自上一步的输出:
代码示例
loop:
result = run_tool(next_operation) # one operation per call
if result.ok: advance using result.data # for example, the em_… ID or verified domain
else: branch on the failure category # see Pattern 4使用 CLI 时,故障类别就是退出码,因此分支无需解析消息内容。完整表格参见 CLI:
代码示例
bird email get "$id" --format json > msg.json
case $? in
0) jq .status msg.json ;; # advance
3) echo "wrong ID: fix the value instead of retrying" ;;
4) bird auth login ;; # recover, then re-run
esac细粒度正是关键:能在步骤间检查状态的代理可以从任何单次故障中恢复;驱动一个大型复合操作的代理只能从头开始。
模式 2:发送返回 202;结果稍后到达
POST 一次发送,你会收到带有消息 ID 的 202 Accepted。已接受表示 Bird 已接收消息,投递正在进行中。 最终结果以 webhook 事件 的形式到达:收件方服务器接受时为 email.delivered,投递永久失败时为 email.bounced,email.complained,等等。
在 202 阶段就宣布成功的代理会静默错过所有退信。应将任务构造为先发送再等待:
代码示例
send → 202 + em_… ID # record the ID; delivery is still pending
await webhook event where data.email_id == em_… id:
email.delivered → done
email.bounced → report failure with bounce_type / bounce_description通过 email_id 进行关联。Webhook 载荷会在身份字段旁回传你的标签和元数据,因此无需额外查询即可找回你自己的上下文。投递至少一次且无序;通过 webhook-id 请求头去重,并按载荷中的 timestamp 排序。如果你的代理没有 webhook 接收端,可以用 GET(或 bird email get)轮询消息,直到其状态变为最终态。轮询更慢,但回读仍然是数据的最终来源。
模式 3:将沙箱用作测试工具
开发循环时,在 messagebird.dev 上使用邮件沙箱的魔法地址,而非真实邮箱。地址决定结果(delivered@ 始终成功投递,bounce@ 始终硬退信,complaint@ 始终触发投诉)。其余一切使用生产管线:相同的 202、事件序列和签名的 webhook 投递,没有任何标记将消息标识为测试。
代码示例
for address in [delivered@, bounce@, suppressed@] @messagebird.dev:
send to address+run42@… # +label correlates the test case
assert the expected terminal event arrives (delivered / bounced / rejected)沙箱提供确定性结果、零声誉风险、不写入屏蔽列表,以及可跨运行复用的地址。通过沙箱矩阵的代理,在接触真实收件箱之前,已完整演练了模式 2 的路径(发送、等待和分支)。
模式 4:基于标准错误响应进行恢复
每个 Bird API 错误都具有相同的结构,因此一条错误恢复路径适用于所有端点:
代码示例
{
"error": {
"type": "validation_error",
"code": "E04006",
"name": "DomainNotVerified",
"message": "The from address uses a domain that is not verified in this workspace.",
"doc_url": "https://bird.com/docs/api/errors/E04006",
"request_id": "req_01krdgeqcxet5s7t44vh8rt9mg"
}
}每个字段在循环中都有其用途。根据 type/code(稳定且机器可读)进行分支,将 message 展示给人类,当代理需要某个具体错误的详情页时获取 doc_url。该 URL 解析为代理可读取的 Markdown。记录 request_id,以便人类将其提供给 Bird 支持团队。然后将可重试错误与请求错误分开:
代码示例
4xx (except 429) → a request bug: fix the input, never retry as-is
429 → back off, then retry (Pattern 5)
5xx / timeout → retry with the same Idempotency-Key (Pattern 5)模式 5:使用 Idempotency-Key 和 Retry-After 安全重试
当发送超时而代理再次尝试时,重试可能导致重复操作。Bird 的幂等性支持使重试变得安全。为每个逻辑操作生成一个 Idempotency-Key,并在每次尝试时复用它:
代码示例
key = uuid() # once per logical send
attempt with Idempotency-Key: key
on 5xx / timeout: backoff, retry with SAME key
on 2xx with Idempotency-Replay: true → the first attempt had succeeded; do not treat as a new sendIdempotency-Replay: true 响应请求头标记了对原始响应的重放,因此你的代理可以记录 "recovered" 而非 "sent twice"。Bird SDK 会在每个变更请求上自动注入密钥,因此基于 SDK 的代理无需额外操作;使用 CLI 时,请在可能重试的变更操作上传入 --idempotency-key。
429 表示代理必须放慢速度。响应携带 Retry-After 请求头;将其作为最小退避时间,而不是另行设计一套调度策略:
代码示例
on 429: sleep max(Retry-After, backoff(attempt)); retry with the same key不要原样重试其他 4xx 响应。幂等性会缓存并重放它们,因为相同的请求产生相同的错误。先修复请求(模式 4),然后使用新的密钥;用不同的请求体复用同一密钥会返回 409 IdempotencyKeyReuse。
后续步骤
- MCP 服务器:这些模式所驱动的工具接口,托管在 mcp.bird.com 上或通过 CLI 在本地运行
- 面向代理的 CLI:面向可执行 shell 的代理的相同操作
- Webhooks 与事件:模式 2 背后的投递语义、签名和事件目录
- 幂等性:模式 5 背后的重放语义和故障模式
- 错误:错误响应结构和完整的错误码目录
- 邮件沙箱:模式 3 背后的魔法地址矩阵