计划执行与检查节点
executing-plans
按既定实施计划完成工作,保持过程检查和反馈。
llm-gateway【效率与协作】LLM gateways in front of RAG stacks. Covers Portkey (caching, fallbacks, retries, observability), OpenRouter (300+ model routing), LiteLLM Proxy, Kong AI Gateway, semantic caching at gateway layer, cost-based routing (cheap model for easy queries), rate-limit handling, and unified API across providers. Config examples. USE WHEN: user mentions "LLM g…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: llm-gateway disable-model-invocation: true description: | LLM gateways in front of RAG stacks. Covers Portkey (caching, fallbacks, retries, observability), OpenRouter (300+ model routing), LiteLLM Proxy, Kong AI Gateway, semantic caching at gateway layer, cost-based routing (cheap model for easy queries), rate-limit handling, and unified API across providers. Config examples.
USE WHEN: user mentions "LLM gateway", "Portkey", "OpenRouter", "LiteLLM", "Kong AI Gateway", "AI gateway", "semantic cache gateway", "provider fallback", "unified LLM API"
rag-caching;
multi-region routing - use multi-region;
cost tracking/dashboarding - use cost-allocation
allowed-tools: Read, Grep, Glob, Write, EditAn LLM gateway sits between your RAG app and the provider APIs. It gives you: provider-agnostic API, retries + fallbacks, rate-limit smoothing, semantic + exact cache, cost-based routing, observability. For any RAG stack running in production, a gateway eliminates a class of 3 AM pages and shaves 20–60% off provider spend.
| Gateway | Strengths | Notes |
|---|---|---|
| Portkey | Prod-grade: cache, fallbacks, retries, load balancing, guardrails, virtual keys, analytics, OSS core + cloud | Most feature-complete; OpenAI-compatible |
| OpenRouter | 300+ models, pay-as-you-go across many providers, cheap routing | Hosted only; simple REST |
| LiteLLM Proxy | Self-hosted, OpenAI-compatible, routing, budgets, teams, LangSmith integration | Python; easy to deploy |
| Kong AI Gateway | Plugs into Kong; AI-specific plugins for rate-limit, transform, cache | Best if you already run Kong |
| Helicone | Observability-first, one-line integration, caching | Less heavyweight than Portkey |
| Cloudflare AI Gateway | Global edge, caching, rate-limit, analytics | Cloudflare ecosystem |
from portkey_ai import Portkey
pk = Portkey(
api_key=PORTKEY_API_KEY,
config="pc-rag-prod-abc123", # Portkey Config ID
virtual_key="anthropic-prod-key",
metadata={"tenant_id": tenant_id, "feature": "qa_chat"},
)
resp = pk.chat.completions.create(
model="claude-sonnet-4-5",
messages=[...],
)
{
"strategy": { "mode": "fallback" },
"targets": [
{
"provider": "anthropic",
"virtual_key": "anthropic-prod",
"override_params": {"model": "claude-sonnet-4-5"},
"retry": {"attempts": 2, "on_status_codes": [429, 500, 502, 503, 504]}
},
{
"provider": "openai",
"virtual_key": "openai-prod",
"override_params": {"model": "gpt-4o"}
}
],
"cache": { "mode": "semantic", "max_age": 3600 },
"request_timeout": 30000
}
{
"strategy": { "mode": "loadbalance" },
"targets": [
{"weight": 0.7, "provider": "anthropic", "override_params": {"model": "claude-haiku-4-5"}},
{"weight": 0.3, "provider": "openai", "override_params": {"model": "gpt-4o-mini"}}
]
}
Use conditional strategy to route by query complexity (simple → cheap, complex → Sonnet/Opus).
from openai import OpenAI
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=OPENROUTER_KEY)
resp = client.chat.completions.create(
model="anthropic/claude-sonnet-4-5",
messages=[{"role": "user", "content": "..."}],
extra_headers={"HTTP-Referer": "https://myapp.com", "X-Title": "RAG QA"},
)
Auto-routing by free-form target:
resp = client.chat.completions.create(
model="openrouter/auto", # OR picks the best-priced working model
messages=[...],
)
Transforms: :floor (cheapest that meets context), :nitro (fastest provider for the model), :free (route to free providers first with fallback).
# config.yaml
model_list:
- model_name: claude-sonnet
litellm_params:
model: anthropic/claude-sonnet-4-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: claude-sonnet
litellm_params:
model: bedrock/anthropic.claude-sonnet-4-5-20250514-v1:0
aws_region_name: us-east-1
- model_name: gpt-4o
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY
router_settings:
routing_strategy: simple-shuffle # or least-busy, usage-based
num_retries: 3
timeout: 30
fallbacks:
- {"claude-sonnet": ["gpt-4o"]}
cooldown_time: 60
general_settings:
master_key: sk-...
database_url: "postgresql://..."
enable_cache: true
cache_params:
type: redis
host: redis
Launch:
litellm --config config.yaml --port 4000
App sees LiteLLM as an OpenAI endpoint:
client = OpenAI(base_url="http://litellm:4000", api_key="sk-team-...")
client.chat.completions.create(model="claude-sonnet", messages=[...])
Per-team virtual keys + budgets are core LiteLLM features — create keys via admin API, each with max_budget and model_list.
Add AI plugins to a Kong route:
plugins:
- name: ai-proxy
config:
provider: anthropic
model:
name: claude-sonnet-4-5
provider: anthropic
auth:
header_name: x-api-key
header_value: ${ANTHROPIC_KEY}
- name: ai-semantic-cache
config:
embeddings:
provider: openai
model: text-embedding-3-small
vectordb:
provider: redis
dimensions: 1536
threshold: 0.95
exact_caching: true
- name: ai-rate-limiting-advanced
config:
limit: [100]
window_size: [60]
identifier: header
header_name: x-tenant-id
Deployable on existing Kong clusters — no new infra if Kong is already in the path.
Two levels:
Hit-rate / risk knobs:
threshold 0.97 -> ~15% hit, ~1% wrong answer on ambiguous queries
threshold 0.93 -> ~30% hit, higher risk; restrict to low-stakes features
Only enable semantic cache on idempotent, time-insensitive features (FAQ bots, docs search). Keep it off for anything operating on fresh data or where answers must be personalized to context.
Invalidation: bump the semantic cache version when re-indexing or swapping embedding models; old cached responses reference stale ground truth.
Route by estimated complexity; Portkey and LiteLLM both support conditional routing.
def route(messages):
n = sum(len(m["content"]) for m in messages)
if n < 2000 and all(m["role"] != "tool" for m in messages):
return "haiku" # cheap path
return "sonnet" # default
Or use a classifier (distilled model or BERT) to predict hard queries and route to Opus/GPT-4o for those.
Provider-side 429s should rarely reach your app — the gateway handles:
Retry-After).Tenant bucket pattern (LiteLLM):
general_settings:
max_parallel_requests: 100
max_tokens_per_minute: 1_000_000
tpm_limit: {"team-acme": 100_000, "team-beta": 500_000}
Gateways expose the OpenAI chat/embeddings schema regardless of upstream. Benefits:
openai client or httpx).Caveat: advanced provider features (Anthropic tool-use shape, OpenAI function-calling nuances, thinking mode) may require gateway-specific passthrough. Check the gateway's feature matrix.
Gateways emit one span per request with: tenant, model, tokens in/out, cost, cache hit/miss, retries, final provider. Export to LangSmith, Langfuse, Datadog, or OTel collectors. This is cheaper than instrumenting each call site.
| Anti-Pattern | Fix |
|---|---|
| App calling providers directly | Route through a single gateway for cache + fallback + observability |
| Cache enabled on personalized answers | Key cache on tenant_id + user_id or disable for that route |
| Semantic cache threshold too loose (<0.9) | Raise threshold; off-limits for high-stakes features |
| Same API key per tenant inside provider | Virtual keys with per-tenant budget + scope |
| Fallback to a structurally different model with no prompt adaptation | Add a prompt router per target model |
| Retrying 4xx (bad request) | Retry only 429/5xx |
| Unbounded gateway timeout | Enforce request_timeout; fail fast |