docs: 使用说明 docs/USAGE.md;LLM URL/模型名配置移到 config.yaml(.env 仅 Key)

- config.yaml 新增 agent.llm:base_url / model 明文配置(默认百炼兼容端点 qwen-plus),api_key 只从 .env 的 LLM_API_KEY 读取;LLM_BASE_URL / LLM_MODEL 仍可经 .env 覆盖
- .env.example 注释同步;core.config 读取逻辑 env > yaml > 默认
- docs/USAGE.md:安装/配置/数据同步/启动/研究 API 与 Job/Experiment/Agent/测试门禁/已知限制/FAQ
- README 增加使用说明入口
- 新增 config LLM 测试 2 项(yaml 默认 + env 覆盖)→ pytest 81 passed / ruff clean
This commit is contained in:
Simon
2026-09-06 17:57:15 +08:00
parent 8f8b6d274f
commit 01d818e12a
5 changed files with 302 additions and 5 deletions
+7 -5
View File
@@ -105,9 +105,11 @@ def get_settings() -> Settings:
secret_env = _deep(cfg, "app.secret_key_env") or "APP_SECRET_KEY"
url_env = _deep(cfg, "database.url_env") or "DATABASE_URL"
token_env = _deep(cfg, "data_source.tushare_token_env") or "TUSHARE_TOKEN"
llm_key_env = _deep(cfg, "agent.llm_key_env") or "LLM_API_KEY"
llm_url_env = _deep(cfg, "agent.llm_base_url_env") or "LLM_BASE_URL"
llm_model_env = _deep(cfg, "agent.llm_model_env") or "LLM_MODEL"
# Agent LLM:URL/模型名在 config.yaml 明文,api_key 只从 .env 读(env 可覆盖 url/model)
agent_llm = _deep(cfg, "agent.llm") or {}
llm_key_env = agent_llm.get("api_key_env") or "LLM_API_KEY"
llm_url_env = agent_llm.get("base_url_env") or "LLM_BASE_URL"
llm_model_env = agent_llm.get("model_env") or "LLM_MODEL"
default_url = "sqlite:///./data/quant.db"
database_url = os.environ.get(url_env) or default_url
@@ -129,7 +131,7 @@ def get_settings() -> Settings:
data_source_fallback=str(_deep(cfg, "data_source.fallback") or "sina"),
tushare_token=os.environ.get(token_env, ""),
llm_api_key=os.environ.get(llm_key_env, ""),
llm_base_url=os.environ.get(llm_url_env) or None,
llm_model=os.environ.get(llm_model_env) or "qwen-plus",
llm_base_url=os.environ.get(llm_url_env) or (agent_llm.get("base_url") or None),
llm_model=os.environ.get(llm_model_env) or agent_llm.get("model") or "qwen-plus",
storage=_resolve_storage_dirs(cfg),
)
+22
View File
@@ -46,3 +46,25 @@ def test_env_file_loading(tmp_path: Path, monkeypatch) -> None:
monkeypatch.setenv("TUSHARE_TOKEN", "kept")
_load_env_file(env_file)
assert os.environ["TUSHARE_TOKEN"] == "kept"
def test_llm_from_config_yaml() -> None:
"""URL 与模型名来自 config.yaml 明文,Key 仅来自环境(当前未设置)。"""
settings = get_settings()
assert settings.llm_model == "qwen-plus"
assert settings.llm_base_url == "https://dashscope.aliyuncs.com/compatible-mode/v1"
assert settings.llm_api_key == "" # .env 未提供 → 空,Agent 层给出引导提示
def test_llm_env_overrides_yaml(monkeypatch) -> None:
from app.core.config import get_settings
monkeypatch.setenv("LLM_MODEL", "env-model")
monkeypatch.setenv("LLM_BASE_URL", "https://example.com/v1")
monkeypatch.setenv("LLM_API_KEY", "sk-test")
get_settings.cache_clear() # Settings 有 lru_cache,刷新以读取新环境变量
s = get_settings()
assert s.llm_model == "env-model"
assert s.llm_base_url == "https://example.com/v1"
assert s.llm_api_key == "sk-test"
get_settings.cache_clear()