From f51a2154eae9122f1dee6d91c4178f61f2f45aa3 Mon Sep 17 00:00:00 2001 From: "fangyaozheng@bytedance.com" Date: Thu, 11 Sep 2025 20:44:56 +0800 Subject: [PATCH 1/3] chore(builder): support tools in yaml file --- docs/docs/agent.md | 9 +++++++-- veadk/agent_builder.py | 21 +++++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/docs/agent.md b/docs/docs/agent.md index 3c87870f..b701c47f 100644 --- a/docs/docs/agent.md +++ b/docs/docs/agent.md @@ -129,6 +129,12 @@ root_agent: backend: local knowledgebase: backend: opensearch + tools: + - module: demo_tool # tool 所在的模块 + func: greeting # tool 的函数名称 + - module: tools.tool + func: count + sub_agents: sub_agents: - ${sub_agent_1} @@ -147,8 +153,7 @@ from veadk.agent_builder import AgentBuilder agent = AgentBuilder().build(path="./agent.yaml") ``` -函数`build`接收3个参数: +函数`build`接收 2 个参数: - `path`:配置文件路径 - `root_agent_identifier`:配置文件中主 Agent 的名称,默认为`root_agent` -- `tools`:主 agent 挂载的工具列表(子 Agent 工具列表暂未推出) diff --git a/veadk/agent_builder.py b/veadk/agent_builder.py index 30aebbab..f81cb045 100644 --- a/veadk/agent_builder.py +++ b/veadk/agent_builder.py @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import importlib + from google.adk.agents import BaseAgent -from google.adk.agents.llm_agent import ToolUnion from omegaconf import OmegaConf from veadk.a2a.remote_ve_agent import RemoteVeAgent @@ -48,8 +49,20 @@ def _build(self, agent_config: dict) -> BaseAgent: sub_agents.append(agent) agent_config.pop("sub_agents") + tools = [] + if agent_config.get("tools", []): + for tool in agent_config["tools"]: + module_name = tool["module"] + func_name = tool["func"] + + module = importlib.import_module(module_name) + func = getattr(module, func_name) + + tools.append(func) + agent_config.pop("tools") + agent_cls = AGENT_TYPES[agent_config["type"]] - agent = agent_cls(**agent_config, sub_agents=sub_agents) + agent = agent_cls(**agent_config, sub_agents=sub_agents, tools=tools) logger.debug("Build agent done.") @@ -72,14 +85,10 @@ def build( self, path: str, root_agent_identifier: str = "root_agent", - tools: list[ToolUnion] | None = None, ) -> BaseAgent: config = self._read_config(path) agent_config = config[root_agent_identifier] agent = self._build(agent_config) - if tools and isinstance(agent, Agent): - agent.tools = tools - return agent From a6b91690d6f27236137b3682eb2d0507fe99d831 Mon Sep 17 00:00:00 2001 From: "fangyaozheng@bytedance.com" Date: Fri, 12 Sep 2025 08:59:10 +0800 Subject: [PATCH 2/3] fix bugs --- veadk/auth/veauth/vesearch_veauth.py | 2 ++ veadk/memory/short_term_memory_processor.py | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/veadk/auth/veauth/vesearch_veauth.py b/veadk/auth/veauth/vesearch_veauth.py index 4ca2010a..26ff136e 100644 --- a/veadk/auth/veauth/vesearch_veauth.py +++ b/veadk/auth/veauth/vesearch_veauth.py @@ -49,6 +49,8 @@ def _fetch_token(self): ) try: self._token = res["Result"]["api_key_vos"][0]["api_key"] + + logger.info("Fetching VeSearch token done.") except KeyError: raise ValueError(f"Failed to get VeSearch token: {res}") diff --git a/veadk/memory/short_term_memory_processor.py b/veadk/memory/short_term_memory_processor.py index 1c2b951a..82c7fa29 100644 --- a/veadk/memory/short_term_memory_processor.py +++ b/veadk/memory/short_term_memory_processor.py @@ -20,7 +20,12 @@ from google.genai.types import Content, Part from litellm import completion -from veadk.config import getenv +from veadk.config import settings +from veadk.consts import ( + DEFAULT_MODEL_AGENT_API_BASE, + DEFAULT_MODEL_AGENT_NAME, + DEFAULT_MODEL_AGENT_PROVIDER, +) from veadk.prompts.prompt_memory_processor import render_prompt from veadk.utils.logger import get_logger @@ -62,9 +67,9 @@ def after_load_session(self, session: Session) -> Session: prompt = render_prompt(messages=messages) res = completion( - model=getenv("MODEL_AGENT_PROVIDER") + "/" + getenv("MODEL_AGENT_NAME"), - base_url=getenv("MODEL_AGENT_API_BASE"), - api_key=getenv("MODEL_AGENT_API_KEY"), + model=DEFAULT_MODEL_AGENT_PROVIDER + "/" + DEFAULT_MODEL_AGENT_NAME, + base_url=DEFAULT_MODEL_AGENT_API_BASE, + api_key=settings.model.api_key, messages=[ { "role": "user", From 0e900b7976dc1fd650dc1d9e806d7cf54b0f640c Mon Sep 17 00:00:00 2001 From: "fangyaozheng@bytedance.com" Date: Fri, 12 Sep 2025 10:01:38 +0800 Subject: [PATCH 3/3] support auto fetch cozeloop space id --- veadk/configs/tracing_configs.py | 27 +++++----- veadk/integrations/ve_cozeloop/ve_cozeloop.py | 52 +++++++++++-------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/veadk/configs/tracing_configs.py b/veadk/configs/tracing_configs.py index ff0b7424..585bc613 100644 --- a/veadk/configs/tracing_configs.py +++ b/veadk/configs/tracing_configs.py @@ -23,9 +23,11 @@ DEFAULT_APMPLUS_OTEL_EXPORTER_ENDPOINT, DEFAULT_APMPLUS_OTEL_EXPORTER_SERVICE_NAME, DEFAULT_COZELOOP_OTEL_EXPORTER_ENDPOINT, + DEFAULT_COZELOOP_SPACE_NAME, DEFAULT_TLS_OTEL_EXPORTER_ENDPOINT, DEFAULT_TLS_OTEL_EXPORTER_REGION, ) +from veadk.integrations.ve_cozeloop.ve_cozeloop import VeCozeloop from veadk.integrations.ve_tls.ve_tls import VeTLS @@ -58,27 +60,24 @@ class CozeloopConfig(BaseSettings): default="", alias="OBSERVABILITY_OPENTELEMETRY_COZELOOP_API_KEY" ) - otel_exporter_space_id: str = Field( - default="", alias="OBSERVABILITY_OPENTELEMETRY_COZELOOP_SERVICE_NAME" - ) - # TODO: auto fetching via AK/SK pair # @cached_property # def otel_exporter_api_key(self) -> str: # pass - # TODO: auto fetching workspace id - # @cached_property - # def otel_exporter_space_id(self) -> str: - # workspace_id = os.getenv("OBSERVABILITY_OPENTELEMETRY_COZELOOP_SERVICE_NAME", "") + @cached_property + def otel_exporter_space_id(self) -> str: + workspace_id = os.getenv( + "OBSERVABILITY_OPENTELEMETRY_COZELOOP_SERVICE_NAME", "" + ) - # if not workspace_id: - # # create a default one - # workspace_id = VeCozeloop(self.otel_exporter_api_key).create_workspace( - # workspace_name=DEFAULT_COZELOOP_SPACE_NAME - # ) + if not workspace_id: + # create a default one + workspace_id = VeCozeloop(self.otel_exporter_api_key).create_workspace( + workspace_name=DEFAULT_COZELOOP_SPACE_NAME + ) - # return workspace_id + return workspace_id class TLSConfig(BaseSettings): diff --git a/veadk/integrations/ve_cozeloop/ve_cozeloop.py b/veadk/integrations/ve_cozeloop/ve_cozeloop.py index 278ffc15..1471f881 100644 --- a/veadk/integrations/ve_cozeloop/ve_cozeloop.py +++ b/veadk/integrations/ve_cozeloop/ve_cozeloop.py @@ -31,30 +31,36 @@ def create_workspace( f"Automatically create Cozeloop workspace with name {workspace_name}" ) - URL = "https://api.coze.cn/v1/workspaces" + try: + workspace_id = self.search_workspace_id(workspace_name=workspace_name) + logger.info(f"Get existing Cozeloop workspace ID: {workspace_id}") - headers = { - "Authorization": f"Bearer {self.api_key}", - "Content-Type": "application/json", - } - - data = { - "name": workspace_name, - "description": "Created by Volcengine Agent Development Kit (VeADK)", - } - - response = requests.post(URL, headers=headers, json=data) - - if response.json().get("code") == 0: - workspace_id = response.json().get("data").get("id") - logger.info(f"Cozeloop workspace ID: {workspace_id}") return workspace_id - else: - raise Exception( - f"Failed to automatically create workspace: {response.json()}" - ) - - def get_workspace_id( + except Exception as _: + URL = "https://api.coze.cn/v1/workspaces" + + headers = { + "Authorization": f"Bearer {self.api_key}", + "Content-Type": "application/json", + } + + data = { + "name": workspace_name, + "description": "Created by Volcengine Agent Development Kit (VeADK)", + } + + response = requests.post(URL, headers=headers, json=data) + + if response.json().get("code") == 0: + workspace_id = response.json().get("data").get("id") + logger.info(f"New created Cozeloop workspace ID: {workspace_id}") + return workspace_id + else: + raise Exception( + f"Failed to automatically create workspace: {response.json()}" + ) + + def search_workspace_id( self, workspace_name: str = DEFAULT_COZELOOP_SPACE_NAME ) -> str: logger.info( @@ -73,7 +79,7 @@ def get_workspace_id( "page_size": 50, } - response = requests.post(URL, headers=headers, json=data) + response = requests.get(URL, headers=headers, json=data) if response.json().get("code") == 0: workspaces = response.json().get("data").get("workspaces", [])