# llm-proxy **Repository Path**: qchen007/llm-proxy ## Basic Information - **Project Name**: llm-proxy - **Description**: 大模型高性能代理 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-18 - **Last Updated**: 2026-06-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # llm-proxy 统一的 LLM API 网关:用 OpenAI 兼容协议访问 OpenAI 和 Anthropic,可叠加 Redis 后端的多维限流与 Prometheus 指标(阶段 2)。 ## 快速开始 1. 复制配置模板: ```bash cp config.example.yaml config.yaml ``` 2. 设置必需的环境变量: ```bash export PROXY_KEY_DEV="sk-proxy-dev-xxx" # 客户端用这把 key export OPENAI_API_KEY="sk-..." # 你的 OpenAI key export ANTHROPIC_API_KEY="sk-ant-..." # 你的 Anthropic key ``` 3. 启动: ```bash cargo run --release -- --config ./config.yaml ``` 4. 调用(用任何 OpenAI 兼容 SDK,base_url 指向代理): ```python from openai import OpenAI c = OpenAI(api_key="sk-proxy-dev-xxx", base_url="http://localhost:8080/v1") r = c.chat.completions.create( model="anthropic/claude-sonnet-4-5", messages=[{"role": "user", "content": "Hello"}], ) print(r.choices[0].message.content) ``` 把 `model` 改成 `openai/gpt-4o` 就会路由到 OpenAI。 ## Docker ```bash docker build -t llm-proxy:dev . docker run --rm -p 8080:8080 \ -e PROXY_KEY_DEV=$PROXY_KEY_DEV \ -e OPENAI_API_KEY=$OPENAI_API_KEY \ -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \ -v "$(pwd)/config.yaml:/etc/llm-proxy/config.yaml:ro" \ llm-proxy:dev ``` ## 阶段 1 范围 - `POST /v1/chat/completions`(同步 + SSE 流式) - `GET /healthz` - 两家厂商:OpenAI、Anthropic - 静态 API Key 鉴权(配置文件) - 结构化 JSON 访问日志 阶段 1 **不支持**:tool calling、限流、计费、多租户、配置热重载、Prometheus。 ## 阶段 2:限流 + 可观测性 阶段 2 在阶段 1 之上叠加:Redis 后端的多维限流(key × model,RPM + TPM 滑动窗口)、Prometheus `/metrics` 端点、访问日志补全 token / 上游耗时 / 剩余额度字段。所有规则仍走 YAML(无 MySQL)。 ### 配置 ```yaml redis: url: "${REDIS_URL}" # e.g. redis://redis:6379 key_prefix: "llm-proxy:prod:" # 可选,多套环境共享 Redis 时用 metrics: enabled: true path: "/metrics" rate_limits: # 第一条命中的生效;exact model 永远比 wildcard 优先(与声明顺序无关)。 - match: { key: "team-a", model: "anthropic/*" } rpm: 60 tpm: 100000 - match: { key: "team-a", model: "anthropic/claude-sonnet-4-5" } rpm: 10 ``` 规则按 `(client_key_name, model)` 索引。`model` 接受精确公开名(`anthropic/claude-sonnet-4-5`)或厂商通配(`anthropic/*`)。未命中任何规则 = 不限流。 ### 响应头 成功且命中规则的请求会带上 OpenAI 风格的额度头: ``` x-ratelimit-limit-requests: 60 x-ratelimit-remaining-requests: 47 x-ratelimit-reset-requests: 23 x-ratelimit-limit-tokens: 100000 x-ratelimit-remaining-tokens: 41200 x-ratelimit-reset-tokens: 41 ``` 超额请求返回 `429 Too Many Requests`,响应体: ```json {"error":{"message":"rate limit exceeded","type":"rate_limit_error","code":"rate_limited"}} ``` 并附加 `Retry-After: <秒>`。 ### Prometheus 指标 `/metrics` 在 `metrics.enabled: true` 时挂载(无鉴权): | 名称 | 类型 | 标签 | |---|---|---| | `proxy_requests_total` | counter | `provider`, `model`, `status` | | `proxy_request_duration_seconds` | histogram | `provider`, `model` | | `proxy_upstream_duration_seconds` | histogram | `provider` | | `proxy_tokens_total` | counter | `provider`, `model`, `kind`(`prompt`/`completion`) | | `proxy_ratelimit_rejected_total` | counter | `key_name`, `model` | | `proxy_ratelimit_unavailable_total` | counter | — | 请求 / 响应正文永不出现在 label 中。 ### fail-open Redis 不可达时,日志记 `WARN`,`proxy_ratelimit_unavailable_total` 加 1,请求**继续放行**。阶段 2 没有 fail-closed 开关(YAGNI)。 ### 本地运行 ```bash docker run --rm -p 6379:6379 redis:7-alpine & REDIS_URL=redis://127.0.0.1:6379 cargo run -- --config ./config.yaml ``` ### 集成测试 依赖 Redis 的测试一律 `#[ignore]`,确保默认 `cargo test` 在无 Docker 环境下绿色。需 Redis 的跑: ```bash cargo test -- --ignored ``` 要求 Docker Desktop 正在运行。 ## 开发 ```bash cargo test # 全部单元 + 集成测试(不含 #[ignore]) cargo test -- --ignored # 需要 Docker:Redis-backed 集成测试 cargo run -- --help # CLI 帮助 ```