diff --git a/docs/sphinx_doc/en/source/tutorial/208-distribute.md b/docs/sphinx_doc/en/source/tutorial/208-distribute.md index 6aa7c205c..0381a13f1 100644 --- a/docs/sphinx_doc/en/source/tutorial/208-distribute.md +++ b/docs/sphinx_doc/en/source/tutorial/208-distribute.md @@ -61,7 +61,7 @@ b = AgentB( In the Independent Process Mode, we need to start the agent server process on the target machine first. When starting the agent server process, you need to specify a model config file, which contains the models which can be used in the agent server, the IP address and port of the agent server process For example, start two agent server processes on the two different machines with IP `ip_a` and `ip_b`(called `Machine1` and `Machine2` accrodingly). -You can run the following code on `Machine1`, and make sure you have put your model config file in `model_config_path_a`. The example model config file instances are located under `examples/model_configs_template`. +You can run the following code on `Machine1`.Before running, make sure that the machine has access to all models that used in your application, specifically, you need to put your model config file in `model_config_path_a` and set environment variables such as your model API key correctly in `Machine1`. The example model config file instances are located under `examples/model_configs_template`. ```python # import some packages @@ -87,7 +87,7 @@ server.wait_until_terminate() > as_server --host ip_a --port 12001 --model-config-path model_config_path_a > ``` -And put your model config file accordingly in `model_config_path_b` and run the following code on `Machine2`. +Then put your model config file accordingly in `model_config_path_b`, set environment variables, and run the following code on `Machine2`. ```python # import some packages diff --git a/docs/sphinx_doc/zh_CN/source/tutorial/208-distribute.md b/docs/sphinx_doc/zh_CN/source/tutorial/208-distribute.md index ecbe50a6a..a185bd5da 100644 --- a/docs/sphinx_doc/zh_CN/source/tutorial/208-distribute.md +++ b/docs/sphinx_doc/zh_CN/source/tutorial/208-distribute.md @@ -59,7 +59,7 @@ b = AgentB( 在独立进程模式中,需要首先在目标机器上启动智能体服务器进程,启动时需要提供该服务器能够使用的模型的配置信息,以及服务器的 IP 和端口号。 例如想要将两个智能体服务进程部署在 IP 分别为 `ip_a` 和 `ip_b` 的机器上(假设这两台机器分别为`Machine1` 和 `Machine2`)。 -你可以先在 `Machine1` 上运行如下代码,运行之前请确保已经将模型配置文件放置在 `model_config_path_a` 位置,模型配置文件样例可参考 `examples/model_configs_template`。 +你可以在 `Machine1` 上运行如下代码。在运行之前请确保该机器能够正确访问到应用中所使用的所有模型。具体来讲,需要将用到的所有模型的配置信息放置在 `model_config_path_a` 文件中,并检查API key 等环境变量是否正确设置,模型配置文件样例可参考 `examples/model_configs_template`。 ```python # import some packages @@ -85,7 +85,7 @@ server.wait_until_terminate() > as_server --host ip_a --port 12001 --model-config-path model_config_path_a > ``` -在 `Machine2` 上运行如下代码,这里同样要确保已经将模型配置文件放置在 `model_config_path_b` 位置。 +在 `Machine2` 上运行如下代码,这里同样要确保已经将模型配置文件放置在 `model_config_path_b` 位置并设置环境变量,从而确保运行在该机器上的 Agent 能够正常访问到模型。 ```python # import some packages diff --git a/src/agentscope/server/launcher.py b/src/agentscope/server/launcher.py index c5c17ed30..fda6ffa19 100644 --- a/src/agentscope/server/launcher.py +++ b/src/agentscope/server/launcher.py @@ -3,11 +3,10 @@ import os from multiprocessing import Process, Event, Pipe from multiprocessing.synchronize import Event as EventClass -import socket import asyncio import signal import argparse -from typing import Type, Optional +from typing import Type from concurrent import futures from loguru import logger @@ -28,10 +27,13 @@ import agentscope from agentscope.server.servicer import AgentServerServicer from agentscope.agents.agent import AgentBase -from agentscope.utils.tools import _get_timestamp +from agentscope.utils.tools import ( + _get_timestamp, + check_port, +) -def setup_agent_server( +def _setup_agent_server( host: str, port: int, server_id: str, @@ -73,7 +75,7 @@ def setup_agent_server( A list of custom agent classes that are not in `agentscope.agents`. """ asyncio.run( - setup_agent_server_async( + _setup_agent_server_async( host=host, port=port, server_id=server_id, @@ -89,7 +91,7 @@ def setup_agent_server( ) -async def setup_agent_server_async( +async def _setup_agent_server_async( host: str, port: int, server_id: str, @@ -198,42 +200,6 @@ async def shutdown_signal_handler() -> None: ) -def find_available_port() -> int: - """Get an unoccupied socket port number.""" - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.bind(("", 0)) - return s.getsockname()[1] - - -def check_port(port: Optional[int] = None) -> int: - """Check if the port is available. - - Args: - port (`int`): - the port number being checked. - - Returns: - `int`: the port number that passed the check. If the port is found - to be occupied, an available port number will be automatically - returned. - """ - if port is None: - new_port = find_available_port() - logger.warning( - "agent server port is not provided, automatically select " - f"[{new_port}] as the port number.", - ) - return new_port - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - if s.connect_ex(("localhost", port)) == 0: - new_port = find_available_port() - logger.warning( - f"Port [{port}] is occupied, use [{new_port}] instead", - ) - return new_port - return port - - class RpcAgentServerLauncher: """The launcher of AgentServer.""" @@ -309,7 +275,7 @@ def _launch_in_main(self) -> None: f"Launching agent server at [{self.host}:{self.port}]...", ) asyncio.run( - setup_agent_server_async( + _setup_agent_server_async( host=self.host, port=self.port, server_id=self.server_id, @@ -328,7 +294,7 @@ def _launch_in_sub(self) -> None: self.parent_con, child_con = Pipe() start_event = Event() server_process = Process( - target=setup_agent_server, + target=_setup_agent_server, kwargs={ "host": self.host, "port": self.port, diff --git a/src/agentscope/server/servicer.py b/src/agentscope/server/servicer.py index 0b3dd179b..8f6134f81 100644 --- a/src/agentscope/server/servicer.py +++ b/src/agentscope/server/servicer.py @@ -36,7 +36,7 @@ class AgentServerServicer(RpcAgentServicer): - """A Servicer for agent to run on (formerly RpcServerSideWrapper)""" + """A Servicer for RPC Agent Server (formerly RpcServerSideWrapper)""" def __init__( self, diff --git a/src/agentscope/utils/tools.py b/src/agentscope/utils/tools.py index 8ebd23777..8888d99e6 100644 --- a/src/agentscope/utils/tools.py +++ b/src/agentscope/utils/tools.py @@ -6,7 +6,8 @@ import os.path import secrets import string -from typing import Any, Literal, List +import socket +from typing import Any, Literal, List, Optional from urllib.parse import urlparse @@ -61,6 +62,42 @@ def to_dialog_str(item: dict) -> str: return f"{speaker}: {content}" +def find_available_port() -> int: + """Get an unoccupied socket port number.""" + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind(("", 0)) + return s.getsockname()[1] + + +def check_port(port: Optional[int] = None) -> int: + """Check if the port is available. + + Args: + port (`int`): + the port number being checked. + + Returns: + `int`: the port number that passed the check. If the port is found + to be occupied, an available port number will be automatically + returned. + """ + if port is None: + new_port = find_available_port() + logger.warning( + "agent server port is not provided, automatically select " + f"[{new_port}] as the port number.", + ) + return new_port + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + if s.connect_ex(("localhost", port)) == 0: + new_port = find_available_port() + logger.warning( + f"Port [{port}] is occupied, use [{new_port}] instead", + ) + return new_port + return port + + def _guess_type_by_extension( url: str, ) -> Literal["image", "audio", "video", "file"]: