llm_service.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. """LLM服务"""
  2. import json
  3. import os
  4. from pathlib import Path
  5. from hello_agents import HelloAgentsLLM
  6. from ..config import get_settings
  7. _llm_instance = None
  8. _llm_config_override = None
  9. LLM_CONFIG_FILE = Path(__file__).parent.parent.parent / "data" / "llm_config.json"
  10. def _load_llm_config():
  11. """从文件加载运行时LLM配置(优先于.env)"""
  12. global _llm_config_override
  13. if LLM_CONFIG_FILE.exists():
  14. try:
  15. with open(LLM_CONFIG_FILE, "r", encoding="utf-8") as f:
  16. _llm_config_override = json.load(f)
  17. print(f"[LLM] 加载运行时配置: {_llm_config_override.get('base_url', '')}")
  18. except Exception as e:
  19. print(f"[LLM] 加载运行时配置失败: {e}")
  20. _llm_config_override = None
  21. else:
  22. _llm_config_override = None
  23. def _build_llm():
  24. """根据配置创建LLM实例(运行时配置优先,回退到.env)"""
  25. settings = get_settings()
  26. # 优先使用运行时配置,空字符串回退到.env
  27. if _llm_config_override:
  28. model = _llm_config_override.get("model_id") or settings.deepseek_model_id
  29. api_key = _llm_config_override.get("api_key") or settings.deepseek_api_key
  30. base_url = _llm_config_override.get("base_url") or settings.deepseek_base_url
  31. else:
  32. model = settings.deepseek_model_id
  33. api_key = settings.deepseek_api_key
  34. base_url = settings.deepseek_base_url
  35. return HelloAgentsLLM(
  36. model=model,
  37. api_key=api_key,
  38. base_url=base_url,
  39. )
  40. def get_llm() -> HelloAgentsLLM:
  41. """获取LLM实例"""
  42. global _llm_instance
  43. if _llm_instance is None:
  44. _load_llm_config()
  45. _llm_instance = _build_llm()
  46. print(f"LLM服务初始化成功: {_llm_instance.model}")
  47. return _llm_instance
  48. def reload_llm(config: dict = None) -> HelloAgentsLLM:
  49. """重新配置并刷新LLM实例"""
  50. global _llm_instance, _llm_config_override
  51. if config:
  52. # 清洗空值:去掉空字符串的字段,保留有效值
  53. clean = {}
  54. for key in ("base_url", "model_id", "api_key"):
  55. val = (config.get(key) or "").strip()
  56. if val:
  57. clean[key] = val
  58. # 保存运行时配置
  59. LLM_CONFIG_FILE.parent.mkdir(parents=True, exist_ok=True)
  60. with open(LLM_CONFIG_FILE, "w", encoding="utf-8") as f:
  61. json.dump(clean, f, ensure_ascii=False, indent=2)
  62. _load_llm_config()
  63. # 重置实例
  64. _llm_instance = None
  65. new_llm = get_llm()
  66. print(f"LLM服务已重新配置: {new_llm.model}")
  67. return new_llm
  68. def reset_llm_config() -> HelloAgentsLLM:
  69. """清除运行时配置,回退到.env默认值"""
  70. global _llm_instance, _llm_config_override
  71. _llm_config_override = None
  72. if LLM_CONFIG_FILE.exists():
  73. LLM_CONFIG_FILE.unlink()
  74. print("[LLM] 已清除运行时配置文件,回退到.env默认值")
  75. _llm_instance = None
  76. return get_llm()
  77. def get_llm_config() -> dict:
  78. """获取当前LLM配置(API密钥脱敏)"""
  79. settings = get_settings()
  80. if _llm_config_override:
  81. config = _llm_config_override.copy()
  82. else:
  83. config = {
  84. "base_url": settings.deepseek_base_url,
  85. "model_id": settings.deepseek_model_id,
  86. "api_key": settings.deepseek_api_key,
  87. }
  88. # API密钥脱敏
  89. if config.get("api_key"):
  90. key = config["api_key"]
  91. config["api_key"] = key[:4] + "****" + key[-4:] if len(key) > 8 else "****"
  92. return config