pierobruncoronado/semantic-llm-gateway

GitHub: pierobruncoronado/semantic-llm-gateway

位于 LLM 应用与 Anthropic API 之间的语义缓存网关,通过 embedding 相似度匹配复用响应来优化延迟与成本,并附带注入过滤及防滥用机制。

Stars: 0 | Forks: 0

# 语义 LLM Gateway 一个位于基于 LLM 的应用与 Anthropic API 之间的边界层。它是 Anthropic endpoint 的直接替代方案——只需将现有 client 的 base URL 指向此处,其余一切如常。它增加了 **语义缓存**(对 prompt 进行 embedding,在余弦相似度命中时直接提供缓存的响应,而不是再次调用模型)、**调用前 prompt 注入过滤器**、**防滥用防御**(速率限制、payload 上限、输入截断)以及一个 `/metrics` endpoint——所有这些都配备了真实的测量数据,而非估算值。 ## 为什么是语义匹配,而不是精确匹配 基于精确字符串匹配的缓存会漏掉每一个复述。基于 embedding 相似度的缓存能捕获复述——但余弦相似度**无法**可靠地将“意图相同,措辞不同”与“意图不同,表面形式相似”区分开来。人工设定的阈值可能会在 prompt *看起来*像之前的某个 prompt、但实际含义不同时,静默地提供错误的缓存答案(误报)——例如,“列出我们仓库里**确实**有的东西”与“列出我们**没有**的东西”。 本项目将相似度阈值视为系统的核心校准参数——而非简单的默认值。`CACHE_SIMILARITY_THRESHOLD=0.90` 是通过一次包含 23 对数据的黄金数据集扫描(`scripts/threshold_eval.py`)确定的,该扫描将误报率作为北极星指标进行衡量,而非原始命中率。完整的扫描表、不可避免的交叉重叠发现(一对使用相同模板但意图相反的查询得分*高于*一对真正的跨语言复述),以及在 `0.90` 处接受的权衡,都记录在 [`docs/DECISIONS.md`](docs/DECISIONS.md)("Día 7")中。 ## 架构 ``` Client (e.g. a clinic's WhatsApp agent) │ POST /v1/messages (same shape as the Anthropic API) ▼ ┌───────────────────────────────────────────────────────────┐ │ Gateway pipeline │ │ │ │ 1. payload cap (413 if body too large) │ │ 2. rate limit per bucket (x-api-key, fallback to IP) │ │ 3. input truncation (long messages clipped, not rejected) │ │ 4. injection filter (known patterns → 400, hard reject) │ │ 5. embed prompt (Voyage) → query Upstash Vector │ │ score >= 0.90 ──► serve cached response (no LLM call) │ │ score < 0.90 ──► call Anthropic, cache the response │ └───────────────────────────────────────────────────────────┘ │ ▼ Anthropic API (model is caller-specified; Haiku is the default for cheap upstream) ``` 如果 Upstash Vector 或 embedding 调用失败,gateway 会降级为直接透传给 Anthropic,而不会崩溃——缓存是一种优化,而非保证正确性的依赖项。 `Provider`(`app/providers/base.py`)是一个为支持多个 provider 而准备的抽象层;在 v1 版本中仅实现了 Anthropic 适配器——请参阅 [`docs/spec.md`](docs/spec.md) 了解明确超出范围的内容(多 provider、路由/故障转移、身份验证/虚拟密钥、仪表板 UI、流式传输)。 ## 本地设置 — 克隆 → 运行不到 10 分钟 **前置条件:** Python 3.11+,一个 [Anthropic API key](https://console.anthropic.com),一个 [Upstash Vector](https://upstash.com) index(余弦相似度),以及一个 [Voyage AI](https://www.voyageai.com) API key。 ``` git clone https://github.com/pierobruncoronado/semantic-llm-gateway.git cd semantic-llm-gateway python -m venv .venv .venv\Scripts\activate # Windows # source .venv/bin/activate # macOS/Linux pip install -r requirements.txt cp .env.example .env # 填写: ANTHROPIC_API_KEY, UPSTASH_VECTOR_REST_URL, UPSTASH_VECTOR_REST_TOKEN, VOYAGE_API_KEY uvicorn app.main:app --reload ``` ``` # 健康检查 curl http://localhost:8000/health # 真实请求 — 首次调用 passthrough,第二次 cache-hit curl -X POST http://localhost:8000/v1/messages \ -H "Content-Type: application/json" \ -d '{"model":"claude-haiku-4-5-20251001","max_tokens":32,"messages":[{"role":"user","content":"What is the boiling point of water in Celsius?"}]}' # 聚合指标 curl http://localhost:8000/metrics ``` ### 环境变量 | 变量 | 必需 | 描述 | |----------|----------|-------------| | `ANTHROPIC_API_KEY` | **是** | 上游模型调用。 | | `UPSTASH_VECTOR_REST_URL` | **是** | 语义缓存存储(余弦 index)。 | | `UPSTASH_VECTOR_REST_TOKEN` | **是** | Upstash Vector REST 身份验证 token。 | | `VOYAGE_API_KEY` | **是** | 用于缓存的 embedding(`voyage-3.5`,1024 维)。 | | `DEFAULT_MODEL` | 否(默认为 `claude-haiku-4-5-20251001`) | 在调用方省略 `model` 时使用。 | | `CACHE_SIMILARITY_THRESHOLD` | 否(默认为 `0.90`) | 已校准——修改前请参阅上文的“为什么是语义匹配,而不是精确匹配”。 | | `RATE_LIMIT_MAX_REQUESTS` / `RATE_LIMIT_WINDOW_SECONDS` | 否(默认为 `60`/`60`) | 每个桶的滑动窗口速率限制。 | | `MAX_MESSAGE_CHARS` | 否(默认为 `8000`) | 单条消息截断上限。 | | `MAX_PAYLOAD_BYTES` | 否(默认为 `262144`) | 整个请求的大小上限(超过此值将返回 414)。 | ## 部署到 Render(7x24 小时运行,无需笔记本电脑) 此仓库附带一个 `Dockerfile` 和 `render.yaml`(Render Blueprint IaC)——Render 的 GitHub 部署会自动检测 Dockerfile,无需配置 buildpack。 1. 将此仓库推送到 GitHub(已在 `origin` 中设置,参见 `git remote -v`)。 2. 在 [Render dashboard](https://render.com) 中:**New → Web Service** → 连接 `semantic-llm-gateway` 仓库 → runtime 选择 **Docker**,plan 选择 **Free**。 3. 在 **Environment** 下,添加上表中的 4 个必需密钥 (`ANTHROPIC_API_KEY`, `UPSTASH_VECTOR_REST_URL`, `UPSTASH_VECTOR_REST_TOKEN`, `VOYAGE_API_KEY`)。**不要**添加 `PORT` 变量——Render 会自动注入它,并且 Dockerfile 的 `CMD` 会在容器启动时读取它。 4. 部署。`render.yaml` 的 `healthCheckPath: /health` 会在路由流量之前确认容器是否已启动。仅更新 env vars **不会**触发重新部署——请使用 `render deploys create --confirm --wait` 强制进行部署。 5. 部署完成后,根据 Render 分配的公共 URL 验证 (`https://.onrender.com`): ``` curl https://.onrender.com/health curl https://.onrender.com/metrics curl -X POST https://.onrender.com/v1/messages \ -H "Content-Type: application/json" \ -d '{"model":"claude-haiku-4-5-20251001","max_tokens":32,"messages":[{"role":"user","content":"Say pong and nothing else."}]}' ``` 在笔记本电脑关闭/关机状态下,这三个请求都返回 200 确认了验收标准 ("desplegado en cloud, responde con la laptop apagada")。Free tier 会在空闲 15 分钟后将服务置于休眠状态;此后的第一次请求需要 30-60 秒才能唤醒它。 **这里没有 Postgres session-pooler 的陷阱:** 与基于 Supabase 的兄弟项目(clinic、Analyst)不同,这里的缓存存储是 **Upstash Vector**,一个 REST/HTTPS 服务——没有数据库连接池,没有 IPv4/IPv6 的区分,也没有会弄错的 prepared-statement 模式。 ## 演示 client:clinic [`whatsapp-clinic-agent`](https://github.com/pierobruncoronado/whatsapp-clinic-agent) 项目将其上游的 Anthropic URL 指向此 gateway 的 `/v1/messages`——因为 gateway 完美映射了 Anthropic 的请求/响应格式,clinic 端无需修改任何代码。 ## 技术栈 Python · [FastAPI](https://fastapi.tiangolo.com) · [Anthropic SDK](https://github.com/anthropics/anthropic-sdk-python) · [Upstash Vector](https://upstash.com/docs/vector)(余弦相似度 index) · [Voyage AI](https://www.voyageai.com)(`voyage-3.5` embedding) · [Render](https://render.com)(Docker 部署) ## 文档 - [`docs/spec.md`](docs/spec.md) — 完整规范(事实来源、验收标准) - [`docs/DECISIONS.md`](docs/DECISIONS.md) — 决策日志:内容/原因/方式、真实运行证据、注意事项
标签:AI安全防护, Anthropic API, API网关, DLL 劫持, 大语言模型, 提示词注入防御, 语义缓存, 请求拦截, 逆向工具