{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 命令行代码执行器\n", "\n", "命令行代码执行是最简单的代码执行形式。一般来说,它会将每个代码块保存到文件中,然后执行该文件。这意味着每个代码块都在新进程中执行。这种执行器有两种形式:\n", "\n", "- Docker ({py:class}`~autogen_ext.code_executor.docker_executor.DockerCommandLineCodeExecutor`) - 所有命令都在 Docker 容器中执行\n", "- 本地 ({py:class}`~autogen_core.components.code_executor.LocalCommandLineCodeExecutor`) - 所有命令都在主机上执行\n", "\n", "## Docker\n", "\n", "```{note}\n", "要使用 `DockerCommandLineCodeExecutor`,请确保安装了 `autogen-ext[docker]` 包。更多详情,请参阅[包文档](https://microsoft.github.io/autogen/dev/packages/index.html)。\n", "```\n", "\n", "{py:class}`~autogen_ext.code_executor.docker_executor.DockerCommandLineCodeExecutor` 将创建一个 Docker 容器并在该容器内运行所有命令。默认使用的镜像是 `python:3-slim`,可以通过向构造函数传递 `image` 参数来自定义。如果本地找不到镜像,则类将尝试拉取它。因此,在本地构建镜像就足够了。这个镜像要与执行器兼容,唯一需要的是安装 `sh` 和 `python`。因此,创建自定义镜像是确保所需系统依赖可用的简单有效方法。\n", "\n", "您可以将执行器用作上下文管理器,以确保在使用后清理容器。否则,`atexit` 模块将在程序退出时用于停止容器。\n", "\n", "### 检查容器\n", "\n", "如果您出于某种原因希望在 AutoGen 使用完容器后保留它(例如,检查容器),那么您可以在创建执行器时将 `auto_remove` 参数设置为 `False`。`stop_container` 也可以设置为 `False` 以防止容器在执行结束时被停止。\n", "\n", "### 示例" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CommandLineCodeResult(exit_code=0, output='Hello, World!\\n', code_file='coding/tmp_code_2b33215fadf3c54926d5c4100348afc158dbff4c94b15044e3a7fe804f80ed2d.python')\n" ] } ], "source": [ "from pathlib import Path\n", "\n", "from autogen_core.base import CancellationToken\n", "from autogen_core.components.code_executor import CodeBlock\n", "from autogen_ext.code_executors import DockerCommandLineCodeExecutor\n", "\n", "work_dir = Path(\"coding\")\n", "work_dir.mkdir(exist_ok=True)\n", "\n", "async with DockerCommandLineCodeExecutor(work_dir=work_dir) as executor: # type: ignore\n", " print(\n", " await executor.execute_code_blocks(\n", " code_blocks=[\n", " CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n", " ],\n", " cancellation_token=CancellationToken(),\n", " )\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 将 Docker 中的应用程序与基于 Docker 的执行器结合\n", "\n", "将应用程序打包到 Docker 镜像中是很理想的。但是,如何让您的容器化应用程序在不同的容器中执行代码呢?\n", "\n", "推荐的方法称为\"Docker out of Docker\",其中 Docker 套接字被挂载到主 AutoGen 容器,这样它就可以在主机上生成和控制\"兄弟\"容器。这比所谓的\"Docker in Docker\"更好,后者是主容器运行 Docker 守护进程并在其内部生成容器。您可以在[这里](https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/)阅读更多相关信息。\n", "\n", "要做到这一点,您需要将 Docker 套接字挂载到运行应用程序的容器中。这可以通过在 `docker run` 命令中添加以下内容来完成:\n", "\n", "```bash\n", "-v /var/run/docker.sock:/var/run/docker.sock\n", "```\n", "\n", "这将允许您的应用程序容器在主机上生成和控制兄弟容器。\n", "\n", "如果您需要将工作目录绑定到应用程序的容器,但该目录属于您的主机,请使用 `bind_dir` 参数。这将允许应用程序的容器将*主机*目录绑定到新生成的容器,并允许它访问该目录中的文件。如果未指定 `bind_dir`,它将回退到 `work_dir`。\n", "\n", "## 本地\n", "\n", "```{attention}\n", "本地版本将在您的本地系统上运行代码。请谨慎使用。\n", "```\n", "\n", "要在主机(即运行应用程序的机器)上执行代码,可以使用 {py:class}`~autogen_core.components.code_executor.LocalCommandLineCodeExecutor`。\n", "\n", "### 示例" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CommandLineCodeResult(exit_code=0, output='Hello, World!\\n', code_file='/data/git/autogen/python/packages/autogen-core/doc-zh/src/user-guide/core-user-guide/framework/coding/tmp_code_2b33215fadf3c54926d5c4100348afc158dbff4c94b15044e3a7fe804f80ed2d.py')\n" ] } ], "source": [ "from pathlib import Path\n", "\n", "from autogen_core.base import CancellationToken\n", "from autogen_core.components.code_executor import CodeBlock, LocalCommandLineCodeExecutor\n", "\n", "work_dir = Path(\"coding\")\n", "work_dir.mkdir(exist_ok=True)\n", "\n", "local_executor = LocalCommandLineCodeExecutor(work_dir=work_dir)\n", "print(\n", " await local_executor.execute_code_blocks(\n", " code_blocks=[\n", " CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n", " ],\n", " cancellation_token=CancellationToken(),\n", " )\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 虚拟环境中的本地执行\n", "\n", "如果您希望代码在作为应用程序设置的一部分创建的虚拟环境中运行,您可以为新创建的环境指定一个目录,并将其上下文传递给 {py:class}`~autogen_core.components.code_executor.LocalCommandLineCodeExecutor`。这种设置允许执行器在应用程序的整个生命周期中一致地使用指定的虚拟环境,确保隔离的依赖关系和受控的运行时环境。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "CommandLineCodeResult(exit_code=125, output='\\n Cancelled', code_file='/data/git/autogen/python/packages/autogen-core/doc-zh/src/user-guide/core-user-guide/framework/coding/tmp_code_d2a7db48799db3cc785156a11a38822a45c19f3956f02ec69b92e4169ecbf2ca.bash')" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import venv\n", "from pathlib import Path\n", "\n", "from autogen_core.base import CancellationToken\n", "from autogen_core.components.code_executor import CodeBlock, LocalCommandLineCodeExecutor\n", "\n", "work_dir = Path(\"coding\")\n", "work_dir.mkdir(exist_ok=True)\n", "\n", "venv_dir = work_dir / \".venv\"\n", "venv_builder = venv.EnvBuilder(with_pip=True)\n", "venv_builder.create(venv_dir)\n", "venv_context = venv_builder.ensure_directories(venv_dir)\n", "\n", "local_executor = LocalCommandLineCodeExecutor(work_dir=work_dir, virtual_env_context=venv_context)\n", "await local_executor.execute_code_blocks(\n", " code_blocks=[\n", " CodeBlock(language=\"bash\", code=\"pip install matplotlib\"),\n", " ],\n", " cancellation_token=CancellationToken(),\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "正如我们所看到的,代码已成功执行,并且安装已被隔离到新创建的虚拟环境中,没有影响我们的全局环境。" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 2 }