CodexQA

Industry & PracticeTools & Frameworks

Promptfoo:生成的代码先关进 Docker,再谈通过率

CodexQA 团队4 min read

Promptfoo 这篇教程用 epicbox 在 python:3.9-alpine 里跑模型写出的函数,CPU 限 1 秒、内存限 64。三道题分别期望 120、True 和 9;退出码非 0 或输出不符都记 0 分。

In this piece

在沙箱里评测大模型生成的代码

你在用大语言模型生成代码片段、函数,甚至整个程序。在生产环境里——甚至在开发环境里——盲目信任并执行这些生成的代码,可能是严重的安全风险。

沙箱评测就是为此准备的。沙箱是把待测代码放进隔离环境里运行,使它碰不到宿主系统。把大语言模型生成的代码放在受控、隔离的环境里运行,我们可以:

  1. 安全地评估代码是否正确。
  2. 给不同的大语言模型或提示词做基准,找出哪一种产出最可靠的代码。
  3. 在无限循环或耗费资源的操作影响到宿主系统之前,抓住潜在错误。

在这篇教程里,我们用 promptfoo 搭一条自动流水线:用大语言模型生成 Python 代码,用 epicbox 在安全沙箱里执行,再评测结果。promptfoo 是一个用配置文件驱动的大语言模型评测命令行工具。epicbox 是一个在 Docker 容器里按资源限制执行代码的 Python 库。

前置条件

确认已经安装:

  • Node.js 和 npm
  • Python 3.10 及以上
  • Docker
  • promptfoo(npm install -g promptfoo)

在 Windows 上,请在 WSL 2 里运行本教程,并打开 Docker Desktop 的 WSL 集成。在 WSL 里安装 Node.js 和 Python;Epicbox 不支持原生 Windows 上的 Python。

在项目目录里创建虚拟环境,并安装示例的 Python 依赖。

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r https://raw.githubusercontent.com/promptfoo/promptfoo/main/examples/integration-docker/code-generation-sandbox/requirements.txt

跑评测时,让这个虚拟环境在同一个 shell 里保持激活。

这些依赖使用 Epicbox 1.1.1 的官方 GitHub 发布,并用 SHA-256 哈希核验,同时保留传输安全的最低要求。PyPI 上的 Epicbox 1.1.0 与 urllib3 2 不兼容。

把要用的 Docker 镜像拉到本地,这样它就在本机可用。本教程使用一个通用的 Python 镜像,你也可以换成自定义镜像:

docker pull python:3.9-alpine

配置

创建 promptfoo 配置文件

创建名为 promptfooconfig.yaml 的文件:

prompts: file://code_generation_prompt.txt

providers:
  - openai:gpt-5
  - ollama:chat:llama4:scout

tests:
  - vars:
      problem: 'Write a Python function to calculate the factorial of a number'
      function_name: 'factorial'
      test_input: '5'
      expected_output: '120'
  - vars:
      problem: 'Write a Python function to check if a string is a palindrome'
      function_name: 'is_palindrome'
      test_input: "'racecar'"
      expected_output: 'True'
  - vars:
      problem: 'Write a Python function to find the largest element in a list'
      function_name: 'find_largest'
      test_input: '[1, 5, 3, 9, 2]'
      expected_output: '9'

defaultTest:
  assert:
    - type: python
      value: file://validate_and_run_code.py

这份配置做了几件重要的事:

  1. 它告诉 promptfoo 使用我们的提示词模板。
  2. 我们在测试 GPT-5 和 Llama 4(你可以换成自己选择的 provider。provider 是 promptfoo 用来调用某一个模型的适配器。Promptfoo 同时支持本地和商业 provider)。
  3. 它定义编码题目。每道题指定函数名、一个测试输入和期望输出。
  4. 它设置一条基于 Python 的断言,对每个测试用例运行,用来校验生成的代码。断言是判定该条测试通过或失败的检查。

创建提示词模板

创建名为 code_generation_prompt.txt 的文件,内容如下:

You are a Python code generator. Write a Python function to solve the following problem:

{{problem}}

Use the following function name: {{function_name}}

Only provide the function code, without any explanations or additional text. Wrap your code in triple backticks.

这条提示词会发给大语言模型,{{variables}} 会按对应值替换(这条提示词是兼容 Jinja 的模板)。

准备 Python 断言脚本

创建名为 validate_and_run_code.py 的文件。这是一条 Python 断言,它用 epicbox 在 Docker 容器里运行,从而给每道编码题动态打分。

```python import epicbox import r

Replace with your preferred Docker image

DOCKER_IMAGE = 'python:3.9-alpine'

def get_assert(output, context):

Extract the Python function from the LLM output

function_match = re.search(r'``python\s*\n(def\s+.*?)\n`', output, re.DOTALL) if not function_match: return {'pass': False, 'score': 0, 'reason': 'No function definition found'

function_code = function_match.group(1)

epicbox.configure( profiles=[ epicbox.Profile('python', DOCKER_IMAGE) ] )

function_name = context['vars']['function_name'] test_input = context['vars']['test_input'] expected_output = context['vars']['expected_output']

Create a Python script to call the LLM-written function

test_code = f""" {function_code}

Test the function

result = {function_name}({test_input}) print(result) """

files = [{'name': 'main.py', 'content': test_code.encode('utf-8')}] limits = {'cputime': 1, 'memory': 64}

Run it

result = epicbox.run('python', 'python main.py', files=files, limits=limits)

Check the result

if result['exit_code'] != 0: return {'pass': False, 'score': 0, 'reason': f"Execution error: {result['stderr'].decode('utf-8')}"}

actual_output = result['stdout'].decode('utf-8').strip() if actual_output == str(expected_output): return {'pass': True, 'score': 1, 'reason': f'Correct output: got {expected_output}'} else: return {'pass': False, 'score': 0, 'reason': f"Incorrect output. Expected: {expected_output}, Got: {actual_output}"} ````

运行评测

在终端执行:

promptfoo eval

这条命令会:

  • 用大语言模型为每道题生成 Python 代码
  • 抽出生成的代码
  • 在 Docker 沙箱环境里运行它
  • 判定输出是否正确

分析结果

评测跑完后,打开网页查看器:

promptfoo view

它会显示结果摘要。你可以分析:

  • 生成代码的总体通过率
  • 大语言模型成功或失败的具体测试用例
  • 失败测试的错误信息或不正确输出

图:promptfoo 网页查看器里的代码生成评测结果。

接下来

若要继续看 promptfoo 能做什么,可以考虑:

  • 测试不同的大语言模型 provider
  • 修改你的提示词
  • 扩大编码题目和测试用例的范围

更多信息见官方 指南。你也可以看 持续集成 以及和其他工具的集成。

Promptfoo,Sandboxed Evaluations of LLM-Generated Code,2026-09-27,https://www.promptfoo.dev/docs/guides/sandboxed-code-evals/,MIT

Found it useful? Pass it on

WeChat

Scan with WeChat to open it on your phone and forward it.

Subscribe via RSS

Submit a correction