コードレビューは、標準を維持し、プロジェクト内のコードのベストプラクティスを強調する上で常に重要です。これは開発者がコードをどのようにレビューすべきかについての投稿ではなく、コードの一部を AI に委任することについての投稿です。
Michael Lynch が投稿「人間のようにコード レビューを行う方法」で述べているように、コード レビューの退屈な部分は コンピュータに任せるべきです。マイケルは書式設定ツールを強調していますが、私はそれをさらに一歩進めて、人工知能に理解させたいと考えています。つまり、業界の AI ブームを利用してみてはいかがでしょうか?
私は、整形ツールやリンターの代わりに AI を使用すべきだと言っているわけではありません。代わりに、人間が見逃してしまう可能性のある些細な情報をキャッチするために、その上で使用されます。
そこで、プル リクエストの差分をコードレビューし、AI を使用して提案を生成する github アクションを作成することにしました。順を追って説明しましょう。
?注記
- この GitHub アクションは GitHub マーケットプレイスで入手できるようになりました。
- これは JavaScript アクションです - JavaScript github アクションの作成について詳しく学習してください。
github API と対話するために、octokit を使用しました。これは、慣用的な方法で github API と対話するための SDK またはクライアント ライブラリの一種です。
発生したプル リクエストの差分を取得するには、値 application/vnd.github.diff を持つ Accept ヘッダーを必要なパラメータとともに渡す必要があります。
async function getPullRequestDetails(octokit, { mode }) { let AcceptFormat = "application/vnd.github.raw json"; if (mode === "diff") AcceptFormat = "application/vnd.github.diff"; if (mode === "json") AcceptFormat = "application/vnd.github.raw json"; return await octokit.rest.pulls.get({ owner: github.context.repo.owner, repo: github.context.repo.repo, pull_number: github.context.payload.pull_request.number, headers: { accept: AcceptFormat, }, }); }
Github Actions にまったく慣れていない場合は、Victoria Lo による Github Actions 101 シリーズが良いスタートとなります。
差分を取得したら、それを解析して不要な変更を削除し、次に示すスキーマで返します。
/** using zod */ schema = z.object({ path: z.string(), position: z.number(), line: z.number(), change: z.object({ type: z.string(), add: z.boolean(), ln: z.number(), content: z.string(), relativePosition: z.number(), }), previously: z.string().optional(), suggestions: z.string().optional(), })
ファイルを無視するのは非常に簡単です。ユーザー入力リストには、セミコロンで区切られた glob パターンの文字列が必要です。その後、解析され、無視されたファイルのデフォルトのリストと連結され、重複が排除されます。
**/*.md; **/*.env; **/*.lock;
const filesToIgnoreList = [ ...new Set( filesToIgnore .split(";") .map(file => file.trim()) .filter(file => file !== "") .concat(FILES_IGNORED_BY_DEFAULT) ), ];
無視されたファイルのリストは、無視されたファイルを参照する diff の変更を削除するために使用されます。これにより、必要な変更のみを含む生のペイロードが得られます。
差分の解析後に生のペイロードを取得したら、それをプラットフォーム API に渡します。これは OpenAI API の実装です。
async function useOpenAI({ rawComments, openAI, rules, modelName, pullRequestContext }) { const result = await openAI.beta.chat.completions.parse({ model: getModelName(modelName, "openai"), messages: [ { role: "system", content: COMMON_SYSTEM_PROMPT, }, { role: "user", content: getUserPrompt(rules, rawComments, pullRequestContext), }, ], response_format: zodResponseFormat(diffPayloadSchema, "json_diff_response"), }); const { message } = result.choices[0]; if (message.refusal) { throw new Error(`the model refused to generate suggestions - ${message.refusal}`); } return message.parsed; }
API 実装で応答形式が使用されていることに気づくかもしれません。これは多くの LLM プラットフォームによって提供される機能で、特定のスキーマ/形式で応答を生成するようにモデルに指示できます。これは、モデルが幻覚を起こしてプル リクエスト内の間違ったファイルや位置の提案を生成したり、応答ペイロードに新しいプロパティを追加したりすることを望まないため、この場合に特に役立ちます。
システム プロンプトは、コード レビューをどのように行うべきか、またどのような点に留意する必要があるかについて、モデルに詳細なコンテキストを提供するためにあります。ここ github.com/murtuzaalisurti/better.
でシステム プロンプトを表示できます。ユーザー プロンプトには、実際の差分、ルール、プル リクエストのコンテキストが含まれています。これがコードレビューの始まりです。
この github アクションは、OpenAI モデルと Anthropic モデルの両方をサポートしています。 Anthropic API の実装方法は次のとおりです:
async function useAnthropic({ rawComments, anthropic, rules, modelName, pullRequestContext }) { const { definitions } = zodToJsonSchema(diffPayloadSchema, "diffPayloadSchema"); const result = await anthropic.messages.create({ max_tokens: 8192, model: getModelName(modelName, "anthropic"), system: COMMON_SYSTEM_PROMPT, tools: [ { name: "structuredOutput", description: "Structured Output", input_schema: definitions["diffPayloadSchema"], }, ], tool_choice: { type: "tool", name: "structuredOutput", }, messages: [ { role: "user", content: getUserPrompt(rules, rawComments, pullRequestContext), }, ], }); let parsed = null; for (const block of result.content) { if (block.type === "tool_use") { parsed = block.input; break; } } return parsed; }
最後に、提案を取得した後、それらをサニタイズして github API に渡し、レビューの一部としてコメントを追加します。
コメントを追加するために以下の方法を選択しました。新しいレビューを作成すると、一度に 1 つのコメントを追加するのではなく、すべてのコメントを一度に追加できるためです。コメントを 1 つずつ追加すると、通知がトリガーされ、ユーザーに通知をスパム送信したくないため、レート制限がトリガーされる可能性もあります。
function filterPositionsNotPresentInRawPayload(rawComments, comments) { return comments.filter(comment => rawComments.some(rawComment => rawComment.path === comment.path && rawComment.line === comment.line) ); } async function addReviewComments(suggestions, octokit, rawComments, modelName) { const { info } = log({ withTimestamp: true }); // eslint-disable-line no-use-before-define const comments = filterPositionsNotPresentInRawPayload(rawComments, extractComments().comments(suggestions)); try { await octokit.rest.pulls.createReview({ owner: github.context.repo.owner, repo: github.context.repo.repo, pull_number: github.context.payload.pull_request.number, body: `Code Review by ${modelName}`, event: "COMMENT", comments, }); } catch (error) { info(`Failed to add review comments: ${JSON.stringify(comments, null, 2)}`); throw error; } }
github アクションをオープンエンドで統合にオープンな状態に保ちたかったので、任意のモデルを使用できます (サポートされているモデルのリストを参照)、または微調整してビルドすることもできますサポートされている基本モデルに加えて独自のカスタム モデルを作成し、この github アクションで使用します。
トークンの問題やレート制限が発生した場合は、それぞれのプラットフォームのドキュメントを参照してモデル制限をアップグレードすることをお勧めします。
それで、何を待っているのですか? github にリポジトリがある場合は、今すぐアクションを試してください。github アクション マーケットプレイスにあります。
AI を活用したコード レビューアーの Github アクション。ワークフローですぐに使用できます。
リポジトリの .github/workflows フォルダー内に次の内容のワークフロー ファイルを作成します (存在しない場合は作成します):
name: Code Review
on
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
branches:
- main # change this to your target branch
workflow_dispatch: # Allows you to run the workflow manually from the Actions tab
permissions: # necessary permissions
pull-requests: write
contents: read
jobs:
your-job-name:
runs-on: ubuntu-latest
name: your-job-name
steps:
- name: step-name
id: step-id
uses: murtuzaalisurti/better@v2 # this is
…免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3