Repository: antgroup/agentUniverse (language: python)

Issue:
add keys information



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7ec09f51..6d663bf4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,22 @@ Note - Additional remarks regarding the version.
 ***************************************************
 
 # Version Update History
+## [0.0.10] - 2024-06-28
+### Added
+- Added standard integration for the DeepSeek model in the LLM module.
+- Added a new OpenAI general protocol wrapper class, OpenAIStyleLLM.
+  - Models using the OpenAI protocol can be configured directly.
+- Added a new LangChain tool wrapper class, LangChainTool, with several example tools for search and execution.
+  - LangChain tools can be configured directly.
+- Added Agent information collection capability in the monitor module.
+
+### Note
+- Added use cases.
+  - Supplemented documentation with a financial event analysis case study using PEER collaborative mode.
+- Added several new documents for LLM components, tool components, and the Monitor module.
+- Updated the new README.
+- Some code optimizations and documentation updates.
+
 ## [0.0.9] - 2024-06-14
 ### Added
 - Added standard integration for Claude and Ollama LLM components
diff --git a/CHANGELOG_zh.md b/CHANGELOG_zh.md
index 600479be..c8fc95c9 100644
--- a/CHANGELOG_zh.md
+++ b/CHANGELOG_zh.md
@@ -24,6 +24,22 @@ Note - 对于版本的额外说明。
 ***************************************************
 
 # 版本更新记录
+## [0.0.10] - 2024-06-28
+### Added
+- LLM组件新增DeepSeek模型标准接入
+- 新增OpenAI通用协议包装类OpenAIStyleLLM
+  - openai协议类模型接入可直接配置
+- 新增LangChain工具包装类LangChainTool，新增搜索类、执行类示例工具若干
+  - LangChain工具接入可直接配置
+- monitor模块新增Agent纬度信息采集能力
+
+### Note
+- 新增使用案例
+  - PEER协同模式的金融事件分析案例文档补充
+- 新增若干LLM组件、工具组件、Monitor模块文档
+- 新版README更新
+- 部分代码优化与文档更新
+
 ## [0.0.9] - 2024-06-14
 ### Added
 - LLM组件新增claude、ollama标准接入
diff --git a/README.md b/README.md
index babf44d5..23299e7b 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Language version: [English](./README.md) | [中文](./README_zh.md) | [日本語
 ![](https://img.shields.io/badge/framework-agentUniverse-pink)
 ![](https://img.shields.io/badge/python-3.10%2B-blue?logo=Python)
 [![](https://img.shields.io/badge/%20license-Apache--2.0-yellow)](LICENSE)
-[![Static Badge](https://img.shields.io/badge/pypi-v0.0.9-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
+[![Static Badge](https://img.shields.io/badge/pypi-v0.0.10-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
 
 ![](docs/guidebook/_picture/logo_bar.jpg)
 ****************************************
diff --git a/README_jp.md b/README_jp.md
index f7752ec7..1fd7c690 100644
--- a/README_jp.md
+++ b/README_jp.md
@@ -5,7 +5,7 @@
 ![](https://img.shields.io/badge/framework-agentUniverse-pink)
 ![](https://img.shields.io/badge/python-3.10%2B-blue?logo=Python)
 [![](https://img.shields.io/badge/%20license-Apache--2.0-yellow)](LICENSE)
-[![Static Badge](https://img.shields.io/badge/pypi-v0.0.9-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
+[![Static Badge](https://img.shields.io/badge/pypi-v0.0.10-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
 
 ![](docs/guidebook/_picture/logo_bar.jpg)
 ****************************************
diff --git a/README_zh.md b/README_zh.md
index 7a144ddf..bf096bbe 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -5,7 +5,7 @@
 ![](https://img.shields.io/badge/framework-agentUniverse-pink)
 ![](https://img.shields.io/badge/python-3.10%2B-blue?logo=Python)
 [![](https://img.shields.io/badge/%20license-Apache--2.0-yellow)](LICENSE)
-[![Static Badge](https://img.shields.io/badge/pypi-v0.0.9-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
+[![Static Badge](https://img.shields.io/badge/pypi-v0.0.10-blue?logo=pypi)](https://pypi.org/project/agentUniverse/)
 
 ![](docs/guidebook/_picture/logo_bar.jpg)
 ****************************************
diff --git a/agentuniverse/agent/action/knowledge/knowledge.py b/agentuniverse/agent/action/knowledge/knowledge.py
index f8e631a7..d6fc4920 100644
--- a/agentuniverse/agent/action/knowledge/knowledge.py
+++ b/agentuniverse/agent/action/knowledge/knowledge.py
@@ -5,7 +5,10 @@
 # @Author  : wangchongshi
 # @Email   : wangchongshi.wcs@antgroup.com
 # @FileName: knowledge.py
-from typing import Optional, Dict, List, Any
+from typing import Optional, Dict, List
+
+from langchain_core.utils.json import parse_json_markdown
+from langchain.tools import Tool as LangchainTool
 
 from agentuniverse.agent.action.knowledge.reader.reader import Reader
 from agentuniverse.agent.action.knowledge.store.document import Document
@@ -77,3 +80,37 @@ def initialize_by_component_configer(self, component_configer: KnowledgeConfiger
         if component_configer.ext_info:
             self.ext_info = component_configer.ext_info
         return self
+
+    def langchain_query(self, query: str) -> str:
+        """Query the knowledge using LangChain.
+
+        Query documents from the store and return the results.
+        """
+        parse_query = parse_json_markdown(query)
+        query = Query(**parse_query)
+        knowledge = self.store.query(query)
+        res = ['This is Query Result']
+        for doc in knowledge:
+            res.append(doc.text)
+        return "\n=========================================\n".join(res)
+
+    def as_langchain_tool(self) -> LangchainTool:
+        """Convert the Knowledge object to a LangChain tool.
+
+        Returns:
+            Any: the LangChain tool object
+        """
+        args_description = """
+        This is a knowledge base tool, which stores the content you may need. To use this tool, you need to give a json string with the following format:
+        ```json
+        {
+            "query_str": "<your query here>",
+            "top_k": <number of results to return>,
+        }
+        ```
+        """
+        return LangchainTool(
+            name=self.name,
+            description=self.description + args_description,
+            func=self.langchain_query,
+        )
diff --git a/agentuniverse/agent/action/knowledge/store/chroma_store.py b/agentuniverse/agent/action/knowledge/store/chroma_store.py
index dcb67a6a..d389150a 100644
--- a/agentuniverse/agent/action/knowledge/store/chroma_store.py
+++ b/agentuniverse/agent/action/knowledge/store/chroma_store.py
@@ -6,10 +6,11 @@
 # @Email   : wangchongshi.wcs@antgroup.com
 # @FileName: chroma_store.py
 from typing import List, Any, Optional
+from pydantic import SkipValidation
 
 import chromadb
 from chromadb import QueryResult
-from chromadb.api.models import Collection
+from chromadb.api.models.Collection import Collection
 
 from agentuniverse.agent.action.knowledge.store.document import Document
 from agentuniverse.agent.action.knowledge.store.query import Query
@@ -28,7 +29,7 @@ class ChromaStore(Store):
     """
 
     collection_name: Optional[str] = 'chroma_db'
-    collection: Collection = None
+    collection: SkipValidation[Collection] = None
     persist_path: Optional[str] = None
 
     def __init__(self, **kwargs):
diff --git a/agentuniverse/agent/agent.py b/agentuniverse/agent/agent.py
index 2f4099fc..d6fe3034 100644
--- a/agentuniverse/agent/agent.py
+++ b/agentuniverse/agent/agent.py
@@ -6,21 +6,26 @@
 # @Email   : lc299034@antgroup.com
 # @FileName: agent.py
 """The definition of agent paradigm."""
+import json
 from abc import abstractmethod
 from datetime import datetime
 from typing import Optional
 
+from langchain_core.utils.json import parse_json_markdown
+
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
 from agentuniverse.agent.output_object import OutputObject
 from agentuniverse.agent.plan.planner.planner import Planner
 from agentuniverse.agent.plan.planner.planner_manager import PlannerManager
+from agentuniverse.base.annotation.trace import trace_agent
 from agentuniverse.base.component.component_base import ComponentBase
 from agentuniverse.base.component.component_enum import ComponentEnum
 from agentuniverse.base.config.application_configer.application_config_manager \
     import ApplicationConfigManager
 from agentuniverse.base.config.component_configer.configers.agent_configer \
     import AgentConfiger
+from agentuniverse.base.util.logging.logging_util import LOGGER
 from agentuniverse.llm.llm import LLM
 
 
@@ -66,6 +71,7 @@ def parse_result(self, planner_result: dict) -> dict:
         """
         pass
 
+    @trace_agent
     def run(self, **kwargs) -> OutputObject:
         """Agent instance running entry.
 
@@ -156,3 +162,35 @@ def initialize_by_component_configer(self, component_configer: AgentConfiger) ->
                                                        plan=plan, memory=memory, action=action)
         self.agent_model = agent_model
         return self
+
+    def langchain_run(self, input: str, callbacks=None, **kwargs):
+        """Run the agent model using LangChain."""
+        try:
+            parse_result = parse_json_markdown(input)
+        except Exception as e:
+            LOGGER.error(f"langchain run parse_json_markdown error,input(parse_result) error({str(e)})")
+            return "Error , Your Action Input is not a valid JSON string"
+        output_object = self.run(**parse_result, callbacks=callbacks, **kwargs)
+        result_dict = {}
+        for key in self.output_keys():
+            result_dict[key] = output_object.get_data(key)
+        return result_dict
+
+    def as_langchain_tool(self):
+        """Convert to LangChain tool."""
+        from langchain.agents.tools import Tool
+        format_dict = {}
+        for key in self.input_keys():
+            format_dict.setdefault(key, "input val")
+        format_str = json.dumps(format_dict)
+
+        args_description = f"""
+        to use this tool,your input must be a json string,must contain all keys of {self.input_keys()},
+        and the value of the key must be a json string,the format of the json string is as follows:
+        ```{format_str}```
+        """
+        return Tool(
+            name=self.agent_model.info.get("name"),
+            func=self.langchain_run,
+            description=self.agent_model.info.get("description") + args_description
+        )
diff --git a/agentuniverse/agent/default/executing_agent/executing_agent.py b/agentuniverse/agent/default/executing_agent/executing_agent.py
index 94e4143d..63ac6a44 100644
--- a/agentuniverse/agent/default/executing_agent/executing_agent.py
+++ b/agentuniverse/agent/default/executing_agent/executing_agent.py
@@ -8,8 +8,11 @@
 import copy
 from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
 from typing import Optional, Any
+
+from agentuniverse.agent.action.tool.tool_manager import ToolManager
 from agentuniverse.agent.agent import Agent
 from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.plan.planner.planner import Planner
 from agentuniverse.agent.plan.planner.planner_manager import PlannerManager
 
 
@@ -75,9 +78,35 @@ def execute(self, input_object: InputObject, agent_input: dict) -> dict:
         for task in framework:
             agent_input_copy: dict = copy.deepcopy(agent_input)
             agent_input_copy['input'] = task
+            planner: Planner = PlannerManager().get_instance_obj(self.agent_model.plan.get('planner').get('name'))
             futures.append(
-                self.executor.submit(
-                    PlannerManager().get_instance_obj(self.agent_model.plan.get('planner').get('name')).invoke,
-                    self.agent_model, agent_input_copy, input_object))
+                self.executor.submit(planner.invoke, self.agent_model, agent_input_copy,
+                                     self.process_intput_object(input_object, task, planner.input_key)))
         wait(futures, return_when=ALL_COMPLETED)
         return {'futures': futures}
+
+    def process_intput_object(self, input_object: InputObject, subtask: str, planner_input_key: str) -> InputObject:
+        """Process input object for the executing agent.
+
+        Args:
+            input_object (InputObject): input parameters passed by the user.
+            subtask (str): subtask to be executed.
+            planner_input_key (str): planner input key.
+
+        Returns:
+            input_object (InputObject): processed input object.
+        """
+        # get agent toolsets.
+        action: dict = self.agent_model.action or dict()
+        tools: list = action.get('tool') or list()
+        input_object_copy: InputObject = copy.deepcopy(input_object)
+        # wrap input_object for agent knowledge.
+        input_object_copy.add_data(planner_input_key, subtask)
+        # wrap input_object for agent toolsets.
+        for tool_name in tools:
+            tool = ToolManager().get_instance_obj(tool_name)
+            if tool is None:
+                continue
+            # note: only insert the first key of tool input.
+            input_object_copy.add_data(tool.input_keys[0], subtask)
+        return input_object_copy
diff --git a/agentuniverse/agent/memory/langchain_instance.py b/agentuniverse/agent/memory/langchain_instance.py
index bbbe5258..4b3936c6 100644
--- a/agentuniverse/agent/memory/langchain_instance.py
+++ b/agentuniverse/agent/memory/langchain_instance.py
@@ -9,6 +9,7 @@
 
 from langchain_core.messages import BaseMessage, get_buffer_string
 from langchain.memory import ConversationSummaryBufferMemory, ConversationTokenBufferMemory
+from langchain_core.output_parsers import StrOutputParser
 
 from agentuniverse.agent.memory.enum import ChatMessageEnum
 from agentuniverse.agent.memory.message import Message
@@ -115,9 +116,8 @@ def predict_new_summary(
         )
         prompt_version = self.prompt_version if self.prompt_version else 'chat_memory.summarizer_cn'
         prompt: Prompt = PromptManager().get_instance_obj(prompt_version)
-        chain = prompt.as_langchain() | self.llm
-        res = chain.invoke(input={'summary': existing_summary, 'new_lines': new_lines})
-        return res.content
+        chain = prompt.as_langchain() | self.llm | StrOutputParser()
+        return chain.invoke(input={'summary': existing_summary, 'new_lines': new_lines})
 
 
 class AuConversationTokenBufferMemory(ConversationTokenBufferMemory):
diff --git a/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py b/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py
index a25fb3bc..e552a876 100644
--- a/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py
+++ b/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py
@@ -146,7 +146,7 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu
 
             if not expressing_result or jump_step in ["planning", "executing", "expressing"]:
                 if not expressingAgent:
-                    LOGGER.warn("no expression agent.")
+                    LOGGER.warn("no expressing agent.")
                     expressing_result = OutputObject({})
                 else:
                     LOGGER.info(f"Starting expressing agent.")
@@ -160,7 +160,7 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu
 
             if not reviewing_result or jump_step in ["planning", "executing", "expressing", "reviewing"]:
                 if not reviewingAgent:
-                    LOGGER.warn("no expression agent.")
+                    LOGGER.warn("no reviewing agent.")
                     loopResults.append({
                         "planning_result": planning_result,
                         "executing_result": executing_result,
diff --git a/agentuniverse/agent/plan/planner/react_planner/react_planner.py b/agentuniverse/agent/plan/planner/react_planner/react_planner.py
index ef1f76f9..b3f20211 100644
--- a/agentuniverse/agent/plan/planner/react_planner/react_planner.py
+++ b/agentuniverse/agent/plan/planner/react_planner/react_planner.py
@@ -11,8 +11,12 @@
 from langchain.tools import Tool as LangchainTool
 from langchain_core.runnables import RunnableConfig
 
+from agentuniverse.agent.action.knowledge.knowledge import Knowledge
+from agentuniverse.agent.action.knowledge.knowledge_manager import KnowledgeManager
 from agentuniverse.agent.action.tool.tool import Tool
 from agentuniverse.agent.action.tool.tool_manager import ToolManager
+from agentuniverse.agent.agent import Agent
+from agentuniverse.agent.agent_manager import AgentManager
 from agentuniverse.agent.agent_model import AgentModel
 from agentuniverse.agent.input_object import InputObject
 from agentuniverse.agent.memory.chat_memory import ChatMemory
@@ -78,6 +82,15 @@ def acquire_tools(action) -> list[LangchainTool]:
         for tool_name in tool_names:
             tool: Tool = ToolManager().get_instance_obj(tool_name)
             lc_tools.append(tool.as_langchain())
+        knowledge: list = action.get('knowledge') or list()
+        for knowledge_name in knowledge:
+            knowledge_tool: Knowledge = KnowledgeManager().get_instance_obj(knowledge_name)
+            lc_tools.append(knowledge_tool.as_langchain_tool())
+
+        agents: list = action.get('agent') or list()
+        for agent_name in agents:
+            agent_tool: Agent = AgentManager().get_instance_obj(agent_name)
+            lc_tools.append(agent_tool.as_langchain_tool())
         return lc_tools
 
     def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt:
diff --git a/agentuniverse/base/annotation/trace.py b/agentuniverse/base/annotation/trace.py
index d3333edb..428856f1 100644
--- a/agentuniverse/base/annotation/trace.py
+++ b/agentuniverse/base/annotation/trace.py
@@ -8,14 +8,15 @@
 import asyncio
 import functools
 import inspect
+import json
 
 from functools import wraps
 
+from agentuniverse.agent.input_object import InputObject
+from agentuniverse.agent.output_object import OutputObject
 from agentuniverse.base.util.monitor.monitor import Monitor
 from agentuniverse.llm.llm_output import LLMOutput
 
-monitor = Monitor()
-
 
 def trace_llm(func):
     """Annotation: @trace_llm
@@ -37,7 +38,7 @@ async def wrapper_async(*args, **kwargs):
         # not streaming
         if isinstance(result, LLMOutput):
             # add llm invocation info to monitor
-            monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input, llm_output=result.text)
+            Monitor().trace_llm_invocation(source=func.__qualname__, llm_input=llm_input, llm_output=result.text)
             return result
         else:
             # streaming
@@ -47,8 +48,8 @@ async def gen_iterator():
                     llm_output.append(chunk.text)
                     yield chunk
                 # add llm invocation info to monitor
-                monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input,
-                                             llm_output="".join(llm_output))
+                Monitor().trace_llm_invocation(source=func.__qualname__, llm_input=llm_input,
+                                               llm_output="".join(llm_output))
 
             return gen_iterator()
 
@@ -59,14 +60,14 @@ def wrapper_sync(*args, **kwargs):
         # check whether the tracing switch is enabled
         self = llm_input.pop('self', None)
         if self and hasattr(self, 'tracing'):
-            if not self.tracing:
+            if self.tracing is False:
                 return func(*args, **kwargs)
         # invoke function
         result = func(*args, **kwargs)
         # not streaming
         if isinstance(result, LLMOutput):
             # add llm invocation info to monitor
-            monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input, llm_output=result.text)
+            Monitor().trace_llm_invocation(source=func.__qualname__, llm_input=llm_input, llm_output=result.text)
             return result
         else:
             # streaming
@@ -76,8 +77,8 @@ def gen_iterator():
                     llm_output.append(chunk.text)
                     yield chunk
                 # add llm invocation info to monitor
-                monitor.trace_llm_invocation(source=func.__qualname__, llm_input=llm_input,
-                                             llm_output="".join(llm_output))
+                Monitor().trace_llm_invocation(source=func.__qualname__, llm_input=llm_input,
+                                               llm_output="".join(llm_output))
 
             return gen_iterator()
 
@@ -95,3 +96,65 @@ def _get_llm_input(func, *args, **kwargs) -> dict:
     bound_args = sig.bind(*args, **kwargs)
     bound_args.apply_defaults()
     return {k: v for k, v in bound_args.arguments.items()}
+
+
+def trace_agent(func):
+    """Annotation: @trace_agent
+
+    Decorator to trace the agent invocation, add agent input and output to the monitor.
+    """
+
+    @functools.wraps(func)
+    def wrapper_sync(*args, **kwargs):
+        # get agent input from arguments
+        agent_input = _get_agent_input(func, *args, **kwargs)
+        # check whether the tracing switch is enabled
+        source = func.__qualname__
+        self = agent_input.pop('self', None)
+
+        tracing = None
+        if isinstance(self, object):
+            agent_model = getattr(self, 'agent_model', None)
+            if isinstance(agent_model, object):
+                info = getattr(agent_model, 'info', None)
+                profile = getattr(agent_model, 'profile', None)
+                if isinstance(info, dict):
+                    source = info.get('name', None)
+                if isinstance(profile, dict):
+                    tracing = profile.get('tracing', None)
+
+        if tracing is False:
+            return func(*args, **kwargs)
+
+        # invoke function
+        result = func(*args, **kwargs)
+        # serialize agent input and output dict
+        agent_input = serialize_agent_invocation(agent_input)
+        agent_output = serialize_agent_invocation(result)
+        # add agent invocation info to monitor
+        Monitor().trace_agent_invocation(source=source, agent_input=agent_input, agent_output=agent_output)
+        return result
+
+    # sync function
+    return wrapper_sync
+
+
+def _get_agent_input(func, *args, **kwargs) -> dict:
+    """Get the agent input from arguments."""
+    sig = inspect.signature(func)
+    bound_args = sig.bind(*args, **kwargs)
+    bound_args.apply_defaults()
+    return {k: v for k, v in bound_args.arguments.items()}
+
+
+def default_serializer(obj):
+    if isinstance(obj, InputObject):
+        return obj.to_dict()
+    elif isinstance(obj, OutputObject):
+        return obj.to_dict()
+    raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")
+
+
+def serialize_agent_invocation(agent_invocation):
+    agent_invocation_serialized = json.loads(json.dumps(agent_invocation, default=default_serializer))
+    return agent_invocation_serialized
diff --git a/agentuniverse/base/util/monitor/monitor.py b/agentuniverse/base/util/monitor/monitor.py
index 7b4e942e..e69388af 100644
--- a/agentuniverse/base/util/monitor/monitor.py
+++ b/agentuniverse/base/util/monitor/monitor.py
@@ -16,6 +16,7 @@
 from agentuniverse.base.config.configer import Configer
 
 LLM_INVOCATION_SUBDIR = "llm_invocation"
+AGENT_INVOCATION_SUBDIR = "agent_invocation"
 
 
 @singleton
@@ -54,11 +55,38 @@ def trace_llm_invocation(self, source: str, llm_input: Union[str, dict], llm_out
 
             # write to jsonl
             with jsonlines.open(path_save, 'a') as writer:
-                json_record = json.dumps(llm_invocation, ensure_ascii=False)
-                writer.write(json_record)
+                writer.write(llm_invocation)
 
     def _get_or_create_subdir(self, subdir: str) -> str:
         """Get or create a subdirectory if it doesn't exist in the monitor directory."""
         path = os.path.join(self.dir, subdir)
         os.makedirs(path, exist_ok=True)
         return path
+
+    def trace_agent_invocation(self, source: str, agent_input: Union[str, dict],
+                               agent_output: Union[str, dict]) -> None:
+        """Trace the agent invocation and save it to the monitor jsonl file."""
+        if self.activate:
+            try:
+                import jsonlines
+            except ImportError:
+                raise ImportError(
+                    "jsonlines is required to trace llm invocation: `pip install jsonlines`"
+                )
+            # get the current time
+            date = datetime.datetime.now()
+            agent_invocation = {
+                "source": source,
+                "date": date.strftime("%Y-%m-%d %H:%M:%S"),
+                "agent_input": agent_input,
+                "agent_output": agent_output,
+            }
+            # files are stored in hours
+            filename = f"agent_{source}_{date.strftime('%Y-%m-%d-%H')}.jsonl"
+            # file path to save
+            path_save = os.path.join(str(self._get_or_create_subdir(AGENT_INVOCATION_SUBDIR)), filename)
+
+            # write to jsonl
+            with jsonlines.open(path_save, 'a') as writer:
+                writer.write(agent_invocation)
+
diff --git a/agentuniverse/llm/default/deep_seek_openai_style_llm.py b/agentuniverse/llm/default/deep_seek_openai_style_llm.py
new file mode 100644
index 00000000..485ec685
--- /dev/null
+++ b/agentuniverse/llm/default/deep_seek_openai_style_llm.py
@@ -0,0 +1,70 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/21 17:49
+# @Author  : weizjajj 
+# @Email   : weizhongjie.wzj@antgroup.com
+# @FileName: claude_llm.py
+
+from typing import Optional, Any, Union, Iterator, AsyncIterator
+
+from pydantic import Field
+
+from agentuniverse.base.annotation.trace import trace_llm
+from agentuniverse.base.util.env_util import get_from_env
+from agentuniverse.llm.llm_output import LLMOutput
+from agentuniverse.llm.openai_style_llm import OpenAIStyleLLM
+
+DEEpSEEkMAXCONTETNLENGTH = {
+    "deepseek-chat": 32000,
+    "deepseek-coder": 32000,
+    "claude-3-haiku-20240307": 200000,
+    "claude-2.1": 200000,
+    "claude-2.0": 100000,
+    "claude-instant-1.2": 100000
+}
+
+
+class DefaultDeepSeekLLM(OpenAIStyleLLM):
+    """The agentUniverse default openai llm module.
+
+    LLM parameters, such as name/description/model_name/max_tokens,
+    are injected into this class by the default_openai_llm.yaml configuration.
+    """
+
+    api_key: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_API_KEY"))
+    organization: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_ORGANIZATION"))
+    api_base: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_API_BASE"))
+    proxy: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_PROXY"))
+
+    @trace_llm
+    def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
+        """ The call method of the LLM.
+
+        Users can customize how the model interacts by overriding call method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return super().call(messages, **kwargs)
+
+    @trace_llm
+    async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
+        """ The async call method of the LLM.
+
+        Users can customize how the model interacts by overriding acall method of the LLM class.
+
+        Args:
+            messages (list): The messages to send to the LLM.
+            **kwargs: Arbitrary keyword arguments.
+        """
+        return await super().acall(messages, **kwargs)
+
+    def max_context_length(self) -> int:
+        """Max context length.
+
+          The total length of input tokens and generated tokens is limited by the openai model's context length.
+          """
+        return DEEpSEEkMAXCONTETNLENGTH.get(self.model_name, 4096)
+
diff --git a/agentuniverse/llm/default/deep_seek_openai_style_llm.yaml b/agentuniverse/llm/default/deep_seek_openai_style_llm.yaml
new file mode 100644
index 00000000..3921577a
--- /dev/null
+++ b/agentuniverse/llm/default/deep_seek_openai_style_llm.yaml
@@ -0,0 +1,8 @@
+name: 'default_deepseek_llm'
+description: 'default default_deepseek_llm llm with spi'
+model_name: 'deepseek-chat'
+max_tokens: 1000
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.default.deep_seek_openai_style_llm'
+  class: 'DefaultDeepSeekLLM'
\ No newline at end of file
diff --git a/agentuniverse/llm/llm.py b/agentuniverse/llm/llm.py
index 53c4fd67..4d33c629 100644
--- a/agentuniverse/llm/llm.py
+++ b/agentuniverse/llm/llm.py
@@ -103,6 +103,8 @@ def initialize_by_component_configer(self, component_configer: LLMConfiger) -> '
         if component_configer.ext_info:
             self.ext_info = component_configer.ext_info
         self.tracing = component_configer.tracing
+        if 'max_context_length' in component_configer.configer.value:
+            self._max_context_length = component_configer.configer.value['max_context_length']
         return self
 
     def set_by_agent_model(self, **kwargs) -> None:
diff --git a/agentuniverse/llm/openai_style_llm.py b/agentuniverse/llm/openai_style_llm.py
index 2d5a3ea0..0981e47a 100644
--- a/agentuniverse/llm/openai_style_llm.py
+++ b/agentuniverse/llm/openai_style_llm.py
@@ -14,6 +14,8 @@
 from langchain_core.language_models.base import BaseLanguageModel
 from openai import OpenAI, AsyncOpenAI
 
+from agentuniverse.base.config.component_configer.configers.llm_configer import LLMConfiger
+from agentuniverse.base.util.env_util import get_from_env
 from agentuniverse.llm.llm import LLM, LLMOutput
 from agentuniverse.llm.openai_style_langchain_instance import LangchainOpenAIStyleInstance
 
@@ -161,6 +163,17 @@ async def agenerate_stream_result(self, stream: AsyncIterator) -> AsyncIterator[
 
         await self.aclose()
 
+    def initialize_by_component_configer(self, component_configer: LLMConfiger) -> 'LLM':
+        if 'api_base' in component_configer.configer.value:
+            self.api_base = component_configer.configer.value.get('api_base')
+        elif 'api_base_env' in component_configer.configer.value:
+            self.api_base = get_from_env(component_configer.configer.value.get('api_base_env'))
+        if 'api_key' in component_configer .configer.value:
+            self.api_key = component_configer.configer.value.get('api_key')
+        elif 'api_key_env' in component_configer.configer.value:
+            self.api_key = get_from_env(component_configer.configer.value.get('api_key_env'))
+        return super().initialize_by_component_configer(component_configer)
+
     def get_num_tokens(self, text: str) -> int:
         """Get the number of tokens present in the text.
 
@@ -187,3 +200,9 @@ async def aclose(self):
         """Async close the client."""
         if hasattr(self, 'async_client') and self.async_client:
             await self.async_client.close()
+
+    def max_context_length(self) -> int:
+        """Return the maximum length of the context."""
+        if super().max_context_length():
+            return super().max_context_length()
+        return 4000
diff --git a/docs/guidebook/en/0_index.md b/docs/guidebook/en/0_index.md
index ff85fc87..432fd39d 100644
--- a/docs/guidebook/en/0_index.md
+++ b/docs/guidebook/en/0_index.md
@@ -42,6 +42,7 @@
   * 2.4.4 Logging
     * 2.4.4.1 [Logging Component](2_6_Logging_Utils.md)
   * 2.4.5 Data Collection
+    * 2.4.5.1 [Monitor Module](2_5_1_Monitor_Module.md)
 
 **3. Component Reference Manual**
 * 3.1 Domain Components
@@ -54,7 +55,11 @@
     * 3.1.2.5 [BaiChuan Usage Instructions](3_1_2_BaiChuan_LLM_Use.md)
     * 3.1.2.6 [Claude Usage Instructions](3_1_2_Claude_LLM_Use.md)
     * 3.1.2.7 [Ollama Usage Instructions](3_1_2_Ollama_LLM_Use.md)
+    * 3.1.2.8 [DeepSeek Usage Instructions](3_1_2_DeepSeek_LLM_Use.md)
+    * 3.1.2.9 [General OpenAI Protocol Style Wrapper](3_1_2_OpenAIStyleLLM_Use.md)
   * 3.1.3 List of Tools
+    * 3.1.3.1 [Integration Tool Details](2_2_3_Integrated_Tools.md)
+    * 3.1.3.2 [LangChain Tool Wrapper](2_2_3_Integrated_LangChain_Tools.md)
   * 3.1.4 List of Knowledge
   * 3.1.5 List of Memories
   * 3.1.6 List of Planners
diff --git a/docs/guidebook/en/2_2_3_Integrated_LangChain_Tools.md b/docs/guidebook/en/2_2_3_Integrated_LangChain_Tools.md
new file mode 100644
index 00000000..fcaba8f4
--- /dev/null
+++ b/docs/guidebook/en/2_2_3_Integrated_LangChain_Tools.md
@@ -0,0 +1,83 @@
+# Integrated LangChain Tool
+
+Based on the level of difficulty in initializing tool objects in LangChain, they can be divided into two categories:
+The first category involves simple initialization, where initialization can be completed with basic parameter configuration.
+The second category involves complex initialization with intricate internal objects that need to be set up.
+For the first category of tools, you can use configuration files in aU to directly perform initialization, such as initializing the DuDuckGo search tool.
+For the second category of tools, we have implemented a LangChainTool base class. You only need to implement the init_langchain_tool method of this class to initialize the corresponding LangChain tool objects, with reference to the initialization method of Wikipedia.
+
+Note: If you want to directly use the description from LangChain, the description in the configuration file must be set to empty.
+
+An Example of Tool Initialization:
+[Tool Address](../../../sample_standard_app/app/core/tool/langchain_tool/human_input_run.yaml)
+```yaml
+name: 'human_input_run'
+description: ''
+tool_type: 'api'
+input_keys: ['input']
+langchain:
+  module: langchain_community.tools
+  class_name: HumanInputRun
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool'
+  class: 'LangChainTool'
+```
+Parameter Description:
+    langchain: The LangChain tool you intend to use, which requires the configuration of module and class_name.
+    langchain.module: The name of the LangChain module, e.g., langchain_community.tools.
+    langchain.class_name: The name of the LangChain class, e.g., HumanInputRun.
+    langchain.init_params: The initialization parameters for LangChain, such as:
+        ```yaml
+        langchain:
+          module: langchain_community.tools
+          class_name: HumanInputRun
+          init_params:
+            prompt: 'please Input your question'
+        ```
+    If you completely override the `init_langchain_tool` method, then you do not need to configure this part.
+
+## 1. Integrate the DuckDuckGo Tool from LangChain
+[Tool Address](../../../sample_standard_app/app/core/tool/langchain_tool/duckduckgo_search.yaml)
+```yaml
+name: 'duckduckgo_search'
+description: 'DuckDuckGo Search tool'
+tool_type: 'api'
+input_keys: ['input']
+langchain:
+  module: langchain.tools
+  class_name: DuckDuckGoSearchResults
+  init_params:
+    backend: news
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool.langchain_tool'
+  class: 'LangChainTool'
+```
+This tool can be used directly without any keys.
+
+## 2.Integrate Wikipedia Search
+Since the definition of LangChain includes an api_wrapper object, define the object file and override the initialization method:
+```python
+from langchain_community.tools import WikipediaQueryRun
+from langchain_community.utilities import WikipediaAPIWrapper
+
+from sample_standard_app.app.core.tool.langchain_tool.langchain_tool import LangChainTool
+
+
+class WikipediaTool(LangChainTool):
+    def init_langchain_tool(self, component_configer):
+        wrapper = WikipediaAPIWrapper()
+        return WikipediaQueryRun(api_wrapper=wrapper)
+```
+Define Configuration:
+```yaml
+name: 'wikipedia_query'
+description: ''
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool.wikipedia_query'
+  class: 'WikipediaTool'
+```
\ No newline at end of file
diff --git a/docs/guidebook/en/2_2_3_Integrated_Tools.md b/docs/guidebook/en/2_2_3_Integrated_Tools.md
new file mode 100644
index 00000000..6db58fe8
--- /dev/null
+++ b/docs/guidebook/en/2_2_3_Integrated_Tools.md
@@ -0,0 +1,189 @@
+# Integrated Tools
+
+In the current au's sample project, the following tools are integrated.
+
+## 1. Search Tools
+
+### 1.1 Google Search
+[工具地址](../../../sample_standard_app/app/core/tool/google_search_tool.yaml)  
+Detailed Configuration Information:
+
+```yaml
+name: 'google_search_tool'
+description: |
+  This tool can be used to perform Google searches. The tool's input is the content you want to search for.
+  Example inputs for the tool:
+    Example 1: If you want to search for the weather in Shanghai, the tool's input should be: "Shanghai weather today"
+    Example 2: If you want to search for the weather in Japan, the tool's input should be: "Japan weather"
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.google_search_tool'
+  class: 'GoogleSearchTool'
+```
+To use this API, you must apply for a BING_SUBSCRIPTION_KEY at https://serper.dev and configure it in your environment variables. 
+Configuration method:
+1. Configure via Python code You must configure: SERPER_API_KEY
+```python
+import os
+os.environ['SERPER_API_KEY'] = 'xxxx'
+```
+2. Configure via configuration file In the custom_key.toml file located in the config directory of the project, add the configuration:  
+```toml
+SERPER_API_KEY="xxxx"
+```
+
+
+### 1.2 Bing Search 
+Currently, it integrates with the official Bing search.
+[工具地址](../../../sample_standard_app/app/core/tool/bing_search_tool.yaml)  
+Tool configuration:
+```yaml
+name: 'bing_search_tool'
+description: 'demo bing search tool'
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.bing_search_tool'
+  class: 'BingSearchTool'
+```
+To use this API, you must apply for BING_SUBSCRIPTION_KEY and configure it in environment variables. 
+Configuration method:
+1. Configure through Python code
+Mandatory configuration: BING_SUBSCRIPTION_KEY
+```python
+import os
+os.environ['BING_SUBSCRIPTION_KEY'] = 'xxxx'
+```
+2. Configure through configuration file
+In custom_key.toml under config directory of the project, add configuration:
+```toml
+BING_SUBSCRIPTION_KEY="xxxx"
+```
+
+
+
+### 1.3 Search API
+Supports multiple search tools, such as: 
+- [Baidu search](../../../sample_standard_app/app/core/tool/search_api_baidu_tool.yaml)
+- [Bing search](../../../sample_standard_app/app/core/tool/search_api_bing_tool.yaml)  
+Other search engines also include: Google search, Amazon search, YouTube search, etc. For more information, please refer to: https://www.searchapi.io/
+Tool configuration:
+```yaml
+name: 'search_api_baidu_tool'
+description: 'Baidu (Bing) search tool, input is a string of content to be searched, e.g.: input="What is the price of gold?"'
+tool_type: 'api'
+input_keys: ['input']
+engine: 'baidu'
+search_type: 'json'
+search_params:
+  num: 10
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.search_api_tool'
+  class: 'SearchAPITool'
+```
+Parameter description:
+
+search_type: Represents the format of the expected search results, where json represents the expectation for JSON format and common represents the expectation for string string format.
+search_params: Represents additional parameters that need to be passed to the search engine, such as in Baidu search, num represents the number of returned search results, detailed parameters need to be referenced at [https://www.searchapi.io/].
+engine: The search engine you expect to use, including baidu, google, bing, amazon, youtube, ... To use this API, you must apply for SEARCH_API_KEY from the official website ([https://www.searchapi.io/]) and configure it in environment variables.
+Configuration method:
+You must configure：SEARCHAPI_API_KEY
+1. Configure via Python code :
+```python
+import os
+os.environ['SEARCHAPI_API_KEY'] = 'xxxxxx'
+```
+2. Configure through configuration file
+Add configuration in custom_key.toml under the config directory of the project:
+```toml
+SEARCHAPI_API_KEY="xxxxxx"
+```
+
+
+## 2. Code Tool
+
+### 2.1 PythonRepl
+[Tool address](../../../sample_standard_app/app/core/tool/python_repl_tool.yaml)  
+This tool can execute a piece of Python code, the configuration information of the tool:  
+```yaml
+name: 'python_runner'
+description: 'The tool can execute Python code, which can be directly run in PyCharm. The input to the tool must be valid Python code. If you want to view the execution result of the tool, you must use print(...) to print the content you want to view in the Python code.
+  Example of tool input:
+    When you want to calculate what 1 + 3 equals, the input to the tool should be:
+        ```py 
+        print(1+3)
+        ```
+      When you want to get information about the Baidu page, the input to the tool should be:
+        ```py 
+        import requests
+        resp=requests.get("https://www.baidu.com")
+        print(resp.content)
+        ```'
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.python_repl'
+  class: 'PythonREPLTool'
+```
+
+This tool can be used directly without any key, but for system security, please do not use this tool in production environments.
+
+
+## 3.HTTP Tool
+
+### 3.1 HTTP GET
+[Tool address](../../../sample_standard_app/app/core/tool/request_get_tool.yaml)
+The tool can send a GET request, with its configuration information being:
+```yaml
+name: 'requests_get'
+description: 'A portal to the internet. Use this when you need to get specific
+    content from a website. Input should be a  url (i.e. https://www.google.com).
+    The output will be the text response of the GET request.
+        ```'
+headers:
+  content-type: 'application/json'
+method: 'POST'
+json_parser: true
+response_content_type: json
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.request_tool'
+  class: 'RequestTool'
+```
+Configuration to Refer to When Sending a POST Request：
+```yaml
+name: 'requests_post'
+# description copy from langchain RequestPOSTTool
+description: 'Use this when you want to POST to a website.
+    Input should be a json string with two keys: "url" and "data".
+    The value of "url" should be a string, and the value of "data" should be a dictionary of 
+    key-value pairs you want to POST to the url.
+    Be careful to always use double quotes for strings in the json string
+    The output will be the text response of the POST request.
+        ```'
+headers:
+  content-type: 'application/json'
+method: 'POST'
+json_parser: true
+response_content_type: json
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.request_tool'
+  class: 'RequestTool'
+```
+Parameter Description:
+    method: The method of the request, such as GET, POST, PUT, etc.
+    headers: The HTTP headers required for sending the request.
+    json_parse: Specifies whether the input parameters need to be parsed by HTTP. It should be set to True for POST requests and False for GET requests.
+    response_content_type: The parsing method for the HTTP request result. If set to 'json', the result will be returned in JSON format; if set to 'text', the result will be returned as text.
+This tool can be used directly without any keys required.
+
diff --git a/docs/guidebook/en/2_5_1_Monitor_Module.md b/docs/guidebook/en/2_5_1_Monitor_Module.md
new file mode 100644
index 00000000..57201e24
--- /dev/null
+++ b/docs/guidebook/en/2_5_1_Monitor_Module.md
@@ -0,0 +1,201 @@
+# Monitor Module
+
+agentUniverse monitor module, mainly around the agent runtime LLM invocation/token expenses for data tracking and
+recording. In this document, we will provide a detailed introduction on how to use the **LLM and Agent invocation tracking
+capabilities** that are currently open in the agentUniverse.
+
+## Monitor Configuration
+
+Configure the monitor module settings in the main configuration file `config.toml` of agentUniverse, as follows:
+
+```toml
+[MONITOR]
+activate = true
+dir = './monitor'
+```
+
+- **`activate`**: The master switch for the monitor module is set to off by default. When set to true, it will turn on
+  the LLM and Agent invocation tracking functions.
+- **`dir`**: The local storage directory corresponding to the monitor module is, by default, the 'monitor' directory one
+  level above the runtime directory. Users can customize the configuration of the directory path.
+
+### LLM Tracing Configuration
+
+For the LLM invocation tracking capability, agentUniverse also supports model granularity configuration. Once the main
+switch of the monitor module is turned on, the invocation tracking function for specific models can be selectively
+disabled through the LLM's yaml file.
+
+For example, for a user-defined model such as `demo_llm`, if the tracing is set to false, then the invocation tracking
+function for this model will be turned off.
+
+```yaml
+name: 'demo_llm'
+description: 'demo openai'
+model_name: 'gpt-4o'
+max_tokens: 1000
+max_retries: 2
+tracing: false
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.default.default_openai_llm'
+  class: 'DefaultOpenAILLM'
+```
+
+Special note: In the main configuration file of agentUniverse, the monitor module's master switch has the **highest
+priority**. If the `activate` configuration is set to false, the model granularity configuration will not take effect.
+
+### Agent Tracing Configuration
+
+For the agent invocation tracking capability, agentUniverse also supports agent granularity configuration. Once the main
+switch of the monitor module is turned on, the invocation tracking function for specific agent can be selectively
+disabled through the agent's yaml file.
+
+For example, for a user-defined agent such as `demo_agent`, if the tracing is set to false, then the invocation tracking
+function for this agent will be turned off.
+
+```yaml
+info:
+  name: 'demo_agent'
+  description: 'demo agent'
+profile:
+  tracing: false
+  prompt_version: demo_agent_prompt.cn
+  llm_model:
+    name: 'qwen_llm'
+plan:
+  planner:
+    name: 'rag_planner'
+action:
+  tool:
+    - 'google_search_tool'
+memory:
+  name: ''
+metadata:
+  type: 'AGENT'
+  module: 'sample_standard_app.app.core.agent.rag_agent_case.demo_rag_agent'
+  class: 'DemoRagAgent'
+```
+
+Special note: In the main configuration file of agentUniverse, the monitor module's master switch has the **highest
+priority**. If the `activate` configuration is set to false, the agent granularity configuration will not take effect.
+
+
+## Monitor Module Introduction
+
+### LLM Invocation Tracking
+
+If the user utilizes the **default model class** supported by the agentUniverse, the feature can be used after the
+configuration as described above is completed.
+
+#### trace_llm Decorator
+
+If a user customizes the extension based on the agentUniverse's model base class `LLM` to implement a custom model
+invocation, it is necessary to add the `@trace_llm` decorator to the call/acall method of the custom model class.
+
+Custom model example code as follows:
+
+```python
+from typing import Any, Iterator, Union, AsyncIterator
+
+from agentuniverse.llm.llm import LLM, LLMOutput
+from agentuniverse.base.annotation.trace import trace_llm
+
+
+class DemoLLM(LLM):
+
+    @trace_llm
+    def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
+        pass
+
+    @trace_llm
+    async def acall(self, *args: Any, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
+        pass
+```
+
+agentUniverse implements the `@trace_llm` decorator, which, when the agent calls the corresponding LLM call/acall
+methods, collects the model's prompt and response, serializes the information into JSON, and stores it in the local
+storage directory corresponding to the monitor configuration in the form of a jsonl file, divided by the hour.
+
+#### Demo Effect
+
+Call the `demo_rag_agent` in the sample project of agentUniverse, using the gpt-4o model, with the query to analyze the
+reasons behind Warren Buffett's reduction of his stake in BYD. The model invocation tracking function captures the
+following data:
+
+```json
+{
+  "source": "DefaultOpenAILLM.acall",
+  "date": "2024-06-24 16:27:14",
+  "llm_input": {
+    "messages": [
+      {
+        "role": "system",
+        "content": "You are an AI assistant proficient in information analysis.\nYour goal is to determine whether the corresponding answers to the questions provide valuable information, and to make suggestions and evaluations on the answers to the questions."
+      },
+      {
+        "role": "user",
+        "content": "The rules you need to follow are:\n1. You must answer the user's questions using English, combining the background information of the query with the knowledge you possess.\n2. Generate structured answers, and use blank lines to enhance the reading experience when necessary.\\n the question needs to be answered is: the reasons behind Warren Buffett's reduction of his stake in BYD\\n"
+      }
+    ]
+  },
+  "kwargs": {
+    "model": "gpt-4o",
+    "stream": false,
+    "n": 1,
+    "temperature": 0.5,
+    "max_tokens": 1000
+  },
+  "llm_output": "Reasons Behind Warren Buffett's Reduction of His Stake in BYD\n\nWarren Buffett, through his company Berkshire Hathaway, has been reducing his stake in BYD since August 24, 2022. There are several potential reasons behind this decision:\n\n1. **Portfolio Rebalancing**:\n   - **Investment Strategy**: Buffett is known for his long-term investment strategy and value investing. Reducing his stake in BYD could be part of a broader portfolio rebalancing effort to diversify or allocate capital to other investment opportunities.\n   - **Profit Realization**: Given that Buffett's initial investment in BYD has appreciated significantly (approximately 31 times the initial value), selling some shares allows him to realize substantial profits.\n\n2. **Market Conditions**:\n   - **Stock Performance**: Despite the reduction in stake, BYD's stock price has remained relatively stable. This suggests that Buffett's decision to sell shares is not necessarily a reflection of a negative outlook on the company's stock performance.\n   - **Economic Factors**: The broader economic environment, including interest rates, inflation, and market volatility, may influence investment decisions. Buffett might be adjusting his holdings in response to these macroeconomic factors.\n\n3. **Company Evaluation**:\n   - **Intrinsic Value**: Buffett's investment philosophy focuses on the intrinsic value of a company rather than short-term stock price movements. He might believe that the current market price of BYD reflects its intrinsic value, prompting a partial exit.\n   - **Sector Analysis**: While BYD remains a leading player in the Chinese electric vehicle (EV) market, Buffett might be evaluating the competitive landscape and future growth prospects, leading to a strategic reduction in holdings.\n\n"
+}
+```
+
+- **`source`**: the source of LLM invocation during agent runtime.
+- **`date`**: LLM invocation time
+- **`llm_input`**: LLM invocation messages and model parameters
+- **`llm_output`**: LLM output text
+
+### Agent Invocation Tracking
+
+#### trace_agent Decorator
+
+agentUniverse implements the `@trace_agent` decorator, which, when the agent calls the run
+method, collects the agent's input and output parameters, serializes the information into JSON, and stores it in the local
+storage directory corresponding to the monitor configuration in the form of a jsonl file, divided by the hour and the specific agent.
+
+#### Demo Effect
+
+Call the `demo_rag_agent` in the sample project of agentUniverse, using the gpt-4o model, with the query to analyze the
+reasons behind Warren Buffett's reduction of his stake in BYD. The agent invocation tracking function captures the
+following data:
+
+```json
+{
+  "source": "demo_rag_agent", 
+  "date": "2024-06-28 12:12:17", 
+  "agent_input": {
+    "kwargs": {
+      "input": "analyze the reasons behind Warren Buffett's reduction of his stake in BYD"
+    }
+  }, 
+  "agent_output": {
+    "chat_history": [
+      {
+        "content": "analyze the reasons behind Warren Buffett's reduction of his stake in BYD", 
+        "type": "human"
+      }, 
+      {
+        "content": "### Analysis of Warren Buffett's Reduction in Stake in BYD\n\nWarren Buffett, through his investment conglomerate Berkshire Hathaway, has been gradually reducing his stake in BYD Company Limited, a major player in the electric vehicle (EV) market. Here are the key reasons behind this strategic move:\n\n#### 1. Profit-Taking\n\n**Initial Investment vs. Current Valuation:**\n- **Initial Investment:** Berkshire Hathaway first bought about 225 million shares of Shenzhen-based BYD in 2008.\n- **Current Sale:** Recently, Berkshire sold nearly 2.02 million Hong Kong-listed shares of BYD at $234.57 apiece.\n\nGiven the significant appreciation in the value of BYD shares since the initial investment, it is plausible that Berkshire Hathaway is looking to realize profits from this long-term investment.\n\n#### 2. Portfolio Management\n\n**Stake Reduction:**\n- **Previous Stake:** Berkshire Hathaway's stake in BYD was previously 7%.\n- **Current Stake:** The sale has reduced the stake to 5.99%.\n\nReducing the stake in BYD allows Berkshire Hathaway to prune its portfolio, potentially reallocating resources to other investment opportunities or maintaining a diversified portfolio.\n\n#### 3. Market Performance and Strategic Positioning\n\n**Market Analysis:**\n- BYD, along with Tesla, is a leading player in the global electric vehicle market. However, market dynamics and competition are constantly evolving. Berkshire Hathaway's decision to reduce its stake could be influenced by an analysis of market performance and future growth prospects.\n\n**Value Investing:**\n- Warren Buffett is known for his value investing strategy. The timing of the BYD share sale may align with Buffett's assessment of the company's current valuation relative to its future growth potential.\n\n### Conclusion\n\nWarren Buffett's reduction in his stake in BYD appears to be a strategic decision influenced by multiple factors, including profit-taking, portfolio management, and an analysis of market performance. This move aligns with Berkshire Hathaway's broader investment strategy and reflects a calculated approach to managing its investments in a dynamic global market.", 
+        "type": "ai"
+      }],
+    "background": "Warren Buffett's Berkshire Hathaway may have sold BYD to take profits, free up cash, prune its portfolio, cut its geopolitical risk, ... Missing: analyze | Show results with:analyze. Explore Berkshire Hathaway's gradual divestment from BYD, analyzing geopolitical tensions, market performance, and strategic positioning. According to various media reports and analysis, Warren Buffett's reduction of shareholdings in BYD Company Limited may be due to various ... Berkshire sold nearly 2.02 million Hong Kong-listed shares of BYD at $234.57 apiece, dropping its stake from 6.18% to 5.99%. The disposal was ... Warren Buffett's Berkshire Hathaway has further cut its large stake in BYD, which vies with Tesla as the world's largest electric car (EV) maker ... Missing: analyze | Show results with:analyze. The sale reduced Berkshire's holding to 6.9%, from 7%. The conglomerate first bought about 225 million shares of Shenzhen-based BYD in 2008 for ... According to HKEX disclosure, Warren Buffett's investment flagship Berkshire Hathaway reduced its stake in BYD COMPANY (01211. Warren Buffett's Berkshire Hathaway Inc. (NYSE:BRK)(NYSE:BRK) is reducing its stake in BYD Co., Ltd. (OTC:BYDDY) (OTC:BYDDF) to less than 6%. The odd timing of the BYD share sale has less to do with Buffett's outlook on the Chinese EV maker and more to do with 'value investing.' Investment mogul Warren Buffett has quickened the reduction of his stake in Chinese electric vehicle-maker BYD, selling holdings in the firm ...", 
+    "date": "2024-06-28", 
+    "input": "analyze the reasons behind Warren Buffett's reduction of his stake in BYD", 
+    "output": "### Analysis of Warren Buffett's Reduction in Stake in BYD\n\nWarren Buffett, through his investment conglomerate Berkshire Hathaway, has been gradually reducing his stake in BYD Company Limited, a major player in the electric vehicle (EV) market. Here are the key reasons behind this strategic move:\n\n#### 1. Profit-Taking\n\n**Initial Investment vs. Current Valuation:**\n- **Initial Investment:** Berkshire Hathaway first bought about 225 million shares of Shenzhen-based BYD in 2008.\n- **Current Sale:** Recently, Berkshire sold nearly 2.02 million Hong Kong-listed shares of BYD at $234.57 apiece.\n\nGiven the significant appreciation in the value of BYD shares since the initial investment, it is plausible that Berkshire Hathaway is looking to realize profits from this long-term investment.\n\n#### 2. Portfolio Management\n\n**Stake Reduction:**\n- **Previous Stake:** Berkshire Hathaway's stake in BYD was previously 7%.\n- **Current Stake:** The sale has reduced the stake to 5.99%.\n\nReducing the stake in BYD allows Berkshire Hathaway to prune its portfolio, potentially reallocating resources to other investment opportunities or maintaining a diversified portfolio.\n\n#### 3. Market Performance and Strategic Positioning\n\n**Market Analysis:**\n- BYD, along with Tesla, is a leading player in the global electric vehicle market. However, market dynamics and competition are constantly evolving. Berkshire Hathaway's decision to reduce its stake could be influenced by an analysis of market performance and future growth prospects.\n\n**Value Investing:**\n- Warren Buffett is known for his value investing strategy. The timing of the BYD share sale may align with Buffett's assessment of the company's current valuation relative to its future growth potential.\n\n### Conclusion\n\nWarren Buffett's reduction in his stake in BYD appears to be a strategic decision influenced by multiple factors, including profit-taking, portfolio management, and an analysis of market performance. This move aligns with Berkshire Hathaway's broader investment strategy and reflects a calculated approach to managing its investments in a dynamic global market."
+  }
+}
+```
+
+- **`source`**: the Agent name.
+- **`date`**: Agent invocation time
+- **`llm_input`**: Agent invocation input parameters
+- **`llm_output`**: Agent output parameters
\ No newline at end of file
diff --git a/docs/guidebook/en/3_1_2_0_List_Of_LLMs.md b/docs/guidebook/en/3_1_2_0_List_Of_LLMs.md
index a56aa83f..c283b92b 100644
--- a/docs/guidebook/en/3_1_2_0_List_Of_LLMs.md
+++ b/docs/guidebook/en/3_1_2_0_List_Of_LLMs.md
@@ -10,6 +10,9 @@ The platform has currently integrated the following list of models; please refer
 | [BaiChuan](3_1_2_BaiChuan_LLM_Use.md) |
 | [Claude](3_1_2_Claude_LLM_Use.md)     |
 | [ollama](3_1_2_Ollama_LLM_Use.md)     |
+| [DeepSeek](3_1_2_DeepSeek_LLM_Use.md)      |
+
+To facilitate the integration of models with OpenAI-style protocols, we offer a wrapper object based on the OpenAI general protocol. See [OpenAIStyleLLM](3_1_2_OpenAIStyleLLM_Use.md).
 
 For LLM not included in the list, you can customize the integration of any LLM according to the steps provided in the [LLM definition](2_2_3_Tool_Create_And_Use.md).
 
diff --git a/docs/guidebook/en/3_1_2_DeepSeek_LLM_Use.md b/docs/guidebook/en/3_1_2_DeepSeek_LLM_Use.md
new file mode 100644
index 00000000..99622433
--- /dev/null
+++ b/docs/guidebook/en/3_1_2_DeepSeek_LLM_Use.md
@@ -0,0 +1,35 @@
+# DeepSeek  Usage
+## 1. Create the relevant file.
+Create a YAML file, for example, user_deepseek_llm.yaml
+Paste the following content into your user_deepseek_llm.yaml file.
+```yaml
+name: 'user_deepseek_llm'
+description: 'default default_deepseek_llm llm with spi'
+model_name: 'deepseek-chat'
+max_tokens: 1000
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.default.deep_seek_openai_style_llm'
+  class: 'DefaultDeepSeekLLM'
+```
+##  2. Environment Setup
+Must be configured: DEEPSEEK_API_KEY  
+Optional: DEEPSEEK_API_BASE
+### 2.1 Configure through Python code
+```python
+import os
+os.environ['DEEPSEEK_API_KEY'] = 'sk-***'
+os.environ['DEEPSEEK_API_BASE'] = 'https://xxxxxx'
+```
+### 2.2 Configure through the configuration file
+In the custom_key.toml file under the config directory of the project, add the configuration:
+```toml
+DEEPSEEK_API_KEY="sk-******"
+DEEPSEEK_API_BASE="https://xxxxxx"
+```
+## 3. Obtaining the DeepSeek API KEY 
+Please refer to the official documentation of DEEPSEEK:https://platform.deepseek.com/api_keys
+
+## 4. Tips
+In the agentuniverse, we have established an LLM named default_deepseek_llm. Users can directly utilize it after configuring their DEEPSEEK_API_KEY.
+
diff --git a/docs/guidebook/en/3_1_2_OpenAIStyleLLM_Use.md b/docs/guidebook/en/3_1_2_OpenAIStyleLLM_Use.md
new file mode 100644
index 00000000..ab712fc3
--- /dev/null
+++ b/docs/guidebook/en/3_1_2_OpenAIStyleLLM_Use.md
@@ -0,0 +1,37 @@
+# OpenAIStyleLLM Usage
+## 1. Create the relevant file.
+Create a YAML file, for example, user_openai_style_llm.yaml
+Paste the following content into your user_openai_style_llm.yaml file.
+```yaml
+name: 'deep_seek_llm'
+description: 'demo deep_seek llm with spi'
+model_name: 'deepseek-chat'
+max_tokens: 4000
+max_context_length: 32000
+api_key_env: 'DEEPSEEK_API_KEY'
+api_base_env: 'DEEPSEEK_API_BASE'
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.openai_style_llm'
+  class: 'OpenAIStyleLLM'
+```
+Parameter Description:
+max_context_length: The context length that the model can handle.
+api_key_env: The name of the environment variable for the API key.
+api_base_env: The name of the environment variable for the API base.
+These parameters must be configured, and upon service startup, the corresponding values will be loaded from the environment variables.
+##  2. Environment Setup
+Mandatory Configuration: $api_key_env, $api_base_env.
+In the configuration file, api_key_env and api_base_env are set as DEEPSEEK_API_KEY and DEEPSEEK_API_BASE respectively. Therefore, the configuration should be as follows:
+### 2.1 Configure through Python code
+```python
+import os
+os.environ['DEEPSEEK_API_KEY'] = 'sk-***'
+os.environ['DEEPSEEK_API_BASE'] = 'https://xxxxxx'
+```
+### 2.2 Configure through the configuration file
+In the custom_key.toml file under the config directory of the project, add the configuration:
+```toml
+DEEPSEEK_API_KEY="DEEPSEEK_API_KEY"
+DEEPSEEK_API_BASE="https://xxxxxx"
+```
diff --git a/docs/guidebook/en/5_1_1_Docker_Container_Deployment.md b/docs/guidebook/en/5_1_1_Docker_Container_Deployment.md
index 8afa9008..ec2aec02 100644
--- a/docs/guidebook/en/5_1_1_Docker_Container_Deployment.md
+++ b/docs/guidebook/en/5_1_1_Docker_Container_Deployment.md
@@ -1,22 +1,22 @@
 # 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.
+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. You can get full tag list in [this site](https://cr.console.aliyun.com/repository/cn-hangzhou/agent_universe/agent_universe/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
+docker pull registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.9_centos8
 ```
 
 
 ## 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
+docker run -d -p 8888:8888 -v ./sample_standard_app/:/usr/local/etc/workspace/project/sample_standard_app registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.9_centos8
 ```
 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.
+`-v {local_dir}:/usr/local/etc/workspace/project/{local_dir_name}`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. `local_dir_name` stands for the last pattern of the `local_dir`.
 
 ### 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:：
diff --git a/docs/guidebook/en/5_1_2_K8S_Deployment.md b/docs/guidebook/en/5_1_2_K8S_Deployment.md
index 2fde72fe..0606bd67 100644
--- a/docs/guidebook/en/5_1_2_K8S_Deployment.md
+++ b/docs/guidebook/en/5_1_2_K8S_Deployment.md
@@ -1,5 +1,5 @@
 # High Availability Deployment with K8S
-AgentUniverse provides standard working environment images, designed to support containerized deployments on Kubernetes (K8S) clusters. This guide will show you how to utilize these working environment images to deploy and set up a cluster on K8S.
+AgentUniverse provides standard working environment images, designed to support containerized deployments on Kubernetes (K8S) clusters. This guide will show you how to utilize these working environment images to deploy and set up a cluster on K8S. You can get full tag list in [this site](https://cr.console.aliyun.com/repository/cn-hangzhou/agent_universe/agent_universe/images).
 Official K8S Documentation: [Kubernetes Setup Documentation](https://kubernetes.io/docs/setup/)
 
 ## 1. Resource Configuration
@@ -30,7 +30,7 @@ spec:
     spec:
       containers:
       - name: agentuniverse-container
-        image: registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta
+        image: registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.9_centos8
         ports:
         - containerPort: 8888
         command: ["/bin/bash", "-c"]
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 27c590f0..9dbf3c8b 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"
@@ -46,6 +46,7 @@
   * 2.4.4 日志体系
     * 2.4.4.1 [日志组件](2_4_4_日志组件.md)
   * 2.4.5 数据采集
+    * 2.4.5.1 [monitor模块](2_5_1_监控模块.md)
 
 **3.组件参考手册**
 * 3.1 领域组件
@@ -58,7 +59,11 @@
     * 3.1.2.5 [百川使用说明](3_1_2_百川使用.md)
     * 3.1.2.6 [Claude使用说明](3_1_2_Claude使用.md)
     * 3.1.2.7 [Ollama使用说明](3_1_2_Ollama使用.md)
+    * 3.1.2.8 [DeepSeek使用说明](3_1_2_DeepSeek使用.md)
+    * 3.1.2.9 [通用OpenAI协议风格包装类型](3_1_2_OpenAIStyleLLM使用.md)
   * 3.1.3 工具列表(Tool)
+    * 3.1.3.1 [集成工具列表](2_2_3_集成的工具.md)
+    * 3.1.3.2 [LangChain工具包装类型](2_2_3_集成LangChain工具.md)
   * 3.1.4 知识列表(Knowledge)
   * 3.1.5 记忆列表(Memory)
   * 3.1.6 计划列表(Planner)
diff --git "a/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220LangChain\345\267\245\345\205\267.md" "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220LangChain\345\267\245\345\205\267.md"
new file mode 100644
index 00000000..d8126469
--- /dev/null
+++ "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220LangChain\345\267\245\345\205\267.md"
@@ -0,0 +1,84 @@
+# 集成LangChain工具
+
+根据langchain中工具对象的初始化的难易程度，可以将其分为两类：
+第一类，简单初始化，只需要简单的参数配置即可完成初始化。
+第二类，复杂初始化，内部包含一些复杂的对象需要进行初始化。
+对于一类工具，你可以在aU中直接使用配置文件进行初始化，如DuDuckGo搜索工具的初始化。
+对于第二类工具，我们实现了一个LangChainTool基础类，你只需要实现该类的init_langchain_tool方法，初始化对应的langchain工具对象即可，参考维基百科的初始化方法。
+
+注意，如果你想直接使用LangChain中的description，在配置文件中description必须要配置为空
+
+一个工具初始化示例：
+[工具地址](../../../sample_standard_app/app/core/tool/langchain_tool/human_input_run.yaml)
+```yaml
+name: 'human_input_run'
+description: ''
+tool_type: 'api'
+input_keys: ['input']
+langchain:
+  module: langchain_community.tools
+  class_name: HumanInputRun
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool'
+  class: 'LangChainTool'
+```
+参数说明：
+    langchain: 你打算使用的langchain工具，需要配置module和class_name
+    langchain.module: langchain的模块名，例如langchain_community.tools
+    langchain.class_name: langchain的类名，例如HumanInputRun
+    langchain.init_params： langchain的初始化参数，例如：
+        ```yaml
+        langchain:
+          module: langchain_community.tools
+          class_name: HumanInputRun
+          init_params:
+            prompt: '请输入你的问题'
+        ```
+    如果需要使用你完全重写了init_langchain_tool方法，那么你不需要配置该部分
+该工具可以直接使用，无需任何keys
+
+## 1. 集成LangChain中的DuckDuckGo工具
+[工具地址](../../../sample_standard_app/app/core/tool/langchain_tool/duckduckgo_search.yaml)
+```yaml
+name: 'duckduckgo_search'
+description: 'DuckDuckGo Search tool'
+tool_type: 'api'
+input_keys: ['input']
+langchain:
+  module: langchain.tools
+  class_name: DuckDuckGoSearchResults
+  init_params:
+    backend: news
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool.langchain_tool'
+  class: 'LangChainTool'
+```
+该工具可以直接使用，无需任何keys
+
+## 2.集成维基百科搜索
+因为LangChain的定义当中，包含一个api_wrapper对象，因此定义对象文件，并重写初始化方法：
+```python
+from langchain_community.tools import WikipediaQueryRun
+from langchain_community.utilities import WikipediaAPIWrapper
+
+from sample_standard_app.app.core.tool.langchain_tool.langchain_tool import LangChainTool
+
+
+class WikipediaTool(LangChainTool):
+    def init_langchain_tool(self, component_configer):
+        wrapper = WikipediaAPIWrapper()
+        return WikipediaQueryRun(api_wrapper=wrapper)
+```
+定义配置
+```yaml
+name: 'wikipedia_query'
+description: ''
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool.wikipedia_query'
+  class: 'WikipediaTool'
+```
\ No newline at end of file
diff --git "a/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md"
new file mode 100644
index 00000000..6e153352
--- /dev/null
+++ "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md"
@@ -0,0 +1,188 @@
+# 集成的工具
+
+当前au的 sample工程当中，集成了以下工具：
+
+## 1. 搜索工具
+
+### 1.1 谷歌搜索
+[工具地址](../../../sample_standard_app/app/core/tool/google_search_tool.yaml)  
+详细配置信息：
+
+```yaml
+name: 'google_search_tool'
+description: |
+  该工具可以用来进行谷歌搜索，工具的输入是你想搜索的内容。
+  工具输入示例：
+    示例1: 你想要搜索上海的天气时，工具的输入应该是：上海今天的天气
+    示例2: 你想要搜索日本的天气时，工具的输入应该是：日本的天气
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.google_search_tool'
+  class: 'GoogleSearchTool'
+```
+为了使用该api,你必须申请(https://serper.dev)SERPER_API_KEY并配置在环境变量当中。  
+配置方法：
+1. 通过python代码配置
+必须配置：SERPER_API_KEY
+```python
+import os
+os.environ['SERPER_API_KEY'] = 'xxxx'
+```
+2. 通过配置文件配置
+在项目的config目录下的custom_key.toml当中，添加配置：
+```toml
+SERPER_API_KEY="xxxx"
+```
+
+
+### 1.2 Bing(必应)搜索
+当前集成了Bing官方的搜索
+[工具地址](../../../sample_standard_app/app/core/tool/bing_search_tool.yaml)  
+工具配置：
+```yaml
+name: 'bing_search_tool'
+description: 'demo bing search tool'
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.bing_search_tool'
+  class: 'BingSearchTool'
+```
+为了使用该api,你必须申请BING_SUBSCRIPTION_KEY,并配置在环境变量当中。  
+配置方法：
+1. 通过python代码配置
+必须配置：BING_SUBSCRIPTION_KEY
+```python
+import os
+os.environ['BING_SUBSCRIPTION_KEY'] = 'xxxx'
+```
+2. 通过配置文件配置
+在项目的config目录下的custom_key.toml当中，添加配置：
+```toml
+BING_SUBSCRIPTION_KEY="xxxx"
+```
+
+
+
+### 1.3 Search API
+支持多种搜索工具，例如：   
+- [百度搜索](../../../sample_standard_app/app/core/tool/search_api_baidu_tool.yaml)
+- [Bing搜索](../../../sample_standard_app/app/core/tool/search_api_bing_tool.yaml)  
+其他搜索引擎还包括: 谷歌搜索、亚马逊搜索、YouTube搜索等,详细信息可以参考:https://www.searchapi.io/
+工具配置：
+```yaml
+name: 'search_api_baidu_tool'
+description: '百度(必应)搜索工具，输入为一个要搜索内容的字符串，例如：input=黄金价格是多少'
+tool_type: 'api'
+input_keys: ['input']
+engine: 'baidu'
+search_type: 'json'
+search_params:
+  num: 10
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.search_api_tool'
+  class: 'SearchAPITool'
+```
+参数说明:  
+search_type: 代表你期望返回的搜索结果的格式，json代表你期望为json格式，common代表你期望为string字符串格式。
+search_params: 代表你需要额外的传递给搜索引擎的参数，比如在百度搜索中，num代表了返回的搜索结果条数，详细参数需要参考https://www.searchapi.io/  。
+engine: 你期望使用的搜索引擎，baidu、google、bing、amazon、youtube...
+为了使用该api,你必须从[官网](https://www.searchapi.io/)申请SEARCH_API_KEY,并配置在环境变量当中。  
+配置方法：
+1. 通过python代码配置
+必须配置：SEARCH_API_KEY
+```python
+import os
+os.environ['SEARCHAPI_API_KEY'] = 'xxxxxx'
+```
+2. 通过配置文件配置
+在项目的config目录下的custom_key.toml当中，添加配置：
+```toml
+SEARCHAPI_API_KEY="xxxxxx"
+```
+
+
+## 2. 代码工具
+
+### 2.1 PythonRepl
+[工具地址](../../../sample_standard_app/app/core/tool/python_repl_tool.yaml)  
+该工具可以执行一段Python代码,工具的配置信息:  
+```yaml
+name: 'python_runner'
+description: '使用该工具可以执行python代码，可以在pycharm中直接运行的代码.工具的输入必须时一段有效的python代码. 如何你想要查看工具的执行结果, 必须在python代码中使用print(...)打印你想查看的内容。
+    工具输入示例：
+      你想要计算1+3等于多少时，工具的输入应该是：
+        ```py 
+        print(1+3)
+        ```
+      你想要获取百度页面的信息时，工具的输入应该是: 
+        ```py 
+        import requests
+        resp=requests.get("https://www.baidu.com")
+        print(resp.content)
+        ```'
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.python_repl'
+  class: 'PythonREPLTool'
+```
+
+该工具可以直接使用，无需任何key，但是为了系统安全，请不要在生产环境使用该工具
+
+## 3.HTTP 工具
+[工具地址](../../../sample_standard_app/app/core/tool/request_get_tool.yaml)
+该工具可以发送一个GET请求，工具的配置信息 :  
+```yaml
+name: 'requests_get'
+# description copy from langchain RequestGetTool
+description: 'A portal to the internet. Use this when you need to get specific
+    content from a website. Input should be a  url (i.e. https://www.google.com).
+    The output will be the text response of the GET request.
+        ```'
+headers:
+  content-type: 'application/json'
+method: 'POST'
+json_parser: false
+response_content_type: json
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.request_tool'
+  class: 'RequestTool'
+```
+发送POST请求时可以参考的配置：
+```yaml
+name: 'requests_post'
+# description copy from langchain RequestPOSTTool
+description: 'Use this when you want to POST to a website.
+    Input should be a json string with two keys: "url" and "data".
+    The value of "url" should be a string, and the value of "data" should be a dictionary of 
+    key-value pairs you want to POST to the url.
+    Be careful to always use double quotes for strings in the json string
+    The output will be the text response of the POST request.
+        ```'
+headers:
+  content-type: 'application/json'
+method: 'POST'
+json_parser: true
+response_content_type: json
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.request_tool'
+  class: 'RequestTool'
+```
+参数说明：
+    method 请求的方式GET/POST/PUT等
+    headers 发送请求需要使用的 http的header,
+    json_parse 输入参数是否需要是要HTTP解析，POST请求时需要设置为True,GET请求需要设置为False
+    response_content_type http请求结果的解析方式，设置为json时，会返回json结果，设置为text时会返回text结果
+该工具可以直接使用，无需任何keys
\ No newline at end of file
diff --git "a/docs/guidebook/zh/2_5_1_\347\233\221\346\216\247\346\250\241\345\235\227.md" "b/docs/guidebook/zh/2_5_1_\347\233\221\346\216\247\346\250\241\345\235\227.md"
new file mode 100644
index 00000000..e2dbdb6d
--- /dev/null
+++ "b/docs/guidebook/zh/2_5_1_\347\233\221\346\216\247\346\250\241\345\235\227.md"
@@ -0,0 +1,180 @@
+# 监控模块
+
+agentUniverse监控模块，主要围绕agent运行时的模型调用/token开销等进行数据追踪与记录。针对**目前框架已开放的模型调用追踪能力和agent调用追踪能力**，本文将详细介绍如何使用这两个功能。
+
+## 监控配置
+
+在agentUniverse的主配置文件`config.toml`中配置监控模块配置信息，如下：
+
+```toml
+[MONITOR]
+activate = true
+dir = './monitor'
+```
+
+- **`activate`**: 监控模块总开关，默认关闭，设置为true后将开启agent运行时的LLM调用追踪功能和agent调用追踪功能。
+- **`dir`**: 监控模块对应的本地记录存储目录，默认为运行时，上一层级下的monitor目录，用户可自定义配置目录路径。
+
+### 模型粒度配置
+
+针对LLM调用追踪能力，agentUniverse同样支持模型粒度配置，当监控模块主开关打开后，可以通过LLM的yaml文件选择关闭特定模型调用追踪功能。
+
+比如用户自定义的`demo_llm`模型，tracing设置为false，则关闭该模型的调用追踪功能。
+
+```yaml
+name: 'demo_llm'
+description: 'demo openai'
+model_name: 'gpt-4o'
+max_tokens: 1000
+max_retries: 2
+tracing: false
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.default.default_openai_llm'
+  class: 'DefaultOpenAILLM'
+```
+
+特别说明：agentUniverse主配置文件的监控模块总开关**优先级最高**，若activate配置为false的情况下，模型粒度配置不生效。
+
+### Agent粒度配置
+
+针对agent调用追踪能力，agentUniverse同样支持agent粒度配置，当监控模块主开关打开后，可以通过agent的yaml文件选择关闭特定agent调用追踪功能。
+
+比如用户自定义的`demo_agent`智能体，tracing设置为false，则关闭该智能体的调用追踪功能。
+
+```yaml
+info:
+  name: 'demo_agent'
+  description: 'demo agent'
+profile:
+  tracing: false
+  prompt_version: demo_agent_prompt.cn
+  llm_model:
+    name: 'qwen_llm'
+plan:
+  planner:
+    name: 'rag_planner'
+action:
+  tool:
+    - 'google_search_tool'
+memory:
+  name: ''
+metadata:
+  type: 'AGENT'
+  module: 'sample_standard_app.app.core.agent.rag_agent_case.demo_rag_agent'
+  class: 'DemoRagAgent'
+```
+
+特别说明：agentUniverse主配置文件的监控模块总开关**优先级最高**，若activate配置为false的情况下，agent粒度配置不生效。
+
+## 监控模块说明
+
+### 模型调用追踪
+
+用户若使用当前agentUniverse支持的**默认模型类**，则如上文所述配置完成后即可使用该功能。
+
+#### trace_llm装饰器
+
+若用户根据agentUniverse的模型基类LLM做自定义扩展，实现自定义模型调用，则需要在自定义模型类的调用方法call/acall中增加@trace_llm装饰器功能。
+
+如下自定义模型示例代码：
+
+```python
+from typing import Any, Iterator, Union, AsyncIterator
+
+from agentuniverse.llm.llm import LLM, LLMOutput
+from agentuniverse.base.annotation.trace import trace_llm
+
+
+class DemoLLM(LLM):
+
+    @trace_llm
+    def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]:
+        pass
+
+    @trace_llm
+    async def acall(self, *args: Any, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]:
+        pass
+```
+
+agentUniverse通过`@trace_llm`装饰器实现，agent在调用对应LLM
+call/acall方法时，采集模型prompt和response，将信息json序列化后存储到上文监控配置对应的本地存储目录下，以jsonl文件的形式按小时为单位分割。
+
+#### 具体效果
+
+调用agentUniverse sample工程中的demo_rag_agent，使用qwen-turbo模型，query为分析下巴菲特减持比亚迪的原因，模型调用追踪功能捕捉到的数据如下：
+
+```json
+{
+  "source": "QWenOpenAIStyleLLM.acall",
+  "date": "2024-06-24 16:27:14",
+  "llm_input": {
+    "messages": [
+      {
+        "role": "system",
+        "content": "你是一位精通信息分析的ai助手。\\n 你的目标是判断问题对应的答案是否提供了有价值的信息，并对问题的答案做出建议和评价"
+      },
+      {
+        "role": "user",
+        "content": "你需要遵守的规则是:\\n1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。\\n2. 结构化答案生成，必要时通过空行提升阅读体验。\\n 需要回答的问题是: 分析下巴菲特减持比亚迪的原因\\n"
+      }
+    ]
+  },
+  "kwargs": {
+    "model": "qwen-turbo",
+    "stream": false,
+    "n": 1,
+    "temperature": 0.5,
+    "max_tokens": 1000
+  },
+  "llm_output": "巴菲特减持比亚迪股票的原因可以从几个方面来分析：\\n\\n1. **投资策略调整**：尽管巴菲特通常倾向于长期持有优质股票，但投资组合管理需要灵活性。他可能会根据市场动态、行业趋势和个人评估的变化，适时调整持仓以优化资产配置或分散风险。\\n\\n2. **估值与预期回报**：减持可能反映了巴菲特对比亚迪当前股价与他内在价值评估的差距。尽管比亚迪业绩强劲，但如果他认为股价过高，可能会选择部分兑现利润。\\n 综上所述，巴菲特减持比亚迪股票可能是基于上述因素的综合考虑，但具体原因只有巴菲特和芒格本人了解。值得注意的是，尽管减持，他们对比亚迪的长期看好并未改变，这从芒格的演讲和持续的股东大会支持可以看出。"
+}
+```
+
+- **`source`**: agent运行时LLM的调用来源
+- **`date`**: LLM调用时间
+- **`llm_input`**: LLM调用message及模型参数
+- **`llm_output`**: LLM输出文本段信息
+
+### Agent调用追踪
+
+#### trace_agent装饰器
+
+agentUniverse通过`@trace_agent`装饰器实现，agent在调用run方法时，采集agent输入和输出，将信息json序列化后存储到上文监控配置对应的本地存储目录下，以jsonl文件的形式按小时及单智能体为单位分割。
+
+#### 具体效果
+
+调用agentUniverse sample工程中的demo_rag_agent，query为分析下巴菲特减持比亚迪的原因，agent调用追踪功能捕捉到的数据如下：
+
+```json
+{
+  "source": "demo_rag_agent",
+  "date": "2024-06-27 19:26:46",
+  "agent_input": {
+    "kwargs": {
+      "input": "分析下巴菲特减持比亚迪的原因"
+    }
+  },
+  "agent_output": {
+    "chat_history": [
+      {
+        "content": "分析下巴菲特减持比亚迪的原因",
+        "type": "human"
+      },
+      {
+        "content": "巴菲特减持比亚迪的原因可能涉及多个方面：\n\n1. **投资回报与资产配置**：随着比亚迪股价的大幅上涨，特别是新能源汽车业务的强劲表现，巴菲特可能认为已经达到其预期的回报，需要将资本转向其他潜在收益更高的投资。\n\n2. **芒格影响减弱**：芒格去世后，巴菲特作为伯克希尔·哈撒韦的唯一决策者，投资策略可能会有所调整，这可能影响他对比亚迪的投资态度。\n\n3. **资本结构调整**：巴菲特可能寻求更均衡的投资组合，通过减持比亚迪来优化伯克希尔·哈撒韦的整体资产配置。\n\n4. **风险控制**：持股比例降低至5%以下后，巴菲特的减持速度可能会加快，这可能是为了降低单一投资的风险。\n\n5. **市场动态**：在比亚迪股价下跌时未大幅减持，可能表明他之前是在等待一个更合适的市场时机。\n\n综合以上分析，巴菲特减持比亚迪的原因可能包含对投资回报的追求、对公司估值的判断以及个人投资策略的更新。然而，具体原因还需更多官方信息来确认。",
+        "type": "ai"
+      }
+    ],
+    "background": "针对巴菲特减持比亚迪的原因，目前市场依然处于猜想的状态，但从近年来的投资举动来看，也大概可以看出巴菲特减持比亚迪的一些想法。 我们可以从巴菲特 ... 为何巴菲特减持比亚迪？ 综合多家媒体的分析报道，巴菲特减持比亚迪股份可能是出于多种考虑，包括为了更好地配置资本、实现投资回报、投资策略的调整以及 ... 有私募人士分析认为，巴菲特从2008年建仓至今，比亚迪在新能源汽车的快速渗透下，营收和利润也达到了空前的规模，股价近30倍的涨幅，伯克希尔减持比亚迪 ... 对于巴菲特减持原因，相关人士表示，“公司在和对方沟通。”问及公司估值是否偏高，上述人士表示，“公司经营状况良好，销量、利润等保持增长。” 6月18日， ... 据证券时报e公司报道，中泰国际策略分析师颜招骏认为，巴菲特减持应该是看到长线的基本面发生变化或估值已经大幅偏离内在价值。一旦持股比例降至5%， ... 在比亚迪股票处于大幅下跌的阶段，伯克希尔哈撒韦则采取了观望的态度，减持力度并未有太明显。对股神巴菲特来说，在股价处于高位的时候获利了结、锁定 ... 相较于常规动力电池，刀片电池内部体积利用率增长了50%以上，整体体积能量密度可以媲美高能量密度的三元锂电池，能够在保证安全的前提下，提升新能源车的 ... ... 巴菲特第一次减持比亚迪了。从最初的19.92%到现在的5.99%，巴菲特对比亚迪的投资似乎正在逐步减少。有分析师指出，一旦持股比例降至5%，巴菲特的减持速度可能会加快。 巴菲特减持比亚迪的真实原因如何？对此，有各种各样的分析。 有的从地缘 ... 有的从地缘政治切入，有的从芒格去世后，巴菲特独掌大权后的风格切换进行分析， ... 市场分析认为，巴菲特的减持可能是为了更好地配置资本，并且进行获利了结。巴菲特本人也曾表示，减持比亚迪是为了找到这些资金更好的配置用途。同时， ...",
+    "date": "2024-06-27",
+    "input": "分析下巴菲特减持比亚迪的原因",
+    "output": "巴菲特减持比亚迪的原因可能涉及多个方面：\n\n1. **投资回报与资产配置**：随着比亚迪股价的大幅上涨，特别是新能源汽车业务的强劲表现，巴菲特可能认为已经达到其预期的回报，需要将资本转向其他潜在收益更高的投资。\n\n2. **芒格影响减弱**：芒格去世后，巴菲特作为伯克希尔·哈撒韦的唯一决策者，投资策略可能会有所调整，这可能影响他对比亚迪的投资态度。\n\n3. **资本结构调整**：巴菲特可能寻求更均衡的投资组合，通过减持比亚迪来优化伯克希尔·哈撒韦的整体资产配置。\n\n4. **风险控制**：持股比例降低至5%以下后，巴菲特的减持速度可能会加快，这可能是为了降低单一投资的风险。\n\n5. **市场动态**：在比亚迪股价下跌时未大幅减持，可能表明他之前是在等待一个更合适的市场时机。\n\n综合以上分析，巴菲特减持比亚迪的原因可能包含对投资回报的追求、对公司估值的判断以及个人投资策略的更新。然而，具体原因还需更多官方信息来确认。"
+  }
+}
+```
+
+- **`source`**: Agent运行时的调用来源（智能体名称）
+- **`date`**: Agent调用时间
+- **`agent_input`**: Agent调用输入参数
+- **`agent_output`**: Agent输出参数
\ No newline at end of file
diff --git "a/docs/guidebook/zh/3_1_2_0_\346\250\241\345\236\213\345\210\227\350\241\250.md" "b/docs/guidebook/zh/3_1_2_0_\346\250\241\345\236\213\345\210\227\350\241\250.md"
index 5e62a724..6a7fbed6 100644
--- "a/docs/guidebook/zh/3_1_2_0_\346\250\241\345\236\213\345\210\227\350\241\250.md"
+++ "b/docs/guidebook/zh/3_1_2_0_\346\250\241\345\236\213\345\210\227\350\241\250.md"
@@ -10,6 +10,9 @@
 | [百川](3_1_2_百川使用.md)              |
 | [Claude](3_1_2_Claude使用.md)      |
 | [ollama](3_1_2_Ollama使用.md)      |
+| [DeepSeek](3_1_2_DeepSeek使用.md)      |
+
+为方便用户接入OpenAI风格协议的模型，提供基于OpenAI通用协议接入包装对象 [OpenAIStyleLLM](3_1_2_OpenAIStyleLLM使用.md)。
 
 未在列表中的模型您可以根据[模型定义](2_2_2_模型定义与使用.md)中的步骤自定义接入任何模型。
 
diff --git "a/docs/guidebook/zh/3_1_2_DeepSeek\344\275\277\347\224\250.md" "b/docs/guidebook/zh/3_1_2_DeepSeek\344\275\277\347\224\250.md"
new file mode 100644
index 00000000..7a243ed2
--- /dev/null
+++ "b/docs/guidebook/zh/3_1_2_DeepSeek\344\275\277\347\224\250.md"
@@ -0,0 +1,35 @@
+# DeepSeek 使用
+## 1. 创建相关文件
+创建一个yaml文件，例如 user_deepseek_llm.yaml
+将以下内容粘贴到您的user_deepseek_llm.yaml文件当中
+```yaml
+name: 'user_deepseek_llm'
+description: 'default default_deepseek_llm llm with spi'
+model_name: 'deepseek-chat'
+max_tokens: 1000
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.default.deep_seek_openai_style_llm'
+  class: 'DefaultDeepSeekLLM'
+```
+## 2. 环境设置
+### 2.1 通过python代码配置
+必须配置：DEEPSEEK_API_KEY  
+可选配置：DEEPSEEK_API_BASE
+```python
+import os
+os.environ['DEEPSEEK_API_KEY'] = 'sk-***'
+os.environ['DEEPSEEK_API_BASE'] = 'https://xxxxxx'
+```
+### 2.2 通过配置文件配置
+在项目的config目录下的custom_key.toml当中，添加配置：
+```toml
+DEEPSEEK_API_KEY="sk-******"
+DEEPSEEK_API_BASE="https://xxxxxx"
+```
+## 3. DEEPSEEK API KEY 获取
+参考 DEEPSEEK 官方文档：https://platform.deepseek.com/api_keys
+
+## 4. Tips
+在agentuniverse中，我们已经创建了一个name为default_deepseek_llm的llm,用户在配置DEEPSEEK_API_KEY之后可以直接使用。
+
diff --git "a/docs/guidebook/zh/3_1_2_OpenAIStyleLLM\344\275\277\347\224\250.md" "b/docs/guidebook/zh/3_1_2_OpenAIStyleLLM\344\275\277\347\224\250.md"
new file mode 100644
index 00000000..e2078d9c
--- /dev/null
+++ "b/docs/guidebook/zh/3_1_2_OpenAIStyleLLM\344\275\277\347\224\250.md"
@@ -0,0 +1,39 @@
+# OpenAIStyleLLM 使用
+通过该配置，您可以连接任何遵守OpenAI标准的模型服务
+## 1. 创建相关文件
+创建一个yaml文件，例如 user_openai_style_llm.yaml
+将以下内容粘贴到您的user_openai_style_llm.yaml文件当中
+```yaml
+name: 'deep_seek_llm'
+description: 'demo deep_seek llm with spi'
+model_name: 'deepseek-chat'
+max_tokens: 4000
+max_context_length: 32000
+api_key_env: 'DEEPSEEK_API_KEY'
+api_base_env: 'DEEPSEEK_API_BASE'
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.openai_style_llm'
+  class: 'OpenAIStyleLLM'
+```
+参数说明：
+    max_context_length: 模型所能承接的上下文
+    api_key_env: api key的env变量名
+    api_base_env: api base的env变量名
+上述参数必须配置,服务启动时会从环境变量中加载相关的值
+## 2. 环境设置
+必须配置：$api_key_env, $api_base_env
+配置文件中api_key_env与api_base_env分别为DEEPSEEK_API_KEY、DEEPSEEK_API_BASE，所以配置如下：
+### 2.1 通过python代码配置
+```python
+import os
+os.environ['DEEPSEEK_API_KEY'] = 'sk-***'
+os.environ['DEEPSEEK_API_BASE'] = 'https://xxxxxx'
+```
+### 2.2 通过配置文件配置
+在项目的config目录下的custom_key.toml当中，添加配置：
+```toml
+DEEPSEEK_API_KEY="DEEPSEEK_API_KEY"
+DEEPSEEK_API_BASE="https://xxxxxx"
+```
+注意，这里必须与配置文件中锁配置的api_key_env、api_base_env一致
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"
index a1d4c23b..1b5d5f24 100644
--- "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"
@@ -1,22 +1,22 @@
 # Docker容器化部署
 
-AgentUniverse提供标准的工作环境镜像用于容器化部署AgentUniverse工程。本文档将介绍如何基于工作环境镜像部署您自己的工程项目。
+AgentUniverse提供标准的工作环境镜像用于容器化部署AgentUniverse工程。本文档将介绍如何基于工作环境镜像部署您自己的工程项目。镜像tag列表可以在[这里获取](https://cr.console.aliyun.com/repository/cn-hangzhou/agent_universe/agent_universe/images)。
 
 ## 准备工作
 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
+docker pull registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.9_centos8
 ```
 
 
 ## 方法一：挂载宿主机路径
 您可以通过将宿主机目录挂载您的项目至容器内路径，参考命令如下:
 ```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
+docker run -d -p 8888:8888 -e OPENAI_API_KEY=XXX -v ./sample_standard_app/:/usr/local/etc/workspace/project/sample_standard_app registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.9_centos8
 ```
 其中`-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`目录，容器内目录为固定值，不可修改。
+`-v {local_dir}:/usr/local/etc/workspace/project/{local_dir_name}`表示把本地`local_dir`目录挂载至容器内的`/usr/local/etc/workspace/project`目录，容器内目录为固定值，不可修改,`local_dir_name`表示你本地文件夹的名字，也就是`local_dir`的最后一级目录名称。
 
 ### 使用多个容器挂载相同目录时，有以下几点建议：
 由于多个容器在相同的挂载目录进行文件的读写，有几处设置可以优化并发读写的冲突：
diff --git "a/docs/guidebook/zh/5_1_2_K8S\351\203\250\347\275\262.md" "b/docs/guidebook/zh/5_1_2_K8S\351\203\250\347\275\262.md"
index a651ecf5..20a07020 100644
--- "a/docs/guidebook/zh/5_1_2_K8S\351\203\250\347\275\262.md"
+++ "b/docs/guidebook/zh/5_1_2_K8S\351\203\250\347\275\262.md"
@@ -1,5 +1,5 @@
 # K8S集群部署
-AgentUniverse 提供标准的工作环境镜像，并且支持在 Kubernetes (K8S) 集群上容器化部署。本指南将指导您如何利用这些工作环境镜像，在 K8S 上部署和搭建集群。
+AgentUniverse 提供标准的工作环境镜像，并且支持在 Kubernetes (K8S) 集群上容器化部署。本指南将指导您如何利用这些工作环境镜像，在 K8S 上部署和搭建集群。镜像tag列表您可以在[这里获取](https://cr.console.aliyun.com/repository/cn-hangzhou/agent_universe/agent_universe/images)。
 
 官方K8S使用文档：[Kubernetes Setup Documentation](https://kubernetes.io/docs/setup/)
 
@@ -32,7 +32,7 @@ spec:
     spec:
       containers:
       - name: agentuniverse-container
-        image: registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.5_centos8_beta
+        image: registry.cn-hangzhou.aliyuncs.com/agent_universe/agent_universe:0.0.9_centos8
         ports:
         - containerPort: 8888
         command: ["/bin/bash", "-c"]
diff --git a/pyproject.toml b/pyproject.toml
index e29498b8..d3c32309 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "agentUniverse"
-version = "0.0.9"
+version = "0.0.10"
 description = "agentUniverse is a framework for developing applications powered by multi-agent base on large language model."
 
 authors = ["AntGroup <jerry.zzw@antgroup.com>"]
@@ -51,6 +51,11 @@ dashscope = "^1.19.1"
 anthropic = "^0.26.0"
 ollama = '^0.2.1'
 langchain-anthropic = '^0.1.13'
+numpy = '^1.26.0'
+pandas = "^2.2.2"
+pyarrow = "^16.1.0"
+duckduckgo-search = "^6.1.7"
+wikipedia= "^1.4.0"
 
 [tool.poetry.extras]
 log_ext = ["aliyun-log-python-sdk"]
diff --git a/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml b/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml
index 2fd13785..8732f8a1 100644
--- a/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml
+++ b/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml
@@ -15,8 +15,10 @@ profile:
 #    model_name: 'Baichuan2-Turbo'
 #    name: 'qwen_llm'
 #    model_name: 'qwen-turbo'
-    name: 'wenxin_llm'
-    model_name: 'ERNIE-3.5-8K'
+#    name: 'wenxin_llm'
+#    model_name: 'ERNIE-3.5-8K'
+#    name: 'deep_seek_llm'
+    name: 'default_deepseek_llm'
 plan:
   planner:
     name: 'rag_planner'
diff --git a/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml b/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml
index bf917fcd..03ced866 100644
--- a/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml
+++ b/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml
@@ -1,6 +1,6 @@
 info:
   name: 'law_rag_agent'
-  description: 'law rag agent'
+  description: '一个法律顾问，可以根据给出的事件，以及提供的背景知识做出客观的司法判断。'
 profile:
   introduction: 你是一位精通信息分析的ai法律顾问。
   target: 你的目标是根据给出的事件，以及提供的背景知识做出客观的司法判断。
diff --git a/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml b/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml
index 8a38838d..b9a4e02a 100644
--- a/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml
+++ b/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml
@@ -5,11 +5,17 @@ profile:
   prompt_version: qwen_react_agent.cn
   llm_model:
     name: 'default_qwen_llm'
+    model_name: 'qwen-max'
     temperature: 0
 action:
   tool:
     - 'google_search_tool'
     - 'python_runner'
+  knowledge:
+    - 'civil_law_knowledge'
+    - 'criminal_law_knowledge'
+  agent:
+    - 'law_rag_agent'
 plan:
   planner:
     name: 'react_planner'
diff --git a/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml b/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml
index 86ddd6b0..3cf789e9 100644
--- a/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml
+++ b/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml
@@ -1,5 +1,5 @@
 name: 'civil_law_knowledge'
-description: 'civil law knowledge'
+description: 民法知识库，可以查询民法典法律相关内容'
 metadata:
   type: 'KNOWLEDGE'
   module: 'sample_standard_app.app.core.knowledge.civil_law_knowledge'
diff --git a/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml b/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml
index 5a1b2a8c..184b16f9 100644
--- a/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml
+++ b/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml
@@ -1,5 +1,5 @@
 name: 'criminal_law_knowledge'
-description: 'criminal law knowledge'
+description: '刑法知识库，可以查询与刑法相关的内容'
 metadata:
   type: 'KNOWLEDGE'
   module: 'sample_standard_app.app.core.knowledge.criminal_law_knowledge'
diff --git a/sample_standard_app/app/core/llm/deep_seek_opneai_llm.yaml b/sample_standard_app/app/core/llm/deep_seek_opneai_llm.yaml
new file mode 100644
index 00000000..a4aebb15
--- /dev/null
+++ b/sample_standard_app/app/core/llm/deep_seek_opneai_llm.yaml
@@ -0,0 +1,11 @@
+name: 'deep_seek_llm'
+description: 'demo deep_seek llm with spi'
+model_name: 'deepseek-chat'
+max_tokens: 4000
+max_context_length: 32000
+api_key_env: 'DEEPSEEK_API_KEY'
+api_base_env: 'DEEPSEEK_API_BASE'
+metadata:
+  type: 'LLM'
+  module: 'agentuniverse.llm.openai_style_llm'
+  class: 'OpenAIStyleLLM'
\ No newline at end of file
diff --git a/sample_standard_app/app/core/tool/langchain_tool/__init__.py b/sample_standard_app/app/core/tool/langchain_tool/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/sample_standard_app/app/core/tool/langchain_tool/duckduckgo_search.yaml b/sample_standard_app/app/core/tool/langchain_tool/duckduckgo_search.yaml
new file mode 100644
index 00000000..9bbb2977
--- /dev/null
+++ b/sample_standard_app/app/core/tool/langchain_tool/duckduckgo_search.yaml
@@ -0,0 +1,13 @@
+name: 'duckduckgo_search'
+description: ''
+tool_type: 'api'
+input_keys: ['input']
+langchain:
+  module: langchain.tools
+  class_name: DuckDuckGoSearchResults
+  init_params:
+    backend: news
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool.langchain_tool'
+  class: 'LangChainTool'
\ No newline at end of file
diff --git a/sample_standard_app/app/core/tool/langchain_tool/human_input_run.yaml b/sample_standard_app/app/core/tool/langchain_tool/human_input_run.yaml
new file mode 100644
index 00000000..405b6ea8
--- /dev/null
+++ b/sample_standard_app/app/core/tool/langchain_tool/human_input_run.yaml
@@ -0,0 +1,11 @@
+name: 'human_input_run'
+description: ''
+tool_type: 'api'
+input_keys: ['input']
+langchain:
+  module: langchain_community.tools
+  class_name: HumanInputRun
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool.langchain_tool'
+  class: 'LangChainTool'
\ No newline at end of file
diff --git a/sample_standard_app/app/core/tool/langchain_tool/langchain_tool.py b/sample_standard_app/app/core/tool/langchain_tool/langchain_tool.py
new file mode 100644
index 00000000..5a8a3d7a
--- /dev/null
+++ b/sample_standard_app/app/core/tool/langchain_tool/langchain_tool.py
@@ -0,0 +1,50 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+import importlib
+import json
+# @Time    : 2024/6/24 11:42
+# @Author  : weizjajj 
+# @Email   : weizhongjie.wzj@antgroup.com
+# @FileName: langchain_tool.py
+
+from typing import Optional, Type
+
+from langchain_community.tools import DuckDuckGoSearchResults
+from langchain_core.tools import BaseTool
+
+from agentuniverse.agent.action.tool.tool import Tool, ToolInput
+from agentuniverse.base.config.component_configer.configers.tool_configer import ToolConfiger
+
+
+class LangChainTool(Tool):
+    name: Optional[str] = ""
+    description: Optional[str] = ""
+    tool: Optional[BaseTool] = None
+
+    def execute(self, tool_input: ToolInput):
+        input = tool_input.get_data("input")
+        callbacks = tool_input.get_data("callbacks", None)
+        return self.tool.run(input, callbacks=callbacks)
+
+    def initialize_by_component_configer(self, component_configer: ToolConfiger) -> 'Tool':
+        super().initialize_by_component_configer(component_configer)
+        self.tool = self.init_langchain_tool(component_configer)
+        if not component_configer.description:
+            self.description = self.tool.description
+        return self
+
+    def init_langchain_tool(self, component_configer):
+        langchain_info = component_configer.configer.value.get('langchain')
+        module = langchain_info.get("module")
+        class_name = langchain_info.get("class_name")
+        module = importlib.import_module(module)
+        clz = getattr(module, class_name)
+        init_params = langchain_info.get("init_params")
+        self.get_langchain_tool(init_params, clz)
+        return self.tool
+
+    def get_langchain_tool(self, init_params: dict, clz: Type[BaseTool]):
+        if init_params:
+            self.tool = clz(**init_params)
+        else:
+            self.tool = clz()
diff --git a/sample_standard_app/app/core/tool/langchain_tool/wikipedia_query.py b/sample_standard_app/app/core/tool/langchain_tool/wikipedia_query.py
new file mode 100644
index 00000000..6c4e65a9
--- /dev/null
+++ b/sample_standard_app/app/core/tool/langchain_tool/wikipedia_query.py
@@ -0,0 +1,19 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/6/27 17:38
+# @Author  : weizjajj 
+# @Email   : weizhongjie.wzj@antgroup.com
+# @FileName: wikipedia_query.py
+
+
+from langchain_community.tools import WikipediaQueryRun
+from langchain_community.utilities import WikipediaAPIWrapper
+
+from sample_standard_app.app.core.tool.langchain_tool.langchain_tool import LangChainTool
+
+
+class WikipediaTool(LangChainTool):
+    def init_langchain_tool(self, component_configer):
+        wrapper = WikipediaAPIWrapper()
+        return WikipediaQueryRun(api_wrapper=wrapper)
diff --git a/sample_standard_app/app/core/tool/langchain_tool/wikipedia_query.yaml b/sample_standard_app/app/core/tool/langchain_tool/wikipedia_query.yaml
new file mode 100644
index 00000000..71fafe62
--- /dev/null
+++ b/sample_standard_app/app/core/tool/langchain_tool/wikipedia_query.yaml
@@ -0,0 +1,8 @@
+name: 'wikipedia_query'
+description: ''
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.langchain_tool.wikipedia_query'
+  class: 'WikipediaTool'
\ No newline at end of file
diff --git a/sample_standard_app/app/core/tool/request_get_tool.yaml b/sample_standard_app/app/core/tool/request_get_tool.yaml
new file mode 100644
index 00000000..97426045
--- /dev/null
+++ b/sample_standard_app/app/core/tool/request_get_tool.yaml
@@ -0,0 +1,16 @@
+name: 'requests_get'
+description: 'A portal to the internet. Use this when you need to get specific
+    content from a website. Input should be a  url (i.e. https://www.google.com).
+    The output will be the text response of the GET request.
+        ```'
+headers:
+  content-type: 'application/json'
+method: 'GET'
+json_parser: false
+response_content_type: json
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.request_tool'
+  class: 'RequestTool'
\ No newline at end of file
diff --git a/sample_standard_app/app/core/tool/request_post_tool.yaml b/sample_standard_app/app/core/tool/request_post_tool.yaml
new file mode 100644
index 00000000..6a5a8c8f
--- /dev/null
+++ b/sample_standard_app/app/core/tool/request_post_tool.yaml
@@ -0,0 +1,19 @@
+name: 'requests_post'
+description: 'Use this when you want to POST to a website.
+    Input should be a json string with two keys: "url" and "data".
+    The value of "url" should be a string, and the value of "data" should be a dictionary of 
+    key-value pairs you want to POST to the url.
+    Be careful to always use double quotes for strings in the json string
+    The output will be the text response of the POST request.
+        ```'
+headers:
+  content-type: 'application/json'
+method: 'POST'
+json_parser: true
+response_content_type: json
+tool_type: 'api'
+input_keys: ['input']
+metadata:
+  type: 'TOOL'
+  module: 'sample_standard_app.app.core.tool.request_tool'
+  class: 'RequestTool'
\ No newline at end of file
diff --git a/sample_standard_app/app/core/tool/request_tool.py b/sample_standard_app/app/core/tool/request_tool.py
new file mode 100644
index 00000000..ae007614
--- /dev/null
+++ b/sample_standard_app/app/core/tool/request_tool.py
@@ -0,0 +1,69 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/6/24 10:19
+# @Author  : weizjajj 
+# @Email   : weizhongjie.wzj@antgroup.com
+# @FileName: request_tool.py
+
+
+from typing import Optional
+
+from langchain_community.utilities.requests import GenericRequestsWrapper
+from langchain_core.utils.json import parse_json_markdown
+
+from agentuniverse.agent.action.tool.tool import Tool, ToolInput
+from agentuniverse.base.config.component_configer.configers.tool_configer import ToolConfiger
+from agentuniverse.base.util.logging.logging_util import LOGGER
+
+
+class RequestTool(Tool):
+    method:Optional[str] = 'GET'
+    headers: Optional[dict]= {}
+    response_content_type:Optional[str] = 'text'
+    requests_wrapper: Optional[GenericRequestsWrapper] = None
+    json_parser: Optional[bool] = False
+
+    @staticmethod
+    def _clean_url(url: str) -> str:
+        """Strips quotes from the url."""
+        return url.strip("\"'")
+
+    def execute(self, tool_input: ToolInput):
+        input_params: str = tool_input.get_data('input')
+        if self.json_parser:
+            try:
+                parse_data = parse_json_markdown(input_params)
+                return self.execute_by_method(**parse_data)
+            except Exception as e:
+                LOGGER.error(f'execute request error input{input_params} error{e}')
+                return str(e)
+        else:
+            return self.execute_by_method(input_params)
+
+    def execute_by_method(self, url: str, data: dict = None, **kwargs):
+        url = self._clean_url(url)
+        if self.method == 'GET':
+            return self.requests_wrapper.get(url)
+        elif self.method == 'POST':
+            return self.requests_wrapper.post(url, data=data)
+        elif self.method == 'PUT':
+            return self.requests_wrapper.put(url, data=data)
+        elif self.method == 'DELETE':
+            return self.requests_wrapper.delete(url)
+        else:
+            raise ValueError(f"Unsupported method: {self.method}")
+
+    def initialize_by_component_configer(self, component_configer: ToolConfiger) -> 'Tool':
+        """
+        :param component_configer:
+        :return:
+        """
+        self.headers = component_configer.configer.value.get('headers')
+        self.method = component_configer.configer.value.get('method')
+        self.response_content_type = component_configer.configer.value.get('response_content_type')
+        self.requests_wrapper = GenericRequestsWrapper(
+            headers=self.headers,
+            response_content_type=self.response_content_type
+        )
+        return super().initialize_by_component_configer(component_configer)
diff --git a/sample_standard_app/config/custom_key.toml.sample b/sample_standard_app/config/custom_key.toml.sample
index ccde297e..f0bdf78c 100644
--- a/sample_standard_app/config/custom_key.toml.sample
+++ b/sample_standard_app/config/custom_key.toml.sample
@@ -1,4 +1,43 @@
 # Example file of custom_key.toml. Rename to custom_key.toml while using.
 [KEY_LIST]
 # Perform a full component scan and registration for all the paths under this list.
-example_key = 'AnExampleKey'
\ No newline at end of file
+example_key = 'AnExampleKey'
+
+# models
+#kimi default name: default_kimi_llm
+#KIMI_API_KEY='sk-xxxxxxxx'
+#
+##Qwen default name: default_qwen_llm
+#DASHSCOPE_API_KEY='sk-xxxxxx'
+#
+##Opean default name: default_openai_llm
+#OPENAI_API_KEY='sk-xxxxxx'
+#
+##DEEPSEEK default name: default_deepseek_llm
+#DEEPSEEK_API_KEY='sk-xxxxxxx'
+#DEEPSEEK_API_BASE='https://api.deepseek.com/v1'
+#
+## WenXin default name: default_wenxin_llm
+#QIANFAN_AK='xxxx'
+#QIANFAN_SK='xxxx'
+#
+##Ollama default name: default_ollama_llm
+#OLLAMA_BASE_URL='xxxxxx'
+#
+##claude default name: default_claude_llm
+#ANTHROPIC_API_KEY='xxxxxx'
+#ANTHROPIC_API_URL='xxxxxx'
+#
+##baichuan default name: default_baichuan_llm
+#BAICHUAN_API_KEY='xxxxxx'
+
+
+# search
+#Google search
+#SERPER_API_KEY='xxxxxx'
+#
+##search api
+#SEARCHAPI_API_KEY='xxxxxx'
+#
+##bing seacrh
+#BING_SUBSCRIPTION_KEY='xxxxxx'
\ No newline at end of file
diff --git a/sample_standard_app/config/gunicorn_config.toml b/sample_standard_app/config/gunicorn_config.toml
index 2dd3b915..3b8836de 100644
--- a/sample_standard_app/config/gunicorn_config.toml
+++ b/sample_standard_app/config/gunicorn_config.toml
@@ -1,5 +1,5 @@
 [GUNICORN_CONFIG]
-bind = '127.0.0.1:8888'
+bind = '0.0.0.0:8888'
 backlog = 2048
 worker_class = 'gthread'
 threads = 4
diff --git a/sample_standard_app/pyproject.toml b/sample_standard_app/pyproject.toml
index 7b763d8d..eab8e02b 100644
--- a/sample_standard_app/pyproject.toml
+++ b/sample_standard_app/pyproject.toml
@@ -11,7 +11,7 @@ packages = [
 
 [tool.poetry.dependencies]
 python = "^3.10"
-agentUniverse = "^0.0.5"
+agentUniverse = "^0.0.9"
 
 [tool.poetry.group.dev.dependencies]
 pytest = "^7.2.0"


Test patch:
diff --git a/sample_standard_app/app/test/test_deep_seek_llm.py b/sample_standard_app/app/test/test_deep_seek_llm.py
new file mode 100644
index 00000000..8afb55c8
--- /dev/null
+++ b/sample_standard_app/app/test/test_deep_seek_llm.py
@@ -0,0 +1,56 @@
+# !/usr/bin/env python3
+# -*- coding:utf-8 -*-
+
+# @Time    : 2024/5/22 16:25
+# @Author  : weizjajj 
+# @Email   : weizhongjie.wzj@antgroup.com
+# @FileName: test_wenxin_llm.py
+
+
+import asyncio
+import time
+import unittest
+
+from agentuniverse.base.agentuniverse import AgentUniverse
+from agentuniverse.llm.default.wenxin_llm import WenXinLLM
+from agentuniverse.llm.llm_manager import LLMManager
+
+
+class DeepSeekLLMTest(unittest.TestCase):
+    """Test cases for the reviewing agent"""
+
+    def setUp(self) -> None:
+        AgentUniverse().start(config_path='../../config/config.toml')
+
+    def test_reviewing_agent(self):
+        llm: WenXinLLM = LLMManager().get_instance_obj("deep_seek_llm")
+        res = llm.call(
+            messages=[{"role": "user", "content": "你好"}],
+            streaming=True
+        )
+        print(res)
+        for item in res:
+            print(item)
+
+        langchain_llm = llm.as_langchain()
+        print(langchain_llm.invoke(input="你好"))
+        time.sleep(1)
+        asyncio.run(self.call_stream())
+
+    async def call_stream(self):
+        llm: WenXinLLM = LLMManager().get_instance_obj("deep_seek_llm")
+        res = await llm.acall(
+            messages=[{"role": "user", "content": "你好"}],
+            streaming=True
+        )
+        print(res)
+        async for item in res:
+            print(item)
+
+        langchain_llm = llm.as_langchain()
+        res = await langchain_llm.ainvoke(input="你好")
+        print(res)
+
+
+if __name__ == '__main__':
+    unittest.main()