deepdata: core product code (backend, frontend, runtime, deepflow module)

This commit is contained in:
figmar
2026-08-30 19:23:38 +08:00
commit bd3db30be9
1405 changed files with 271727 additions and 0 deletions
@@ -0,0 +1,7 @@
# app/core/llm/__init__.py
"""
LangChain 模型工厂:统一创建 Chat、Embedding 及健康检查,便于各模块复用。
"""
from .factory import LLMFactory
__all__ = ["LLMFactory"]
@@ -0,0 +1,124 @@
# app/module/shared/llm/factory.py
"""
LangChain 模型工厂:基于 OpenAI 兼容接口封装 Chat / Embedding 的创建、健康检查与同步调用。
- DashScope compatible‑mode:重写embedding逻辑,规避tiktoken token数组输入问题
- 其他OpenAI兼容服务商:完全使用原生 OpenAIEmbeddings / ChatOpenAI
"""
from typing import Literal, List, Optional
import httpx
from langchain_core.language_models import BaseChatModel
from langchain_core.embeddings import Embeddings
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from pydantic import SecretStr
class DashScopeOpenAIEmbeddings(OpenAIEmbeddings, Embeddings):
"""
仅用于阿里云DashScope compatible‑mode
1. 绕过原生tiktoken逻辑,直接传入原始字符串,不传入token数字数组
2. 适配新版openai SDK返回Pydantic Embedding对象,使用属性 .embedding
"""
def _get_len_safe_embeddings(self, texts: List[str], *, engine: str, **kwargs) -> List[List[float]]:
batch_size = self.chunk_size
embeddings: List[List[float]] = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i + batch_size]
resp = self.client.create(
input=batch,
model=self.model,
encoding_format="float",
)
embeddings.extend([data.embedding for data in resp.data])
return embeddings
class LLMFactory:
@staticmethod
def _is_dashscope_compatible(base_url: Optional[str]) -> bool:
if not base_url:
return False
return "dashscope.aliyuncs.com/compatible-mode" in base_url
@staticmethod
def create_chat(
model_name: str,
base_url: str,
api_key: str | None = None,
) -> BaseChatModel:
"""创建对话模型,兼容 OpenAI 及任意 base_url 的 OpenAI 兼容服务。"""
# DashScope容器环境关闭SSL校验;其余服务商使用默认httpx客户端(开启证书校验)
if LLMFactory._is_dashscope_compatible(base_url):
http_client = httpx.Client(verify=False)
else:
http_client = None
return ChatOpenAI(
model=model_name,
base_url=base_url or None,
api_key=SecretStr(api_key or ""),
http_client=http_client,
)
@staticmethod
def create_embedding(
model_name: str,
base_url: str,
api_key: str | None = None,
) -> Embeddings:
is_dashscope = LLMFactory._is_dashscope_compatible(base_url)
# DashScope才关闭SSL校验,其他服务商走默认SSL校验
if is_dashscope:
http_client = httpx.Client(verify=False)
else:
http_client = None
kwargs = {
"model": model_name,
"base_url": base_url or None,
"api_key": SecretStr(api_key or ""),
"http_client": http_client,
}
# 仅DashScope注入encoding_format="float",其他服务商不强制注入,避免参数不兼容
if is_dashscope:
import inspect
sig = inspect.signature(OpenAIEmbeddings.__init__)
if "encoding_format" in sig.parameters:
kwargs["encoding_format"] = "float"
return DashScopeOpenAIEmbeddings(**kwargs)
# 其余所有OpenAI兼容模型,走原生实现
return OpenAIEmbeddings(**kwargs)
@staticmethod
def check_health(
model_name: str,
base_url: str,
api_key: str | None,
model_type: Literal["CHAT", "EMBEDDING"] | str,
) -> None:
"""对配置做一次最小化调用进行健康检查,失败则抛出。"""
if model_type == "CHAT":
model = LLMFactory.create_chat(model_name, base_url, api_key)
model.invoke("hello")
else:
model = LLMFactory.create_embedding(model_name, base_url, api_key)
model.embed_query("text")
@staticmethod
def get_embedding_dimension(
model_name: str,
base_url: str,
api_key: str | None = None,
) -> int:
"""创建 Embedding 模型并返回向量维度。"""
emb = LLMFactory.create_embedding(model_name, base_url, api_key)
return len(emb.embed_query("text"))
@staticmethod
def invoke_sync(chat_model: BaseChatModel, prompt: str) -> str:
"""同步调用对话模型并返回 content,供 run_in_executor 等场景使用。"""
return chat_model.invoke(prompt).content