fix(web): fall back to backend defaults for unset search LLM parameters (#19079)

Fix search app LLM settings defaulting to 0 and overriding backend defaults on save. top_p=0 collapses sampling. Needs proper default handling.
This commit is contained in:
LuckTerence authored and GitHub committed 2026-09-01 14:44:47 +08:00
1 parent 50554a02fb
commit 5f697490a2
3 files changed
+107 -4

No files matched your search

@@ -0,0 +1,55 @@
import { llmSettingDefaults, resolveInitialLlmSetting } from './llm-setting-defaults';
// The four generation parameters must fall back to the backend defaults
// (LLM_SETTING_DEFAULTS in api/db/services/llm_service.py), not to 0: an
// unset top_p persisted as 0 would collapse nucleus sampling on the next
// save because the enabled flags default to true.
describe('resolveInitialLlmSetting', () => {
test('unset llm_setting falls back to the backend defaults', () => {
expect(resolveInitialLlmSetting(undefined)).toEqual(llmSettingDefaults);
expect(resolveInitialLlmSetting(null)).toEqual(llmSettingDefaults);
expect(resolveInitialLlmSetting({})).toEqual(llmSettingDefaults);
});
test('stored values are kept', () => {
expect(
resolveInitialLlmSetting({
temperature: 0.8,
top_p: 0.9,
frequency_penalty: 0.2,
presence_penalty: 0.5,
}),
).toEqual({
temperature: 0.8,
top_p: 0.9,
frequency_penalty: 0.2,
presence_penalty: 0.5,
});
});
test('a stored 0 is a deliberate choice and must not be replaced', () => {
expect(
resolveInitialLlmSetting({
temperature: 0,
top_p: 0,
frequency_penalty: 0,
presence_penalty: 0,
}),
).toEqual({
temperature: 0,
top_p: 0,
frequency_penalty: 0,
presence_penalty: 0,
});
});
test('partially stored values only fill the missing ones', () => {
expect(resolveInitialLlmSetting({ temperature: 0.5 })).toEqual({
temperature: 0.5,
top_p: llmSettingDefaults.top_p,
frequency_penalty: llmSettingDefaults.frequency_penalty,
presence_penalty: llmSettingDefaults.presence_penalty,
});
});
});
@@ -0,0 +1,50 @@
/*
* Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Mirrors LLM_SETTING_DEFAULTS in api/db/services/llm_service.py: when a
// generation parameter was never saved, the backend resolves it to these
// defaults. Falling back to 0 in the form would persist 0 as an explicit
// value and override the backend defaults on the next save (e.g. top_p 0
// collapses nucleus sampling).
export const llmSettingDefaults = {
temperature: 0.1,
top_p: 0.3,
frequency_penalty: 0.7,
presence_penalty: 0.4,
} as const;
type LlmSettingNumericFields = {
temperature?: number | null;
top_p?: number | null;
frequency_penalty?: number | null;
presence_penalty?: number | null;
};
/**
* Fill the four generation parameters for the form's initial values. A stored
* 0 is a deliberate choice and must be kept; only unset values fall back to
* the backend defaults.
*/
export const resolveInitialLlmSetting = (
llm_setting?: LlmSettingNumericFields | null,
) => ({
temperature: llm_setting?.temperature ?? llmSettingDefaults.temperature,
top_p: llm_setting?.top_p ?? llmSettingDefaults.top_p,
frequency_penalty:
llm_setting?.frequency_penalty ?? llmSettingDefaults.frequency_penalty,
presence_penalty:
llm_setting?.presence_penalty ?? llmSettingDefaults.presence_penalty,
});
+2 -4
View File
@@ -53,6 +53,7 @@ import {
useUpdateSearch,
} from '../next-searches/hooks';
import { RerankFormFields } from '@/components/rerank';
import { resolveInitialLlmSetting } from './llm-setting-defaults';
import {
SearchSettingFormData,
useRevalidatePersistedModels,
@@ -116,10 +117,7 @@ function SearchSetting({
llm_setting: {
llm_id: search_config?.chat_id || '',
parameter: llm_setting?.parameter || '',
temperature: llm_setting?.temperature || 0,
top_p: llm_setting?.top_p || 0,
frequency_penalty: llm_setting?.frequency_penalty || 0,
presence_penalty: llm_setting?.presence_penalty || 0,
...resolveInitialLlmSetting(llm_setting),
},
chat_settingcross_languages: [],
highlight: false,