{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 命令行代码执行器\n\n命令行代码执行是最简单的代码执行形式。\n一般来说,它会将每个代码块保存到文件中然后执行该文件。\n这意味着每个代码块都在新进程中执行。这种执行器有两种形式:\n\n- Docker ({py:class}`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor`) - 所有命令都在Docker容器中执行\n- 本地 ({py:class}`~autogen_ext.code_executors.local.LocalCommandLineCodeExecutor`) - 所有命令都在主机上执行\n\n## Docker\n\n```{note}\n使用 {py:class}`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor` 前,请确保已安装 `autogen-ext[docker]` 包。详情请参阅[包文档](https://microsoft.github.io/autogen/dev/packages/index.html)。\n```\n\n{py:class}`~autogen_ext.code_executors.docker.DockerCommandLineCodeExecutor` 会创建一个Docker容器并在其中运行所有命令。\n默认使用的镜像是 `python:3-slim`,可以通过构造函数的 `image` 参数自定义。\n如果本地找不到镜像,该类会尝试拉取它。\n因此,只要在本地构建好镜像就足够了。该镜像与执行器兼容的唯一要求是安装了 `sh` 和 `python`。\n因此,创建自定义镜像是确保系统依赖可用的简单有效方法。\n\n您可以将执行器用作上下文管理器,以确保使用后清理容器。\n否则,程序退出时将使用 `atexit` 模块停止容器。\n\n### 检查容器\n\n如果出于任何原因(例如检查容器)希望在AutoGen使用后保留容器,\n可以在创建执行器时将 `auto_remove` 参数设为 `False`。\n也可以将 `stop_container` 设为 `False` 以防止在执行结束时停止容器。\n\n### 示例\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CommandLineCodeResult(exit_code=0, output='Hello, World!\\n', code_file='coding/tmp_code_07da107bb575cc4e02b0e1d6d99cc204.python')\n" ] } ], "source": [ "from pathlib import Path\n", "\n", "from autogen_core import CancellationToken\n", "from autogen_core.code_executor import CodeBlock\n", "from autogen_ext.code_executors.docker 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外Docker\"模式,即将Docker套接字挂载到主AutoGen容器,使其可以在主机上生成和控制\"兄弟\"容器。这比\"Docker中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如果需要将工作目录绑定到应用程序容器但该目录属于主机,\n请使用 `bind_dir` 参数。这将允许应用程序容器将*主机*目录绑定到新生成的容器,并访问该目录中的文件。如果未指定 `bind_dir`,将回退到 `work_dir`。\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 本地执行\n\n```{attention}\n本地版本将在您的本地系统上运行代码。请谨慎使用。\n```\n\n要在运行应用程序的主机上执行代码,可以使用 {py:class}`~autogen_ext.code_executors.local.LocalCommandLineCodeExecutor`。\n\n### 示例\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CommandLineCodeResult(exit_code=0, output='Hello, World!\\n', code_file='/home/ekzhu/agnext/python/packages/autogen-core/docs/src/guides/coding/tmp_code_07da107bb575cc4e02b0e1d6d99cc204.py')\n" ] } ], "source": [ "from pathlib import Path\n", "\n", "from autogen_core import CancellationToken\n", "from autogen_core.code_executor import CodeBlock\n", "from autogen_ext.code_executors.local import 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_ext.code_executors.local.LocalCommandLineCodeExecutor`。这种设置允许执行器在应用程序生命周期内始终使用指定的虚拟环境,确保依赖隔离和受控的运行时环境。\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "CommandLineCodeResult(exit_code=0, output='', code_file='/Users/gziz/Dev/autogen/python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/coding/tmp_code_d2a7db48799db3cc785156a11a38822a45c19f3956f02ec69b92e4169ecbf2ca.bash')" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import venv\n", "from pathlib import Path\n", "\n", "from autogen_core import CancellationToken\n", "from autogen_core.code_executor import CodeBlock\n", "from autogen_ext.code_executors.local import 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": [ "如我们所见,代码已成功执行,安装过程被隔离到新创建的虚拟环境中,未影响我们的全局环境。\n" ] } ], "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.5" } }, "nbformat": 4, "nbformat_minor": 2 }