Nakatatsu Tech Notes

生成AI × AWS × IaC でインフラ構築を自動化するクラウドエンジニアのブログ

生成したTerraformコードの自動修正:生成AIに渡すプロンプトは短ければ短いほどいい?

生成AIに渡すプロンプトは短ければ短いほど低コストで済み、精度も高まる傾向があります。プロンプトが短いほど利用するAIのトークン数(処理する文字や文脈の単位)が少なくなり、利用料金が下がり、必要な処理だけを高精度で実行することができるためです。余分な情報によってモデルの焦点がぼやけてしまう可能性があることは、MicrosoftAzure AI services Blogでも指摘されています。

Provide Necessary Context, Omit the Rest: Include any domain information the model will need (facts of a case, data for a math problem, etc.), since the model might not have up-to-date or niche knowledge​. But don’t overload the prompt with unrelated text or too many examples – extra fluff can dilute the model’s focus​

安いし精度も良い――短いプロンプトは良いことづくめのようですが、しかし条件があります。「推論に必要な情報がすべて揃っているならば」短い方が有利ということなのです。たしかに意味もなく長くするとAIが処理すべき情報が増え、料金が上がる割にかえって精度が落ちる傾向まで出てしまうのですが、無理に短くして本来必要だった情報まで欠落させてしまうとかえって問題が起こります。たとえプロンプトが長くなろうとも必要な情報は全て渡す必要があります(トークン制限を超えるほど長くなるとカットされますが)。

最適なプロンプトの長さとは?

AIにTerraformコードを自動修正させる際にも同じことが言えます。

関連性のないリソースや不要な情報まで含んだ長大なプロンプトを渡すと、無駄なコストがかかるばかりか、不要な箇所を修正したり必要な箇所を直してくれなかったりします。そのため必要以上に長くすることは避け、短いプロンプトで済ませるほうが適切です。

例を挙げてみます。下記はある特定のリソースブロックの命名規則違反を修正させた際のプロンプトです。このように明確で局所的なエラーは、短く限定的なプロンプトで正確に修正可能です。

下記ルールに違反している場合は修正してください。

- AWSのリソースの名前(タグのName)などに該当するものは`[環境名]-[プロジェクト名]([-追加情報(あれば)])`のように命名します。(e.g., `production-practitioner-api`) 。HCLの中では変数を用いて`${var.environment}-${var.project}-api`のようにします。apiは例にすぎないため、必ずさしかえてください。

resource "aws_subnet" "public" {
  for_each = toset(data.aws_availability_zones.available.names)

  vpc_id            = aws_vpc.main.id
  availability_zone = each.key

  cidr_block = cidrsubnet(
    var.vpc_cidr_base,
    4,
    index(data.aws_availability_zones.available.names, each.key),
  )

  ipv6_cidr_block = cidrsubnet(
    aws_vpc.main.ipv6_cidr_block,
    8,
    index(data.aws_availability_zones.available.names, each.key),
  )

  map_public_ip_on_launch         = true
  assign_ipv6_address_on_creation = true

  tags = {
    Name = "subnet-public-${each.key}-${var.project}-${var.environment}"
  }
}

下記がレスポンス。期待通りに修正されています。(Name = "${var.environment}-${var.project}-subnet-public-${each.key}"の箇所)

```hcl
resource "aws_subnet" "public" {
  for_each = toset(data.aws_availability_zones.available.names)

  vpc_id            = aws_vpc.main.id
  availability_zone = each.key

  cidr_block = cidrsubnet(
    var.vpc_cidr_base,
    4,
    index(data.aws_availability_zones.available.names, each.key),
  )

  ipv6_cidr_block = cidrsubnet(
    aws_vpc.main.ipv6_cidr_block,
    8,
    index(data.aws_availability_zones.available.names, each.key),
  )

  map_public_ip_on_launch         = true
  assign_ipv6_address_on_creation = true

  tags = {
    Name = "${var.environment}-${var.project}-subnet-public-${each.key}"
  }
}
```

しかし、短いほうが良いからと解答に必要な情報まで削ってしまってはいけません。

IPv6を扱うVPCのモジュールをAIに生成させた際のことです。生成されたコードの中にaws_subnet_ipv6_cidr_block_associationというリソースタイプが使われていました。このリソースタイプは実在しません。サブネットにIPv6の設定を行うならaws_subnetipv6_cidr_blockを記載するのが正解です。

resource "aws_subnet" "public" {
  for_each = toset(data.aws_availability_zones.available.names)

  vpc_id                          = aws_vpc.main.id
  availability_zone               = each.key
  cidr_block                      = cidrsubnet(var.vpc_cidr_base, 4, index(data.aws_availability_zones.available.names, each.key))
  map_public_ip_on_launch         = true
  assign_ipv6_address_on_creation = true

  tags = {
    Name = "subnet-public-${each.key}-${var.project}-${var.environment}"
  }
}

# aws_subnet_ipv6_cidr_block_associationは実在しないため完全にハルシネーションです
resource "aws_subnet_ipv6_cidr_block_association" "public" {
  for_each = aws_subnet.public

  subnet_id = each.value.id
  # ipv6_cidr_blockは、正しくはaws_subnetに書きます
  ipv6_cidr_block = cidrsubnet( 
    aws_vpc.main.ipv6_cidr_block,
    8,
    index(data.aws_availability_zones.available.names, each.key)
  )
}

ところが、先ほどのようにリソースブロック単体で修正するスクリプトを用いてこの問題をAIに修正させようとしても無理なのです。この問題はaws_subnetの修正も必要だからです。修正箇所として両方渡されないと、いくらAIが正しくても直しようがありません。下記のようにaws_subnet_ipv6_cidr_block_associationとエラーメッセージだけを渡して修正させようとしても、「aws_subnet_ipv6_cidr_block_association.publicを削除し、aws_subnet.publicを修正すべきです」とは返しようがないわけです。実際、修正は失敗しました。

Please fix the following Terraform error. Return only the corrected code enclosed in ```hcl ... ```.

[Error]: The provider hashicorp/aws does not support resource type "aws_subnet_ipv6_cidr_block_association".

[Code]:
```hcl
resource "aws_subnet_ipv6_cidr_block_association" "public" {
  for_each = aws_subnet.public

  subnet_id = each.value.id
  ipv6_cidr_block = cidrsubnet(
    aws_vpc.main.ipv6_cidr_block,
    8,
    index(data.aws_availability_zones.available.names, each.key)
  )
}

そこで次にエラーメッセージとファイル全体を丸ごと渡して自動修正をさせました。必要ない箇所も大量に渡される、とても大雑把なやり方です。ところがこれで無事に修正されました。ノイズ交じりでも必要な情報が揃っているほうがまだ良い結果になったのです。

つまるところ目的や用途に応じてプロンプトの長さを適切に使い分けることが重要となります。一律で短いほうが良い、または長いほうが良いと決めつけてしまうと、かえって陥穽に落ちることになりかねません。必要最小限の長さが望ましいのはたしかなのですが、経験的に、うまく範囲を特定できないケースではむしろ渡せる情報を丸ごと渡してしまうほうが良い結果になりやすいようです。Terraformコード(開発言語でも似たようなことが言えるだろうと推測しますが)の自動修正をプロセスに組み込むにあたっては、上記の事情をふまえ、必要に応じてAIに渡す情報量を上手く調整する必要があります。