diff --git a/config.py b/config.py
index cdce26f..85c5436 100644
--- a/config.py
+++ b/config.py
@@ -25,7 +25,7 @@ available_setting = {
     "single_chat_reply_suffix": "",  # 私聊时自动回复的后缀,\n 可以换行    
     "group_chat_prefix": ["@bot"],  # 群聊时包含该前缀则会触发机器人回复 
     "group_chat_reply_prefix": "",  # 群聊时自动回复的前缀
-    "group_chat_reply_suffix": "",   # 群聊时自动回复的后缀,\n 可以换行
+    "group_chat_reply_suffix": "",  # 群聊时自动回复的后缀,\n 可以换行
     "group_chat_keyword": [],  # 群聊时包含该关键词则会触发机器人回复
     "group_at_off": False,  # 是否关闭群聊时@bot的触发
     "group_name_white_list": ["ChatGPT测试群", "ChatGPT测试群2"],  # 开启自动回复的群名称列表
@@ -37,7 +37,8 @@ available_setting = {
     "image_create_size": "256x256",  # 图片大小,可选有 256x256, 512x512, 1024x1024
     # chatgpt会话参数
     "expires_in_seconds": 3600,  # 无操作会话的过期时间
-    "character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。",  # 人格描述
+    # 人格描述
+    "character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。",
     "conversation_max_tokens": 1000,  # 支持上下文记忆的最多字符数
     # chatgpt限流配置
     "rate_limit_chatgpt": 20,  # chatgpt的调用频率限制
@@ -228,3 +229,26 @@ def subscribe_msg():
     trigger_prefix = conf().get("single_chat_prefix", [""])[0]
     msg = conf().get("subscribe_msg", "")
     return msg.format(trigger_prefix=trigger_prefix)
+
+
+# global plugin config
+plugin_config = {}
+
+
+def write_plugin_config(pconf: dict):
+    """
+    写入插件全局配置
+    :param pconf: 全量插件配置
+    """
+    global plugin_config
+    for k in pconf:
+        plugin_config[k.lower()] = pconf[k]
+
+
+def pconf(plugin_name: str) -> dict:
+    """
+    根据插件名称获取配置
+    :param plugin_name: 插件名称
+    :return: 该插件的配置项
+    """
+    return plugin_config.get(plugin_name.lower())
diff --git a/plugins/banwords/banwords.py b/plugins/banwords/banwords.py
index 118b963..2a33a5a 100644
--- a/plugins/banwords/banwords.py
+++ b/plugins/banwords/banwords.py
@@ -24,16 +24,17 @@ class Banwords(Plugin):
     def __init__(self):
         super().__init__()
         try:
+            # load config
+            conf = super().load_config()
             curdir = os.path.dirname(__file__)
-            config_path = os.path.join(curdir, "config.json")
-            conf = None
-            if not os.path.exists(config_path):
-                conf = {"action": "ignore"}
-                with open(config_path, "w") as f:
-                    json.dump(conf, f, indent=4)
-            else:
-                with open(config_path, "r") as f:
-                    conf = json.load(f)
+            if not conf:
+                # 配置不存在则写入默认配置
+                config_path = os.path.join(curdir, "config.json")
+                if not os.path.exists(config_path):
+                    conf = {"action": "ignore"}
+                    with open(config_path, "w") as f:
+                        json.dump(conf, f, indent=4)
+
             self.searchr = WordsSearch()
             self.action = conf["action"]
             banwords_path = os.path.join(curdir, "banwords.txt")
diff --git a/plugins/bdunit/bdunit.py b/plugins/bdunit/bdunit.py
index e41e8d2..33194e3 100644
--- a/plugins/bdunit/bdunit.py
+++ b/plugins/bdunit/bdunit.py
@@ -29,14 +29,9 @@ class BDunit(Plugin):
     def __init__(self):
         super().__init__()
         try:
-            curdir = os.path.dirname(__file__)
-            config_path = os.path.join(curdir, "config.json")
-            conf = None
-            if not os.path.exists(config_path):
+            conf = super().load_config()
+            if not conf:
                 raise Exception("config.json not found")
-            else:
-                with open(config_path, "r") as f:
-                    conf = json.load(f)
             self.service_id = conf["service_id"]
             self.api_key = conf["api_key"]
             self.secret_key = conf["secret_key"]
diff --git a/plugins/config.json.template b/plugins/config.json.template
new file mode 100644
index 0000000..5c2b19b
--- /dev/null
+++ b/plugins/config.json.template
@@ -0,0 +1,24 @@
+{
+    "godcmd": {
+        "password": "",
+        "admin_users": []
+    },
+    "banwords": {
+        "action": "replace",
+        "reply_filter": true,
+        "reply_action": "ignore"
+    },
+    "tool": {
+        "tools": [
+            "python",
+            "url-get",
+            "terminal",
+            "meteo-weather"
+        ],
+        "kwargs": {
+            "top_k_results": 2,
+            "no_default": false,
+            "model_name": "gpt-3.5-turbo"
+        }
+    }
+}
diff --git a/plugins/godcmd/godcmd.py b/plugins/godcmd/godcmd.py
index 2ce370f..08bc09e 100644
--- a/plugins/godcmd/godcmd.py
+++ b/plugins/godcmd/godcmd.py
@@ -178,16 +178,13 @@ class Godcmd(Plugin):
     def __init__(self):
         super().__init__()
 
-        curdir = os.path.dirname(__file__)
-        config_path = os.path.join(curdir, "config.json")
-        gconf = None
-        if not os.path.exists(config_path):
-            gconf = {"password": "", "admin_users": []}
-            with open(config_path, "w") as f:
-                json.dump(gconf, f, indent=4)
-        else:
-            with open(config_path, "r") as f:
-                gconf = json.load(f)
+        config_path = os.path.join(os.path.dirname(__file__), "config.json")
+        gconf = super().load_config()
+        if not gconf:
+            if not os.path.exists(config_path):
+                gconf = {"password": "", "admin_users": []}
+                with open(config_path, "w") as f:
+                    json.dump(gconf, f, indent=4)
         if gconf["password"] == "":
             self.temp_password = "".join(random.sample(string.digits, 4))
             logger.info("[Godcmd] 因未设置口令,本次的临时口令为%s。" % self.temp_password)
diff --git a/plugins/plugin.py b/plugins/plugin.py
index 6c82c8d..e7444d2 100644
--- a/plugins/plugin.py
+++ b/plugins/plugin.py
@@ -1,6 +1,28 @@
+import os
+import json
+from config import pconf
+from common.log import logger
+
+
 class Plugin:
     def __init__(self):
         self.handlers = {}
 
+    def load_config(self) -> dict:
+        """
+        加载当前插件配置
+        :return: 插件配置字典
+        """
+        # 优先获取 plugins/config.json 中的全局配置
+        plugin_conf = pconf(self.name)
+        if not plugin_conf:
+            # 全局配置不存在,则获取插件目录下的配置
+            plugin_config_path = os.path.join(self.path, "config.json")
+            if os.path.exists(plugin_config_path):
+                with open(plugin_config_path, "r") as f:
+                    plugin_conf = json.load(f)
+        logger.debug(f"loading plugin config, plugin_name={self.name}, conf={plugin_conf}")
+        return plugin_conf
+
     def get_help_text(self, **kwargs):
         return "暂无帮助信息"
diff --git a/plugins/plugin_manager.py b/plugins/plugin_manager.py
index 2696954..49c13ca 100644
--- a/plugins/plugin_manager.py
+++ b/plugins/plugin_manager.py
@@ -9,7 +9,7 @@ import sys
 from common.log import logger
 from common.singleton import singleton
 from common.sorted_dict import SortedDict
-from config import conf
+from config import conf, write_plugin_config
 
 from .event import *
 
@@ -62,6 +62,28 @@ class PluginManager:
             self.save_config()
         return pconf
 
+    @staticmethod
+    def _load_all_config():
+        """
+        背景: 目前插件配置存放于每个插件目录的config.json下,docker运行时不方便进行映射,故增加统一管理的入口,优先
+        加载 plugins/config.json,原插件目录下的config.json 不受影响
+
+        从 plugins/config.json 中加载所有插件的配置并写入 config.py 的全局配置中,供插件中使用
+        插件实例中通过 config.pconf(plugin_name) 即可获取该插件的配置
+        """
+        all_config_path = "./plugins/config.json"
+        try:
+            if os.path.exists(all_config_path):
+                # read from all plugins config
+                with open(all_config_path, "r", encoding="utf-8") as f:
+                    all_conf = json.load(f)
+                    logger.info(f"load all config from plugins/config.json: {all_conf}")
+
+                # write to global config
+                write_plugin_config(all_conf)
+        except Exception as e:
+            logger.error(e)
+
     def scan_plugins(self):
         logger.info("Scaning plugins ...")
         plugins_dir = "./plugins"
@@ -88,7 +110,7 @@ class PluginManager:
                             self.loaded[plugin_path] = importlib.import_module(import_path)
                         self.current_plugin_path = None
                     except Exception as e:
-                        logger.exception("Failed to import plugin %s: %s" % (plugin_name, e))
+                        logger.warn("Failed to import plugin %s: %s" % (plugin_name, e))
                         continue
         pconf = self.pconf
         news = [self.plugins[name] for name in self.plugins]
@@ -123,7 +145,7 @@ class PluginManager:
                     try:
                         instance = plugincls()
                     except Exception as e:
-                        logger.exception("Failed to init %s, diabled. %s" % (name, e))
+                        logger.warn("Failed to init %s, diabled. %s" % (name, e))
                         self.disable_plugin(name)
                         failed_plugins.append(name)
                         continue
@@ -149,6 +171,8 @@ class PluginManager:
     def load_plugins(self):
         self.load_config()
         self.scan_plugins()
+        # 加载全量插件配置
+        self._load_all_config()
         pconf = self.pconf
         logger.debug("plugins.json config={}".format(pconf))
         for name, plugin in pconf["plugins"].items():
diff --git a/plugins/tool/tool.py b/plugins/tool/tool.py
index 1c3b13d..b99eabb 100644
--- a/plugins/tool/tool.py
+++ b/plugins/tool/tool.py
@@ -10,7 +10,6 @@ from bridge.bridge import Bridge
 from bridge.context import ContextType
 from bridge.reply import Reply, ReplyType
 from common import const
-from common.log import logger
 from config import conf
 from plugins import *
 
@@ -119,15 +118,8 @@ class Tool(Plugin):
         return
 
     def _read_json(self) -> dict:
-        curdir = os.path.dirname(__file__)
-        config_path = os.path.join(curdir, "config.json")
-        tool_config = {"tools": [], "kwargs": {}}
-        if not os.path.exists(config_path):
-            return tool_config
-        else:
-            with open(config_path, "r") as f:
-                tool_config = json.load(f)
-        return tool_config
+        default_config = {"tools": [], "kwargs": {}}
+        return super().load_config() or default_config
 
     def _build_tool_kwargs(self, kwargs: dict):
         tool_model_name = kwargs.get("model_name")