Repository: antgroup/agentUniverse (language: python)

Issue:
fix: add get num tokens in openai_style_langchain_instance.



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 20210ccc..3ee1b273 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,38 @@ Note - Additional remarks regarding the version.
 ***************************************************
 
 # Version Update History
+## [0.0.8] - 2024-06-06
+### Added
+- Introduced a new monitor module
+  - Data running in any agentUniverse can be collected and observed
+- Added webserver post_fork functionality
+  - Provides multi-node process intervention capabilities after starting the webserver in agentUniverse
+- Introduced SQLDB_WRAPPER wrapper class, offering typical database connection methods
+  - Through the SQLDB_WRAPPER wrapper class, you can conveniently connect to various databases and storage technologies including SQLite, MySQL, Oracle, PostgreSQL, and others
+- Added connection support for Milvus vector database component
+
+For more usage of the above features, please pay attention to the agentUniverse guidebook.
+
+### Changed
+- Flask is set as the default webserver startup method across all platforms, with gunicorn and gRPC capabilities disabled by default
+  - In the previous version, we found slight compatibility differences with gunicorn and gRPC across different operating systems. Thus, we have made Flask the primary startup method for all platforms. You can enable gunicorn and gRPC in the configuration as needed.
+
+### Security
+- Some aU dependencies were identified to have security vulnerabilities in third-party packages. For security reasons, we have upgraded their versions, with the main changes including:
+  - requests (^2.31.0 -> ^2.32.0)
+  - flask (^2.2 -> ^2.3.2)
+  - werkzeug (^2.2.2 -> ^3.0.3)
+  - langchain (0.0.352 -> 0.1.20)
+  - langchain-core (0.1.3 -> 0.1.52)
+  - langchain-community (no version lock -> 0.0.38)
+  - gunicorn (21.2.0 -> ^22.0.0)
+  - Jinja2 (no version lock -> ^3.1.4)
+  - tqdm (no version lock -> ^4.66.3)
+If your system has external access, we strongly recommend installing version v0.0.8 of agentUniverse to mitigate the security risks posed by these third-party packages. For more detailed information, you can visit https://security.snyk.io.
+
+### Note
+- Some code optimizations and documentation updates.
+
 ## [0.0.7] - 2024-05-29
 ### Added
 - LLM component supports multimodal parameter invocation.
diff --git a/CHANGELOG_zh.md b/CHANGELOG_zh.md
index 580c0772..974374c8 100644
--- a/CHANGELOG_zh.md
+++ b/CHANGELOG_zh.md
@@ -24,6 +24,38 @@ Note - 对于版本的额外说明。
 ***************************************************
 
 # 版本更新记录
+## [0.0.8] - 2024-06-06
+### Added
+- 新增monitor模块
+  - 任何agentUniverse运行时的数据可以被采集与观测
+- 新增webserver post_fork功能
+  - 开放agentUniverse中webserver启动后的多节点流程干预功能
+- 新增SQLDB_WRAPPER包装类，提供典型数据库连接方式
+  - 通过SQLDB_WRAPPER包装类您可以非常方便的连接如SQLite、MySQL、Oracle、PostgreSQL、SQLite等几十种数据库与存储技术组件。
+- 新增milvus向量数据库组件连接
+
+上述功能更多用法请关注agentUniverse指导手册部分。
+
+### Changed
+- 全平台以flask作为默认webserver启动方式，gunicorn与GRPC能力置为默认关闭
+  - 我们在上个版本中发现不同的操作系统对于gunicorn与GRPC的兼容性会有略微差异，我们将flask作为全平台的第一启动方式，您可以按需在配置中开启gunicorn与GRPC。
+
+### Security
+- 部分aU依赖第三方包识别到安全漏洞，出于安全考虑我们对其进行版本升级，主要包含如下变动：
+  - requests (^2.31.0 -> ^2.32.0)
+  - flask (^2.2 -> ^2.3.2)
+  - werkzeug (^2.2.2 -> ^3.0.3)
+  - langchain (0.0.352 -> 0.1.20)
+  - langchain-core (0.1.3 -> 0.1.52)
+  - langchain-community (no version lock -> 0.0.38)
+  - gunicorn (21.2.0 -> ^22.0.0)
+  - Jinja2 (no version lock -> ^3.1.4)
+  - tqdm (no version lock -> ^4.66.3)
+若您的系统存在外部访问，强烈建议您安装v0.0.8版本的aU以规避这些三方包的安全风险，更详细的说明您可以关注https://security.snyk.io。
+
+### Note
+- 部分代码优化与文档更新
+
 ## [0.0.7] - 2024-05-29
 ### Added
 - LLM组件支持多模态参数调用
diff --git a/README.md b/README.md
index 00549a62..4823b33b 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Language version: [English](./README.md) | [中文](./README_zh.md)
 ![](https://img.shields.io/badge/framework-agentUniverse-pink)
 ![](https://img.shields.io/badge/python-3.10%2B-blue?logo=Python)
 [![](https://img.shields.io/badge/%20license-Apache--2.0-yellow)](LICENSE)
-[![Static Badge](https://img.shields.io/badge/pypi-v0.0.7-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
+[![Static Badge](https://img.shields.io/badge/pypi-v0.0.8-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
 
 ![](docs/guidebook/_picture/logo_bar.jpg)
 ****************************************
diff --git a/README_zh.md b/README_zh.md
index 26534b65..0bb45fb1 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -5,7 +5,7 @@
 ![](https://img.shields.io/badge/framework-agentUniverse-pink)
 ![](https://img.shields.io/badge/python-3.10%2B-blue?logo=Python)
 [![](https://img.shields.io/badge/%20license-Apache--2.0-yellow)](LICENSE)
-[![Static Badge](https://img.shields.io/badge/pypi-v0.0.7-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
+[![Static Badge](https://img.shields.io/badge/pypi-v0.0.8-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
 
 ![](docs/guidebook/_picture/logo_bar.jpg)
 ****************************************
diff --git a/agentuniverse/agent/action/knowledge/store/milvus_store.py b/agentuniverse/agent/action/knowledge/store/milvus_store.py
new file mode 100644
index 00000000..ced1ac14
--- /dev/null
+++ b/agentuniverse/agent/action/knowledge/store/milvus_store.py
@@ -0,0 +1,228 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/30 10:22
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: milvus_store.py
+from typing import List, Optional
+
+try:
+    from pymilvus import connections, Collection, CollectionSchema, \
+        FieldSchema, DataType, utility
+except ImportError as e:
+    raise ImportError(
+        "pymilvus is not installed. Please install it with 'pip install pymilvus'") from e
+
+from agentuniverse.agent.action.knowledge.store.document import Document
+from agentuniverse.agent.action.knowledge.store.query import Query
+from agentuniverse.agent.action.knowledge.store.store import Store
+
+DEFAULT_CONNECTION_ARGS = {
+    "host": "localhost",
+    "port": "19530"
+}
+
+DEFAULT_SEARCH_ARGS = {
+    "metric_type": "L2",
+    "params": {"nprobe": 10}
+}
+
+DEFAULT_INDEX_PARAMS = {
+    "metric_type": "L2",
+    "index_type": "HNSW",
+    "params": {"M": 8, "efConstruction": 64},
+}
+
+
+class MilvusStore(Store):
+    collection_name: Optional[str] = 'milvus_db'
+    collection: Collection = None
+    connection_name: str = 'default_connection'
+
+    def __init__(
+            self,
+            connection_args: dict = None,
+            **kwargs
+    ):
+        """Initialize the Milvus store class."""
+        super().__init__(**kwargs)
+        if not connection_args:
+            connection_args = DEFAULT_CONNECTION_ARGS
+        host = connection_args["host"]
+        port = connection_args["port"]
+        db_name = connection_args.get("db_name", "default")
+        self.connection_name = f"{host}_{port}_{db_name}"
+        self._connect_to_milvus(connection_args)
+        if utility.has_collection(self.collection_name,
+                                  using=self.connection_name):
+            self.collection = Collection(
+                self.collection_name, using=self.connection_name
+            )
+            self.collection.load()
+
+
+    def _connect_to_milvus(self, connection_args: dict):
+        """Connect to Milvus server."""
+        if not connections.has_connection(self.connection_name):
+            connections.connect(
+                alias=self.connection_name, **connection_args
+            )
+
+    def _create_or_load_collection(self,
+                                   dim: int = 128,
+                                   max_length: int = 65535,
+                                   index_params: dict = None):
+        """
+        Create a new collection or load an existing collection.
+
+        This method handles the creation of a new collection with specified parameters
+        or loads an existing collection if it already exists. Collections are used
+        to store data with specific dimensional attributes and indexing parameters.
+
+        Parameters:
+        - dim (int): The dimension of the collection, default is 128.
+        - max_length (int): The maximum length of the collection, default is 65535.
+        - index_params (dict, optional): Additional parameters for indexing. This
+          dictionary can include specific configurations for the index creation or loading.
+
+        Returns:
+        None
+        """
+        if utility.has_collection(self.collection_name,
+                                  using=self.connection_name):
+            self.collection = Collection(
+                self.collection_name, using=self.connection_name
+            )
+        else:
+            if not index_params:
+                index_params = DEFAULT_INDEX_PARAMS
+            fields = [
+                FieldSchema(name="id", dtype=DataType.VARCHAR, max_length=100,
+                            is_primary=True),
+                FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR,
+                            dim=dim),
+                FieldSchema(name="text", dtype=DataType.VARCHAR,
+                            max_length=max_length),
+                FieldSchema(name="metadata", dtype=DataType.JSON)
+            ]
+            schema = CollectionSchema(fields, "Milvus collection schema")
+            self.collection = Collection(self.collection_name, schema,
+                                         using=self.connection_name)
+            self.collection.create_index(
+                field_name="embedding",
+                index_params=index_params
+            )
+            self.collection.load()
+
+    def query(self,
+              query: Query,
+              search_args: dict = None,
+              **kwargs) -> List[Document]:
+        """
+        Query the Milvus collection with the given query and return the top k results.
+
+        Parameters:
+        - query (Query): The query object that contains the parameters and data for the search.
+        - search_args (dict, optional): A dictionary of additional arguments for the search.
+          This can include parameters such as the number of results to return, specific search
+          algorithms, or other configurations.
+
+        Returns:
+        - List[Document]: A list of Document objects that are the top k results from the query.
+        """
+        if not self.collection:
+            return self.to_documents([])
+        embedding = query.embedding
+        if self.embedding_model is not None and len(embedding) == 0:
+            embedding = self.embedding_model.get_embeddings([query.query_str])[
+                0]
+        if not search_args:
+            search_args = DEFAULT_SEARCH_ARGS
+        if len(embedding) > 0:
+            query_result = self.collection.search(
+                data=[embedding],
+                anns_field="embedding",
+                param=search_args,
+                limit=query.similarity_top_k,
+                output_fields=["id", "text", "embedding", "metadata"]
+            )
+        else:
+            query_result = []
+        return self.to_documents(query_result)
+
+
+    def upsert_document(self,
+                        documents: List[Document],
+                        max_length: int = 65535,
+                        index_params: dict = None,
+                        **kwargs):
+        """
+        This method inserts new documents or updates existing documents in the collection.
+        The upsert operation ensures that the documents are either added if they do not
+        already exist or updated if they do.
+
+        Parameters:
+        - documents (List[Document]): A list of Document objects to be upserted into the collection.
+        - max_length (int): The maximum length of the collection, default is 65535.
+        - index_params (dict, optional): Additional parameters for indexing. This dictionary
+          can include specific configurations for the index creation or updating.
+
+        Returns:
+        None
+        """
+        for document in documents:
+            embedding = document.embedding
+            if self.embedding_model is not None and len(embedding) == 0:
+                embedding = self.embedding_model.get_embeddings([document.text])[0]
+            if not self.collection:
+                self._create_or_load_collection(
+                    dim=len(embedding),
+                    max_length=max_length,
+                    index_params=index_params
+                )
+            expr = f'id == "{document.id}"'
+            existing_docs = self.collection.query(expr)
+            entities = [
+                [document.id],
+                [embedding],
+                [document.text],
+                [document.metadata]
+            ]
+            if existing_docs:
+                self.collection.delete(expr)
+                self.collection.insert(entities)
+            else:
+                self.collection.insert(entities)
+            self.collection.load()
+
+    def insert_documents(self,
+                         documents: List[Document],
+                         max_length: int = 65535,
+                         index_params: dict = None,
+                         ):
+        """Insert documents to the Milvus collection."""
+        self.upsert_document(documents, max_length, index_params)
+
+    def update_document(self, documents: List[Document], **kwargs):
+        """Update document into the store."""
+        self.upsert_document(documents)
+
+    @staticmethod
+    def to_documents(query_result) -> List[Document]:
+        """Convert the query results of Milvus to the AgentUniverse(AU)
+        document format."""
+        if query_result is None:
+            return []
+        documents = []
+        for result in query_result:
+            for res in result:
+                documents.append(Document(
+                    id=res.fields.get("id"),
+                    text=res.fields.get("text"),
+                    embedding=res.fields.get("embedding")
+                    if res.fields.get("embedding") else [],
+                    metadata=res.fields.get("metadata")
+                    if res.fields.get("metadata") else None)
+                )
+        return documents
diff --git a/agentuniverse/agent/default/planning_agent/planning_agent.py b/agentuniverse/agent/default/planning_agent/planning_agent.py
index cff17070..132bfba7 100644
--- a/agentuniverse/agent/default/planning_agent/planning_agent.py
+++ b/agentuniverse/agent/default/planning_agent/planning_agent.py
@@ -5,7 +5,8 @@
 # @Email   : lc299034@antgroup.com
 # @FileName: planning_agent.py
 """Planning agent module."""
-import json
+from langchain.output_parsers.json import parse_json_markdown
+
 from agentuniverse.agent.agent import Agent
 from agentuniverse.agent.input_object import InputObject
 
@@ -44,7 +45,7 @@ def parse_result(self, planner_result: dict) -> dict:
             dict: Agent result object.
         """
         output = planner_result.get('output')
-        output = json.loads(output)
+        output = parse_json_markdown(output)
         planner_result['framework'] = output['framework']
         planner_result['thought'] = output['thought']
         return planner_result
diff --git a/agentuniverse/agent/default/reviewing_agent/reviewing_agent.py b/agentuniverse/agent/default/reviewing_agent/reviewing_agent.py
index 16bbef28..f806310f 100644
--- a/agentuniverse/agent/default/reviewing_agent/reviewing_agent.py
+++ b/agentuniverse/agent/default/reviewing_agent/reviewing_agent.py
@@ -5,7 +5,8 @@
 # @Email   : lc299034@antgroup.com
 # @FileName: reviewing_agent.py
 """Reviewing Agent class."""
-import json
+from langchain.output_parsers.json import parse_json_markdown
+
 from agentuniverse.agent.agent import Agent
 from agentuniverse.agent.input_object import InputObject
 
@@ -46,7 +47,7 @@ def parse_result(self, planner_result: dict) -> dict:
         agent_result = dict()
 
         output = planner_result.get('output')
-        output = json.loads(output)
+        output = parse_json_markdown(output)
         is_useful = output.get('is_useful')
         if is_useful is None:
             is_useful = False
diff --git a/agentuniverse/agent/memory/default/default_memory.py b/agentuniverse/agent/memory/default/default_memory.py
index 2d581ac3..260d534a 100644
--- a/agentuniverse/agent/memory/default/default_memory.py
+++ b/agentuniverse/agent/memory/default/default_memory.py
@@ -6,7 +6,7 @@
 # @Email   : wangchongshi.wcs@antgroup.com
 # @FileName: default_memory.py
 from agentuniverse.agent.memory.chat_memory import ChatMemory
-from agentuniverse.llm.openai_llm import OpenAILLM
+from agentuniverse.llm.default.default_openai_llm import DefaultOpenAILLM
 
 
 class DefaultMemory(ChatMemory):
@@ -24,4 +24,4 @@ def __init__(self, **kwargs):
             default memory uses OpenAILLM(gpt-3.5-turbo) object as the memory llm.
         """
         super().__init__(**kwargs)
-        self.llm = OpenAILLM(model_name="gpt-3.5-turbo")
+        self.llm = DefaultOpenAILLM(model_name="gpt-4o")
diff --git a/agentuniverse/agent/memory/langchain_instance.py b/agentuniverse/agent/memory/langchain_instance.py
index 432b5f6a..bbbe5258 100644
--- a/agentuniverse/agent/memory/langchain_instance.py
+++ b/agentuniverse/agent/memory/langchain_instance.py
@@ -7,10 +7,8 @@
 # @FileName: langchain_instance.py
 from typing import List, Optional, Dict, Any
 
-from langchain.chains import LLMChain
 from langchain_core.messages import BaseMessage, get_buffer_string
 from langchain.memory import ConversationSummaryBufferMemory, ConversationTokenBufferMemory
-from langchain.memory.summary import SummarizerMixin
 
 from agentuniverse.agent.memory.enum import ChatMessageEnum
 from agentuniverse.agent.memory.message import Message
@@ -18,7 +16,7 @@
 from agentuniverse.prompt.prompt_manager import PromptManager
 
 
-class AuConversationSummaryBufferMemory(ConversationSummaryBufferMemory, SummarizerMixin):
+class AuConversationSummaryBufferMemory(ConversationSummaryBufferMemory):
     """Long term memory to store conversation memory.
 
     If memories exceeds the max tokens limit,
@@ -46,18 +44,18 @@ def __init__(self, **kwargs):
     @property
     def load_memory(self) -> List[BaseMessage]:
         """ General method: load the memory context from the memory buffer."""
-        buffer = self.buffer
+        messages = self.chat_memory.messages
         if self.moving_summary_buffer != "":
             moving_messages: List[BaseMessage] = [
                 self.summary_message_cls(content=self.moving_summary_buffer)
             ]
-            buffer = moving_messages + buffer
-        return buffer
+            messages = moving_messages + messages
+        return messages
 
     @property
     def load_memory_str(self) -> str:
         """ General method: load the memory context from the memory buffer as string format."""
-        buffer = get_buffer_string(self.buffer)
+        buffer = get_buffer_string(self.chat_memory.messages)
         if self.moving_summary_buffer is not None:
             buffer = self.moving_summary_buffer + buffer
         return buffer
@@ -117,8 +115,9 @@ def predict_new_summary(
         )
         prompt_version = self.prompt_version if self.prompt_version else 'chat_memory.summarizer_cn'
         prompt: Prompt = PromptManager().get_instance_obj(prompt_version)
-        chain = LLMChain(llm=self.llm, prompt=prompt.as_langchain())
-        return chain.predict(summary=existing_summary, new_lines=new_lines)
+        chain = prompt.as_langchain() | self.llm
+        res = chain.invoke(input={'summary': existing_summary, 'new_lines': new_lines})
+        return res.content
 
 
 class AuConversationTokenBufferMemory(ConversationTokenBufferMemory):
diff --git a/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py b/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py
index 6a2bb310..78526fba 100644
--- a/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py
+++ b/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py
@@ -7,12 +7,14 @@
 """Execution planner module."""
 import asyncio
 
-from langchain.chains import LLMChain
-from langchain_core.memory import BaseMemory
+from langchain_core.chat_history import InMemoryChatMessageHistory
+from langchain_core.runnables.history import RunnableWithMessageHistory
 
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.memory.chat_memory import ChatMemory
 from agentuniverse.agent.plan.planner.planner import Planner
+from agentuniverse.base.util.memory_util import generate_memories
 from agentuniverse.base.util.prompt_util import process_llm_token
 from agentuniverse.llm.llm import LLM
 from agentuniverse.prompt.prompt import Prompt
@@ -34,7 +36,7 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, input_object: Inp
             dict: The planner result.
         """
 
-        memory: BaseMemory = self.handle_memory(agent_model, planner_input)
+        memory: ChatMemory = self.handle_memory(agent_model, planner_input)
 
         self.handle_all_actions(agent_model, planner_input, input_object)
 
@@ -43,10 +45,17 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, input_object: Inp
         prompt: Prompt = self.handle_prompt(agent_model, planner_input)
         process_llm_token(llm, prompt.as_langchain(), agent_model.profile, planner_input)
 
-        llm_chain = LLMChain(llm=llm.as_langchain(),
-                             prompt=prompt.as_langchain(),
-                             output_key=self.output_key, memory=memory)
-        return asyncio.run(llm_chain.acall(inputs=planner_input))
+        chat_history = memory.as_langchain().chat_memory if memory else InMemoryChatMessageHistory()
+
+        chain_with_history = RunnableWithMessageHistory(
+            prompt.as_langchain() | llm.as_langchain(),
+            lambda session_id: chat_history,
+            history_messages_key="chat_history",
+            input_messages_key=self.input_key,
+        )
+        res = asyncio.run(
+            chain_with_history.ainvoke(input=planner_input, config={"configurable": {"session_id": "unused"}}))
+        return {**planner_input, self.output_key: res.content, 'chat_history': generate_memories(chat_history)}
 
     def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt:
         """Prompt module processing.
diff --git a/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py b/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py
index 98ba29c2..a7204af1 100644
--- a/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py
+++ b/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py
@@ -7,12 +7,14 @@
 """Expressing planner module."""
 import asyncio
 
-from langchain.chains import LLMChain
-from langchain_core.memory import BaseMemory
+from langchain_core.chat_history import InMemoryChatMessageHistory
+from langchain_core.runnables.history import RunnableWithMessageHistory
 
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.memory.chat_memory import ChatMemory
 from agentuniverse.agent.plan.planner.planner import Planner
+from agentuniverse.base.util.memory_util import generate_memories
 from agentuniverse.base.util.prompt_util import process_llm_token
 from agentuniverse.llm.llm import LLM
 from agentuniverse.prompt.prompt import Prompt
@@ -33,18 +35,24 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, input_object: Inp
         Returns:
             dict: The planner result.
         """
-        memory: BaseMemory = self.handle_memory(agent_model, planner_input)
+        memory: ChatMemory = self.handle_memory(agent_model, planner_input)
 
         llm: LLM = self.handle_llm(agent_model)
 
         prompt: Prompt = self.handle_prompt(agent_model, planner_input)
         process_llm_token(llm, prompt.as_langchain(), agent_model.profile, planner_input)
 
-        llm_chain = LLMChain(llm=llm.as_langchain(),
-                             prompt=prompt.as_langchain(),
-                             output_key=self.output_key, memory=memory)
-
-        return asyncio.run(llm_chain.acall(inputs=planner_input))
+        chat_history = memory.as_langchain().chat_memory if memory else InMemoryChatMessageHistory()
+
+        chain_with_history = RunnableWithMessageHistory(
+            prompt.as_langchain() | llm.as_langchain(),
+            lambda session_id: chat_history,
+            history_messages_key="chat_history",
+            input_messages_key=self.input_key,
+        )
+        res = asyncio.run(
+            chain_with_history.ainvoke(input=planner_input, config={"configurable": {"session_id": "unused"}}))
+        return {**planner_input, self.output_key: res.content, 'chat_history': generate_memories(chat_history)}
 
     def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt:
         """Prompt module processing.
diff --git a/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py b/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py
index e3614e7c..a25fb3bc 100644
--- a/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py
+++ b/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py
@@ -56,6 +56,8 @@ def generate_sub_agents(planner_config: dict) -> dict:
         agents = dict()
         for config_key, default_agent in default_sub_agents.items():
             config_data = planner_config.get(config_key, None)
+            if config_data == '':
+                continue
             agents[config_key] = AgentManager().get_instance_obj(config_data if config_data else default_agent)
         return agents
 
@@ -108,10 +110,10 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu
         reviewingAgent = agents.get('reviewing')
 
         for _ in range(retry_count):
-            LOGGER.info(f"Starting peer agents, retry_count is {_}.")
+            LOGGER.info(f"Starting peer agents, retry_count is {_ + 1}.")
             if not planning_result or jump_step == "planning":
                 if not planningAgent:
-                    LOGGER.warn("no planning agent, use default.")
+                    LOGGER.warn("no planning agent.")
                     planning_result = OutputObject({"framework": [agent_input.get('input')]})
                 else:
                     LOGGER.info(f"Starting planning agent.")
@@ -126,7 +128,7 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu
 
             if not executing_result or jump_step in ["planning", "executing"]:
                 if not executingAgent:
-                    LOGGER.warn("no executing agent, use default.")
+                    LOGGER.warn("no executing agent.")
                     executing_result = OutputObject({})
                 else:
                     LOGGER.info(f"Starting executing agent.")
@@ -135,15 +137,16 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu
                 input_object.add_data('executing_result', executing_result)
                 # add executing agent log info
                 logger_info = f"\nExecuting agent execution result is :\n"
-                for index, one_exec_res in enumerate(executing_result.get_data('executing_result')):
-                    one_exec_log_info = f"[{index + 1}] input: {one_exec_res['input']}\n"
-                    one_exec_log_info += f"[{index + 1}] output: {one_exec_res['output']}\n"
-                    logger_info += one_exec_log_info
+                if executing_result.get_data('executing_result'):
+                    for index, one_exec_res in enumerate(executing_result.get_data('executing_result')):
+                        one_exec_log_info = f"[{index + 1}] input: {one_exec_res['input']}\n"
+                        one_exec_log_info += f"[{index + 1}] output: {one_exec_res['output']}\n"
+                        logger_info += one_exec_log_info
                 LOGGER.info(logger_info)
 
             if not expressing_result or jump_step in ["planning", "executing", "expressing"]:
                 if not expressingAgent:
-                    LOGGER.warn("no expression agent, use default.")
+                    LOGGER.warn("no expression agent.")
                     expressing_result = OutputObject({})
                 else:
                     LOGGER.info(f"Starting expressing agent.")
@@ -157,7 +160,7 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu
 
             if not reviewing_result or jump_step in ["planning", "executing", "expressing", "reviewing"]:
                 if not reviewingAgent:
-                    LOGGER.warn("no expression agent, use default.")
+                    LOGGER.warn("no expression agent.")
                     loopResults.append({
                         "planning_result": planning_result,
                         "executing_result": executing_result,
@@ -169,7 +172,7 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu
                 else:
                     LOGGER.info(f"Starting reviewing agent.")
                     reviewing_result = reviewingAgent.run(**input_object.to_dict())
-                    input_object.add_data('evaluator_result', reviewing_result)
+                    input_object.add_data('reviewing_result', reviewing_result)
 
                     # add reviewing agent log info
                     logger_info = f"\nReviewing agent execution result is :\n"
diff --git a/agentuniverse/agent/plan/planner/planner.py b/agentuniverse/agent/plan/planner/planner.py
index 83e8107d..a9401807 100644
--- a/agentuniverse/agent/plan/planner/planner.py
+++ b/agentuniverse/agent/plan/planner/planner.py
@@ -5,12 +5,11 @@
 # @Email   : lc299034@antgroup.com
 # @FileName: planner.py
 """Base class for Planner."""
-import copy
 from abc import abstractmethod
+import copy
+import logging
 from typing import Optional, List
 
-from langchain_core.memory import BaseMemory
-
 from agentuniverse.agent.action.knowledge.knowledge import Knowledge
 from agentuniverse.agent.action.knowledge.knowledge_manager import KnowledgeManager
 from agentuniverse.agent.action.knowledge.store.document import Document
@@ -18,6 +17,7 @@
 from agentuniverse.agent.action.tool.tool_manager import ToolManager
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.memory.chat_memory import ChatMemory
 from agentuniverse.agent.memory.memory import Memory
 from agentuniverse.agent.memory.message import Message
 from agentuniverse.agent.memory.memory_manager import MemoryManager
@@ -29,6 +29,8 @@
 from agentuniverse.prompt.prompt import Prompt
 from agentuniverse.base.util.memory_util import generate_messages
 
+logging.getLogger().setLevel(logging.ERROR)
+
 
 class Planner(ComponentBase):
     """
@@ -60,7 +62,7 @@ def invoke(self, agent_model: AgentModel, planner_input: dict,
         """
         pass
 
-    def handle_memory(self, agent_model: AgentModel, planner_input: dict) -> BaseMemory | None:
+    def handle_memory(self, agent_model: AgentModel, planner_input: dict) -> ChatMemory | None:
         """Memory module processing.
 
         Args:
@@ -82,15 +84,11 @@ def handle_memory(self, agent_model: AgentModel, planner_input: dict) -> BaseMem
         params['input_key'] = self.input_key
         params['output_key'] = self.output_key
 
-        memory: Memory = MemoryManager().get_instance_obj(memory_name)
+        memory: ChatMemory = MemoryManager().get_instance_obj(component_instance_name=memory_name, new_instance=True)
         if memory is None:
             return None
-        copied_memory = copy.deepcopy(memory)
-        copied_memory.set_by_agent_model(**params)
-        langchain_memory: BaseMemory = copied_memory.as_langchain()
-
-        planner_input['chat_history'] = langchain_memory.load_memory_str
-        return langchain_memory
+        memory.set_by_agent_model(**params)
+        return memory
 
     def handle_all_actions(self, agent_model: AgentModel, planner_input: dict, input_object: InputObject):
         """Tool and knowledge processing.
@@ -144,10 +142,9 @@ def handle_llm(self, agent_model: AgentModel) -> LLM:
             LLM: The language model.
         """
         llm_name = agent_model.profile.get('llm_model').get('name')
-        llm: LLM = LLMManager().get_instance_obj(llm_name)
-        copied_llm = copy.deepcopy(llm)
-        copied_llm.set_by_agent_model(**agent_model.profile.get('llm_model'))
-        return copied_llm
+        llm: LLM = LLMManager().get_instance_obj(component_instance_name=llm_name, new_instance=True)
+        llm.set_by_agent_model(**agent_model.profile.get('llm_model'))
+        return llm
 
     def initialize_by_component_configer(self, component_configer: PlannerConfiger) -> 'Planner':
         """Initialize the planner by the PlannerConfiger object.
diff --git a/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py b/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py
index 96d7bdad..c983f14d 100644
--- a/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py
+++ b/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py
@@ -7,12 +7,14 @@
 """Planning planner module."""
 import asyncio
 
-from langchain.chains import LLMChain
-from langchain_core.memory import BaseMemory
+from langchain_core.chat_history import InMemoryChatMessageHistory
+from langchain_core.runnables.history import RunnableWithMessageHistory
 
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.memory.chat_memory import ChatMemory
 from agentuniverse.agent.plan.planner.planner import Planner
+from agentuniverse.base.util.memory_util import generate_memories
 from agentuniverse.base.util.prompt_util import process_llm_token
 from agentuniverse.llm.llm import LLM
 from agentuniverse.prompt.prompt import Prompt
@@ -34,18 +36,24 @@ def invoke(self, agent_model: AgentModel, planner_input: dict,
         Returns:
             dict: The planner result.
         """
-        memory: BaseMemory = self.handle_memory(agent_model, planner_input)
+        memory: ChatMemory = self.handle_memory(agent_model, planner_input)
 
         llm: LLM = self.handle_llm(agent_model)
 
         prompt: Prompt = self.handle_prompt(agent_model, planner_input)
         process_llm_token(llm, prompt.as_langchain(), agent_model.profile, planner_input)
 
-        llm_chain = LLMChain(llm=llm.as_langchain(),
-                             prompt=prompt.as_langchain(),
-                             output_key=self.output_key, memory=memory)
-
-        return asyncio.run(llm_chain.acall(planner_input))
+        chat_history = memory.as_langchain().chat_memory if memory else InMemoryChatMessageHistory()
+
+        chain_with_history = RunnableWithMessageHistory(
+            prompt.as_langchain() | llm.as_langchain(),
+            lambda session_id: chat_history,
+            history_messages_key="chat_history",
+            input_messages_key=self.input_key,
+        )
+        res = asyncio.run(
+            chain_with_history.ainvoke(input=planner_input, config={"configurable": {"session_id": "unused"}}))
+        return {**planner_input, self.output_key: res.content, 'chat_history': generate_memories(chat_history)}
 
     def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt:
         """Prompt module processing.
diff --git a/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py b/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py
index 26a19c75..29d38c1c 100644
--- a/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py
+++ b/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py
@@ -7,12 +7,14 @@
 """Rag planner module."""
 import asyncio
 
-from langchain.chains import LLMChain
-from langchain_core.memory import BaseMemory
+from langchain_core.chat_history import InMemoryChatMessageHistory
+from langchain_core.runnables.history import RunnableWithMessageHistory
 
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.memory.chat_memory import ChatMemory
 from agentuniverse.agent.plan.planner.planner import Planner
+from agentuniverse.base.util.memory_util import generate_memories
 from agentuniverse.base.util.prompt_util import process_llm_token
 from agentuniverse.llm.llm import LLM
 from agentuniverse.prompt.chat_prompt import ChatPrompt
@@ -35,7 +37,7 @@ def invoke(self, agent_model: AgentModel, planner_input: dict,
         Returns:
             dict: The planner result.
         """
-        memory: BaseMemory = self.handle_memory(agent_model, planner_input)
+        memory: ChatMemory = self.handle_memory(agent_model, planner_input)
 
         self.handle_all_actions(agent_model, planner_input, input_object)
 
@@ -43,11 +45,18 @@ def invoke(self, agent_model: AgentModel, planner_input: dict,
 
         prompt: ChatPrompt = self.handle_prompt(agent_model, planner_input)
         process_llm_token(llm, prompt.as_langchain(), agent_model.profile, planner_input)
-        llm_chain = LLMChain(llm=llm.as_langchain(),
-                             prompt=prompt.as_langchain(),
-                             output_key=self.output_key, memory=memory)
 
-        return asyncio.run(llm_chain.acall(inputs=planner_input))
+        chat_history = memory.as_langchain().chat_memory if memory else InMemoryChatMessageHistory()
+
+        chain_with_history = RunnableWithMessageHistory(
+            prompt.as_langchain() | llm.as_langchain(),
+            lambda session_id: chat_history,
+            history_messages_key="chat_history",
+            input_messages_key=self.input_key,
+        )
+        res = asyncio.run(
+            chain_with_history.ainvoke(input=planner_input, config={"configurable": {"session_id": "unused"}}))
+        return {**planner_input, self.output_key: res.content, 'chat_history': generate_memories(chat_history)}
 
     def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> ChatPrompt:
         """Prompt module processing.
diff --git a/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py b/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py
index 24fe6d52..960f98d5 100644
--- a/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py
+++ b/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py
@@ -7,12 +7,14 @@
 """Reviewing planner module."""
 import asyncio
 
-from langchain.chains import LLMChain
-from langchain_core.memory import BaseMemory
+from langchain_core.chat_history import InMemoryChatMessageHistory
+from langchain_core.runnables.history import RunnableWithMessageHistory
 
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.memory.chat_memory import ChatMemory
 from agentuniverse.agent.plan.planner.planner import Planner
+from agentuniverse.base.util.memory_util import generate_memories
 from agentuniverse.base.util.prompt_util import process_llm_token
 from agentuniverse.llm.llm import LLM
 from agentuniverse.prompt.prompt import Prompt
@@ -33,18 +35,24 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, input_object: Inp
         Returns:
             dict: The planner result.
         """
-        memory: BaseMemory = self.handle_memory(agent_model, planner_input)
+        memory: ChatMemory = self.handle_memory(agent_model, planner_input)
 
         llm: LLM = self.handle_llm(agent_model)
 
         prompt: Prompt = self.handle_prompt(agent_model, planner_input)
         process_llm_token(llm, prompt.as_langchain(), agent_model.profile, planner_input)
 
-        llm_chain = LLMChain(llm=llm.as_langchain(),
-                             prompt=prompt.as_langchain(),
-                             output_key=self.output_key, memory=memory)
-
-        return asyncio.run(llm_chain.acall(inputs=planner_input))
+        chat_history = memory.as_langchain().chat_memory if memory else InMemoryChatMessageHistory()
+
+        chain_with_history = RunnableWithMessageHistory(
+            prompt.as_langchain() | llm.as_langchain(),
+            lambda session_id: chat_history,
+            history_messages_key="chat_history",
+            input_messages_key=self.input_key,
+        )
+        res = asyncio.run(
+            chain_with_history.ainvoke(input=planner_input, config={"configurable": {"session_id": "unused"}}))
+        return {**planner_input, self.output_key: res.content, 'chat_history': generate_memories(chat_history)}
 
     def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt:
         """Generate prompt template for the planner.
diff --git a/agentuniverse/agent_serve/web/dal/request_library.py b/agentuniverse/agent_serve/web/dal/request_library.py
index 3b598453..b8674fb3 100644
--- a/agentuniverse/agent_serve/web/dal/request_library.py
+++ b/agentuniverse/agent_serve/web/dal/request_library.py
@@ -7,18 +7,18 @@
 # @FileName: request_library.py
 
 import datetime
-import json
 
 from sqlalchemy import JSON, Integer, String, DateTime, Text, Column
-from sqlalchemy import create_engine
 from sqlalchemy import select
-from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import declarative_base
 
 from .entity.request_do import RequestDO
 from agentuniverse.base.util.system_util import get_project_root_path
 from agentuniverse.base.config.configer import Configer
+from agentuniverse.base.config.component_configer.configers.sqldb_wrapper_config import SQLDBWrapperConfiger
 from agentuniverse.base.annotation.singleton import singleton
+from agentuniverse.database.sqldb_wrapper import SQLDBWrapper
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
 
 REQUEST_TABLE_NAME = 'request_task'
 Base = declarative_base()
@@ -51,14 +51,33 @@ def __init__(self, configer: Configer = None):
             if not system_db_uri:
                 system_db_uri = configer.get('DB', {}).get('mysql_uri')
         if system_db_uri and system_db_uri.strip():
-            db_uri = system_db_uri
+            pass
         else:
             db_path = get_project_root_path() / 'DB' / 'agent_universe.db'
             db_path.parent.mkdir(parents=True, exist_ok=True)
-            db_uri = f'sqlite:////{db_path}'
+            system_db_uri = f'sqlite:////{db_path}'
+
+        self.session = None
+        # create a sqldb_wrapper_instance
+        _configer = SQLDBWrapperConfiger()
+        _configer.db_uri = system_db_uri
+        self.sqldb_wrapper = SQLDBWrapper(
+            name="__system_db__",
+            db_wrapper_configer=_configer
+        )
+        SQLDBWrapperManager().register("__system_db__", self.sqldb_wrapper)
+
+    def __init_request_table(self):
+        with self.sqldb_wrapper.sql_database._engine.connect() as conn:
+            if not conn.dialect.has_table(conn, REQUEST_TABLE_NAME):
+                Base.metadata.create_all(self.sqldb_wrapper.sql_database._engine)
+
+    def get_session(self):
+        if not self.session:
+            self.__init_request_table()
+            self.session = self.sqldb_wrapper.get_session()
+        return self.session
 
-        self.db_uri = db_uri
-        self.Session = None
 
     def query_request_by_request_id(self, request_id: str) -> RequestDO | None:
         """Get a RequestDO with given request_id.
@@ -69,7 +88,7 @@ def query_request_by_request_id(self, request_id: str) -> RequestDO | None:
         Return:
             The target RequestDO or none when no such data.
         """
-        session = self.__get_session()
+        session = self.get_session()
         try:
             result = session.execute(
                 select(RequestORM).where(RequestORM.request_id == request_id)
@@ -89,7 +108,7 @@ def add_request(self, request_do: RequestDO) -> int:
         Return:
             A int stands unique data id in table.
         """
-        session = self.__get_session()
+        session = self.get_session()
         try:
             request_orm = RequestORM(**request_do.model_dump())
             session.add(request_orm)
@@ -101,7 +120,7 @@ def add_request(self, request_do: RequestDO) -> int:
     def update_request(self, request_do: RequestDO):
         """Update the request data with same request id as the given
         RequestDO."""
-        session = self.__get_session()
+        session = self.get_session()
         try:
             db_request_do = session.query(RequestORM).filter(
                 RequestORM.request_id == request_do.request_id).first()
@@ -116,7 +135,7 @@ def update_request(self, request_do: RequestDO):
 
     def update_gmt_modified(self, request_id: str):
         """Update the request task latest active time."""
-        session = self.__get_session()
+        session = self.get_session()
         try:
             db_request_do = session.query(RequestORM).filter(
                 RequestORM.request_id == request_id).first()
@@ -127,21 +146,6 @@ def update_gmt_modified(self, request_id: str):
         finally:
             session.close()
 
-    def __get_session(self):
-        if self.Session:
-            return self.Session()
-        # Create database engine
-        self.engine = create_engine(
-            self.db_uri,
-            json_serializer=lambda x: json.dumps(x, ensure_ascii=False)
-        )
-        self.Session = sessionmaker(bind=self.engine)
-
-        with self.engine.connect() as conn:
-            if not conn.dialect.has_table(conn, REQUEST_TABLE_NAME):
-                Base.metadata.create_all(self.engine)
-        return self.Session()
-
     def __request_orm_to_do(self, request_orm: RequestORM) -> RequestDO:
         """Transfer a RequestORM to RequestDO."""
         request_obj = RequestDO(
diff --git a/agentuniverse/agent_serve/web/flask_server.py b/agentuniverse/agent_serve/web/flask_server.py
index 61547598..9f6a1f84 100644
--- a/agentuniverse/agent_serve/web/flask_server.py
+++ b/agentuniverse/agent_serve/web/flask_server.py
@@ -11,6 +11,7 @@
 
 app = Flask(__name__)
 app.config['JSON_AS_ASCII'] = False
+app.json.ensure_ascii = False
 
 
 @app.route("/echo")
diff --git a/agentuniverse/agent_serve/web/gunicorn_server.py b/agentuniverse/agent_serve/web/gunicorn_server.py
index 5d2ed4e6..c7f914f6 100644
--- a/agentuniverse/agent_serve/web/gunicorn_server.py
+++ b/agentuniverse/agent_serve/web/gunicorn_server.py
@@ -10,6 +10,7 @@
 from gunicorn.app.base import BaseApplication
 
 from .flask_server import app
+from .post_fork_queue import POST_FORK_QUEUE
 from ...base.annotation.singleton import singleton
 
 
@@ -24,6 +25,12 @@
 }
 
 
+# Execute all func in the queue after fork chile process.
+def post_fork(server, worker):
+    for _func, args, kwargs in POST_FORK_QUEUE:
+        _func(*args, **kwargs)
+
+
 @singleton
 class GunicornApplication(BaseApplication):
     """Use gunicorn to wrap the flask web server."""
@@ -52,6 +59,9 @@ def load_config(self):
             if key in self.cfg.settings and value is not None:
                 self.cfg.set(key.lower(), value)
 
+        # Set post fork.
+        self.cfg.set('post_fork', post_fork)
+
     def update_config(self, options: dict):
         self.options = options
         self.load_config()
diff --git a/agentuniverse/agent_serve/web/post_fork_queue.py b/agentuniverse/agent_serve/web/post_fork_queue.py
new file mode 100644
index 00000000..6310f19e
--- /dev/null
+++ b/agentuniverse/agent_serve/web/post_fork_queue.py
@@ -0,0 +1,24 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/6/3 23:09
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: post_fork_queue.py
+
+from typing import List, Tuple, Callable, Any
+
+FunctionWithArgs = Tuple[Callable, Tuple[Any, ...], dict]
+POST_FORK_QUEUE: List[FunctionWithArgs] = []
+
+
+def add_post_fork(func: Callable, *args: Any, **kwargs: Any) -> None:
+    """
+    Add funcs and parameters into a waiting list, all of them will be executed
+    after gunicorn worker child processes have been forked, or before flask
+    main app start if you work without gunicorn.
+    """
+
+    POST_FORK_QUEUE.append((func, args, kwargs))
+
+
diff --git a/agentuniverse/agent_serve/web/request_task.py b/agentuniverse/agent_serve/web/request_task.py
index ce9b7a51..5f32ae8b 100644
--- a/agentuniverse/agent_serve/web/request_task.py
+++ b/agentuniverse/agent_serve/web/request_task.py
@@ -225,7 +225,7 @@ def finished(self):
         self.__request_do__.state = TaskStateEnum.FINISHED.value
 
     @staticmethod
-    def query_request_state(request_id: str) -> dict:
+    def query_request_state(request_id: str) -> dict|None:
         """Query the request data in database by given request_id.
 
         Args:
@@ -234,9 +234,7 @@ def query_request_state(request_id: str) -> dict:
         request_do = RequestLibrary().query_request_by_request_id(
             request_id)
         if request_do is None:
-            return {"state": TaskStateEnum.INIT.value,
-                    "result": None,
-                    "steps": None}
+            return None
         RequestTask.is_validate(request_do)
         return {
             "state": request_do.state,
diff --git a/agentuniverse/agent_serve/web/rpc/grpc/grpc_server_booster.py b/agentuniverse/agent_serve/web/rpc/grpc/grpc_server_booster.py
index b2c9467a..161a805c 100644
--- a/agentuniverse/agent_serve/web/rpc/grpc/grpc_server_booster.py
+++ b/agentuniverse/agent_serve/web/rpc/grpc/grpc_server_booster.py
@@ -13,6 +13,7 @@
     agentuniverse_service_pb2_grpc
 from agentuniverse.agent_serve.web.rpc.rpc_server import service_run, service_run_async, service_run_result
 
+GRPC_CONFIG = {}
 
 class AgentUniverseService(agentuniverse_service_pb2_grpc.AgentUniverseService):
     """Implementation class of grpc service."""
@@ -106,15 +107,16 @@ def service_run_result(self, request, context):
         )
 
 
-def start_grpc_server(configer=None):
+def set_grpc_config(configer):
+    GRPC_CONFIG["server_port"] = configer.value.get('GRPC', {}).get('server_port', 50051)
+    GRPC_CONFIG["max_workers"] = configer.value.get('GRPC', {}).get('max_workers', 10)
+
+
+def start_grpc_server():
     """Used to start a grpc server, use configer to read grpc server config if
     applied, or use default config of 10 workers and 50051 port."""
-    if configer:
-        server_port = configer.value.get('GRPC', {}).get('server_port')
-        max_workers = configer.value.get('GRPC', {}).get('max_workers')
-    else:
-        max_workers = 10
-        server_port = 50051
+    server_port = GRPC_CONFIG.get('server_port', 50051)
+    max_workers = GRPC_CONFIG.get('max_workers', 10)
     server = grpc.server(futures.ThreadPoolExecutor(max_workers=max_workers))
     agentuniverse_service_pb2_grpc.add_AgentUniverseServiceServicer_to_server(
         AgentUniverseService(), server
diff --git a/agentuniverse/agent_serve/web/web_booster.py b/agentuniverse/agent_serve/web/web_booster.py
index f6c7652f..50a34169 100644
--- a/agentuniverse/agent_serve/web/web_booster.py
+++ b/agentuniverse/agent_serve/web/web_booster.py
@@ -7,12 +7,38 @@
 # @FileName: web_booster.py
 
 import sys
+import threading
+
+from .post_fork_queue import POST_FORK_QUEUE
+
+ACTIVATE_OPTIONS = {
+    "gunicorn": False,
+    "grpc": False
+}
 
 
 def start_web_server(**kwargs):
-    """Start func of flask server(on windows platform) or gunicorn server(on
-    others). Accept input arguments to overwrite default gunicorn config."""
-    if sys.platform.startswith('win'):
+    """
+    Start func of web server, include http server and grpc server. Use Flask
+    as default http server.
+    The gRPC server is not enabled by default; it needs
+    to be configured in the configuration file.
+    Accept input arguments to overwrite default config.
+    """
+    # Start grpc server.
+    if ACTIVATE_OPTIONS["grpc"]:
+        from .rpc.grpc.grpc_server_booster import start_grpc_server
+        grpc_thread = threading.Thread(
+            target=start_grpc_server
+        )
+        grpc_thread.start()
+
+    # Start http server.
+    if ACTIVATE_OPTIONS["gunicorn"]:
+        from .gunicorn_server import GunicornApplication
+        GunicornApplication().update_config(kwargs)
+        GunicornApplication().run()
+    else:
         from .flask_server import app
         if 'bind' in kwargs:
             host, port = kwargs['bind'].split(':')
@@ -20,8 +46,6 @@ def start_web_server(**kwargs):
         else:
             port = 8888
             host = '0.0.0.0'
+        for _func, args, kwargs in POST_FORK_QUEUE:
+            _func(*args, **kwargs)
         app.run(port=port, host=host, debug=False)
-    else:
-        from .gunicorn_server import GunicornApplication
-        GunicornApplication().update_config(kwargs)
-        GunicornApplication().run()
\ No newline at end of file
diff --git a/agentuniverse/base/agentuniverse.py b/agentuniverse/base/agentuniverse.py
index 80ea5723..7b463c0e 100644
--- a/agentuniverse/base/agentuniverse.py
+++ b/agentuniverse/base/agentuniverse.py
@@ -21,10 +21,12 @@
 from agentuniverse.base.config.configer import Configer
 from agentuniverse.base.config.custom_configer.custom_key_configer import CustomKeyConfiger
 from agentuniverse.base.component.component_enum import ComponentEnum
+from agentuniverse.base.util.monitor.monitor import Monitor
 from agentuniverse.base.util.system_util import get_project_root_path
 from agentuniverse.base.util.logging.logging_util import init_loggers
 from agentuniverse.agent_serve.web.request_task import RequestLibrary
-from agentuniverse.agent_serve.web.rpc.grpc.grpc_server_booster import start_grpc_server
+from agentuniverse.agent_serve.web.rpc.grpc.grpc_server_booster import set_grpc_config
+from agentuniverse.agent_serve.web.web_booster import ACTIVATE_OPTIONS
 
 
 @singleton
@@ -73,19 +75,18 @@ def start(self, config_path: str = None):
         # init web request task database
         RequestLibrary(configer=configer)
 
-        # init grpc server
+        # Edit grpc config.
         grpc_activate = configer.value.get('GRPC', {}).get('activate')
         if grpc_activate and grpc_activate.lower() == 'true':
-            grpc_thread = threading.Thread(
-                target=start_grpc_server,
-                kwargs={"configer": configer}
-            )
-            grpc_thread.start()
+            ACTIVATE_OPTIONS["grpc"] = True
+            set_grpc_config(configer)
 
-        # init gunicorn web server on mac or unix platform
-        if not sys.platform.lower().startswith("win"):
+        # Init gunicorn web server with config file.
+        gunicorn_activate = configer.value.get('GUNICORN', {}).get('activate')
+        if gunicorn_activate and gunicorn_activate.lower() == 'true':
+            ACTIVATE_OPTIONS["gunicorn"] = True
             gunicorn_config_path = self.__parse_sub_config_path(
-                configer.value.get('SUB_CONFIG_PATH', {})
+                configer.value.get('GUNICORN', {})
                 .get('gunicorn_config_path'), config_path
             )
             from ..agent_serve.web.gunicorn_server import \
@@ -98,6 +99,9 @@ def start(self, config_path: str = None):
             for ext_class in ext_classes:
                 self.__dynamic_import_and_init(ext_class, configer)
 
+        # init monitor module
+        Monitor(configer=configer)
+
         # scan and register the components
         self.__scan_and_register(self.__config_container.app_configer)
 
@@ -116,6 +120,7 @@ def __scan_and_register(self, app_configer: AppConfiger):
                                      + self.__system_default_planner_package)
         core_tool_package_list = app_configer.core_tool_package_list or app_configer.core_default_package_list
         core_service_package_list = app_configer.core_service_package_list or app_configer.core_default_package_list
+        core_sqldb_wrapper_package_list = app_configer.core_sqldb_wrapper_package_list or app_configer.core_default_package_list
         core_memory_package_list = ((app_configer.core_memory_package_list or app_configer.core_default_package_list)
                                     + self.__system_default_memory_package)
         core_prompt_package_list = ((app_configer.core_prompt_package_list or app_configer.core_default_package_list)
@@ -128,6 +133,7 @@ def __scan_and_register(self, app_configer: AppConfiger):
             ComponentEnum.PLANNER: core_planner_package_list,
             ComponentEnum.TOOL: core_tool_package_list,
             ComponentEnum.SERVICE: core_service_package_list,
+            ComponentEnum.SQLDB_WRAPPER: core_sqldb_wrapper_package_list,
             ComponentEnum.MEMORY: core_memory_package_list,
             ComponentEnum.PROMPT: core_prompt_package_list
         }
diff --git a/agentuniverse/base/annotation/trace.py b/agentuniverse/base/annotation/trace.py
new file mode 100644
index 00000000..d3333edb
--- /dev/null
+++ b/agentuniverse/base/annotation/trace.py
@@ -0,0 +1,97 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/6/5 15:33
+# @Author  : wangchongshi
+# @Email   : wangchongshi.wcs@antgroup.com
+# @FileName: trace.py
+import asyncio
+import functools
+import inspect
+
+from functools import wraps
+
+from agentuniverse.base.util.monitor.monitor import Monitor
+from agentuniverse.llm.llm_output import LLMOutput
+
+monitor = Monitor()
+
+
+def trace_llm(func):
+    """Annotation: @trace_llm
+
+    Decorator to trace the LLM invocation, add llm input and output to the monitor.
+    """
+
+    @wraps(func)
+    async def wrapper_async(*args, **kwargs):
+        # get llm input from arguments
+        llm_input = _get_llm_input(func, *args, **kwargs)
+        # check whether the tracing switch is enabled
+        self = llm_input.pop('self', None)
+        if self and hasattr(self, 'tracing'):
+            if self.tracing is False:
+                return await func(*args, **kwargs)
+        # invoke function
+        result = await func(*args, **kwargs)
+        # not streaming
+        if isinstance(result, LLMOutput):
+            # add llm invocation info to monitor
+            monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input, llm_output=result.text)
+            return result
+        else:
+            # streaming
+            async def gen_iterator():
+                llm_output = []
+                async for chunk in result:
+                    llm_output.append(chunk.text)
+                    yield chunk
+                # add llm invocation info to monitor
+                monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input,
+                                             llm_output="".join(llm_output))
+
+            return gen_iterator()
+
+    @functools.wraps(func)
+    def wrapper_sync(*args, **kwargs):
+        # get llm input from arguments
+        llm_input = _get_llm_input(func, *args, **kwargs)
+        # check whether the tracing switch is enabled
+        self = llm_input.pop('self', None)
+        if self and hasattr(self, 'tracing'):
+            if not self.tracing:
+                return func(*args, **kwargs)
+        # invoke function
+        result = func(*args, **kwargs)
+        # not streaming
+        if isinstance(result, LLMOutput):
+            # add llm invocation info to monitor
+            monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input, llm_output=result.text)
+            return result
+        else:
+            # streaming
+            def gen_iterator():
+                llm_output = []
+                for chunk in result:
+                    llm_output.append(chunk.text)
+                    yield chunk
+                # add llm invocation info to monitor
+                monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input,
+                                             llm_output="".join(llm_output))
+
+            return gen_iterator()
+
+    if asyncio.iscoroutinefunction(func):
+        # async function
+        return wrapper_async
+    else:
+        # sync function
+        return wrapper_sync
+
+
+def _get_llm_input(func, *args, **kwargs) -> dict:
+    """Get the llm input from arguments."""
+    sig = inspect.signature(func)
+    bound_args = sig.bind(*args, **kwargs)
+    bound_args.apply_defaults()
+    return {k: v for k, v in bound_args.arguments.items()}
diff --git a/agentuniverse/base/component/component_configer_util.py b/agentuniverse/base/component/component_configer_util.py
index d230d3c6..7809275f 100644
--- a/agentuniverse/base/component/component_configer_util.py
+++ b/agentuniverse/base/component/component_configer_util.py
@@ -15,6 +15,7 @@
 from agentuniverse.agent.plan.planner.planner_manager import PlannerManager
 from agentuniverse.agent_serve.service_manager import ServiceManager
 from agentuniverse.agent_serve.service_configer import ServiceConfiger
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
 from agentuniverse.base.config.component_configer.component_configer import ComponentConfiger
 from agentuniverse.base.config.component_configer.configers.agent_configer import AgentConfiger
 from agentuniverse.base.config.component_configer.configers.knowledge_configer import KnowledgeConfiger
@@ -22,6 +23,7 @@
 from agentuniverse.base.config.component_configer.configers.planner_configer import PlannerConfiger
 from agentuniverse.base.config.component_configer.configers.prompt_configer import PromptConfiger
 from agentuniverse.base.config.component_configer.configers.tool_configer import ToolConfiger
+from agentuniverse.base.config.component_configer.configers.sqldb_wrapper_config import SQLDBWrapperConfiger
 from agentuniverse.base.config.config_type_enum import ConfigTypeEnum
 from agentuniverse.base.config.component_configer.configers.llm_configer import LLMConfiger
 from agentuniverse.base.component.component_enum import ComponentEnum
@@ -41,6 +43,7 @@ class ComponentConfigerUtil(object):
         ComponentEnum.MEMORY: MemoryConfiger,
         ComponentEnum.SERVICE: ServiceConfiger,
         ComponentEnum.PROMPT: PromptConfiger,
+        ComponentEnum.SQLDB_WRAPPER: SQLDBWrapperConfiger,
         ComponentEnum.DEFAULT: ComponentConfiger
     }
 
@@ -52,6 +55,7 @@ class ComponentConfigerUtil(object):
         ComponentEnum.TOOL: ToolManager,
         ComponentEnum.MEMORY: MemoryManager,
         ComponentEnum.SERVICE: ServiceManager,
+        ComponentEnum.SQLDB_WRAPPER: SQLDBWrapperManager,
         ComponentEnum.PROMPT: PromptManager
     }
 
diff --git a/agentuniverse/base/component/component_enum.py b/agentuniverse/base/component/component_enum.py
index 5c88a1f0..82071368 100644
--- a/agentuniverse/base/component/component_enum.py
+++ b/agentuniverse/base/component/component_enum.py
@@ -19,6 +19,7 @@ class ComponentEnum(Enum):
     SERVICE = "SERVICE"
     MEMORY = "MEMORY"
     PROMPT = "PROMPT"
+    SQLDB_WRAPPER = "SQLDB_WRAPPER"
 
     @staticmethod
     def to_value_list():
diff --git a/agentuniverse/base/component/component_manager_base.py b/agentuniverse/base/component/component_manager_base.py
index a9b1cf9b..465e492d 100644
--- a/agentuniverse/base/component/component_manager_base.py
+++ b/agentuniverse/base/component/component_manager_base.py
@@ -5,14 +5,12 @@
 # @Author  : jerry.zzw 
 # @Email   : jerry.zzw@antgroup.com
 # @FileName: component_manager_base.py
-from agentuniverse.base.component.component_base import ComponentBase
-from agentuniverse.base.component.component_enum import ComponentEnum
-import importlib
-import inspect
-import pkgutil
+import copy
 from typing import TypeVar, Generic
 
 from agentuniverse.base.config.application_configer.application_config_manager import ApplicationConfigManager
+from agentuniverse.base.component.component_base import ComponentBase
+from agentuniverse.base.component.component_enum import ComponentEnum
 
 # 添加类型范型限定
 ComponentTypeVar = TypeVar("ComponentTypeVar", bound=ComponentBase)
@@ -40,10 +38,12 @@ def unregister(self, component_instance_name: str):
         self._instance_obj_map.pop(component_instance_name)
 
     def get_instance_obj(self, component_instance_name: str,
-                         appname: str = None) -> ComponentTypeVar:
+                         appname: str = None, new_instance: bool = None) -> ComponentTypeVar:
         """Return the component instance object."""
         appname = appname or ApplicationConfigManager().app_configer.base_info_appname
         instance_code = f'{appname}.{self._component_type.value.lower()}.{component_instance_name}'
+        if new_instance:
+            return copy.deepcopy(self._instance_obj_map.get(instance_code))
         return self._instance_obj_map.get(instance_code)
 
     def get_instance_name_list(self) -> list[str]:
diff --git a/agentuniverse/base/config/application_configer/app_configer.py b/agentuniverse/base/config/application_configer/app_configer.py
index 08b0e133..56598a23 100644
--- a/agentuniverse/base/config/application_configer/app_configer.py
+++ b/agentuniverse/base/config/application_configer/app_configer.py
@@ -24,6 +24,7 @@ def __init__(self):
         self.__core_tool_package_list: Optional[list[str]] = None
         self.__core_memory_package_list: Optional[list[str]] = None
         self.__core_service_package_list: Optional[list[str]] = None
+        self.__core_sqldb_wrapper_package_list: Optional[list[str]] = None
         self.__core_prompt_package_list: Optional[list[str]] = None
 
     @property
@@ -71,6 +72,11 @@ def core_service_package_list(self) -> Optional[list[str]]:
         """Return the service package list of the core."""
         return self.__core_service_package_list
 
+    @property
+    def core_sqldb_wrapper_package_list(self) -> Optional[list[str]]:
+        """Return the sql db wrapper package list of the core."""
+        return self.__core_sqldb_wrapper_package_list
+
     @property
     def core_prompt_package_list(self) -> Optional[list[str]]:
         return self.__core_prompt_package_list
@@ -93,5 +99,6 @@ def load_by_configer(self, configer: Configer) -> 'AppConfiger':
         self.__core_tool_package_list = configer.value.get('CORE_PACKAGE', {}).get('tool')
         self.__core_memory_package_list = configer.value.get('CORE_PACKAGE', {}).get('memory')
         self.__core_service_package_list = configer.value.get('CORE_PACKAGE', {}).get('service')
+        self.__core_sqldb_wrapper_package_list = configer.value.get('CORE_PACKAGE', {}).get('sqldb_wrapper')
         self.__core_prompt_package_list = configer.value.get('CORE_PACKAGE', {}).get('prompt')
         return self
diff --git a/agentuniverse/base/config/component_configer/configers/llm_configer.py b/agentuniverse/base/config/component_configer/configers/llm_configer.py
index 6551f189..f89fb40e 100644
--- a/agentuniverse/base/config/component_configer/configers/llm_configer.py
+++ b/agentuniverse/base/config/component_configer/configers/llm_configer.py
@@ -26,6 +26,7 @@ def __init__(self, configer: Optional[Configer] = None):
         self.__streaming: Optional[bool] = None
         self.__ext_info: Optional[dict] = None
         self.__max_context_length: Optional[int] = None
+        self.__tracing: Optional[bool] = None
 
     @property
     def name(self) -> Optional[str]:
@@ -70,6 +71,10 @@ def ext_info(self) -> Optional[dict]:
     def max_content_length(self) -> Optional[int]:
         return self.__max_context_length
 
+    @property
+    def tracing(self) -> Optional[bool]:
+        return self.__tracing
+
     def load(self) -> 'LLMConfiger':
         """Load the configuration by the Configer object.
         Returns:
@@ -97,6 +102,7 @@ def load_by_configer(self, configer: Configer) -> 'LLMConfiger':
             self.__streaming = configer.value.get('streaming')
             self.__ext_info = configer.value.get('ext_info')
             self.__max_context_length = configer.value.get('max_context_length')
+            self.__tracing = configer.value.get('tracing')
         except Exception as e:
             raise Exception(f"Failed to parse the LLM configuration: {e}")
         return self
diff --git a/agentuniverse/base/config/component_configer/configers/sqldb_wrapper_config.py b/agentuniverse/base/config/component_configer/configers/sqldb_wrapper_config.py
new file mode 100644
index 00000000..9c9f775c
--- /dev/null
+++ b/agentuniverse/base/config/component_configer/configers/sqldb_wrapper_config.py
@@ -0,0 +1,83 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/21 17:13
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: sqldb_wrapper_config.py
+
+from typing import Optional
+
+from agentuniverse.base.config.component_configer.component_configer import ComponentConfiger
+from agentuniverse.base.config.configer import Configer
+from agentuniverse.base.util.system_util import parse_dynamic_str
+
+
+class SQLDBWrapperConfiger(ComponentConfiger):
+    """The SQLDBWrapperConfiger class, used to load and manage the sql db wrapper
+    configuration."""
+
+    _ComponentConfiger__metadata_class: Optional[str] = None
+    _ComponentConfiger__metadata_module: Optional[str] = None
+
+    def __init__(self, configer: Optional[Configer] = None):
+        """Initialize the DBWrapperConfiger."""
+        super().__init__(configer)
+        self.__name: Optional[str] = None
+        self.__description: Optional[str] = None
+
+        self.sql_database_args: dict = {}
+        self.db_uri: Optional[str] = None
+        self.engine_args: dict = {}
+
+        self.__set_default_meta_info()
+
+    @property
+    def name(self) -> Optional[str]:
+        """Name field."""
+        return self.__name
+
+    @property
+    def description(self) -> Optional[str]:
+        """Description field."""
+        return self.__description
+
+    def __set_default_meta_info(self):
+        """Set default instantiated class of service."""
+        if (not hasattr(self, '_ComponentConfiger__metadata_module')
+                or self._ComponentConfiger__metadata_module is None):
+            self._ComponentConfiger__metadata_module = (
+                "agentuniverse.database.sqldb_wrapper"
+            )
+        if (not hasattr(self, '_ComponentConfiger__metadata_class')
+                or self._ComponentConfiger__metadata_class is None):
+            self._ComponentConfiger__metadata_class = 'SQLDBWrapper'
+
+    def load(self) -> 'SQLDBWrapperConfiger':
+        """Setting property using own configer member property.
+
+        Returns:
+            SQLDBWrapperConfiger: A SQLDBWrapperConfiger instance.
+        """
+        return self.load_by_configer(self.configer)
+
+    def load_by_configer(self, configer: Configer) -> 'SQLDBWrapperConfiger':
+        """Initialize self using given configer, get SQLDBWrapperConfiger property
+        from it.
+        Args:
+            configer(Configer): A Configer instance.
+        Returns:
+            SQLDBWrapperConfiger: A SQLDBWrapperConfiger instance.
+        """
+        super().load_by_configer(configer)
+        self.__set_default_meta_info()
+        try:
+            self.__name = configer.value.get('name')
+            self.__description = configer.value.get('description')
+            self.db_uri = parse_dynamic_str(configer.value.get('db_uri'))
+            self.engine_args = dict(configer.value.get('engine_args', {}))
+            self.sql_database_args = dict(configer.value.get('sql_database_args', {}))
+
+        except Exception as e:
+            raise Exception(f"Failed to parse the db wrapper configuration: {e}")
+        return self
diff --git a/agentuniverse/base/util/memory_util.py b/agentuniverse/base/util/memory_util.py
index e89e584c..e8179c8a 100644
--- a/agentuniverse/base/util/memory_util.py
+++ b/agentuniverse/base/util/memory_util.py
@@ -7,6 +7,8 @@
 # @FileName: memory_util.py
 from typing import List
 
+from langchain_core.chat_history import BaseChatMessageHistory
+
 from agentuniverse.agent.memory.message import Message
 
 
@@ -16,3 +18,8 @@ def generate_messages(memories: list) -> List[Message]:
         message: Message = Message(type=memory.get('type'), content=memory.get('content'))
         messages.append(message)
     return messages
+
+
+def generate_memories(chat_messages: BaseChatMessageHistory) -> list:
+    return [{"content": message.content, "type": message.type}
+            for message in chat_messages.messages] if chat_messages.messages else []
diff --git a/agentuniverse/base/util/monitor/__init__.py b/agentuniverse/base/util/monitor/__init__.py
new file mode 100644
index 00000000..34cfc90e
--- /dev/null
+++ b/agentuniverse/base/util/monitor/__init__.py
@@ -0,0 +1,7 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/6/5 15:38
+# @Author  : wangchongshi
+# @Email   : wangchongshi.wcs@antgroup.com
+# @FileName: __init__.py.py
diff --git a/agentuniverse/base/util/monitor/monitor.py b/agentuniverse/base/util/monitor/monitor.py
new file mode 100644
index 00000000..7b4e942e
--- /dev/null
+++ b/agentuniverse/base/util/monitor/monitor.py
@@ -0,0 +1,64 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/20 16:24
+# @Author  : wangchongshi
+# @Email   : wangchongshi.wcs@antgroup.com
+# @FileName: monitor.py
+import datetime
+import json
+import os
+from typing import Union, Optional
+
+from pydantic import BaseModel
+
+from agentuniverse.base.annotation.singleton import singleton
+from agentuniverse.base.config.configer import Configer
+
+LLM_INVOCATION_SUBDIR = "llm_invocation"
+
+
+@singleton
+class Monitor(BaseModel):
+    dir: Optional[str] = './monitor'
+    activate: Optional[bool] = False
+
+    def __init__(self, configer: Configer = None, **kwargs):
+        super().__init__(**kwargs)
+        if configer:
+            config: dict = configer.value.get('MONITOR', {})
+            self.dir = config.get('dir', './monitor')
+            self.activate = config.get('activate', False)
+
+    def trace_llm_invocation(self, source: str, llm_input: Union[str, dict], llm_output: Union[str, dict]) -> None:
+        """Trace the llm invocation and save it to the monitor jsonl file."""
+        if self.activate:
+            try:
+                import jsonlines
+            except ImportError:
+                raise ImportError(
+                    "jsonlines is required to trace llm invocation: `pip install jsonlines`"
+                )
+            # get the current time
+            date = datetime.datetime.now()
+            llm_invocation = {
+                "source": source,
+                "date": date.strftime("%Y-%m-%d %H:%M:%S"),
+                "llm_input": llm_input,
+                "llm_output": llm_output,
+            }
+            # files are stored in hours
+            filename = f"llm_{date.strftime('%Y-%m-%d-%H')}.jsonl"
+            # file path to save
+            path_save = os.path.join(str(self._get_or_create_subdir(LLM_INVOCATION_SUBDIR)), filename)
+
+            # write to jsonl
+            with jsonlines.open(path_save, 'a') as writer:
+                json_record = json.dumps(llm_invocation, ensure_ascii=False)
+                writer.write(json_record)
+
+    def _get_or_create_subdir(self, subdir: str) -> str:
+        """Get or create a subdirectory if it doesn't exist in the monitor directory."""
+        path = os.path.join(self.dir, subdir)
+        os.makedirs(path, exist_ok=True)
+        return path
diff --git a/agentuniverse/base/util/prompt_util.py b/agentuniverse/base/util/prompt_util.py
index 49a3301e..ec6b2dcb 100644
--- a/agentuniverse/base/util/prompt_util.py
+++ b/agentuniverse/base/util/prompt_util.py
@@ -171,15 +171,18 @@ def process_llm_token(agent_llm: LLM, lc_prompt_template, profile: dict, planner
 
     # compress the background in the prompt
     content = planner_input.get('background')
-    if process_prompt_type_enum == PromptProcessEnum.TRUNCATE:
-        planner_input['background'] = truncate_content(content, input_tokens, agent_llm)
-    elif process_prompt_type_enum == PromptProcessEnum.STUFF:
-        planner_input['background'] = summarize_by_stuff(texts=[content], llm=prompt_llm,
-                                                         summary_prompt=PromptManager().get_instance_obj(
-                                                             summary_prompt_version))
-    elif process_prompt_type_enum == PromptProcessEnum.MAP_REDUCE:
-        planner_input['background'] = summarize_by_map_reduce(texts=split_texts([content], agent_llm), llm=prompt_llm,
-                                                              summary_prompt=PromptManager().get_instance_obj(
-                                                                  summary_prompt_version),
-                                                              combine_prompt=PromptManager().get_instance_obj(
-                                                                  combine_prompt_version))
+
+    if content:
+        if process_prompt_type_enum == PromptProcessEnum.TRUNCATE:
+            planner_input['background'] = truncate_content(content, input_tokens, agent_llm)
+        elif process_prompt_type_enum == PromptProcessEnum.STUFF:
+            planner_input['background'] = summarize_by_stuff(texts=[content], llm=prompt_llm,
+                                                             summary_prompt=PromptManager().get_instance_obj(
+                                                                 summary_prompt_version))
+        elif process_prompt_type_enum == PromptProcessEnum.MAP_REDUCE:
+            planner_input['background'] = summarize_by_map_reduce(texts=split_texts([content], agent_llm),
+                                                                  llm=prompt_llm,
+                                                                  summary_prompt=PromptManager().get_instance_obj(
+                                                                      summary_prompt_version),
+                                                                  combine_prompt=PromptManager().get_instance_obj(
+                                                                      combine_prompt_version))
diff --git a/agentuniverse/base/util/system_util.py b/agentuniverse/base/util/system_util.py
index 94d977be..6d0e2f17 100644
--- a/agentuniverse/base/util/system_util.py
+++ b/agentuniverse/base/util/system_util.py
@@ -7,6 +7,7 @@
 # @FileName: system_util.py
 
 from pathlib import Path
+import importlib
 
 PROJECT_ROOT_PATH = None
 
@@ -24,3 +25,27 @@ def get_project_root_path() -> Path:
     root_path = current_work_directory.parents[1]
     PROJECT_ROOT_PATH = root_path
     return root_path
+
+
+def parse_dynamic_str(param: str):
+    """
+    Translate a string, firstly attempting to parse it as a full path to a
+    parameterless function. If it can be correctly imported, return the result
+    of the function execution, otherwise return the original string.
+    This is useful in scenarios where it's inconvenient to write the real
+    value directly, such as with secret keys.
+    """
+    try:
+        parts = param.rsplit('.', 1)
+        if len(parts) == 2:
+            module_path, func_name = parts
+            module = importlib.import_module(module_path)
+            func = getattr(module, func_name)
+            if callable(func):
+                return func()
+            else:
+                return param
+        else:
+            return param
+    except (ImportError, AttributeError, Exception):
+        return param
\ No newline at end of file
diff --git a/agentuniverse/database/__init__.py b/agentuniverse/database/__init__.py
new file mode 100644
index 00000000..1b80a9b1
--- /dev/null
+++ b/agentuniverse/database/__init__.py
@@ -0,0 +1,7 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/21 16:48
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: __init__.py.py
diff --git a/agentuniverse/database/sqldb_wrapper.py b/agentuniverse/database/sqldb_wrapper.py
new file mode 100644
index 00000000..407d8542
--- /dev/null
+++ b/agentuniverse/database/sqldb_wrapper.py
@@ -0,0 +1,106 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/21 17:12
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: sqldb_wrapper.py
+
+import json
+from typing import Optional, Sequence, Any, Dict
+
+from langchain_community.utilities.sql_database import SQLDatabase
+from sqlalchemy.orm import sessionmaker
+
+from ..base.config.application_configer.application_config_manager import (
+    ApplicationConfigManager
+)
+from ..base.config.component_configer.configers.sqldb_wrapper_config import SQLDBWrapperConfiger
+from ..base.component.component_base import ComponentBase
+from ..base.component.component_enum import ComponentEnum
+
+
+class SQLDBWrapper(ComponentBase):
+    """A sql DB wrapper based on sqlalchemy and langchain sql database, """
+
+    # Basic attributes of the service class.
+    component_type: ComponentEnum = ComponentEnum.SQLDB_WRAPPER
+    name: Optional[str] = None
+    description: Optional[str] = None
+    __sql_database: Optional[SQLDatabase] = None
+    db_session: Optional[sessionmaker] = None
+    db_wrapper_configer: Optional[SQLDBWrapperConfiger] = None
+
+    class Config:
+        arbitrary_types_allowed = True
+
+    def get_instance_code(self) -> str:
+        """Generate the full instance code from sql db wrapper name. """
+        app_cfg_manager: ApplicationConfigManager = ApplicationConfigManager()
+        appname = app_cfg_manager.app_configer.base_info_appname
+        return f"{appname}.{self.component_type.value.lower()}.{self.name}"
+
+    def initialize_by_component_configer(self,
+                                         db_wrapper_configer: SQLDBWrapperConfiger
+                                         ) -> 'SQLDBWrapper':
+        """Initialize the SQLDBWrapper by the ComponentConfiger object.
+
+        Args:
+            db_wrapper_configer(SQLDBWrapperConfiger): A configer contains service
+            basic info.
+        Returns:
+            SQLDBWrapper: A SQLDBWrapper instance.
+        """
+        self.name = db_wrapper_configer.name
+        self.description = db_wrapper_configer.description
+        self.db_wrapper_configer = db_wrapper_configer
+        return self
+
+    def run(self, command: str) -> Sequence[Dict[str, Any]]:
+        """
+        Execute given sql command and return a result sequence.
+        """
+        return self.sql_database._execute(command=command)
+
+
+    def run_with_str_return(self, command: str) -> str:
+        """
+        Execute given sql command and return a str result, intended to be used
+        as a part of llm input. If db wrapper's 'max_string_length' property is
+        not negative, result str will be truncated.
+        """
+        return self.sql_database.run(command, fetch="all")
+
+    @property
+    def sql_database(self):
+        """
+        Lazy init, to ensure that database engine can be init correctly in
+        separate processes like gunicorn.
+        """
+        if not self.__sql_database:
+            self.db_wrapper_configer.engine_args.setdefault(
+                "json_serializer", lambda x: json.dumps(x, ensure_ascii=False)
+            )
+            self.db_wrapper_configer.sql_database_args.setdefault(
+                "sample_rows_in_table_info", 3
+            )
+            self.db_wrapper_configer.sql_database_args.setdefault(
+                "max_string_length", -1
+            )
+            self.__sql_database = SQLDatabase.from_uri(
+                engine_args=self.db_wrapper_configer.engine_args,
+                database_uri=self.db_wrapper_configer.db_uri,
+                **self.db_wrapper_configer.sql_database_args
+            )
+        return self.__sql_database
+
+
+    def get_session(self):
+        """
+           Get a sqlalchemy session, used for operating with orm.
+        """
+        if self.db_session:
+            return self.db_session()
+        # Create database engine
+        self.db_session = sessionmaker(bind=self.sql_database._engine)
+        return self.db_session()
diff --git a/agentuniverse/database/sqldb_wrapper_manager.py b/agentuniverse/database/sqldb_wrapper_manager.py
new file mode 100644
index 00000000..f3f6eb65
--- /dev/null
+++ b/agentuniverse/database/sqldb_wrapper_manager.py
@@ -0,0 +1,13 @@
+from ..base.annotation.singleton import singleton
+from ..base.component.component_enum import ComponentEnum
+from ..base.component.component_manager_base import ComponentManagerBase
+from .sqldb_wrapper import SQLDBWrapper
+
+
+@singleton
+class SQLDBWrapperManager(ComponentManagerBase[SQLDBWrapper]):
+    """A singleton manager class of the DBWrapper."""
+
+    def __init__(self):
+        super().__init__(ComponentEnum.SQLDB_WRAPPER)
+
diff --git a/agentuniverse/llm/default/baichuan_openai_style_llm.py b/agentuniverse/llm/default/baichuan_openai_style_llm.py
index 38b58395..0ba743d9 100644
--- a/agentuniverse/llm/default/baichuan_openai_style_llm.py
+++ b/agentuniverse/llm/default/baichuan_openai_style_llm.py
@@ -5,14 +5,13 @@
 # @Author  : weizjajj
 # @Email   : weizhongjie.wzj@antgroup.com
 # @FileName: baichuan_openai_style_llm.py
+from typing import Optional, Any, Union, Iterator, AsyncIterator
 
-from typing import Optional
-
-from langchain_community.chat_models import ChatBaichuan
-from langchain_core.language_models import BaseLanguageModel
 from pydantic import Field
 
+from agentuniverse.base.annotation.trace import trace_llm
 from agentuniverse.base.util.env_util import get_from_env
+from agentuniverse.llm.llm_output import LLMOutput
 from agentuniverse.llm.openai_style_llm import OpenAIStyleLLM
 
 BAICHUAN_Max_CONTEXT_LENGTH = {
@@ -41,3 +40,27 @@ def max_context_length(self) -> int:
         if super().max_context_length():
             return super().max_context_length()
         return BAICHUAN_Max_CONTEXT_LENGTH.get(self.model_name, 8000)
+
+    @trace_llm
+    def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
+        """ The call method of the LLM.
+
+        Users can customize how the model interacts by overriding call method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return super().call(messages, **kwargs)
+
+    @trace_llm
+    async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
+        """ The async call method of the LLM.
+
+        Users can customize how the model interacts by overriding acall method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return await super().acall(messages, **kwargs)
diff --git a/agentuniverse/llm/default/default_openai_llm.py b/agentuniverse/llm/default/default_openai_llm.py
index 38987727..9dafa1a8 100644
--- a/agentuniverse/llm/default/default_openai_llm.py
+++ b/agentuniverse/llm/default/default_openai_llm.py
@@ -5,15 +5,15 @@
 # @Author  : wangchongshi
 # @Email   : wangchongshi.wcs@antgroup.com
 # @FileName: default_openai_llm.py
-from typing import Any, Optional
+from typing import Any, Optional, Iterator, Union, AsyncIterator
 
 from pydantic import Field
 
+from agentuniverse.base.annotation.trace import trace_llm
 from agentuniverse.base.util.env_util import get_from_env
 from agentuniverse.llm.llm_output import LLMOutput
 from agentuniverse.llm.openai_style_llm import OpenAIStyleLLM
 
-
 OPENAI_MAX_CONTEXT_LENGTH = {
     "gpt-3.5-turbo": 4096,
     "gpt-3.5-turbo-0301": 4096,
@@ -47,7 +47,8 @@ class DefaultOpenAILLM(OpenAIStyleLLM):
     api_base: Optional[str] = Field(default_factory=lambda: get_from_env("OPENAI_API_BASE"))
     proxy: Optional[str] = Field(default_factory=lambda: get_from_env("OPENAI_PROXY"))
 
-    def call(self, messages: list, **kwargs: Any) -> LLMOutput:
+    @trace_llm
+    def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
         """ The call method of the LLM.
 
         Users can customize how the model interacts by overriding call method of the LLM class.
@@ -58,7 +59,8 @@ def call(self, messages: list, **kwargs: Any) -> LLMOutput:
         """
         return super().call(messages, **kwargs)
 
-    async def acall(self, messages: list, **kwargs: Any) -> LLMOutput:
+    @trace_llm
+    async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
         """ The async call method of the LLM.
 
         Users can customize how the model interacts by overriding acall method of the LLM class.
diff --git a/agentuniverse/llm/default/kimi_openai_style_llm.py b/agentuniverse/llm/default/kimi_openai_style_llm.py
index 122f8175..5c6112c9 100644
--- a/agentuniverse/llm/default/kimi_openai_style_llm.py
+++ b/agentuniverse/llm/default/kimi_openai_style_llm.py
@@ -5,13 +5,14 @@
 # @Author  : weizjajj
 # @Email   : weizhongjie.wzj@antgroup.com
 # @FileName: kimi_openai_style_llm.py
-
-from typing import Optional
+from typing import Optional, Any, Union, Iterator, AsyncIterator
 
 import requests
 from pydantic import Field
 
+from agentuniverse.base.annotation.trace import trace_llm
 from agentuniverse.base.util.env_util import get_from_env
+from agentuniverse.llm.llm_output import LLMOutput
 from agentuniverse.llm.openai_style_llm import OpenAIStyleLLM
 
 KIMI_Max_CONTEXT_LENGTH = {
@@ -33,6 +34,30 @@ class KIMIOpenAIStyleLLM(OpenAIStyleLLM):
     proxy: Optional[str] = Field(default_factory=lambda: get_from_env("KIMI_PROXY"))
     organization: Optional[str] = Field(default_factory=lambda: get_from_env("KIMI_ORGANIZATION"))
 
+    @trace_llm
+    def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
+        """ The call method of the LLM.
+
+        Users can customize how the model interacts by overriding call method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return super().call(messages, **kwargs)
+
+    @trace_llm
+    async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
+        """ The async call method of the LLM.
+
+        Users can customize how the model interacts by overriding acall method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return await super().acall(messages, **kwargs)
+
     def max_context_length(self) -> int:
         if super().max_context_length():
             return super().max_context_length()
diff --git a/agentuniverse/llm/default/qwen_openai_style_llm.py b/agentuniverse/llm/default/qwen_openai_style_llm.py
index 2816c32e..47295b65 100644
--- a/agentuniverse/llm/default/qwen_openai_style_llm.py
+++ b/agentuniverse/llm/default/qwen_openai_style_llm.py
@@ -5,13 +5,14 @@
 # @Author  : weizjajj
 # @Email   : weizhongjie.wzj@antgroup.com
 # @FileName: qwen_openai_style_llm.py
-
-from typing import Optional
+from typing import Optional, Any, Union, Iterator, AsyncIterator
 
 from dashscope import get_tokenizer
 from pydantic import Field
 
+from agentuniverse.base.annotation.trace import trace_llm
 from agentuniverse.base.util.env_util import get_from_env
+from agentuniverse.llm.llm_output import LLMOutput
 from agentuniverse.llm.openai_style_llm import OpenAIStyleLLM
 
 QWen_Max_CONTEXT_LENGTH = {
@@ -26,7 +27,6 @@
 
 
 class QWenOpenAIStyleLLM(OpenAIStyleLLM):
-
     """
         QWen OpenAI style LLM
         Args:
@@ -39,6 +39,30 @@ class QWenOpenAIStyleLLM(OpenAIStyleLLM):
     proxy: Optional[str] = Field(default_factory=lambda: get_from_env("DASHSCOPE_PROXY"))
     organization: Optional[str] = Field(default_factory=lambda: get_from_env("DASHSCOPE_ORGANIZATION"))
 
+    @trace_llm
+    def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
+        """ The call method of the LLM.
+
+        Users can customize how the model interacts by overriding call method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return super().call(messages, **kwargs)
+
+    @trace_llm
+    async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
+        """ The async call method of the LLM.
+
+        Users can customize how the model interacts by overriding acall method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return await super().acall(messages, **kwargs)
+
     def max_context_length(self) -> int:
         if super().max_context_length():
             return super().max_context_length()
diff --git a/agentuniverse/llm/default/wenxin_llm.py b/agentuniverse/llm/default/wenxin_llm.py
index 44ee53d9..a4ace3fa 100644
--- a/agentuniverse/llm/default/wenxin_llm.py
+++ b/agentuniverse/llm/default/wenxin_llm.py
@@ -5,16 +5,15 @@
 # @Author  : weizjajj 
 # @Email   : weizhongjie.wzj@antgroup.com
 # @FileName: wenxin_llm.py
-
 from typing import Any, Union, AsyncIterator, Iterator
 
 import qianfan
-from langchain_community.chat_models import QianfanChatEndpoint
 from langchain_core.language_models import BaseLanguageModel
 from pydantic import Field
 from qianfan import QfResponse
 from qianfan.resources.tools import tokenizer
 
+from agentuniverse.base.annotation.trace import trace_llm
 from agentuniverse.base.util.env_util import get_from_env
 from agentuniverse.llm.llm import LLM
 from agentuniverse.llm.llm_output import LLMOutput
@@ -51,6 +50,7 @@ def _new_client(self):
         """Create a new Qianfan client."""
         return qianfan.ChatCompletion(ak=self.qianfan_ak, sk=self.qianfan_sk)
 
+    @trace_llm
     def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
         """Run the OpenAI LLM.
 
@@ -73,6 +73,7 @@ def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOu
             return self.parse_result(chat_completion)
         return self.generate_stream_result(chat_completion)
 
+    @trace_llm
     async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
         """Asynchronously run the OpenAI LLM.
 
diff --git a/agentuniverse/llm/langchain_instance.py b/agentuniverse/llm/langchain_instance.py
index eb9f965f..d60bfee9 100644
--- a/agentuniverse/llm/langchain_instance.py
+++ b/agentuniverse/llm/langchain_instance.py
@@ -9,7 +9,7 @@
 from typing import Any, List, Optional, AsyncIterator
 
 from langchain.callbacks.manager import AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun
-from langchain.chat_models import ChatOpenAI
+from langchain_community.chat_models.openai import ChatOpenAI
 from langchain.schema import BaseMessage, ChatResult
 from langchain_community.chat_models.openai import _convert_delta_to_message_chunk
 from langchain_core.language_models.chat_models import generate_from_stream, agenerate_from_stream
diff --git a/agentuniverse/llm/llm.py b/agentuniverse/llm/llm.py
index 23c97d26..736e7f67 100644
--- a/agentuniverse/llm/llm.py
+++ b/agentuniverse/llm/llm.py
@@ -44,6 +44,7 @@ class LLM(ComponentBase):
     max_retries: Optional[int] = 2
     streaming: Optional[bool] = False
     ext_info: Optional[dict] = None
+    tracing: Optional[bool] = None
     __max_context_length: Optional[int] = None
 
     def __init__(self, **kwargs):
@@ -101,7 +102,7 @@ def initialize_by_component_configer(self, component_configer: LLMConfiger) -> '
             self.streaming = component_configer.streaming
         if component_configer.ext_info:
             self.ext_info = component_configer.ext_info
-
+        self.tracing = component_configer.tracing
         return self
 
     def set_by_agent_model(self, **kwargs) -> None:
@@ -140,6 +141,3 @@ def get_num_tokens(self, text: str) -> int:
         Returns:
             The integer number of tokens in the text.
         """
-
-    class Config:
-        protected_namespaces = ()
diff --git a/agentuniverse/llm/openai_style_langchain_instance.py b/agentuniverse/llm/openai_style_langchain_instance.py
index 582361a5..8b9506ce 100644
--- a/agentuniverse/llm/openai_style_langchain_instance.py
+++ b/agentuniverse/llm/openai_style_langchain_instance.py
@@ -12,7 +12,7 @@
 from langchain.schema import BaseMessage, ChatResult
 from langchain_community.chat_models.openai import _convert_delta_to_message_chunk
 from langchain_core.language_models.chat_models import generate_from_stream, agenerate_from_stream
-from langchain_core.messages import AIMessageChunk
+from langchain_core.messages import AIMessageChunk, get_buffer_string
 from langchain_core.outputs import ChatGenerationChunk
 from langchain_community.chat_models import ChatOpenAI
 
@@ -130,3 +130,7 @@ async def as_langchain_achunk(stream_iterator: AsyncIterator, run_manager=None)
             yield chunk
             if run_manager:
                 await run_manager.on_llm_new_token(token=chunk.text, chunk=chunk)
+
+    def get_num_tokens_from_messages(self, messages: List[BaseMessage]) -> int:
+        messages_str = get_buffer_string(messages)
+        return self.llm.get_num_tokens(messages_str)
diff --git a/agentuniverse/llm/openai_style_llm.py b/agentuniverse/llm/openai_style_llm.py
index 4a668374..c4a84da4 100644
--- a/agentuniverse/llm/openai_style_llm.py
+++ b/agentuniverse/llm/openai_style_llm.py
@@ -19,11 +19,12 @@
 
 
 class OpenAIStyleLLM(LLM):
-    """
-    This is a wrapper around the OpenAI API that implements a chat interface for the LLM.
+    """This is a wrapper around the OpenAI API that implements a chat interface for the LLM.
+
     It uses the `chat` endpoint of the OpenAI API.
     It also supports using the `completion` endpoint instead of the `chat` endpoint.
     It supports both sync and async modes.
+
     Attributes:
         api_key (Optional[str]): The API key to use for authentication.
         organization (Optional[str]): The organization ID to use for authentication.
diff --git a/docs/guidebook/en/0_index.md b/docs/guidebook/en/0_index.md
index 58fda6b7..6ca56443 100644
--- a/docs/guidebook/en/0_index.md
+++ b/docs/guidebook/en/0_index.md
@@ -54,6 +54,8 @@
   * 3.2.1 RPC
     * 3.2.1.1 [gRPC](3_2_1_gRPC.md)
   * 3.2.2 Store
+    * 3.2.2.1 [SQLDBWrapper](2_3_1_SQLDB_WRAPPER.md)
+    * 3.2.2.2 [Milvus](3_3_1_Milvus.md)
   * 3.2.3 Msg
   * 3.2.4 Logging
     * 3.2.4.1 [Alibaba Cloud SLS](3_2_4_Alibaba_Cloud_SLS.md)
diff --git a/docs/guidebook/en/2_3_1_SQLDB_WRAPPER.md b/docs/guidebook/en/2_3_1_SQLDB_WRAPPER.md
new file mode 100644
index 00000000..2051c52c
--- /dev/null
+++ b/docs/guidebook/en/2_3_1_SQLDB_WRAPPER.md
@@ -0,0 +1,76 @@
+# SQLDB Wrapper
+
+Based on SQLAlchemy and langchain's SQLDatabase, agentUniverse offers a `SQLDBWrapper` class allowing users to conveniently use most SQL-based databases like SQLite, MySQL, Oracle, etc. For details, please refer to the [SQLAlchemy official website](https://docs.sqlalchemy.org/en/20/dialects/). With SQLDBWrapper, you can easily manage multiple different database connection objects at the same time.
+
+## Registration Method
+
+### Step One: Configure Scan Path
+gentUniverse automatically registers the SQLDBWrapper configuration files by scanning the configured paths at application startup. The paths to scan are configured in the `config.toml` file:
+```toml
+[CORE_PACKAGE]
+default = ['default_scan_path']
+sqldb_wrapper = ['sqldb_wrapper_scan_path']
+```
+By default, AgentUniverse scans all paths under `default` or `sqldb_wrapper`, with paths under `sqldb_wrapper` having a higher priority over `default`.
+
+
+### Step Two: Configuration File
+```yaml
+name: 'demo_sql'
+description: 'demo_sql'
+db_uri: "sqlite:///./demo.db"
+sql_database_args:
+  include_tables: ["users"]
+engine_args:
+  pool_size: 10
+metadata:
+  type: 'SQLDB_WRAPPER'
+```
+- **`name`**: The name of the SQLDBWrapper, used to identify a unique instance.
+- **`description`**: A description of the SQLDBWrapper's functionality.
+- **`db_uri`**: A SQLAlchemy-style database URI, used to create a SQLAlchemy engine.
+- **`sql_database_args`**: Optional parameters for the SQLDatabase class in `LangChain`, for specific details refer to [LangChain's official website](https://python.langchain.com/v0.1/docs/integrations/toolkits/sql_database/).
+- **`engine_args`**: Optional parameters, used to configure SQLAlchemy engine parameters. For specific configurable contents, please refer to [SQLAlchemy's webpage](https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.create_engine).
+- **`metadata`**: Indicates that this configuration is for a `SQLDB_WRAPPER`, no need to change.
+
+## Usage
+The SQLDBWrapper class offers the following functions for users:
+
+### run
+`run` accepts a `str` type parameter command, representing an SQL statement, and executes this SQL via SQLAlchemy, returning the results. The result is a list, if command is a query statement then the list will contain the query results, each element is a dictionary representing a row in the database, with the key as the column name and the value as the corresponding value.
+```python
+from agentuniverse.database.sqldb_wrapper import SQLDBWrapper
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
+
+demo_sqldb_wrapper:SQLDBWrapper = SQLDBWrapperManager().get_instance_obj("demo_sqldb_wrapper")
+demo_sqldb_wrapper.run("select * from USERS")
+```
+Example of returned result:
+```text
+[{'age': 30, 'id': 1, 'name': 'Alice'}, {'age': 25, 'id': 2, 'name': 'Bob'}]
+```
+
+### run_with_str_return
+`run_with_str_return` accepts a `str` type parameter command, representing an SQL statement, and executes this SQL via SQLAlchemy, returning the results. The result is a `str`, if command is a query statement then the str consists of all the query results concatenated together, and if the `max_string_length` parameter was configured in `sql_database_args`, the result will be truncated. This function is more convenient for using the results as input for llm.
+```python
+from agentuniverse.database.sqldb_wrapper import SQLDBWrapper
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
+
+demo_sqldb_wrapper:SQLDBWrapper = SQLDBWrapperManager().get_instance_obj("demo_sqldb_wrapper")
+demo_sqldb_wrapper.run_with_str_return("select * from USERS")
+```
+Example of returned result:
+```text
+"[(1, 'Alice', 30), (2, 'Bob', 25)]"
+```
+
+### sql_database
+If you wish to use some of the native features of SQLAlchemy or SQLDatabase, you can access the corresponding object through the `sql_database` property of SQLDBWrapper:
+```python
+from agentuniverse.database.sqldb_wrapper import SQLDBWrapper
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
+
+demo_sqldb_wrapper:SQLDBWrapper = SQLDBWrapperManager().get_instance_obj("demo_sqldb_wrapper")
+sql_database_ins = demo_sqldb_wrapper.sql_database
+sql_alchemy_engine = sql_database_ins._engine
+```
\ No newline at end of file
diff --git a/docs/guidebook/en/2_4_1_Service_Information_Storage.md b/docs/guidebook/en/2_4_1_Service_Information_Storage.md
index 0f384206..6130e76d 100644
--- a/docs/guidebook/en/2_4_1_Service_Information_Storage.md
+++ b/docs/guidebook/en/2_4_1_Service_Information_Storage.md
@@ -12,6 +12,9 @@ system_db_uri = ''
 ```
 Please note that this URI should comply with the URI format specification in SQLAlchemy.
 When this value is empty, a `DB` folder will be created in the project root directory, and a SQLite DB file named `agent_universe.db` will be created in the folder as the default system database.
+If you wish to obtain more information on how to use the system database, you can refer to the section [SQLDB_WRAPPER](2_3_1_SQLDB_WRAPPER.md), where the name of the system database is registered as `__system_db__`.
+
+
 
 ## Service Information Table Format
 agentUniverse uses the following ORM to store request information:
diff --git a/docs/guidebook/en/2_4_1_Web_Server.md b/docs/guidebook/en/2_4_1_Web_Server.md
index bad0a992..997912fe 100644
--- a/docs/guidebook/en/2_4_1_Web_Server.md
+++ b/docs/guidebook/en/2_4_1_Web_Server.md
@@ -1,6 +1,6 @@
 # Web Server
 
-AgentUniverse provides a web server based on Gunicorn+Flask. You can call the developed Agent services through the preset APIs in the web server.
+AgentUniverse provides a web server based on Flask. You can call the developed Agent services through the preset APIs in the web server.
 
 ## Web Server Launch
 You need to start the web server after launching the AgentUniverse application.
@@ -12,22 +12,30 @@ from agentuniverse.base.agentuniverse import AgentUniverse
 AgentUniverse().start()
 start_web_server()
 ```
-
-## Windows Users
-If you are using AgentUniverse on Windows, due to Gunicorn compatibility issues, AgentUniverse will run the Flask program directly. You can modify the start port in start_web_server, like this:：
+Flask server default port is 8888，you can change it by edit `bind` param:
 ```python
 from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
 
-start_web_server(bind='127.0.0.1:8888')
+AgentUniverse().start()
+start_web_server(bind="127.0.0.1:8002")
 ```
 
-## Web Server Configuration
-The configuration of the web server consists of four levels in order of increasing priority: native Gunicorn default configuration, AgentUniverse default configuration, configuration file settings, and startup configuration. For Gunicorn's native default configuration, please refer to the official documentation for the corresponding version of Gunicorn.
+If you need to configure more details or pursue production stability, you can use Gunicorn as the HTTP server.
+
+## Gunicorn Configuration
+You can set Gunicorn as your HTTP server by configuring it in the configuration file as follows:
+```toml
+[GUNICORN]
+activate = 'true'
+```
+
+The configuration of the Gunicorn server consists of four levels in order of increasing priority: native Gunicorn default configuration, AgentUniverse default configuration, configuration file settings, and startup configuration. For Gunicorn's native default configuration, please refer to the official documentation for the corresponding version of Gunicorn.
 
 ### AgentUniverse Default Configuration
 ```python
 DEFAULT_GUNICORN_CONFIG = {
-    'bind': '127.0.0.1:8000',
+    'bind': '127.0.0.1:8888',
     'workers': 5,
     'backlog': 2048,
     'worker_class': 'gthread',
@@ -41,7 +49,7 @@ AgentUniverse has pre-configured some parameters based on the framework's workin
 ### Configuration File Path
 The configuration path for the web server is specified in AgentUniverse's main configuration file `config.toml`.
 ```toml
-[SUB_CONFIG_PATH]
+[GUNICORN]
 # Gunicorn config file path, an absolute path or a relative path based on the dir where the current config file is located.
 gunicorn_config_path = './gunicorn_config.toml'
 ```
@@ -50,7 +58,7 @@ If this parameter is in relative path format, the corresponding parent directory
 ### Configuration File
 ```toml
 [GUNICORN_CONFIG]
-bind = '127.0.0.1:8000'
+bind = '127.0.0.1:8888'
 backlog = 2048
 worker_class = 'gthread'
 threads = 4
@@ -64,6 +72,22 @@ The configuration file is written in TOML format, and the specific configuration
 You can also configure the web server at startup as follows:
 ```python
 from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
 
+AgentUniverse().start()
 start_web_server(bind="127.0.0.1:8002", threads=4)
-```
\ No newline at end of file
+```
+If you have certain functions you want to execute after gunicorn fork child processes, you can add them in a way similar to the following:
+```python
+from agentuniverse.agent_serve.web.post_fork_queue import add_post_fork
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
+
+def print_hello(name: str):
+    print(f"hello {name}")
+
+add_post_fork(print_hello, "name")
+AgentUniverse().start()
+start_web_server(bind="127.0.0.1:8002")
+```
+You should observe the same amount output "hello name" as gunicorn workers。
\ No newline at end of file
diff --git a/docs/guidebook/en/3_2_1_gRPC.md b/docs/guidebook/en/3_2_1_gRPC.md
index 1024934f..68f2d20d 100644
--- a/docs/guidebook/en/3_2_1_gRPC.md
+++ b/docs/guidebook/en/3_2_1_gRPC.md
@@ -13,6 +13,16 @@ server_port = 50051
 - **max_workers**: The maximum number of threads in the gRPC server thread pool, with a default of 10.
 - **server_port**: The service port of the gRPC server, with a default of 50051.
 
+And then start the gRPC server:
+```python
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
+
+AgentUniverse().start()
+start_web_server()
+```
+
+
 ### Calling the gRPC Service
 
 ### Interface Definition
diff --git a/docs/guidebook/en/3_3_1_Milvus.md b/docs/guidebook/en/3_3_1_Milvus.md
new file mode 100644
index 00000000..a0c83538
--- /dev/null
+++ b/docs/guidebook/en/3_3_1_Milvus.md
@@ -0,0 +1,40 @@
+## Milvus
+If you want to use the Milvus vector database in aU, you need to:
+
+1. Install the Milvus vector database
+You can refer to the [official Milvus installation documentation](https://milvus.io/docs/install_standalone-docker.md) to install and use Milvus. We recommend starting the Milvus container in Docker with the following commands:
+``` shell
+# Download the installation script
+$ curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh
+
+# Start the Docker container
+$ bash standalone_embed.sh start
+```
+These two commands will pull the Milvus image and start a container, providing database services on port 19530. For more details and other installation methods, please refer to the official documentation.
+
+2. Install the Milvus Python SDK
+```
+pip install pymilvus
+```
+
+### What can I do with Milvus
+You can use Milvus in the Knowledge component to store and query knowledge. You can create a storage component using Milvus as follows:
+
+```python
+from agentuniverse.agent.action.knowledge.store.milvus_store import MilvusStore
+from agentuniverse.agent.action.knowledge.embedding.openai_embedding import OpenAIEmbedding
+from agentuniverse.agent.action.knowledge.knowledge import Knowledge
+
+init_params = {}
+init_params['name'] = 'test_knowledge'
+init_params['description'] = 'test_knowledge_description'
+init_params['store'] = MilvusStore(
+    connection_args={"host": "localhost", "port": "19530"},
+    collection_name="test_knowledge", 
+    embedding_model=OpenAIEmbedding(
+            embedding_model_name='text-embedding-ada-002'
+    )
+)
+knowledge = Knowledge(**init_params)
+```
+The above code will create a Milvus-based Knowledge instance. For detailed usage of Knowledge, you can refer to the [Knowledge documentation]() or the code `tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge_with_milvus.py`.
\ No newline at end of file
diff --git "a/docs/guidebook/zh/0_\347\233\256\345\275\225.md" "b/docs/guidebook/zh/0_\347\233\256\345\275\225.md"
index 5a296760..4090dd06 100644
--- "a/docs/guidebook/zh/0_\347\233\256\345\275\225.md"
+++ "b/docs/guidebook/zh/0_\347\233\256\345\275\225.md"
@@ -58,6 +58,8 @@
   * 3.2.1 RPC
     * 3.2.1.1 [gRPC](3_2_1_gRPC.md)
   * 3.2.2 存储 (Store)
+    * 3.2.2.1 [SQLDBWrapper](2_3_1_SQLDB_WRAPPER.md)
+    * 3.2.2.2 [Milvus](3_3_1_Milvus.md)
   * 3.2.3 消息(Msg)
   * 3.2.4 日志(Logging)
     * 3.2.4.1 [阿里云SLS](3_2_4_阿里云SLS.md)
diff --git a/docs/guidebook/zh/2_3_1_SQLDB_WRAPPER.md b/docs/guidebook/zh/2_3_1_SQLDB_WRAPPER.md
new file mode 100644
index 00000000..bf9c86f8
--- /dev/null
+++ b/docs/guidebook/zh/2_3_1_SQLDB_WRAPPER.md
@@ -0,0 +1,76 @@
+# SQLDB Wrapper
+
+AgentUniverse基于SQLAlchemy和langchain的SQLDatabase，提供了一个方便用户使用大多数基于SQL的数据库的`SQLDBWrapper`类，如SQLite、MySQL、Oracle等，具体请参考[SQLAlchemy官方网站](https://docs.sqlalchemy.org/en/20/dialects/)。通过`SQLDBWrapper`，您可以方便的同时管理多种不同的数据库连接对象。
+
+## 注册方式
+
+### 第一步：配置扫描路径
+AgentUniverse通过在应用启动时扫描配置路径的方式寻找SQLDBWrapper的配置文件并进行自动注册，扫描的路径配置在配置文件`config.toml`中：
+```toml
+[CORE_PACKAGE]
+default = ['default_scan_path']
+sqldb_wrapper = ['sqldb_wrapper_scan_path']
+```
+AgentUniverse默认会扫描`default`或`sqldb_wrapper`中的所有路径，`sqldb_wrapper`下的路径配置优先级高于`default`。
+
+
+### 第二步：配置文件
+```yaml
+name: 'demo_sql'
+description: 'demo_sql'
+db_uri: "sqlite:///./demo.db"
+sql_database_args:
+  include_tables: ["users"]
+engine_args:
+  pool_size: 10
+metadata:
+  type: 'SQLDB_WRAPPER'
+```
+- **`name`**:SQLDBWrapper的名称，用于标识唯一的一个实例。
+- **`description`**:对SQLDBWrapper的名称功能的描述。
+- **`db_uri`**:一个SQLAlchemy风的数据库uri，用于创建SQLAlchemy引擎。
+- **`sql_database_args`**:可选参数，`LangChain`中`SQLDatabase`类的配置参数，具体可参考[LangChain官网](https://python.langchain.com/v0.1/docs/integrations/toolkits/sql_database/)。
+- **`engine_args`**:可选参数，用于配置SQLAlchemy的引擎参数。具体可配置内容请参考[SQLAlchemy网页](https://docs.sqlalchemy.org/en/20/core/engines.html#sqlalchemy.create_engine)。
+- **`metadata`**:表示该配置是一个SQLDB_WRAPPER配置，无需改动。
+
+## 使用方式
+SQLDBWrapper类有以下几个函数供用户使用：
+
+### run
+`run`接收一个`str`类型的参数`command`，表示一个SQL语句，并通过SQLAlchemy执行该SQL并返回结果。结果形式为一个`list`，如果`command`为查询语句则`list`中会含有查询的结果，每一个元素都是一个字典，代表一行数据库中的数据，key为列名而value为对应的值。
+```python
+from agentuniverse.database.sqldb_wrapper import SQLDBWrapper
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
+
+demo_sqldb_wrapper:SQLDBWrapper = SQLDBWrapperManager().get_instance_obj("demo_sqldb_wrapper")
+demo_sqldb_wrapper.run("select * from USERS")
+```
+返回结果示例:
+```text
+[{'age': 30, 'id': 1, 'name': 'Alice'}, {'age': 25, 'id': 2, 'name': 'Bob'}]
+```
+
+### run_with_str_return
+`run`接收一个`str`类型的参数`command`，表示一个SQL语句，并通过SQLAlchemy执行该SQL并返回结果。结果形式为一个`str`，如果`command`为查询语句则`str`为所有查询结果数据的拼接，且如果在`sql_database_args`中配置了`max_string_length`参数的话，会对结果进行截断。这个函数更方便用于将结果作为llm的输入
+```python
+from agentuniverse.database.sqldb_wrapper import SQLDBWrapper
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
+
+demo_sqldb_wrapper:SQLDBWrapper = SQLDBWrapperManager().get_instance_obj("demo_sqldb_wrapper")
+demo_sqldb_wrapper.run_with_str_return("select * from USERS")
+```
+返回结果示例：
+```text
+"[(1, 'Alice', 30), (2, 'Bob', 25)]"
+```
+
+### sql_database
+如果您希望使用一些SQLAlchemy或者SQLDatabase原生的功能，您可以通过访问SQLDBWrapper的`sql_database`属性获取对应对象：
+```python
+from agentuniverse.database.sqldb_wrapper import SQLDBWrapper
+from agentuniverse.database.sqldb_wrapper_manager import SQLDBWrapperManager
+
+demo_sqldb_wrapper:SQLDBWrapper = SQLDBWrapperManager().get_instance_obj("demo_sqldb_wrapper")
+sql_database_ins = demo_sqldb_wrapper.sql_database
+sql_alchemy_engine = sql_database_ins._engine
+```
\ No newline at end of file
diff --git a/docs/guidebook/zh/2_4_1_Web_Server.md b/docs/guidebook/zh/2_4_1_Web_Server.md
index 67054a75..0a44cf41 100644
--- a/docs/guidebook/zh/2_4_1_Web_Server.md
+++ b/docs/guidebook/zh/2_4_1_Web_Server.md
@@ -1,6 +1,6 @@
 # Web Server
 
-AgentUniverse提供了一个基于Gunicorn+Flask的Web Server，您可以通过Web Server中预置的API调用开发完成的Agent服务。
+AgentUniverse提供了一个基于Flask的Web Server，您可以通过Web Server中预置的API调用开发完成的Agent服务。
 
 ## Web Server启动
 您需要在AgentUniverse应用启动后，启动Web Server。  
@@ -12,22 +12,30 @@ from agentuniverse.base.agentuniverse import AgentUniverse
 AgentUniverse().start()
 start_web_server()
 ```
-
-## Windows用户
-如果您正在windows上使用AgentUniverse，由于Gunicorn兼容性问题，AgentUniverse会直接运行Flask程序。您可以在`start_web_server`中修改启动端口，如：
+Flask服务的默认启动端口为8888，您可以通过bind参数修改启动端口:
 ```python
 from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
 
-start_web_server(bind='127.0.0.1:8888')
+AgentUniverse().start()
+start_web_server(bind="127.0.0.1:8002")
 ```
 
-## Web Server配置
-Web Server的配置按照优先度从低到高包含四个层次:`gunicorn`原生默认配置，AgentUniverse默认配置，配置文件配置和启动时配置。其中`gunicorn`的原生默认配置请参考对应版本的`gunicorn`官方文档。
+如果您需要配置更多细节或是追求生产的稳定性，您可以使用Gunicorn作为HTTP Server。
+
+## Gunicorn配置
+您可以通过在配置文件中进行如下配置将Gunicorn设置为您的HTTP Server:
+```toml
+[GUNICORN]
+activate = 'true'
+```
+
+Gunicorn的配置按照优先度从低到高包含四个层次:`gunicorn`原生默认配置，AgentUniverse默认配置，配置文件配置和启动时配置。其中`gunicorn`的原生默认配置请参考对应版本的`gunicorn`官方文档。
 
 ### AgentUniverse默认配置
 ```python
 DEFAULT_GUNICORN_CONFIG = {
-    'bind': '127.0.0.1:8000',
+    'bind': '127.0.0.1:8888',
     'workers': 5,
     'backlog': 2048,
     'worker_class': 'gthread',
@@ -41,7 +49,7 @@ AgentUniverse根据框架的工作特性预先进行了部分参数的配置，
 ### 配置文件路径
 Web Server的配置路径会在AgentUniverse的主配置config.toml中指定。
 ```toml
-[SUB_CONFIG_PATH]
+[GUNICORN]
 # Gunicorn config file path, an absolute path or a relative path based on the dir where the current config file is located.
 gunicorn_config_path = './gunicorn_config.toml'
 ```
@@ -50,7 +58,7 @@ gunicorn_config_path = './gunicorn_config.toml'
 ### 配置文件
 ```toml
 [GUNICORN_CONFIG]
-bind = '127.0.0.1:8000'
+bind = '127.0.0.1:8888'
 backlog = 2048
 worker_class = 'gthread'
 threads = 4
@@ -64,6 +72,22 @@ keepalive = 10
 您也可以通过以下方式在启动Web Server时进行配置：
 ```python
 from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
 
+AgentUniverse().start()
 start_web_server(bind="127.0.0.1:8002", threads=4)
-```
\ No newline at end of file
+```
+如果您有某些函数想在启动后执行，可以用类似以下方式添加:
+```python
+from agentuniverse.agent_serve.web.post_fork_queue import add_post_fork
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
+
+def print_hello(name: str):
+    print(f"hello {name}")
+
+add_post_fork(print_hello, "name")
+AgentUniverse().start()
+start_web_server(bind="127.0.0.1:8002")
+```
+您可以在启动后看到和worker数相等的"hello name"。
\ No newline at end of file
diff --git "a/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241\344\277\241\346\201\257\345\255\230\345\202\250.md" "b/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241\344\277\241\346\201\257\345\255\230\345\202\250.md"
index 6693718f..e217bac7 100644
--- "a/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241\344\277\241\346\201\257\345\255\230\345\202\250.md"
+++ "b/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241\344\277\241\346\201\257\345\255\230\345\202\250.md"
@@ -12,6 +12,7 @@ system_db_uri = ''
 ```
 需注意该uri应当符合`SQLAlchemy`中的uri格式规范。  
 当该值为空的时候，会在项目根目录创建一个DB文件夹，并在文件夹中创建一个名为`agent_universe.db`的sqlite DB文件作为默认系统数据库。
+如果您希望获取更多关于系统数据库的相关使用方式，您可以参考[SQLDB_WRAPPER](2_3_1_SQLDB_WRAPPER.md)章节，系统数据库的名字注册为`__system_db__`。
 
 ## 服务信息表格式
 agentUniverse中使用如下ORM存储请求信息：
diff --git a/docs/guidebook/zh/3_2_1_gRPC.md b/docs/guidebook/zh/3_2_1_gRPC.md
index 736091a7..f8759e56 100644
--- a/docs/guidebook/zh/3_2_1_gRPC.md
+++ b/docs/guidebook/zh/3_2_1_gRPC.md
@@ -13,6 +13,16 @@ server_port = 50051
 - **max_workers**: gRPC服务器线程池的最大线程数量，默认为10
 - **server_port**: gRPC服务器的服务端口，默认为50051
 
+然后启动grpc服务器：
+```python
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+from agentuniverse.base.agentuniverse import AgentUniverse
+
+AgentUniverse().start()
+start_web_server()
+```
+
+
 ### 调用gRPC服务
 
 ### 接口定义
diff --git a/docs/guidebook/zh/3_3_1_Milvus.md b/docs/guidebook/zh/3_3_1_Milvus.md
new file mode 100644
index 00000000..0f97daaa
--- /dev/null
+++ b/docs/guidebook/zh/3_3_1_Milvus.md
@@ -0,0 +1,41 @@
+## Milvus
+如果您想在aU中使用Milvus 向量数据库的话您需要：
+
+1. 安装Milvus向量数据库  
+您可以参考[Milvus官方安装文档](https://milvus.io/docs/install_standalone-docker.md)安装并使用Milvus。我们推荐在Docker中启动Milvus容器的方式：
+```shell
+# Download the installation script
+$ curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh
+
+# Start the Docker container
+$ bash standalone_embed.sh start
+```
+这两行命令会拉取Milvus的镜像并启动一个容器，在19530端口上提供数据库服务。
+更多详细内容及其它安装方式请参考官方文档。
+
+2. 安装milvus的python sdk
+```shell
+pip install pymilvus
+````
+
+### 我可以用Milvus做些什么
+
+您可以在[Knowledge组件]()中使用Milvus来存储和查询知识，你可以使用以下方式来创建一个使用Milvus的存储组件:
+```python
+from agentuniverse.agent.action.knowledge.store.milvus_store import MilvusStore
+from agentuniverse.agent.action.knowledge.embedding.openai_embedding import OpenAIEmbedding
+from agentuniverse.agent.action.knowledge.knowledge import Knowledge
+
+init_params = {}
+init_params['name'] = 'test_knowledge'
+init_params['description'] = 'test_knowledge_description'
+init_params['store'] = MilvusStore(
+    connection_args={"host": "localhost", "port": "19530"},
+    collection_name="test_knowledge", 
+    embedding_model=OpenAIEmbedding(
+            embedding_model_name='text-embedding-ada-002'
+    )
+)
+knowledge = Knowledge(**init_params)
+```
+上面的代码会创建一个基于Milvus的Knowledge，关于Knowledge的具体用法您可以参考[Knowledge文档]()，或是参考代码`tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge_with_milvus.py`。
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index b94bda12..d725b8f9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "agentUniverse"
-version = "0.0.7"
+version = "0.0.8"
 description = "agentUniverse is a framework for developing applications powered by multi-agent base on large language model."
 
 authors = ["AntGroup <jerry.zzw@antgroup.com>"]
@@ -21,24 +21,28 @@ classifiers = [
 
 [tool.poetry.dependencies]
 python = "^3.10"
-requests = "^2.31.0"
+requests = "^2.32.0"
 cffi = "^1.15.1"
-flask = "2.2"
-werkzeug = "2.2.2"
-langchain = "0.0.352"
-langchain-core = "0.1.3"
+flask = "^2.3.2"
+werkzeug = "^3.0.3"
+langchain = "0.1.20"
+langchain-core = "0.1.52"
+langchain-community = "0.0.38"
 openai = '1.13.3'
 tiktoken = '0.5.2'
 loguru = '0.7.2'
 flask_cors = '4.0.0'
 SQLAlchemy = '2.0.25'
 pydantic = "^2.6.4"
-gunicorn = "21.2.0"
+gunicorn = "^22.0.0"
 grpcio = "1.63.0"
 chromadb = "0.4.24"
 sphinx = "^7.2.6"
+Jinja2 = "^3.1.4"
+tqdm = "^4.66.3"
 sphinx-rtd-theme = "^2.0.0"
 aliyun-log-python-sdk = { version = "0.8.8", optional = true}
+pymilvus = { version = "^2.4.3", optional = true}
 googleapis-common-protos = "^1.63.0"
 myst-parser = "^2.0.0"
 qianfan = "^0.3.12"
@@ -47,6 +51,7 @@ anthropic = "^0.26.0"
 
 [tool.poetry.extras]
 log_ext = ["aliyun-log-python-sdk"]
+store_ext = ["pymilvus"]
 
 [tool.poetry.group.dev.dependencies]
 pytest = "^7.2.0"
diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml
index b3f5f39a..278b6fff 100644
--- a/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml
+++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml
@@ -10,6 +10,8 @@ profile:
 plan:
   planner:
     name: 'planning_planner'
+memory:
+  name: ''
 metadata:
   type: 'AGENT'
   module: 'agentuniverse.agent.default.planning_agent.planning_agent'
diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml
index 56f50ef6..38f45076 100644
--- a/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml
+++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml
@@ -9,6 +9,8 @@ profile:
 plan:
   planner:
     name: 'reviewing_planner'
+memory:
+  name: ''
 metadata:
   type: 'AGENT'
   module: 'agentuniverse.agent.default.reviewing_agent.reviewing_agent'
diff --git a/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml b/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml
index 07a9649d..2fd13785 100644
--- a/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml
+++ b/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml
@@ -9,14 +9,14 @@ profile:
 
     The question that needs to be answered is: {input}
   llm_model:
-    name: 'kimi_llm'
-    model_name: 'moonshot-v1-8k'
+#    name: 'kimi_llm'
+#    model_name: 'moonshot-v1-8k'
 #    name: 'baichuan_llm'
 #    model_name: 'Baichuan2-Turbo'
 #    name: 'qwen_llm'
 #    model_name: 'qwen-turbo'
-#    name: 'wenxin_llm'
-#    model_name: 'ERNIE-3.5-8K'
+    name: 'wenxin_llm'
+    model_name: 'ERNIE-3.5-8K'
 plan:
   planner:
     name: 'rag_planner'
diff --git a/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml b/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml
index 6841d584..8457d2df 100644
--- a/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml
+++ b/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml
@@ -16,7 +16,10 @@ profile:
 
     背景信息是:
     {background}
-
+  
+    之前的对话:
+    {chat_history}
+    
     开始!
 
     需要回答的问题是: {input}
@@ -29,6 +32,8 @@ plan:
 action:
   tool:
     - 'google_search_tool'
+memory:
+  name: ''
 metadata:
   type: 'AGENT'
   module: 'sample_standard_app.app.core.agent.rag_agent_case.demo_rag_agent'
diff --git a/sample_standard_app/app/core/prompt/expressing_agent_cn.yaml b/sample_standard_app/app/core/prompt/expressing_agent_cn.yaml
index de0e0724..e99547f6 100644
--- a/sample_standard_app/app/core/prompt/expressing_agent_cn.yaml
+++ b/sample_standard_app/app/core/prompt/expressing_agent_cn.yaml
@@ -10,6 +10,9 @@ instruction: |
   - 不做对问题没有帮助的回答、不可以出现XXX、ABC等不明确的词语。
   - 整体回答结果没有重复信息，必要时可以通过空行提升阅读体验。
   
+  之前的对话:
+  {chat_history}
+  
   背景信息是:
   {background}
   
diff --git a/sample_standard_app/app/core/prompt/planning_agent_cn.yaml b/sample_standard_app/app/core/prompt/planning_agent_cn.yaml
index 38179542..9368b518 100644
--- a/sample_standard_app/app/core/prompt/planning_agent_cn.yaml
+++ b/sample_standard_app/app/core/prompt/planning_agent_cn.yaml
@@ -14,7 +14,10 @@ instruction: |
   
   开始!
   今天的日期是: {date}
-
+  
+  之前的对话:
+  {chat_history}
+  
   输出必须是按照以下格式化的Json代码片段，不加额外的json标识，thought字段代表拆解问题的思考过程，framework字段代表拆解后的子问题列表。
   {{
       "thought": string,
diff --git a/sample_standard_app/app/core/sqldb_wrapper/__init__.py b/sample_standard_app/app/core/sqldb_wrapper/__init__.py
new file mode 100644
index 00000000..fcb52da2
--- /dev/null
+++ b/sample_standard_app/app/core/sqldb_wrapper/__init__.py
@@ -0,0 +1,7 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/24 00:27
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: __init__.py.py
diff --git a/sample_standard_app/app/core/sqldb_wrapper/demo_sqldb_wrapper.yaml b/sample_standard_app/app/core/sqldb_wrapper/demo_sqldb_wrapper.yaml
new file mode 100644
index 00000000..02cc3cfb
--- /dev/null
+++ b/sample_standard_app/app/core/sqldb_wrapper/demo_sqldb_wrapper.yaml
@@ -0,0 +1,7 @@
+name: 'demo_sqldb_wrapper'
+description: 'demo_sqldb_wrapper'
+db_uri: "sqlite:///./demo_sqldb_wrapper.db"
+engine_args:
+  pool_size: 5
+metadata:
+  type: 'SQLDB_WRAPPER'
\ No newline at end of file
diff --git a/sample_standard_app/config/config.toml b/sample_standard_app/config/config.toml
index a412d988..4a662064 100644
--- a/sample_standard_app/config/config.toml
+++ b/sample_standard_app/config/config.toml
@@ -21,12 +21,12 @@ memory = ['sample_standard_app.app.core.memory']
 service = ['sample_standard_app.app.core.service']
 # Scan and register prompt components for all paths under this list, with priority over the default.
 prompt = ['sample_standard_app.app.core.prompt']
+# Scan and register prompt components for all paths under this list, with priority over the default.
+sqldb_wrapper = ['sample_standard_app.app.core.sqldb_wrapper']
 
 [SUB_CONFIG_PATH]
 # Log config file path, an absolute path or a relative path based on the dir where the current config file is located.
 log_config_path = './log_config.toml'
-# Gunicorn config file path, an absolute path or a relative path based on the dir where the current config file is located.
-gunicorn_config_path = './gunicorn_config.toml'
 # Custom key file path, use to save your own secret key like open ai or sth else. REMEMBER TO ADD IT TO .gitignore.
 #custom_key_path = './custom_key.toml'
 
@@ -35,7 +35,17 @@ gunicorn_config_path = './gunicorn_config.toml'
 # If it's empty, agentUniverse will create a local sqlite db as default choice.
 system_db_uri = ''
 
+[GUNICORN]
+# Use gunicorn as http server when activate is 'true', or only use flask.
+activate = 'false'
+# Gunicorn config file path, an absolute path or a relative path based on the dir where the current config file is located.
+gunicorn_config_path = './gunicorn_config.toml'
+
 [GRPC]
-activate = 'true'
+activate = 'false'
 max_workers = 10
-server_port = 50051
\ No newline at end of file
+server_port = 50051
+
+[MONITOR]
+activate = false
+dir = './monitor'
diff --git a/sample_standard_app/config/gunicorn_config.toml b/sample_standard_app/config/gunicorn_config.toml
index 8865a33a..2dd3b915 100644
--- a/sample_standard_app/config/gunicorn_config.toml
+++ b/sample_standard_app/config/gunicorn_config.toml
@@ -1,5 +1,5 @@
 [GUNICORN_CONFIG]
-bind = '127.0.0.1:8000'
+bind = '127.0.0.1:8888'
 backlog = 2048
 worker_class = 'gthread'
 threads = 4


Test patch:
diff --git a/sample_standard_app/app/test/test_sqldb_wrapper.py b/sample_standard_app/app/test/test_sqldb_wrapper.py
new file mode 100644
index 00000000..74a75946
--- /dev/null
+++ b/sample_standard_app/app/test/test_sqldb_wrapper.py
@@ -0,0 +1,43 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/24 01:23
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: test_sqldb_wrapper.py
+import unittest
+
+from agentuniverse.base.agentuniverse import AgentUniverse
+from agentuniverse.database.sqldb_wrapper_manager import \
+            SQLDBWrapperManager
+
+class SQLDBWrapperTest(unittest.TestCase):
+    """
+    Test cases for the SQLDBWrapper
+    """
+
+    def setUp(self) -> None:
+        AgentUniverse().start(config_path='../../config/config.toml')
+
+
+    def test_sqldb_wrapper(self):
+        manager: SQLDBWrapperManager = SQLDBWrapperManager()
+        demo_sqldb_wrapper = manager.get_instance_obj("demo_sqldb_wrapper")
+        insert_statement = """
+                INSERT INTO users (name, age)
+                VALUES
+                    ('Alice', 30),
+                    ('Bob', 25);
+                """
+        demo_sqldb_wrapper.run("DROP TABLE IF EXISTS users")
+        demo_sqldb_wrapper.run(
+            "CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER)"
+        )
+        demo_sqldb_wrapper.run(insert_statement)
+        result = demo_sqldb_wrapper.run("select * from users")
+        demo_sqldb_wrapper.run("select * from users")
+        assert len(result) == 2
+
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge_with_milvus.py b/tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge_with_milvus.py
new file mode 100644
index 00000000..13c65708
--- /dev/null
+++ b/tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge_with_milvus.py
@@ -0,0 +1,53 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/3/20 10:10
+# @Author  : fanen
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: test_knowledge_with_milvus.py
+import unittest
+
+from agentuniverse.agent.action.knowledge.embedding.openai_embedding import OpenAIEmbedding
+from agentuniverse.agent.action.knowledge.knowledge import Knowledge
+from agentuniverse.agent.action.knowledge.store.milvus_store import MilvusStore
+from agentuniverse.agent.action.knowledge.store.query import Query
+from agentuniverse.agent.action.knowledge.store.document import Document
+
+
+class KnowledgeTest(unittest.TestCase):
+    """
+    Test cases for Knowledge class
+    """
+
+    def setUp(self) -> None:
+        init_params = {}
+        init_params['name'] = 'test_knowledge'
+        init_params['description'] = 'test_knowledge_description'
+        init_params['store'] = MilvusStore(collection_name="test_knowledge", embedding_model=OpenAIEmbedding(
+            embedding_model_name='text-embedding-ada-002'))
+        self.knowledge = Knowledge(**init_params)
+
+    def test_store_update_documents(self) -> None:
+        store = self.knowledge.store
+        store.update_document([Document(text='This is an iPhone', metadata={'type': 'Electronic products'}),
+                               Document(text='This is a Tesla.', metadata={'type': 'Industrial products'})])
+
+    def test_store_upsert_documents(self) -> None:
+        store = self.knowledge.store
+        store.upsert_document([Document(text='This is an iPhone', metadata={'type': 'Cell phone'}),
+                               Document(text='This is a Tesla.', metadata={'type': 'Car'})])
+
+    def test_store_insert_documents(self) -> None:
+        store = self.knowledge.store
+        store.insert_documents([Document(text='This is a document about engineer'),
+                                Document(text='This is a document about finance')])
+
+    def test_query(self) -> None:
+        store = self.knowledge.store
+        query = Query(query_str='Which one is a cell phone?', similarity_top_k=1)
+        res = store.query(query)
+        print(res)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_agentuniverse/unit/agent/memory/test_memory.py b/tests/test_agentuniverse/unit/agent/memory/test_memory.py
index 0081a274..17e67450 100644
--- a/tests/test_agentuniverse/unit/agent/memory/test_memory.py
+++ b/tests/test_agentuniverse/unit/agent/memory/test_memory.py
@@ -13,7 +13,7 @@
 from agentuniverse.agent.memory.chat_memory import ChatMemory
 from agentuniverse.agent.memory.enum import MemoryTypeEnum
 from agentuniverse.agent.memory.message import Message
-from agentuniverse.llm.openai_llm import OpenAILLM
+from agentuniverse.llm.default.default_openai_llm import DefaultOpenAILLM
 
 template = """
 You are a chatbot having a conversation with a human.
@@ -33,12 +33,12 @@ class MemoryTest(unittest.TestCase):
 
     def setUp(self) -> None:
         init_params = dict()
-        init_params['model_name'] = 'gpt-3.5-turbo'
+        init_params['model_name'] = 'gpt-4o'
         init_params['temperature'] = 0.7
         init_params['max_retries'] = 2
         init_params['streaming'] = False
 
-        init_params['llm'] = OpenAILLM(**init_params)
+        init_params['llm'] = DefaultOpenAILLM(**init_params)
         init_params['memory_key'] = 'chat_history'
         init_params['max_tokens'] = '1024'
         init_params['type'] = MemoryTypeEnum.LONG_TERM
diff --git a/tests/test_agentuniverse/unit/llm/test_llm.py b/tests/test_agentuniverse/unit/llm/test_llm.py
index 4d2fa99e..23c9aeb9 100644
--- a/tests/test_agentuniverse/unit/llm/test_llm.py
+++ b/tests/test_agentuniverse/unit/llm/test_llm.py
@@ -9,7 +9,7 @@
 
 from langchain.chains import ConversationChain
 
-from agentuniverse.llm.openai_llm import OpenAILLM
+from agentuniverse.llm.default.default_openai_llm import DefaultOpenAILLM
 
 
 class LLMTest(unittest.TestCase):
@@ -18,7 +18,7 @@ class LLMTest(unittest.TestCase):
     """
 
     def setUp(self) -> None:
-        self.llm = OpenAILLM(model_name='gpt-4o')
+        self.llm = DefaultOpenAILLM(model_name='gpt-4o')
 
     def test_call(self) -> None:
         messages = [