Blog
はじめに
Preferred Networksでは、大規模言語モデル「PLaMo」の開発を行っています。
PLaMoは開発サイクルにて様々なベンチマークによりその能力を評価していますが、今回はコード生成ベンチマークにてモデルが生成する、安全性が保証されていないコードを実行するためのサンドボックス環境を紹介します。
サンドボックス環境がなぜ必要か
HumanEvalやLiveCodeBenchなどのコード生成ベンチマークは、評価対象のモデルに対しプロンプトを与え、生成されたコードにテストコードを付与してコンパイル・実行することでコーディング能力を問います。
コード生成ベンチマークでは、安全性が保証されていない(危険な処理を行う可能性がある)コードも実行されうることに注意が必要です。
LLMを利用したユーザー補助のためのコード補完ツールやサービスは、ユーザーが補完候補を見て利用の可否を決めることができます。一方でコード生成ベンチマークは数百以上のコードを生成および評価するため、すべての生成結果を人がチェックすることは困難です。
例えば rm -rf / のような明らかに危険なコードも実行者の権限に依存し実行できてしまうので、システムが破壊される可能性があります。
また、ネットワークへ大量のデータを流したり不審なリクエストを送るなど別のシステムに影響を与える可能性もあります。
サンドボックス環境の導入によりコード生成ベンチマークの実行環境を隔離し、システムを保護します。
設計と実装
サンドボックス環境の実装条件は以下の通りです。
- システムの重要なファイルが破壊されても良い
- 秘密鍵や認証情報などのシークレットは置かない
- サンドボックス環境からアウトバウンドの通信はすべて許可しない
- アクセス制御によりサンドボックス環境へのリクエスト送信者を制限する
上記を満たすためにDockerコンテナとして実環境から隔離し、HTTPで実行リクエストを受け取るシンプルな実装を行いました。
以下のようにPOST APIで実行言語とコード、任意の標準入力データを送信すると、実行時の標準出力やリターンコードをレスポンスとして返します。
$ curl -v 'http://code-eval-sandbox-service/run' \
-H 'Content-Type: application/json' \
--data '{"language": "python", "code": "print(40 + 2)"}'
{"status": "ok", "stdout": "42\n", "stderr": ""}
コード生成ベンチマークは主にPythonコードを対象としていますが、C++やJavaなどの多言語評価を行うベンチマークもあるため、実行言語を指定可能にしました。(e.g. MultiPL-EやMcEvalなど)
サンドボックス環境でリクエストを受け付けてコードを実行するサーバーについては、FastAPIでシンプルに実装できるので割愛します。
Kubernetes実装: In-Cluster Service
サンドボックス環境は任意コード実行が可能な状態なので、内部ネットワークからも隔離された状態で動作するのが望ましいと言えます。
例えばKubernetes (k8s) 基盤のクラスタの場合、上記のサンドボックス環境を任意のK8s namespace上で実行するには以下のようなマニフェストを利用できます。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: sandbox-network-policy
spec:
podSelector:
matchLabels:
role: sandbox
policyTypes:
- Ingress # `role=sandbox-user`ラベルを持つPodからしかアクセスできないようにする
- Egress # egress設定を空にしてすべての外向き通信を拒否
ingress:
- from:
- podSelector:
matchLabels:
role: sandbox-user
---
apiVersion: v1
kind: Service
metadata:
name: sandbox-service
spec:
selector:
role: sandbox
# 8080番ポートでリクエストをうける
ports:
- protocol: TCP
port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sandbox-deployment
labels:
role: sandbox
spec:
replicas: 1
selector:
matchLabels:
role: sandbox
template:
metadata:
labels:
role: sandbox
spec:
containers:
- name: container
image: docker.pkg.dev/examples/code-eval-sandbox:latest
ports:
- containerPort: 8080
restartPolicy: Always
automountServiceAccountToken: false
上記ではリソースラベルに role=sandbox-user が与えられた同一ネットワーク上のリソースからしかリクエストを送信できないようにし、サンドボックス環境のPodから外への通信を遮断しています。
AWS Lambda実装: Out-of-Cluster Service
PLaMo開発はK8s基盤の自社クラスタ (Preferred Computing Platform, PFCP) だけではなく、Google CloudやABCIといったIaaS型クラウドやスーパーコンピュータシステムも活用しています。
しかし、開発基盤となるクラスタの仕様に合わせて都度サンドボックス環境の構築・保守を行うのはそれなりに工数が必要です。
また、システムによってはコンテナの常時起動が難しかったり、ユーザーがREST APIなどを使って内部ネットワーク上の別計算リソースと通信することを想定していない場合もあります。
以上のコストや問題を解決するため、現在はAWS Lambdaにサンドボックス環境を構築し、すべての開発環境で同一の評価環境を利用しています。
図1に、AWS Lambdaを用いたサンドボックス環境のアーキテクチャ図を記載します。

図1: AWS Lambdaを用いたコード評価用サンドボックス環境の実装(Amazon Web Services、AWS、Powered by AWS のロゴは、Amazon.com, Inc.またはその関係会社の商標です)
要点は以下の通りです。
- 各クラスタはInvoke APIのみを許可したIAM Roleを使用しLambda関数を同期呼び出しする
- Lambda関数には全トラフィックを拒否するセキュリティグループを設定する
Lambda関数呼び出しの認証
AWS Lambdaは関数呼び出しを同期・非同期で実行可能ですが、扱いやすい上に生成したコードの実行結果はすぐに欲しいので、同期呼び出しを使っています。
Lambda関数では、IAM認証もしくは無認証のHTTP(S) エンドポイントも提供可能ですが、本環境ではアクセス可能なユーザー等を最小限にしぼりたいので、IAM認証付きのInvoke APIでのリクエストにしぼりました。
リクエスト送信者はInvoke APIだけ許可されていれば良いので、必要なIAM Policyは非常にシンプルです。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "lambda:InvokeFunction",
"Effect": "Allow",
"Resource": "arn:aws:lambda:{region}:{aws-account}:function:{function-name}"
}
]
}
ネットワークの制限
Lambda関数はデフォルトで、AWSの他のサービスおよびインターネットに接続された状態の、Lambdaサービス管理のVPCで実行されます。
最初に書いた通り、安全でないコードからネットワーク上の別システムへの影響を避けるため、サンドボックス環境であるLambda関数からのネットワークアクセスは制限したいです。
一方で、インターネット (AWS外) から関数呼び出し可能な状態でなければコード生成ベンチマークの評価に利用できません。
本環境ではLambda関数に別途VPC (+ セキュリティグループ) を設定し、Lambda関数から外向きの通信ができないようにしました。
前述の通りLambda関数自体はLambdaサービス管理のVPCで実行されますが、自前のVPCを設定するとLambda関数がアクセスできるのはそのVPC内のリソースのみになります。
あとは空のセキュリティグループを設定すれば、同一VPC内のリソースにアクセスできず、インターネットにアクセスできず、しかしLambda関数として外部から呼び出し可能、という状態が作れます。
AWS Lambdaの実行コスト
必要なメモリサイズ
Lambda関数の料金は割り当てるメモリのサイズおよび使用時間の積と、リクエスト数、およびEphemeral storageの割り当てサイズで決定されます。
今回はEphemeral storageに大容量のファイルを書き込むことはない想定で、追加費用なしの512 MBに固定します。
Lambda関数に割り当てるメモリサイズは動的に変更できないので、日常的に評価しているコード生成ベンチマークのcanonical answer (ベンチマークが定義している場合) がすべて動作するメモリサイズについて、CloudWatch metricsを使って調べました。
Lambda関数に512 MBのメモリを割り当てると、関数1回の呼び出しあたり平均1秒でリクエストを処理可能で、コールドスタートや極端に重い処理が必要な場合に数秒かかる、という傾向が見られました。
メモリを減らしても動作しますが、処理時間が線形あるいは(おそらくスラッシングにより)極端に増加する、という傾向が見られたので512 MBとしました。
呼び出し回数から使用量を見積もる
コード生成ベンチマークではpass@kが評価指標になりますが、k回の生成と評価を行うため、実行コストはkと各ベンチマークの問題数に依存します。
例えばHumanEvalの場合は164問あり、pass@10とすると1640回のコード実行が必要です。
メモリ使用料金はGB秒での単価になっているので、pass@10のHumanEvalを実行をするには164回 * 10 * 1秒 * 0.5 GB = 820 GB秒程度が必要になります。
ただし、AWS Lambdaは1ヶ月あたり以下が無料利用枠として設定されています。
- 100万件分のリクエスト
- 40万GB秒の使用量
pass@10のHumanEvalだけに絞ると、月あたり約610回分のリクエスト、約488回分の使用量がカバーできる想定です。
次に無料枠がない状態で月100万リクエストを処理したとします。
ap-northeast1リージョンを使用し、x86_64でLambda関数を実行したとすると、リクエスト分は0.2 USDで、使用量は約8.33 USD、およそ8.53 USDです。(2026年2月10日時点の料金に基づきます)
ただし上記料金は無限ループに陥ったり、処理が遅くタイムアウトしてしまうなど異常系のコストは含まれていません。
異常系に加え、LiveCodeBenchなど複数ベンチマークを実行することを考えても妥当なコストで収まると期待されます。
リクエストペイロードのサイズ制限
隔離された環境での任意コード実行を、モデルを開発するシステムの環境に依存せず実行できるようになりましたが、複雑なコード生成ベンチマークではAWS Lambdaのペイロードサイズ制限が障壁になりました。
AWS Lambdaの同期呼び出しは、リクエストのペイロード長は最大6 MBに制限されています。非同期呼び出しの場合は1 MBと、より少なくなります。
HumanEvalやMBPPなどでは問題ありませんでしたが、LiveCodeBenchはこの制限を超えてしまうことがありました。
LiveCodeBenchは主要な3つの競技プログラミングのプラットフォーム(LeetCode, AtCoder, Codeforces)の問題から構成されていて、1つのテストケースの実行に必要な入力(生成されたコード、テストコード、テストコードに必要な入力)がHumanEvalなどと比較して大きいケースがありました。
その結果、LiveCodeBenchの複数の問題でペイロード制限である6 MBを超えてしまい、正当な評価が困難となりました。
この制限の回避手段として、S3にペイロード本体を保存して使うといった方法がありますが、サンドボックス環境としては相手がAWSリソースでも外向きの通信は避けたいです。
今回は少し特殊解ですが、ペイロードを圧縮データとして送り、サンドボックス環境で解凍して実行することで解決しました。
普通のシステムならマルウェア感染経路の典型例ですが、サンドボックス環境自体が任意コードを実行するための隔離環境で機密情報が入っておらず、かつIAM認証で送信者が限定されているので、許容できるものと考えています。
おわりに
今回はコード生成ベンチマークの評価を対象とした、任意コード実行のためのサンドボックス環境の実装を紹介しました。使用するシステムに依存しない環境をどこからでも利用できる、というのがクラウドの強みだと思います。
一方で、例えばSWE-benchのようなエージェント的なタスクを評価するベンチマークの場合、今回のような環境では不十分で、より高い自由度が必要だと思います。
PFNでは現在、LLMの事前学習エンジニアを募集しております。より高性能な事前学習モデルの開発そのものだけでなく、今回のような評価環境の開発・運用などのスキルをお持ちの方も募集しておりますので、ご興味のある方は是非以下をご覧ください。
Tag







