Repository: antgroup/agentUniverse (language: python)

Issue:
feat: add gpt-4o llm model in agentUniverse.
feat: add gpt-4o llm model in agentUniverse.


Discussion / hints:

Fix patch:
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 74232943..00000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,13 +0,0 @@
-include CHANGELOG.md
-include CHANGELOG_zh.md
-include LICENSE
-include README.md
-include README_zh.md
-include requirements.txt
-include MANIFEST.in
-recursive-exclude docs *
-recursive-exclude sample_standard_app *
-recursive-exclude tests *
-global-exclude __pycache__
-global-exclude *.log
-global-exclude *.pyc
\ No newline at end of file
diff --git a/agentuniverse/agent_serve/web/flask_server.py b/agentuniverse/agent_serve/web/flask_server.py
index 9f3cdeba..61547598 100644
--- a/agentuniverse/agent_serve/web/flask_server.py
+++ b/agentuniverse/agent_serve/web/flask_server.py
@@ -30,17 +30,16 @@ def service_run(service_id: str, params: dict, saved: bool = False):
     """Synchronous invocation of an agent service.
 
     Request Args:
-        service_id(`str`): The id of the agent service. Format like
-            {appname}.service.{service_name}.
+        service_id(`str`): The id of the agent service.
         params(`dict`): Json style params passed to service.
         saved(`bool`): Save the request and result into database.
 
     Return:
         Returns a dict containing two keys: success and result.
         success: This key holds a boolean value indicating the task was
-        successfully or not.
+            successfully or not.
         result: This key points to a nested dictionary that includes the
-        result of the task.
+            result of the task.
     """
     params = {} if params is None else params
     request_task = RequestTask(ServiceInstance(service_id).run, saved, **params)
@@ -55,8 +54,7 @@ def service_run_stream(service_id: str, params: dict, saved: bool = False):
     """Synchronous invocation of an agent service, return in stream form.
 
     Request Args:
-        service_id(`str`): The id of the agent service. Format like
-            {appname}.service.{service_name}.
+        service_id(`str`): The id of the agent service.
         params(`dict`): Json style params passed to service.
         saved(`bool`): Save the request and result into database.
 
@@ -78,22 +76,16 @@ def service_run_async(service_id: str, params: dict, saved: bool = True):
     get result later.
 
     Request Args:
-        service_id(`str`): The id of the agent service. Format like
-            {appname}.service.{service_name}.
+        service_id(`str`): The id of the agent service.
         params(`dict`): Json style params passed to service.
         saved(`bool`): Save the request and result into database.
 
     Return:
         Returns a dict containing two keys: success and result.
         success: This key holds a boolean value indicating the task was
-        successfully or not.
-        result: This key points to a dictionary contains a key: request_id,
-        its value can be used in service_run_result api to get the result
-        of async task.
-
-    Example Response:
-        {"success": True, "data": {
-        "request_id":"05d0a28785cc455894ebb88bba14a67e"}}.
+            successfully or not.
+        request_id: Stand for a single request taski, can be used in
+            service_run_result api to get the result of async task.
     """
     params = {} if params is None else params
     params['service_id'] = service_id
@@ -115,9 +107,9 @@ def service_run_result(request_id: str):
         Returns a dict containing two keys: success and result if request_id
         exists in database.
         success: This key holds a boolean value indicating the task was
-        successfully or not.
+            successfully or not.
         result: This key points to a nested dictionary that includes the
-        result of the task.
+            result of the task.
     """
     data = RequestTask.query_request_state(request_id)
     if data is None:
diff --git a/agentuniverse/agent_serve/web/rpc/grpc/__init__.py b/agentuniverse/agent_serve/web/rpc/grpc/__init__.py
new file mode 100644
index 00000000..7a6ce924
--- /dev/null
+++ b/agentuniverse/agent_serve/web/rpc/grpc/__init__.py
@@ -0,0 +1,7 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/14 09:49
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: __init__.py.py
diff --git a/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service.proto b/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service.proto
new file mode 100644
index 00000000..b9ba404d
--- /dev/null
+++ b/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service.proto
@@ -0,0 +1,28 @@
+syntax = "proto3";
+
+package agentuniverse;
+
+// RPC 服务定义
+service AgentUniverseService {
+  // 方法定义
+  rpc service_run(AgentServiceRequest) returns (AgentServiceResponse);
+  rpc service_run_async(AgentServiceRequest) returns (AgentServiceResponse);
+  rpc service_run_result(AgentResultRequest) returns (AgentServiceResponse);
+}
+
+message AgentServiceRequest {
+  string service_id = 1;
+  string params = 2;
+  bool saved = 3;
+}
+
+message AgentServiceResponse {
+  string message = 1;
+  bool success = 2;
+  string request_id = 3;
+  string result = 4;
+}
+
+message AgentResultRequest {
+    string request_id = 1;
+}
\ No newline at end of file
diff --git a/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service_pb2.py b/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service_pb2.py
new file mode 100644
index 00000000..c28eb157
--- /dev/null
+++ b/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service_pb2.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: agentuniverse_service.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x61gentuniverse_service.proto\x12\ragentuniverse\"H\n\x13\x41gentServiceRequest\x12\x12\n\nservice_id\x18\x01 \x01(\t\x12\x0e\n\x06params\x18\x02 \x01(\t\x12\r\n\x05saved\x18\x03 \x01(\x08\"\\\n\x14\x41gentServiceResponse\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\nrequest_id\x18\x03 \x01(\t\x12\x0e\n\x06result\x18\x04 \x01(\t\"(\n\x12\x41gentResultRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t2\xaa\x02\n\x14\x41gentUniverseService\x12V\n\x0bservice_run\x12\".agentuniverse.AgentServiceRequest\x1a#.agentuniverse.AgentServiceResponse\x12\\\n\x11service_run_async\x12\".agentuniverse.AgentServiceRequest\x1a#.agentuniverse.AgentServiceResponse\x12\\\n\x12service_run_result\x12!.agentuniverse.AgentResultRequest\x1a#.agentuniverse.AgentServiceResponseb\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agentuniverse_service_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+  DESCRIPTOR._options = None
+  _globals['_AGENTSERVICEREQUEST']._serialized_start=46
+  _globals['_AGENTSERVICEREQUEST']._serialized_end=118
+  _globals['_AGENTSERVICERESPONSE']._serialized_start=120
+  _globals['_AGENTSERVICERESPONSE']._serialized_end=212
+  _globals['_AGENTRESULTREQUEST']._serialized_start=214
+  _globals['_AGENTRESULTREQUEST']._serialized_end=254
+  _globals['_AGENTUNIVERSESERVICE']._serialized_start=257
+  _globals['_AGENTUNIVERSESERVICE']._serialized_end=555
+# @@protoc_insertion_point(module_scope)
diff --git a/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service_pb2_grpc.py b/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service_pb2_grpc.py
new file mode 100644
index 00000000..c8ea92f2
--- /dev/null
+++ b/agentuniverse/agent_serve/web/rpc/grpc/agentuniverse_service_pb2_grpc.py
@@ -0,0 +1,137 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from agentuniverse.agent_serve.web.rpc.grpc import \
+    agentuniverse_service_pb2 as agentuniverse__service__pb2
+
+
+class AgentUniverseServiceStub(object):
+    """RPC 服务定义
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.service_run = channel.unary_unary(
+                '/agentuniverse.AgentUniverseService/service_run',
+                request_serializer=agentuniverse__service__pb2.AgentServiceRequest.SerializeToString,
+                response_deserializer=agentuniverse__service__pb2.AgentServiceResponse.FromString,
+                )
+        self.service_run_async = channel.unary_unary(
+                '/agentuniverse.AgentUniverseService/service_run_async',
+                request_serializer=agentuniverse__service__pb2.AgentServiceRequest.SerializeToString,
+                response_deserializer=agentuniverse__service__pb2.AgentServiceResponse.FromString,
+                )
+        self.service_run_result = channel.unary_unary(
+                '/agentuniverse.AgentUniverseService/service_run_result',
+                request_serializer=agentuniverse__service__pb2.AgentResultRequest.SerializeToString,
+                response_deserializer=agentuniverse__service__pb2.AgentServiceResponse.FromString,
+                )
+
+
+class AgentUniverseServiceServicer(object):
+    """RPC 服务定义
+    """
+
+    def service_run(self, request, context):
+        """方法定义
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def service_run_async(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def service_run_result(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_AgentUniverseServiceServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'service_run': grpc.unary_unary_rpc_method_handler(
+                    servicer.service_run,
+                    request_deserializer=agentuniverse__service__pb2.AgentServiceRequest.FromString,
+                    response_serializer=agentuniverse__service__pb2.AgentServiceResponse.SerializeToString,
+            ),
+            'service_run_async': grpc.unary_unary_rpc_method_handler(
+                    servicer.service_run_async,
+                    request_deserializer=agentuniverse__service__pb2.AgentServiceRequest.FromString,
+                    response_serializer=agentuniverse__service__pb2.AgentServiceResponse.SerializeToString,
+            ),
+            'service_run_result': grpc.unary_unary_rpc_method_handler(
+                    servicer.service_run_result,
+                    request_deserializer=agentuniverse__service__pb2.AgentResultRequest.FromString,
+                    response_serializer=agentuniverse__service__pb2.AgentServiceResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'agentuniverse.AgentUniverseService', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class AgentUniverseService(object):
+    """RPC 服务定义
+    """
+
+    @staticmethod
+    def service_run(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/agentuniverse.AgentUniverseService/service_run',
+            agentuniverse__service__pb2.AgentServiceRequest.SerializeToString,
+            agentuniverse__service__pb2.AgentServiceResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def service_run_async(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/agentuniverse.AgentUniverseService/service_run_async',
+            agentuniverse__service__pb2.AgentServiceRequest.SerializeToString,
+            agentuniverse__service__pb2.AgentServiceResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def service_run_result(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/agentuniverse.AgentUniverseService/service_run_result',
+            agentuniverse__service__pb2.AgentResultRequest.SerializeToString,
+            agentuniverse__service__pb2.AgentServiceResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/agentuniverse/agent_serve/web/rpc/grpc/grpc_server_booster.py b/agentuniverse/agent_serve/web/rpc/grpc/grpc_server_booster.py
new file mode 100644
index 00000000..b2c9467a
--- /dev/null
+++ b/agentuniverse/agent_serve/web/rpc/grpc/grpc_server_booster.py
@@ -0,0 +1,125 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/10 11:28
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: grpc_server_booster.py
+
+from concurrent import futures
+import grpc
+
+from agentuniverse.agent_serve.web.rpc.grpc import agentuniverse_service_pb2, \
+    agentuniverse_service_pb2_grpc
+from agentuniverse.agent_serve.web.rpc.rpc_server import service_run, service_run_async, service_run_result
+
+
+class AgentUniverseService(agentuniverse_service_pb2_grpc.AgentUniverseService):
+    """Implementation class of grpc service."""
+    def service_run(self, request, context):
+        """
+        Synchronous invocation of an agent service. Used in rpc implementation.
+
+        Request Args:
+            request(`agentuniverse_service_pb2.AgentServiceRequest`):
+                service_id(`str`): The id of the agent service.
+                params(`str`): A Json String contains agent params passed to service.
+                saved(`bool`): Save the request and result into database.
+            context: grpc context, needn't pass anything.
+
+        Return:
+            Returns agentuniverse_service_pb2.AgentServiceResponse:
+            success: This key holds a boolean value indicating the task was
+                successfully or not.
+            result: This key points to a nested dictionary that includes the
+                result of the task.
+        """
+        service_result = service_run(
+            saved=request.saved,
+            params=request.params,
+            service_id=request.service_id
+        )
+
+        return agentuniverse_service_pb2.AgentServiceResponse(
+            result=service_result['result'],
+            request_id=service_result['request_id'],
+            success=service_result['success'],
+            message=service_result['message']
+        )
+
+    def service_run_async(self, request, context):
+        """
+        Async invocation of an agent service, return the request id used to
+        get result later. Used in rpc implementation.
+
+        Request Args:
+            request(`agentuniverse_service_pb2.AgentServiceRequest`):
+                service_id(`str`): The id of the agent service.
+                params(`str`): A Json String contains agent params passed to service.
+                saved(`bool`): Save the request and result into database.
+            context: grpc context, needn't pass anything.
+
+        Return:
+            Returns agentuniverse_service_pb2.AgentServiceResponse:
+            success: This key holds a boolean value indicating the task was
+                successfully or not.
+            request_id: Stand for a single request taski, can be used in
+                service_run_result api to get the result of async task.
+        """
+        service_result = service_run_async(
+            saved=request.saved,
+            params=request.params,
+            service_id=request.service_id
+        )
+        return agentuniverse_service_pb2.AgentServiceResponse(
+            result=service_result['result'],
+            request_id=service_result['request_id'],
+            success=service_result['success'],
+            message=service_result['message']
+        )
+
+    def service_run_result(self, request, context):
+        """
+        Get the async service result.
+
+        Request Args:
+            request(`agentuniverse_service_pb2.AgentResultRequest`):
+                request_id(`str`): Request id returned by async run api.
+            context: grpc context, needn't pass anything.
+
+        Return:
+            Returns agentuniverse_service_pb2.AgentServiceResponse if
+            request_id exists in database.
+            success: This key holds a boolean value indicating the task was
+                successfully or not.
+            result: This key points to a nested dictionary that includes the
+                result of the task.
+        """
+        service_result = service_run_result(
+            request_id=request.request_id
+        )
+        return agentuniverse_service_pb2.AgentServiceResponse(
+            result=service_result['result'],
+            request_id=service_result['request_id'],
+            success=service_result['success'],
+            message=service_result['message']
+        )
+
+
+def start_grpc_server(configer=None):
+    """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 = grpc.server(futures.ThreadPoolExecutor(max_workers=max_workers))
+    agentuniverse_service_pb2_grpc.add_AgentUniverseServiceServicer_to_server(
+        AgentUniverseService(), server
+    )
+    server.add_insecure_port(f'[::]:{str(server_port)}')
+    server.start()
+    print(f"AgentUniverse grpc server start at port {str(server_port)}.")
+    server.wait_for_termination()
diff --git a/agentuniverse/agent_serve/web/rpc/rpc_server.py b/agentuniverse/agent_serve/web/rpc/rpc_server.py
index 81e67e4d..1b294769 100644
--- a/agentuniverse/agent_serve/web/rpc/rpc_server.py
+++ b/agentuniverse/agent_serve/web/rpc/rpc_server.py
@@ -12,10 +12,22 @@
 from ..request_task import RequestTask
 from ..web_util import service_run_queue
 
-# TODO: RPC Agent Service API.
-
 
 def service_run(saved: bool, params: str, service_id: str):
+    """Synchronous invocation of an agent service. Used in rpc implementation.
+
+    Request Args:
+        service_id(`str`): The id of the agent service.
+        params(`str`): A Json String contains agent params passed to service.
+        saved(`bool`): Save the request and result into database.
+
+    Return:
+        Returns a dict containing two keys: success and result.
+        success: This key holds a boolean value indicating the task was
+            successfully or not.
+        result: This key points to a nested dictionary that includes the
+            result of the task.
+    """
     if params and params.strip():
         params = json.loads(params)
     else:
@@ -32,6 +44,21 @@ def service_run(saved: bool, params: str, service_id: str):
 
 
 def service_run_async(saved: bool, params: str, service_id: str):
+    """Async invocation of an agent service, return the request id used to
+    get result later. Used in rpc implementation.
+
+    Request Args:
+        service_id(`str`): The id of the agent service.
+        params(`str`): A Json String contains agent params passed to service.
+        saved(`bool`): Save the request and result into database.
+
+    Return:
+        Returns a dict containing two keys: success and request_id.
+        success: This key holds a boolean value indicating the task was
+            successfully or not.
+        request_id: Stand for a single request taski, can be used in
+            service_run_result api to get the result of async task.
+    """
     if params and params.strip():
         params = json.loads(params)
     else:
@@ -45,3 +72,31 @@ def service_run_async(saved: bool, params: str, service_id: str):
         "message": None,
         "request_id": task.request_id
     }
+
+
+def service_run_result(request_id: str):
+    """Get the async service result.
+
+    Request Args:
+        request_id(`str`): Request id returned by async run api.
+
+    Return:
+        Returns a dict containing two keys: success and result if request_id
+        exists in database.
+        success: This key holds a boolean value indicating the task was
+            successfully or not.
+        result: This key points to a nested dictionary that includes the
+            result of the task.
+    """
+    data = RequestTask.query_request_state(request_id)
+    if data is None:
+        return {
+            "success": False,
+            "message": f"request {request_id} not found"
+        }
+    return {
+        "success": True,
+        "result": json.dumps(data, ensure_ascii=False),
+        "message": None,
+        "request_id": request_id
+    }
\ No newline at end of file
diff --git a/agentuniverse/base/agentuniverse.py b/agentuniverse/base/agentuniverse.py
index 99177916..d8598942 100644
--- a/agentuniverse/base/agentuniverse.py
+++ b/agentuniverse/base/agentuniverse.py
@@ -7,6 +7,7 @@
 # @FileName: agentuniverse.py
 import importlib
 import sys
+import threading
 from pathlib import Path
 
 from agentuniverse.base.annotation.singleton import singleton
@@ -23,6 +24,7 @@
 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
 
 
 @singleton
@@ -71,6 +73,15 @@ def start(self, config_path: str = None):
         # init web request task database
         RequestLibrary(configer=configer)
 
+        # init grpc server
+        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()
+
         # init gunicorn web server on mac or unix platform
         if not sys.platform.lower().startswith("win"):
             gunicorn_config_path = self.__parse_sub_config_path(
diff --git a/agentuniverse/llm/llm.py b/agentuniverse/llm/llm.py
index 0b6d2687..f56ebb87 100644
--- a/agentuniverse/llm/llm.py
+++ b/agentuniverse/llm/llm.py
@@ -40,7 +40,7 @@ class LLM(ComponentBase):
     model_name: Optional[str] = None
     temperature: Optional[float] = 0.5
     request_timeout: Optional[int] = None
-    max_tokens: Optional[int] = None
+    max_tokens: Optional[int] = 1024
     max_retries: Optional[int] = 2
     streaming: Optional[bool] = False
     ext_info: Optional[dict] = None
diff --git a/agentuniverse/llm/openai_llm.py b/agentuniverse/llm/openai_llm.py
index 139ae49d..69896993 100644
--- a/agentuniverse/llm/openai_llm.py
+++ b/agentuniverse/llm/openai_llm.py
@@ -34,6 +34,8 @@
     "gpt-4-0613": 8192,
     "gpt-4-1106-preview": 128000,
     "gpt-4-turbo": 128000,
+    "gpt-4o": 128000,
+    "gpt-4o-2024-05-13": 128000,
 }
 
 
@@ -92,18 +94,19 @@ def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOu
         """
         streaming = kwargs.pop("streaming") if "streaming" in kwargs else self.streaming
         self.client = self._new_client()
-        chat_completion = self.client.chat.completions.create(
-            messages=messages,
-            model=kwargs.pop('model', self.model_name),
-            temperature=kwargs.pop('temperature', self.temperature),
-            stream=kwargs.pop('stream', streaming),
-            max_tokens=kwargs.pop('max_tokens', self.max_tokens),
-            **kwargs,
-        )
-        if not streaming:
-            text = chat_completion.choices[0].message.content
-            return LLMOutput(text=text, raw=chat_completion.model_dump())
-        return self.generate_stream_result(chat_completion)
+        with self.client as client:
+            chat_completion = client.chat.completions.create(
+                messages=messages,
+                model=kwargs.pop('model', self.model_name),
+                temperature=kwargs.pop('temperature', self.temperature),
+                stream=kwargs.pop('stream', streaming),
+                max_tokens=kwargs.pop('max_tokens', self.max_tokens),
+                **kwargs,
+            )
+            if not streaming:
+                text = chat_completion.choices[0].message.content
+                return LLMOutput(text=text, raw=chat_completion.model_dump())
+            return self.generate_stream_result(chat_completion)
 
     async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
         """Asynchronously run the OpenAI LLM.
@@ -114,18 +117,19 @@ async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIt
         """
         streaming = kwargs.pop("streaming") if "streaming" in kwargs else self.streaming
         self.async_client = self._new_async_client()
-        chat_completion = await self.async_client.chat.completions.create(
-            messages=messages,
-            model=kwargs.pop('model', self.model_name),
-            temperature=kwargs.pop('temperature', self.temperature),
-            stream=kwargs.pop('stream', streaming),
-            max_tokens=kwargs.pop('max_tokens', self.max_tokens),
-            **kwargs,
-        )
-        if not streaming:
-            text = chat_completion.choices[0].message.content
-            return LLMOutput(text=text, raw=chat_completion.model_dump())
-        return self.agenerate_stream_result(chat_completion)
+        async with self.async_client as async_client:
+            chat_completion = await async_client.chat.completions.create(
+                messages=messages,
+                model=kwargs.pop('model', self.model_name),
+                temperature=kwargs.pop('temperature', self.temperature),
+                stream=kwargs.pop('stream', streaming),
+                max_tokens=kwargs.pop('max_tokens', self.max_tokens),
+                **kwargs,
+            )
+            if not streaming:
+                text = chat_completion.choices[0].message.content
+                return LLMOutput(text=text, raw=chat_completion.model_dump())
+            return self.agenerate_stream_result(chat_completion)
 
     def as_langchain(self) -> BaseLanguageModel:
         """Convert the AgentUniverse(AU) openai llm class to the langchain openai llm class."""
diff --git a/agentuniverse/prompt/prompt_model.py b/agentuniverse/prompt/prompt_model.py
index 491558ff..5ae1ac20 100644
--- a/agentuniverse/prompt/prompt_model.py
+++ b/agentuniverse/prompt/prompt_model.py
@@ -33,4 +33,4 @@ def __bool__(self):
         Return True if one of the introduction, target and instruction attribute is not empty.
         Return False otherwise.
         """
-        return bool(self.introduction or self.introduction or self.introduction)
+        return bool(self.introduction or self.target or self.instruction)
diff --git a/docs/guidebook/en/0_index.md b/docs/guidebook/en/0_index.md
index 981b95cd..618d32ca 100644
--- a/docs/guidebook/en/0_index.md
+++ b/docs/guidebook/en/0_index.md
@@ -12,7 +12,7 @@
 
 * 2.1 Framework Principles
 * 2.2 [Domain Components](2_2_Domain_Component_Principles.md)
-  * 2.2.1 Agent
+  * 2.2.1 [Agent](2_2_1_Agent.md)
   * 2.2.2 LLM
   * 2.2.3 Tool
   * 2.2.4 Knowledge
@@ -21,9 +21,13 @@
 * 2.3 Technical Components
 * 2.4 Others
   * 2.4.1 Service
+    * 2.4.1.1 [Registration and Usage](2_4_1_Service_Registration_and_Usage.md)
+    * 2.4.1.2 [Web Server](2_4_1_Web_Server.md)
+    * 2.4.1.3 [Web API](2_4_1_Web_Api.md)
   * 2.4.2 Prompt Management
   * 2.4.3 Multi-turn Dialogue
   * 2.4.4 Logging
+    * 2.4.4.1 [Logging Component](2_6_Logging_Utils.md)
   * 2.4.5 Data Collection
 
 **3. Component Reference Manual**
@@ -38,12 +42,14 @@
   * 3.2.1 RPC
   * 3.2.2 Store
   * 3.2.3 Msg
+  * 3.2.4 Logging
+    * 3.2.4.1 [Alibaba Cloud SLS](3_2_4_Alibaba_Cloud_SLS.md)
 
 **[4. API Reference Manual](4_1_API_Reference.md)**
 
 **5. Best Practices**
 * 5.1 Operations and Deployment
-  * 5.1.1 Docker Containerization Solution
+  * 5.1.1 [Docker Containerization Solution](5_1_1_Docker_Container_Deployment.md)
 
 **6. Series of Articles**
 
diff --git a/docs/guidebook/en/2_1_1_Agent.md b/docs/guidebook/en/2_2_1_Agent.md
similarity index 95%
rename from docs/guidebook/en/2_1_1_Agent.md
rename to docs/guidebook/en/2_2_1_Agent.md
index 1bff4173..2819bc8d 100644
--- a/docs/guidebook/en/2_1_1_Agent.md
+++ b/docs/guidebook/en/2_2_1_Agent.md
@@ -68,5 +68,8 @@ Tools available for Agents. agentUniverse offers numerous existing Tool componen
 ### Knowledge
 Knowledge available for Agents. agentUniverse provides a wide range of existing Knowledge components and standard methods for Knowledge customization. You can opt to use or define the Knowledge you want to use, and then load it into the Agent through configuration. In addition, agentUniverse supports the expanded integration of underlying storage technology middleware, such as SQLite, Chroma, and other storage options, meaning you can access data from any storage medium. We will explain in detail how they work in the Knowledge section.
 
-# Summary
+## Memory
+The memory available for Agents. agentUniverse provides standard optional memory types, and in most cases, users do not need to concern themselves with the specific implementation of memory. The memory component also offers the capability for users to customize it themselves. We will explain in detail how they work in the Memory section.
+
+# Conclusion
 Up to this point, you have gained a comprehensive understanding of the components and principles of an Agent. In the next section, we will specifically introduce the standard definitions of Agent components, how to customize an Agent, and how to use an Agent, among other topics.
\ No newline at end of file
diff --git a/docs/guidebook/en/2_4_1_Service_Registration_and_Usage.md b/docs/guidebook/en/2_4_1_Service_Registration_and_Usage.md
new file mode 100644
index 00000000..cb2462fc
--- /dev/null
+++ b/docs/guidebook/en/2_4_1_Service_Registration_and_Usage.md
@@ -0,0 +1,31 @@
+# Service
+
+AgentUniverse allows developers to register completed Agents as a Service using a simple template definition. This enables the use of the corresponding Agent services through Web API calls after launching the built-in web server.
+
+## Registration Method
+
+### Step1: Configure Scan Path
+AgentUniverse automatically registers Service configuration files by scanning configured paths at application startup. The scanning paths are configured in the `config.toml` file:
+```toml
+[CORE_PACKAGE]
+default = ['default_scan_path']
+service = ['service_scan_path']
+```
+By default, AgentUniverse scans all paths under default or service, with the path configuration under service having higher priority than default.
+
+
+### Step2: Configuration File
+```yaml
+name: 'service_name'
+description: 'description of the service'
+agent: 'agent_name'
+metadata:
+  type: 'SERVICE'
+```
+- **`name`**: The name of the Service, which needs to be provided when calling the service through the Web API.
+- **`description`**: Description of the Service's functionality.
+- **`agent`**: The name of the Agent. For more information about Agents, please refer to [Agent]().
+- **`metadata`**: Indicates that this configuration is for a Service; no changes are needed.
+
+## Usage
+Please refer to [Web API](2_4_1_Web_Api.md).
\ No newline at end of file
diff --git a/docs/guidebook/en/2_4_1_Web_Api.md b/docs/guidebook/en/2_4_1_Web_Api.md
new file mode 100644
index 00000000..2864a63b
--- /dev/null
+++ b/docs/guidebook/en/2_4_1_Web_Api.md
@@ -0,0 +1,98 @@
+# Web API
+
+The Web Server of AgentUniverse provides several API interfaces for calling Agent services, allowing developers to call Agent services through web api.
+
+For convenience, let's assume that the Web Server is started on port 8888 locally and has registered an Agent service named `demo_service`：
+```yaml
+name: 'demo_service'
+description: 'A demo service used for explaining.'
+agent: 'demo_agent'
+metadata:
+  type: 'SERVICE'
+```
+The `demo_agent` accepts a string type input parameter,
+and returns a string: `"Your input is {input}."`
+
+## /service_run
+This POST interface calls the Agent service in a synchronous manner, and the call will block until the target Agent service returns a result.
+An example call is as follows:
+```shell
+curl -X POST -H "Content-Type: application/json" -d '{"service_id":"demo_service","params":{"input":"Hello!"}}' http://127.0.0.1:8888/service_run
+```
+The expected return value example is as follows:
+```shell
+{
+        "success": true,
+        "result": "Your input is Hello!.",
+        "message": null,
+        "request_id": "7dd7d737b6b64c3c92addf541e73e97c"
+}
+```
+- **`success`**: Indicates whether the Agent call was successful or not, with values `true` and `false`.。
+- **`message`**: When the `success` value is `false`, this value represents the error message, and it is `null` when successful.
+- **`result`**: Represents the result of the execution when the Agent call is successful.
+- **`request_id`**: A random string, used for a unique request. It can be used in the [/service_run_result](#servicerunresult) interface to query the result of the corresponding request.
+
+## /service_run_stream
+
+This POST interface is similar to `/service_run`, and its call method is consistent with it:
+```shell
+curl -X POST -H "Content-Type: application/json" -d '{"service_id":"demo_service","params":{"input":"Hello!"}}' http://127.0.0.1:8888/service_run_stream
+```
+However, the return result of the Agent will be returned in a streaming manner:
+```text
+# agentuniverse.agent_serve_web.flask_server.service_run_stream
+
+response = Response(task.stream_run(), mimetype="text/event-stream")
+response.headers['X-Request-ID'] = task.request_id
+```
+`request_id` will be included in the response header X-Request-ID.
+
+## /service_run_async
+This POST interface calls the Agent service in an asynchronous manner. The calling method is as follows:
+```shell
+curl -X POST -H "Content-Type: application/json" -d '{"service_id":"demo_service","params":{"input":"Hello!"}}' http://127.0.0.1:8888/service_run_async
+```
+The interface will return immediately:
+```shell
+{
+        "success": true,
+        "result": null,
+        "message": null,
+        "request_id": "7dd7d737b6b64c3c92addf541e73e97c"
+}
+```
+The return result will only contain the success indicating whether the call was successful or not, and the request_id indicating this call.
+For the result of the call, you need to use the request_id to query in the [/service_run_result](#servicerunresult) interface.
+
+## /service_run_result
+This GET interface allows users to check the request status with request_id, an example call is as follows:
+```shell
+ curl 'http://127.0.0.1:8888/service_run_result?request_id=8e6f17dbe7ff4730a62b4a2914d73c74'
+```
+The expected return value example is as follows:
+```shell
+{
+  "message":null,
+  "request_id":"8e6f17dbe7ff4730a62b4a2914d73c74",
+  "result":{
+    "result":"Your input is Hello!.",
+    "state":"finish",
+    "steps":[]
+    },
+  "success":true}
+
+```
+The `result` contains three parts: `result` indicates the result of the Agent service execution, `state` indicates the state of the Agent service execution, and `steps` indicates the intermediate process of the Agent service execution.  
+`state` represents the task status and includes the following scenarios:
+```text
+# agentuniverse.agent_serve.web.request_task.TaskStateEnum
+
+class TaskStateEnum(Enum):
+    """All possible state of a web request task."""
+    INIT = "init"
+    RUNNING = "running"
+    FINISHED = "finished"
+    FAIL = "fail"
+    CANCELED = "canceled"
+```
diff --git a/docs/guidebook/en/2_4_1_Web_Server.md b/docs/guidebook/en/2_4_1_Web_Server.md
new file mode 100644
index 00000000..bad0a992
--- /dev/null
+++ b/docs/guidebook/en/2_4_1_Web_Server.md
@@ -0,0 +1,69 @@
+# 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.
+
+## Web Server Launch
+You need to start the web server after launching the AgentUniverse application.
+Here is an example of how to launch it:
+```python
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+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:：
+```python
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+
+start_web_server(bind='127.0.0.1:8888')
+```
+
+## 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.
+
+### AgentUniverse Default Configuration
+```python
+DEFAULT_GUNICORN_CONFIG = {
+    'bind': '127.0.0.1:8000',
+    'workers': 5,
+    'backlog': 2048,
+    'worker_class': 'gthread',
+    'threads': 4,
+    'timeout': 60,
+    'keepalive': 10
+}
+```
+AgentUniverse has pre-configured some parameters based on the framework's working characteristics, which you can modify through the configuration file below or parameters when launching the web server.
+
+### 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 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'
+```
+If this parameter is in relative path format, the corresponding parent directory is the directory where the main configuration file config.toml is located.
+
+### Configuration File
+```toml
+[GUNICORN_CONFIG]
+bind = '127.0.0.1:8000'
+backlog = 2048
+worker_class = 'gthread'
+threads = 4
+workers = 5
+timeout = 60
+keepalive = 10
+```
+The configuration file is written in TOML format, and the specific configuration items are not limited to the content in the example above. You can refer to the official Gunicorn documentation for more detailed configurations.
+
+### Startup Configuration
+You can also configure the web server at startup as follows:
+```python
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+
+start_web_server(bind="127.0.0.1:8002", threads=4)
+```
\ No newline at end of file
diff --git a/docs/guidebook/en/2_6_Logging_Utils.md b/docs/guidebook/en/2_6_Logging_Utils.md
new file mode 100644
index 00000000..9d22846f
--- /dev/null
+++ b/docs/guidebook/en/2_6_Logging_Utils.md
@@ -0,0 +1,75 @@
+# Logging Utils
+
+The log component of AgentUniverse is implemented based on loguru, providing a well-packaged global log component and customizable log components. This tutorial will first introduce the usage of the log configuration file in AgentUniverse, then explain the usage of the global log component and customizable log components in turn, and finally describe how to interface with external log service components.
+    
+## Log Configuration
+
+### Configuration File Path
+The configuration path of the log file is specified in the main configuration of AgentUniverse, config.toml.
+```toml
+[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'
+```
+ If this parameter is a relative path, its parent directory is the directory where the main configuration file, config.toml, is located.
+If this parameter does not exist, AgentUniverse will use the default log configuration, see [default configuration](#default-configuration).
+
+### Configuration File Options
+The configuration file for logs is in the toml file format; an example configuration is as follows:
+```toml
+[LOG_CONFIG]
+[LOG_CONFIG.BASIC_CONFIG]
+log_level = "INFO"
+log_path = "~/.agent_universe_log"
+log_rotation = "100 MB"
+log_retention = "7 days"
+```
+- **`log_level`**: The default log level, possible values include "TRACE", "DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL". The level of the global log component will be the same as this value. When creating a custom log component, if log level is not specified, this default level will be used.
+- **`log_path`**: The log storage path, if this value is empty, a {workdir}/../../logs folder will be created as the log storage path.
+- **`log_rotation`**: This parameter accepts a duration (e.g., "1 week") or file size (e.g., "100 MB"), indicating the condition for log file rotation.
+- **`log_retention`**: This parameter accepts a duration (e.g., "7 days") indicating the retention period for old log files, which will be deleted after they expire.
+
+### Default Configuration
+Configuration not specified in the log configuration file will take the following default settings:
+- **`log_level`**: "INFO"
+- **`log_rotation`**: "10MB"
+- **`log_retention`**: "3 days"
+
+Two default log files, `au_all.log` and `au_error.log`, will be located in the log storage path. 'All' records all logs above the default log level set in the log configuration, while 'error' records only logs at the ERROR level and above. The format for log component output is:
+```python
+log_format: str = ("<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> "
+                       "| <level>{level: <8}</level> "
+                       "| {extra[context_prefix]} "
+                       "| <cyan>{name}</cyan>"
+                       ":<cyan>{function}</cyan>"
+                       ":<cyan>{line}</cyan> "
+                       "| <level>{message}</level>")
+```
+Where `{extra[context_prefix]}` defaults to `default`, When `LOG_CONTEXT` exists in the framework context, its contents will be replaced by the contents of `LOG_CONTEXT`. For more information related to the framework context, please refer to  [Framework_Context](2_7_Framework_Context.md)。
+
+## Global Log Component
+AgentUniverse provides a directly usable log component `logging_util.Logger`, which you can introduce into your project as follows:
+```python
+from agentuniverse.base.util.logging.logging_util import LOGGER
+```
+You can use this object's different member functions to record logs of different levels:
+```python
+from agentuniverse.base.util.logging.logging_util import LOGGER
+
+LOGGER.info("This is an info log.")
+LOGGER.debug("This is a debug log.")
+LOGGER.warn("This is a warn log.")
+LOGGER.error("This is an error log.")
+```
+
+## Custom Log Components
+If you want to output and save certain logs separately, you can create a custom log component using the `get_module_logger` function::
+```python
+from agentuniverse.base.util.logging.logging_util import get_module_logger
+new_logger = get_module_logger("new_module")
+```
+Logs recorded by this new component will be saved in the log storage path, in a log file named `au_{module_name}.log`,  where `{module_name}` is the module name you passed into `get_module_logger`, as in the example above, the corresponding file would be `au_new_module.log`.
+
+## External Log Service
+
+If you want to use more log utils, please refer to [extension logging utils](3_2_4_Alibaba_Cloud_SLS.md).
diff --git a/docs/guidebook/en/2_7_Framework_Context.md b/docs/guidebook/en/2_7_Framework_Context.md
new file mode 100644
index 00000000..784879c8
--- /dev/null
+++ b/docs/guidebook/en/2_7_Framework_Context.md
@@ -0,0 +1,37 @@
+# Framework Context
+
+AgentUniverse provides a context management tool that is independent on threads and coroutines level, allowing the storage and retrieval of context variables in a key-value format that need to be managed separately within threads or coroutines.
+
+## Usage
+
+### Creating Context Variables
+#### Method 1:
+```python
+from agentuniverse.base.context.framework_context import FrameworkContext
+
+with FrameworkContext({"context_var1": 1,
+                       "context_var2":"context_var"}):
+    pass
+```
+By using the `with` keyword to create a `FrameworkContext` instance, which accepts a `dict` type parameter, AgentUniverse will save all key-value pairs from the parameters to the context manager within the scope of with, and remove them upon exit.
+
+#### Method 2:
+```python
+from agentuniverse.base.context.framework_context_manager import FrameworkContextManager
+
+FrameworkContextManager().set_context("context_var", "value")
+```
+Create a new context variable with `FrameworkContextManager` directly. Variables created in this way will exist throughout the lifecycle of the thread or coroutine and can be manually deleted with following code:
+```python
+from agentuniverse.base.context.framework_context_manager import FrameworkContextManager
+
+FrameworkContextManager().del_context("context_var")
+```
+### Using Context Variables
+You can retrieve previously saved variables through the `FrameworkContextManager`：
+```python
+from agentuniverse.base.context.framework_context_manager import FrameworkContextManager
+
+FrameworkContextManager().get_context("context_var", default_value=None)
+```
+The `default_value` is `None` by default. When there is no corresponding key in the context, `default_value` is returned.
\ No newline at end of file
diff --git a/docs/guidebook/en/3_2_4_Alibaba_Cloud_SLS.md b/docs/guidebook/en/3_2_4_Alibaba_Cloud_SLS.md
new file mode 100644
index 00000000..a370019f
--- /dev/null
+++ b/docs/guidebook/en/3_2_4_Alibaba_Cloud_SLS.md
@@ -0,0 +1,38 @@
+## Aliyun SLS
+If you want to use aliyun sls, you should install agentUniverse in this way:
+```shell
+pip install agentuniverse[log_ext]
+```
+
+You will need to make the following configuration in the log configuration file:
+```toml
+[LOG_CONFIG.EXTEND_MODULE]
+# Whether use aliyun simple log server. If value is True, you should fill the ALIYUN_SLS_CONFIG below.
+sls_log = "True"
+
+[LOG_CONFIG.ALIYUN_SLS_CONFIG]
+# Aliyun sls endpoint.
+sls_endpoint = "mock_endpoint"
+# Your sls log project name.
+sls_project = "mock_project"
+# Your sls log store name.
+sls_log_store = "mock_log_store"
+# Aliyun sls access_key_id.
+access_key_id = "mock_key_id"
+# Aliyun sls access_key_secret.
+access_key_secret = "mock_key_secret"
+# Log queue max size, antfinagentframework uses a queue to save the logs to be sent, they will be sent periodically.
+sls_log_queue_max_size = 1000
+# Interval of sending logs to aliyun sls.
+sls_log_send_interval = 3.0
+```
+- **`sls_log`**: This must be True if you need to use sls.
+- **`sls_endpoint`**: The endpoint address for Aliyun sls.
+- **`sls_project`**: The project in Aliyun sls.
+- **`sls_log_store`**: The log store in Aliyun sls.
+- **`access_key_id`**: The access key id for Aliyun sls.
+- **`access_key_secret`**: The access key secret for Aliyun sls.
+- **`sls_log_queue_max_size`**: The AgentUniverse adopts a mechanism of timing batch uploading of logs. This parameter signifies the maximum number of log entries that can be cached during each upload interval.
+- **`sls_log_send_interval`**: The interval for uploading logs to sls, in seconds.
+
+ After configuration, you can directly use the global log component or your custom log components to record logs. AgentUniverse will automatically upload the recorded content to your sls.
\ No newline at end of file
diff --git a/docs/guidebook/en/5_1_1_Docker_Container_Deployment.md b/docs/guidebook/en/5_1_1_Docker_Container_Deployment.md
new file mode 100644
index 00000000..4c3b3b4a
--- /dev/null
+++ b/docs/guidebook/en/5_1_1_Docker_Container_Deployment.md
@@ -0,0 +1,45 @@
+# Docker container deployment
+
+AgentUniverse provides standard work environment images for containerized deployment of AgentUniverse projects. This document will explain how to deploy your own project based on the such images.
+
+## Preparations
+1.  Build your own project according to the standard directory structure of AgentUniverse, referring to [Application_Engineering_Structure_Explanation](1_4_Application_Engineering_Structure_Explanation.md)。For ease of explanation, this document assumes the project name and project directory are `sample_standard_app`.
+2.   Get the required version of the AgentUniverse image.
+```shell
+docker pull registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta
+```
+
+
+## Method 1: Mount the host path
+You can mount your project to a path inside the container by mounting the host directory, with the reference command as follows:
+```shell
+docker run -d -p 8888:8888 -v ./sample_standard_app/:/usr/local/etc/workspace/project registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta
+```
+The`-p 8888:8888`represents the port mapping for the Web Server. The first 8888 indicates that the web server inside the container is started on port 8888, and the latter indicates that it is mapped to port 8888 on the host machine. Adjust it according to the actual startup conditions of the application as needed.  
+`-v {local_dir}:/usr/local/etc/workspace/project`indicates that the `local_dir` directory on the host is mounted to the `/usr/local/etc/workspace/project`within the container. The directory path inside the container is a fixed value and cannot be modified.
+
+### Precautions:：
+If you need multiple containers to mount the same directory, it's advised to pay attention to the following points when using this method:：
+1. Specify a SQLite database file address outside the mounted path `/usr/local/etc/workspace/project`in the config.toml, such as inside `/usr/local/etc` in the container, for example,
+    ```toml
+    mysql_uri = 'sqlite:////usr/local/etc/agent_universe.db'
+    ```
+    This can reduce the problems with SQLite concurrency (as SQLite does not handle concurrency very well). Alternatively, you can directly use MySQL, which will offer better concurrency performance.
+2. Specify a directory outside the mounted path in the log_config.toml, like
+    ```toml
+    log_path = "/usr/local/etc/au_log"
+    ```
+    To prevent all containers from logging in the same file, which makes it difficult to read.
+
+## Method 2: Pull the project from Github
+The image already has the git command installed. You can modify the image's entrypoint to git clone your project and then copy the entire project to a specified path. For example:
+```shell
+docker run -d -p 8888:8888 --entrypoint=/bin/bash registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta -c "git clone {repo_addr}; mv {project_dir} /usr/local/etc/workspace/project; /bin/bash --login /usr/local/etc/workspace/shell/start.sh"
+````
+Where `repo_addr` is the address of your git project，and `project_dir` is the project directory, for example，if `sample_standard_app` is in the `project`directory within your git project, then`project_dir` would be `project/sample_standard_app`。
+## Result Verification
+Taking the example of port 8888, you can verify whether the service has started correctly using the curl command:
+```shell
+curl http://127.0.0.1:8888/echo
+```
+Try to access the web service, and if it returns the word "Welcome" it means the service has started successfully.
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 6e59dbb8..c2883ffa 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"
@@ -16,7 +16,7 @@
 
 * 2.1 框架原理
 * 2.2 [领域组件](2_2_领域组件原理.md)
-  * 2.2.1 智能体(Agent)
+  * 2.2.1 [智能体(Agent)](2_2_1_智能体.md)
   * 2.2.2 模型(LLM)
   * 2.2.3 工具(Tool)
   * 2.2.4 知识(Knowledge)
@@ -25,9 +25,13 @@
 * 2.3 技术组件
 * 2.4 其他
   * 2.4.1 服务化
+    * 2.4.1.1 [注册与使用](2_4_1_服务注册与使用.md)
+    * 2.4.1.2 [Web Server](2_4_1_Web_Server.md)
+    * 2.4.1.3 [服务API](2_4_1_服务Api.md)
   * 2.4.2 prompt管理
   * 2.4.3 多轮会话
   * 2.4.4 日志体系
+    * 2.4.4.1 [日志组件](2_4_4_日志组件.md)
   * 2.4.5 数据采集
 
 **3.组件参考手册**
@@ -40,14 +44,16 @@
   * 3.1.6 规划(Planner)
 * 3.2 技术组件
   * 3.2.1 RPC
-  * 3.2.2 存储 (store)
+  * 3.2.2 存储 (Store)
   * 3.2.3 消息(Msg)
+  * 3.2.4 日志(Logging)
+    * 3.2.4.1 [阿里云SLS](3_2_4_阿里云SLS.md)
 
 **[4.API参考手册](4_1_API参考.md)**
 
 **5.最佳实践**
 * 5.1 运维部署
-  * 5.1.1 docker容器化方案
+  * 5.1.1 [docker容器化方案](5_1_1_Docker容器化部署.md)
 
 **6.系列文章**
 
diff --git "a/docs/guidebook/zh/2_1_1_\346\231\272\350\203\275\344\275\223.md" "b/docs/guidebook/zh/2_2_1_\346\231\272\350\203\275\344\275\223.md"
similarity index 95%
rename from "docs/guidebook/zh/2_1_1_\346\231\272\350\203\275\344\275\223.md"
rename to "docs/guidebook/zh/2_2_1_\346\231\272\350\203\275\344\275\223.md"
index 7f26accd..ad957ff0 100644
--- "a/docs/guidebook/zh/2_1_1_\346\231\272\350\203\275\344\275\223.md"
+++ "b/docs/guidebook/zh/2_2_1_\346\231\272\350\203\275\344\275\223.md"
@@ -1,5 +1,5 @@
 # 智能体(Agent)
-智能体（Agent）能够自主行动完成人类设定的目标，它具备学习、推理、决策和执行能力，通过任务拆分、工具知识使用、进度控制等步骤，实现目标并自主结束工作。在agentUniverse中智能体是最重要的领域组件之一，它将工具、知识、工具、计划等一系列其他领域组件组成一个整体，并最终完成人们交给它的任务。
+智能体（Agent）能够自主行动实现人类设定的目标，它具备学习、推理、决策和执行能力，通过任务拆分、工具知识使用、进度控制等步骤，实现目标并自主结束工作。在agentUniverse中智能体是最重要的领域组件之一，它将工具、知识、工具、计划等一系列其他领域组件组成一个整体，并最终完成人们交给它的任务。
 
 智能体的表现直接影响了应用服务能力的强弱，在复杂的服务场景中往往需要一个或多个非常出色的智能体去完成任务。agentUniverse根据业界与学界的成果结合实际产业落地过程中的经验拥有如下对于agent的定义，见图。
 ![](../_picture/agent.jpg)
@@ -62,5 +62,8 @@ agentUniverse提供了大量已经验证有效的Pattern模式并提供对应沉
 ### 知识（Knowledge）
 可供Agent使用的知识。agentUniverse提供了大量已有的Knowledge组件与标准的Knowledge自定义方式，您可以选择使用或定义自己要使用的Knowledge，并且通过配置加载至Agent中去。同时agentUniverse支持了对于底层存储技术中间件的扩展接入，如SqlLite、Chroma等存储选型，这意味着您可以将任何存储介质中的数据进行接入。我们会在Knowledge章节中具体说明他们如何工作。
 
+## 记忆（Memory）
+可供Agent使用的记忆。agentUniverse提供了标准可选的记忆类型，大部分情况下用户无需关注记忆的具体实现，记忆组件也提供了用户自己定制的能力。我们会在Memory章节中具体说明他们如何工作。
+
 # 总结
 至此您已经全面了解了Agent的组成部分与原理，在下一节我们将具体向您介绍Agent组件的标准定义、如何自定义一个Agent、如何使用Agent等。
\ 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
new file mode 100644
index 00000000..67054a75
--- /dev/null
+++ b/docs/guidebook/zh/2_4_1_Web_Server.md
@@ -0,0 +1,69 @@
+# Web Server
+
+AgentUniverse提供了一个基于Gunicorn+Flask的Web Server，您可以通过Web Server中预置的API调用开发完成的Agent服务。
+
+## Web Server启动
+您需要在AgentUniverse应用启动后，启动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()
+```
+
+## Windows用户
+如果您正在windows上使用AgentUniverse，由于Gunicorn兼容性问题，AgentUniverse会直接运行Flask程序。您可以在`start_web_server`中修改启动端口，如：
+```python
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+
+start_web_server(bind='127.0.0.1:8888')
+```
+
+## Web Server配置
+Web Server的配置按照优先度从低到高包含四个层次:`gunicorn`原生默认配置，AgentUniverse默认配置，配置文件配置和启动时配置。其中`gunicorn`的原生默认配置请参考对应版本的`gunicorn`官方文档。
+
+### AgentUniverse默认配置
+```python
+DEFAULT_GUNICORN_CONFIG = {
+    'bind': '127.0.0.1:8000',
+    'workers': 5,
+    'backlog': 2048,
+    'worker_class': 'gthread',
+    'threads': 4,
+    'timeout': 60,
+    'keepalive': 10
+}
+```
+AgentUniverse根据框架的工作特性预先进行了部分参数的配置，您可以通过下面的配置文件或者是启动Web Server时的参数进行修改。
+
+### 配置文件路径
+Web Server的配置路径会在AgentUniverse的主配置config.toml中指定。
+```toml
+[SUB_CONFIG_PATH]
+# 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'
+```
+如果该参数为相对路径形式，对应的父目录为主配置config.toml所在目录。
+
+### 配置文件
+```toml
+[GUNICORN_CONFIG]
+bind = '127.0.0.1:8000'
+backlog = 2048
+worker_class = 'gthread'
+threads = 4
+workers = 5
+timeout = 60
+keepalive = 10
+```
+配置文件以toml格式书写，具体的配置项不局限于上述实例中的内容，您可以参考`gunicorn`的官方文档进行更详细的配置。
+
+### 启动配置
+您也可以通过以下方式在启动Web Server时进行配置：
+```python
+from agentuniverse.agent_serve.web.web_booster import start_web_server
+
+start_web_server(bind="127.0.0.1:8002", threads=4)
+```
\ No newline at end of file
diff --git "a/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241Api.md" "b/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241Api.md"
new file mode 100644
index 00000000..3c876bf1
--- /dev/null
+++ "b/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241Api.md"
@@ -0,0 +1,99 @@
+# Web API
+
+AgentUniverse的Web Server提供了数个调用Agent服务的API接口，允许开发者按自己的需求从外部调用Agent服务。
+
+为了方便说明，我们假设Web Server启动在本地的8888端口上，并注册了一个名为`demo_service`的Agent服务：
+```yaml
+name: 'demo_service'
+description: 'A demo service used for explaining.'
+agent: 'demo_agent'
+metadata:
+  type: 'SERVICE'
+```
+其中的`demo_agent`接受一个str类型的input参数,  
+并返回一个字符串:`"Your input is {input}."`
+
+## /service_run
+该POST接口以同步的方式调用Agent服务，调用会阻塞直到目标Agent服务返回结果。  
+调用示例如下:
+```shell
+curl -X POST -H "Content-Type: application/json" -d '{"service_id":"demo_service","params":{"input":"Hello!"}}' http://127.0.0.1:8888/service_run
+```
+预期收到的返回值示例如下：
+```shell
+{
+        "success": true,
+        "result": "Your input is Hello!.",
+        "message": null,
+        "request_id": "7dd7d737b6b64c3c92addf541e73e97c"
+}
+```
+- **`success`**:表示Agent调用的成功与否，取值为`true`和`false`。
+- **`message`**:当`success`值为`false`时，该值表示错误信息，成功时为`null`。
+- **`result`**:Agent调用成功时，表示执行的结果。
+- **`request_id`**:一串随机的字符串，用于一个唯一的请求。可以用于[/service_run_result]()接口，查询对应请求的结果。
+
+## /service_run_stream
+
+该POST接口类似`/service_run`，调用方式与其一致:
+```shell
+curl -X POST -H "Content-Type: application/json" -d '{"service_id":"demo_service","params":{"input":"Hello!"}}' http://127.0.0.1:8888/service_run_stream
+```
+但是Agent的返回结果会以流式的形式返回:
+```text
+# agentuniverse.agent_serve_web.flask_server.service_run_stream
+
+response = Response(task.stream_run(), mimetype="text/event-stream")
+response.headers['X-Request-ID'] = task.request_id
+```
+`request_id`会被包含在响应头`X-Request-ID`中。
+
+## /service_run_async
+该POST接口以异步的形式调用Agent服务。调用方式如下:
+```shell
+curl -X POST -H "Content-Type: application/json" -d '{"service_id":"demo_service","params":{"input":"Hello!"}}' http://127.0.0.1:8888/service_run_async
+```
+该接口调用后会立刻返回:
+```shell
+{
+        "success": true,
+        "result": null,
+        "message": null,
+        "request_id": "7dd7d737b6b64c3c92addf541e73e97c"
+}
+```
+返回结果中仅会包含表示调用成功与否的`success`与表示本次调用的`request_id`。
+对于调用的结果，您需要使用`request_id`在[/service_run_result]()接口中进行查询。
+
+## /service_run_result
+该GET接口允许用户用request_id的状态，调用样例如下：
+```shell
+ curl 'http://127.0.0.1:8888/service_run_result?request_id=8e6f17dbe7ff4730a62b4a2914d73c74'
+```
+预期收到的返回值示例如下：
+```shell
+{
+  "message":null,
+  "request_id":"8e6f17dbe7ff4730a62b4a2914d73c74",
+  "result":{
+    "result":"Your input is Hello!.",
+    "state":"finish",
+    "steps":[]
+    },
+  "success":true}
+
+```
+其中`result`包含三个部分：`result`表示Agent服务的执行结果，`state`表示Agent服务的执行状态，`steps`表示Agent服务执行的中间过程。
+
+`state`表示的任务状态包含以下几种情况：
+```text
+# agentuniverse.agent_serve.web.request_task.TaskStateEnum
+
+class TaskStateEnum(Enum):
+    """All possible state of a web request task."""
+    INIT = "init"
+    RUNNING = "running"
+    FINISHED = "finished"
+    FAIL = "fail"
+    CANCELED = "canceled"
+```
diff --git "a/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241\346\263\250\345\206\214\344\270\216\344\275\277\347\224\250.md" "b/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241\346\263\250\345\206\214\344\270\216\344\275\277\347\224\250.md"
new file mode 100644
index 00000000..b6ac0b5a
--- /dev/null
+++ "b/docs/guidebook/zh/2_4_1_\346\234\215\345\212\241\346\263\250\345\206\214\344\270\216\344\275\277\347\224\250.md"
@@ -0,0 +1,31 @@
+# Service
+
+AgentUniverse允许开发者使用简单模版定义的方式将开发完成的Agent注册为一个Service，能够在启动内置的Web服务器后，通过调用Web API使用对应的Agent服务。
+
+## 注册方式
+
+### 第一步：配置扫描路径
+AgentUniverse通过在应用启动时扫描配置路径的方式寻找Service的配置文件并进行自动注册，扫描的路径配置在配置文件`config.toml`中：
+```toml
+[CORE_PACKAGE]
+default = ['default_scan_path']
+service = ['service_scan_path']
+```
+AgentUniverse默认会扫描`default`或`service`中的所有路径，`service`下的路径配置优先级高于`default`。
+
+
+### 第二步：配置文件
+```yaml
+name: 'service_name'
+description: 'description of the service'
+agent: 'agent_name'
+metadata:
+  type: 'SERVICE'
+```
+- **`name`**:Service的名称，在Web API中调用服务时需要传入该名称。
+- **`description`**:对Service功能的描述。
+- **`agent`**:Agent的名称，关于Agent的具体内容请参考[Agent]()。
+- **`metadata`**:表示该配置是一个Service配置，无需改动。
+
+## 使用方式
+请参考[Web API](2_4_1_服务Api.md).
\ No newline at end of file
diff --git "a/docs/guidebook/zh/2_4_4_\346\227\245\345\277\227\347\273\204\344\273\266.md" "b/docs/guidebook/zh/2_4_4_\346\227\245\345\277\227\347\273\204\344\273\266.md"
new file mode 100644
index 00000000..5077429d
--- /dev/null
+++ "b/docs/guidebook/zh/2_4_4_\346\227\245\345\277\227\347\273\204\344\273\266.md"
@@ -0,0 +1,76 @@
+# 日志组件
+
+AgentUniverse的日志组件基于loguru实现，提供封装好的全局日志组件和定制日志组件。本教程将首先介绍AgentUniverse中关于日志的配置文件使用方式，然后依次介绍关于全局日志组件和定制日志组件的使用方式，并在最后介绍如何对接外部的日志服务组件。
+## 日志配置
+
+### 配置文件路径
+日志文件的配置路径会在AgentUniverse的主配置config.toml中指定
+```toml
+[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'
+```
+如果该参数为相对路径形式，对应的父目录为主配置config.toml所在目录。
+如果该参数不存在，则AgentUniverse会使用默认日志配置，具体配置参考[默认配置](#默认配置)
+
+### 配置文件选项
+日志的配置文件为toml文件格式，一个示例配置如下。
+```toml
+[LOG_CONFIG]
+[LOG_CONFIG.BASIC_CONFIG]
+log_level = "INFO"
+log_path = "~/.agent_universe_log"
+log_rotation = "100 MB"
+log_retention = "7 days"
+```
+- **`log_level`**: 默认的日志级别，可取值包括"TRACE","DEBUG","INFO", "SUCCESS","WARNING","ERROR","CRITICAL"。全局日志组件的级别和该值相同。创建定制日志组件的时候如果不额外指定级别，则也默认使用该级别。
+- **`log_path`**: 日志存储路径，如果该值为空，则会创建一个{workdir}/../../logs文件夹作为日志存储路径。
+- **`log_rotation`**: 该参数接受一个时间长度(e.g., "1 week")或一个文件大小 (e.g., "100 MB")，用于表示日志文件滚动的条件。
+- **`log_retention`**: 该参数接受一个时间长度(e.g., "7 days")用于表示旧日志文件的保留时间，过期日志文件将会被删除。
+
+### 默认配置
+未在日志配置文件中指定的配置项采取以下默认配置：
+- **`log_level`**: "INFO"
+- **`log_rotation`**: "10MB"
+- **`log_retention`**: "3 days"
+
+在日志存储路径下会有两个默认日志文件`au_all.log`和`au_error.log`。其中all会记录所有高于日志配置中默认日志级别的日志，而error文件仅记录ERROR级别以上的日志。
+
+日志组件的输出格式为：
+```python
+log_format: str = ("<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> "
+                       "| <level>{level: <8}</level> "
+                       "| {extra[context_prefix]} "
+                       "| <cyan>{name}</cyan>"
+                       ":<cyan>{function}</cyan>"
+                       ":<cyan>{line}</cyan> "
+                       "| <level>{message}</level>")
+```
+其中`{extra[context_prefix]}`默认为`default`, 当框架上下文中存在`LOG_CONTEXT`时，则会内容替换为`LOG_CONTEXT`的内容。关于更多框架上下文相关的内容，请参考[框架上下文](2_7_框架上下文.md)。
+
+## 全局日志组件
+AgentUniverse提供一个可直接使用的日志组件`logging_util.Logger`,您可以在项目中通过如下方式引入该组件：
+```python
+from agentuniverse.base.util.logging.logging_util import LOGGER
+```
+您可以用通过该对象的不同成员函数记录不同等级的日志：
+```python
+from agentuniverse.base.util.logging.logging_util import LOGGER
+
+LOGGER.info("This is an info log.")
+LOGGER.debug("This is a debug log.")
+LOGGER.warn("This is a warn log.")
+LOGGER.error("This is an error log.")
+```
+
+## 定制日志组件
+如果您想将某些日志单独输出保存，您可以使用`get_module_logger`函数创建一个自定义的日志组件:
+```python
+from agentuniverse.base.util.logging.logging_util import get_module_logger
+new_logger = get_module_logger("new_module")
+```
+由这个新组件记录的日志会被保存在日志存储路径下名为`au_{module_name}.log`的日志文件中，其中`{module_name}`是您使用`get_module_logger`时传入的模块名称，如上述例子中对应的文件为`au_new_module.log`。
+
+## 外部日志服务对接
+
+关于外部日志服务对接相关的内容您可以参考[拓展日志组件](3_2_4_阿里云SLS.md)。
\ No newline at end of file
diff --git "a/docs/guidebook/zh/2_7_\346\241\206\346\236\266\344\270\212\344\270\213\346\226\207.md" "b/docs/guidebook/zh/2_7_\346\241\206\346\236\266\344\270\212\344\270\213\346\226\207.md"
new file mode 100644
index 00000000..873412ae
--- /dev/null
+++ "b/docs/guidebook/zh/2_7_\346\241\206\346\236\266\344\270\212\344\270\213\346\226\207.md"
@@ -0,0 +1,37 @@
+# 框架上下文
+
+AgentUniverse提供了一个线程、协程独立的上下文管理工具，以key-value的形式存取需要在线程或是协程中分别管理的上下文变量。
+
+## 使用方式
+
+### 新建上下文变量
+方式1：
+```python
+from agentuniverse.base.context.framework_context import FrameworkContext
+
+with FrameworkContext({"context_var1": 1,
+                       "context_var2":"context_var"}):
+    pass
+```
+通过with关键字创建一个`FrameworkContext`实例，接受一个`dict`参数，AgentUniverse会在with的作用域内将入参中的所有key-value对保存至上下文管理器中，并在退出时清除。
+
+方式2：
+```python
+from agentuniverse.base.context.framework_context_manager import FrameworkContextManager
+
+FrameworkContextManager().set_context("context_var", "value")
+```
+直接通过上下文管理器`FrameworkContextManager`新建一个上下文变量，通过这种方式新建的变量会在整个线程或协程的生命周期内存在，可以通过下面的方式手动删除：
+```python
+from agentuniverse.base.context.framework_context_manager import FrameworkContextManager
+
+FrameworkContextManager().del_context("context_var")
+```
+### 使用上下文变量
+您可以通过上下文管理器`FrameworkContextManager`获取已经保存过的变量：
+```python
+from agentuniverse.base.context.framework_context_manager import FrameworkContextManager
+
+FrameworkContextManager().get_context("context_var", default_value=None)
+```
+其中`default_value`默认值为`None`，当上下文中不存在对应key值时返回`default_value`。
\ No newline at end of file
diff --git "a/docs/guidebook/zh/3_2_4_\351\230\277\351\207\214\344\272\221SLS.md" "b/docs/guidebook/zh/3_2_4_\351\230\277\351\207\214\344\272\221SLS.md"
new file mode 100644
index 00000000..fa1a4f6e
--- /dev/null
+++ "b/docs/guidebook/zh/3_2_4_\351\230\277\351\207\214\344\272\221SLS.md"
@@ -0,0 +1,37 @@
+## 阿里云SLS
+如果您想使用阿里云SLS的相关功能，你需要安装log_ext相关依赖:
+```shell
+pip install agentuniverse[log_ext]
+```
+您需要在日志配置文件中进行以下配置：
+```toml
+[LOG_CONFIG.EXTEND_MODULE]
+# Whether use aliyun simple log server. If value is True, you should fill the ALIYUN_SLS_CONFIG below.
+sls_log = "True"
+
+[LOG_CONFIG.ALIYUN_SLS_CONFIG]
+# Aliyun sls endpoint.
+sls_endpoint = "mock_endpoint"
+# Your sls log project name.
+sls_project = "mock_project"
+# Your sls log store name.
+sls_log_store = "mock_log_store"
+# Aliyun sls access_key_id.
+access_key_id = "mock_key_id"
+# Aliyun sls access_key_secret.
+access_key_secret = "mock_key_secret"
+# Log queue max size, antfinagentframework uses a queue to save the logs to be sent, they will be sent periodically.
+sls_log_queue_max_size = 1000
+# Interval of sending logs to aliyun sls.
+sls_log_send_interval = 3.0
+```
+- **`sls_log`**: 当您需要使用sls的时候该值必须为True
+- **`sls_endpoint`**:阿里云sls的endpoint地址
+- **`sls_project`**:阿里云sls的project
+- **`sls_log_store`**:阿里云sls的log_store
+- **`access_key_id`**:阿里云sls的ak
+- **`access_key_secret`**:阿里云sls的sk
+- **`sls_log_queue_max_size`**:AgentUniverse采用定时批量上送日志的形式，这个参数表示每次上送间隔中能缓存的最大日志条数。
+- **`sls_log_send_interval`**:上送日志到sls的间隔，单位为秒
+
+在配置完成后，您可以直接使用全局日志组件或是定制日志组件记录日志，AgentUniverse会自动将记录的内容上送至您的sls。
\ No newline at end of file
diff --git "a/docs/guidebook/zh/5_1_1_Docker\345\256\271\345\231\250\345\214\226\351\203\250\347\275\262.md" "b/docs/guidebook/zh/5_1_1_Docker\345\256\271\345\231\250\345\214\226\351\203\250\347\275\262.md"
new file mode 100644
index 00000000..bcbbf782
--- /dev/null
+++ "b/docs/guidebook/zh/5_1_1_Docker\345\256\271\345\231\250\345\214\226\351\203\250\347\275\262.md"
@@ -0,0 +1,47 @@
+# Docker容器化部署
+
+AgentUniverse提供标准的工作环境镜像用于容器化部署AgentUniverse工程。本文档将介绍如何基于工作环境镜像部署您自己的工程项目。
+
+## 准备工作
+1.  按照AgentUniverse的标准结构目录搭建自己的项目，具体结构参考[应用工程结构及说明](1_4_应用工程结构及说明.md)。为方便说明，在本文档中假设项目名称和工程目录为`sample_standard_app`。
+2.  获取所需版本的镜像:
+```shell
+docker pull registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta
+```
+
+
+## 方法一：挂载宿主机路径
+您可以通过将宿主机目录挂载您的项目至容器内路径，参考命令如下:
+```shell
+docker run -d -p 8888:8888 -e OPENAI_API_KEY=XXX -v ./sample_standard_app/:/usr/local/etc/workspace/project registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta
+```
+其中`-p 8888:8888`为Web Server的端口映射，前面的8888表示容器内的webserver启动在8888端口，后者表示映射到宿主机的8888端口，可自行根据实际应用的启动情况调整。-e OPENAI_API_KEY=XXX可以添加容器内的环境变量。  
+`-v {local_dir}:/usr/local/etc/workspace/project`表示把本地local_dir目录挂载至容器内的`/usr/local/etc/workspace/project`目录，容器内目录为固定值，不可修改。
+
+### 使用多个容器挂载相同目录时，有以下几点建议：
+由于多个容器在相同的挂载目录进行文件的读写，有几处设置可以优化并发读写的冲突：
+1. 当您使用本地Sqlite库时，sqlite的本地数据库文件默认保存在项目主目录下，因此所有容器会读写同一个数据库文件，可能引发并发问题。建议在config.toml中指定一个非挂载路径 `/usr/local/etc/workspace/project`下的sqlite数据库文件地址，如容器内的`/usr/local/etc`下，例如
+    ```toml
+    mysql_uri = 'sqlite:////usr/local/etc/agent_universe.db'
+    ```
+    或者也可以使用mysql，避免在本地进行数据库文件的读写。
+2. 日志文件输出的默认路径是在项目工程的主目录，也就是挂载目录中，因此推荐在log_config.toml中指定一个非挂载路径下的目录，如
+    ```toml
+    log_path = "/usr/local/etc/au_log"
+    ```
+    这样可以避免所有容器日志打印在同一个文件中导致难以阅读。
+3. 上述命令的端口映射部分`8888:8888`需要将后面的8888修改为不同端口，否则会发生端口冲突  
+
+## 方法二：从Github拉取项目
+镜像中已安装git命令，您可以通过修改镜像的entrypoint，git clone您的项目后将整个工程复制到指定路径，示例命令：
+```shell
+docker run -d -p 8888:8888 --entrypoint=/bin/bash registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta -c "git clone {repo_addr}; mv {project_dir} /usr/local/etc/workspace/project; /bin/bash --login /usr/local/etc/workspace/shell/start.sh"
+````
+
+其中`repo_addr`是你的git项目地址，`project_dir`是工程路径，比如`sample_standard_app`在你git项目下的`project`目录，那么`project_dir`就是`project/sample_standard_app`。
+## 结果验证
+以该示例中的8888端口为例，您可以通过curl命令验证服务是否正确启动
+```shell
+curl http://127.0.0.1:8888/echo
+```
+来尝试访问web服务，如返回Welcome字样则说明服务已启动成功。
diff --git a/pyproject.toml b/pyproject.toml
index ee8917f8..b58b3854 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,9 +1,23 @@
 [tool.poetry]
 name = "agentUniverse"
-version = "0.0.5"
+version = "0.0.6_beta"
 description = "agentUniverse is a framework for developing applications powered by multi-agent base on large language model."
-authors = ["AntGroup <AntGroup>"]
-readme = "README.md"
+
+authors = ["AntGroup <jerry.zzw@antgroup.com>"]
+repository = "https://github.com/alipay/agentUniverse"
+readme = "README_PYPI.md"
+
+packages = [
+    { include = "agentuniverse" },
+    { include = "agentuniverse_connector" },
+    { include = "agentuniverse_extension" },
+]
+include = ["*.yaml"]
+classifiers = [
+    "Programming Language :: Python :: 3.10",
+    "License :: OSI Approved :: Apache Software License",
+    "Operating System :: OS Independent",
+]
 
 [tool.poetry.dependencies]
 python = "^3.10"
@@ -20,6 +34,7 @@ flask_cors = '4.0.0'
 SQLAlchemy = '2.0.25'
 pydantic = "^2.6.4"
 gunicorn = "21.2.0"
+grpcio = "1.63.0"
 chromadb = "0.4.24"
 sphinx = "^7.2.6"
 sphinx-rtd-theme = "^2.0.0"
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 23a67452..00000000
--- a/requirements.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-requests>=2.31.0
-cffi>=1.15.1
-flask>=2.2
-werkzeug>=2.2.2
-langchain>=0.0.352
-langchain-core>=0.1.3
-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
-chromadb>=0.4.24
-aliyun-log-python-sdk>=0.8.8
-googleapis-common-protos>=1.63.0
-myst-parser>=2.0.0
-pdfminer.six
\ No newline at end of file
diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml
index c2fd4f11..b5189daf 100644
--- a/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml
+++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml
@@ -5,7 +5,7 @@ profile:
   prompt_version: demo_expressing_agent.cn
   llm_model:
     name: demo_llm
-    model_name: gpt-4-turbo
+    model_name: gpt-4o
     temperature: 0.2
     prompt_processor:
       type: stuff
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 365e7065..b3f5f39a 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
@@ -5,7 +5,7 @@ profile:
   prompt_version: demo_planning_agent.cn
   llm_model:
     name: 'demo_llm'
-    model_name: 'gpt-4'
+    model_name: 'gpt-4o'
     temperature: 0.5
 plan:
   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 bb8be0f4..6841d584 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
@@ -22,7 +22,7 @@ profile:
     需要回答的问题是: {input}
   llm_model:
     name: 'demo_llm'
-    model_name: 'gpt-4-turbo'
+    model_name: 'gpt-4o'
 plan:
   planner:
     name: 'rag_planner'
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 b2560fa1..38179542 100644
--- a/sample_standard_app/app/core/prompt/planning_agent_cn.yaml
+++ b/sample_standard_app/app/core/prompt/planning_agent_cn.yaml
@@ -15,7 +15,7 @@ instruction: |
   开始!
   今天的日期是: {date}
 
-  输出必须是按照以下格式化的Json代码片段，thought字段代表拆解问题的思考过程，framework字段代表拆解后的子问题列表。
+  输出必须是按照以下格式化的Json代码片段，不加额外的json标识，thought字段代表拆解问题的思考过程，framework字段代表拆解后的子问题列表。
   {{
       "thought": string,
       "framework": list
diff --git a/sample_standard_app/examples/__init__.py b/sample_standard_app/app/examples/__init__.py
similarity index 100%
rename from sample_standard_app/examples/__init__.py
rename to sample_standard_app/app/examples/__init__.py
diff --git a/sample_standard_app/examples/peer_chat_bot.py b/sample_standard_app/app/examples/peer_chat_bot.py
similarity index 91%
rename from sample_standard_app/examples/peer_chat_bot.py
rename to sample_standard_app/app/examples/peer_chat_bot.py
index ed25834a..a80ea228 100644
--- a/sample_standard_app/examples/peer_chat_bot.py
+++ b/sample_standard_app/app/examples/peer_chat_bot.py
@@ -9,7 +9,7 @@
 from agentuniverse.agent.agent import Agent
 from agentuniverse.agent.agent_manager import AgentManager
 
-AgentUniverse().start(config_path='../config/config.toml')
+AgentUniverse().start(config_path='../../config/config.toml')
 
 
 def chat(question: str):
diff --git a/sample_standard_app/examples/rag_chat_bot.py b/sample_standard_app/app/examples/rag_chat_bot.py
similarity index 93%
rename from sample_standard_app/examples/rag_chat_bot.py
rename to sample_standard_app/app/examples/rag_chat_bot.py
index 4b0906e4..15d0ebd6 100644
--- a/sample_standard_app/examples/rag_chat_bot.py
+++ b/sample_standard_app/app/examples/rag_chat_bot.py
@@ -10,7 +10,7 @@
 from agentuniverse.agent.agent_manager import AgentManager
 from agentuniverse.base.agentuniverse import AgentUniverse
 
-AgentUniverse().start(config_path='../config/config.toml')
+AgentUniverse().start(config_path='../../config/config.toml')
 
 
 def chat(question: str):
diff --git a/sample_standard_app/config/config.toml b/sample_standard_app/config/config.toml
index ca5b7150..4c3f0c9f 100644
--- a/sample_standard_app/config/config.toml
+++ b/sample_standard_app/config/config.toml
@@ -32,4 +32,9 @@ gunicorn_config_path = './gunicorn_config.toml'
 
 [DB]
 # A mysql db uri used to save web request task status. Status will be saved in sqllite if the uri is empty all not exist.
-mysql_uri = ''
\ No newline at end of file
+mysql_uri = ''
+
+[GRPC]
+activate = 'true'
+max_workers = 10
+server_port = 50051
\ No newline at end of file
diff --git a/sample_standard_app/poetry.lock b/sample_standard_app/poetry.lock
index bdcdd7c5..810a95c9 100644
--- a/sample_standard_app/poetry.lock
+++ b/sample_standard_app/poetry.lock
@@ -2,13 +2,12 @@
 
 [[package]]
 name = "agentuniverse"
-version = "0.0.3"
+version = "0.0.5"
 description = "agentUniverse is a framework for developing applications powered by multi-agent base on large language model."
 optional = false
 python-versions = "*"
 files = [
-    {file = "agentUniverse-0.0.3-py3-none-any.whl", hash = "sha256:c8a7e9f83ad8e5c3a774fcb5993bea88a60a1e1bfa4ee6990b55dd6869ad533f"},
-    {file = "agentUniverse-0.0.3.tar.gz", hash = "sha256:b7584e4aa1037fda6f83a03b7e3a9d971f93053a9799b6247d179baa994f3335"},
+
 ]
 
 [package.dependencies]
diff --git a/sample_standard_app/pyproject.toml b/sample_standard_app/pyproject.toml
index af94f146..7b763d8d 100644
--- a/sample_standard_app/pyproject.toml
+++ b/sample_standard_app/pyproject.toml
@@ -3,7 +3,7 @@ name = "sample_standard_app"
 version = "0.0.1"
 description = "This is a sample project for agentuniverse."
 authors = ["AntGroup <AntGroup>"]
-#repository = "https://github.com/alipay/agentUniverse/tree/master/sample_standard_app"
+repository = "https://github.com/alipay/agentUniverse/tree/master/sample_standard_app"
 readme = "README.md"
 packages = [
     { include = "sample_standard_app" }
@@ -11,7 +11,7 @@ packages = [
 
 [tool.poetry.dependencies]
 python = "^3.10"
-agentUniverse = "^0.0.3"
+agentUniverse = "^0.0.5"
 
 [tool.poetry.group.dev.dependencies]
 pytest = "^7.2.0"
diff --git a/setup.py b/setup.py
deleted file mode 100644
index ffe538a5..00000000
--- a/setup.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# !/usr/bin/env python3
-# -*- coding:utf-8 -*-
-
-# @Time    : 2024/4/8 16:17
-# @Author  : jerry.zzw 
-# @Email   : jerry.zzw@antgroup.com
-# @FileName: setup.py
-
-import setuptools
-
-with open("README_PYPI.md", "r") as fh:
-    long_description = fh.read()
-
-
-def read_requirements():
-    with open('requirements.txt', 'r') as req:
-        content = req.read()
-        requirements = content.split('\n')
-
-    return requirements
-
-
-setuptools.setup(
-    name="agentUniverse",
-    version="0.0.5",
-    author="AntGroup",
-    author_email="jerry.zzw@antgroup.com",
-    description="agentUniverse is a framework for developing applications powered "
-                "by multi-agent base on large language model.",
-    long_description=long_description,
-    long_description_content_type="text/markdown",
-    url="https://gitee.com/agentUniverse/agentUniverse",
-    packages=setuptools.find_packages(exclude=["*sample_standard_app*", "*docs*", "*tests*"]),
-    package_data={
-            '': ['*.yaml'],
-        },
-    install_requires=read_requirements(),
-    classifiers=[
-        'Programming Language :: Python :: 3.10',
-        "License :: OSI Approved :: Apache Software License",
-        "Operating System :: OS Independent",
-    ],
-)


Test patch:
diff --git a/sample_standard_app/app/test/test_grpc_server.py b/sample_standard_app/app/test/test_grpc_server.py
new file mode 100644
index 00000000..dcc06695
--- /dev/null
+++ b/sample_standard_app/app/test/test_grpc_server.py
@@ -0,0 +1,30 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/11 14:58
+# @Author  : fanen.lhy
+# @Email   : fanen.lhy@antgroup.com
+# @FileName: test_grpc_server.py.py
+import grpc
+from agentuniverse.agent_serve.web.rpc.grpc import agentuniverse_service_pb2, \
+    agentuniverse_service_pb2_grpc
+
+
+# Start you server_application first.
+def test_run():
+    with grpc.insecure_channel('localhost:50051') as channel:
+        stub = agentuniverse_service_pb2_grpc.AgentUniverseServiceStub(channel)
+        response = stub.service_run(agentuniverse_service_pb2.AgentServiceRequest(
+            service_id='demo_service',
+            params='{"input":"(18+3-5)/2*4=?"}',
+            saved=True
+        ))
+        print("client received: " + response.request_id)
+
+        response = stub.service_run_result(agentuniverse_service_pb2.AgentResultRequest(
+            request_id=response.request_id
+        ))
+        print("client received: " + response.result)
+
+if __name__ == '__main__':
+    test_run()
\ No newline at end of file
diff --git a/tests/test_agentuniverse/unit/llm/test_llm.py b/tests/test_agentuniverse/unit/llm/test_llm.py
index 61e96c1d..4d2fa99e 100644
--- a/tests/test_agentuniverse/unit/llm/test_llm.py
+++ b/tests/test_agentuniverse/unit/llm/test_llm.py
@@ -18,7 +18,7 @@ class LLMTest(unittest.TestCase):
     """
 
     def setUp(self) -> None:
-        self.llm = OpenAILLM(model_name='gpt-4')
+        self.llm = OpenAILLM(model_name='gpt-4o')
 
     def test_call(self) -> None:
         messages = [
@@ -27,7 +27,7 @@ def test_call(self) -> None:
                 "content": "hi, please introduce yourself",
             }
         ]
-        output = self.llm.call(messages=messages,streaming=False)
+        output = self.llm.call(messages=messages, streaming=False)
         print(output.__str__())
 
     def test_acall(self) -> None:
@@ -37,7 +37,7 @@ def test_acall(self) -> None:
                 "content": "hi, please introduce yourself",
             }
         ]
-        output = asyncio.run(self.llm.acall(messages=messages,streaming=False))
+        output = asyncio.run(self.llm.acall(messages=messages, streaming=False))
         print(output.__str__())
 
     def test_call_stream(self):
@@ -74,6 +74,22 @@ def test_as_langchain(self):
         res = llm_chain.predict(input='hello')
         print(res)
 
+    def test_gpt_4o_image(self):
+        response = self.llm.call(
+            messages=[
+                {"role": "system",
+                 "content": "You are a helpful assistant that responds in Markdown. Help me with my math homework!"},
+                {"role": "user", "content": [
+                    {"type": "text", "text": "What's the area of the triangle?"},
+                    {"type": "image_url", "image_url": {
+                        "url": "https://upload.wikimedia.org/wikipedia/commons/e/e2/The_Algebra_of_Mohammed_Ben_Musa_-_page_82b.png"}
+                     }
+                ]}
+            ],
+            temperature=0.0,
+        )
+        print(response.__str__())
+
 
 if __name__ == '__main__':
     unittest.main()