# 如何让大模子安全地主动天生代码并执行? ## 前言

打印 上一主题 下一主题

主题 1951|帖子 1951|积分 5853

前言

本文带来的分享是在crewai中利用代码表明器,为了安全,代码在docker中运行。
为什么要利用代码表明器呢?
之前的文章中利用的是function call + 各种工具 来完成一个任务,比如文件读取工具、文件生存工具等。
但是用户的需求是多变的,你很难提前写好全部的工具。
读取文件内容,利用代码表明器的结果如下所示:

实践

首先必要看下crewai中提供的代码表明器工具代码,学习一下。
代码在:https://github.com/crewAIInc/crewAI-tools/tree/main/crewai_tools/tools/code_interpreter_tool
文件如下:

先来看一下Dockerfile:
  1. FROM python:3.12-alpine
  2. RUN pip install requests beautifulsoup4
  3. # Set the working directory
  4. WORKDIR /workspace
复制代码
这是一个Dockerfile的片段,用于构建一个Python环境的Docker镜像。表明如下:
FROM python:3.12-alpine:这行指定了底子镜像为Python 3.12版本的Alpine Linux镜像。Alpine Linux是一种轻量级的Linux发行版,非常适合作为Docker镜像的底子。
RUN pip install requests beautifulsoup4:这行利用pip安装两个Python包:requests和beautifulsoup4。requests是一个用于发送HTTP请求的库,而beautifulsoup4是一个用于解析HTML和XML文档的库。
WORKDIR /workspace:这行设置了容器中的工作目录为/workspace。当容器启动时,会主动进入这个目录。
总的来说,这个Dockerfile构建了一个Python环境,安装了两个常用的库,并将工作目录设置为/workspace。这个镜像可以用于运行Python应用步伐,尤其是那些必要解析HTML和发送HTTP请求的应用步伐。
再来看一下code_interpreter_tool.py的代码:
  1. import importlib.util
  2. import os
  3. from typing import List, Optional, Type
  4. from crewai.tools import BaseTool
  5. from docker import from_env as docker_from_env
  6. from docker import DockerClient
  7. from docker.models.containers import Container
  8. from docker.errors import ImageNotFound, NotFound
  9. from docker.models.containers import Container
  10. from pydantic import BaseModel, Field
  11. class CodeInterpreterSchema(BaseModel):
  12.     """
  13.     Input for CodeInterpreterTool.
  14.     供代码解释工具输入。
  15.     """
  16.     code: str = Field(
  17.         ...,
  18.         # Python3代码原来是在Docker容器中被解释的。始终打印最终结果和代码的输出。
  19.         description="Python3 code used to be interpreted in the Docker container. ALWAYS PRINT the final result and the output of the code",
  20.     )
  21.     libraries_used: Optional[List[str]] = Field(
  22.         None,
  23.         # 代码中使用的库列表,带有适当的安装名称,以逗号分隔。例如: numpy,pandas,beautifulsoup4
  24.         description="List of libraries used in the code with proper installing names separated by commas. Example: numpy,pandas,beautifulsoup4",
  25.     )
  26. class CodeInterpreterTool(BaseTool):
  27.     name: str = "Code Interpreter"
  28.     description: str = "Interprets Python3 code strings with a final print statement."
  29.     args_schema: Type[BaseModel] = CodeInterpreterSchema
  30.     default_image_tag: str = "code-interpreter:latest"
  31.     code: Optional[str] = None
  32.     user_dockerfile_path: Optional[str] = None
  33.     user_docker_base_url: Optional[str] = None
  34.     unsafe_mode: bool = False
  35.     @staticmethod
  36.     def _get_installed_package_path():
  37.         spec = importlib.util.find_spec("crewai_tools")
  38.         return os.path.dirname(spec.origin)
  39.     def _verify_docker_image(self) -> None:
  40.         """
  41.         Verify if the Docker image is available. Optionally use a user-provided Dockerfile.
  42.         验证Docker镜像是否可用。可选地使用用户提供的Dockerfile。
  43.         """
  44.         client = (
  45.             docker_from_env()
  46.             if self.user_docker_base_url == None
  47.             else DockerClient(base_url=self.user_docker_base_url)
  48.         )
  49.         try:
  50.             client.images.get(self.default_image_tag)
  51.         except ImageNotFound:
  52.             if self.user_dockerfile_path and os.path.exists(self.user_dockerfile_path):
  53.                 dockerfile_path = self.user_dockerfile_path
  54.             else:
  55.                 package_path = self._get_installed_package_path()
  56.                 dockerfile_path = os.path.join(
  57.                     package_path, "tools/code_interpreter_tool"
  58.                 )
  59.                 if not os.path.exists(dockerfile_path):
  60.                     raise FileNotFoundError(
  61.                         f"Dockerfile not found in {dockerfile_path}"
  62.                     )
  63.             client.images.build(
  64.                 path=dockerfile_path,
  65.                 tag=self.default_image_tag,
  66.                 rm=True,
  67.             )
  68.     def _run(self, **kwargs) -> str:
  69.         code = kwargs.get("code", self.code)
  70.         libraries_used = kwargs.get("libraries_used", [])
  71.         if self.unsafe_mode:
  72.             return self.run_code_unsafe(code, libraries_used)
  73.         else:
  74.             return self.run_code_in_docker(code, libraries_used)
  75.     def _install_libraries(self, container: Container, libraries: List[str]) -> None:
  76.         """
  77.         Install missing libraries in the Docker container
  78.         """
  79.         for library in libraries:
  80.             container.exec_run(["pip", "install", library])
  81.     def _init_docker_container(self) -> Container:
  82.         container_name = "code-interpreter"
  83.         client = docker_from_env()
  84.         current_path = os.getcwd()
  85.         # Check if the container is already running
  86.         try:
  87.             existing_container = client.containers.get(container_name)
  88.             existing_container.stop()
  89.             existing_container.remove()
  90.         except NotFound:
  91.             pass  # Container does not exist, no need to remove
  92.         return client.containers.run(
  93.             self.default_image_tag,
  94.             detach=True,
  95.             tty=True,
  96.             working_dir="/workspace",
  97.             name=container_name,
  98.             volumes={current_path: {"bind": "/workspace", "mode": "rw"}},  # type: ignore
  99.         )
  100.     def run_code_in_docker(self, code: str, libraries_used: List[str]) -> str:
  101.         self._verify_docker_image()
  102.         container = self._init_docker_container()
  103.         self._install_libraries(container, libraries_used)
  104.         exec_result = container.exec_run(["python3", "-c", code])
  105.         container.stop()
  106.         container.remove()
  107.         if exec_result.exit_code != 0:
  108.             return f"Something went wrong while running the code: \n{exec_result.output.decode('utf-8')}"
  109.         return exec_result.output.decode("utf-8")
  110.     def run_code_unsafe(self, code: str, libraries_used: List[str]) -> str:
  111.         """
  112.         Run the code directly on the host machine (unsafe mode).
  113.         """
  114.         # Install libraries on the host machine
  115.         for library in libraries_used:
  116.             os.system(f"pip install {library}")
  117.         # Execute the code
  118.         try:
  119.             exec_locals = {}
  120.             exec(code, {}, exec_locals)
  121.             return exec_locals.get("result", "No result variable found.")
  122.         except Exception as e:
  123.             return f"An error occurred: {str(e)}"
复制代码
主要的参数与描述如下:
  1. code: str = Field(
  2.         ...,
  3.         # Python3代码原来是在Docker容器中被解释的。始终打印最终结果和代码的输出。
  4.         description="Python3 code used to be interpreted in the Docker container. ALWAYS PRINT the final result and the output of the code",
  5.     )
  6.     libraries_used: Optional[List[str]] = Field(
  7.         None,
  8.         # 代码中使用的库列表,带有适当的安装名称,以逗号分隔。例如: numpy,pandas,beautifulsoup4
  9.         description="List of libraries used in the code with proper installing names separated by commas. Example: numpy,pandas,beautifulsoup4",
  10.     )
复制代码
测试这个工具的代码:
  1. from crewai import LLM, Agent, Crew, Process, Task
  2. # from crewai_tools import CodeInterpreterTool
  3. from code_interpreter_tool import CodeInterpreterTool
  4. import os
  5. from dotenv import load_dotenv
  6. load_dotenv()
  7. api_key = os.getenv('SiliconCloud_API_KEY')
  8. base_url = os.getenv('SiliconCloud_API_BASE')
  9. model = os.getenv('SiliconCloud_MODEL_NAME', 'openai/Qwen/Qwen2.5-72B-Instruct')  # Provide a default model if not set
  10. agent_llm = LLM(
  11. model=model,
  12. base_url=base_url,
  13. api_key=api_key
  14.         )
  15. # Create an LLM with a temperature of 0 to ensure deterministic outputs
  16. # llm = LLM(model="gpt-4o-mini", temperature=0)
  17. # Create an agent with the knowledge store
  18. agent = Agent(
  19.     role="Tool User",
  20.     goal="You know how to use the tool.",
  21.     backstory="""
  22.     You are a master at using the tool.
  23.     使用代码执行工具时,如果没有使用库,则libraries_used参数为空列表,需要写成libraries_used=[]。
  24.     """,
  25.     verbose=True,
  26.     allow_delegation=False,
  27.     llm=agent_llm,
  28.     tools=[CodeInterpreterTool()],
  29. )
  30. task = Task(
  31.     description="""
  32.     根据用户需求:{question}
  33.     使用相应的工具。
  34.     """,
  35.     expected_output="获取本次工具输出的结果,无需其它内容。",
  36.     agent=agent,
  37. )
  38. crew = Crew(
  39.     agents=[agent],
  40.     tasks=[task],
  41.     verbose=True,
  42.     process=Process.sequential,
  43. )
  44. result = crew.kickoff(
  45.     inputs={
  46.         "question": "获取test2.txt的内容"
  47.     }
  48. )
复制代码
在这个地方可以输入你的需求看看代码表明器能不能实现。
先来一个最简朴的:
  1. result = crew.kickoff(
  2.     inputs={
  3.         "question": "输出你好世界"
  4.     }
  5. )
复制代码

再来一个创建文件的:
  1. result = crew.kickoff(
  2.     inputs={
  3.         "question": "创建test3.txt,里面写入我是一只鱼。"
  4.     }
  5. )
复制代码


再试一下必要利用库的:
  1. result = crew.kickoff(
  2.     inputs={
  3.         "question": "画一个折线图,横坐标为1月、2月、3月,纵坐标为12、15、17,将结果保存到test.png。"
  4.     }
  5. )
复制代码


中文字体没有正常表现,修改需求:
  1. 画一个折线图,横坐标为1月、2月、3月,纵坐标为12、15、17,需要显示中文字体,将结果保存到test.png。
复制代码
还是没有成功。
在docker环境中没有安装中文字体。

并且利用代码表明器的一个缺点就是你无法保证AI天生的代码就是能用的,轻微复杂一点的需求,就有大概天生无法运行的代码。

如许来看代码表明器的可玩性还是有很大的限制。
但是确实可以替代一些简朴的工具了。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表