Skip to content

Commit 389af54

Browse files
committed
Feat: 支持配置OpenAI/Anthropic api 与litellm的prompt cache
1 parent 614b07d commit 389af54

30 files changed

Lines changed: 3264 additions & 146 deletions

docs/mkdocs/en/model.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Models in tRPC-Agent have the following core features:
99
- **Multi-protocol support**: Provides OpenAIModel, AnthropicModel, LiteLLMModel, etc., compatible with most OpenAI-like and Anthropic interfaces both internally and externally
1010
- **Streaming response support**: Supports streaming output for real-time interactive experiences
1111
- **Multimodal capabilities**: Supports multimodal content processing including text, images, etc. (e.g., Hunyuan multimodal models)
12+
- **Prompt Cache support**: Provides unified prompt cache configuration across OpenAI, Anthropic, and LiteLLM routes to reduce repeated input cost for long prompts and multi-turn conversations
1213
- **Extensible configuration**: Supports custom configuration options such as GenerateContentConfig, HttpOptions, client_args to meet various scenario requirements
1314

1415
## Quick Start
@@ -398,6 +399,120 @@ LlmAgent(
398399
)
399400
```
400401

402+
### Prompt Cache
403+
404+
Prompt Cache is useful when system prompts are long, tool definitions are large, or multi-turn conversations share a stable prefix. Many providers, including OpenAI-compatible serving stacks such as `openai/sglang`, already support automatic prefix caching on the server side. `tRPC-Agent` does not replace the provider's cache implementation; instead, it provides unified management hints and normalized observability for prompt cache behavior.
405+
406+
`tRPC-Agent` exposes these capabilities through `PromptCacheConfig`, which currently applies to `OpenAIModel`, `AnthropicModel`, and provider-prefixed `LiteLLMModel`. Because providers expose different cache controls and usage fields, the SDK maps management options and cache usage metrics to each provider protocol on a best-effort basis:
407+
408+
| Provider | SDK Capability | Typical Usage Fields |
409+
|----------|----------------|----------------------|
410+
| Anthropic | Manages explicit `cache_control` breakpoints according to `breakpoints` | `cache_read_input_tokens`, `cache_creation_input_tokens` |
411+
| OpenAI / OpenAI-compatible endpoints | Passes cache hints such as `prompt_cache_key` / `prompt_cache_retention` when supported; provider-side automatic prefix caching still owns cache creation and lookup | Usually only `cache_read_input_tokens` |
412+
| LiteLLM | Chooses the Anthropic-style or OpenAI-style cache management path according to the `provider/model` prefix, while preserving provider-native automatic caching such as `openai/sglang` | Depends on the final provider route |
413+
414+
#### Model-level configuration
415+
416+
Model-level configuration becomes the default prompt-cache management and observability configuration for the model instance. Use it when all requests can share the same cache hints:
417+
418+
```python
419+
from trpc_agent_sdk.configs import PromptCacheConfig
420+
from trpc_agent_sdk.models import OpenAIModel
421+
422+
model = OpenAIModel(
423+
model_name="gpt-4o",
424+
api_key="your-api-key",
425+
prompt_cache_config=PromptCacheConfig(
426+
enabled=True,
427+
ttl="24h",
428+
prompt_cache_key="weather-concierge-v1",
429+
),
430+
)
431+
```
432+
433+
#### Per-run override
434+
435+
You can also override prompt-cache settings for a single `runner.run_async()` call through `RunConfig.prompt_cache`. The per-run config overrides model-level settings field by field, which is useful when setting different cache hints by user, tenant, or business scenario:
436+
437+
```python
438+
from trpc_agent_sdk.configs import PromptCacheConfig
439+
from trpc_agent_sdk.configs import RunConfig
440+
441+
async for event in runner.run_async(
442+
user_id=user_id,
443+
session_id=session_id,
444+
new_message=user_content,
445+
run_config=RunConfig(
446+
prompt_cache=PromptCacheConfig(
447+
enabled=True,
448+
prompt_cache_key="weather-concierge-user-42",
449+
),
450+
),
451+
):
452+
...
453+
```
454+
455+
#### Anthropic breakpoints
456+
457+
Anthropic-style caching requires selecting breakpoint locations. `breakpoints` supports the following values:
458+
459+
- `"system"`: cache the system prompt, suitable for long instructions
460+
- `"tools"`: cache the last tool definition, suitable when tools are numerous or tool schemas are large
461+
- `"messages"`: cache the most recent assistant message, suitable for growing stable history prefixes in multi-turn conversations
462+
463+
```python
464+
from trpc_agent_sdk.configs import PromptCacheConfig
465+
from trpc_agent_sdk.models import AnthropicModel
466+
467+
model = AnthropicModel(
468+
model_name="claude-3-5-sonnet-20241022",
469+
api_key="your-api-key",
470+
prompt_cache_config=PromptCacheConfig(
471+
enabled=True,
472+
ttl="1h",
473+
breakpoints=["tools", "system", "messages"],
474+
),
475+
)
476+
```
477+
478+
A good starting point is `["tools", "system"]`; add `"messages"` when long multi-turn conversations need to cache a growing history prefix. Some Anthropic proxies or Bedrock routes require a minimum cache block size, so short prompts may not create cache entries.
479+
480+
#### LiteLLM routes
481+
482+
When using `LiteLLMModel`, the model name should include a `provider/model` prefix. The SDK uses that provider prefix to select the appropriate cache-management mapping. For example:
483+
484+
```python
485+
from trpc_agent_sdk.configs import PromptCacheConfig
486+
from trpc_agent_sdk.models import LiteLLMModel
487+
488+
model = LiteLLMModel(
489+
model_name="openai/gpt-4o",
490+
api_key="your-api-key",
491+
prompt_cache_config=PromptCacheConfig(
492+
enabled=True,
493+
prompt_cache_key="shared-prefix-v1",
494+
),
495+
)
496+
```
497+
498+
If the model name does not include a provider prefix, the SDK cannot determine which cache-management protocol to use, so SDK-managed cache hints may not take effect.
499+
500+
#### Reading cache usage
501+
502+
The model response's `usage_metadata` normalizes cache usage fields where possible:
503+
504+
```python
505+
async for event in runner.run_async(...):
506+
usage = getattr(event, "usage_metadata", None)
507+
if usage:
508+
print(usage.cache_read_input_tokens) # Input tokens read from cache
509+
print(usage.cache_creation_input_tokens) # Input tokens written to cache, usually only reported by Anthropic
510+
print(usage.prompt_token_count) # Total input tokens
511+
```
512+
513+
Different model services report different fields. OpenAI-compatible endpoints usually report cache reads but not cache writes. With load-balanced proxies, each backend instance may have its own KV cache and may not be warmed up at the same time, so cache hit rates can fluctuate during the first few runs.
514+
515+
For a complete runnable example, see [examples/llmagent_with_prompt_cache](../../../examples/llmagent_with_prompt_cache/README.md).
401516

402517
### Custom HTTP Headers
403518

docs/mkdocs/zh/model.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ tRPC-Agent 内的模型具有以下核心特性:
99
- **多协议支持**:提供 OpenAIModel、AnthropicModel、LiteLLMModel 等,兼容公司内外多数 OpenAI-like 及 Anthropic 接口
1010
- **流式响应支持**:支持流式输出,实现实时交互体验
1111
- **多模态能力**:支持文本、图像等多模态内容处理(如 hunyuan 多模态模型)
12+
- **Prompt Cache 支持**:支持跨 OpenAI、Anthropic 与 LiteLLM 路由的统一 prompt cache 配置,降低长提示词和多轮会话的重复输入成本
1213
- **可扩展配置**:支持 GenerateContentConfig、HttpOptions、client_args 等自定义配置项,满足不同场景需求
1314

1415
## 快速上手
@@ -398,6 +399,120 @@ LlmAgent(
398399
)
399400
```
400401

402+
### Prompt Cache
403+
404+
Prompt Cache 适用于系统提示词较长、工具定义较多或多轮会话前缀高度稳定的场景。很多 provider(包括 `openai/sglang` 这类 OpenAI 兼容推理服务)本身已经支持服务端自动前缀缓存。`tRPC-Agent` 并不替代 provider 的缓存实现,而是提供统一的缓存管理提示与缓存观测能力。
405+
406+
`tRPC-Agent` 通过 `PromptCacheConfig` 暴露这些能力,目前可用于 `OpenAIModel``AnthropicModel` 以及带 provider 前缀的 `LiteLLMModel`。不同供应商对缓存控制和统计字段的支持不完全相同,SDK 会尽量将管理选项和缓存用量指标映射到对应协议:
407+
408+
| Provider | SDK 能力 | 典型统计字段 |
409+
|----------|----------|--------------|
410+
| Anthropic | 根据 `breakpoints` 管理显式 `cache_control` 断点 | `cache_read_input_tokens``cache_creation_input_tokens` |
411+
| OpenAI / OpenAI 兼容端点 | 在支持时传递 `prompt_cache_key` / `prompt_cache_retention` 等缓存提示;缓存创建和命中仍由 provider 侧自动前缀缓存负责 | 通常只有 `cache_read_input_tokens` |
412+
| LiteLLM | 根据 `provider/model` 前缀选择 Anthropic 风格或 OpenAI 风格的缓存管理路径 | 取决于最终路由的 provider |
413+
414+
#### 模型级配置
415+
416+
模型级配置会作为该模型实例默认的 prompt cache 管理与观测配置,适合在所有请求中复用同一套缓存提示:
417+
418+
```python
419+
from trpc_agent_sdk.configs import PromptCacheConfig
420+
from trpc_agent_sdk.models import OpenAIModel
421+
422+
model = OpenAIModel(
423+
model_name="gpt-4o",
424+
api_key="your-api-key",
425+
prompt_cache_config=PromptCacheConfig(
426+
enabled=True,
427+
ttl="24h",
428+
prompt_cache_key="weather-concierge-v1",
429+
),
430+
)
431+
```
432+
433+
#### 单次运行覆盖
434+
435+
也可以通过 `RunConfig.prompt_cache` 对单次 `runner.run_async()` 覆盖 prompt cache 配置。单次运行配置会按字段覆盖模型级配置,适合按用户、租户或业务场景设置不同的缓存提示:
436+
437+
```python
438+
from trpc_agent_sdk.configs import PromptCacheConfig
439+
from trpc_agent_sdk.configs import RunConfig
440+
441+
async for event in runner.run_async(
442+
user_id=user_id,
443+
session_id=session_id,
444+
new_message=user_content,
445+
run_config=RunConfig(
446+
prompt_cache=PromptCacheConfig(
447+
enabled=True,
448+
prompt_cache_key="weather-concierge-user-42",
449+
),
450+
),
451+
):
452+
...
453+
```
454+
455+
#### Anthropic 断点配置
456+
457+
Anthropic 风格的缓存需要选择断点位置。`breakpoints` 支持以下值:
458+
459+
- `"system"`:缓存系统提示词,适合长 instruction 场景
460+
- `"tools"`:缓存最后一个工具定义,适合工具较多或工具 schema 较大的场景
461+
- `"messages"`:缓存最近一条 assistant 消息,适合多轮会话中不断增长的稳定历史前缀
462+
463+
```python
464+
from trpc_agent_sdk.configs import PromptCacheConfig
465+
from trpc_agent_sdk.models import AnthropicModel
466+
467+
model = AnthropicModel(
468+
model_name="claude-3-5-sonnet-20241022",
469+
api_key="your-api-key",
470+
prompt_cache_config=PromptCacheConfig(
471+
enabled=True,
472+
ttl="1h",
473+
breakpoints=["tools", "system", "messages"],
474+
),
475+
)
476+
```
477+
478+
建议从 `["tools", "system"]` 开始;当长多轮会话需要缓存不断增长的历史前缀时,再加入 `"messages"`。部分 Anthropic 代理或 Bedrock 路由对最小缓存块大小有要求,如果提示词过短,可能不会产生缓存写入。
479+
480+
#### LiteLLM 路由
481+
482+
使用 `LiteLLMModel` 时,模型名需要带 `provider/model` 前缀。SDK 会根据 provider 前缀选择对应的缓存管理映射,例如:
483+
484+
```python
485+
from trpc_agent_sdk.configs import PromptCacheConfig
486+
from trpc_agent_sdk.models import LiteLLMModel
487+
488+
model = LiteLLMModel(
489+
model_name="openai/gpt-4o",
490+
api_key="your-api-key",
491+
prompt_cache_config=PromptCacheConfig(
492+
enabled=True,
493+
prompt_cache_key="shared-prefix-v1",
494+
),
495+
)
496+
```
497+
498+
如果模型名缺少 provider 前缀,SDK 无法判断应使用哪类缓存管理协议,因此 SDK 管理的缓存提示可能不会生效。
499+
500+
#### 读取缓存统计
501+
502+
模型响应的 `usage_metadata` 中会尽量归一化缓存统计字段:
503+
504+
```python
505+
async for event in runner.run_async(...):
506+
usage = getattr(event, "usage_metadata", None)
507+
if usage:
508+
print(usage.cache_read_input_tokens) # 从缓存读取的输入 token 数
509+
print(usage.cache_creation_input_tokens) # 写入缓存的输入 token 数,通常仅 Anthropic 上报
510+
print(usage.prompt_token_count) # 总输入 token 数
511+
```
512+
513+
不同模型服务上报的字段并不完全一致。OpenAI 兼容端点通常只上报缓存读取,不上报缓存写入;负载均衡代理场景下,不同后端实例的 KV 缓存可能尚未全部预热,因此命中率可能在前几次运行中波动。
514+
515+
完整可运行示例见 [examples/llmagent_with_prompt_cache](../../../examples/llmagent_with_prompt_cache/README.md)
401516

402517
### 自定义 HTTP Header
403518

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Set TRPC_AGENT_API_KEY、TRPC_AGENT_BASE_URL、TRPC_AGENT_MODEL_NAME
2+
TRPC_AGENT_API_KEY=your-api-key
3+
TRPC_AGENT_BASE_URL=your-base-url
4+
TRPC_AGENT_MODEL_NAME=your-model-name
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Prompt Cache 示例
2+
3+
本示例演示如何在 OpenAI、Anthropic 上,以及其他经 LiteLLM 接入的兼容端点上,使用 SDK 统一的 prompt cache。
4+
所有场景使用同一个「天气管家」Agent,区别仅在于所选的模型类和缓存配置。
5+
6+
运行这个例子后,在支持 prompt cache 的 API 上,期望能够看到较高的 prompt cache 命中率,以及随轮次增长的 TTFT 改善(Turn 2 起缓存命中后响应明显变快)。本示例中的 TTFT 指从请求开始到第一个有效生成 token 出现的耗时;无论该 token 属于普通 message 还是 tool call 都计入。
7+
8+
---
9+
10+
## 目录结构
11+
12+
```
13+
llmagent_with_prompt_cache/
14+
├── agent/
15+
│ ├── agent.py ← 三个工厂函数 + 自动探测 helper
16+
│ ├── config.py ← 环境变量 helper
17+
│ ├── prompts.py ← 长系统提示词(约 4 900 token)
18+
│ └── tools.py ← 模拟天气工具
19+
20+
├── run_agent.py ← 根据环境变量自动探测 provider 并运行 demo 循环
21+
22+
└── .env ← 环境变量配置(三个 provider 均在此注释分段)
23+
```
24+
25+
---
26+
27+
## 环境与运行
28+
29+
### 环境要求
30+
31+
- Python 3.12
32+
33+
### 安装步骤
34+
35+
```bash
36+
git clone https://github.com/trpc-group/trpc-agent-python.git
37+
cd trpc-agent-python
38+
python3 -m venv .venv
39+
source .venv/bin/activate
40+
pip3 install -e .
41+
```
42+
43+
### 环境变量要求
44+
45+
[examples/llmagent_with_prompt_cache/.env](./.env) 中填入凭证:
46+
47+
- `TRPC_AGENT_API_KEY`
48+
- `TRPC_AGENT_BASE_URL`
49+
- `TRPC_AGENT_MODEL_NAME`
50+
51+
### 运行命令
52+
53+
```bash
54+
cd examples/llmagent_with_prompt_cache
55+
python3 run_agent.py # 根据 .env 的模型名字自动选择 provider
56+
```
57+
58+
---
59+
60+
## FQA
61+
### 缓存命中不稳定(命中后又未命中又命中)
62+
63+
在负载均衡的代理部署下属于正常现象。每个后端实例都有独立的 KV 缓存。无论其他实例
64+
预热了多少,落到冷实例上的请求总会显示未命中。把脚本多跑几次即可提高命中率。
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Tencent is pleased to support the open source community by making tRPC-Agent-Python available.
2+
#
3+
# Copyright (C) 2026 Tencent. All rights reserved.
4+
#
5+
# tRPC-Agent-Python is licensed under Apache-2.0.

0 commit comments

Comments
 (0)