„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Besser – eine KI-gestützte Code-Reviewer-GitHub-Aktion

Besser – eine KI-gestützte Code-Reviewer-GitHub-Aktion

Veröffentlicht am 08.11.2024
Durchsuche:615

Codeüberprüfungen waren schon immer von entscheidender Bedeutung für die Aufrechterhaltung eines Standards und die Betonung der Best Practices des Codes in einem Projekt. In diesem Beitrag geht es nicht darum, wie Entwickler den Code überprüfen sollten, sondern vielmehr darum, einen Teil davon an die KI zu delegieren.

Wie Michael Lynch in seinem Beitrag „How to Do Code Reviews Like a Human“ erwähnt, sollten wir den Computern die langweiligen Teile der Codeüberprüfung überlassen. Während Michael den Schwerpunkt auf ein Formatierungstool legt, möchte ich noch einen Schritt weiter gehen und es künstlicher Intelligenz überlassen. Ich meine, warum nicht den KI-Boom in der Branche nutzen?

Jetzt sage ich nicht, dass KI anstelle von Formatierungstools und Linters verwendet werden sollte. Stattdessen soll es darüber hinaus verwendet werden, um triviale Dinge zu fangen, die einem Menschen möglicherweise entgehen.

Deshalb habe ich beschlossen, eine Github-Aktion zu erstellen, deren Code einen Pull-Request-Diff überprüft und mithilfe von KI Vorschläge generiert. Lassen Sie mich es Ihnen erklären.

? Notiz

  • Diese GitHub-Aktion ist jetzt auf dem GitHub-Marktplatz verfügbar.
  • Es ist eine Javascript-Aktion – erfahren Sie mehr über das Erstellen von Javascript-Github-Aktionen.

Den Unterschied bekommen

Um mit der Github-API zu interagieren, habe ich Octokit verwendet, eine Art SDK oder eine Client-Bibliothek für die idiomatische Interaktion mit der Github-API.

Damit Sie den Diff der Pull-Anfrage erhalten, müssen Sie den Accept-Header mit dem Wert application/vnd.github.diff zusammen mit den erforderlichen Parametern übergeben.

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,
        },
    });
}

Wenn Sie mit Github-Aktionen überhaupt nicht vertraut sind, finden Sie hier eine Github-Aktionen 101-Serie von Victoria Lo und es ist ein guter Anfang.

Sobald ich den Unterschied erhalte, analysiere ich ihn, entferne unerwünschte Änderungen und gebe ihn dann in einem unten gezeigten Schema zurück:

/** 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(),
})

Dateien ignorieren

Dateien zu ignorieren ist ganz einfach. Die Benutzereingabeliste erfordert eine durch Semikolons getrennte Zeichenfolge von Glob-Mustern. Anschließend wird es analysiert, mit der Standardliste der ignorierten Dateien verkettet und dedupliziert.

**/*.md; **/*.env; **/*.lock;
const filesToIgnoreList = [
    ...new Set(
        filesToIgnore
            .split(";")
            .map(file => file.trim())
            .filter(file => file !== "")
            .concat(FILES_IGNORED_BY_DEFAULT)
    ),
];

Die Liste der ignorierten Dateien wird dann verwendet, um die Diff-Änderungen zu entfernen, die sich auf diese ignorierten Dateien beziehen. Dadurch erhalten Sie eine Rohnutzlast, die nur die gewünschten Änderungen enthält.

Vorschläge generieren

Sobald ich nach dem Parsen des Diffs die Rohnutzlast erhalte, übergebe ich sie an die Plattform-API. Hier ist eine Implementierung der 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;
}

Möglicherweise bemerken Sie die Verwendung des Antwortformats in der API-Implementierung. Hierbei handelt es sich um eine von vielen LLM-Plattformen bereitgestellte Funktion, mit der Sie das Modell anweisen können, die Antwort in einem bestimmten Schema/Format zu generieren. Dies ist in diesem Fall besonders hilfreich, da ich nicht möchte, dass das Modell halluziniert und Vorschläge für falsche Dateien oder Positionen in der Pull-Anfrage generiert oder der Antwortnutzlast neue Eigenschaften hinzufügt.

Die Systemeingabeaufforderung dient dazu, dem Modell mehr Kontext dazu zu geben, wie es die Codeüberprüfung durchführen soll und welche Dinge zu beachten sind. Sie können die Systemaufforderung hier anzeigen: github.com/murtuzaalisurti/better.

Die Benutzeraufforderung enthält das eigentliche Diff, die Regeln und den Kontext des Pull-Requests. Es ist der Startschuss für die Codeüberprüfung.

Diese Github-Aktion unterstützt sowohl OpenAI- als auch Anthropic-Modelle. So implementiert es die 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;
}

Kommentare hinzufügen

Nachdem ich die Vorschläge abgerufen habe, bereinige ich sie und übergebe sie an die Github-API, um im Rahmen der Überprüfung Kommentare hinzuzufügen.

Ich habe die unten stehende Methode zum Hinzufügen von Kommentaren gewählt, da Sie durch das Erstellen einer neuen Bewertung alle Kommentare auf einmal hinzufügen können, anstatt jeweils einen einzelnen Kommentar hinzuzufügen. Das Hinzufügen von Kommentaren nacheinander kann ebenfalls eine Ratenbegrenzung auslösen, da das Hinzufügen von Kommentaren Benachrichtigungen auslöst und Sie Benutzer nicht mit Benachrichtigungen spammen möchten.

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;
    }
}

Abschluss

Ich wollte die Github-Aktion offen und offen für Integrationen halten und deshalb können Sie jedes Modell Ihrer Wahl verwenden (siehe Liste der unterstützten Modelle), oder Sie können eine Feinabstimmung vornehmen und erstellen Erstellen Sie Ihr eigenes benutzerdefiniertes Modell zusätzlich zu den unterstützten Basismodellen und verwenden Sie es mit dieser Github-Aktion.

Wenn Sie auf Token-Probleme oder Ratenbegrenzungen stoßen, möchten Sie möglicherweise Ihre Modelllimits aktualisieren, indem Sie sich auf die Dokumentation der jeweiligen Plattform beziehen.

Also, worauf warten Sie noch? Wenn Sie ein Repository auf Github haben, probieren Sie die Aktion jetzt aus – sie befindet sich auf dem Github-Aktionsmarktplatz.

Better - An AI powered Code Reviewer GitHub Action murtuzaalisurti / besser

Eine von KI unterstützte Code-Reviewer-Github-Aktion, die in Ihrem Workflow verwendet werden kann.

besser

Eine von KI unterstützte Code-Reviewer-Github-Aktion, die in Ihrem Workflow verwendet werden kann.

Warum es verwenden?

  • Standardisieren Sie Ihren Codeüberprüfungsprozess
  • Schneller Feedback erhalten
  • Muster erkennen, die zu fehlerhaftem Code führen
  • Erkennung häufiger Probleme
  • Sicherheitslücken identifizieren
  • Zweite Meinung
  • Damit sich Menschen auf komplexere Aufgaben konzentrieren können

Verwendung

1. Erstellen Sie einen Workflow

Erstellen Sie eine Workflow-Datei im Ordner „.github/workflows“ (erstellen Sie sie, falls sie nicht vorhanden ist) Ihres Repositorys mit dem folgenden Inhalt:

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
Vollbildmodus aufrufen Vollbildmodus verlassen
Auf GitHub ansehen
Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/murtuzaalisurti/better-an-ai-powered-code-reviewer-github-action-2n28?1 Bei Verstößen wenden Sie sich zum Löschen bitte an [email protected] Es
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3