refactor(aibox): make profile reasoning_enabled a constructor param (M3)
Profile-level reasoning_enabled was attached as an instance attribute after construction only when a profile matched; the base class never declared it and consumers probed with double getattr. Any code that accidentally set client.reasoning_enabled would silently override the global switch. The flag is now an explicit LLMClient constructor parameter with three-state semantics: True/False (profile-level explicit, or the global api.reasoning_enabled value concretized when the profile omits the field) and None (no profile -> consumer falls back to global). create_llm_client passes it at construction and no longer mutates the client afterwards; DeepSeekChat._reasoning_enabled simplifies to a single getattr probe that still tolerates clients without the attr. Tests: TestM3ReasoningConstructor (4 cases) covering profile True, profile-omitted -> global concretized, base default None, and the None -> global fallback at the consumer; one legacy assertion updated to the new contract (attribute exists, value None). Full suite 299 passed.
This commit is contained in:
1 parent
5f3ca9a246
commit
a583f44d5d
4 files changed
+71
-17
No files matched your search
+13
-7
@@ -29,13 +29,16 @@ class LLMClient(ABC):
|
||||
"""大模型客户端抽象基类。子类需实现流式/非流式两种调用,并归一化为统一事件格式。"""
|
||||
|
||||
def __init__(self, api_key: str, model: str, base_url: str,
|
||||
timeout: int, config=None, logger=None):
|
||||
timeout: int, config=None, logger=None,
|
||||
reasoning_enabled: bool = None):
|
||||
self.api_key = api_key
|
||||
self.model = model
|
||||
self.base_url = base_url
|
||||
self.timeout = timeout
|
||||
self.config = config # 可选,用于读取代理等动态配置
|
||||
self.logger = logger # 可选,用于日志输出
|
||||
# M3:档案级思考模式开关为构造契约;None = 未配置(消费方回退全局 api.reasoning_enabled)
|
||||
self.reasoning_enabled = reasoning_enabled
|
||||
# 当前活动的 HTTP 响应引用,供 cancel() 强制关闭底层连接以中断阻塞读取
|
||||
self._current_response = None
|
||||
|
||||
@@ -99,8 +102,10 @@ class DeepSeekClient(LLMClient):
|
||||
"""
|
||||
|
||||
def __init__(self, api_key: str, model: str, base_url: str,
|
||||
timeout: int = 30, config=None, logger=None):
|
||||
super().__init__(api_key, model, base_url, timeout, config, logger)
|
||||
timeout: int = 30, config=None, logger=None,
|
||||
reasoning_enabled: bool = None):
|
||||
super().__init__(api_key, model, base_url, timeout, config, logger,
|
||||
reasoning_enabled=reasoning_enabled)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
@@ -362,11 +367,12 @@ def create_llm_client(config, api_key: Optional[str] = None,
|
||||
timeout=timeout,
|
||||
config=config,
|
||||
logger=logger,
|
||||
# M3:档案级思考模式作为构造参数(None=未配置,消费方回退全局),
|
||||
# 不再构造后挂实例属性——契约显式化,杜绝外部误设属性静默覆盖全局
|
||||
reasoning_enabled=(profile.get("reasoning_enabled",
|
||||
config.get("api.reasoning_enabled", False))
|
||||
if profile is not None else None),
|
||||
)
|
||||
# 档案级思考模式开关(未配置时回退全局 api.reasoning_enabled)
|
||||
if profile is not None:
|
||||
client.reasoning_enabled = profile.get(
|
||||
"reasoning_enabled", config.get("api.reasoning_enabled", False))
|
||||
return client
|
||||
|
||||
# 其他 OpenAI 兼容厂商:可直接复用 DeepSeekClient(继承其协议解析),
|
||||
|
||||
Reference in new issue
Block a user