你大概遇到过这种纠结:手上有个服务想给模型用,是包成 OpenAI 的 tools 字段塞进请求里,还是写成一个 MCP 服务器挂上去?两边都能让模型「动手」,但一个跟单次请求绑死,一个是可以复用的常驻能力。这篇不讲协议规范,只讲落地时怎么选、拆开以后各自的超时、并发、日志和验收怎么处理。
你大概遇到过这种纠结:手上有个服务想给模型用,是包成 OpenAI 接口的 tools 字段塞进请求里,还是写成一个 MCP 服务器挂上去?两边都能让模型「动手」,但一个跟单次请求绑死,一个是可以复用的常驻能力。这篇不讲协议规范,只讲落地时怎么选,以及拆开以后各自的超时、并发、日志和验收怎么处理。
先说一个容易踩的坑:很多人把这两个当成同一层的东西比较,其实位置不一样。搞清楚谁在请求里、谁在请求外,后面的选型、排查、监控才有统一的判断口径。下面按位置、超时、并发日志、迁移清单、怎么选这五段来说,每段都给你能直接照着做的检查项。
先把两者的位置摆正:一个是请求内的字段,一个是外挂的能力层
OpenAI 接口侧的工具调用,是请求参数的一部分。你在一次对话请求里声明有哪些函数、模型决定调哪个、由你自己的代码执行完再把结果塞回去,整个连接生命周期跟着这次请求走,请求结束连接也就散了。MCP 走的是客户端与服务端分离的路子,能力先被注册到一个可被发现的服务器上,调用方按需连接、列出能力、再调用。
- 请求内声明
- 工具定义写在每次请求里,随请求生随请求灭,调用方就是发起对话的那段代码。
- MCP 服务
- 能力挂在独立服务上,多个客户端、多个会话可以反复接上,声明一次复用多次。
- 发现机制
- 请求内靠你自己维护函数清单,MCP 靠客户端去列能力,写错名字的表现完全不同。
- 只是当前这条链路用、参数每次都变,放请求里更省事,改起来只动一处代码。
- 要被多个应用、多个人反复用,或者本身要连数据库、连内网系统,做成 MCP 服务更划算。
- 能力要单独限流、单独发布、单独扩容的,倾向 MCP;跟对话节奏完全同步的,倾向请求内。
- 不适用的情况:调用方根本不是支持 MCP 的客户端,或者运行环境不允许起常驻进程,那这条路走不通,还是回到请求内声明。
超时怎么设:一条请求内调用 vs 一次外挂连接
请求内的工具调用,超时算在整条请求里。函数本身跑多久,会直接顶掉这次对话的等待时间,所以先给函数自己设一个比整条请求更短的硬上限,别让它拖垮整次请求。MCP 这边要拆开看三段:连接建立的超时、单次工具调用的超时、以及服务端自身执行任务的超时。三段分别设,混成一个数字,最后很难定位是哪一段慢。
| 关注点 | 请求内调用 | MCP 服务 |
|---|---|---|
| 超时归属 | 整条请求超时的一部分 | 连接、调用、服务端执行三段 |
| 典型失败 | 函数报错或超时,顶掉整轮对话 | 连不上、列不出能力、调用返回错误 |
| 排查起点 | 先测函数自己跑多久 | 先确认服务进程活着、端口通 |
| 重试方式 | 重发整轮或让模型换参数 | 先重连,再重试单次调用 |
失败处理的差异也挺大。请求内调用失败,通常重试整轮或者让模型换个参数再试;MCP 服务挂了,调用方往往先表现为连接不上或列不出能力,这时候要先确认服务在不在,而不是急着改提示词。改提示词是最后一步,别一上来就动它。
并发与日志:两边该记的字段不是一回事
请求内调用天然和对话并发绑在一起,你的并发上限就是接口的并发上限。工具函数要么做成无状态,要么自己排队,否则会出现同一份数据被同时改。MCP 服务是独立进程,可以单独限流、单独扩容,好处是工具侧不会因为对话量突增被打爆,代价是多了一层要监控的东西。
| 日志字段 | 请求内调用 | MCP 服务 |
|---|---|---|
| 关联标识 | 请求 ID | 请求 ID + 连接 ID + 实例标识 |
| 工具信息 | 工具名、入参摘要 | 工具名、入参摘要、能力版本 |
| 耗时 | 函数耗时 | 建连耗时 + 调用耗时 + 服务端耗时 |
| 结果 | 状态、错误码 | 状态、错误码、服务端返回原文 |
- 请求 ID 两边都留,用来把一次任务串起来看,不然跨服务就有断点。
- MCP 侧多加服务实例标识和连接 ID,多实例部署时才分得清是哪台在出错。
- 如果工具就是一次纯查询、没有副作用,日志可以只留耗时和状态,没必要把入参全打出来,省得把敏感字段落盘。
- 有写操作的工具,入参摘要也别直接存原文,留个可追溯的哈希或者编号就够。
从请求内调用迁到 MCP,按这个清单走一遍
- 先盘点重复声明的工具翻一遍代码,看哪些工具被三个以上地方重复声明过,这些最值得迁;只在一个流程里用一次的,迁过去反而多一层维护成本。
- 冻结输入输出结构MCP 服务一旦上线,改参数结构会同时影响所有调用方,比改一次请求麻烦得多,所以迁之前把输入输出字段名和类型定死。
- 灰度并存跑对照新老两条路并存一段时间,用同一批测试输入跑对照,看结果是否一致;不一致先查参数类型和字段命名,这两处最容易在搬迁时走样。
- 验收三个指标单次调用的耗时基线、失败率、走通一次完整任务需要的调用轮数。数字对不上就别急着下线老路。站内 /tools/speed-test 可以先量出你的延迟基线再对比。
迁移里最容易忽略的是调用轮数。原来在请求内一轮就能拿到的结果,拆成 MCP 之后可能要「列能力、调工具、再确认」好几步,轮数上去了,整体体感就慢了。所以验收不只看单次调用快不快,还要看一次任务总共走了几步。
怎么选:按场景对照,而不是按哪个更先进
选请求内调用,适合链路短、工具是当前应用私有的、团队里没人维护额外服务、调用方是不支持 MCP 的客户端这些情况。选 MCP,适合能力要跨应用复用、要连内网或数据库、需要独立限流和独立发布节奏,或者你想让别人也能接上你这份能力。两者可以共存,高频且私有的放请求里,通用且要复用的做成 MCP,不用强迫自己二选一。
| 你的情况 | 倾向选择 | 理由 |
|---|---|---|
| 工具只服务一个应用 | 请求内调用 | 少一层服务,改起来快 |
| 三个以上地方重复声明 | MCP | 声明一次复用多次 |
| 要连内网或数据库 | MCP | 独立进程好控权限和网络 |
| 调用方不支持 MCP | 请求内调用 | 没得选,先把功能跑通 |
拿不准时的临时做法:先把工具写成普通函数跑通,等第二个调用方出现再考虑封成 MCP 服务,这样能避免过早抽象。过早抽象的成本不是写服务那几天,而是后面每次改结构都要通知一圈调用方。想拓展工具生态可以去 /mcp 翻一翻现有服务器都提供了哪些能力,心里有个参照。
下一步先按上面那张对照表给你的工具分个类,再拿 /tools/speed-test 量一条延迟基线;真要迁移前,把耗时和轮数记下来,到 /sites 对一下同类中转与工具链的接入情况,心里更有底。→常见问题
MCP 是不是就能替代 OpenAI 接口的工具调用?
不是替代关系。两者解决的是不同层面的问题:一个解决能力怎么被发现和复用,一个解决单次请求里怎么让模型触发一个函数。实际项目里经常同时存在,私有短链路走请求内声明,通用能力做成 MCP 服务,按复用频率和是否有独立进程需求来分。
只写 OpenAI tools 字段,不搞 MCP,会不会有什么硬伤?
取决于规模。工具少、调用方单一、没有跨应用复用需求时完全够用,硬伤不明显。真正会疼的是:同一份工具声明被复制到多个项目里改来改去;工具需要访问内网资源而你的接口层不方便直连;以及想单独给工具限流却发现它和对话并发绑死了。
迁移的时候最容易踩的坑是什么?
参数结构走样和超时口径混在一起。前者表现为模型调用时字段对不上,多半是搬迁时改了命名或嵌套层级;后者表现为偶尔整体变慢,其实是把连接超时、调用超时和服务执行超时合并成了一个数字,定位不出是哪一段。先固定数据结构、再分段设超时,能挡掉大半问题。