From 478c9846a1f967b002448cfdf157828daeeeaab2 Mon Sep 17 00:00:00 2001 From: Lynn Date: Wed, 10 Jun 2026 14:59:57 +0800 Subject: [PATCH] Fix: model list (#15860) ### What problem does this PR solve? Remove tenant_llm call in rag. ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --- admin/server/auth.py | 6 ++-- api/apps/restful_apis/chunk_api.py | 3 +- api/apps/restful_apis/user_api.py | 11 ++----- api/apps/services/dataset_api_service.py | 5 ++-- api/apps/services/models_api_service.py | 3 +- api/db/init_data.py | 1 + api/db/joint_services/tenant_model_service.py | 30 ++++++++++++++++++- api/db/joint_services/user_account_service.py | 16 ++++------ api/db/services/tenant_model_service.py | 9 ++++++ rag/app/naive.py | 6 ++-- rag/flow/parser/parser.py | 8 +++-- .../test_user_tenant_routes_unit.py | 14 ++------- 12 files changed, 64 insertions(+), 48 deletions(-) diff --git a/admin/server/auth.py b/admin/server/auth.py index 0aa96d0e37..36cf60f8f3 100644 --- a/admin/server/auth.py +++ b/admin/server/auth.py @@ -115,8 +115,6 @@ def init_default_admin(): def add_tenant_for_admin(user_info: dict, role: str): - from api.db.services.tenant_llm_service import TenantLLMService - from api.db.services.llm_service import get_init_tenant_llm tenant = { "id": user_info["id"], @@ -135,10 +133,10 @@ def add_tenant_for_admin(user_info: dict, role: str): "role": role } - tenant_llm = get_init_tenant_llm(user_info["id"]) + # tenant_llm = get_init_tenant_llm(user_info["id"]) TenantService.insert(**tenant) UserTenantService.insert(**usr_tenant) - TenantLLMService.insert_many(tenant_llm) + # TenantLLMService.insert_many(tenant_llm) logging.info( f"Added tenant for email: {user_info['email']}, A default tenant has been set; changing the default models after login is strongly recommended.") diff --git a/api/apps/restful_apis/chunk_api.py b/api/apps/restful_apis/chunk_api.py index d2f803f7bc..8e5058bcfa 100644 --- a/api/apps/restful_apis/chunk_api.py +++ b/api/apps/restful_apis/chunk_api.py @@ -25,6 +25,7 @@ from quart import request from api.apps import login_required from api.db.joint_services.tenant_model_service import ( + split_model_name, get_model_config_from_provider_instance, get_tenant_default_model_by_type, ) @@ -266,7 +267,7 @@ async def retrieval_test(tenant_id): if not KnowledgebaseService.accessible(kb_id=id, user_id=tenant_id): return get_error_data_result(f"You don't own the dataset {id}.") kbs = KnowledgebaseService.get_by_ids(kb_ids) - embd_nms = list(set([TenantLLMService.split_model_name_and_factory(kb.embd_id)[0] for kb in kbs])) + embd_nms = list(set([split_model_name(kb.embd_id)[0] for kb in kbs])) if len(embd_nms) != 1: return get_result(message="Datasets use different embedding models.", code=RetCode.DATA_ERROR) if "question" not in req: diff --git a/api/apps/restful_apis/user_api.py b/api/apps/restful_apis/user_api.py index b5aedf3d6e..95e318e123 100644 --- a/api/apps/restful_apis/user_api.py +++ b/api/apps/restful_apis/user_api.py @@ -27,10 +27,7 @@ from werkzeug.security import check_password_hash, generate_password_hash from api.apps.auth import get_auth_client from api.db import FileType, UserTenantRole -from api.db.db_models import TenantLLM from api.db.services.file_service import FileService -from api.db.services.llm_service import get_init_tenant_llm -from api.db.services.tenant_llm_service import TenantLLMService from api.db.services.user_service import TenantService, UserService, UserTenantService from common.time_utils import current_timestamp, datetime_format, get_format_time from common.misc_utils import download_img, get_uuid @@ -412,10 +409,6 @@ def rollback_user_registration(user_id): UserTenantService.delete_by_id(u[0].id) except Exception: pass - try: - TenantLLM.delete().where(TenantLLM.tenant_id == user_id).execute() - except Exception: - pass def user_register(user_id, user): @@ -448,13 +441,13 @@ def user_register(user_id, user): "location": "", } - tenant_llm = get_init_tenant_llm(user_id) + # tenant_llm = get_init_tenant_llm(user_id) if not UserService.save(**user): return None TenantService.insert(**tenant) UserTenantService.insert(**usr_tenant) - TenantLLMService.insert_many(tenant_llm) + # TenantLLMService.insert_many(tenant_llm) FileService.insert(file) return UserService.query(email=user["email"]) diff --git a/api/apps/services/dataset_api_service.py b/api/apps/services/dataset_api_service.py index 6cbc9770d7..a02e3900b5 100644 --- a/api/apps/services/dataset_api_service.py +++ b/api/apps/services/dataset_api_service.py @@ -29,7 +29,6 @@ from api.db.services.knowledgebase_service import KnowledgebaseService from api.db.services.connector_service import Connector2KbService from api.db.services.task_service import GRAPH_RAPTOR_FAKE_DOC_ID, TaskService from api.db.services.user_service import TenantService, UserService, UserTenantService -from api.db.services.tenant_llm_service import TenantLLMService from common.constants import FileSource, StatusEnum from api.utils.api_utils import deep_merge, get_parser_config, remap_dictionary_keys, verify_embedding_availability @@ -1276,7 +1275,7 @@ async def search_datasets(tenant_id: str, req: dict): :param req: search request containing dataset_ids and other params :return: (success, result) or (success, error_message) """ - from api.db.joint_services.tenant_model_service import get_tenant_default_model_by_type + from api.db.joint_services.tenant_model_service import get_tenant_default_model_by_type, split_model_name from api.db.services.doc_metadata_service import DocMetadataService from api.db.services.llm_service import LLMBundle from api.db.services.search_service import SearchService @@ -1315,7 +1314,7 @@ async def search_datasets(tenant_id: str, req: dict): return False, "Datasets not found!" # All datasets must use the same embedding model - embd_nms = list(set([TenantLLMService.split_model_name_and_factory(kb.embd_id)[0] for kb in kbs])) + embd_nms = list(set([split_model_name(kb.embd_id)[0] for kb in kbs])) if len(embd_nms) != 1: return False, "Datasets use different embedding models." diff --git a/api/apps/services/models_api_service.py b/api/apps/services/models_api_service.py index 19c533d872..e32c693b69 100644 --- a/api/apps/services/models_api_service.py +++ b/api/apps/services/models_api_service.py @@ -16,7 +16,7 @@ import os import logging -from api.db.joint_services.tenant_model_service import ensure_mineru_from_env, ensure_paddleocr_from_env +from api.db.joint_services.tenant_model_service import ensure_mineru_from_env, ensure_paddleocr_from_env, ensure_opendataloader_from_env from common.constants import ActiveStatusEnum, LLMType from common.settings import FACTORY_LLM_INFOS from api.db.services.tenant_model_provider_service import TenantModelProviderService @@ -304,6 +304,7 @@ def list_tenant_added_models(tenant_id: str, model_type_filter: str=None): ensure_mineru_from_env(tenant_id) ensure_paddleocr_from_env(tenant_id) + ensure_opendataloader_from_env(tenant_id) if model_type_filter: model_type_filter = model_type_filter.lower() diff --git a/api/db/init_data.py b/api/db/init_data.py index ec200a931d..93c92cc64f 100644 --- a/api/db/init_data.py +++ b/api/db/init_data.py @@ -107,6 +107,7 @@ def init_superuser(nickname=DEFAULT_SUPERUSER_NICKNAME, email=DEFAULT_SUPERUSER_ def init_llm_factory(): + # todo deprecated LLMFactoriesService.filter_delete([1 == 1]) factory_llm_infos = settings.FACTORY_LLM_INFOS for factory_llm_info in factory_llm_infos: diff --git a/api/db/joint_services/tenant_model_service.py b/api/db/joint_services/tenant_model_service.py index bccd7ecdbb..53a3d8e1c2 100644 --- a/api/db/joint_services/tenant_model_service.py +++ b/api/db/joint_services/tenant_model_service.py @@ -18,7 +18,7 @@ import os import enum import json from common import settings -from common.constants import ActiveStatusEnum, LLMType, MINERU_DEFAULT_CONFIG, MINERU_ENV_KEYS, PADDLEOCR_DEFAULT_CONFIG, PADDLEOCR_ENV_KEYS +from common.constants import ActiveStatusEnum, LLMType, MINERU_DEFAULT_CONFIG, MINERU_ENV_KEYS, OPENDATALOADER_DEFAULT_CONFIG, OPENDATALOADER_ENV_KEYS, PADDLEOCR_DEFAULT_CONFIG, PADDLEOCR_ENV_KEYS from api.db.services.tenant_llm_service import TenantService from api.db.services.tenant_model_provider_service import TenantModelProviderService from api.db.services.tenant_model_instance_service import TenantModelInstanceService @@ -294,3 +294,31 @@ def delete_models_by_instance_ids(instance_ids: list[str]): def delete_instances_by_provider_ids(provider_ids: list[str]): return TenantModelInstanceService.delete_by_provider_ids(provider_ids) + + +def ensure_opendataloader_from_env(tenant_id: str) -> str | None: + return _ensure_ocr_provider_from_env( + tenant_id, + "OpenDataLoader", + "opendataloader-from-env", + _collect_env_config(OPENDATALOADER_ENV_KEYS, OPENDATALOADER_DEFAULT_CONFIG), + ) + + +def get_models_by_tenant_and_provider_and_model_type(tenant_id: str, provider_name: str, model_type: str): + """ + Query TenantModel records by tenant_id, provider_name and model_name. + Returns all matching model records under all instances of the specified provider. + """ + provider_obj = TenantModelProviderService.get_by_tenant_id_and_provider_name(tenant_id, provider_name) + if not provider_obj: + return [] + instances = TenantModelInstanceService.get_all_by_provider_id(provider_obj.id) + if not instances: + return [] + results = [] + for inst in instances: + models = TenantModelService.get_by_provider_id_and_instance_id_and_model_type(provider_obj.id, inst.id, model_type) + if models: + results.extend(models) + return results diff --git a/api/db/joint_services/user_account_service.py b/api/db/joint_services/user_account_service.py index 6f992576a7..91e6e38362 100644 --- a/api/db/joint_services/user_account_service.py +++ b/api/db/joint_services/user_account_service.py @@ -27,12 +27,10 @@ from api.db.services.doc_metadata_service import DocMetadataService from api.db.services.file2document_service import File2DocumentService from api.db.services.knowledgebase_service import KnowledgebaseService from api.db.services.langfuse_service import TenantLangfuseService -from api.db.services.llm_service import get_init_tenant_llm from api.db.services.file_service import FileService from api.db.services.mcp_server_service import MCPServerService from api.db.services.search_service import SearchService from api.db.services.task_service import TaskService -from api.db.services.tenant_llm_service import TenantLLMService from api.db.services.user_canvas_version import UserCanvasVersionService from api.db.services.user_service import TenantService, UserService, UserTenantService from api.db.services.memory_service import MemoryService @@ -90,14 +88,14 @@ def create_new_user(user_info: dict) -> dict: "location": "", } try: - tenant_llm = get_init_tenant_llm(user_id) + # tenant_llm = get_init_tenant_llm(user_id) if not UserService.save(**user_info): return {"success": False} TenantService.insert(**tenant) UserTenantService.insert(**usr_tenant) - TenantLLMService.insert_many(tenant_llm) + # TenantLLMService.insert_many(tenant_llm) FileService.insert(file) return { @@ -123,10 +121,6 @@ def create_new_user(user_info: dict) -> dict: UserTenantService.delete_by_id(u[0].id) except Exception as e: logging.exception(e) - try: - TenantLLMService.delete_by_tenant_id(user_id) - except Exception as e: - logging.exception(e) try: FileService.delete_by_id(file["id"]) except Exception as e: @@ -209,9 +203,9 @@ def delete_user_data(user_id: str) -> dict: # step1.1.7 delete search search_delete_res = SearchService.delete_by_tenant_id(usr.id) done_msg += f"- Deleted {search_delete_res} search records.\n" - # step1.2 delete tenant_llm and tenant_langfuse - llm_delete_res = TenantLLMService.delete_by_tenant_id(tenant_id) - done_msg += f"- Deleted {llm_delete_res} tenant-LLM records.\n" + # step1.2 delete tenant_langfuse + # llm_delete_res = TenantLLMService.delete_by_tenant_id(tenant_id) + # done_msg += f"- Deleted {llm_delete_res} tenant-LLM records.\n" langfuse_delete_res = TenantLangfuseService.delete_ty_tenant_id(tenant_id) done_msg += f"- Deleted {langfuse_delete_res} langfuse records.\n" try: diff --git a/api/db/services/tenant_model_service.py b/api/db/services/tenant_model_service.py index 00aa0e659b..e75390956d 100644 --- a/api/db/services/tenant_model_service.py +++ b/api/db/services/tenant_model_service.py @@ -35,6 +35,15 @@ class TenantModelService(CommonService): cls.model.model_name == model_name ) + @classmethod + @DB.connection_context() + def get_by_provider_id_and_instance_id_and_model_type(cls, provider_id, instance_id, model_type): + return cls.model.get_or_none( + cls.model.provider_id == provider_id, + cls.model.instance_id == instance_id, + cls.model.model_type == model_type + ) + @classmethod @DB.connection_context() def get_models_by_instance_id(cls, instance_id): diff --git a/rag/app/naive.py b/rag/app/naive.py index ff0fa3d3f9..a6db0d96d2 100644 --- a/rag/app/naive.py +++ b/rag/app/naive.py @@ -219,10 +219,10 @@ def by_opendataloader( if tenant_id: if not opendataloader_llm_name: try: - from api.db.services.tenant_llm_service import TenantLLMService + from api.db.joint_services.tenant_model_service import get_models_by_tenant_and_provider_and_model_type, ensure_opendataloader_from_env - env_name = TenantLLMService.ensure_opendataloader_from_env(tenant_id) - candidates = TenantLLMService.query(tenant_id=tenant_id, llm_factory="OpenDataLoader", model_type=LLMType.OCR) + env_name = ensure_opendataloader_from_env(tenant_id) + candidates = get_models_by_tenant_and_provider_and_model_type(tenant_id=tenant_id, provider_name="OpenDataLoader", model_type=LLMType.OCR) if candidates: opendataloader_llm_name = candidates[0].llm_name elif env_name: diff --git a/rag/flow/parser/parser.py b/rag/flow/parser/parser.py index b765675b96..e8830d5bcc 100644 --- a/rag/flow/parser/parser.py +++ b/rag/flow/parser/parser.py @@ -446,9 +446,11 @@ class Parser(ProcessBase): tenant_id = self._canvas._tenant_id if not tenant_id: return None - from api.db.services.tenant_llm_service import TenantLLMService - env_name = TenantLLMService.ensure_opendataloader_from_env(tenant_id) - candidates = TenantLLMService.query(tenant_id=tenant_id, llm_factory="OpenDataLoader", model_type=LLMType.OCR.value) + + from api.db.joint_services.tenant_model_service import ensure_opendataloader_from_env, get_models_by_tenant_and_provider_and_model_type + + env_name = ensure_opendataloader_from_env(tenant_id) + candidates = get_models_by_tenant_and_provider_and_model_type(tenant_id=tenant_id, provider_name="OpenDataLoader", model_type=LLMType.OCR) if candidates: return candidates[0].llm_name return env_name diff --git a/test/testcases/restful_api/test_user_tenant_routes_unit.py b/test/testcases/restful_api/test_user_tenant_routes_unit.py index ec9af40790..30dffe0c01 100644 --- a/test/testcases/restful_api/test_user_tenant_routes_unit.py +++ b/test/testcases/restful_api/test_user_tenant_routes_unit.py @@ -1036,23 +1036,14 @@ def test_logout_setting_profile_matrix_unit(monkeypatch): def test_registration_helpers_and_register_route_matrix_unit(monkeypatch): module = _load_user_app(monkeypatch) - deleted = {"user": 0, "tenant": 0, "user_tenant": 0, "tenant_llm": 0} + deleted = {"user": 0, "tenant": 0, "user_tenant": 0} monkeypatch.setattr(module.UserService, "delete_by_id", lambda _user_id: deleted.__setitem__("user", deleted["user"] + 1)) monkeypatch.setattr(module.TenantService, "delete_by_id", lambda _tenant_id: deleted.__setitem__("tenant", deleted["tenant"] + 1)) monkeypatch.setattr(module.UserTenantService, "query", lambda **_kwargs: [SimpleNamespace(id="ut-1")]) monkeypatch.setattr(module.UserTenantService, "delete_by_id", lambda _ut_id: deleted.__setitem__("user_tenant", deleted["user_tenant"] + 1)) - class _DeleteQuery: - def where(self, *_args, **_kwargs): - return self - - def execute(self): - deleted["tenant_llm"] += 1 - return 1 - - monkeypatch.setattr(module.TenantLLM, "delete", lambda: _DeleteQuery()) module.rollback_user_registration("user-1") - assert deleted == {"user": 1, "tenant": 1, "user_tenant": 1, "tenant_llm": 1}, deleted + assert deleted == {"user": 1, "tenant": 1, "user_tenant": 1}, deleted monkeypatch.setattr(module.UserService, "delete_by_id", lambda _user_id: (_ for _ in ()).throw(RuntimeError("u boom"))) monkeypatch.setattr(module.TenantService, "delete_by_id", lambda _tenant_id: (_ for _ in ()).throw(RuntimeError("t boom"))) @@ -1062,7 +1053,6 @@ def test_registration_helpers_and_register_route_matrix_unit(monkeypatch): def where(self, *_args, **_kwargs): raise RuntimeError("llm boom") - monkeypatch.setattr(module.TenantLLM, "delete", lambda: _RaisingDeleteQuery()) module.rollback_user_registration("user-2") monkeypatch.setattr(module.UserService, "save", lambda **_kwargs: False)