Back to blog
Tutorial·7 min read·1218 words

How to Build an AI-Powered Code Review Bot with Function Calling

Learn how to build a production-ready AI code review bot using function calling. This step-by-step tutorial covers tool definitions, the tool-call loop, GitHub Actions integration, and cost optimization.

How to Build an AI-Powered Code Review Bot with Function Calling — illustration

How to Build an AI-Powered Code Review Bot with Function Calling

Code review is one of the most time-consuming tasks in software development. Senior engineers spend hours reading pull requests, catching bugs, enforcing style guides, and suggesting improvements. But what if you could automate the repetitive parts — and let AI handle the first pass?

In this tutorial, you will build a fully functional AI code review bot that analyzes pull requests, identifies potential issues, and posts review comments automatically. We will use function calling (also known as tool use) to give the AI model structured tools for inspecting code, and we will deploy it as a GitHub Action.

Prerequisites

Before starting, you will need:

  • A Qubax API key (for access to AI models)
  • Node.js 20+ installed
  • A GitHub repository where you have admin access
  • Basic familiarity with JavaScript/TypeScript

We will use Claude Sonnet 5 as our review model — it offers excellent code analysis at reasonable cost ($1.94/M input, $9.70/M output on Qubax). You can swap in any model that supports function calling.

Step 1: Understanding Function Calling

Function calling lets you define tools that the AI model can invoke. Instead of just generating text, the model can call functions you provide, receive the results, and continue reasoning.

For our code review bot, we will define tools like:

  • report_issue — Report a code issue found during review
  • approve_pr — Approve the pull request with no issues found

Here is the tool definition format:

javascript
const tools = [
  {
    type: "function",
    function: {
      name: "report_issue",
      description: "Report a code issue found during review.",
      parameters: {
        type: "object",
        properties: {
          severity: {
            type: "string",
            enum: ["critical", "warning", "suggestion", "nitpick"]
          },
          file: { type: "string" },
          line: { type: "number" },
          message: { type: "string" },
          suggestion: { type: "string" }
        },
        required: ["severity", "file", "message"]
      }
    }
  },
  {
    type: "function",
    function: {
      name: "approve_pr",
      description: "Approve the pull request with no issues found.",
      parameters: {
        type: "object",
        properties: {
          summary: { type: "string" }
        },
        required: ["summary"]
      }
    }
  }
];

Step 2: Setting Up the Project

Create a new directory and initialize the project:

bash
mkdir ai-code-reviewer
cd ai-code-reviewer
npm init -y
npm install dotenv

Create a .env file:

code
QUBAX_API_KEY=your-key-here

Step 3: Building the Core Review Engine

Create reviewer.mjs — this is the heart of our bot:

javascript
import 'dotenv/config';

const QUBAX_API_KEY = process.env.QUBAX_API_KEY;
const MODEL = 'claude-sonnet-5';

const tools = [
  {
    type: "function",
    function: {
      name: "report_issue",
      description: "Report a code issue found during review.",
      parameters: {
        type: "object",
        properties: {
          severity: { type: "string", enum: ["critical", "warning", "suggestion", "nitpick"] },
          file: { type: "string" },
          line: { type: "number" },
          message: { type: "string" },
          suggestion: { type: "string" }
        },
        required: ["severity", "file", "message"]
      }
    }
  }
];

async function reviewPullRequest(files, prDescription) {
  const systemPrompt = `You are an expert code reviewer. Analyze the changed files from a pull request.

PR Description: ${prDescription}

For each file, look for:
1. Bugs and logic errors
2. Security vulnerabilities
3. Performance issues
4. Style and best practice violations
5. Missing error handling

Use the report_issue tool for each issue found.`;

  const fileContents = files.map(f =>
    `--- File: ${f.filename} ---${'\n'}${f.patch || f.content}`
  ).join('\n\n');

  const messages = [
    { role: "system", content: systemPrompt },
    { role: "user", content: `Review these files:\n\n${fileContents}` }
  ];

  let allIssues = [];
  let isComplete = false;
  let loopCount = 0;

  while (!isComplete && loopCount < 10) {
    loopCount++;
    const response = await fetch('https://api.qubax.ai/v1/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${QUBAX_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        model: MODEL,
        messages: messages,
        tools: tools,
        tool_choice: "auto",
        temperature: 0.1
      })
    });

    const data = await response.json();
    const assistantMessage = data.choices[0].message;
    messages.push(assistantMessage);

    if (assistantMessage.tool_calls && assistantMessage.tool_calls.length > 0) {
      for (const toolCall of assistantMessage.tool_calls) {
        const args = JSON.parse(toolCall.function.arguments);
        if (toolCall.function.name === 'report_issue') {
          allIssues.push(args);
          messages.push({
            role: "tool",
            tool_call_id: toolCall.id,
            content: JSON.stringify({ status: "recorded" })
          });
        }
      }
    } else {
      isComplete = true;
    }
  }

  return { issues: allIssues, totalIssues: allIssues.length };
}

export { reviewPullRequest };

The key pattern is the tool-call loop: send the request, check if the model called any tools, process those tool calls, feed the results back, and repeat until the model stops calling tools.

Step 4: Creating the GitHub Action

Create .github/workflows/ai-review.yml:

yaml
name: AI Code Review
on:
  pull_request:
    types: [opened, synchronize, reopened]
jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install dependencies
        run: npm install dotenv
      - name: Run AI Review
        env:
          QUBAX_API_KEY: ${{ secrets.QUBAX_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: node review-action.mjs

Step 5: Testing the Bot

Push the workflow and open a test PR with intentional issues:

javascript
// buggy-auth.js
const password = "hardcoded_secret_123";

function login(req, res) {
  const user = db.query("SELECT * FROM users WHERE name = '" + req.body.username + "'");
  if (user.password == req.body.password) {
    return res.send({ token: generateToken(user.id) });
  }
  res.send("Login failed");
}

The AI reviewer should flag the hardcoded password, SQL injection, loose equality, and error message leakage.

Step 6: Cost Optimization

Use Cheaper Models for Simple Files

javascript
function selectModel(file) {
  const linesChanged = (file.patch || '').split('\n').length;
  if (linesChanged < 50) return 'gpt-5.6-luna';
  if (linesChanged > 200) return 'claude-sonnet-5';
  return 'glm-5.2';
}

Skip Generated Files

javascript
const SKIP_PATTERNS = [/lock$/, /\.min\./, /node_modules/, /generated/, /\.snap$/];
const shouldReview = (filename) => !SKIP_PATTERNS.some(p => p.test(filename));

Cost Estimation

For a team with 50 PRs per week, each averaging 200 lines of changes:

ModelEst. Weekly CostMonthly Cost
GPT-5.6 Luna~$3~$12
GLM 5.2~$2~$8
Claude Sonnet 5~$15~$60

Using a tiered approach keeps costs around $20-30/month. See Qubax pricing for current rates.

Going Further

  • Inline comments: Post comments on specific GitHub lines
  • Memory: Store review feedback for team preference learning
  • Custom rules: Define project-specific rules in a config file
  • Slack notifications: Alert on critical issues

Conclusion

Building an AI code review bot with function calling saves engineering teams hours every week. With models ranging from budget-friendly GLM 5.2 to powerful Claude Sonnet 5 on Qubax, you can tune the cost-to-quality ratio for your team. Get started with the Qubax API docs.


FAQ

Which AI model is best for code review?

Claude Sonnet 5 offers the best balance of accuracy and cost. For budget-conscious teams, GLM 5.2 or GPT-5.6 Luna work well for simpler files. All available on Qubax.

How much does it cost to run an AI code reviewer?

For a small team (50 PRs/week), expect $8-60/month depending on model choice. A tiered approach keeps costs around $20-30/month.

Does this work with GitLab or Bitbucket?

Yes. The review engine is platform-agnostic. Replace the GitHub-specific API calls with your platform equivalents.

Can the bot approve PRs automatically?

Yes, but use caution. Configure branch protection to require at least one human review for production code.

How do I handle large pull requests?

Batch files into groups of 5-10 per API call. Use a summarization step first for very large PRs.

🤖

Try Claude Sonnet 5 on Qubax

Best balance of speed and quality. Up to 62% off.

View pricing

Article tags

#code-review#function-calling#github-actions#automation#tutorial
Share:Post on XTelegramLinkedInYHacker NewsReddit
Qubax AI

Qubax AI

AI Models at up to 99% off · Pay with crypto

Reading about Claude Sonnet 5 and Claude? Access them — plus 340+ other models — through one API. Best balance of speed and quality. Up to 62% off.

Related articles