2026年5月21日木曜日

OpenCodeとLM StudioでローカルでのAPEXlangによるアプリケーション生成を試してみる

以前の記事でOpenAI Codex、Claude CodeおよびGoogle Gemini CLIを使って、APEX 26.1のAPEXlangによるアプリケーション生成を実施しています。

今回はOpenCodeとローカルLLM(LM Studio)を使用して、ローカル環境でのAPEXアプリケーションの生成を試してみました。ついでにClaude CodeとCodexからも、ローカルLLMを呼び出してみました。

作業はApple Macbook Proで行なっています。作業手順はCodexやClaude Codeのときと、ほとんど変わりません。作業にあたって、いくつか気をつけた点などを紹介します。

作業ディレクトリとしてemp-crud-opencodeを作成します。作成後、作業ディレクトリに移動します。

mkdir emp-crud-opencode
cd emp-crud-opencode

Documents % mkdir emp-crud-opencode

Documents % cd emp-crud-opencode

emp-crud-opencode % 


Microsoft APMを使ってAPEXlangのAgent Skillsをロードするため、以下のファイルをapm.ymlとして作成します。
name: emp-crud
version: 0.1.0
description: Oracle APEX 26.1のAPEXlangを使ってアプリケーションを作成する。
author: Yuji
dependencies:
  apm:
    # Oracle Database Skills
    - git: https://github.com/oracle/skills
      path: db
      ref: main
    # Oracle APEXlang Skills
    - git: https://github.com/oracle/skills
      path: apex
      ref: main
定義したAgent SkillsをOpenCode向けにインストールします。ターゲットはopencodeです。

apm install --target opencode

emp-crud-opencode % apm install --target opencode


[>] Installing dependencies from apm.yml...

[i] Targets: opencode  (source: --target flag)

  [+] github.com/oracle/skills/apex#main #main @11e528de (cached)

  |-- Skill integrated -> .agents/skills/

  [+] github.com/oracle/skills/db#main #main @11e528de (cached)

  |-- Skill integrated -> .agents/skills/


[*] Installed 2 APM dependencies in 6.3s.

emp-crud-opencode % 


Gitによる管理はしませんが、作業ディレクトリを初期化しておきます。

git init

emp-crud-opencode % git init   

Initialized empty Git repository in /Users/____________/Documents/emp-crud-opencode/.git/

emp-crud-opencode % 


APEXアプリケーションの作成先として、ディレクトリapplicationsを作成します。

mkdir applications

emp-crud-opencode % mkdir applications

emp-crud-opencode % 


OpenCodeで呼び出すモデルやSQLclのMCPサーバーを設定します。LLMのプロバイダとして、ローカルで実行しているLM Studioを呼び出します。

以下のファイルをopencode.jsoncとして作成します。OpenCodeでのプロバイダやモデルの指定方法は、こちらに記載されています。以下では、デフォルトで使用するモデルとしてLM Studioにロードしたunsloth/Qwen3.6-35B-A3B-MLX-8bitを設定しています。
{
  "$schema": "https://opencode.ai/config.json",
  "model": "lmstudio/qwen3.6-35b-a3b-mlx",
  "provider": {
    "lmstudio": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "LM Studio",
      "options": {
        "baseURL": "http://127.0.0.1:1234/v1",
      },
      "models": {
        "qwen/qwen3-coder-next": {
          "name": "Qwen3 Coder Next"
        },
        "mlx-community/gpt-oss-120b": {
          "name": "GPT OSS 120B"
        },
        "qwen3.6-35b-a3b-ud-mlx": {
          "name": "Qwen3.6 35B A3B UD"
        },
        "qwen3.6-35b-a3b-mlx": {
          "name": "Qwen3.6 35B A3B"
        },
        "qwen3.6-27b-mlx": {
          "name": "Qwen3.6 27B"
        }
      }
    }
  },
  "mcp": {
    "oracle-apexdev": {
      "type": "local",
      "command": [
          "/opt/homebrew/Caskroom/sqlcl/26.1.2.132.1334/sqlcl/bin/sql",
          "-R",
          "4",
          "-mcp"
      ],
      "enabled": true,
      "environment": {}
    }
  }
}
LM Studioではモデルがダウンロード済みであれば、APIリクエストで指定されているモデルはオンデマンドでロードされます。しかし、コード生成ではコンテキスト長が重要なので、LM Studioのローカルサーバーを起動し、あらかじめモデルをロードしておきます。

コンテキスト長として262144を指定します。

lms server start
lms load qwen3.6-35b-a3b-mlx -c 262144
lms ps

emp-crud-opencode % lms server start

Success! Server is now running on port 1234

emp-crud-opencode % lms load qwen3.6-35b-a3b-mlx -c 262144

Waking up LM Studio service...


! Multiple models match the provided model key. Please select one.

Select a model to load | qwen3.6-35b-a3b-mlx

Model loaded successfully in 10.15s.

(35.15 GiB)

To use the model in the API/SDK, use the identifier "qwen3.6-35b-a3b-mlx".

emp-crud-opencode % lms ps


IDENTIFIER             MODEL                  STATUS    SIZE        CONTEXT    PARALLEL    DEVICE    TTL

qwen3.6-35b-a3b-mlx    qwen3.6-35b-a3b-mlx    IDLE      37.74 GB    262144     1           Local        


emp-crud-opencode % 


後はopencodeを起動し、以下のプロンプトを与えます。
1. MCPサーバーoracle-apexdevで、データベースlocal-26ai-apexdevに接続してください。
2. local-26ai-apexdevはユーザーapexdevで接続されています。これはAPEXワークスペースAPEXDEVのdefault parsing schemaです。
3. スキーマAPEXDEVには表EMPが存在します。MCPサーバーoracle-apexdevのツールを呼び出して表定義を参照してください。
4. APEXlangのスキルを使って、表EMPの一覧を表示する対話モード・レポートのページと、従業員の作成、更新、削除ができるフォームを持つAPEXアプリケーションEMP_CRUD_OPENCODEを作成してください。
5. OpenCodeが作成したことがわかるように、アプリケーション名にOPENCODEをつけてください。
6. アプリケーションのインポートはMCPサーバーではなく、applications/<application_name>に移動した後に、”sql -name local-26ai-apexdev”でSQLclを起動し、apex importを実行することで、APEXアプリケーションのインポートを行なってください。

LLMの稼働状況はlms log streamの実行でも確認できますが、LM StudioのGUIを開いた方がわかりやすいでしょう。


とりあえずローカルLLMでもなんとかAPEXアプリケーションの作成とインポートまではできましたが、作られたアプリケーションの出来は良くありませんでした。とはいえ、Qwen3.6より前のモデルでは、アプリケーションのインポートまで作業が進まなかったので、それに比べると上出来ではあります。


せっかくローカルLLMを準備したので、Claude Codeから呼び出してみました。

LM StudioはAnthropic互換APIを提供しているため、環境変数ANTHROPIC_BASE_URLでLM Studioを指すことにより、ローカルLLMを呼び出すことができます。LM StudioはAPIキーの検証は行わないため(APIキーによる保護をかけることもできます)、AHTHROPIC_AUTH_TOKENについては何を設定してもかまいません。

環境変数を設定したのち、claudeを実行します。

export ANTHROPIC_BASE_URL=http://localhost:1234
export ANTHROPIC_AUTH_TOKEN=lmstudio
claude --model qwen3.6-35b-a3b-mlx

Claude Codeでも、とりあえずAPEXアプリケーションの作成とインポートまではできました。作成されたAPEXアプリケーション自体は、OpenCodeと同様に、そのままで使えるようなものではなかったです。呼び出しているLLMが同じなので、結果はそう変わりません。


同様にOpenAI Codexから呼び出してみました。

Codexで、./.codex/config.tomlに以下を記述してMCPサーバーを追加した場合です。
[mcp_servers.oracle-apexdev]
command = "/opt/homebrew/Caskroom/sqlcl/26.1.2.132.1334/sqlcl/bin/sql"
args = [ "-R", "4", "-mcp" ]
カスタムで追加したMCPサーバーに限らない(プラグインのComputer Useなどでも同様)ですが、CodexはMCPサーバー(またはプラグイン)単位でnamespaceにまとめてツール定義をリクエストに含めるようです。
{
  "type": "namespace",
  "name": "mcp__oracle_apexdev__",
  "tools": [
    {
      "type": "function",
      "name": "connect"
    },
    {
      "type": "function",
      "name": "sql_run"
    }
  ]
}
LM Studioはこのnamespaceでまとめたツール定義を解釈できず、以下のようなエラーを返します。
{
  "error": {
    "message": "Invalid",
    "type": "invalid_request_error",
    "param": "tools.8.type",
    "code": "invalid_string"
  }
}
そのため、CodexからLM Studioのモデルを呼び出すときは、SQLclのMCPサーバーは使用できません。代わりにSQLclを直接呼び出すようにプロンプトを与えることにします。

MCPサーバーのエラーを回避するため、Computer UseとBrowser Useも無効にします。

グローバル設定の~/.codex/config.tomlを更新します。
[plugins."computer-use@openai-bundled"]
enabled = false

[plugins."browser-use@openai-bundled"]
enabled = false
プロファイルlocalとして、LM Studioのモデルqwen3.6-35b-a3b-mlxを呼び出せるように、グローバル設定の~/.codex/config.tomlに以下を追加します。
[model_providers.lmstudio_local]
name = "LM Studio"
base_url = "http://127.0.0.1:1234/v1"
wire_api = "responses"

[profiles.local]
model = "qwen3.6-35b-a3b-mlx"
model_provider = "lmstudio_local"
プロジェクト・ローカルの./.codex/config.tomlにネットワーク・アクセスを許可する設定を記述します。
[sandbox_workspace_write]
network_access = true
以上でCodexからLM Studioのモデルを呼び出す準備は完了です。Codexを起動します。

codex -p local --sandbox workspace-write

MCPサーバーの代わりにSQLclを直接呼び出すように、以下のプロンプトを与えました。
1. sqlコマンドを呼び出し -name オプションでデータベースlocal-26ai-apexdevに接続してください。
2. local-26ai-apexdevはユーザーapexdevで接続されます。これはAPEXワークスペースAPEXDEVのパーシング・スキーマです。
3. スキーマAPEXDEVには表EMPが存在します。
4. APEXlangのスキルを参照して、表EMPの一覧を表示する対話モード・レポートのページと、従業員の作成、更新、削除ができるフォームを持つAPEXアプリケーションEMP_CRUDを作成してください。
5. アプリケーションはディレクトリapplications以下にEMP_CRUDとして作成してください。
6. アプリケーションのインポートは、applications/EMP_CRUDに移動した後に、"sql -name local-26ai-apexdev"でSQLclを起動し、"apex import"を実行することで、APEXアプリケーションのインポートを行なってください。
色々と紆余曲折がありましたが、なんとかAPEXアプリケーションの生成とインポートまではできました。

────────────────────────────────────────────────────────────────────────────────────────────────────────


Ran cd /Users/ynakakoshi/Documents/emp-crud-codex/applications/EMP_CRUD && sql -S -name

  local-26ai-apexdev <<'SQLEOF'

  apex validate -input .

  │ … +2 lines

  └ APEXLang Compile Warnings:

    File: pages/p00002-employee-list.apx

    … +146 lines (ctrl + t to view transcript)

    Validation successful.



────────────────────────────────────────────────────────────────────────────────────────────────────────


バリデーションが成功しました!警告のみでエラーはありません。いよいよインポートします。


Ran cd /Users/ynakakoshi/Documents/emp-crud-codex/applications/EMP_CRUD && sql -S -name

  local-26ai-apexdev <<'SQLEOF'

  apex import -input .

  │ … +2 lines

  └ Importing application ID: 106 into workspace: APEXDEV

    APEXLang Compile Warnings:

    … +147 lines (ctrl + t to view transcript)

    Import successful.



────────────────────────────────────────────────────────────────────────────────────────────────────────


インポート成功です!アプリケーションID 106としてAPEXDEVワークスペースにインポートされました。確認しま

  す。


Ran cd /Users/ynakakoshi/Documents/emp-crud-codex && sql -S -name local-26ai-apexdev <<'SQLEOF'

  apex list

  exit;

  │ … +1 lines

  └ WORKSPACE_ID        WORKSPACE    APPLICATION_ID    APPLICATION_NAME     BUILD_STATUS

    LAST_UPDATED_ON  LAST_UPDATED_BY

    … +3 lines (ctrl + t to view transcript)




────────────────────────────────────────────────────────────────────────────────────────────────────────


Ran cd /Users/ynakakoshi/Documents/emp-crud-codex && sql -S -name local-26ai-apexdev <<'SQLEOF'

  apex list -applicationid 106

  exit;

  │ … +1 lines

  └ LAST_UPDATED_ON     ID                                   NAME

    2026-05-21 05:09    AUTHENTICATION:7000641439333978      Oracle APEX Accounts

    … +35 lines (ctrl + t to view transcript)




────────────────────────────────────────────────────────────────────────────────────────────────────────


完了しました。EMP_CRUDアプリケーションが正常にデータベースにインポートされました。


  インポート結果:


  - アプリケーションID: 106

  - ワークスペース: APEXDEV

  - 状態: Run and Develop


  構成ページ:


  ┌────────┬───────────────┬─────────────────────────────────────────────┐

  ページ 名前          内容                                       

  ├────────┼───────────────┼─────────────────────────────────────────────┤

  0      Global Page   グローバル設定                             

  1      Home          ホーム画面                                 

  2      Employee List EMP表のインタラクティブレポート(一覧表示)

  3      Employee Form EMP表のフォーム(作成・更新・削除)        

  9999   Login Page    ログイン画面                               

  └────────┴───────────────┴─────────────────────────────────────────────┘


  主な機能:


  - ページ2(一覧): EMP表の全カラム(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)を表示するイ

    ンタラクティブレポート。「Create Employee」ボタンでページ3へ遷移

  - ページ3(フォーム): EMP表のCREATE/UPDATE/DELETEができるフォーム。EMPNOは自動採番で表示のみ、他のカ

    ラムは編集可能。Save/Cancel/Deleteボタン付き


─ Worked for 19m 31s ───────────────────────────────────────────────────────────────────────────────────

Token usage: total=189,294 input=172,049 (+ 5,036,832 cached) output=17,245 (reasoning 16,261)

To continue this session, run codex resume 019e48de-80e3-7fc3-ab63-2d2613929f26

emp-crud-codex %


最近のローカルLLMも性能が上がっているから試してみましたが、この結果だと厳しいというのが正直な感想です。プロンプトが適当なのは事実ですが、ローカルLLMの性能のせいか、以下の繰り返しが頻繁に発生しました。
  1. LLMが適当にAPEXlangでページを生成する。
  2. 生成したページを検証する。
  3. エラーがたくさん発生する。
  4. ページを書き直すが、それも適当なAPEXlangで書き直す。
  5. 2へ戻る。
Claude Sonnect/Opus、OpenAI GPT、Google Geminiを使ってもまだまだの状況なので、ローカルLLMは時期尚早ということでしょう。