Skip to content

Commit fabfd3e

Browse files
jorbenclaude
andauthored
fix(llm): 🐛 修复 max_tokens 为 undefined 时导致的请求问题 (#44)
当调用 LLM 接口时未提供 maxTokens 参数,会导致请求体中包含 max_tokens: null,某些 API 提供商可能将其解释为 0 或 1, 导致只返回极少内容。 修复内容: - OpenAIClient: 仅在 maxTokens 不为 undefined 时添加 max_tokens - OpenAIResponsesClient: 同上 - AnthropicClient: 同上 - GeminiClient: 仅在 maxTokens 不为 undefined 时添加 maxOutputTokens 同时添加测试用例验证未提供 maxTokens 时不会包含在请求体中。 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fe9220f commit fabfd3e

5 files changed

Lines changed: 36 additions & 4 deletions

File tree

src/core/infrastructure/adapters/llm/AnthropicClient.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,14 @@ export class AnthropicClient extends LLMClient {
3737
model: modelName,
3838
messages: anthropicMessages,
3939
temperature: normalizedOptions.temperature ?? 0.7,
40-
max_tokens: normalizedOptions.maxTokens,
4140
stream: normalizedOptions.stream || false
4241
};
4342

43+
// 只在提供了 maxTokens 时才添加到请求体
44+
if (normalizedOptions.maxTokens !== undefined) {
45+
requestBody.max_tokens = normalizedOptions.maxTokens;
46+
}
47+
4448
// Anthropic支持System指令,而不是作为一个普通消息
4549
const systemMessage = normalizedOptions.messages.find(msg => msg.role === 'system');
4650
if (systemMessage) {

src/core/infrastructure/adapters/llm/GeminiClient.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,15 @@ export class GeminiClient extends LLMClient {
3535
contents: geminiContents,
3636
generationConfig: {
3737
temperature: normalizedOptions.temperature ?? 0.7,
38-
maxOutputTokens: normalizedOptions.maxTokens,
3938
topP: 0.95
4039
}
4140
};
4241

42+
// 只在提供了 maxTokens 时才添加到请求体
43+
if (normalizedOptions.maxTokens !== undefined) {
44+
requestBody.generationConfig.maxOutputTokens = normalizedOptions.maxTokens;
45+
}
46+
4347
// 添加响应格式(如果指定)
4448
if (normalizedOptions.response_format?.type === 'json_object') {
4549
// Gemini使用不同的键来指定JSON输出

src/core/infrastructure/adapters/llm/OpenAIClient.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@ export class OpenAIClient extends LLMClient {
3434
model: normalizedOptions.model || 'gpt-3.5-turbo',
3535
messages: openaiMessages,
3636
temperature: normalizedOptions.temperature ?? 0.7,
37-
max_tokens: normalizedOptions.maxTokens,
3837
stream: normalizedOptions.stream || false
3938
};
4039

40+
// 只在提供了 maxTokens 时才添加到请求体
41+
if (normalizedOptions.maxTokens !== undefined) {
42+
requestBody.max_tokens = normalizedOptions.maxTokens;
43+
}
44+
4145
// 添加工具配置(如果有)
4246
if (normalizedOptions.tools && normalizedOptions.tools.length > 0) {
4347
requestBody.tools = normalizedOptions.tools;

src/core/infrastructure/adapters/llm/OpenAIResponsesClient.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,14 @@ export class OpenAIResponsesClient extends LLMClient {
3535
model: normalizedOptions.model || 'gpt-4o',
3636
input: input,
3737
temperature: normalizedOptions.temperature ?? 0.7,
38-
max_tokens: normalizedOptions.maxTokens,
3938
stream: normalizedOptions.stream || false
4039
};
4140

41+
// 只在提供了 maxTokens 时才添加到请求体
42+
if (normalizedOptions.maxTokens !== undefined) {
43+
requestBody.max_tokens = normalizedOptions.maxTokens;
44+
}
45+
4246
// 添加系统指令(如果有)
4347
if (instructions) {
4448
requestBody.instructions = instructions;

src/core/infrastructure/adapters/llm/__tests__/OpenAIClient.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,22 @@ describe('OpenAIClient', () => {
425425
expect(body.temperature).toBe(0.7)
426426
})
427427

428+
it('should not include max_tokens when not provided', async () => {
429+
const mockResponse = createMockOpenAIResponse('Response')
430+
mockFetchSuccess(mockResponse)
431+
432+
await client.completion({
433+
messages: [
434+
{ role: 'user', content: { type: 'text', text: 'Test' } }
435+
],
436+
model: 'gpt-4o'
437+
})
438+
439+
const callArgs = (global.fetch as any).mock.calls[0][1]
440+
const body = JSON.parse(callArgs.body)
441+
expect(body.max_tokens).toBeUndefined()
442+
})
443+
428444
it('should include response_format when specified', async () => {
429445
const mockResponse = createMockOpenAIResponse('{"key": "value"}')
430446
mockFetchSuccess(mockResponse)

0 commit comments

Comments
 (0)