from __future__ import annotations from .shared import * class LLMGenerateDbChatMixin: async def _generate_with_db(self, db: AsyncSession, prompt: str, **kwargs: Any) -> str: started_at = time.perf_counter() tenant_id = int(kwargs.get("tenant_id") or 1) function_name = str(kwargs.get("function_name") or "llm_generate") temperature = float(kwargs.get("temperature") or 0.2) max_tokens = int(kwargs.get("max_tokens") or 1024) use_prompt_profile = bool(kwargs.get("use_prompt_profile", True)) response_mode = str(kwargs.get("response_mode") or "complete").strip().lower() or "complete" routing_meta = _normalize_routing_meta(kwargs.get("routing_meta")) response_text = "" status = "success" routing_decision = "primary_engine" engine_meta: dict[str, Any] = {} prompt_profile = {"role_name": "", "system_prompt": ""} prompt_with_context = await self._inject_model_context_bundle_prompt( db=db, tenant_id=tenant_id, function_name=function_name, prompt=prompt, ) merged_prompt = self._merge_prompt_with_profile( prompt=prompt_with_context, prompt_profile=prompt_profile, function_name=function_name, ) def _log_stub_failure(error_obj: Exception, *, used_stub: bool = False) -> None: elapsed_ms = (time.perf_counter() - started_at) * 1000 routing_meta = _read_engine_routing_meta(engine_meta) outcome = "兜底 stub" if used_stub else "显式报错" logger.warning( "[LLM_FAIL] 生成失败 → %s function=%s route=%s error=%r duration_ms=%.0f", outcome, function_name, _routing_meta_log_text(routing_meta) or "unknown", error_obj, elapsed_ms, ) try: if use_prompt_profile: prompt_profile = await self._resolve_active_prompt_profile(db, tenant_id=tenant_id) merged_prompt = self._merge_prompt_with_profile( prompt=prompt_with_context, prompt_profile=prompt_profile, function_name=function_name, ) engine = await self._resolve_engine_for_call( db, tenant_id=tenant_id, function_name=function_name, routing_meta=routing_meta, ) engine_meta = engine provider = str(engine.get("provider") or "") model = str(engine.get("model") or "") response_text = await self._chat_completion( provider=provider, prompt=prompt_with_context, system_prompt=prompt_profile.get("system_prompt") or "", api_key=str(engine.get("api_key") or ""), base_url=str(engine.get("base_url") or ""), model=model, temperature=temperature, max_tokens=max_tokens, function_name=function_name, response_mode=response_mode, routing_meta=routing_meta, ) if not response_text.strip(): raise ValueError("primary_engine_empty_response") if self._call_is_invalid_structured_output( function_name=function_name, response_text=response_text, routing_meta=routing_meta, ): raise ValueError("invalid_structured_output") return response_text except Exception as exc: failover_response, failover_engine = await self._retry_with_high_tier_after_low_model_failure( db=db, tenant_id=tenant_id, function_name=function_name, failed_engine=engine_meta, prompt=prompt_with_context, system_prompt=str(prompt_profile.get("system_prompt") or ""), temperature=temperature, max_tokens=max_tokens, response_mode=response_mode, error=exc, routing_meta=routing_meta, ) if failover_response and isinstance(failover_engine, dict): routing_decision = "low_to_high_escalated" status = "success_failover" response_text = failover_response engine_meta = failover_engine return failover_response status = "failed" reason_text = self._build_model_error_message( function_name=function_name, routing_meta=_read_engine_routing_meta(engine_meta), error=exc, ) response_text = reason_text _log_stub_failure(exc, used_stub=False) raise RuntimeError(reason_text) from exc finally: try: merged_prompt = self._merge_prompt_with_profile( prompt=prompt_with_context, prompt_profile=prompt_profile, function_name=function_name, ) await self._log_ai_call( tenant_id=tenant_id, function_name=function_name, prompt=merged_prompt, response=response_text, status=status, provider=str(engine_meta.get("provider") or ""), model=str(engine_meta.get("model") or ""), routing_meta=_read_engine_routing_meta(engine_meta), ) routing_meta = _read_engine_routing_meta(engine_meta) if ( routing_meta.get("planned_tier") and routing_meta.get("executed_tier") and routing_meta.get("planned_tier") != routing_meta.get("executed_tier") ): _runtime_log( "LLM路由", ( f"function={function_name}, {_routing_meta_log_text(routing_meta)}" ), ) except Exception as log_exc: _runtime_log("LLM", f"调用日志写入失败:{log_exc}")