llm_client.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. """Step 1: LLM 客户端 — 兼容 OpenAI 接口,支持流式响应"""
  2. import os
  3. from openai import OpenAI
  4. from dotenv import load_dotenv
  5. from typing import List, Dict
  6. load_dotenv()
  7. class HelloAgentsLLM:
  8. def __init__(self, model: str = None, apiKey: str = None,
  9. baseUrl: str = None, timeout: int = None):
  10. self.model = model or os.getenv("LLM_MODEL_ID")
  11. apiKey = apiKey or os.getenv("LLM_API_KEY")
  12. baseUrl = baseUrl or os.getenv("LLM_BASE_URL")
  13. timeout = timeout or int(os.getenv("LLM_TIMEOUT", 60))
  14. if not all([self.model, apiKey, baseUrl]):
  15. raise ValueError("请在 .env 中配置 LLM_MODEL_ID, LLM_API_KEY, LLM_BASE_URL")
  16. self.client = OpenAI(api_key=apiKey, base_url=baseUrl, timeout=timeout)
  17. def think(self, messages: List[Dict[str, str]], temperature: float = 0) -> str:
  18. print(f"\n[{self.model}] 思考中...")
  19. try:
  20. response = self.client.chat.completions.create(
  21. model=self.model, messages=messages,
  22. temperature=temperature, stream=True,
  23. )
  24. collected = []
  25. for chunk in response:
  26. if not chunk.choices:
  27. continue
  28. content = chunk.choices[0].delta.content or ""
  29. # 过滤无效代理字符 (surrogates)
  30. clean = content.encode("utf-8", errors="surrogateescape").decode("utf-8", errors="replace")
  31. print(clean, end="", flush=True)
  32. collected.append(clean)
  33. print()
  34. result = "".join(collected)
  35. return result
  36. except Exception as e:
  37. print(f"[ERR] LLM 调用失败: {e}")
  38. # 尝试非流式重试
  39. try:
  40. print(" 尝试非流式重试...")
  41. response = self.client.chat.completions.create(
  42. model=self.model, messages=messages,
  43. temperature=temperature, stream=False,
  44. )
  45. content = response.choices[0].message.content or ""
  46. clean = content.encode("utf-8", errors="surrogateescape").decode("utf-8", errors="replace")
  47. print(clean)
  48. return clean
  49. except Exception as e2:
  50. print(f"[ERR] 非流式也失败: {e2}")
  51. raise RuntimeError(f"LLM调用完全失败: {e2}")