告别“中间层”:用 UTCP 让 AI 直接调用你的 API

想象一下,如果你家的智能音箱不再通过层层转述,而是直接跟你的空调对话,是不是既快又稳?UTCP(Universal Tool Calling Protocol)干的就是这件事——让 AI 直接“拿起电话”打给工具,而不是经过一堆代理服务器。

direct-call

为什么需要 UTCP?

在 AI 应用里,想让大模型调用外部功能(查天气、下单咖啡、搜索论文)时,传统做法通常分三步:

  1. 搭一个“翻译”服务器,把 AI 的自然语言转成 API 请求;
  2. 服务器再去调真正的业务接口;
  3. 把结果包一层返回给 AI。

这套流程带来三个常见痛点:

  • 延迟高:每多一跳网络,就多几十毫秒。
  • 维护重:翻译服务器挂了,全链路停摆。
  • 重复造轮子:每个团队都得写一遍认证、限流、日志。

UTCP 的思路很简单:与其再包一层,不如直接告诉 AI 该怎么打原生的电话。它就像一本“说明书”,写清楚:

  • 电话号码是多少(URL、CLI 命令、WebSocket 地址……)
  • 该说什么语言(JSON、命令行参数、GraphQL 查询……)
  • 需要带什么证件(API Key、OAuth 令牌……)

看完说明书,AI 就能自己拨号,后续通信不再经过 UTCP 本身,省掉中间层,也省掉烦恼。


UTCP 的三件套:Manual、Tool、Provider

为了把“说明书”标准化,UTCP 只定义了三样东西:

名称 日常类比 作用
Manual 产品说明书 列出所有可用工具及其调用方式
Tool 具体功能 一次查天气、一次发邮件、一次跑脚本
Provider 通信方式(电话/微信/邮件) 描述如何连上工具(HTTP、gRPC、CLI 等)

1. Manual:一张 JSON 就能搞定

Manual 就是一个固定格式的 JSON 文件,放在你的域名下(如 /utcp)。示例:

{
  "version": "1.0",
  "tools": [
    {
      "name": "get_weather",
      "description": "查询城市当前天气",
      "inputs": {
        "type": "object",
        "properties": {
          "location": { "type": "string", "description": "城市名,例如 Beijing" },
          "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
        },
        "required": ["location"]
      },
      "outputs": {
        "type": "object",
        "properties": {
          "temperature": { "type": "number" },
          "conditions": { "type": "string" }
        }
      },
      "tool_provider": {
        "provider_type": "http",
        "url": "https://api.example.com/weather",
        "http_method": "GET"
      }
    }
  ]
}

把这段 JSON 放到 /utcp,你就完成了“说明书”的编写。AI 读取后,就知道:

  • 想查天气,就发 GET 请求到 https://api.example.com/weather
  • 必填参数是 location,可选 unit
  • 返回 JSON 里会有 temperatureconditions

2. Tool:最小可调用单元

一个 Tool 就是 Manual 里 tools 数组中的一个对象。它用 JSON Schema 描述输入输出,天然适合程序校验,人类阅读也不费劲。

3. Provider:通信协议的“翻译官”

Provider 挂在每个 Tool 下面,告诉 AI 该用哪种协议:

  • http:最常见的 REST API
  • websocket:需要长连接、推送场景
  • cli:直接跑本地命令行
  • grpc:高性能二进制调用
  • ……

Provider 里还能写变量占位符,比如:

"url": "https://${DOMAIN}/api/v1"

运行时,AI 会自动用本地配置或环境变量把 ${DOMAIN} 替换成真实值,避免把密钥写死。


十分钟上手:从天气 API 到 UTCP 服务

下面我们把一个现有的天气查询 API“UTCP 化”。假设你已经有一个接口:

GET /weather?location=Beijing&unit=celsius
返回
{ "temperature": 23, "conditions": "晴" }

第一步:写 Manual

新建 app.py,用 FastAPI 同时暴露 Manual 和真正的天气接口:

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List

app = FastAPI()

class UTCPManual(BaseModel):
    version: str
    tools: List[dict]

tools = [
    {
        "name": "get_weather",
        "description": "查询城市当前天气",
        "inputs": {
            "type": "object",
            "properties": {
                "location": {"type": "string"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["location"]
        },
        "outputs": {
            "type": "object",
            "properties": {
                "temperature": {"type": "number"},
                "conditions": {"type": "string"}
            }
        },
        "tool_provider": {
            "provider_type": "http",
            "url": "https://api.example.com/weather",
            "http_method": "GET"
        }
    }
]

@app.get("/utcp")
def utcp_discovery():
    return UTCPManual(version="1.0", tools=tools)

@app.get("/weather")
def get_weather(location: str, unit: str = "celsius"):
    # 这里调真实天气服务,示例写死
    return {"temperature": 23, "conditions": "晴"}

启动服务:

uvicorn app:app --reload

浏览器访问 http://localhost:8000/utcp 就能看到 Manual 了。

第二步:用 UTCP 客户端调用

安装官方 SDK(以 Python 为例):

pip install utcp

写个 client.py

import asyncio
from utcp.client import UtcpClient
from utcp.shared.provider import HttpProvider

async def main():
    client = await UtcpClient.create()
    manual_provider = HttpProvider(
        name="weather_demo",
        provider_type="http",
        url="http://localhost:8000/utcp",
        http_method="GET"
    )
    await client.register_manual_provider(manual_provider)

    result = await client.call_tool(
        "weather_demo.get_weather",
        arguments={"location": "Beijing"}
    )
    print(f"北京气温 {result['temperature']}°C,天气 {result['conditions']}")

if __name__ == "__main__":
    asyncio.run(main())

运行:

python client.py

输出:

北京气温 23°C,天气 晴

到这一步,你已经让 AI 直接调用天气 API,没有中间层,也没有额外服务器。


不止 HTTP:CLI、WebSocket 也能玩

UTCP 的魅力在于一视同仁。只要你能描述调用方式,就能被 AI 使用。

CLI 示例:让 AI 跑本地脚本

假设你有一个 Python 脚本 compress.py,接受文件路径参数,返回压缩率:

python compress.py /path/to/file
# 输出  { "ratio": 0.42 }

Manual 片段:

{
  "name": "compress_file",
  "description": "本地压缩文件并返回压缩率",
  "inputs": {
    "type": "object",
    "properties": {
      "path": { "type": "string", "description": "文件绝对路径" }
    },
    "required": ["path"]
  },
  "outputs": {
    "type": "object",
    "properties": {
      "ratio": { "type": "number" }
    }
  },
  "tool_provider": {
    "provider_type": "cli",
    "command": ["python", "compress.py", "${path}"]
  }
}

AI 拿到说明书后,会在本地执行 python compress.py /path/to/file,拿到压缩率。无需你把脚本包装成 HTTP 服务。

WebSocket 示例:实时日志推送

如果工具支持 WebSocket,Manual 可以这么写:

"tool_provider": {
  "provider_type": "websocket",
  "url": "wss://logs.example.com/stream",
  "auth": {
    "auth_type": "api_key",
    "api_key": "$LOG_TOKEN"
  }
}

AI 建立长连接,实时接收日志,再决定要不要继续监听或关闭通道。


变量与认证:安全和灵活兼得

真实环境少不了密钥。UTCP 允许把敏感信息抽离:

"url": "https://${DOMAIN}/api/v1",
"auth": {
  "auth_type": "api_key",
  "api_key": "$API_KEY"
}

变量解析顺序:

  1. 客户端代码里显式传入;
  2. 找不到就去读环境变量。

这样同一份 Manual 能在开发、测试、生产复用,只需换环境变量即可。

支持的认证方式:

  • api_key:放在 Header 或 Query
  • basic:用户名 + 密码
  • oauth2:标准授权码流程
  • 自定义扩展:只要你能描述,就能用

避坑指南:四个常见误区

  1. 把 UTCP 当网关
    UTCP 不做流量转发,它只是“说明书”。网络请求由 AI 直接发,别把 UTCP 部署在公网当代理。

  2. Manual 写死密钥
    用变量占位,避免密钥入库。

  3. 忽略超时和重试
    客户端 SDK 支持配置超时、重试、缓存,记得设置合理值,别让 AI 等半天。

  4. 输入输出 schema 太宽松
    宽松 schema 会导致 AI 胡乱传参。用 JSON Schema 精确描述,既帮助 AI 理解,也方便前端表单生成。


什么时候该用 UTCP?

场景 是否推荐 原因
已有 REST/GraphQL/gRPC 服务 直接暴露 Manual,零改造
本地脚本、命令行工具 CLI Provider 一行配置即可
需要双向实时通信 WebSocket/SSE Provider 原生支持
只想做流量网关 UTCP 不转发流量,用传统 API 网关更合适
需要复杂编排、聚合 UTCP 聚焦“单点调用”,复杂流程需在上层编排

展望:UTCP 与 AI 的未来协作

随着大模型能力增强,AI 将越来越多地直接操作外部世界。UTCP 提供了一种去中心化、低摩擦的接入方式:

  • 开发者:不用再为 AI 特化接口,写好 Manual 即可。
  • AI 平台:统一解析 Manual,就能调用成千上万的外部工具。
  • 用户:获得更快、更稳定的服务体验。

小结

UTCP 像一本清晰、可机读的说明书,让 AI 跳过“翻译官”,直接跟工具对话。它不需要你重写业务代码,也不会把你的系统锁死在某个平台。只要你会写 JSON、会搭 HTTP 端点,十分钟就能把现有服务“AI-ready”。

下次当你想让大模型查询天气、压缩文件、甚至启动训练任务时,不妨给 UTCP 一张说明书,然后让它自己拨号。

把复杂留给自己,把简单留给 AI——这大概就是 UTCP 最动人的地方。