Skip to content

Commit fbff25a

Browse files
fix(ai): 自选 provider 的追问建议改用用户自己的模型,不再落进公共缓存
条件写成 provider !== "intern" && !ZHIPU_API_KEY,线上配了 ZHIPU,于是选了 openai/gemini 并填了自己 key 的用户也走公共缓存分支,cache 里固定用 intern/glm, 用户的 key 和模型被丢掉,和注释「自定义 key 不走公共缓存」相反。
1 parent 5b3c4dc commit fbff25a

2 files changed

Lines changed: 69 additions & 7 deletions

File tree

‎app/api/suggestions/route.ts‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,20 +120,15 @@ export async function POST(req: Request) {
120120

121121
let text = "";
122122
// 判断是否可以使用缓存(如果使用了自定义 apiKey,为了防止数据交叉,不采用公用缓存)
123-
if (provider !== "intern" && !process.env.ZHIPU_API_KEY) {
123+
if (provider !== "intern") {
124124
const { text: directText } = await generateText({
125125
model,
126126
prompt,
127127
});
128128
text = directText;
129129
} else {
130130
// 确定内部用于缓存匹配的模型标识
131-
const internalModelId =
132-
provider === "intern"
133-
? process.env.ZHIPU_API_KEY
134-
? "glm"
135-
: "intern"
136-
: "intern";
131+
const internalModelId = process.env.ZHIPU_API_KEY ? "glm" : "intern";
137132
// 将缓存粒度关联到请求本身的内容上
138133
const suggestionKey = isWelcomeRequest
139134
? `welcome-${pageContext?.slug || "default"}`

‎tests/suggestions-route.test.ts‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2+
3+
const generateText = vi.fn(async () => ({ text: '["q1","q2","q3"]' }));
4+
const unstableCache = vi.fn(
5+
(fn: (...args: unknown[]) => unknown, _keys?: string[], _opts?: object) =>
6+
(...args: unknown[]) =>
7+
fn(...args),
8+
);
9+
10+
vi.mock("ai", () => ({ generateText }));
11+
vi.mock("next/cache", () => ({ unstable_cache: unstableCache }));
12+
vi.mock("@/lib/rate-limit", () => ({
13+
limitChat: async () => ({ success: true }),
14+
rateLimitResponse: () => new Response(null, { status: 429 }),
15+
}));
16+
vi.mock("@/lib/ai/models", () => ({
17+
getModel: (provider: string, apiKey?: string) => ({ provider, apiKey }),
18+
requiresApiKey: (provider: string) => provider !== "intern",
19+
}));
20+
vi.mock("@/lib/ai/providers/glm", () => ({
21+
createGlmFlashModel: () => ({ provider: "glm" }),
22+
}));
23+
24+
const { POST } = await import("@/app/api/suggestions/route");
25+
26+
// 公共缓存按请求建一层 unstable_cache,key 形如 suggestion-key-<...>
27+
const usedSharedCache = () =>
28+
unstableCache.mock.calls.some(([, keys]) =>
29+
(keys as string[]).some((k) => k.startsWith("suggestion-key-")),
30+
);
31+
32+
function post(body: object) {
33+
return POST(
34+
new Request("http://localhost/api/suggestions", {
35+
method: "POST",
36+
body: JSON.stringify(body),
37+
}),
38+
);
39+
}
40+
41+
describe("/api/suggestions 模型选择", () => {
42+
beforeEach(() => vi.stubEnv("ZHIPU_API_KEY", "server-key"));
43+
afterEach(() => {
44+
vi.unstubAllEnvs();
45+
vi.clearAllMocks();
46+
});
47+
48+
it("自带 key 的 provider 用用户自己的模型,不进公共缓存(即使服务端配了 ZHIPU)", async () => {
49+
await post({ messages: [], provider: "openai", apiKey: "user-key" });
50+
51+
expect(usedSharedCache()).toBe(false);
52+
expect(generateText).toHaveBeenCalledWith(
53+
expect.objectContaining({
54+
model: { provider: "openai", apiKey: "user-key" },
55+
}),
56+
);
57+
});
58+
59+
it("默认 intern 走公共缓存,配了 ZHIPU 时用 GLM", async () => {
60+
await post({ messages: [] });
61+
62+
expect(usedSharedCache()).toBe(true);
63+
expect(generateText).toHaveBeenCalledWith(
64+
expect.objectContaining({ model: { provider: "glm" } }),
65+
);
66+
});
67+
});

0 commit comments

Comments
 (0)