This commit is contained in:
aaron 2026-06-08 08:36:13 +08:00
parent ca021d541e
commit ad0247c2a8
2 changed files with 46 additions and 9 deletions

View File

@ -72,6 +72,35 @@ def default_llm_config():
} }
def _llm_env_overrides():
"""Honor explicit LLM env vars even when DB runtime config exists."""
overrides = {}
checks = {
"ALPHAX_LLM_ENABLED": ("enabled", lambda: _env_bool("ALPHAX_LLM_ENABLED", False)),
"ALPHAX_LLM_BASE_URL": ("base_url", lambda: _env_str("ALPHAX_LLM_BASE_URL", "https://api.openai.com/v1")),
"ALPHAX_LLM_API_KEY_ENV": ("api_key_env", lambda: _env_str("ALPHAX_LLM_API_KEY_ENV", "ALPHAX_LLM_API_KEY")),
"ALPHAX_LLM_MODEL": ("model", lambda: _env_str("ALPHAX_LLM_MODEL", "gpt-4o-mini")),
"ALPHAX_LLM_TIMEOUT": ("timeout", lambda: _env_int("ALPHAX_LLM_TIMEOUT", 20)),
"ALPHAX_LLM_MAX_TOKENS": ("max_tokens", lambda: _env_int("ALPHAX_LLM_MAX_TOKENS", 900)),
}
for env_name, (key, loader) in checks.items():
if _env_present(env_name):
overrides[key] = loader()
module_overrides = {}
module_checks = {
"ALPHAX_LLM_RECOMMENDATIONS_ENABLED": ("recommendations", lambda: _env_bool("ALPHAX_LLM_RECOMMENDATIONS_ENABLED", True)),
"ALPHAX_LLM_SENTIMENT_ENABLED": ("sentiment", lambda: _env_bool("ALPHAX_LLM_SENTIMENT_ENABLED", True)),
"ALPHAX_LLM_REVIEW_ENABLED": ("review", lambda: _env_bool("ALPHAX_LLM_REVIEW_ENABLED", True)),
"ALPHAX_LLM_CHAT_ENABLED": ("chat", lambda: _env_bool("ALPHAX_LLM_CHAT_ENABLED", True)),
}
for env_name, (key, loader) in module_checks.items():
if _env_present(env_name):
module_overrides[key] = loader()
if module_overrides:
overrides["modules"] = module_overrides
return overrides
def default_paper_trading_config(): def default_paper_trading_config():
# One shared default keeps buy-now entries and wait-pullback orders from # One shared default keeps buy-now entries and wait-pullback orders from
# drifting into two unrelated RR standards. The explicit entry/order envs # drifting into two unrelated RR standards. The explicit entry/order envs
@ -457,7 +486,8 @@ def llm_config():
if cfg is None: if cfg is None:
_seed_one("llm", default_llm_config(), "LLM provider and module switches; API key remains in env") _seed_one("llm", default_llm_config(), "LLM provider and module switches; API key remains in env")
cfg = get_llm_config(default=None) cfg = get_llm_config(default=None)
return cfg or default_llm_config() merged = deep_merge(default_llm_config(), cfg or {})
return deep_merge(merged, _llm_env_overrides())
def paper_trading_config(): def paper_trading_config():

View File

@ -216,13 +216,19 @@ def test_runtime_config_api_blocks_protected_system_config_updates():
assert delete_resp.status_code == 403 assert delete_resp.status_code == 403
def test_llm_system_config_overrides_env_defaults(monkeypatch): def test_llm_explicit_env_overrides_stale_system_config(monkeypatch):
monkeypatch.setenv("ALPHAX_LLM_ENABLED", "0") monkeypatch.setenv("ALPHAX_LLM_ENABLED", "1")
monkeypatch.setenv("ALPHAX_LLM_BASE_URL", "https://api.deepseek.com")
monkeypatch.setenv("ALPHAX_LLM_API_KEY_ENV", "DEEPSEEK_API_KEY")
monkeypatch.setenv("ALPHAX_LLM_MODEL", "deepseek-chat")
monkeypatch.setenv("ALPHAX_LLM_TIMEOUT", "45")
monkeypatch.setenv("ALPHAX_LLM_MAX_TOKENS", "1200")
monkeypatch.setenv("ALPHAX_LLM_SENTIMENT_ENABLED", "1")
set_config("system", "llm", { set_config("system", "llm", {
"enabled": True, "enabled": True,
"base_url": "https://llm.example/v1", "base_url": "https://llm.example/v1",
"api_key_env": "TEST_LLM_KEY", "api_key_env": "TEST_LLM_KEY",
"model": "test-model", "model": "gpt-5.4",
"timeout": 33, "timeout": 33,
"max_tokens": 444, "max_tokens": 444,
"modules": {"sentiment": False, "review": True}, "modules": {"sentiment": False, "review": True},
@ -231,11 +237,12 @@ def test_llm_system_config_overrides_env_defaults(monkeypatch):
params = get_llm_params() params = get_llm_params()
assert params["enabled"] is True assert params["enabled"] is True
assert params["base_url"] == "https://llm.example/v1" assert params["base_url"] == "https://api.deepseek.com"
assert params["model"] == "test-model" assert params["api_key_env"] == "DEEPSEEK_API_KEY"
assert params["timeout"] == 33 assert params["model"] == "deepseek-chat"
assert params["max_tokens"] == 444 assert params["timeout"] == 45
assert get_llm_module_enabled("sentiment") is False assert params["max_tokens"] == 1200
assert get_llm_module_enabled("sentiment") is True
assert get_llm_module_enabled("review") is True assert get_llm_module_enabled("review") is True