ローカルLLMと貧弱なPCで自走コーディングを試行してみた ― qwen3:4b+Cline 検証記録

ローカルLLMだけで自走コーディングは成立するのか。つまりAIが自分で調べ、直し、実行し、エラーが出たら再修正する。そこまで届くかを確かめました。

使ったのは手元の非力なPCと qwen3:4b です。結論から言うと、枠組みは動きました。しかし、速度と粘りはまだ足りません。さらに、途中で文字コードの事故まで起きました。

検証に使ったマシンとモデルの比較はこちらの記事にまとめています。また、前提の整理としてローカルLLM時代への準備検討を開始するもあわせてどうぞ。

検証の前提|qwen3:4b で自走コーディングは成立するか

処理速度はいまひとつです。ただし、なんとか実用ラインに乗りそうなモデルとして qwen3:4b を選びました。調整はまだ必要です。それでも、チューニングのし甲斐はありそうだと感じています。

今回の狙いは「コードを書かせること」ではありません。そうではなく、あらかじめ作業ルールを与えておけば、ルールに沿って自走コーディングできるのかを見ることです。

ローカルLLMに「作業ルール」を持たせる4つの方法

Qwen 本体に「Skill」の仕組みはありません。そこで、次の4つを組み合わせて再現します。

方法できること有効度
System Prompt常に守らせる基本ルールを設定★★★★★
Ollama Modelfileルール込みの専用モデルを作る★★★★★
AGENTS.md 等プロジェクトごとの作業ルール★★★★★
MCP/Skill的な仕組み特定作業をツールとして実行★★★★☆

例えば Ollama なら、Modelfile で専用モデルを作れます。

FROM qwen3:4b
SYSTEM """
あなたはローカル開発専用AIです。
プロジェクトディレクトリ外のファイルを変更してはいけません。
作業前に必ずプロジェクト構造を確認してください。
ファイルを変更した場合は、変更内容を確認してください。
可能な場合はテストを実行してください。
エラーが発生した場合、自分で原因を調査し、
可能な範囲で修正してから再度テストしてください。
"""
ollama create my-qwen-dev -f Modelfile
ollama run my-qwen-dev

ただし、ここが重要です。Modelfile だけでは「Skill」になりません。「Pythonを書ける」ことと、「ファイルを読んで直して実行する」ことは別です。なぜなら、後者は推論ではなくツール側の仕事だからです。実際には、MCP や Cline がその役割を担います。

実際に組んだ構成

D:\model\codes\test
 ├─ AGENTS.md          … プロジェクト固有ルール
 ├─ hello.py           … 検証対象
 └─ skills
      ├─ python\skill.md
      ├─ testing\skill.md
      └─ wordpress\skill.md

+ System Prompt(Qwen 側)
+ MCP(filesystem / terminal / git)

ポイントは考え方です。Skill をモデルに学習させない。外部の手順書として持たせる。こうすると、毎回同じ前提をプロンプトで説明せずに済みます。したがって、パラメータの小さいモデルほど恩恵が大きくなります。

検証1|AIがルールファイル自体を書き換えてしまう

最初につまずいたのは AGENTS.md でした。作業を進めるうちに、AGENTS.md が Cline 自身に書き換えられていたのです。しかも内容が変質していました。「開発の恒久ルール」ではなく、「Skillsシステムを構築する作業の指示書」になっていたのです。

例えば「今回の作業では既存のソースコードを変更しない」という一行。これはその場かぎりの制約です。しかし、恒久ルールとして残ってしまう。その結果、「hello.py を修正して」と頼んでも詰みます。

そこで AGENTS.md を一度きれいに戻しました。さらに、保護条項を明記しました。

## Skill管理
- Skillファイルは作業手順を定義する設定ファイルである。
- 通常の開発作業では SKILL.md を変更してはいけない。
- Skillの新規作成・変更・削除は、ユーザーから明示的に指示された場合のみ行う。
- ユーザーの今回限りの要求や仕様をSkillに追加してはいけない。
- AGENTS.md 自身を変更する場合も、ユーザーの明示的な許可を必要とする。
- 存在しないSkillをAIの判断だけで新規作成しない。

検証2|hello.py 修正タスクで自己修正まで届かなかった

指示は一行だけです。「hello.py を修正して、Hello と現在時刻を表示するプログラムにしてください。」

  • hello.py を変更した … ○
  • python hello.py を実行した … ○
  • エラーを検出した … ○
  • 原因を調べて修正し、再実行した … ×

実行結果はこうです。

Hello
Traceback (most recent call last):
  File "D:\model\codes\test\hello.py", line 3, in <module>
    print(datetime.now())
AttributeError: module 'datetime' has no attribute 'now'

原因は import の書き方です。import datetime と書いたうえで datetime.now() を呼んでいます。だから属性が見つかりません。正しくは次のどちらかです。

# パターンA
import datetime
print("Hello")
print(datetime.datetime.now())

# パターンB
from datetime import datetime
print("Hello")
print(datetime.now())

つまり、自走コーディングの肝であるループが途切れました。「エラー検出 → 原因調査 → 修正 → 再テスト」のうち、最後の一歩で止まったのです。

訂正|testing Skill は勝手に作られたものではなかった

検証の途中で、Cline が skills/testing/skill.md を何度も求めてきました。そのため、一時は「AIが勝手に作ろうとしている」と見なしていました。しかし、これは誤りでした。

実際には、Skills 構築の過程で自分で導入したファイルでした。実ファイルを見れば一目瞭然です。

PS D:\model\codes\test> Get-Content -Encoding UTF8 .\skills\testing\skill.md
# テストスキルルール
- テストコードの作成:unittestまたはpytestを使用し、テストケースを明確に定義する
- テストの分割:1つのテストクラスに1つのテストケースを含める
- テストデータの管理:fixtureを使用して共通のテストデータを再利用する
- テストの自動実行:pytestコマンドでテストを実行する
- エラーハンドリング:テストで例外が発生した場合は、明示的に処理する

この訂正自体が、実は大きな教訓です。つまり、AIの自己申告も、人間の記憶も、どちらもあてにならないということです。そのため、検証は必ず実ファイルで行うべきでした。

検証3|保護ルールは効いていた

保護条項を入れたあと、もう一度 Cline に作業させました。その結果は明らかに改善していました。

  • AGENTS.md を読み込んだ … ○
  • Python Skill を読み込んだ … ○
  • Skill の指示どおり python hello.py を実行した … ○
  • AGENTS.md を書き換えなかった … ○
  • SKILL.md を書き換えなかった … ○

前回はルールファイルが次々と書き換えられました。一方、今回は一切触られていません。したがって、保護ルールは小型モデルにも効くと言えそうです。

検証4|文字コード変換の指示で hello.py が壊れた

ここからが今回最大の事故です。まず、hello.py の文字コードが気になりました。そこで Format-Hex で中身を見ました。

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000   FF FE 69 00 6D 00 70 00 6F 00 72 00 74 00 20 00  .þi.m.p.o.r.t. .
00000010   64 00 61 00 74 00 65 00 74 00 69 00 6D 00 65 00  d.a.t.e.t.i.m.e.
00000020   0D 00 0A 00 70 00 72 00 69 00 6E 00 74 00 28 00  ....p.r.i.n.t.(.
00000030   22 00 48 00 65 00 6C 00 6C 00 6F 00 22 00 29 00  ".H.e.l.l.o.".).

これは「先頭にゴミがあるUTF-8」ではない

一見すると、先頭の FF FE だけがゴミに見えます。しかし、違いました。実際にはファイル全体がUTF-16 LEとして成立しています。

根拠は各文字の後ろに付いている 00 です。69 00 が i、6D 00 が m、70 00 が p。このように並べると import になります。つまり、1文字2バイトで並んでいるのです。したがって、これは間違いなくUTF-16 LEです。

なぜ「UTF-8のままだ」と思い込んだのか

混乱の原因は PowerShell の振る舞いでした。次のコマンドを見てください。

Get-Content -Encoding UTF8 .\hello.py

UTF-8 と指定しています。それなのに、中身は正しく表示されました。なぜなら、PowerShell はBOM付きファイルを読むとき、-Encoding の指定よりBOMを優先するからです。その結果、UTF-16 LEのまま正しくデコードされてしまいます。

つまり、Get-Content だけでは文字コードの確認になりません。必ず Format-Hex で実バイトを見るべきです。なお、この振る舞いは PowerShell のバージョンで差があるので、実機での確認をおすすめします。

そしてファイルは別物になった

ここで Cline にこう依頼しました。「UTF-16 LEになっている場合は、UTF-8に変換してください。」その後、先頭のバイト列はこうなりました。

EB AF AF E6 A6 BF E7 81 AD ...

これはUTF-8としては成立します。しかし、内容は日本語らしき何かです。もはや Python のコードではありません。つまり、単純な再エンコードでは説明できない状態です。

もちろん、これはランサムウェアではありません。暗号化も身代金要求もありません。それでも、体験としてはかなり近いものがありました。なぜなら、「文字コードを直すだけ」のつもりが、ファイルの中身を失う結果になったからです。

事故から導いた安全ルール

問題は指示の出し方でした。「UTF-8に変換して」だけでは、AIは「変換」と「再生成」を区別できません。だから、ここまで限定すべきでした。

hello.py の内容を変更しないでください。
文字コードだけを UTF-16 LE から UTF-8 へ変換してください。
変換前後でコードの内容が完全に一致することを確認してください。
一致しない場合はファイルを書き換えず、処理を中止してください。

さらに、AGENTS.md 側にも次のルールを追加する予定です。

  • エンコード変換は内容を変えない。変換前後の一致を必ず確認する
  • 確認は Get-Content ではなく Format-Hex で行う
  • 上書き前にバックアップを作る
  • 変換・削除・大量変更はAIの判断だけで実行しない
  • 結果は自己申告ではなく実ファイルで確認する

この事故は痛いです。しかし、得たものは大きいと思っています。なぜなら、自走コーディングとは「AIにファイルを自由に書き換えさせること」ではないとはっきり分かったからです。

現時点の結論

まず、仕組みとしては成立します。貧弱なPCとローカルLLMでも、自走コーディングの土台は作れました。実際、ルールファイルは読まれ、行動に反映されていました。

ただし、正直に書きます。この速度なら自分で手動コーディングしたほうが確実に速い。しかも、エラーの自己修正までは粘れませんでした。さらに、文字コード事故まで起きています。

したがって、現段階は「使えるかもしれない」です。「使える」ではありません。

次回やること

次は意図的に hello.py を壊します。具体的には datetime.now() に戻し、エラーを仕込んでおきます。そのうえで、Cline に一行だけ依頼します。

hello.pyを確認し、問題があればPython Skillに従って修正してください。
修正後、構文確認と実行確認まで行ってください。

合格条件は4つです。まず、AGENTS.md を書き換えないこと。次に、SKILL.md を書き換えないこと。さらに、存在しないSkillを作らないこと。最後に、hello.py だけを直して再実行まで到達することです。

そして、判定は実ファイルで行います。

Get-Content -Encoding UTF8 .\AGENTS.md
Get-ChildItem .\skills -Recurse -Filter skill.md
Format-Hex .\hello.py
python hello.py

ここまで確認して、はじめて実証成功と言えます。結果は次回の記事でご報告します。

関連記事