This is an automated email from the ASF dual-hosted git repository.

yongzao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 46a0c6ac0b1 [AINode] Concurrent inference bug fix (#16595)
46a0c6ac0b1 is described below

commit 46a0c6ac0b13e0ff504662f957ea987647265589
Author: Yongzao <[email protected]>
AuthorDate: Fri Oct 17 08:53:19 2025 +0800

    [AINode] Concurrent inference bug fix (#16595)
---
 .../ainode/it/AINodeConcurrentInferenceIT.java     | 71 +++++++++++-----------
 .../iotdb/ainode/it/AINodeInferenceSQLIT.java      |  4 +-
 .../core/inference/inference_request_pool.py       | 22 ++++---
 .../iotdb/ainode/core/inference/pool_controller.py | 21 +++++--
 .../iotdb/ainode/core/inference/pool_group.py      |  6 ++
 .../pool_scheduler/abstract_pool_scheduler.py      |  9 +--
 .../pool_scheduler/basic_pool_scheduler.py         | 61 ++++++++++---------
 .../iotdb/ainode/core/manager/inference_manager.py |  6 +-
 .../iotdb/ainode/core/manager/model_manager.py     |  3 +
 .../iotdb/ainode/core/model/model_storage.py       |  7 +++
 .../consensus/response/model/GetModelInfoResp.java |  8 ---
 .../iotdb/confignode/manager/ModelManager.java     | 38 +++---------
 .../iotdb/confignode/persistence/ModelInfo.java    |  2 -
 .../queryengine/plan/analyze/AnalyzeVisitor.java   | 10 +--
 .../db/queryengine/plan/analyze/ModelFetcher.java  | 23 +------
 .../parameter/model/ModelInferenceDescriptor.java  |  5 +-
 .../function/tvf/ForecastTableFunction.java        | 14 +----
 .../schema/column/ColumnHeaderConstant.java        |  4 +-
 18 files changed, 145 insertions(+), 169 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeConcurrentInferenceIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeConcurrentInferenceIT.java
index b5b987594d9..a5884a3dc8d 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeConcurrentInferenceIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeConcurrentInferenceIT.java
@@ -20,14 +20,17 @@
 package org.apache.iotdb.ainode.it;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.AIClusterIT;
 import org.apache.iotdb.itbase.env.BaseEnv;
 
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,21 +39,17 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import static 
org.apache.iotdb.ainode.utils.AINodeTestUtils.concurrentInference;
 
+@RunWith(IoTDBTestRunner.class)
+@Category({AIClusterIT.class})
 public class AINodeConcurrentInferenceIT {
 
   private static final Logger LOGGER = 
LoggerFactory.getLogger(AINodeConcurrentInferenceIT.class);
 
-  private static final Map<String, String> MODEL_ID_TO_TYPE_MAP =
-      ImmutableMap.of(
-          "timer_xl", "Timer-XL",
-          "sundial", "Timer-Sundial");
-
   @BeforeClass
   public static void setUp() throws Exception {
     // Init 1C1D1A cluster environment
@@ -86,13 +85,12 @@ public class AINodeConcurrentInferenceIT {
       for (int i = 0; i < 2880; i++) {
         statement.execute(
             String.format(
-                "INSERT INTO root.AI(timestamp, s) VALUES(%d, %f)",
-                i, Math.sin(i * Math.PI / 1440)));
+                "INSERT INTO root.AI(time, s) VALUES(%d, %f)", i, Math.sin(i * 
Math.PI / 1440)));
       }
     }
   }
 
-  @Test
+  //  @Test
   public void concurrentCPUCallInferenceTest() throws SQLException, 
InterruptedException {
     concurrentCPUCallInferenceTest("timer_xl");
     concurrentCPUCallInferenceTest("sundial");
@@ -105,21 +103,21 @@ public class AINodeConcurrentInferenceIT {
       final int threadCnt = 4;
       final int loop = 10;
       final int predictLength = 96;
-      statement.execute(String.format("LOAD MODEL %s TO DEVICES \"cpu\"", 
modelId));
-      checkModelOnSpecifiedDevice(statement, 
MODEL_ID_TO_TYPE_MAP.get(modelId), "cpu");
+      statement.execute(String.format("LOAD MODEL %s TO DEVICES 'cpu'", 
modelId));
+      checkModelOnSpecifiedDevice(statement, modelId, "cpu");
       concurrentInference(
           statement,
           String.format(
-              "CALL INFERENCE(%s, \"SELECT s FROM root.AI\", 
predict_length=%d)",
+              "CALL INFERENCE(%s, 'SELECT s FROM root.AI', predict_length=%d)",
               modelId, predictLength),
           threadCnt,
           loop,
           predictLength);
-      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES \"cpu\"", 
modelId));
+      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES 'cpu'", 
modelId));
     }
   }
 
-  @Test
+  //  @Test
   public void concurrentGPUCallInferenceTest() throws SQLException, 
InterruptedException {
     concurrentGPUCallInferenceTest("timer_xl");
     concurrentGPUCallInferenceTest("sundial");
@@ -133,17 +131,17 @@ public class AINodeConcurrentInferenceIT {
       final int loop = 100;
       final int predictLength = 512;
       final String devices = "0,1";
-      statement.execute(String.format("LOAD MODEL %s TO DEVICES \"%s\"", 
modelId, devices));
-      checkModelOnSpecifiedDevice(statement, 
MODEL_ID_TO_TYPE_MAP.get(modelId), devices);
+      statement.execute(String.format("LOAD MODEL %s TO DEVICES '%s'", 
modelId, devices));
+      checkModelOnSpecifiedDevice(statement, modelId, devices);
       concurrentInference(
           statement,
           String.format(
-              "CALL INFERENCE(%s, \"SELECT s FROM root.AI\", 
predict_length=%d)",
+              "CALL INFERENCE(%s, 'SELECT s FROM root.AI', predict_length=%d)",
               modelId, predictLength),
           threadCnt,
           loop,
           predictLength);
-      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES \"0,1\"", 
modelId));
+      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES '0,1'", 
modelId));
     }
   }
 
@@ -159,8 +157,8 @@ public class AINodeConcurrentInferenceIT {
       final int threadCnt = 4;
       final int loop = 10;
       final int predictLength = 96;
-      statement.execute(String.format("LOAD MODEL %s TO DEVICES \"cpu\"", 
modelId));
-      checkModelOnSpecifiedDevice(statement, 
MODEL_ID_TO_TYPE_MAP.get(modelId), "cpu");
+      statement.execute(String.format("LOAD MODEL %s TO DEVICES 'cpu'", 
modelId));
+      checkModelOnSpecifiedDevice(statement, modelId, "cpu");
       long startTime = System.currentTimeMillis();
       concurrentInference(
           statement,
@@ -175,7 +173,7 @@ public class AINodeConcurrentInferenceIT {
           String.format(
               "Model %s concurrent inference %d reqs (%d threads, %d loops) in 
CPU takes time: %dms",
               modelId, threadCnt * loop, threadCnt, loop, endTime - 
startTime));
-      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES \"cpu\"", 
modelId));
+      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES 'cpu'", 
modelId));
     }
   }
 
@@ -192,8 +190,8 @@ public class AINodeConcurrentInferenceIT {
       final int loop = 100;
       final int predictLength = 512;
       final String devices = "0,1";
-      statement.execute(String.format("LOAD MODEL %s TO DEVICES \"%s\"", 
modelId, devices));
-      checkModelOnSpecifiedDevice(statement, 
MODEL_ID_TO_TYPE_MAP.get(modelId), devices);
+      statement.execute(String.format("LOAD MODEL %s TO DEVICES '%s'", 
modelId, devices));
+      checkModelOnSpecifiedDevice(statement, modelId, devices);
       long startTime = System.currentTimeMillis();
       concurrentInference(
           statement,
@@ -208,32 +206,35 @@ public class AINodeConcurrentInferenceIT {
           String.format(
               "Model %s concurrent inference %d reqs (%d threads, %d loops) in 
GPU takes time: %dms",
               modelId, threadCnt * loop, threadCnt, loop, endTime - 
startTime));
-      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES \"0,1\"", 
modelId));
+      statement.execute(String.format("UNLOAD MODEL %s FROM DEVICES '0,1'", 
modelId));
     }
   }
 
-  private void checkModelOnSpecifiedDevice(Statement statement, String 
modelType, String device)
+  private void checkModelOnSpecifiedDevice(Statement statement, String 
modelId, String device)
       throws SQLException, InterruptedException {
-    for (int retry = 0; retry < 10; retry++) {
-      Set<String> targetDevices = ImmutableSet.copyOf(device.split(","));
+    Set<String> targetDevices = ImmutableSet.copyOf(device.split(","));
+    LOGGER.info("Checking model: {} on target devices: {}", modelId, 
targetDevices);
+    for (int retry = 0; retry < 20; retry++) {
       Set<String> foundDevices = new HashSet<>();
       try (final ResultSet resultSet =
-          statement.executeQuery(String.format("SHOW LOADED MODELS %s", 
device))) {
+          statement.executeQuery(String.format("SHOW LOADED MODELS '%s'", 
device))) {
         while (resultSet.next()) {
-          String deviceId = resultSet.getString(1);
-          String loadedModelType = resultSet.getString(2);
-          int count = resultSet.getInt(3);
-          if (loadedModelType.equals(modelType) && 
targetDevices.contains(deviceId)) {
-            Assert.assertTrue(count > 1);
+          String deviceId = resultSet.getString("DeviceId");
+          String loadedModelId = resultSet.getString("ModelId");
+          int count = resultSet.getInt("Count(instances)");
+          LOGGER.info("Model {} found in device {}, count {}", loadedModelId, 
deviceId, count);
+          if (loadedModelId.equals(modelId) && 
targetDevices.contains(deviceId) && count > 0) {
             foundDevices.add(deviceId);
+            LOGGER.info("Model {} is loaded to device {}", modelId, device);
           }
         }
         if (foundDevices.containsAll(targetDevices)) {
+          LOGGER.info("Model {} is loaded to devices {}, start testing", 
modelId, targetDevices);
           return;
         }
       }
       TimeUnit.SECONDS.sleep(3);
     }
-    Assert.fail("Model " + modelType + " is not loaded on device " + device);
+    Assert.fail("Model " + modelId + " is not loaded on device " + device);
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeInferenceSQLIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeInferenceSQLIT.java
index 2fcc180a3e3..70f7a1d9f9e 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeInferenceSQLIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/ainode/it/AINodeInferenceSQLIT.java
@@ -95,7 +95,7 @@ public class AINodeInferenceSQLIT {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
-  @Test
+  //  @Test
   public void callInferenceTestInTree() throws SQLException {
     try (Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TREE_SQL_DIALECT);
         Statement statement = connection.createStatement()) {
@@ -209,7 +209,7 @@ public class AINodeInferenceSQLIT {
     //    }
   }
 
-  @Test
+  //  @Test
   public void errorCallInferenceTestInTree() throws SQLException {
     try (Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TREE_SQL_DIALECT);
         Statement statement = connection.createStatement()) {
diff --git 
a/iotdb-core/ainode/iotdb/ainode/core/inference/inference_request_pool.py 
b/iotdb-core/ainode/iotdb/ainode/core/inference/inference_request_pool.py
index b5f26c98358..6b054c91fe3 100644
--- a/iotdb-core/ainode/iotdb/ainode/core/inference/inference_request_pool.py
+++ b/iotdb-core/ainode/iotdb/ainode/core/inference/inference_request_pool.py
@@ -36,6 +36,8 @@ from 
iotdb.ainode.core.inference.request_scheduler.basic_request_scheduler impor
 )
 from iotdb.ainode.core.log import Logger
 from iotdb.ainode.core.manager.model_manager import ModelManager
+from iotdb.ainode.core.model.model_enums import BuiltInModelType
+from iotdb.ainode.core.model.model_info import ModelInfo
 from iotdb.ainode.core.util.gpu_mapping import 
convert_device_id_to_torch_device
 
 
@@ -58,7 +60,7 @@ class InferenceRequestPool(mp.Process):
     def __init__(
         self,
         pool_id: int,
-        model_id: str,
+        model_info: ModelInfo,
         device: str,
         config: PretrainedConfig,
         request_queue: mp.Queue,
@@ -68,7 +70,7 @@ class InferenceRequestPool(mp.Process):
     ):
         super().__init__()
         self.pool_id = pool_id
-        self.model_id = model_id
+        self.model_info = model_info
         self.config = config
         self.pool_kwargs = pool_kwargs
         self.ready_event = ready_event
@@ -121,7 +123,7 @@ class InferenceRequestPool(mp.Process):
 
         for requests in grouped_requests:
             batch_inputs = 
self._batcher.batch_request(requests).to(self.device)
-            if self.model_id == "sundial":
+            if self.model_info.model_type == BuiltInModelType.SUNDIAL.value:
                 batch_output = self._model.generate(
                     batch_inputs,
                     max_new_tokens=requests[0].max_new_tokens,
@@ -135,8 +137,7 @@ class InferenceRequestPool(mp.Process):
                     cur_batch_size = request.batch_size
                     cur_output = batch_output[offset : offset + cur_batch_size]
                     offset += cur_batch_size
-                    # TODO Here we only considered the case where batchsize=1 
in one request. If multi-variable adaptation is required in the future, 
modifications may be needed here, such as: `cur_output[0]` maybe not true in 
multi-variable scene
-                    request.write_step_output(cur_output[0].mean(dim=0))
+                    request.write_step_output(cur_output.mean(dim=1))
 
                     request.inference_pipeline.post_decode()
                     if request.is_finished():
@@ -153,7 +154,7 @@ class InferenceRequestPool(mp.Process):
                         )
                         self._waiting_queue.put(request)
 
-            elif self.model_id == "timer_xl":
+            elif self.model_info.model_type == BuiltInModelType.TIMER_XL.value:
                 batch_output = self._model.generate(
                     batch_inputs,
                     max_new_tokens=requests[0].max_new_tokens,
@@ -194,7 +195,9 @@ class InferenceRequestPool(mp.Process):
         )
         self._model_manager = ModelManager()
         self._request_scheduler.device = self.device
-        self._model = self._model_manager.load_model(self.model_id, 
{}).to(self.device)
+        self._model = self._model_manager.load_model(self.model_info.model_id, 
{}).to(
+            self.device
+        )
         self.ready_event.set()
 
         activate_daemon = threading.Thread(
@@ -207,10 +210,13 @@ class InferenceRequestPool(mp.Process):
         )
         self._threads.append(execute_daemon)
         execute_daemon.start()
+        self._logger.info(
+            f"[Inference][Device-{self.device}][Pool-{self.pool_id}] 
InferenceRequestPool for model {self.model_info.model_id} is activated."
+        )
         for thread in self._threads:
             thread.join()
         self._logger.info(
-            f"[Inference][Device-{self.device}][Pool-{self.pool_id}] 
InferenceRequestPool for model {self.model_id} exited cleanly."
+            f"[Inference][Device-{self.device}][Pool-{self.pool_id}] 
InferenceRequestPool for model {self.model_info.model_id} exited cleanly."
         )
 
     def stop(self):
diff --git a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_controller.py 
b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_controller.py
index ce04120474e..069a6b9ced6 100644
--- a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_controller.py
+++ b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_controller.py
@@ -40,6 +40,8 @@ from 
iotdb.ainode.core.inference.pool_scheduler.basic_pool_scheduler import (
     ScaleActionType,
 )
 from iotdb.ainode.core.log import Logger
+from iotdb.ainode.core.manager.model_manager import ModelManager
+from iotdb.ainode.core.model.model_enums import BuiltInModelType
 from iotdb.ainode.core.model.sundial.configuration_sundial import SundialConfig
 from iotdb.ainode.core.model.timerxl.configuration_timer import TimerConfig
 from iotdb.ainode.core.util.atmoic_int import AtomicInt
@@ -48,6 +50,7 @@ from iotdb.ainode.core.util.decorator import synchronized
 from iotdb.ainode.core.util.thread_name import ThreadName
 
 logger = Logger()
+MODEL_MANAGER = ModelManager()
 
 
 class PoolController:
@@ -169,7 +172,7 @@ class PoolController:
             for model_id, device_map in self._request_pool_map.items():
                 if device_id in device_map:
                     pool_group = device_map[device_id]
-                    device_models[model_id] = pool_group.get_pool_count()
+                    device_models[model_id] = 
pool_group.get_running_pool_count()
             result[device_id] = device_models
         return result
 
@@ -191,7 +194,7 @@ class PoolController:
         def _load_model_on_device_task(device_id: str):
             if not self.has_request_pools(model_id, device_id):
                 actions = self._pool_scheduler.schedule_load_model_to_device(
-                    model_id, device_id
+                    MODEL_MANAGER.get_model_info(model_id), device_id
                 )
                 for action in actions:
                     if action.action == ScaleActionType.SCALE_UP:
@@ -218,7 +221,7 @@ class PoolController:
         def _unload_model_on_device_task(device_id: str):
             if self.has_request_pools(model_id, device_id):
                 actions = 
self._pool_scheduler.schedule_unload_model_from_device(
-                    model_id, device_id
+                    MODEL_MANAGER.get_model_info(model_id), device_id
                 )
                 for action in actions:
                     if action.action == ScaleActionType.SCALE_DOWN:
@@ -253,13 +256,19 @@ class PoolController:
         def _expand_pool_on_device(*_):
             result_queue = mp.Queue()
             pool_id = self._new_pool_id.get_and_increment()
-            if model_id == "sundial":
+            model_info = MODEL_MANAGER.get_model_info(model_id)
+            model_type = model_info.model_type
+            if model_type == BuiltInModelType.SUNDIAL.value:
                 config = SundialConfig()
-            elif model_id == "timer_xl":
+            elif model_type == BuiltInModelType.TIMER_XL.value:
                 config = TimerConfig()
+            else:
+                raise InferenceModelInternalError(
+                    f"Unsupported model type {model_type} for loading model 
{model_id}"
+                )
             pool = InferenceRequestPool(
                 pool_id=pool_id,
-                model_id=model_id,
+                model_info=model_info,
                 device=device_id,
                 config=config,
                 request_queue=result_queue,
diff --git a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_group.py 
b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_group.py
index 96dce845585..a700dcee473 100644
--- a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_group.py
+++ b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_group.py
@@ -70,6 +70,12 @@ class PoolGroup:
     def get_pool_count(self) -> int:
         return len(self.pool_group)
 
+    def get_running_pool_count(self) -> int:
+        count = 0
+        for _, state in self.pool_states.items():
+            count += 1 if state == PoolState.RUNNING else 0
+        return count
+
     def dispatch_request(
         self, req: InferenceRequest, infer_proxy: InferenceRequestProxy
     ):
diff --git 
a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/abstract_pool_scheduler.py
 
b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/abstract_pool_scheduler.py
index 6a26d1fe15b..19d21f5822d 100644
--- 
a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/abstract_pool_scheduler.py
+++ 
b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/abstract_pool_scheduler.py
@@ -22,6 +22,7 @@ from enum import Enum
 from typing import Dict, List
 
 from iotdb.ainode.core.inference.pool_group import PoolGroup
+from iotdb.ainode.core.model.model_info import ModelInfo
 
 
 class ScaleActionType(Enum):
@@ -58,12 +59,12 @@ class AbstractPoolScheduler(ABC):
 
     @abstractmethod
     def schedule_load_model_to_device(
-        self, model_id: str, device_id: str
+        self, model_info: ModelInfo, device_id: str
     ) -> List[ScaleAction]:
         """
         Schedule a series of actions to load the model to the device.
         Args:
-            model_id: The model to be loaded.
+            model_info: The model to be loaded.
             device_id: The device to load the model to.
         Returns:
             A list of ScaleAction to be performed.
@@ -72,12 +73,12 @@ class AbstractPoolScheduler(ABC):
 
     @abstractmethod
     def schedule_unload_model_from_device(
-        self, model_id: str, device_id: str
+        self, model_info: ModelInfo, device_id: str
     ) -> List[ScaleAction]:
         """
         Schedule a series of actions to unload the model from the device.
         Args:
-            model_id: The model to be unloaded.
+            model_info: The model to be unloaded.
             device_id: The device to unload the model from.
         Returns:
             A list of ScaleAction to be performed.
diff --git 
a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/basic_pool_scheduler.py
 
b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/basic_pool_scheduler.py
index 9aefd236730..5ee1b4f0c9a 100644
--- 
a/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/basic_pool_scheduler.py
+++ 
b/iotdb-core/ainode/iotdb/ainode/core/inference/pool_scheduler/basic_pool_scheduler.py
@@ -28,6 +28,7 @@ from 
iotdb.ainode.core.inference.pool_scheduler.abstract_pool_scheduler import (
     ScaleActionType,
 )
 from iotdb.ainode.core.log import Logger
+from iotdb.ainode.core.manager.model_manager import ModelManager
 from iotdb.ainode.core.manager.utils import (
     INFERENCE_EXTRA_MEMORY_RATIO,
     INFERENCE_MEMORY_USAGE_RATIO,
@@ -35,16 +36,18 @@ from iotdb.ainode.core.manager.utils import (
     estimate_pool_size,
     evaluate_system_resources,
 )
-from iotdb.ainode.core.model.model_info import BUILT_IN_LTSM_MAP
+from iotdb.ainode.core.model.model_info import BUILT_IN_LTSM_MAP, ModelInfo
 from iotdb.ainode.core.util.gpu_mapping import 
convert_device_id_to_torch_device
 
 logger = Logger()
 
+MODEL_MANAGER = ModelManager()
+
 
 def _estimate_shared_pool_size_by_total_mem(
     device: torch.device,
-    existing_model_ids: List[str],
-    new_model_id: Optional[str] = None,
+    existing_model_infos: List[ModelInfo],
+    new_model_info: Optional[ModelInfo] = None,
 ) -> Dict[str, int]:
     """
     Estimate pool counts for (existing_model_ids + new_model_id) by equally
@@ -54,17 +57,15 @@ def _estimate_shared_pool_size_by_total_mem(
         mapping {model_id: pool_num}
     """
     # Extract unique model IDs
-    all_models = existing_model_ids + (
-        [new_model_id] if new_model_id is not None else []
+    all_models = existing_model_infos + (
+        [new_model_info] if new_model_info is not None else []
     )
 
     # Seize memory usage for each model
     mem_usages: Dict[str, float] = {}
-    for model_id in all_models:
-        model_info = BUILT_IN_LTSM_MAP.get(model_id)
-        model_type = model_info.model_type
-        mem_usages[model_id] = (
-            MODEL_MEM_USAGE_MAP[model_type] * INFERENCE_EXTRA_MEMORY_RATIO
+    for model_info in all_models:
+        mem_usages[model_info.model_id] = (
+            MODEL_MEM_USAGE_MAP[model_info.model_type] * 
INFERENCE_EXTRA_MEMORY_RATIO
         )
 
     # Evaluate system resources and get TOTAL memory
@@ -84,14 +85,14 @@ def _estimate_shared_pool_size_by_total_mem(
 
     # Calculate pool allocation for each model
     allocation: Dict[str, int] = {}
-    for model_id in all_models:
-        pool_num = int(per_model_share // mem_usages[model_id])
+    for model_info in all_models:
+        pool_num = int(per_model_share // mem_usages[model_info.model_id])
         if pool_num <= 0:
             logger.warning(
-                f"[Inference][Device-{device}] Not enough TOTAL memory to 
guarantee at least 1 pool for model {model_id}, no pool will be scheduled for 
this model. "
-                f"Per-model share={per_model_share / 1024 ** 2:.2f} MB, 
need>={mem_usages[model_id] / 1024 ** 2:.2f} MB"
+                f"[Inference][Device-{device}] Not enough TOTAL memory to 
guarantee at least 1 pool for model {model_info.model_id}, no pool will be 
scheduled for this model. "
+                f"Per-model share={per_model_share / 1024 ** 2:.2f} MB, 
need>={mem_usages[model_info.model_id] / 1024 ** 2:.2f} MB"
             )
-        allocation[model_id] = pool_num
+        allocation[model_info.model_id] = pool_num
     logger.info(
         f"[Inference][Device-{device}] Shared pool allocation (by TOTAL 
memory): {allocation}"
     )
@@ -119,39 +120,41 @@ class BasicPoolScheduler(AbstractPoolScheduler):
             return [ScaleAction(ScaleActionType.SCALE_UP, pool_num, model_id)]
 
     def schedule_load_model_to_device(
-        self, model_id: str, device_id: str
+        self, model_info: ModelInfo, device_id: str
     ) -> List[ScaleAction]:
-        existing_model_ids = [
-            existing_model_id
+        existing_model_infos = [
+            MODEL_MANAGER.get_model_info(existing_model_id)
             for existing_model_id, pool_group_map in 
self._request_pool_map.items()
-            if existing_model_id != model_id and device_id in pool_group_map
+            if existing_model_id != model_info.model_id and device_id in 
pool_group_map
         ]
         allocation_result = _estimate_shared_pool_size_by_total_mem(
             device=convert_device_id_to_torch_device(device_id),
-            existing_model_ids=existing_model_ids,
-            new_model_id=model_id,
+            existing_model_infos=existing_model_infos,
+            new_model_info=model_info,
         )
         return self._convert_allocation_result_to_scale_actions(
             allocation_result, device_id
         )
 
     def schedule_unload_model_from_device(
-        self, model_id: str, device_id: str
+        self, model_info: ModelInfo, device_id: str
     ) -> List[ScaleAction]:
-        existing_model_ids = [
-            existing_model_id
+        existing_model_infos = [
+            MODEL_MANAGER.get_model_info(existing_model_id)
             for existing_model_id, pool_group_map in 
self._request_pool_map.items()
-            if existing_model_id != model_id and device_id in pool_group_map
+            if existing_model_id != model_info.model_id and device_id in 
pool_group_map
         ]
         allocation_result = (
             _estimate_shared_pool_size_by_total_mem(
                 device=convert_device_id_to_torch_device(device_id),
-                existing_model_ids=existing_model_ids,
-                new_model_id=None,
+                existing_model_infos=existing_model_infos,
+                new_model_info=None,
             )
-            if len(existing_model_ids) > 0
-            else {model_id: 0}
+            if len(existing_model_infos) > 0
+            else {model_info.model_id: 0}
         )
+        if len(existing_model_infos) > 0:
+            allocation_result[model_info.model_id] = 0
         return self._convert_allocation_result_to_scale_actions(
             allocation_result, device_id
         )
diff --git a/iotdb-core/ainode/iotdb/ainode/core/manager/inference_manager.py 
b/iotdb-core/ainode/iotdb/ainode/core/manager/inference_manager.py
index 6f14036c8dc..841159d9b4c 100644
--- a/iotdb-core/ainode/iotdb/ainode/core/manager/inference_manager.py
+++ b/iotdb-core/ainode/iotdb/ainode/core/manager/inference_manager.py
@@ -47,6 +47,7 @@ from 
iotdb.ainode.core.inference.strategy.timerxl_inference_pipeline import (
 from iotdb.ainode.core.inference.utils import generate_req_id
 from iotdb.ainode.core.log import Logger
 from iotdb.ainode.core.manager.model_manager import ModelManager
+from iotdb.ainode.core.model.model_enums import BuiltInModelType
 from iotdb.ainode.core.model.sundial.configuration_sundial import SundialConfig
 from iotdb.ainode.core.model.sundial.modeling_sundial import 
SundialForPrediction
 from iotdb.ainode.core.model.timerxl.configuration_timer import TimerConfig
@@ -297,9 +298,10 @@ class InferenceManager:
                     data = np_data.view(np_data.dtype.newbyteorder())
                 # the inputs should be on CPU before passing to the inference 
request
                 inputs = torch.tensor(data).unsqueeze(0).float().to("cpu")
-                if model_id == "sundial":
+                model_type = 
self._model_manager.get_model_info(model_id).model_type
+                if model_type == BuiltInModelType.SUNDIAL.value:
                     inference_pipeline = 
TimerSundialInferencePipeline(SundialConfig())
-                elif model_id == "timer_xl":
+                elif model_type == BuiltInModelType.TIMER_XL.value:
                     inference_pipeline = 
TimerXLInferencePipeline(TimerConfig())
                 else:
                     raise InferenceModelInternalError(
diff --git a/iotdb-core/ainode/iotdb/ainode/core/manager/model_manager.py 
b/iotdb-core/ainode/iotdb/ainode/core/manager/model_manager.py
index d6b0f17d5c0..d84bca77c84 100644
--- a/iotdb-core/ainode/iotdb/ainode/core/manager/model_manager.py
+++ b/iotdb-core/ainode/iotdb/ainode/core/manager/model_manager.py
@@ -144,6 +144,9 @@ class ModelManager:
     def register_built_in_model(self, model_info: ModelInfo):
         self.model_storage.register_built_in_model(model_info)
 
+    def get_model_info(self, model_id: str) -> ModelInfo:
+        return self.model_storage.get_model_info(model_id)
+
     def update_model_state(self, model_id: str, state: ModelStates):
         self.model_storage.update_model_state(model_id, state)
 
diff --git a/iotdb-core/ainode/iotdb/ainode/core/model/model_storage.py 
b/iotdb-core/ainode/iotdb/ainode/core/model/model_storage.py
index 6469e802623..e346f569102 100644
--- a/iotdb-core/ainode/iotdb/ainode/core/model/model_storage.py
+++ b/iotdb-core/ainode/iotdb/ainode/core/model/model_storage.py
@@ -423,6 +423,13 @@ class ModelStorage(object):
         with self._lock_pool.get_lock(model_info.model_id).write_lock():
             self._model_info_map[model_info.model_id] = model_info
 
+    def get_model_info(self, model_id: str) -> ModelInfo:
+        with self._lock_pool.get_lock(model_id).read_lock():
+            if model_id in self._model_info_map:
+                return self._model_info_map[model_id]
+            else:
+                raise ValueError(f"Model {model_id} does not exist.")
+
     def update_model_state(self, model_id: str, state: ModelStates):
         with self._lock_pool.get_lock(model_id).write_lock():
             if model_id in self._model_info_map:
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/model/GetModelInfoResp.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/model/GetModelInfoResp.java
index 14101b95d12..cebc1301b89 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/model/GetModelInfoResp.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/model/GetModelInfoResp.java
@@ -25,12 +25,9 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.confignode.rpc.thrift.TGetModelInfoResp;
 import org.apache.iotdb.consensus.common.DataSet;
 
-import java.nio.ByteBuffer;
-
 public class GetModelInfoResp implements DataSet {
 
   private final TSStatus status;
-  private ByteBuffer serializedModelInformation;
 
   private int targetAINodeId;
   private TEndPoint targetAINodeAddress;
@@ -43,10 +40,6 @@ public class GetModelInfoResp implements DataSet {
     this.status = status;
   }
 
-  public void setModelInfo(ByteBuffer serializedModelInformation) {
-    this.serializedModelInformation = serializedModelInformation;
-  }
-
   public int getTargetAINodeId() {
     return targetAINodeId;
   }
@@ -64,7 +57,6 @@ public class GetModelInfoResp implements DataSet {
 
   public TGetModelInfoResp convertToThriftResponse() {
     TGetModelInfoResp resp = new TGetModelInfoResp(status);
-    resp.setModelInfo(serializedModelInformation);
     resp.setAiNodeAddress(targetAINodeAddress);
     return resp;
   }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ModelManager.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ModelManager.java
index 88143af03e9..4c1f94eab9e 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ModelManager.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ModelManager.java
@@ -31,10 +31,8 @@ import 
org.apache.iotdb.commons.client.exception.ClientManagerException;
 import org.apache.iotdb.commons.model.ModelInformation;
 import org.apache.iotdb.commons.model.ModelStatus;
 import org.apache.iotdb.commons.model.ModelType;
-import 
org.apache.iotdb.confignode.consensus.request.read.model.GetModelInfoPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.model.CreateModelPlan;
 import 
org.apache.iotdb.confignode.consensus.request.write.model.UpdateModelInfoPlan;
-import org.apache.iotdb.confignode.consensus.response.model.GetModelInfoResp;
 import org.apache.iotdb.confignode.exception.NoAvailableAINodeException;
 import org.apache.iotdb.confignode.persistence.ModelInfo;
 import org.apache.iotdb.confignode.rpc.thrift.TAINodeInfo;
@@ -186,33 +184,15 @@ public class ModelManager {
   }
 
   public TGetModelInfoResp getModelInfo(TGetModelInfoReq req) {
-    try {
-      GetModelInfoResp response =
-          (GetModelInfoResp) configManager.getConsensusManager().read(new 
GetModelInfoPlan(req));
-      if (response.getStatus().getCode() != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        return new TGetModelInfoResp(response.getStatus());
-      }
-      int aiNodeId = response.getTargetAINodeId();
-      if (aiNodeId != 0) {
-        response.setTargetAINodeAddress(
-            configManager.getNodeManager().getRegisteredAINode(aiNodeId));
-      } else {
-        if (configManager.getNodeManager().getRegisteredAINodes().isEmpty()) {
-          return new TGetModelInfoResp(
-              new TSStatus(TSStatusCode.GET_MODEL_INFO_ERROR.getStatusCode())
-                  .setMessage("There is no AINode available"));
-        }
-        response.setTargetAINodeAddress(
-            configManager.getNodeManager().getRegisteredAINodes().get(0));
-      }
-      return response.convertToThriftResponse();
-    } catch (ConsensusException e) {
-      LOGGER.warn("Unexpected error happened while getting model: ", e);
-      // consensus layer related errors
-      TSStatus res = new 
TSStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode());
-      res.setMessage(e.getMessage());
-      return new TGetModelInfoResp(res);
-    }
+    return new TGetModelInfoResp()
+        .setStatus(new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()))
+        .setAiNodeAddress(
+            configManager
+                .getNodeManager()
+                .getRegisteredAINodes()
+                .get(0)
+                .getLocation()
+                .getInternalEndPoint());
   }
 
   // Currently this method is only used by built-in timer_xl
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ModelInfo.java
 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ModelInfo.java
index 7f0eb6b4e88..aeada03d15c 100644
--- 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ModelInfo.java
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ModelInfo.java
@@ -46,7 +46,6 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -282,7 +281,6 @@ public class ModelInfo implements SnapshotProcessor {
       PublicBAOS buffer = new PublicBAOS();
       DataOutputStream stream = new DataOutputStream(buffer);
       modelInformation.serialize(stream);
-      getModelInfoResp.setModelInfo(ByteBuffer.wrap(buffer.getBuf(), 0, 
buffer.size()));
       // select the nodeId to process the task, currently we default use the 
first one.
       int aiNodeId = getAvailableAINodeForModel(modelName, modelType);
       if (aiNodeId == -1) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
index ea646986047..30e8426c707 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
@@ -431,17 +431,13 @@ public class AnalyzeVisitor extends 
StatementVisitor<Analysis, MPPQueryContext>
     if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
       throw new GetModelInfoException(status.getMessage());
     }
-    ModelInformation modelInformation = analysis.getModelInformation();
-    if (modelInformation == null || !modelInformation.available()) {
-      throw new SemanticException("Model " + modelId + " is not active");
-    }
 
     // set inference window if there is
     if (queryStatement.isSetInferenceWindow()) {
       InferenceWindow window = queryStatement.getInferenceWindow();
       if (InferenceWindowType.HEAD == window.getType()) {
         long windowSize = ((HeadInferenceWindow) window).getWindowSize();
-        checkWindowSize(windowSize, modelInformation);
+        //        checkWindowSize(windowSize, modelInformation);
         if (queryStatement.hasLimit() && queryStatement.getRowLimit() < 
windowSize) {
           throw new SemanticException(
               "Limit in Sql should be larger than window size in inference");
@@ -450,7 +446,7 @@ public class AnalyzeVisitor extends 
StatementVisitor<Analysis, MPPQueryContext>
         queryStatement.setRowLimit(windowSize);
       } else if (InferenceWindowType.TAIL == window.getType()) {
         long windowSize = ((TailInferenceWindow) window).getWindowSize();
-        checkWindowSize(windowSize, modelInformation);
+        //        checkWindowSize(windowSize, modelInformation);
         InferenceWindowParameter inferenceWindowParameter =
             new BottomInferenceWindowParameter(windowSize);
         analysis
@@ -458,7 +454,7 @@ public class AnalyzeVisitor extends 
StatementVisitor<Analysis, MPPQueryContext>
             .setInferenceWindowParameter(inferenceWindowParameter);
       } else if (InferenceWindowType.COUNT == window.getType()) {
         CountInferenceWindow countInferenceWindow = (CountInferenceWindow) 
window;
-        checkWindowSize(countInferenceWindow.getInterval(), modelInformation);
+        //        checkWindowSize(countInferenceWindow.getInterval(), 
modelInformation);
         InferenceWindowParameter inferenceWindowParameter =
             new CountInferenceWindowParameter(
                 countInferenceWindow.getInterval(), 
countInferenceWindow.getStep());
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ModelFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ModelFetcher.java
index 36382348b8e..dbeee4e8ed4 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ModelFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/ModelFetcher.java
@@ -24,7 +24,6 @@ import org.apache.iotdb.commons.client.IClientManager;
 import org.apache.iotdb.commons.client.exception.ClientManagerException;
 import org.apache.iotdb.commons.consensus.ConfigRegionId;
 import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
-import org.apache.iotdb.commons.model.ModelInformation;
 import org.apache.iotdb.confignode.rpc.thrift.TGetModelInfoReq;
 import org.apache.iotdb.confignode.rpc.thrift.TGetModelInfoResp;
 import org.apache.iotdb.db.exception.ainode.ModelNotFoundException;
@@ -61,17 +60,7 @@ public class ModelFetcher implements IModelFetcher {
         configNodeClientManager.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) 
{
       TGetModelInfoResp getModelInfoResp = client.getModelInfo(new 
TGetModelInfoReq(modelName));
       if (getModelInfoResp.getStatus().getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        if (getModelInfoResp.modelInfo != null && 
getModelInfoResp.isSetAiNodeAddress()) {
-          analysis.setModelInferenceDescriptor(
-              new ModelInferenceDescriptor(
-                  getModelInfoResp.aiNodeAddress,
-                  ModelInformation.deserialize(getModelInfoResp.modelInfo)));
-          return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
-        } else {
-          TSStatus status = new 
TSStatus(TSStatusCode.GET_MODEL_INFO_ERROR.getStatusCode());
-          status.setMessage(String.format("model [%s] is not available", 
modelName));
-          return status;
-        }
+        return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
       } else {
         throw new 
ModelNotFoundException(getModelInfoResp.getStatus().getMessage());
       }
@@ -86,15 +75,7 @@ public class ModelFetcher implements IModelFetcher {
         configNodeClientManager.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) 
{
       TGetModelInfoResp getModelInfoResp = client.getModelInfo(new 
TGetModelInfoReq(modelName));
       if (getModelInfoResp.getStatus().getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        if (getModelInfoResp.modelInfo != null && 
getModelInfoResp.isSetAiNodeAddress()) {
-          return new ModelInferenceDescriptor(
-              getModelInfoResp.aiNodeAddress,
-              ModelInformation.deserialize(getModelInfoResp.modelInfo));
-        } else {
-          throw new IoTDBRuntimeException(
-              String.format("model [%s] is not available", modelName),
-              TSStatusCode.GET_MODEL_INFO_ERROR.getStatusCode());
-        }
+        return new ModelInferenceDescriptor(getModelInfoResp.aiNodeAddress);
       } else {
         throw new 
ModelNotFoundException(getModelInfoResp.getStatus().getMessage());
       }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/parameter/model/ModelInferenceDescriptor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/parameter/model/ModelInferenceDescriptor.java
index bf5f391d9e4..b7c6aaa4f4b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/parameter/model/ModelInferenceDescriptor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/parameter/model/ModelInferenceDescriptor.java
@@ -37,14 +37,13 @@ import java.util.Objects;
 public class ModelInferenceDescriptor {
 
   private final TEndPoint targetAINode;
-  private final ModelInformation modelInformation;
+  private ModelInformation modelInformation;
   private List<String> outputColumnNames;
   private InferenceWindowParameter inferenceWindowParameter;
   private Map<String, String> inferenceAttributes;
 
-  public ModelInferenceDescriptor(TEndPoint targetAINode, ModelInformation 
modelInformation) {
+  public ModelInferenceDescriptor(TEndPoint targetAINode) {
     this.targetAINode = targetAINode;
-    this.modelInformation = modelInformation;
   }
 
   private ModelInferenceDescriptor(ByteBuffer buffer) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java
index afe47a96e64..b7dc5053c3f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java
@@ -207,6 +207,7 @@ public class ForecastTableFunction implements TableFunction 
{
   private static final String IS_INPUT_COLUMN_NAME = "is_input";
   private static final String OPTIONS_PARAMETER_NAME = "MODEL_OPTIONS";
   private static final String DEFAULT_OPTIONS = "";
+  private static final int MAX_INPUT_LENGTH = 1440;
 
   private static final String INVALID_OPTIONS_FORMAT = "Invalid options: %s";
 
@@ -284,16 +285,7 @@ public class ForecastTableFunction implements 
TableFunction {
           String.format("%s should never be null or empty", 
MODEL_ID_PARAMETER_NAME));
     }
 
-    // make sure modelId exists
-    ModelInferenceDescriptor descriptor = getModelInfo(modelId);
-    if (descriptor == null || !descriptor.getModelInformation().available()) {
-      throw new IoTDBRuntimeException(
-          String.format("model [%s] is not available", modelId),
-          TSStatusCode.GET_MODEL_INFO_ERROR.getStatusCode());
-    }
-
-    int maxInputLength = descriptor.getModelInformation().getInputShape()[0];
-    TEndPoint targetAINode = descriptor.getTargetAINode();
+    TEndPoint targetAINode = getModelInfo(modelId).getTargetAINode();
 
     int outputLength =
         (int) ((ScalarArgument) 
arguments.get(OUTPUT_LENGTH_PARAMETER_NAME)).getValue();
@@ -393,7 +385,7 @@ public class ForecastTableFunction implements TableFunction 
{
     ForecastTableFunctionHandle functionHandle =
         new ForecastTableFunctionHandle(
             keepInput,
-            maxInputLength,
+            MAX_INPUT_LENGTH,
             modelId,
             parseOptions(options),
             outputLength,
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
index 6c7cf212da5..30997db31e1 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/column/ColumnHeaderConstant.java
@@ -35,7 +35,7 @@ public class ColumnHeaderConstant {
   public static final String ENDTIME = "__endTime";
   public static final String VALUE = "Value";
   public static final String DEVICE = "Device";
-  public static final String DEVICE_ID = "DeviceID";
+  public static final String DEVICE_ID = "DeviceId";
   public static final String EXPLAIN_ANALYZE = "Explain Analyze";
 
   // column names for schema statement
@@ -635,7 +635,7 @@ public class ColumnHeaderConstant {
   public static final List<ColumnHeader> showLoadedModelsColumnHeaders =
       ImmutableList.of(
           new ColumnHeader(DEVICE_ID, TSDataType.TEXT),
-          new ColumnHeader(MODEL_TYPE, TSDataType.TEXT),
+          new ColumnHeader(MODEL_ID, TSDataType.TEXT),
           new ColumnHeader(COUNT_INSTANCES, TSDataType.INT32));
 
   public static final List<ColumnHeader> showAIDevicesColumnHeaders =


Reply via email to