feat:修改nl2sql功能
This commit is contained in:
+28
-7
@@ -25,6 +25,7 @@ logger = logging.getLogger("tool.llm")
|
||||
FALLBACK_REPLY = "抱歉,服务暂时不可用,请稍后再试,或拨打客服热线 400-XXX-XXXX。"
|
||||
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Backend:
|
||||
"""一个 OpenAI 兼容端点及其模型;name 为 ollama / api。"""
|
||||
@@ -34,6 +35,7 @@ class Backend:
|
||||
chat_model: str
|
||||
embed_model: str
|
||||
api_key: str = ""
|
||||
api_trust_env: bool = True
|
||||
|
||||
@property
|
||||
def is_ollama(self) -> bool:
|
||||
@@ -50,7 +52,8 @@ class Backend:
|
||||
"""ollama 走本机端点,必须绕过系统代理:httpx 会读取 Windows 系统代理,
|
||||
但不识别其 ProxyOverride 白名单,localhost 请求会被转发到代理并返回 502。
|
||||
API 后端保留 trust_env,远端接口可能依赖代理。"""
|
||||
return httpx.AsyncClient(timeout=timeout, trust_env=not self.is_ollama)
|
||||
|
||||
return httpx.AsyncClient(timeout=timeout, trust_env=self.api_trust_env if not self.is_ollama else False)
|
||||
|
||||
|
||||
def resolve_backends(cfg: LLMCfg) -> list[Backend]:
|
||||
@@ -61,6 +64,7 @@ def resolve_backends(cfg: LLMCfg) -> list[Backend]:
|
||||
base_url=cfg.ollama_base.rstrip("/") + "/v1",
|
||||
chat_model=cfg.ollama_chat_model,
|
||||
embed_model=cfg.ollama_embed_model,
|
||||
api_trust_env=False,
|
||||
)
|
||||
if cfg.ollama_base and cfg.ollama_chat_model
|
||||
else None
|
||||
@@ -72,6 +76,7 @@ def resolve_backends(cfg: LLMCfg) -> list[Backend]:
|
||||
chat_model=cfg.api_chat_model,
|
||||
embed_model=cfg.api_embed_model,
|
||||
api_key=cfg.api_key,
|
||||
api_trust_env=cfg.api_trust_env,
|
||||
)
|
||||
if cfg.api_key and cfg.api_base and cfg.api_chat_model
|
||||
else None
|
||||
@@ -224,8 +229,8 @@ class LLMClient:
|
||||
) or backend.embed_model
|
||||
if not embed_model:
|
||||
raise LLMFailError(f"backend={backend.name} 未配置 embed 模型")
|
||||
is_dashscope_compatible = "/compatible-mode/" in backend.base_url.lower()
|
||||
if is_dashscope_compatible:
|
||||
is_dashscope_multimodal = "vision" in embed_model.lower() or "multimodal" in embed_model.lower()
|
||||
if is_dashscope_multimodal:
|
||||
base_url = backend.base_url.rstrip("/")
|
||||
marker = "/compatible-mode/v1"
|
||||
if base_url.lower().endswith(marker):
|
||||
@@ -242,11 +247,27 @@ class LLMClient:
|
||||
"input": texts,
|
||||
"dimensions": self.cfg.embed_dimensions,
|
||||
}
|
||||
response = None
|
||||
max_retries = max(1, int(getattr(self.cfg, "max_retries", 1)))
|
||||
retry_backoff_sec = float(getattr(self.cfg, "retry_backoff_sec", 0))
|
||||
async with backend.client(self.cfg.timeout) as client:
|
||||
r = await client.post(url, headers=backend.headers, json=payload)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
if is_dashscope_compatible:
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = await client.post(
|
||||
url,
|
||||
headers=backend.headers,
|
||||
json=payload,
|
||||
)
|
||||
response.raise_for_status()
|
||||
break
|
||||
except Exception:
|
||||
if attempt == max_retries - 1:
|
||||
raise
|
||||
await asyncio.sleep(retry_backoff_sec * (2**attempt))
|
||||
if response is None: # pragma: no cover - defensive guard
|
||||
raise LLMFailError("Embedding 请求未返回响应")
|
||||
data = response.json()
|
||||
if is_dashscope_multimodal:
|
||||
embeddings = data["output"]["embeddings"]
|
||||
return [
|
||||
item["embedding"]
|
||||
|
||||
Reference in New Issue
Block a user