Sign inSign up

kingfs/llm-tracelab

By kingfs

Updated 6 days ago

A proxy-based tool for tracing, recording, and replaying LLM API requests.

Image
Machine learning & AI
Developer tools
0

6.2K

kingfs/llm-tracelab repository overview

llm-tracelab

Go Version License

中文说明 | English

llm-tracelab 是一个本地优先的 LLM HTTP 录制与回放代理。它当前覆盖 OpenAI-compatible、Anthropic Messages、Google GenAI 和 Vertex-native 这几类主流协议面。核心目标很直接:

  • 开发时把真实大模型 HTTP 请求录下来
  • 单元测试时直接回放,不再依赖外网和真实模型
  • 让测试更稳定、更快、更省钱

项目定位接近 http record/replay,但针对 LLM 场景补了流式响应、Token usage、可视化查看和故障注入能力。

当前版本发布说明

这次重构后的版本重点有四个:

  • pkg/llm 升级为按 provider/endpoint 工作的 adapter 层,统一处理 request、response、stream transcript 和 usage pipeline
  • Monitor 改成 Go embed 的 React UI,列表页异步分页,详情页支持 timeline / summary / raw protocol
  • SQLite 索引改用稳定 trace_id,不再在 URL 中暴露本地路径
  • LLM_PROXY_V3# event: 现在不仅有 request/response 基础事件,还会落 llm.* provider timeline

适合什么场景

  • 给 SDK 或业务代码做高可靠单元测试
  • 复现线上 prompt / tool call / stream 问题
  • 统计模型调用耗时、TTFT、Token 消耗
  • 在本地做 LLM API 代理调试和混沌测试

核心能力

  • 透明代理 OpenAI compatible 请求
  • 将一次请求/响应保存为本地 .http cassette
  • 使用 pkg/replay.Transport 在测试中直接回放
  • Monitor 页面查看请求详情、统一 timeline、原始协议和 Token 消耗
  • 使用 SQLite 维护 metadata 索引,避免统计页每次全量读文件
  • 支持对旧版 V2 记录文件兼容读取

项目结构

cmd/server            服务入口
internal/proxy        代理转发、stream 注入、响应拦截
internal/recorder     .http 录制与落盘
internal/store        SQLite 元数据索引
internal/monitor      Monitor UI 与详情解析
pkg/recordfile        录制文件格式 V2/V3 解析与 V3 写入
pkg/replay            单元测试回放 Transport
pkg/llm               多厂商请求/响应归一化

更适合 AI 阅读的项目约定见 AGENTS.md,架构摘要见 docs/ARCHITECTURE.md,上游兼容矩阵见 docs/UPSTREAM_PROVIDERS.md,项目路线图见 docs/ROADMAP.md,Vertex 协议族设计说明见 docs/VERTEX_NATIVE_PLAN.md

录制文件与索引

当前写入格式是 LLM_PROXY_V3

  1. 文件前导包含紧凑元数据行,而不是固定 2KB 占位行
  2. 原始 HTTP request/response 仍然完整保留,方便人工排查
  3. # event: 会记录统一 timeline,例如 llm.output_text.deltallm.reasoning.deltallm.tool_callllm.usage
  4. 请求摘要、耗时、Token、trace id 等会同步索引到 trace_index.sqlite3

默认存储布局:

logs/
  trace_index.sqlite3
  <upstream-host>/<model>/<yyyy>/<mm>/<dd>/*.http

快速开始

1. 配置

编辑 config/config.yaml

server:
  port: "8080"

monitor:
  port: "8081"

upstream:
  base_url: "https://api.openai.com/v1"
  api_key: "sk-xxx"
  provider_preset: "openai"      # 推荐优先填写 preset
  protocol_family: ""            # 可留空自动推断;与 provider_preset 冲突会在启动时报错
  routing_profile: ""            # 可留空自动推断;不支持的 preset/profile 组合会 fail fast
  api_version: ""                # Azure 用 query 参数;Anthropic 用 anthropic-version header
  deployment: ""                 # Azure deployment routing 时使用
  project: ""                    # Vertex project/location routing 时使用
  location: ""                   # Vertex regional host / path routing 时使用
  model_resource: ""             # Vertex model 资源,例如 publishers/google/models/gemini-2.5-flash
  headers: {}                    # 额外上游请求头,比如 anthropic-beta

debug:
  output_dir: "./logs"
  mask_key: false

如果你不想从零开始写配置,直接参考这些现成样例:

支持的环境变量覆盖:

  • LLM_TRACELAB_SERVER_PORT
  • LLM_TRACELAB_MONITOR_PORT
  • LLM_TRACELAB_UPSTREAM_BASE_URL
  • LLM_TRACELAB_UPSTREAM_API_KEY
  • LLM_TRACELAB_UPSTREAM_PROVIDER_PRESET
  • LLM_TRACELAB_UPSTREAM_PROTOCOL_FAMILY
  • LLM_TRACELAB_UPSTREAM_ROUTING_PROFILE
  • LLM_TRACELAB_UPSTREAM_API_VERSION
  • LLM_TRACELAB_UPSTREAM_DEPLOYMENT
  • LLM_TRACELAB_UPSTREAM_PROJECT
  • LLM_TRACELAB_UPSTREAM_LOCATION
  • LLM_TRACELAB_UPSTREAM_MODEL_RESOURCE
  • LLM_TRACELAB_OUTPUT_DIR
  • LLM_TRACELAB_MASK_KEY

推荐的兼容配置思路:

  • OpenAI / OpenRouter / Fireworks / Together / DeepSeek / Groq 等 OpenAI-compatible 服务:只设置 provider_presetbase_url,并确保 base_url 已包含上游 API 前缀,例如 /v1/api/v1/openai/openai/v1
  • Azure OpenAI /openai/v1/...:设置 provider_preset: azure,可选 api_version
  • Azure deployment 路由:设置 provider_preset: azure,并补 deployment
  • vLLM OpenAI-compatible server:设置 provider_preset: vllm
  • Anthropic Messages API:设置 provider_preset: anthropic,如需 beta 能力可在 headers 里补 anthropic-beta
  • Google GenAI API:设置 provider_preset: google_genai,当前支持 generateContentstreamGenerateContent 基础闭环
  • Vertex AI native API:优先使用 provider_preset: vertex;它会根据 base_url 推断 vertex_expressvertex_project_location

支持级别说明:

  • verified:已有行为测试或 cassette 级回归覆盖
  • compatible:按现有协议族抽象应当可工作,但直接验证较少
  • planned:尚未接入 preset 或尚未实现

配置校验规则:

  • provider_presetprotocol_familyrouting_profile 不再是松散字段
  • 无效组合会在启动时直接报错,而不是等到请求阶段才失败
  • 例如 provider_preset: anthropic 搭配 protocol_family: google_genai 会直接失败
  • 例如 provider_preset: openrouter 搭配 routing_profile: azure_openai_v1 也会直接失败

当前推荐支持矩阵:

  • provider_preset: openai support: verified protocol_family: openai_compatible routing_profile: openai_default
  • provider_preset: openrouter | fireworks | together | deepseek | groq | moonshot | cerebras | perplexity support: openrouter/fireworks/together/groq=verified; deepseek/moonshot/cerebras/perplexity=compatible protocol_family: openai_compatible routing_profile: openai_default
  • provider_preset: azure support: verified protocol_family: openai_compatible routing_profile: azure_openai_v1azure_openai_deployment
  • provider_preset: vllm support: verified protocol_family: openai_compatible routing_profile: vllm_openai
  • provider_preset: anthropic support: verified protocol_family: anthropic_messages routing_profile: anthropic_default
  • provider_preset: google_genai | google | gemini support: verified protocol_family: google_genai routing_profile: google_ai_studio
  • provider_preset: vertex support: verified protocol_family: vertex_native routing_profile: vertex_express | vertex_project_location notes: 受控 preset;已覆盖 adapter / proxy / cassette regression

Anthropic 示例:

upstream:
  base_url: "https://api.anthropic.com"
  api_key: "sk-ant-xxx"
  provider_preset: "anthropic"
  api_version: "2023-06-01"
  headers:
    anthropic-beta: "tools-2024-04-04"

Google GenAI 示例:

upstream:
  base_url: "https://generativelanguage.googleapis.com"
  api_key: "AIza..."
  provider_preset: "google_genai"

Vertex express 示例:

upstream:
  base_url: "https://aiplatform.googleapis.com"
  api_key: "ya29..."
  provider_preset: "vertex"
  model_resource: "publishers/google/models/gemini-2.5-flash"

Vertex project/location 示例:

upstream:
  base_url: "https://us-central1-aiplatform.googleapis.com"
  api_key: "ya29..."
  provider_preset: "vertex"
  project: "demo-project"
  location: "us-central1"
  model_resource: "publishers/google/models/gemini-2.5-flash"

如果你想完全避免 preset,也仍然可以继续显式填写:

  • protocol_family: vertex_native
  • routing_profile: vertex_express | vertex_project_location

Azure deployment 示例:

upstream:
  base_url: "https://demo-resource.openai.azure.com"
  api_key: "azure-key"
  provider_preset: "azure"
  deployment: "gpt-4o-mini"
  api_version: "2025-03-01-preview"
2. 构建和运行

推荐使用 go-task

task build
task run
task migrate

如果只想直接运行:

go run ./cmd/server -c config/config.yaml

把你的 SDK base_url 指向 http://localhost:8080/v1 后,请求就会被代理并录制。

3. 打开 Monitor

访问 http://localhost:8081

详情页现在包含三个主视图:

  • Timeline:消费 cassette 中的统一 llm.* 事件
  • Summary:按对话、工具、输出块聚合展示
  • Raw Protocol:左右分栏查看原始 request/response

老日志迁移与索引重建

显式迁移命令:

go run ./cmd/server migrate -c config/config.yaml

这个命令默认会做两件事:

  • 将旧的 LLM_PROXY_V2 .http 文件原地改写成 LLM_PROXY_V3
  • 清空并重建 trace_index.sqlite3

如果只想做其中一部分:

go run ./cmd/server migrate -c config/config.yaml -rewrite-v2=false
go run ./cmd/server migrate -c config/config.yaml -rebuild-index=false

适合老日志目录批量升级,或者 SQLite 索引损坏/丢失后的全量恢复。

Docker / Compose

容器内约定的标准路径:

  • 可执行文件:/app/bin/llm-tracelab
  • 配置文件:/app/config/config.yaml
  • 数据目录:/app/data/traces
  • SQLite 索引:/app/data/traces/trace_index.sqlite3

默认提供:

启动方式:

export LLM_TRACELAB_UPSTREAM_API_KEY=sk-xxx
docker compose up --build

如果只想直接使用已经发布到 Docker Hub 的镜像,可以不克隆仓库,直接运行:

docker run --rm \
  -p 8080:8080 \
  -p 8081:8081 \
  -e LLM_TRACELAB_UPSTREAM_BASE_URL=https://api.openai.com/v1 \
  -e LLM_TRACELAB_UPSTREAM_API_KEY=sk-xxx \
  -e LLM_TRACELAB_OUTPUT_DIR=/app/data/traces \
  -e LLM_TRACELAB_SERVER_PORT=8080 \
  -e LLM_TRACELAB_MONITOR_PORT=8081 \
  -v "$(pwd)/docker-data:/app/data" \
  kingfs/llm-tracelab:latest serve -c /app/config/config.yaml

如果你更习惯 docker compose,也可以直接引用 Docker Hub 镜像:

services:
  llm-tracelab:
    image: kingfs/llm-tracelab:latest
    ports:
      - "8080:8080"
      - "8081:8081"
    environment:
      LLM_TRACELAB_UPSTREAM_BASE_URL: https://api.openai.com/v1
      LLM_TRACELAB_UPSTREAM_API_KEY: ${LLM_TRACELAB_UPSTREAM_API_KEY}
      LLM_TRACELAB_OUTPUT_DIR: /app/data/traces
      LLM_TRACELAB_SERVER_PORT: "8080"
      LLM_TRACELAB_MONITOR_PORT: "8081"
    volumes:
      - ./config/config.docker.yaml:/app/config/config.yaml:ro
      - ./docker-data:/app/data
    command: ["serve", "-c", "/app/config/config.yaml"]

如果本机访问 Go 官方模块代理较慢,可以在构建时直接传入 GOPROXY

GOPROXY=https://goproxy.cn,direct docker compose build

默认挂载:

  • ./config/config.docker.yaml -> /app/config/config.yaml:ro
  • ./docker-data -> /app/data

运行镜像默认使用 root 用户启动。这是为了兼容最常见的 bind mount 场景,避免宿主机目录属主与容器内固定 UID/GID 不一致时出现 permission denied,例如无法创建 /app/data/traces

如果在容器外部配置,优先通过挂载配置文件和环境变量覆盖 upstream、端口、输出目录;debug.output_dir 建议始终指向容器内挂载卷中的固定路径。

开发命令

task fmt
task lint
task test
task build
task run
task migrate
task check
task docker:build
task docker:up

在单元测试中回放

func TestChat(t *testing.T) {
    tr := replay.NewTransport("testdata/chat.http")

    cfg := openai.DefaultConfig("fake-key")
    cfg.BaseURL = "http://localhost/v1"
    cfg.HTTPClient = &http.Client{Transport: tr}

    client := openai.NewClientWithConfig(cfg)
    resp, err := client.CreateChatCompletion(context.Background(), req)
    _ = resp
    _ = err
}

当前设计原则

  • .http cassette 是回放的事实来源
  • SQLite 只做 metadata 索引,不替代原始文件
  • 新文件写 V3,旧文件继续兼容读取
  • 尽量保持文件可读、测试离线、实现本地优先
  • provider 语义、stream transcript、usage 和 event timeline 尽量收敛在 pkg/llm

截图

  • Monitor 总览
  • 对话详情
  • SSE 原始流
  • 非流式响应

License

MIT

Tag summary

Content type

Image

Digest

sha256:58af90df2

Size

17.7 MB

Last updated

6 days ago

docker pull kingfs/llm-tracelab