很多接口接入测试只做到这一步发送一句“你好”收到 HTTP 200 和一段文本然后宣布接入完成。这个结论下得太早了。HTTP 200 只说明这一次请求被正常处理。它不能证明模型没有经过别名路由不能证明usage可用于账单核对也不能证明 SSE、工具调用、Responses API 或 Claude Messages 能用。普通聊天正常接到 Cursor、Codex、Claude Code 或 Dify 后仍然报错往往就是因为验收只测了最简单的一层。下面是一套我现在使用的检查顺序。示例采用 OpenAI Chat Completions 风格接口Base URL、API Key 和模型 ID 都从环境变量读取换成其他兼容服务也能复用。适用范围公开 HTTPS、Bearer API Key、OpenAI Chat Completions 兼容接口。它不直接验证 OpenAI Responses API、Anthropic Messages、Gemini 原生接口、图片或视频任务。一、先把“连通”和“兼容”拆开我会把验收分成五层DNS、HTTPS 和认证是否正常模型列表与 Chat Completions 是否能调用响应中的模型声明和 Token 字段是否完整SSE 是否真的逐块返回并正常结束工具调用是否返回可解析的函数名与 JSON 参数。前两层通过只能说明基础链路打通。你的项目如果依赖 Agent、函数调用或成本核算后三层才是容易出问题的地方。二、准备三个环境变量macOS 或 Linuxexport API_BASE_URLhttps://www.aifast.hk/v1 export API_KEY你的临时限额Key export MODEL_ID从模型列表复制的真实模型IDPowerShell$env:API_BASE_URL https://www.aifast.hk/v1 $env:API_KEY 你的临时限额Key $env:MODEL_ID 从模型列表复制的真实模型ID建议单独创建临时 Key限制额度检查完成后撤销。不要把 Key 写进脚本、仓库、截图或文章。还有一个常见坑SDK 的base_url通常填写到/v1而原始 HTTP 请求还要继续拼/chat/completions。如果客户端会自动拼版本路径再手动写一遍/v1最终可能变成/v1/v1。不确定最终地址时可以先用 Base URL 检查器查看路径拼接结果。这个工具只在浏览器本地处理地址不需要填写 API Key。三、用标准库跑基础协议检查下面的脚本只使用 Python 标准库不需要安装 SDK。它会检查模型目录、最小聊天、响应模型字段、Token 和固定工具调用。import json import os import secrets import urllib.error import urllib.request BASE_URL os.environ[API_BASE_URL].rstrip(/) API_KEY os.environ[API_KEY] MODEL_ID os.environ[MODEL_ID] def request_json(path, payloadNone): body None if payload is None else json.dumps(payload).encode(utf-8) request urllib.request.Request( f{BASE_URL}{path}, databody, methodGET if payload is None else POST, headers{ Authorization: fBearer {API_KEY}, Content-Type: application/json, }, ) try: with urllib.request.urlopen(request, timeout60) as response: return response.status, dict(response.headers), json.load(response) except urllib.error.HTTPError as error: detail error.read().decode(utf-8, errorsreplace) raise RuntimeError(fHTTP {error.code}: {detail}) from error status, _, models request_json(/models) model_ids { item.get(id) for item in models.get(data, []) if isinstance(item, dict) } print(f[models] HTTP {status}, models{len(model_ids)}) print(f[models] requested model listed{MODEL_ID in model_ids}) nonce secrets.token_hex(6) status, _, chat request_json( /chat/completions, { model: MODEL_ID, temperature: 0, messages: [ { role: user, content: f只回复下面的字符串不要解释probe-{nonce}, } ], }, ) choice (chat.get(choices) or [{}])[0] content ((choice.get(message) or {}).get(content) or ).strip() usage chat.get(usage) or {} print(f[chat] HTTP {status}) print(f[chat] response model{chat.get(model)!r}) print(f[chat] nonce matched{content fprobe-{nonce}}) print( [usage] prompt/completion/total f{usage.get(prompt_tokens)}/ f{usage.get(completion_tokens)}/ f{usage.get(total_tokens)} ) tool_nonce secrets.token_hex(6) status, _, tool_response request_json( /chat/completions, { model: MODEL_ID, temperature: 0, messages: [ { role: user, content: f调用 record_probenonce 必须是 {tool_nonce}, } ], tools: [ { type: function, function: { name: record_probe, description: 记录一次接口验收探针, parameters: { type: object, properties: { nonce: {type: string} }, required: [nonce], additionalProperties: False, }, }, } ], tool_choice: { type: function, function: {name: record_probe}, }, }, ) message ((tool_response.get(choices) or [{}])[0].get(message) or {}) tool_calls message.get(tool_calls) or [] arguments {} if tool_calls: raw_arguments tool_calls[0].get(function, {}).get(arguments, {}) try: arguments json.loads(raw_arguments) except json.JSONDecodeError: pass print(f[tool] HTTP {status}) print(f[tool] call returned{bool(tool_calls)}) print(f[tool] name{tool_calls[0].get(function, {}).get(name) if tool_calls else None}) print(f[tool] nonce matched{arguments.get(nonce) tool_nonce})保存为check_api.py后运行python3 check_api.py脚本没有给接口打总分因为不同项目关注点不同。只做普通问答时工具调用失败未必阻塞上线Agent 项目则相反工具调用是硬门槛。四、怎样看这几项结果1./models返回 200这能说明域名、HTTPS、API Key 和模型目录路由基本正常。还要确认MODEL_ID是否真的出现在data[].id中。有些客户端允许手动输入模型名即使列表中没有也会尝试请求。生产环境不要依赖这种碰运气的配置先以当前账号实际返回的模型 ID 为准。2. 响应model与请求不一致不要立即据此断言“套壳”。模型别名、版本快照、路由组和上游字段映射都可能造成差异。更稳妥的做法是记录请求模型、响应模型、请求时间和请求 ID在不同时段重复测试。如果字段长期变化同时伴随工具调用、上下文或业务题集表现明显漂移再排查路由替换。3.usage缺失或不完整对账、成本控制和限额系统通常需要输入、输出和总 Token。文本能返回但usage为空可能不影响一次聊天却会影响预算告警和调用审计。这里还要注意客户端看到的 Token 字段不一定等于最终账单。正式费用仍应和服务商控制台核对。4. 动态字符串没有原样返回随机 nonce 用来避免缓存固定答案也能发现提示词被额外包装、输出被截断或模型没有遵守最小指令。单次失败不代表模型身份有问题先固定参数重试并和自己的真实任务基线一起看。5. 工具调用返回了文本没有tool_calls这通常表示目标模型、网关或当前路由没有按兼容格式处理工具调用。也可能是tool_choice不受支持。Agent 项目不能只检查模型是否“知道该调用什么”。必须确认函数名、参数 JSON、工具结果回传和后续消息链都能跑通。上面的脚本只验证第一段工具调用正式上线还要补一轮工具结果回传。五、SSE 要单独测试非流式请求返回 200不代表流式链路正常。使用curl -N查看原始事件curl -N $API_BASE_URL/chat/completions \ -H Authorization: Bearer $API_KEY \ -H Content-Type: application/json \ -d { \model\: \$MODEL_ID\, \stream\: true, \messages\: [ {\role\: \user\, \content\: \分五行输出数字1到5\} ] }检查时不要只看终端最后有没有完整文字还要看Content-Type是否为事件流类型是否连续收到多个data:块最后一段是否正常结束中途断开时客户端会不会误报成功反向代理或 CDN 是否把分块缓冲成一次性输出。如果curl -N能逐块输出网页却等到最后才显示问题更可能在应用后端、代理缓冲或前端读取方式而不是模型本身。六、看到这些组合时该查什么现象优先排查/models成功Chat 返回 404Base URL 拼接、接口路径、模型对应的协议普通文本成功SSE 一次性返回代理缓冲、Content-Type、客户端是否按流读取文本成功工具调用被忽略模型能力、tools/tool_choice支持和兼容层转换请求与响应模型长期不一致模型别名、路由映射、上游切换和维护公告usage长期为空网关字段映射、流式最终块、账单统计来源高峰期才出现 429 或 5xx限流、并发、上游容量、重试和熔断策略Chat 正常Codex 仍失败Responses API、流式事件、工具调用和上下文压缩Chat 正常Claude Code 仍失败Anthropic Messages 路径、请求头和tool_use事件最后两行很重要。OpenAI Chat Completions、OpenAI Responses 和 Anthropic Messages 是不同协议。一个接口写着“OpenAI Compatible”不能直接推导出 Codex 或 Claude Code 完整可用。七、什么时候可以进入生产我通常至少保留这些证据最终请求 URL、状态码和响应Content-Type请求模型与响应模型输入、输出和总 TokenSSE 首块、结束事件和断流状态工具名、参数 JSON 和工具结果回传401、404、429、5xx 的原始错误正文两到三个不同时段的重复结果一组来自真实业务、能人工核对的固定题集。不要公开完整 API Key、用户提示词、内部域名和未经脱敏的请求日志。如果不想先写脚本可以使用 大模型 API 中转站在线检测运行基础协议、模型声明、Token、动态题、SSE 和工具调用检查。它适合做风险筛查不是厂商身份认证报告总分表示兼容度也不是模型智力分。进一步阅读检测报告怎么判读Chat、Responses、Claude 与多模态兼容性矩阵SSE 流式输出配置与断流排查参考规范OpenAI API Reference: https://developers.openai.com/api/reference/resources/chatWHATWG Server-Sent Events: HTML StandardRFC 9110 HTTP Semantics: RFC 9110: HTTP Semantics | RFC Editor