接入 Hy3 后只看到一个错误码,最容易误判的是把网关或鉴权问题当成模型没加载。排查顺序建议从离你最近的一层开始:先在客户端把发出去的请求和超时固定下来,再去网关看请求有没有命中路由、鉴权有没有通过,最后才到推理服务日志里确认请求是否真正到达。每一层只回答一个可验证的问题,不要跨层猜。
只看到一个错误码时,先不要改模型服务。按客户端→网关→推理服务分层读日志,能区分请求参数、鉴权配置和服务未就绪。客户端固定请求体和超时,网关核对路由与鉴权,推理服务对齐时间戳或请求标识。若请求未到达模型侧,优先查网关转发与网络;若已到达,再按参数错误、资源不足、服务未就绪三类归位。边界是:只依据日志、配置和可复现命令下判断。
先在客户端把请求体和超时打出来,确认发出去的是什么
这一层的目的不是找出根因,而是先固定输入。很多“推理服务报错”最后发现是客户端字段名写错、content-type 不对或超时太短。建议把请求字段、返回状态码、总耗时和响应体前若干字符一起记录,避免后面把参数问题当成服务问题。
下面是一个通用请求骨架,字段名用占位符表示。替换 <GATEWAY_HOST>、<PATH>、<MODEL_NAME>、<TOKEN> 等为你的实际值。如果使用 SDK,也建议在调用前后加同样日志。
import requests, time, logging
logging.basicConfig(level=logging.INFO)
url = 'http://<GATEWAY_HOST>:<PORT>/<PATH>'
headers = {
'Authorization': 'Bearer <TOKEN>',
'Content-Type': 'application/json',
'x-request-id': '<CLIENT_GENERATED_ID>'
}
payload = {
'model': '<MODEL_NAME>',
'input': '<PROMPT_OR_TENSOR>',
'parameters': {'<PARAM_KEY>': '<PARAM_VALUE>'}
}
start = time.time()
resp = requests.post(url, json=payload, headers=headers, timeout=<TIMEOUT_SEC>)
elapsed = time.time() - start
logging.info('url=%s status=%s elapsed=%.3fs req_id=%s body=%s',
url, resp.status_code, elapsed,
resp.headers.get('x-request-id', '<NONE>'),
resp.text[:500])
print(resp.status_code, elapsed)
需要记录:HTTP 状态码、总耗时(含连接和读取)、响应头中的 request id(若有)、响应体中的错误结构。验证方式:多次重复同一请求,看错误是否稳定复现。风险边界:日志里不要打印完整 token 或敏感输入;只记录字段名和截断后的响应体。
在网关侧确认路由与鉴权配置是否命中
客户端状态码如果是 401、403、404、502、504,问题可能不在推理服务。适用场景是请求经过网关或反向代理。操作动作:逐条核对路由路径、方法、上游地址、鉴权方式和超时。验证方式:在网关访问日志里查同一次请求的 request id 或客户端 IP + 时间。
配置项占位示例(不同网关字段名不同,以实际为准):
routes:
- path: '<ROUTE_PATH>'
methods: ['POST']
upstream: 'http://<INFERENCE_SERVICE_HOST>:<PORT>'
auth:
type: 'bearer'
token_env: '<ENV_VAR_NAME>'
timeout_seconds: <GATEWAY_TIMEOUT>
逐条核对:路径是否完全匹配,注意前缀、尾部斜杠、大小写;方法是否允许;上游地址是否指向当前推理服务实例;鉴权 token 是否与网关配置的环境变量一致;网关超时是否小于推理服务实际处理时间。不同状态码在该层可能对应:401/403 通常表示鉴权失败或权限不足,404 通常表示路由未命中,502 通常表示上游连接失败或返回无效,504 通常表示网关等待上游超时。以实际返回和日志为准,不要只凭状态码下结论。
在推理服务日志里对齐同一次请求的时间戳
如果网关已经转发,下一步要确认请求是否真的到达模型侧。适用场景是网关返回 5xx 或长时间无响应。操作动作:用客户端记录的请求开始时间、网关访问日志时间、推理服务日志时间做窗口对齐;如果客户端或网关生成了 request id,优先用 request id 在推理服务日志中搜索。
对齐方法示例:
# 在推理服务日志中按 request id 查
grep -n '<REQUEST_ID>' /var/log/<INFERENCE_SERVICE>.log
# 若没有 request id,用时间窗口(替换为实际时间)
grep -n '<DATE> <TIME_PREFIX>' /var/log/<INFERENCE_SERVICE>.log
到达与未到达两种情况:如果日志里有对应时间戳或 request id,说明请求已到达模型侧,下一步看输入校验、排队、显存和模型加载状态;如果完全没有记录,优先查网关转发规则、网络连通性、推理服务监听端口和防火墙,而不是改模型参数。风险边界:时间对齐要考虑客户端、网关、推理服务的时钟偏差,建议用 NTP 同步或至少在日志中记录时区。
把报错按参数错误、资源不足、服务未就绪三类归位
不做无依据猜测的归类依据是:响应体错误码、日志关键字和请求是否到达。下面三类可以覆盖常见情况,但需要结合你的实际错误信息。
- 参数错误:响应体常见 400、422,日志含 schema validation failed、missing field、invalid type、shape mismatch、unsupported parameter。处置动作:按提示修正字段名、类型、长度、维度或批量大小,然后重发最小请求验证。
- 资源不足:响应体常见 503、500,日志含 out of memory、CUDA out of memory、no available memory、queue full、max batch exceeded。处置动作:降低单次请求体积或并发,释放显存,检查资源限制,必要时扩容或限流。
- 服务未就绪:连接被拒绝,或响应体含 service unavailable、health check failed、model not loaded、starting。处置动作:等待加载完成,检查启动日志、探针和依赖服务;确认模型文件路径和版本与配置一致。
验证方式:每类归位后只改一个变量再重试,观察错误是否变化。风险边界:不要同时改参数和扩容,否则无法判断是哪一项生效。
确认是服务问题后做一次最小复现并保留现场
最小复现的目的是让问题可交接。适用场景是你已经排除客户端参数和网关鉴权,错误仍出现在推理服务侧。操作动作:用 curl 或脚本发一个最小请求,保留完整命令、响应和两端日志。验证方式:换一台机器或换一个 token 复现,确认是否与调用方环境有关。
最小复现命令骨架:
curl -v -X POST 'http://<GATEWAY_HOST>:<PORT>/<PATH>' \
-H 'Authorization: Bearer <TOKEN>' \
-H 'Content-Type: application/json' \
-H 'x-request-id: <REPRO_ID>' \
-d '{"model":"<MODEL_NAME>","input":"<INPUT>","parameters":{}}'
需要保留的日志片段与配置快照清单:客户端请求头(脱敏)、请求体字段名和大小、响应状态码与响应体;网关访问日志中对应 request id 的条目;网关路由与鉴权配置快照;推理服务启动参数、环境变量(脱敏)、模型版本、资源限制和最近的错误日志段。风险边界:配置快照可能包含密钥或内网地址,交接前先脱敏,只保留与问题相关的字段。