mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-16 23:41:43 +00:00
fix(ui): clarify response cache vs provider prompt caching in logs and caching dashboard
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
212a9213c4
commit
1224ad9b0c
7 changed files with 102 additions and 16 deletions
|
|
@ -2207,7 +2207,7 @@
|
|||
},
|
||||
"src/components/view_logs/LogDetailsDrawer/LogDetailContent.tsx": {
|
||||
"no-nested-ternary": {
|
||||
"count": 4
|
||||
"count": 3
|
||||
}
|
||||
},
|
||||
"src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.tsx": {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,13 @@ describe("CacheDashboard cache analytics charts", () => {
|
|||
adminGlobalCacheActivity.mockResolvedValue(cacheActivity);
|
||||
});
|
||||
|
||||
it("labels the dashboard as response caching and distinguishes it from prompt caching", async () => {
|
||||
renderDashboard();
|
||||
|
||||
expect(await screen.findByRole("heading", { name: "Response Caching" })).toBeInTheDocument();
|
||||
expect(screen.getByText(/separate from provider prompt caching/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders both chart card titles", async () => {
|
||||
renderDashboard();
|
||||
|
||||
|
|
|
|||
|
|
@ -260,6 +260,16 @@ const CacheDashboard: React.FC<CachePageProps> = ({ accessToken, token, userRole
|
|||
|
||||
return (
|
||||
<TabGroup className="gap-2 p-8 h-full w-full mt-2 mb-8">
|
||||
<div className="mb-2">
|
||||
<h1 className="text-2xl font-semibold text-tremor-content-strong dark:text-dark-tremor-content-strong">
|
||||
Response Caching
|
||||
</h1>
|
||||
<Text className="mt-1">
|
||||
Analytics and settings for LiteLLM's response cache, which returns a stored response for repeated
|
||||
requests instead of calling the provider again. This is separate from provider prompt caching; prompt caching
|
||||
is configured under Settings and its per-request activity shows up as prompt cache tokens on the Logs page
|
||||
</Text>
|
||||
</div>
|
||||
<TabList className="flex justify-between mt-2 w-full items-center">
|
||||
<div className="flex">
|
||||
<Tab>Cache Analytics</Tab>
|
||||
|
|
|
|||
|
|
@ -244,7 +244,13 @@ const menuGroups: MenuGroup[] = [
|
|||
icon: <BookOpen {...ICON} />,
|
||||
external_url: "https://models.litellm.ai/cookbook",
|
||||
},
|
||||
{ key: "caching", page: "caching", label: "Caching", icon: <Database {...ICON} />, roles: all_admin_roles },
|
||||
{
|
||||
key: "caching",
|
||||
page: "caching",
|
||||
label: "Response Caching",
|
||||
icon: <Database {...ICON} />,
|
||||
roles: all_admin_roles,
|
||||
},
|
||||
{
|
||||
key: "experimental",
|
||||
page: "experimental",
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ export const pageDescriptions: Record<string, string> = {
|
|||
api_ref: "Browse API documentation and endpoints",
|
||||
"model-hub-table": "Explore available AI models and providers",
|
||||
"learning-resources": "Access tutorials and documentation",
|
||||
caching: "Configure response caching and coordination Redis settings",
|
||||
caching:
|
||||
"Configure LiteLLM response caching (exact-match / semantic) and coordination Redis settings; separate from provider prompt caching",
|
||||
"transform-request": "Set up request transformation rules",
|
||||
"cost-tracking": "Track and analyze API costs",
|
||||
"ui-theme": "Customize dashboard appearance",
|
||||
|
|
|
|||
|
|
@ -255,6 +255,8 @@ describe("LogDetailContent", () => {
|
|||
expect(screen.getByText("2 masked")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
const cacheHitTag = () => screen.getByText("Response Cache Hit").closest(".ant-descriptions-item") as HTMLElement;
|
||||
|
||||
it("should display cache hit information when cache_hit is true", () => {
|
||||
render(
|
||||
<LogDetailContent
|
||||
|
|
@ -271,12 +273,37 @@ describe("LogDetailContent", () => {
|
|||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Cache Hit")).toBeInTheDocument();
|
||||
expect(screen.getByText("true")).toBeInTheDocument();
|
||||
expect(screen.getByText("Cache Read Tokens")).toBeInTheDocument();
|
||||
expect(screen.getByText("Response Cache Hit")).toBeInTheDocument();
|
||||
expect(within(cacheHitTag()).getByText("true").closest(".ant-tag")).toHaveClass("ant-tag-green");
|
||||
expect(screen.getByText("Prompt Cache Read Tokens")).toBeInTheDocument();
|
||||
expect(screen.getByText("100")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should not render a red 'false' tag when only provider prompt caching is active", () => {
|
||||
render(
|
||||
<LogDetailContent
|
||||
logEntry={createLogEntry({
|
||||
cache_hit: "false",
|
||||
metadata: {
|
||||
status: "success",
|
||||
additional_usage_values: {
|
||||
cache_read_input_tokens: 512,
|
||||
cache_creation_input_tokens: 128,
|
||||
},
|
||||
},
|
||||
})}
|
||||
/>,
|
||||
);
|
||||
|
||||
const falseTag = within(cacheHitTag()).getByText("false").closest(".ant-tag") as HTMLElement;
|
||||
expect(falseTag).not.toHaveClass("ant-tag-red");
|
||||
|
||||
expect(screen.getByText("Prompt Cache Read Tokens")).toBeInTheDocument();
|
||||
expect(screen.getByText("512")).toBeInTheDocument();
|
||||
expect(screen.getByText("Prompt Cache Creation Tokens")).toBeInTheDocument();
|
||||
expect(screen.getByText("128")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should display LiteLLM Overhead when litellm_overhead_time_ms is in metadata", () => {
|
||||
render(
|
||||
<LogDetailContent
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useState } from "react";
|
||||
import { Typography, Descriptions, Card, Tag, Tabs, Alert, Collapse, Radio, Space, Spin } from "antd";
|
||||
import { Typography, Descriptions, Card, Tag, Tabs, Alert, Collapse, Radio, Space, Spin, Tooltip } from "antd";
|
||||
import { InfoCircleOutlined } from "@ant-design/icons";
|
||||
import moment from "moment";
|
||||
import { LogEntry } from "../columns";
|
||||
import { formatNumberWithCommas } from "@/utils/dataUtils";
|
||||
|
|
@ -232,6 +233,17 @@ function ErrorDescription({ errorInfo }: { errorInfo: any }) {
|
|||
);
|
||||
}
|
||||
|
||||
function LabelWithInfo({ label, tooltip }: { label: string; tooltip: string }) {
|
||||
return (
|
||||
<Space size={4}>
|
||||
{label}
|
||||
<Tooltip title={tooltip}>
|
||||
<InfoCircleOutlined style={{ color: "#8c8c8c", cursor: "help" }} />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
||||
function TagsSection({ tags }: { tags: Record<string, any> }) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow-sm w-full max-w-full overflow-hidden p-4 mb-6">
|
||||
|
|
@ -291,8 +303,10 @@ function MetricsSection({ logEntry, metadata }: { logEntry: LogEntry; metadata:
|
|||
metadata.additional_usage_values.cache_read_input_tokens > 0);
|
||||
|
||||
const cacheHitValue = String(logEntry.cache_hit ?? "None");
|
||||
const cacheHitColor =
|
||||
cacheHitValue.toLowerCase() === "true" ? "green" : cacheHitValue.toLowerCase() === "false" ? "red" : "default";
|
||||
const cacheHitColor = cacheHitValue.toLowerCase() === "true" ? "green" : "default";
|
||||
|
||||
const cacheReadTokens = metadata?.additional_usage_values?.cache_read_input_tokens;
|
||||
const cacheCreationTokens = metadata?.additional_usage_values?.cache_creation_input_tokens;
|
||||
|
||||
const uncachedInputTokens = getUncachedInputTextTokens(metadata);
|
||||
const showAnthropicMessagesInputOutput =
|
||||
|
|
@ -328,17 +342,38 @@ function MetricsSection({ logEntry, metadata }: { logEntry: LogEntry; metadata:
|
|||
|
||||
{hasCacheActivity && (
|
||||
<>
|
||||
<Descriptions.Item label="Cache Hit">
|
||||
<Descriptions.Item
|
||||
label={
|
||||
<LabelWithInfo
|
||||
label="Response Cache Hit"
|
||||
tooltip="Whether LiteLLM served this entire response from its response cache (the exact-match or semantic cache configured under Response Caching). This is separate from provider prompt caching; a value of false does not mean prompt caching failed. Prompt caching is reflected by the Prompt Cache Read / Creation Tokens below."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Tag color={cacheHitColor}>{cacheHitValue}</Tag>
|
||||
</Descriptions.Item>
|
||||
{metadata?.additional_usage_values?.cache_read_input_tokens > 0 && (
|
||||
<Descriptions.Item label="Cache Read Tokens">
|
||||
{formatNumberWithCommas(metadata.additional_usage_values.cache_read_input_tokens)}
|
||||
{cacheReadTokens > 0 && (
|
||||
<Descriptions.Item
|
||||
label={
|
||||
<LabelWithInfo
|
||||
label="Prompt Cache Read Tokens"
|
||||
tooltip="Input tokens read from the provider's prompt cache. A non-zero value means provider prompt caching is working for this request, even when Response Cache Hit is false."
|
||||
/>
|
||||
}
|
||||
>
|
||||
{formatNumberWithCommas(cacheReadTokens)}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{metadata?.additional_usage_values?.cache_creation_input_tokens > 0 && (
|
||||
<Descriptions.Item label="Cache Creation Tokens">
|
||||
{formatNumberWithCommas(metadata.additional_usage_values.cache_creation_input_tokens)}
|
||||
{cacheCreationTokens > 0 && (
|
||||
<Descriptions.Item
|
||||
label={
|
||||
<LabelWithInfo
|
||||
label="Prompt Cache Creation Tokens"
|
||||
tooltip="Input tokens written to the provider's prompt cache on this request so that subsequent requests can read them back."
|
||||
/>
|
||||
}
|
||||
>
|
||||
{formatNumberWithCommas(cacheCreationTokens)}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
</>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue