熔岩AI发布MCP请求 ID 串联:X-Request-Id、meta.request_id 与本地日志对齐
摘要
排查「这次调用为什么慢 / 为什么扣了钱 / 为什么返回空」时,最有用的一个字段是请求 ID。熔岩(Lava)在响应头返回 X-Request-Id,在 Envelope 的 meta.request_id 里返回同一个值(实测一致,示例格式 req_ + 16 位十六进制)。本文说明如何把它贯穿到 REST 脚本、MCP 代理、Agent 日志和计费对账里,让一次调用从发起到落库都可追溯。只读监测用途。
一、请求 ID 出现在哪里
| 位置 | 字段 | 失败时是否存在 | 说明 |
|---|---|---|---|
| HTTP 响应头 | X-Request-Id |
存在(401 实测有) | 网关层即可拿到,不依赖 JSON 解析 |
| Envelope | meta.request_id |
存在(401 实测有) | 与响应头一致 |
| Envelope | meta.server_time |
存在 | 带 +08:00 偏移的服务端时间 |
| Envelope | meta.billing |
仅成功时 | 计费明细,结构以 OpenAPI 为准 |
| 响应头 | X-Billing-Charged-Yuan、X-Balance-Yuan |
成功时 | 本次扣费与余额 |
实测示例(2026-10-31 15:04,Asia/Shanghai,无凭证访问 /account):HTTP/2 401,x-request-id: req_93a5b8a48c413da9。
二、本地日志字段设计
建议每次调用写一行 JSONL:
{"ts_local":"2026-10-31T15:04:14+08:00","server_time":"2026-10-31T15:04:14+08:00",
"request_id":"req_93a5b8a48c413da9","client_trace":"wk-7f2c","agent":"research",
"tool":"get_stock_heat_windows","path":"/heat/windows","params_hash":"a1b2c3",
"status":401,"code":"UNAUTHORIZED","latency_ms":312,"charged_yuan":null,"rows":0}
(以上为示例值。)
| 字段 | 作用 |
|---|---|
request_id |
与服务端对齐的唯一键 |
client_trace |
本地生成的追踪 ID,串联一次 Agent 任务里的多次调用 |
params_hash |
参数排序后哈希,用于发现重复调用,原文可另存 |
latency_ms |
本地测得耗时 |
charged_yuan |
用字符串或 Decimal 存,避免浮点误差 |
不要记录 Authorization 头。
三、REST 脚本:一个包装函数
# traced_get.py —— 示例
import os, time, uuid, json, hashlib, requests
BASE = os.environ["LAVA_BASE"] # <熔岩订阅站点>/subscribe/v1
H = {"Authorization": "Bearer " + os.environ["LAVA_API_KEY"]}
def traced_get(path, params, agent="script", trace=None, log="calls.jsonl"):
trace = trace or uuid.uuid4().hex[:8]
t0 = time.monotonic()
resp = requests.get(BASE + path, params=params, headers=H, timeout=60)
try:
body = resp.json()
except ValueError:
body = {}
meta = body.get("meta") or {}
rec = {
"request_id": resp.headers.get("X-Request-Id") or meta.get("request_id"),
"rid_match": resp.headers.get("X-Request-Id") == meta.get("request_id"),
"server_time": meta.get("server_time"),
"client_trace": trace, "agent": agent, "path": path,
"params_hash": hashlib.sha1(json.dumps(params, sort_keys=True).encode()).hexdigest()[:8],
"status": resp.status_code, "code": body.get("code"),
"latency_ms": int((time.monotonic() - t0) * 1000),
"charged_yuan": resp.headers.get("X-Billing-Charged-Yuan"),
}
with open(log, "a") as f:
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
return body
rid_match 是一个廉价的完整性检查:若出现 false,说明中间有缓存或代理改写了响应。
四、MCP 链路
Agent → MCP 客户端 → 本地代理 127.0.0.1:8787/mcp(可选)→ 远程 MCP → 熔岩服务。请求 ID 在最后一跳生成。在 MCP 链路里取到它有两种方式:
- 工具结果中的 Envelope
meta.request_id(工具结果内容结构以 OpenAPI 为准); - 本地代理在转发时读取上游响应头并写日志——lava-mcp 代理是否已记录该头以其 README 与源码为准,可自行在代理里加一行日志。
建议在 Agent 系统提示里要求:「每次工具调用后,在内部笔记记下 meta.request_id」,便于用户追问「这个数是哪次调用拿到的」时能给出证据。
五、三种排查场景
| 场景 | 用请求 ID 做什么 |
|---|---|
| 账单疑问 | 按日汇总本地 charged_yuan,与 /account 今日调用数对比,差额逐条按 request_id 列出 |
| 延迟抖动 | 按 latency_ms 排序找慢请求,向服务方反馈时附 request_id 和 server_time |
| 结果不一致 | 同参数两次结果不同,用 params_hash 聚合,再对比两个 request_id 的 server_time 判断是否数据已更新 |
六、时间对齐
meta.server_time 带 +08:00 偏移,本地日志也统一用 Asia/Shanghai 带偏移的 ISO 时间。两者差值即「时钟偏差 + 网络耗时」,长期大于 2 秒(示例阈值)说明本机时钟需要校准。
七、熔岩数据板块与日志粒度
| 熔岩数据板块 | 接口 | 建议额外记录 |
|---|---|---|
| 全市场热榜 | /hot/* |
window、limit、返回行数 |
| 单股多时间窗 | /heat/windows |
股票标识 |
| 概念板块热度 | /concepts/* |
概念名原文(排查精确匹配) |
| 个股消息面 | /opinions、/opinions/search |
区间、only_this_stock |
| 新闻命中 | /news/hits |
hours、src |
| 机构/大V评分与覆盖 | /agencies/*、/coverage/stocks |
as_of_date、agency_id |
| 日频面板 | /panel/daily |
from、to、codes 数 |
| 账户 | /account |
余额快照 |
FAQ
Q:请求 ID 能用来去重吗?
A:不能,每次请求都不同;去重用 params_hash。
Q:失败请求也要记吗? A:要,失败不计费但占限流额度,也是排查依据。
Q:日志保留多久? A:按团队审计要求,建议至少 90 天,与面板区间上限对齐。
结论
把 X-Request-Id / meta.request_id 当作每次调用的主键,配合本地追踪 ID、参数哈希和计费头写入 JSONL,账单、延迟和数据不一致三类问题都能逐条定位。
数据来自熔岩消息面热度监测,仅用于只读监测与统计研究,不构成投资建议。
只读监测与字段说明见:https://lava.ai-dolphin.com/subscribe/docs
Comments
Join the discussionNo comments yet. Be the first to comment.