# 熔岩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：

```json
{"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 脚本：一个包装函数

```python
# 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 链路里取到它有两种方式：

1. 工具结果中的 Envelope `meta.request_id`（工具结果内容结构以 OpenAPI 为准）；
2. 本地代理在转发时读取上游响应头并写日志——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

