{"id":4351,"date":"2025-03-12T15:27:35","date_gmt":"2025-03-12T22:27:35","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=4351"},"modified":"2025-03-13T07:02:51","modified_gmt":"2025-03-13T14:02:51","slug":"customer-case-story-creating-a-semantic-kernel-agent-for-automated-github-code-reviews","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/customer-case-story-creating-a-semantic-kernel-agent-for-automated-github-code-reviews\/","title":{"rendered":"Customer Case Story: Creating a Semantic Kernel Agent for Automated GitHub Code Reviews"},"content":{"rendered":"<p>Today I want to welcome a guest author to our Semantic Kernel blog, Rasmus Wulff Jensen, to cover how he&#8217;s created a Semantic Kernel agent for automated GitHub code review. We&#8217;ll turn it over to Rasmus to dive in.<\/p>\n<h2>Introduction<\/h2>\n<p>If you work in software development, you know that Code reviews are an essential part of the software development process, ensuring quality, security, and maintainability. However, they also consume a significant amount of developers\u2019 time, often delaying feature delivery and increasing workload. Recognizing this challenge, the company\u00a0<a href=\"https:\/\/www.relewise.com\/\">Relewise<\/a>, a Search and Recommendation SASS Business, streamlined its development workflow by introducing an AI Agent that conducts automated pull request (PR) reviews before human intervention.<\/p>\n<h2><strong>Why build it yourself?<\/strong><\/h2>\n<p>Given that GitHub Copilot offers a similar preview feature, one might ask why we chose to build our own solution. The key reasons are control and cost; we have full control over Developer (System) Messages, and the option to include additional task-definition data to the system and control every single step of the way + We only pay for token usage, rather than a per-user subscription. Finally, we see the quality of the reviews being much better.<\/p>\n<h2><strong>How it all works (Building blocks and flow)<\/strong><\/h2>\n<p>Below are the building blocks and the flow of the AI Agent (each of the 6 steps is explained in detail below)<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/03\/Steps.png\"><img decoding=\"async\" class=\"alignnone wp-image-4404 size-full\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/03\/Steps.png\" alt=\"Image Steps\" width=\"940\" height=\"678\" srcset=\"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/Steps.png 940w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/Steps-300x216.png 300w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/Steps-768x554.png 768w\" sizes=\"(max-width: 940px) 100vw, 940px\" \/><\/a><\/p>\n<h2><strong>Step 1: Developer creates Pull Request<\/strong><\/h2>\n<p>When the Developer creates their Pull Request and marks it as ready a GitHub Webhook triggers and informs the AI Agent that it is time to do a review.<\/p>\n<h2><strong>Step 2: Get the Pull Request<\/strong><\/h2>\n<p>The AI Agent now determines, based on its setting what type of Review it should do and gathers the PR Diff Content (what code the developer has added, changed, and removed)<\/p>\n<p><em>Here is how we retrieve the PR diff using the GitHub API<\/em><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">public async Task&lt;string&gt; GetPrDiff(GitHubClient client, string owner, string repo, int pullRequestNumber)\r\n{\r\n\u00a0 \u00a0 var diffUrl = $\"https:\/\/api.github.com\/repos\/{owner}\/{repo}\/pulls\/{pullRequestNumber}\";\r\n\u00a0 \u00a0 var diff = await client.Connection.Get&lt;string&gt;(\r\n\u00a0 \u00a0 \u00a0 \u00a0 new Uri(diffUrl),\r\n\u00a0 \u00a0 \u00a0 \u00a0 new Dictionary&lt;string, string&gt;(),\r\n\u00a0 \u00a0 \u00a0 \u00a0 \"application\/vnd.github.v3.diff\"\r\n );\r\n\r\n\u00a0 \u00a0 return diff.Body;\r\n}<\/code><\/pre>\n<h2><strong>Step 3: Get Task Definition<\/strong><\/h2>\n<p>Beyond the Code, we also want to feed the AI with a title and description of what task, linked to the PR, that the developer set out to achieve, in order for the AI to evaluate if the code actually accomplishes the job.<\/p>\n<h2><strong>Step 4: Conduct the AI Review (+ optional Step 5)<\/strong><\/h2>\n<p>We now have all the data needed for the review, we create our Semantic Kernel object with o3-mini-high for Azure Open AI Services as backend.<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">var kernelBuilder = Kernel.CreateBuilder();\r\n\r\nvar httpClient = new HttpClient\r\n\r\n{\r\n\r\nTimeout = TimeSpan.FromMinutes(5)\r\n\r\n};\r\n\r\nkernelBuilder.AddAzureOpenAIChatCompletion(\"o3-mini\", endpoint, apiKey, httpClient: httpClient);\r\n\r\nvar kernel = kernelBuilder.Build();<\/code><\/pre>\n<p>Our Agent<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">var agent = new ChatCompletionAgent\r\n\r\n{\r\n\r\nName = \"RelewisePrReviewer\",\r\n\r\nKernel = kernel,\r\n\r\nInstructions = \"\"\"\r\n\r\nYou are a highly experienced and extremely thorough C# code reviewer.\r\n\r\nYour task is to review the provided GitHub PR diff.\r\n\r\nYou will particularly pay attention to logical and performance bugs and\r\n\r\nregressions, and generally be very meticulous in determining what this PR\r\n\r\nintroduces in terms of new and\/or changed features and\/or behaviors.\r\n\r\nShould you at any point discover that it would be beneficial to you as the\r\n\r\nreviewer to see additional types, you may at any point continue to ask me for\r\n\r\nadditional types, and then I may provide them to you.\r\n\r\n\"\"\",\r\n\r\nArguments = new KernelArguments(new AzureOpenAIPromptExecutionSettings\r\n\r\n{\r\n\r\nReasoningEffort = ChatReasoningEffortLevel.High,\r\n\r\nResponseFormat = typeof(Review)\r\n\r\n})\r\n\r\n};<\/code><\/pre>\n<p>Note that we use o3-Mini&#8217;\u00a0ReasoningEffortLevel and the\u00a0ResponseFormat\u00a0is set so instead of a normal response we get\u00a0<a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/using-json-schema-for-structured-output-in-net-for-openai-models\/\">structured output<\/a>\u00a0that reduce the Developer (System) Message and allow us to get both the review and additional requested files back in a single request.<\/p>\n<p><em>The Structured Output class is as follows.<\/em><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">public class Review\r\n{\r\n [Description(\"A Short, concise but sufficient summary of what this PR introduces\/changes, and any general observations you find relevant in the context of the review, focus on functional changes that make a difference to the users of the system\")]\r\n\u00a0 \u00a0 public required string Summary { get; init; }\r\n\r\n [Description(\"You will for all bug\/regression\/errors explain what the error is, where it is (include type names and namespaces when possible), why it's an error, and if possible short guidance on how to fix it. Do not use any type of bullet-list formatting\")]\r\n\u00a0 \u00a0 public string[]? PotentialIssuesFound { get; init; }\r\n\r\n [Description(\"A List of other repo files that could improve the review if you had them\")]\r\n\u00a0 \u00a0 public ReviewAdditionalFile[]? AdditionalFilesThatCouldImproveReview { get; init; }\r\n\r\n}<\/code><\/pre>\n<p>We now call the agents InvokeAsync method to get the Review object (and the token usage statistics).<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">var chatHistory = new ChatHistory();\r\nchatHistory.AddUserMessage($\"\"\"\r\n Task: {taskDefinition.Title}\r\n - Description: {taskDefinition.Description}\r\n ---\r\n PR Diff: {prDiffContent}\r\n \"\"\");\r\n\r\nawait foreach (var content in agent.InvokeAsync(chatHistory))\r\n{\r\n\u00a0 \u00a0 var json = content.ToString();\r\n\u00a0 \u00a0 var tokenIn = 0;\r\n\u00a0 \u00a0 var tokenOut = 0;\r\n\u00a0 \u00a0 if (content.Metadata?.TryGetValue(\"Usage\", out var usage) == true &amp;&amp; usage is ChatTokenUsage chatTokenUsage)\r\n {\r\n\u00a0 \u00a0 \u00a0 \u00a0 tokenIn = chatTokenUsage.InputTokenCount;\r\n\u00a0 \u00a0 \u00a0 \u00a0 tokenOut = chatTokenUsage.OutputTokenCount;\r\n }\r\n\u00a0 \u00a0 var review = JsonSerializer.Deserialize&lt;Review&gt;(json)!;\r\n}<\/code><\/pre>\n<p>Some might think, why not ask AI what extra files it needs prior to the Review? It is done this way in order to save Input Tokens which is by far the biggest cost here. So by levering the excellent Structure Output feature we only need to give the PR-diff twice if additional files be needed, and if not a single pass to the LLM was all we needed.<\/p>\n<h2><strong>Step 6: Add Pull Request Comment<\/strong><\/h2>\n<p>As what you now do with the Review is a matter of opinion. We have chosen to add a simple PR Comment with potential comments to keep it short, and with a link to the longer review displayed at a link to the full review on an Internal Website.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/03\/prComment.png\"><img decoding=\"async\" class=\"alignnone wp-image-4403 size-full\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/03\/prComment.png\" alt=\"Image prComment\" width=\"913\" height=\"217\" srcset=\"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/prComment.png 913w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/prComment-300x71.png 300w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/prComment-768x183.png 768w\" sizes=\"(max-width: 913px) 100vw, 913px\" \/><\/a><\/p>\n<p>&#8230; But it is also possible to instruct the AI via the structured output to give line-by-line Comments if that suits your team (it is clever enough to do it) or post the full review directly as a GitHub comment.<\/p>\n<p>The review is now done; If no findings, then it is time for a human to make the final review, but if anything is found the original developer can immediately react to it and not lose flow waiting for colleagues to have time to do the review.<\/p>\n<h2><strong>Reception from the developers<\/strong><\/h2>\n<p>As we started a prototype of this project prior to having API Access to the Open AI reasoning models, early iterations of the Agent sometimes produced inaccurate findings, leading to skepticism among the developers. However, after switching to reasoning models and refining instructions, accuracy has significantly improved. It has even become a thing for one of the developers to do this \ud83d\ude09<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/03\/thanksAi.png\"><img decoding=\"async\" class=\"alignnone wp-image-4402 size-full\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2025\/03\/thanksAi.png\" alt=\"Image thanksAi\" width=\"1138\" height=\"323\" srcset=\"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/thanksAi.png 1138w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/thanksAi-300x85.png 300w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/thanksAi-1024x291.png 1024w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2025\/03\/thanksAi-768x218.png 768w\" sizes=\"(max-width: 1138px) 100vw, 1138px\" \/><\/a><\/p>\n<h2><strong>Future<\/strong><\/h2>\n<p>We will continue to tweak and upgrade to new LLM models + leverage other tools and techniques from Semantic Kernal and Azure Open AI. Perhaps one day in the distant future we might get so far that once the AI is done with the review it will merge and deploy the code itself&#8230; We are not there yet, but this is still a huge first step toward it \ud83d\ude4c<\/p>\n<p>Link to original discussion:<a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/discussions\/10634\"> https:\/\/github.com\/microsoft\/semantic-kernel\/discussions\/10634<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I want to welcome a guest author to our Semantic Kernel blog, Rasmus Wulff Jensen, to cover how he&#8217;s created a Semantic Kernel agent for automated GitHub code review. We&#8217;ll turn it over to Rasmus to dive in. Introduction If you work in software development, you know that Code reviews are an essential part [&hellip;]<\/p>\n","protected":false},"author":149071,"featured_media":4477,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[42,1],"tags":[48,63,126,9],"class_list":["post-4351","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-customer-story","category-semantic-kernel","tag-ai","tag-microsoft-semantic-kernel","tag-relewise","tag-semantic-kernel"],"acf":[],"blog_post_summary":"<p>Today I want to welcome a guest author to our Semantic Kernel blog, Rasmus Wulff Jensen, to cover how he&#8217;s created a Semantic Kernel agent for automated GitHub code review. We&#8217;ll turn it over to Rasmus to dive in. Introduction If you work in software development, you know that Code reviews are an essential part [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4351","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/149071"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=4351"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/4351\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/4477"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=4351"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=4351"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=4351"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}