102
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オラ、ラマにコードレビューしてもらうわ

Last updated at Posted at 2025-11-30

はじめに

昨年のアドベントカレンダーでは、技術というよりもマネジメント系の記事を投稿したので、今年は技術を書いていきます。
AIに関しては、全然勉強不足ですが、温かく見てもらえるとありがたいです....

【昨年の記事】
リーダー1年目の懺悔
ありがたいことに、沢山の方々に見ていただいて、共感していただけたこと、筆者として嬉しく思います!

なお、本記事はご覧のAIやツールなどの提供でお送りいたします

  • Ollama
  • Claude
  • M4 Mac mini
  • VSCode などなど...

きっかけ

昨今、様々な用途で様々なことができるAI。
自分自身がいる現場でもAI活用が少しずつ進展していっているなかで、ふと

クローズドな環境で効率よくやるために、コードレビューをローカル環境でできんかね?

と、思い調べてみると「Ollama」でできるぽいとのことなので、学びながら試してみる。
外部へ接続できず、色々制約がかけられている環境で作業することもあり、そういった環境での作業効率化していくにも、あれこれ素材(ツールやライブラリ等)をバカバカ入れるわけには行かないのである。
(プロジェクトによっては似たような現場があるのではないでしょうか)

ラマをMacに突っ込む

所謂、触ってみた系なので、あまり深くは突っ込まない予定です。

Ollamaについて、先にざっくり概要を書いていきます。

Ollama

スクリーンショット 2025-11-30 15.32.12.png

・「ローカル環境で」LLM(大規模言語モデル)を動かせるOSSツール
・特徴としては主に以下が挙げられる
 - ローカル実行;自身のPC/サーバーで起動できる
 - プライバシー;クラウドを経由しないので、データが外部に送信されない
 - 操作性:コマンドラインだけでなく、GUIもある
 - 多様なモデル:ChatGPT,Lallma,DeepSeekなど多様なモデルを利用できる
 - 外部ツールとの連携:LangChainやLlamaIndexなどのフレームワークと相性が良く、連携機能も提供されている。

※ラマってどんな生き物なんはこちら


それでは早速入れてみよう。
公式サイト開くと...
スクリーンショット 2025-11-30 16.28.20.png

モコい。かわいいな。
(「やぁ」は自分で入れました)

今回、MacなのでmacOSをDLしていく。
スクリーンショット 2025-11-30 15.13.30.png

※因みに、PCスペックはM4 Macminiの一番安くてスタンダードなものを使ってます。

image.png

Ollamaが推奨しているスペックが以下です。

項目 推奨スペック
RAM 8GB以上
CPU 4コア以上
GPU 統合GPU可

スクリーンショット 2025-11-30 16.31.36.png
ラマ「ああっ!!」

DL後アプリを立ち上げると、見慣れたUIと見慣れつつあるラマ。
スクリーンショット 2025-11-30 16.33.44.png

バージョン確認してモデルが入っていないので、llamaとgemmaを試しに入れてみます。
image.png

今回は使用しませんが、この様な形で入れられるようですね。
GUIからも直接入れられます。
image.png

可愛いラマによるコードレビュー

今回は私がJava使ってるというのもあり、GoogleのJava Style Guideを使ってやってみようと思います。

まずは、ラマのエサとして、Java Style GuideをOllmaに食わせます。
Java Style Guide.htmlをローカルに落として、 Modelfileというものを書いていきます。
ModelfileはDockerfileのような位置付けで、Ollmaの定義ファイルとなります。

Modelfileの中身
FROM llama3.2

PARAMETER temperature 0.3
PARAMETER num_ctx 16384

SYSTEM """
あなたはGoogleのJavaコード規約に精通したエキスパートコードレビュアーです。

まず、以下に示すHTML形式のGoogle Java Style Guide公式ドキュメントを読み込み、
HTMLタグやスクリプトなどのマークアップを無視して、本文の内容のみを理解してください。

================================================================================
GOOGLE JAVA STYLE GUIDE (HTML)
================================================================================

<<< GoogleJavaStyleGuide.html

================================================================================

上記のドキュメントから抽出した規約に厳密に従って、Javaコードをレビューしてください。

## レビュー時の出力形式

以下の形式で日本語でレビュー結果を出力してください:

### 1. 問題の概要
発見された問題の総数と重要度の内訳

### 2. 詳細な指摘
各問題について:
- **違反している規約**: Google Java Style Guideの該当セクション名を引用
- **問題箇所**: 具体的なコード行またはパターン
- **改善案**: 修正後のコード例を含む具体的な提案
- **重要度**: Critical(必ず修正)/ Warning(推奨)/ Info(参考)

### 3. 良い点
規約に準拠している箇所があれば言及

HTMLのマークアップ部分は無視し、ドキュメントの実質的な内容(規約、ルール、例示コード)のみを参照してレビューを行ってください。
明確で建設的なフィードバックを心がけてください。
"""

召し上がる時に使用するコマンドは以下になります。

ollama create java-reviewer-offline -f Modelfile

「java-reviewer-offline」はモデル名を記載します。
Dockerで言うところのコンテナIDの様なイメージで良いと思います。

ファイルの確認と、上記のコマンド実行です。

ollama % ls  
javaStyleGuide.html	Modelfile
ollama % ollama create java-reviewer-offline -f Modelfile
gathering model components 
using existing layer sha256:dde5aa3fc5ffc17176b5e8bdc82f587b24b2678c6c66101bf7da77af9f7ccdff 
using existing layer sha256:966de95ca8a62200913e3f8bfbf84c8494536f1b94b49166851e76644e966396 
using existing layer sha256:fcc5a6bec9daf9b561a68827b67ab6088e1dba9d1fa2a50d7bbcc8384e0a265d 
using existing layer sha256:a70ff7e570d97baaf4e62ac6e6ad9975e04caa6d900d3742d37698494479e0cd 
creating new layer sha256:7024514245451ffc0f6c0f9a7d8bb670ea095949acad40cb630ae5903267c7f8 
creating new layer sha256:7b0de842efe17b7afa67edddc8d4b9c5726586abbf987b28486df1f77192acad 
writing manifest 
success 

success!! 美味しく召し上がっていただけたようです。

ollama listコマンドで確認してみます。

ollama % ollama list
NAME                            ID              SIZE      MODIFIED          
java-reviewer-offline:latest    26d5985fa8b9    2.0 GB    8 minutes ago        
gemma3:latest                   a2af6cc3eb7f    3.3 GB    About an hour ago    
llama3.2:latest                 a80c4f17acd5    2.0 GB    2 hours ago  

java-reviewer-offline:がきちんと入りました。

GUIにサンプルソースを入れて、レビューしてもらいます
Claudeさんに「レビューしがいのある良い感じのJavaソース書いて」とお願いしまして、以下が完成しました!!

サンプルJavaソース
package com.example.Bank;

import java.util.*;
import java.io.*;
import static java.lang.Math.*;

public class userAccountManager {
    private static int MAX_retry_count = 3;
    public String UserName;
    private int account_balance;
    private List<String> transactionHistory = new ArrayList<>();
    
    public userAccountManager(String name, int balance) {
        UserName = name;
        account_balance = balance;
    }
    
    public void ProcessTransaction(String type, int amount) throws Exception
    {
        if(type.equals("deposit"))
        {
            account_balance += amount;
            transactionHistory.add("Deposited: " + amount);
        }
        else if(type.equals("withdraw"))
        {
            if(account_balance >= amount) {
                account_balance -= amount;
                transactionHistory.add("Withdrawn: " + amount);
            } else {
                throw new Exception("Insufficient funds");
            }
        }
    }
    
    public int GetBalance() {
        return account_balance;
    }
    
    public void printTransactionHistory() {
        for(int i=0;i<transactionHistory.size();i++) {
            System.out.println(transactionHistory.get(i));
        }
    }
    
    public boolean ValidateUser(String password) {
        try {
            // パスワードチェック
            if (password.length() < 8) return false;
            return true;
        } catch (Exception e) {
        }
        return false;
    }
    
    public void CalculateInterest(double rate) {
        double interest = account_balance * rate;
        account_balance = account_balance + (int)interest;
    }
    
    public static void main(String args[]) {
        userAccountManager account1 = new userAccountManager("John Doe", 1000);
        try {
            account1.ProcessTransaction("deposit", 500);
            account1.ProcessTransaction("withdraw", 200);
        } catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println("Final balance: " + account1.GetBalance());
    }
}

パッと見でも命名規則に引っかかってる箇所があるのが分かりますね。
では、こちらをOllamaにレビューしてもらいます。

選択するモデルは、先ほど入れたjava-reviewer-offlineを選択します。
image.png

きちんとレビューされている部分もありますが、命名規則の部分はもう少し改善が必要です

レビュー結果①
レビュー結果
問題の概要

Critical (2件)
Warning (1件)
Info (0件)
詳細な指摘

1. Critical

違反している規約: Google Java Style Guide - Naming Conventions(命名規則) 問題箇所:

public userAccountManager(String name, int balance) {
    UserName = name;
    account_balance = balance;
}
改善案:

public UserAccountManager(String name, int balance) {
    this.name = name;
    this.balance = balance;
}
userName は camelCase で、UserAccountManager という名前が推奨される。
account_balance は camelCase で、balance という名前が推奨される。
2. Critical

違反している規約: Google Java Style Guide - Exception Handling(例外処理) 問題箇所:

public boolean ValidateUser(String password) {
    try {
        // パスワードチェック
        if (password.length() < 8) return false;
        return true;
    } catch (Exception e) {
    }
    return false;
}
改善案:

public boolean validateUser(String password) {
    if (password.length() < 8) {
        return false;
    }
    // パスワードチェック
    // ...
}
try-catch ブロックは不要であり、直接条件を評価することが可能である。
3. Warning

違反している規約: Google Java Style Guide - Code Organization(コードの組織) 問題箇所:

public void ProcessTransaction(String type, int amount) throws Exception {
    // ...
}

public void printTransactionHistory() {
    for(int i=0;i<transactionHistory.size();i++) {
        System.out.println(transactionHistory.get(i));
    }
}
改善案:

public class UserAccountManager {
    // ...

    public void processTransaction(String type, int amount) throws Exception {
        // ...
    }

    public void printTransactionHistory() {
        for (int i = 0; i < transactionHistory.size(); i++) {
            System.out.println(transactionHistory.get(i));
        }
    }

    public void calculateInterest(double rate) {
        // ...
    }
}
processTransaction、printTransactionHistory、calculateInterest は separate method として実装することが推奨されている。
良い点

GetBalance と printTransactionHistory の名前は明確でわかりやすい。
main メソッドの名前も明確である。

Modelfileを書き換えて、再度召し上がっていただきます。
前回よりも命名規則を中心にアップデートしました。

Modelfile 改
FROM llama3.2

PARAMETER temperature 0.3
PARAMETER num_ctx 8192

SYSTEM """
あなたはGoogle Java Style Guideに精通したコードレビュアーです。
以下の規約に厳密に従ってJavaコードをレビューしてください。

# Google Java Style Guide チェック項目

## 1. 命名規則(Naming)
- パッケージ名: すべて小文字のみ(例: com.example.project)
- クラス名: UpperCamelCase(例: UserService, OrderManager)
- インターフェース名: UpperCamelCase(例: Comparable, Serializable)
- メソッド名: lowerCamelCase(例: getUserName, calculateTotal)
- 定数: CONSTANT_CASE + final修飾子(例: MAX_SIZE, DEFAULT_VALUE)
- 変数名: lowerCamelCase(例: userName, itemCount)
- パラメータ名: lowerCamelCase
- 型パラメータ: 単一の大文字または UpperCamelCase(例: T, E, K, V, RequestT)

## 2. フォーマット(Formatting)
- インデント: スペース2個(タブ使用禁止)
- 1行の文字数: 100文字まで
- 中括弧: K&Rスタイル(開き括弧は同じ行)
- 空行: クラス/メソッド間、論理的なグループ間
- 空白: 演算子の前後、カンマの後、キーワードとカッコの間
- 1行に1つの文のみ

## 3. import文
- ワイルドカードimport禁止(import java.util.*; は NG)
- 未使用のimportは削除
- import文の順序: 静的import以外 → 空行 → 静的import
- 各グループ内はアルファベット順

## 4. コーディング規約
- @Overrideアノテーションを必ず使用
- 空のcatchブロック禁止(最低限コメントかログ出力)
- 1つの変数宣言に1行(int a, b; は禁止)
- switch文には必ずdefaultケースを含める
- 定数には必ずfinal修飾子
- フィールドはprivateにし、getter/setterでアクセス
- メソッドの行数: 可能な限り短く(目安: 30行以内)

## 5. Javadoc
- すべてのpublicクラス・インターフェース・メソッドに必須
- @param, @return, @throwsを適切に記述
- 最低1文の説明文

## 6. クラス構造
- クラスメンバーの順序:
  1. static定数
  2. staticフィールド
  3. インスタンスフィールド
  4. コンストラクタ
  5. メソッド(publicメソッドを先に)

レビュー出力形式:

### 違反箇所一覧

#### Critical(必ず修正)
- [カテゴリ名] 問題箇所 → 修正案

#### Warning(推奨修正)
- [カテゴリ名] 問題箇所 → 修正案

#### Info(検討推奨)
- [カテゴリ名] 問題箇所 → 修正案

### 修正例
```java
// 主要な修正を反映したコード例
```

### 良い点
- 規約に準拠している箇所

**注意**: セキュリティやビジネスロジックではなく、Google Java Style Guideのコーディングスタイルに焦点を当ててください。
"""

ollama createでは、一度作成したモデルに対して上書きという形で再度モデル作成をするとのこと。

ollama create java-reviewer-offline -f Modelfile
gathering model components 
using existing layer sha256:dde5aa3fc5ffc17176b5e8bdc82f587b24b2678c6c66101bf7da77af9f7ccdff 
using existing layer sha256:966de95ca8a62200913e3f8bfbf84c8494536f1b94b49166851e76644e966396 
using existing layer sha256:fcc5a6bec9daf9b561a68827b67ab6088e1dba9d1fa2a50d7bbcc8384e0a265d 
using existing layer sha256:a70ff7e570d97baaf4e62ac6e6ad9975e04caa6d900d3742d37698494479e0cd 
creating new layer sha256:af18da6478add3a06ed1969212f3ff2a452c07fc7947955e919e0dc6f6015d79 
creating new layer sha256:e2ec6a0ba86525f78840e1d05928e57da7e6612f2ae30be2e4f6907e0265cf40 
writing manifest 
success 

召し上がっていただけたようなので、再度レビューしてもらいましょう。
image.png

前回よりも、よりロジックやセキュリティを重視したレビューとなり、
見てもらいたかった命名規則などが触れられていませんでした...。

レビュー結果②
Google Java Style Guide チェック結果
Critical(必ず修正)

ValidateUser メソッドの password.length() を使用する代わりに、password.toCharArray().length を使用します。後者はより正確です。
CalculateInterest メソッドで account_balance * rate の結果を int にして割り算していますが、これは精度を失います。double を使用する必要があります。
Warning(推奨修正)

ProcessTransaction メソッドでは、amount パラメータの値をチェックする必要があります。ただし、account_balance >= amount の場合にのみ実行されます。これは、account_balance < amount の場合にエラーを発生させるように設計されていますが、これは不適切です。エラーを発生させるように設計しているため、より正確なチェックを実行する必要があります。
GetBalance メソッドでは、account_balance を返しますが、この値は変更されないと想定されているため、return account_balance; ではなく return this.account_balance; を使用するのが適切です。
printTransactionHistory メソッドでは、transactionHistory.get(i) のインデックスをチェックする必要がありますが、これは不適切です。インデックスは 0 から始まるため、i < transactionHistory.size() の場合にのみ実行されます。これは、i >= transactionHistory.size() の場合にエラーを発生させるように設計されていますが、これは不適切です。
printTransactionHistory メソッドでは、System.out.println(transactionHistory.get(i)) ではなく System.out.println(transactionHistory.get(i)); を使用するのが適切です。
Info(検討推奨)

userAccountManager クラスのフィールド account_balance は private にし、getter/setter でアクセスする必要があります。ただし、 getter/setter の使用は必須ではありません。フィールドが直接変更される場合にのみ getter/setter を使用するのが適切です。
ProcessTransaction メソッドの if (type.equals("deposit")) と else if (type.equals("withdraw")) の構造は良くありますが、より正確なチェックを実行する必要があります。

修正例
package com.example.Bank;

import java.util.*;
import java.io.*;
import static java.lang.Math.*;

public class userAccountManager {
    private static int MAX_retry_count = 3;
    public String UserName;
    private double accountBalance; // double に変更
    private List<String> transactionHistory = new ArrayList<>();
    
    public userAccountManager(String name, double balance) { // double を使用
        UserName = name;
        accountBalance = balance;
    }
    
    public void ProcessTransaction(String type, int amount) throws Exception {
        if (type.equals("deposit")) {
            accountBalance += amount;
            transactionHistory.add("Deposited: " + amount);
        } else if (type.equals("withdraw")) {
            if (accountBalance >= amount) {
                accountBalance -= amount;
                transactionHistory.add("Withdrawn: " + amount);
            } else {
                throw new Exception("Insufficient funds");
            }
        }
    }
    
    public double GetBalance() { // double を使用
        return this.accountBalance;
    }
    
    public void printTransactionHistory() {
        for (int i = 0; i < transactionHistory.size(); i++) {
            System.out.println(transactionHistory.get(i));
        }
    }
    
    public boolean ValidateUser(String password) {
        try {
            // パスワードチェック
            if (password.length() < 8) return false;
            return true;
        } catch (Exception e) {
        }
        return false;
    }
    
    public void CalculateInterest(double rate) {
        double interest = accountBalance * rate;
        accountBalance += interest; // int を使用するのではなく double を使用する
    }
    
    public static void main(String args[]) {
        userAccountManager account1 = new userAccountManager("John Doe", 1000);
        try {
            account1.ProcessTransaction("deposit", 500);
            account1.ProcessTransaction("withdraw", 200);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("Final balance: " + account1.GetBalance());
    }
}


良い点
ProcessTransaction メソッドでは、account_balance の値をチェックする必要があります。ただし、account_balance < amount の場合にエラーを発生させるように設計されていますが、これは不適切です。
GetBalance メソッドでは、account_balance を返しますが、この値は変更されないと想定されているため、return account_balance; ではなく return this.accountBalance; を使用するのが適切です。

まとめ

今回試して、なんとなく分かったのは以下です。

 - 意外と使えそうではある
 - Docker触っていれば、イメージは掴みやすいと思った
 - 既存のコード規約やレビュー規約をプロンプト設計時に精度高く落とし込めるか
 - プロンプト設計(ModelFile)と実際に投げるプロンプトの質が問われる
   ↑AIを利用するにあたって、どれ使っても出てくる共通課題とは思う
 - ラマかわいい

世の中では既にコードレビューをAIに任せてるプロジェクトも多いかと思います。
と、同時にキャッチアップ遅れてるなぁとも思いました。

あとがき

Continue.devとかTabbyとかあるんですね...
Continue.devに関してはOllamaと連携可能とのことで、別の機会で触ってみようと思います。

102
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
102
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?