From 11b2dfcfdd082077343c86c427dbfaeed2b11037 Mon Sep 17 00:00:00 2001 From: Lynn Date: Tue, 4 Aug 2026 10:02:14 +0800 Subject: [PATCH] Fix: handle llm_setting switch (#17745) --- api/apps/restful_apis/_generation_params.py | 42 +++++++++++++++++++ api/apps/restful_apis/bot_api.py | 3 +- api/apps/restful_apis/chat_api.py | 4 +- api/db/db_models.py | 15 ++++--- .../test_agentbots_access_control.py | 4 +- web/src/pages/agent/utils/download-dsl.ts | 5 +-- .../dataset/dataset-setting/general-form.tsx | 4 +- web/src/pages/next-search/search-setting.tsx | 16 +++---- web/src/pages/next-searches/hooks.ts | 4 ++ 9 files changed, 74 insertions(+), 23 deletions(-) diff --git a/api/apps/restful_apis/_generation_params.py b/api/apps/restful_apis/_generation_params.py index e5fa79c2bf..50f0f7582f 100644 --- a/api/apps/restful_apis/_generation_params.py +++ b/api/apps/restful_apis/_generation_params.py @@ -18,6 +18,48 @@ from copy import deepcopy GENERATION_CONFIG_KEYS = ("temperature", "top_p", "frequency_penalty", "presence_penalty", "max_tokens") +# Default values for the four LLM generation parameters stored in +# search_config.llm_setting. When the corresponding ``_enabled`` flag is +# ``False`` (or the key is absent), the default is used instead of whatever +# the user may have stored in ``llm_setting``. +LLM_SETTING_DEFAULTS = { + "temperature": 0.1, + "top_p": 0.3, + "frequency_penalty": 0.7, + "presence_penalty": 0.4, +} + + +def resolve_llm_setting(llm_setting): + """Resolve *llm_setting* values according to their enable flags. + + For each of the four generation parameters the dictionary may carry a + ``{key}_enabled`` boolean. When the flag is ``True`` and the value + exists in *llm_setting*, the user-configured value is kept; otherwise + the default from :data:`LLM_SETTING_DEFAULTS` is substituted. + + Keys whose name ends with ``_enabled`` are stripped from the result so + they are never forwarded to the downstream LLM call. + """ + if not llm_setting: + return dict(LLM_SETTING_DEFAULTS) + + resolved = {} + for key, default_val in LLM_SETTING_DEFAULTS.items(): + enabled_key = f"{key}_enabled" + if llm_setting.get(enabled_key, True) and key in llm_setting: + resolved[key] = llm_setting[key] + else: + resolved[key] = default_val + + # Carry over any extra keys that are not generation parameters and not + # enable flags (e.g. ``llm_id``, ``model_type``). + for key, val in llm_setting.items(): + if key not in resolved and not key.endswith("_enabled"): + resolved[key] = val + + return resolved + def extract_generation_config(req): return {key: req[key] for key in GENERATION_CONFIG_KEYS if key in req and req[key] is not None} diff --git a/api/apps/restful_apis/bot_api.py b/api/apps/restful_apis/bot_api.py index 18ee47e327..2c1938357b 100644 --- a/api/apps/restful_apis/bot_api.py +++ b/api/apps/restful_apis/bot_api.py @@ -36,6 +36,7 @@ from common.metadata_utils import apply_meta_data_filter from api.db.services.search_service import SearchService from api.db.services.user_service import UserTenantService from api.db.joint_services.tenant_model_service import get_tenant_default_model_by_type, resolve_model_config +from api.apps.restful_apis._generation_params import resolve_llm_setting from common.misc_utils import thread_pool_exec from api.utils.api_utils import get_error_data_result, get_json_result, add_tenant_id_to_kwargs, get_result, get_request_json, server_error_response, validate_request from rag.app.tag import label_question @@ -493,7 +494,7 @@ async def related_questions_embedded(tenant_id=None): chat_model_config = await thread_pool_exec(get_tenant_default_model_by_type, tenant_id, LLMType.CHAT) chat_mdl = LLMBundle(tenant_id, chat_model_config) - gen_conf = search_config.get("llm_setting", {"temperature": 0.9}) + gen_conf = resolve_llm_setting(search_config.get("llm_setting")) prompt = load_prompt("related_question") ans = await chat_mdl.async_chat( prompt, diff --git a/api/apps/restful_apis/chat_api.py b/api/apps/restful_apis/chat_api.py index 4472b4065d..05c980b718 100644 --- a/api/apps/restful_apis/chat_api.py +++ b/api/apps/restful_apis/chat_api.py @@ -27,7 +27,7 @@ from quart import Response, request from werkzeug.exceptions import BadRequest from api.apps import current_user, login_required -from api.apps.restful_apis._generation_params import merge_generation_config, pop_generation_config +from api.apps.restful_apis._generation_params import merge_generation_config, pop_generation_config, resolve_llm_setting from api.db.joint_services.tenant_model_service import ( get_api_key, get_composite_model_name_by_id, @@ -1176,7 +1176,7 @@ async def recommendation(): chat_model_config = get_tenant_default_model_by_type(current_user.id, LLMType.CHAT) chat_mdl = LLMBundle(current_user.id, chat_model_config) - gen_conf = search_config.get("llm_setting", {"temperature": 0.9}) + gen_conf = resolve_llm_setting(search_config.get("llm_setting")) if "parameter" in gen_conf: del gen_conf["parameter"] prompt = load_prompt("related_question") diff --git a/api/db/db_models.py b/api/db/db_models.py index ed977c314c..1eb2a7a7af 100644 --- a/api/db/db_models.py +++ b/api/db/db_models.py @@ -1206,13 +1206,16 @@ class Search(DataBaseModel): "top_k": 1024, # chat settings "summary": False, - "chat_id": "", - # Leave it here for reference, don't need to set default values + "chat_id": "", # id of chat model in tenant_model table "llm_setting": { - # "temperature": 0.1, - # "top_p": 0.3, - # "frequency_penalty": 0.7, - # "presence_penalty": 0.4, + "temperature": 0.1, + "top_p": 0.3, + "frequency_penalty": 0.7, + "presence_penalty": 0.4, + "temperature_enabled": True, + "top_p_enabled": True, + "frequency_penalty_enabled": True, + "presence_penalty_enabled": True, }, "chat_settingcross_languages": [], "highlight": False, diff --git a/test/unit_test/api/apps/restful_apis/test_agentbots_access_control.py b/test/unit_test/api/apps/restful_apis/test_agentbots_access_control.py index 9174d8c9f3..93cd6e6371 100644 --- a/test/unit_test/api/apps/restful_apis/test_agentbots_access_control.py +++ b/test/unit_test/api/apps/restful_apis/test_agentbots_access_control.py @@ -71,7 +71,9 @@ def _load_bot_api(monkeypatch, *, accessible, calls): return _gen() _stub(monkeypatch, "quart", Response=lambda *a, **k: SimpleNamespace(headers=SimpleNamespace(add_header=lambda *aa, **kk: None)), request=SimpleNamespace()) - _stub(monkeypatch, "api.apps", AUTH_BETA="beta", login_required=lambda *_a, **_k: lambda func: func) + _stub(monkeypatch, "api.apps", AUTH_BETA="beta", login_required=lambda *_a, **_k: lambda func: func, __path__=[]) + _stub(monkeypatch, "api.apps.restful_apis", __path__=[]) + _stub(monkeypatch, "api.apps.restful_apis._generation_params", resolve_llm_setting=lambda s: s or {"temperature": 0.1, "top_p": 0.3, "frequency_penalty": 0.7, "presence_penalty": 0.4}) _stub(monkeypatch, "agent.canvas", Canvas=lambda *a, **k: SimpleNamespace(get_component_input_form=lambda _n: {}, get_prologue=lambda: "", get_mode=lambda: "agent")) _stub(monkeypatch, "api.db.db_models", APIToken=SimpleNamespace(query=lambda **_k: [SimpleNamespace(tenant_id="attacker-tenant")])) _stub(monkeypatch, "api.db.services.api_service", API4ConversationService=SimpleNamespace()) diff --git a/web/src/pages/agent/utils/download-dsl.ts b/web/src/pages/agent/utils/download-dsl.ts index 62afaf8b1f..587452d89c 100644 --- a/web/src/pages/agent/utils/download-dsl.ts +++ b/web/src/pages/agent/utils/download-dsl.ts @@ -8,10 +8,7 @@ import { clearSensitiveFields } from './clear-sensitive-fields'; * canvas export button and the version-history dialog so both emit * the same structure. */ -export const downloadDsl = ( - dsl: DSL | Record, - title: string, -) => { +export const downloadDsl = (dsl: DSL | Record, title: string) => { const sanitizedDsl = clearSensitiveFields(dsl); downloadJsonFile( { ...sanitizedDsl, globals: { ...(sanitizedDsl.globals ?? {}) } }, diff --git a/web/src/pages/dataset/dataset-setting/general-form.tsx b/web/src/pages/dataset/dataset-setting/general-form.tsx index 8016309995..a24c9a005d 100644 --- a/web/src/pages/dataset/dataset-setting/general-form.tsx +++ b/web/src/pages/dataset/dataset-setting/general-form.tsx @@ -130,7 +130,9 @@ export function GeneralForm() { ownerTenantId={useKnowledgeBaseContext().knowledgeBase?.tenant_id} > - + diff --git a/web/src/pages/next-search/search-setting.tsx b/web/src/pages/next-search/search-setting.tsx index 64ec626378..00e3e00f4b 100644 --- a/web/src/pages/next-search/search-setting.tsx +++ b/web/src/pages/next-search/search-setting.tsx @@ -160,10 +160,10 @@ const SearchSetting: React.FC = ({ : undefined, }, }, - temperatureEnabled: llm_setting?.temperature !== undefined, - topPEnabled: llm_setting?.top_p !== undefined, - presencePenaltyEnabled: llm_setting?.presence_penalty !== undefined, - frequencyPenaltyEnabled: llm_setting?.frequency_penalty !== undefined, + temperatureEnabled: llm_setting?.temperature_enabled ?? true, + topPEnabled: llm_setting?.top_p_enabled ?? true, + presencePenaltyEnabled: llm_setting?.presence_penalty_enabled ?? true, + frequencyPenaltyEnabled: llm_setting?.frequency_penalty_enabled ?? true, }); }, [data, search_config, llm_setting, formMethods, descriptionDefaultValue]); @@ -273,10 +273,6 @@ const SearchSetting: React.FC = ({ frequencyPenaltyEnabled?: boolean; maxTokensEnabled?: boolean; }; - void _temperatureEnabled; - void _topPEnabled; - void _presencePenaltyEnabled; - void _frequencyPenaltyEnabled; void _maxTokensEnabled; const { llm_setting, @@ -292,6 +288,10 @@ const SearchSetting: React.FC = ({ top_p: llm_setting.top_p, frequency_penalty: llm_setting.frequency_penalty, presence_penalty: llm_setting.presence_penalty, + temperature_enabled: _temperatureEnabled, + top_p_enabled: _topPEnabled, + frequency_penalty_enabled: _frequencyPenaltyEnabled, + presence_penalty_enabled: _presencePenaltyEnabled, } as IllmSettingProps; const referenceMetadata = other_config.reference_metadata; const normalizedReferenceMetadata = referenceMetadata diff --git a/web/src/pages/next-searches/hooks.ts b/web/src/pages/next-searches/hooks.ts index 39427c8dd2..c4ef9bbc94 100644 --- a/web/src/pages/next-searches/hooks.ts +++ b/web/src/pages/next-searches/hooks.ts @@ -155,6 +155,10 @@ export interface IllmSettingProps { top_p?: number; frequency_penalty?: number; presence_penalty?: number; + temperature_enabled?: boolean; + top_p_enabled?: boolean; + frequency_penalty_enabled?: boolean; + presence_penalty_enabled?: boolean; } interface IllmSettingEnableProps { temperatureEnabled?: boolean;