ここのところ気温も暖かくなり、外に出かけるのが楽しみになってきた、カメラ好き機械学習エンジニアの@yktm31です。
いま世間を賑わせている生成系AI、ChatGPTは私にとって欠かせないものになりました。
そんな中つい先日、AWSから「Amazon CodeWhisperer」がGAになりました。
といことで、さっそく試してみました。
目次
概要
Amazon CodeWhispererは、リアルタイムでAIによるコード提案をしてくれるサービスです。類似のサービスとしては「GitHub Copilot」があります。
以下のように、コードを書いている途中でもその先を予測し、候補を出してくれるというものです。
特徴
CodeWhispererは、他のコード生成AIに比べ以下のような特徴があるようです。
サポート
サポートされるプログラミング言語
Amazon CodeWhispererで生成可能なプログラミング言語は15種類あるようです。
その中でも、Java、Python、JavaScript、TypeScript、C#の5つが、学習データの質が高い(=より精度の高い提案をしてくれると想定できる)ようです。
サポートされるIDE
以下のIDEがサポートされているようです。
- Visual Studio Code
- すべてのJetBrains IDE
- AWS Cloud9
- AWS Lambda コンソールエディタ
サポートされる自然言語
コード生成のためのコメントは、現時点では、英語以外は公式にはサポートしていないようです。 ただ、学習データに英語以外の言語が含まれているため、日本語を利用した場合でも、コードの候補が出てくることもあるようです。
使い方
利用開始方法
AWSのサイトに動画で各IDEでの利用方法が説明されています。 VSCodeでの利用を試してみましたが、インストールは非常に簡単でした。
①VS Codeの拡張機能「AWS Toolkit」をインストールします
②サイドパネルからAWS Toolkitのアイコンを選択し、CodeWhispererを開始します
③認証を求められるので認証方法を選び認証を通します
AWS LambdaコンソールやAWS Cloud9で利用する際は、codewhisperer:GenerateRecommendations
のIAMポリシーをIAM userかroleにアタッチする必要があるようです。
基本操作
VS Codeでは、以下のような操作で行います。
アクション | キー操作 |
---|---|
コードを提案させる | Alt + C |
別の候補を出す | 矢印キー(←、→) |
提案されたコードを採用する | Tabキー |
もちろん、コーディング中に自動で続きのコードの提案も出てくるのですが、 Alt + Cで明示的に提案させることができる点が、使い勝手がよいと感じました。
※VS Code拡張機能でIntelliJ系のキーマップにするものを入れていると、上記の操作が上手くいかないことがあるので注意です。
Lambdaで、DynamoDBのレコードを取得する処理と、そのユニットテストを書いてみた
実際どんなコードを生成してくれるのか、まずは基本的な処理として、DynamoDBのレコードを取得するようなコードを書いてみました。
言語はPythonを利用し、pytestとmotoを利用したユニットテストも生成してみました。
結論として、100%そのまま動くわけではありませんでしたが、手直しは1~2割程度で、8割のコードは自動生成されたものが使えました。
コメントを書いて「Ctrl+C」で提案されたコードを使い、手直しする際も、最初の数文字入力してから、「Ctrl+C」をすれば、続きの実装が提案され非常に楽にできました。 生産性は十分向上するレベルだと感じました。
DynamoDBへのアクセスを担うRepositoryクラスの実装をしている様子を撮影してみました。
以下に実装したコードの全体像を載せます。 CodeWhispererを使って、手直しつつ、5分かからずに書くことができました。 モックのDynamoDBテーブル作成など、正直面倒な部分も、さくっと一発作成されるので、かなり体験がよかったです。
リポジトリクラスとLambda handler
import boto3 # Write a DynamodbRepository class for accessing DynamoDB. # Use boto3.client('dynamodb') to create a client. # get_item/put_item methods and error handling are required. class DynamodbRepository: def __init__(self, table_name): self.client = boto3.client('dynamodb', region_name='us-east-1') self.table_name = table_name def get_item(self, key): try: response = self.client.get_item(TableName=self.table_name, Key=key) return response['Item'] except Exception as e: print(e) return None def put_item(self, item): try: response = self.client.put_item(TableName=self.table_name, Item=item) return response except Exception as e: print(e) return None # Write delete_item method here. def delete_item(self, key): try: response = self.client.delete_item(TableName=self.table_name, Key=key) return response except Exception as e: print(e) return None # Write a handler for get user item from DynamoDB using DynamodbRepository. # Trable name is 'users' and key is 'user_id' def get_user_item(event, context): table_name = 'users' dynamodb_repository = DynamodbRepository(table_name) key = {'user_id': {'S': event['pathParameters']['user_id']}} user_item = dynamodb_repository.get_item(key) if user_item is None: return { 'statusCode': 404, 'body': 'User not found' } else: return { 'statusCode': 200, 'body': user_item }
テストコード
import boto3 from handler import DynamodbRepository, get_user_item from moto import mock_dynamodb # write a test for DynamodbRepository.get_item() # Table item schema is {user_id: str, name: str, age: int} @mock_dynamodb def test_get_item(): client = boto3.client("dynamodb", region_name="us-east-1") client.create_table( TableName="users", KeySchema=[ {"AttributeName": "user_id", "KeyType": "HASH"}, ], AttributeDefinitions=[ {"AttributeName": "user_id", "AttributeType": "S"}, ], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) # put item to table using boto3 client client.put_item( TableName="users", Item={ "user_id": {"S": "1"}, "name": {"S": "John"}, "age": {"N": "20"}, } ) repo = DynamodbRepository('users') item = repo.get_item( key={'user_id': {'S': '1'}}) # assert assert item["user_id"]['S'] == "1" assert item["name"]['S'] == "John" assert item["age"]['N'] == "20" # write test code for get_user_item handler using pytest. using @mock_dynamodb and prepare data. @mock_dynamodb def test_get_user_item(): client = boto3.client("dynamodb", region_name="us-east-1") client.create_table( TableName="users", KeySchema=[ {"AttributeName": "user_id", "KeyType": "HASH"}, ], AttributeDefinitions=[ {"AttributeName": "user_id", "AttributeType": "S"}, ], ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, ) # put item to table using boto3 client client.put_item( TableName="users", Item={ "user_id": {"S": "1"}, "name": {"S": "John"}, "age": {"N": "20"}, } ) # prepare event event = { "pathParameters": { "user_id": "1" } } # call handler response = get_user_item(event, None) # assert assert response["statusCode"] == 200
実装として、もう少し丁寧に作りたい部分はありつつも、十分助けになるサポートになると感じました。 より使いこなすには、コメントを詳細に、より具体的するなど、指示の出し方のスキルが大事になりそうです。
なお、DynamoDB操作に関しては、直近非推奨になってしまったboto3.resource
を使った実装が提案されることもありました。
これは、学習段階ではboto3.resource
が利用されたコードがあったのだと想像します。
boto3.resource
に関するドキュメントは以下です。
https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html
コード参照(Code references)を試してみる
CodeWhispererでコードを生成していると、VS Codeであれば、「CODEWHISPERER REFERENCE LOG」の部分に 生成したコードがどんなオープンソースのコードを参照したか教えてくれます。
今回は、「Apache-2.0 license」のオープンソースのコードを参照しているようなので、問題なさそうです。
この機能はデフォルトでONになっており、オプトアウト可能なものです。
CodeWhispererを利用した結果、意図せずライセンス違反をする、なんてことを防げる便利な機能だと思いました。
セキュリティスキャンを試してみる
試しに、セキュリティキーをハードコーディングしてみると、ちゃんと警告を出してくれます。 ただし、セキュリティスキャンは、明示的に「Run Security Scan」を実行する必要があります。(画像赤枠部分)
次に、ベストプラクティスに沿っていない書き方をしてみます。
AWSリソースを関数実行のたびに作成するのは非効率だと、警告が出ています。
セキュリティスキャン機能を使うことで問題に気づいて対処すれば、問題も防げ、レビュイーの負担も減って嬉しいですね。
使い方については、AWSのYoutubeチャンネルには、PythonでDDDベースのサーバレスアプリをAmazon CodeWhispererで作るデモもあります。 この動画では、より大規模に開発をしているので、参考になりそうです。
また、どんな使い方があるのかも、ドキュメントで例が載っていました。 こちらも参考にできそうです。 docs.aws.amazon.com
ドキュメントからわかったこと
最後に、ドキュメント等を一通り読んでわかったことです。 実際に業務で利用する上で、確認しておきたいプランの違いやセキュリティについて、特に重要だと感じた部分をまとめてみました。
安全性・セキュリティ
この手のサービスで気になるのは、セキュリティや安全性だと思います。 ドキュメントやFAQsのページで説明されている内容で、特に重要と思った項目を挙げてみたいと思います。
- CloudTrail適用
- TLSサポート
- データ収集
- 著作権面
-
- Amazon CodeWhisperer のFAQsページでは、はっきりと、CodeWhispererで生成したコードを含め、開発者本人が所有することが明記されています。
- FAQsの原文を引用すると、こう表現されています。「Just like with your IDE, you own the code that you write, including any code suggestions provided by CodeWhisperer. 」
- 生成AIで作成したコードは誰が所有するのか?という問題は、しばしば議論される領域で、他のサービスではコードの所有が誰にあるのか明言していないものもあります。CodeWhispererがここで「you own the code」と明言しているのは、業務で利用するという点で、一つハードルをクリアしやすくなっていると思いました。
- 収集されたコードの漏洩
-
- Professionalでは、「No. Content processed by CodeWhisperer Professional, such as code snippets, comments, and contents from files open in the IDE, is not stored or used to train the model, and therefore will never be reproduced in a code suggestion for another user.」と書かれており、はっきりと否定されています。
- Individualでは、「We have safeguards designed to prevent reproduction of unique private code collected from CodeWhisperer Individual users.」という説明がされています。
- このことから、コード漏洩のリスクとしては、Professionalプランを利用する方が安全であると思われます。
ProfessionalとIndividualの違い
- ユースケース
-
- Professional利用は、組織や企業向けに設計されています。ソフトウェア開発プロジェクトに取り組むチームのニーズに対応する追加機能と構成を提供します。
- Individual利用は、CodeWhispererの機能から恩恵を受けたいが、高度な機能や組織レベルの構成を必要としない個人の開発者や小規模なチーム向けに設計されています。
- データの収集と使用
- メトリクスの送信
-
- ProfessionalとIndividualの両方で、サービス改善のためにクライアントサイドのメトリクスを収集し、使用されるようです。IDEの設定でオプトアウトすることができるようです。
- ユーザ管理
料金と制限
IndividualとProfessionalの、料金・制限の面での違いをまとめました。
機能 | Individual | Professional |
---|---|---|
料金 | 無料 | $19/ユーザー/月 |
認証 | AWS Builder ID | AWS IAM Identity Center |
コード生成言語 | 全てのサポート言語 | 全てのサポート言語 |
コード参照 (Code references) | あり | あり |
コードセキュリティスキャン | $50/ユーザー/月 | $500/ユーザー/月 |
組織ライセンス管理 | なし | あり |
組織ポリシー管理 | なし | あり |
オプトアウト方法
CodeWhisperer利用時にAWSに送信されるデータのオプトアウト方法についてみてみます。
先に触れたように、Individualプランではコメント、IDEで開いているファイルの内容などのコンテンツがAWSに送信されます。 IDEのメトリクスやテレメトリーは、IndividualでもProfessionalでもAWSに送信されます。
それぞれのプラン、IDEでのオプトアウト方法は、以下のドキュメントに記載がありました。
まとめ
Amazon CodeWhispererを使用してみて、使い勝手の良さが非常によかったです。 特に、AWSサービスを利用する実装は、他のAIコード生成サービスよりも、CodeWhispererに軍配が上がる感触を持ちました。 セキュリティスキャン、ライセンス検知などの機能も便利で、コード品質向上のために実際的に役に立つと感じました。
また、セキュリティ・安全性の観点から、業務での利用はProfessionalを利用することが望ましいように思います。 組織の要件に応じて、オプトアウトすることも忘れずに適用しておきたいところです。
今回はPythonでLambda関数を書く例でしたが、CodeWhispererを活用すれば、CDKの実装やFargateで動かすAPIサーバーなんかも、楽につくれるようになるのではと思います。
生成AI、万歳!
それでは
Acroquest Technologyでは、キャリア採用を行っています。少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。 www.wantedly.com
- ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
- Elasticsearch等を使ったデータ収集/分析/可視化
- マイクロサービス、DevOps、最新のOSSやクラウドサービスを利用する開発プロジェクト
- 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長