deepseek_chat.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import os
  2. from openai import OpenAI
  3. from .base_llm_chat import BaseLLMChat
  4. class DeepSeekChat(BaseLLMChat):
  5. """DeepSeek AI聊天实现"""
  6. def __init__(self, config=None):
  7. print("...DeepSeekChat init...")
  8. super().__init__(config=config)
  9. if config is None:
  10. self.client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
  11. return
  12. if "api_key" in config:
  13. # 使用配置中的base_url,如果没有则使用默认值
  14. base_url = config.get("base_url", "https://api.deepseek.com")
  15. self.client = OpenAI(
  16. api_key=config["api_key"],
  17. base_url=base_url
  18. )
  19. def submit_prompt(self, prompt, **kwargs) -> str:
  20. if prompt is None:
  21. raise Exception("Prompt is None")
  22. if len(prompt) == 0:
  23. raise Exception("Prompt is empty")
  24. # Count the number of tokens in the message log
  25. num_tokens = 0
  26. for message in prompt:
  27. num_tokens += len(message["content"]) / 4
  28. # 获取 stream 参数
  29. stream_mode = kwargs.get("stream", self.config.get("stream", False) if self.config else False)
  30. # 获取 enable_thinking 参数
  31. enable_thinking = kwargs.get("enable_thinking", self.config.get("enable_thinking", False) if self.config else False)
  32. # DeepSeek API约束:enable_thinking=True时建议使用stream=True
  33. # 如果stream=False但enable_thinking=True,则忽略enable_thinking
  34. if enable_thinking and not stream_mode:
  35. print("WARNING: enable_thinking=True 不生效,因为它需要 stream=True")
  36. enable_thinking = False
  37. # 确定使用的模型
  38. model = None
  39. if kwargs.get("model", None) is not None:
  40. model = kwargs.get("model", None)
  41. elif kwargs.get("engine", None) is not None:
  42. model = kwargs.get("engine", None)
  43. elif self.config is not None and "engine" in self.config:
  44. model = self.config["engine"]
  45. elif self.config is not None and "model" in self.config:
  46. model = self.config["model"]
  47. else:
  48. # 根据 enable_thinking 选择模型
  49. if enable_thinking:
  50. model = "deepseek-reasoner"
  51. else:
  52. if num_tokens > 3500:
  53. model = "deepseek-chat"
  54. else:
  55. model = "deepseek-chat"
  56. # 模型兼容性提示(但不强制切换)
  57. if enable_thinking and model not in ["deepseek-reasoner"]:
  58. print(f"提示:模型 {model} 可能不支持推理功能,推理相关参数将被忽略")
  59. print(f"\nUsing model {model} for {num_tokens} tokens (approx)")
  60. print(f"Enable thinking: {enable_thinking}, Stream mode: {stream_mode}")
  61. # 方案1:通过 system prompt 控制中文输出(DeepSeek 不支持 language 参数)
  62. # 检查配置中的语言设置,并在 system prompt 中添加中文指令
  63. # language_setting = self.config.get("language", "").lower() if self.config else ""
  64. # print(f"DEBUG: language_setting='{language_setting}', model='{model}', enable_thinking={enable_thinking}")
  65. # if language_setting == "chinese" and enable_thinking:
  66. # print("DEBUG: ✅ 触发中文指令添加")
  67. # # 为推理模型添加中文思考指令
  68. # chinese_instruction = {"role": "system", "content": "请用中文进行思考和回答。在推理过程中,请使用中文进行分析和思考。<think></think>之间也请使用中文"}
  69. # # 如果第一条消息不是 system 消息,则添加中文指令
  70. # if not prompt or prompt[0].get("role") != "system":
  71. # prompt = [chinese_instruction] + prompt
  72. # else:
  73. # # 如果已有 system 消息,则在其内容中添加中文指令
  74. # existing_content = prompt[0]["content"]
  75. # prompt[0]["content"] = f"{existing_content}\n\n请用中文进行思考和回答。在推理过程中,请使用中文进行分析和思考。<think></think>之间也请使用中文"
  76. # else:
  77. # print(f"DEBUG: ❌ 未触发中文指令 - language_setting==chinese: {language_setting == 'chinese'}, model==deepseek-reasoner: {model == 'deepseek-reasoner'}, enable_thinking: {enable_thinking}")
  78. # 构建 API 调用参数
  79. api_params = {
  80. "model": model,
  81. "messages": prompt,
  82. "stop": None,
  83. "temperature": self.temperature,
  84. "stream": stream_mode,
  85. }
  86. # 过滤掉自定义参数,避免传递给 API
  87. # 注意:保留 language 参数,让 DeepSeek API 自己处理
  88. filtered_kwargs = {k: v for k, v in kwargs.items()
  89. if k not in ['model', 'engine', 'enable_thinking', 'stream']}
  90. # 根据模型过滤不支持的参数
  91. if model == "deepseek-reasoner":
  92. # deepseek-reasoner 不支持的参数
  93. unsupported_params = ['top_p', 'presence_penalty', 'frequency_penalty', 'logprobs', 'top_logprobs']
  94. for param in unsupported_params:
  95. if param in filtered_kwargs:
  96. print(f"警告:deepseek-reasoner 不支持参数 {param},已忽略")
  97. filtered_kwargs.pop(param, None)
  98. else:
  99. # deepseek-chat 等其他模型,只过滤明确会导致错误的参数
  100. # 目前 deepseek-chat 支持大部分标准参数,暂不过滤
  101. pass
  102. # 添加其他参数
  103. api_params.update(filtered_kwargs)
  104. if stream_mode:
  105. # 流式处理模式
  106. if model == "deepseek-reasoner" and enable_thinking:
  107. print("使用流式处理模式,启用推理功能")
  108. else:
  109. print("使用流式处理模式,常规聊天")
  110. response_stream = self.client.chat.completions.create(**api_params)
  111. if model == "deepseek-reasoner" and enable_thinking:
  112. # 推理模型的流式处理
  113. collected_reasoning = []
  114. collected_content = []
  115. for chunk in response_stream:
  116. if hasattr(chunk, 'choices') and chunk.choices:
  117. delta = chunk.choices[0].delta
  118. # 收集推理内容
  119. if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
  120. collected_reasoning.append(delta.reasoning_content)
  121. # 收集最终答案
  122. if hasattr(delta, 'content') and delta.content:
  123. collected_content.append(delta.content)
  124. # 可选:打印推理过程
  125. if collected_reasoning:
  126. reasoning_text = "".join(collected_reasoning)
  127. print("Model reasoning process:\n", reasoning_text)
  128. # 方案2:返回包含 <think></think> 标签的完整内容,与 QianWen 保持一致
  129. final_content = "".join(collected_content)
  130. if collected_reasoning:
  131. reasoning_text = "".join(collected_reasoning)
  132. return f"<think>{reasoning_text}</think>\n\n{final_content}"
  133. else:
  134. return final_content
  135. else:
  136. # 其他模型的流式处理(如 deepseek-chat)
  137. collected_content = []
  138. for chunk in response_stream:
  139. if hasattr(chunk, 'choices') and chunk.choices:
  140. delta = chunk.choices[0].delta
  141. if hasattr(delta, 'content') and delta.content:
  142. collected_content.append(delta.content)
  143. return "".join(collected_content)
  144. else:
  145. # 非流式处理模式
  146. if model == "deepseek-reasoner" and enable_thinking:
  147. print("使用非流式处理模式,启用推理功能")
  148. else:
  149. print("使用非流式处理模式,常规聊天")
  150. response = self.client.chat.completions.create(**api_params)
  151. if model == "deepseek-reasoner" and enable_thinking:
  152. # 推理模型的非流式处理
  153. message = response.choices[0].message
  154. # 可选:打印推理过程
  155. reasoning_content = ""
  156. if hasattr(message, 'reasoning_content') and message.reasoning_content:
  157. reasoning_content = message.reasoning_content
  158. print("Model reasoning process:\n", reasoning_content)
  159. # 方案2:返回包含 <think></think> 标签的完整内容,与 QianWen 保持一致
  160. final_content = message.content
  161. if reasoning_content:
  162. return f"<think>{reasoning_content}</think>\n\n{final_content}"
  163. else:
  164. return final_content
  165. else:
  166. # 其他模型的非流式处理(如 deepseek-chat)
  167. return response.choices[0].message.content