Algomatic Tech Blog

Algomaticの開発チームによる Tech Blog です

実装の中で育てるClaude Code SDK理解:PoC自動化から得た学び

1. はじめに

こんにちは、Algomatic AXの岩城祐作(@yukl_dev)です。
私は5月にAlgomaticに入社し、AIエンジニアとして働いています。
入社エントリに、転職の背景の1つとして以下を書きました。

PoCループの虚しさと危機感 一方で、技術検証やデモ作成にとどまるPoC(Proof of Concept)も少なくありませんでした。 LLMOps導入など、生成AIの現場でよく用いられる実践的な経験を積み重ねる機会が少なく、AI領域に関わっているにも関わらずエンジニアとして活かせていない現状に、危機感が募りました。

果たして自分は本当に価値を提供できているのか?そもそも今の開発は本当に求められていることか?という不安が大きくなっていました。

企業支援のみを目的としたエンジニアでいることの危機感と無力感が、日に日に大きくなりました。

良ければ入社エントリもご覧ください。 note.com

「技術検証やデモ作成にとどまるPoC(Proof of Concept)」が意味のないものとは思いません。
ただ、エンジニアと顧客の双方がより価値ある時間を過ごせるように、以下を目指してPoC自動化プロダクトの開発に取り組み始めました。

  • エンジニアが専門的な課題に価値投下できる状態を作る
  • 属人化する必要のないPoCに必要な知見を集約し、同種PoCの初速を最大化する
  • 各エンジニアや組織にとってより価値のある知見の蓄積につなげる

Claude Code SDK」を使って実装を進めており、今回はその実装過程で得られたClaude Code SDKに関する知見を共有します。

2. Claude Code SDKの概要

Claude Code SDKとは何か

開発者がターミナルで対話的にClaudeとやり取りするClaude CodeのCLI利用は、皆さんイメージできると思います。

Claude Code SDKは、CLIと同様のclaude実行ファイルをアプリケーション側から操るためのライブラリです。

イベントやストリームを受け取りながら、計画から適用、ツール実行まで非対話(ヘッドレス)でプログラム制御できる仕組みを提供しており、アプリケーションとして作り込みやすいです。

docs.anthropic.com

なお、claude -pを使えば、CLIでも非対話(ヘッドレス)で実行は可能です。本プロダクトでは、アプリケーション側でのオーケストレーションによる拡張性と制御性を優先し、Claude Code SDKを採用しています。

TypeScript版とPython版の特徴

Claude Code SDKは現在、TypeScriptとPythonの2つの言語で提供されています。

TypeScript SDK

  • npmパッケージ@anthropic-ai/claude-codeでCLIと一緒にインストール
  • CLIと同様のclaude実行ファイルを直接扱うので、無駄な処理なくよりネイティブな操作感

Python SDK

  • pip install claude-code-sdkに加え、Node.jsと@anthropic-ai/claude-codeの導入が必須
  • 内部でCLIを起動し、JSONストリームをパースする仕組み
  • CLI未導入時にはCLINotFoundErrorなど専用例外でエラーハンドリング

3. Claude Code SDKを使って得られたこと

Permission Modesによる安全な実行計画

Claude Codeでは、以下の4つのPermission Modesが利用可能で、それぞれ安全性や利用シーンに応じて選択できます。

Mode 説明 使用シーン
default 標準動作 - 各ツールの初回使用時に権限確認 通常の開発作業、手動確認を重視したい場合
acceptEdits セッション中のファイル編集権限を自動承認 開発効率を重視、ファイル変更が頻繁な作業
plan 分析のみ可能、ファイル変更・コマンド実行は禁止 コードレビュー、設計検討、安全な事前確認
bypassPermissions 全ての権限プロンプトをスキップ(安全な環境必須) CI/CD、完全自動化された環境での実行

Identity and Access Management - Anthropic

私のPoC自動化プロダクトでは、3つのエンドポイントのモードを個別設定して実装することで 「計画 → 承認 → 継続改修」のフローを自動化しつつ、安全性と柔軟性を両立 しています。

  • POST /api/poc/build
    • モード: plan
    • 計画のみを生成し、ファイル編集やコマンド実行は行わない。
  • POST /api/poc/approve
    • モード: default
    • 承認後、同じセッションで実行に移行。ツール使用時には初回のみ確認が入り、以降はセッション内で承認済みとして進行。
  • POST /api/poc/extend
    • モード: default
    • 追加改修も同一セッションのまま行われ、同じ権限制御が適用される。(まだ不安定…)

さらに、defaultモードで権限確認が発生した場合でも、同じ approve エンドポイントを介して応答することで、セッションを途切れさせずに継続できるように設計しています。

コマンドレベルで制御を実現

allowedToolsdisallowedToolsを使って、具体的なコマンドレベルの制御もしています。

  • allowedTools: 明示的に「利用を許可する操作」を列挙。指定した範囲内の操作は確認なしで実行される。
  • disallowedTools: 明示的に「禁止する操作」を列挙。指定にマッチする操作はセッション内でブロックされる。

現時点のPoC自動化プロダクト内のコマンドリストは、最低限のものを指定していますが、部署やチームと調整してアップデートする予定です。

// 設定例
const options = {
  allowedTools: [
    "Read",
    "Bash(npm install)",
    "Bash(npm run test:*)",  // test系コマンドを許可
    "Edit(src/**)"           // srcディレクトリ内の編集を許可
  ],
  disallowedTools: [
    "Bash(rm *)",
    "Bash(sudo *)",          // 危険なコマンドを拒否
    "Edit(config/production.json)"  // 本番設定の変更を禁止
  ]
}

Hooksによる確実な実行

Claude Code hooksは、各ツールの実行前後に外部コマンドを自動実行する機能です。

Hooksの基本概念

Hooksは、複数のタイミングで処理を差し込むことができます。
代表的なイベントは次の通りです。

  • PreToolUse: ツール実行前に呼び出される
  • PostToolUse: ツール実行後に呼び出される
  • SessionStart: セッション開始時に呼び出される
  • Notification: 権限待ちなどの通知タイミングで呼び出される
  • UserPromptSubmit: ユーザーのプロンプト送信直後に呼び出される

そのほかに PreCompact / Stop / SubagentStop などのイベントがあります。

Hooks reference - Anthropic

これらを活用することで、より柔軟な制御と確実なワークフローの実行が可能になります。

その他Hooksの詳細と事例については、弊社の柗村@yu_mattznの記事もご覧ください。

tech.algomatic.jp

ドキュメント自動生成の実装

私のPoC自動化プロダクトでは、以下が実現したいことでした。

  • 作り直し前提の開発サイクル:次フェーズ(本番開発)への移行を容易にし、作り直し前提とする開発サイクルのハードルを下げる
  • 速度と検証の両立:対象の検証速度を早めつつ、検証結果(特に実現可能性)を明確にする。この説明責任を大切にする

そのため、PostToolUseを使って、基本機能とその実現方法などの以下ドキュメントを残す工程を自動化しました。

  • README.md: 生成したアプリケーションの全体像と使い方
  • POC_REQUIREMENTS.md: PoCの検証内容や要件
  • FEATURES_IMPLEMENTATION.md: 実装機能とその実現方法
  • ARCHITECTURE.md: 全体構成と設計意図

4. まとめ

今回は、PoCの自動化を目指す中でClaude Code SDKを活用した実装知見を共有しました。
本記事はClaude Code SDKの紹介がメインでしたが、PoC自動化プロダクトについてはまた別の機会に共有したいです。
引き続き形にしていく取り組みを進めてまいりますので、ご意見やフィードバックをいただければ幸いです。


最後にAlgomaticは一緒に働くメンバーを募集しています! 以下よりお気軽にカジュアル面談をお申し込みいただけると幸いです!

jobs.algomatic.jp


Claude Code hooksで始めるPromptOps:チームで意図を残す仕組み作り

こんにちは。Algomatic AI Transformation(AX) の柗村@yu_mattznです。

私は7月にAIプロダクトエンジニアとして入社し、今はネオデザインAIの開発責任者をしています。プロダクト出身でAIについての深い知見はないため、日々AIエンジニアの方々の投稿からキャッチアップできて最高な環境です。

今回は、Claude Codeをチームで使う際、プロンプトを共有するのが今後大事になってくるのではないか?と考えたきっかけとその取り組みを紹介します。

Claude Codeを導入してみて

Claude Codeが出た時、部署では一瞬で使用を許可していただきました。(爆速。感謝)

使ってみて、フロントもバックエンドも一通して開発させることができ、実装スピードは跳ね上がりましたが、バックエンドは自身が使用してきた言語ではなかったのもあり、コードレビューがボトルネックになりました。

そこで、いかに並行開発しスピードを出すか、より、どうやってレビューをしやすくするか、を考えるようになりました。 (もちろんAIにレビューさせる前提で、どこまでレビューするかはプロダクトや組織によるとは思いますが、完全Vibe codingは立場上できませんでした。)

コーディングの意図が分からないとレビューがしづらい

Claude Codeに実装させてpull requestを出す -> GitHubのpull request画面でレビューをする。他のメンバーのコードも同時にレビューしていて、自分の体感ではAIで書かせたコードのレビュー時間の方が短くできました。

他のメンバーのコードレビューでもAIが書いたコードレビューでも、pull requestは基本的には「何をしたか(What)」が記述されます。しかし、AIに私がコードを書かせた場合、レビューする側(つまり私)は、その背景にある「なぜこれが必要だったのか(Why)」を理解しながらプロンプトに打ち込んでいます。自分の意図がプロンプトに込められており、目で処理を追いながら、動作の度に止めたり再開したりの試行錯誤をしている時もあるので、大体のコードは頭に入っています。

人のコードに対してはGitHub上でのコミュニケーションで捕捉していると思います。

この問題は、Vibe codingで生まれたプロトタイプをプロダクトに昇格させるような、引き継ぎの場面でより顕著になりました。

  • 技術選定の背景がわからない(ex. なぜプロダクト1はNext.jsで、プロダクト2はReact+Viteなのか?)
  • ドキュメント化されていない「お作法」や「秘伝のタレ」のようなコードが存在する
  • 変更を加えたくても、意図が不明なため影響範囲が読めず、修正が怖い

コードレビューや運用保守において、表面的な「What:どういう変更か」だけでなく、そのコードが生まれた背景にある「Why:なぜこのコードが生まれたか」、つまり開発者が込めた意図を知りたい瞬間って結構あると思います。

これだけだと、CLAUDE.mdにコーディングの意図を含めてコメントやGitのコミットメッセージに書くように指示をして終わりですがもう一つ別の観点で。

AIコーディングエージェントの使用Tipsの共有・伝承

ペアプロ・モブプロっていいですよね。VSCodeの便利な使い方や、Excelのショートカットなどでも、普段意識することないレベルに使い込まれた技能を知ることができ、地味なんだけど生産性がとても上がったことを覚えています。

Claude Codeのように丸っと頼めるコーディングエージェントを使用していて、設定などは共有できるとしても、どういうプロンプトを打って開発させているのか、をチームで共有し、学ぶことに価値があるのではないか?と思うようになりました。

使用したプロンプトを残して共有する

上二つの観点から、私は「AIに与えたプロンプトを残し、共有することが今後大事になってくるのではないか」と考えました。

最初はCLAUDE.mdに書いたプロンプトをファイルに記載するように頼んでいたのですが、たまに無視するし、トークンを節約してるのか英語で書いたりと散々でした。

Claude Code hooks

そんな時に出たのがClaude Code hooks。特定のイベント後に確定でアクションを起こせます。最初はClaude Codeが終了した際に、発行されるStopイベントを利用していましたが、ユーザーが自ら止めた時に動かなかったり、プロンプト自体を取ることができなかったのでtranscript_pathに貯まるログファイルから抽出する手間があったりしたんですが、

最近しれっと追加されたUserPromptSubmitイベント。 このイベントは、ユーザーがプロンプトを叩くたびに発行され、InputのkeyにPromptが存在していて取り回しもしやすいです。

今回はUserPromptSubmitを使って、pull requestの詳細に使用したプロンプトが全て記載されるようにした仕組みを紹介します。 (ファイルとしてそのまま残すのも考えましたが、AIが開発時にノイズになったり、ディレクトリに残ってるのも微妙か?と考え、pull requestに全て乗るように作りました)

Step 1: Claude Code hooksでプロンプトを保存する

以下のスクリプトを.claude/scripts/save_prompt.shとして配置します。このスクリプトは、プロンプトが実行されるたびに、その内容をプロジェクトルートの.claude/prompts.logファイルに追記します。

#!/bin/bash
set -euo pipefail

# プロジェクトルートを取得(Claude Codeがcdで動き回るため固定)
repo_root=$(git rev-parse --show-toplevel)

# ログファイルのパス設定(プロジェクトの.claudeディレクトリ内)
LOG_DIR="$repo_root/.claude"
LOG_FILE="$LOG_DIR/prompts.log"

# 標準入力からJSONを読み込む
input=$(cat)

# jqを使ってプロンプトとセッションIDを抽出
if command -v jq >/dev/null 2>&1; then
  prompt=$(echo "$input" | jq -r '.prompt // "No prompt"')
  session_id=$(echo "$input" | jq -r '.session_id // "unknown"')
  cwd=$(echo "$input" | jq -r '.cwd // "unknown"')
else
  echo "❌ jqがインストールされていません。jqをインストールしてください。" >&2
  exit 1
fi

# タイムスタンプ
timestamp=$(date '+%Y-%m-%d %H:%M:%S')

# ログに追記
{
  echo "[$timestamp]"
  echo "Session ID: $session_id"
  echo "Working Directory: $cwd"
  echo "Prompt: $prompt"
  echo "=========================================='"
  echo ""
} >> "$LOG_FILE"

echo "✅ プロンプトをログに記録しました: $LOG_FILE" >&2
exit 0

これを.claude/settings.jsonに記載します。

{
    "$schema": "https://json.schemastore.org/claude-code-settings.json",
    "hooks": [
        {
            "event": "UserPromptSubmit",
            "script": ".claude/save_prompt.sh"
        }
    ]
}

.claude/settings.jsonを共有していてhooksを書いてる場合、チームメンバーは許可する・しないに関わらず、スクリプトが実施されてしまうので、お気をつけて・・・! (OSSをインストールしてClaude Codeを使用する際にもお気をつけて)

Claude Codeを最初起動する時の注意書き

Step 2: githooksでプロンプトをコミットメッセージに含める

ログファイルにプロンプトを記録するだけでは、どのプロンプトがどの変更に対応するのかわかりません。そこで、git commitを実行する際に、記録されたプロンプトを自動でコミットメッセージに含めるようにします。

Gitのprepare-commit-msgフックを利用します。以下の内容を.git/hooks/prepare-commit-msgとして保存し、実行権限を付与してください。

#!/bin/bash

# prepare-commit-msg hook
# コミットメッセージファイル、コミットタイプ、SHA1を受け取る
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3

# プロンプトログファイル
PROMPTS_LOG=".claude/prompts.log"

# prompts.logが存在する場合のみ処理を実行
if [ -f "$PROMPTS_LOG" ]; then
    # 既存のコミットメッセージを一時保存
    TEMP_MSG=$(cat "$COMMIT_MSG_FILE")
    
    # prompts.logから全プロンプトを抽出(重複を除去)
    PROMPTS=$(grep "^Prompt: " "$PROMPTS_LOG" 2>/dev/null | sed 's/^Prompt: //' | sort -u)
    
    # プロンプトが見つかった場合のみ追加
    if [ -n "$PROMPTS" ]; then
        # プロンプトを整形
        ADDITIONAL_MSG="## Claude Code プロンプト履歴"$'\n'
        while IFS= read -r prompt; do
            ADDITIONAL_MSG+="- $prompt"$'\n'
        done <<< "$PROMPTS"
        
        # 新しいメッセージを作成(既存のメッセージ + プロンプト履歴)
        cat > "$COMMIT_MSG_FILE" << EOF
$TEMP_MSG

$ADDITIONAL_MSG
EOF
    fi
    
    # prompts.logを削除
    rm "$PROMPTS_LOG"
    echo "✓ $PROMPTS_LOG を削除しました"
fi

exit 0

Step 3: GitHub Actionsでpull requestに集約する

pull requestが作成・更新されたタイミングで、そこに含まれる全てのコミットからプロンプト履歴を抽出し、PRのdescriptionに自動で追記するGitHub Actionsのワークフローを作成します。

.github/workflows/update_pr.ymlとして以下のファイルを作成します。

name: Update PR with User Instructions

on:
  pull_request:
    types: [opened, synchronize]
  workflow_dispatch:

permissions:
  pull-requests: write
  contents: read

jobs:
  update-pr-description:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Update PR description with user instructions
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const pr = context.payload.pull_request;
            if (!pr) {
              console.log('No PR found in context');
              return;
            }

            const { data: commits } = await github.rest.pulls.listCommits({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: pr.number
            });

            const userInstructions = new Map();
            let totalCommits = 0;
            let commitsWithInstructions = 0;

            for (const commit of commits) {
              totalCommits++;
              
              const lines = commit.commit.message.split('\n');
              let inPromptsSection = false;
              const instructionLines = [];

              for (const line of lines) {
                if (line.includes('## Claude Code プロンプト履歴')) {
                  inPromptsSection = true;
                  continue;
                }
                if (inPromptsSection && line.startsWith('##')) {
                  inPromptsSection = false;
                }
                if (inPromptsSection && line.trim().startsWith('- ')) {
                  const instruction = line.trim().replace(/^-\s*/, '').trim();
                  if (instruction) {
                    instructionLines.push(instruction);
                  }
                }
              }

              if (instructionLines.length > 0) {
                commitsWithInstructions++;
                for (const instruction of instructionLines) {
                  userInstructions.set(instruction, (userInstructions.get(instruction) || 0) + 1);
                }
              }
            }

            let commitSection = '## 📝 ユーザー指示履歴\n\n';
            if (userInstructions.size === 0) {
              commitSection += `このPRには${totalCommits}件のコミットがありますが、明確なユーザー指示は含まれていません。\n`;
            } else {
              commitSection += `総コミット数: ${totalCommits}件(うち${commitsWithInstructions}件にユーザー指示あり)\n\n`;
              commitSection += '### ユーザー指示一覧:\n\n';
              const sortedInstructions = Array.from(userInstructions.entries()).sort((a, b) => b[1] - a[1]);
              for (const [instruction, count] of sortedInstructions) {
                commitSection += `- ${instruction}${count > 1 ? ` (${count}回)` : ''}\n`;
              }
            }

            const currentBody = pr.body || '';
            const commitSectionRegex = /## 📝 (?:コミット履歴|ユーザー指示履歴)[\s\S]*?(?=\n## |$)/g;
            let newBody = currentBody.replace(commitSectionRegex, commitSection.trim());

            if (newBody === currentBody) {
              newBody = currentBody + '\n\n' + commitSection;
            }

            await github.rest.pulls.update({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: pr.number,
              body: newBody
            });

結果

この仕組みを導入することで、pull requestには以下のような「ユーザー指示履歴」が自動で追加されるようになります。

実際の画面

レビュアーは、コードの変更がどのような意図で行われたのかを把握できるし、チームメンバーがどのようにClaude Codeに指示を出しているかを理解し、どう使っていくのかの共有もできるようになりました。

まとめ

今回はAIが開発するのが当たり前になる世界観では、そのコードを生み出した「意図(プロンプト)」を管理し、チームで共有するかが大事になってくるのではないか、という仮説のもと、取り組みを紹介しました。


最後にAlgomaticは一緒に働くメンバーを募集しています! 私のようなプロダクトエンジニアも募集しているので、以下よりお気軽にカジュアル面談をお申し込みいただけると幸いです!

jobs.algomatic.jp

オープンウェイトモデルで広がる生成AI活用: LLM API活用の課題と自社運用

はじめに

こんにちは。Algomatic AI Transformation(AX) のsergicalsix(@sergicalsix)です。

近年、大規模言語モデル(LLM)の登場により、AIがビジネスの現場で急速に浸透しています。ChatGPTやClaudeなどのAPIを活用し、業務効率化や新サービス開発に取り組む企業も増えてきました。

しかし、実際にLLMをAPIで活用しようとすると、コストや安全性などの課題にぶつかることがあります。

その課題の解決策として、本記事ではオープンウェイトモデル(モデルの重みパラメータが公開されており、自由にダウンロード・利用できるLLM)の活用という観点で事例や先行研究をご紹介していきます。

LLMのAPI活用の課題

LLMのAPI活用における課題として、今回取り上げる課題は以下3つです。*1

コスト面の課題

LLMを本格的に業務へ導入すると、API利用料は短期間で高額になり得ます。 例えば、社内のナレッジベースから検索・要約を行うシステムや、大量の顧客対応を自動化するチャットボットでは、「1リクエストあたり数円」でも、数十万〜数百万リクエストが積み重なれば月間で数百万円規模のコストになることも珍しくありません。 さらに、モデルの大型化やコンテキスト長の増加に伴ってコストが増加するという構造的な課題もあります。 *2

速度面の課題

リアルタイム性が求められる業務では、APIの応答速度が致命的な制約になります。 たとえば、顧客とのチャットサポートや現場作業員への指示出しなどでは、わずか数秒の遅延でもUXの悪化やオペレーション効率の低下につながります。 特に大規模モデルでは、推論計算自体の遅延に加え、API経由のネットワーク遅延、さらにプロンプトやコンテキストの長文化によるトークン生成速度の低下が複合的に影響します。*3

安全面の課題

業務でAPIを活用する場合、データが外部に送信されることによる情報漏洩リスクや、生成結果の正確性・安全性の担保といった問題も避けられません。 特に法務や金融、医療分野では、誤った生成結果が即座に業務リスクにつながるため、単に「高性能モデルを使う」だけでは不十分です。 これらはモデルそのものの性能というより、API活用時の運用設計などの問題ですが、生成AI導入には避けて通れません。


これらの課題は、多くの企業がLLM APIを本格活用する際の障壁となっています。

解決策としてのオープンウェイトモデルの自社活用

前章で述べた3つの課題に対して、有効な解決策として注目されているのが「オープンウェイトモデルを自社の閉域網内で運用する」というアプローチです。

これにより、以下のメリットが期待できます。

  • コスト:ランニングコストの削減

  • 速度:通信遅延削減による低レイテンシー実現

  • 安全性:データが社外に出ないため、セキュリティリスクが軽減

ただオープンウェイトモデルの活用には欠点があり、その一つが性能面です。一般的にオープンウェイトなモデルは、現在最も性能が高いと言われているGPT-5やClaude Opus 4、Gemini 2.5 Proなどのクローズドなモデルと比べて性能が低いです。その理由の一つには、モデルサイズが小さいことが挙げられます。

ただタスク特化させた場合は、必ずしもモデルサイズが性能に比例するわけではありません。例えばコード生成系のタスクにおいてCodeLlama 7BがLlama 2 70Bよりも精度が高いことが報告されています(Subramanian et al., 2025)。

このように、個別タスクに特化させることにより「小さくても強い」モデルの構築が可能であることが明らかになっています。

さらにこのような背景の中、約1週間前に発表された「gpt-oss」は、o3-miniなどの既存モデルに匹敵する性能であることが報告されています(Open AI, 2025)。 gpt-ossについては特に注目度が高く、弊社(株式会社Algomatic)や株式会社リコー様が実用化に向けた取り組みを発表しています。

prtimes.jp

jp.ricoh.com

次章では、オープンウェイトモデルの具体的な導入・活用手法について、最新の研究成果をもとに解説します。

オープンウェイトモデルの活用

本章では、オープンウェイトモデルを実践的に活用するための2つのアプローチを紹介します。

1. 既存システムからの移行

2. 複数モデルを組み合わせたハイブリッド運用

以下で紹介する手法は、元々Small Language Model (SLM) のarXivで提案されたものですが、オープンウェイトモデルに適用可能なフレームワークのため紹介していきます。

以下では、オープンウェイトモデルを自社環境にデプロイして運用する場合を「自社運用モデル」と呼びます。

既存システムからの移行(Belcak et al., 2025)

Belcak et al., 2025は、既存システムから自社運用モデルへの移行プロセスを6つのステップで整理しています。またこれらは必ずしもAPIを利用しているシステムからの移行のみならず、人間が実施している業務でも同様の移行プロセスを実施することが可能です。

Step1. データ収集

まずは既存のモデルやエージェントが処理したすべての入出力ログを網羅的に集めます。 対象はテキストプロンプトやモデルの応答だけでなく、外部ツールやAPIの呼び出し履歴、検索クエリ、ユーザーのクリックや選択などの行動データも含まれます。 特に後続の分析や改善では、モデルの出力だけではなく「なぜその結果になったのか」を追えるコンテキスト情報が重要です。そのため、リクエストのタイムスタンプ、ユーザー属性(匿名化済み)、使用モデルやバージョンなどのメタデータも併せて収集します。

Step2. データ前処理

収集したデータは、そのままでは学習に使えません。品質の低いデータやリスクのある情報が混ざっているため、次のような処理を行います。

  • 個人情報や機密情報の削除/マスク

例:氏名、住所、メールアドレス、顧客IDなどを正規表現やNER(固有表現抽出)で検出し匿名化。

  • ノイズの除去

無意味な会話や重複データ、明らかな誤回答などを除去し、学習効率を高めます。

  • データの正規化

言い回しや表記揺れ(例:「メール」「Eメール」)を統一し、モデルが学習しやすい形に整えます。

  • バリエーション生成(パラフレーズ作成)

同じ意味を異なる表現で追加することで、モデルの汎化性能を向上させます。

こうした処理により、安全かつ多様性のある高品質データセットが得られます。

Step3. タスクのクラスタリング

ログを分析し、類似タスクをグルーピングすることでデータを分類します。これにより、各領域に特化したカスタムモデルやプロンプトチューニングが可能になります。

補足ですが、Step2. データの前処理とStep3. タスクのクラスタリングについては、以下に詳しく記述されています。

arxiv.org

arxiv.org

Step4. モデル選定

クラスタリングされたタスクごとに、性能・推論速度・コンテキストウィンドウ・運用要件などを総合的に評価し、最適なモデルを選びます。 ここでは単一の指標を見るだけではなく、各タスクに最も適した特性を持つモデルを選び、無駄な計算資源を削減しながらも必要な精度を確保することが重要です。

Step5. チューニング

プロンプトチューニングや選定したモデルに対して、LoRAやQLoRAなどでファインチューニングを行います。必要に応じて、蒸留も活用し、性能を補強します。 こうした軽量かつ効率的な学習手法を組み合わせることで、限られたリソースでも実運用に耐える精度と応答速度を実現できます。

Step6. 継続的な改善

運用後についてもStep2〜Step5の工程を繰り返し、精度や速度向上などを実施します。 新しい利用パターンやデータが蓄積されるたびにモデルを更新し、変化する業務ニーズやユーザー期待に対応できる状態を保つことが大切です。


しかし、すべてのタスクを一度に移行するのは現実的ではない場合もあります。 次節では、段階的な移行を可能にするハイブリッドなアプローチを紹介します。

複数モデルを組み合わせたハイブリッド運用(Chen et al., 2025)

完全な自社運用モデル移行が困難な場合でも、以下の4つのパターンでクローズドモデル(API)とオープンウェイトモデルを効果的に組み合わせることで、コスト削減とセキュリティ向上を実現できます。*4

1. Pipeline(パイプライン)

処理を複数のステップに分解し、自社運用モデルで前処理や定型作業を実行後、その結果をAPIに渡して後続の処理を実行します。

例えばCoGenesis(Zhang et al., 2024)では、端末上のSLMが個人のコンテキストを読み取って整形し、クラウド上のLLMがタスクを実行するといったワークフローが採用されています。

CoGenesisの概念図(Zhang et al., 2024)

2. Routing(ルーティング)

入力内容の複雑度や機密性に応じて、自社運用モデルとAPIを動的に使い分けます。簡単なタスクは自社運用モデルで素早く回答し、難しいタスクはAPIを通じて実施します。

例えばCITER(Zheng et al., 2025)では、出力の生成過程をトークン単位で制御し、定型的な部分や平易な部分はSLMが生成し、重要度が高く正確さが必要な部分はLLMが担当します。このルーティングは強化学習で最適化され、品質とコストのバランスを取っています。

CITERの概念図(Zheng et al., 2025)

3. Auxiliary(補助/強化)

APIをメインとしつつ、自社運用モデルが前処理や情報抽出で支援します。例えば自社運用モデルが社内文書から関連情報を検索・構造化し、その結果をコンテキストとしてクローズドモデルに提供するなどです。

例えばCollab-RAG(Xu et al., 2025)では、SLMが複雑な質問を複数のサブクエリに分解することで検索精度を向上させ、LLMが最終的な回答を作成します。

Collab-RAGの概念図(Xu et al., 2025)

4. Knowledge Distillation(知識蒸留)

クローズドモデルの出力を教師データとして、自社運用モデルを改善します。

例えば全体の出力のN(0 < N < 100)%をAPIで処理し、データを収集することで自社運用モデルを継続的に訓練するといった活用方法が考えられます。

余談ですが、知識蒸留については以下のサーベイ論文に参考になります。

arxiv.org

複数モデルを組み合わせたパターンの選択指針

所属されているチームの優先事項や目的に応じて、以下のアプローチを選択すると良いです。

  • コスト削減: Pipelineを採用し、前処理や簡単な処理を自社運用モデルで対応

  • セキュリティ最優先: Routingを採用し、機密データが関わる部分を自社運用モデルに分離

  • 精度向上: Auxiliaryを採用し、社内ナレッジや専門知識を自社運用モデルで補強

  • 段階的移行: Distillationを採用し、徐々に自社運用モデルを強化

まとめ

本記事では、LLM APIの活用で多くの企業が直面する「コスト」「速度」「安全性」の課題に対して、オープンウェイトモデルの活用は現実的な解決策の一つです。

定型的なタスクから自社運用モデル化を始め、徐々に適用範囲を広げていくといったアプローチやハイブリッドなモデル運用などが今後必要になってくるかもしれません、

今後もオープンウェイトモデルの動向を注視しながら、最適な活用方法を模索していきたいと思います。


最後にAlgomaticは一緒に働くメンバーを募集しています!

以下よりお気軽にカジュアル面談をお申し込みいただけると幸いです!

jobs.algomatic.jp

*1:今回取り上げなかった課題として、①オフライン環境またはネットワーク速度が低い環境で使えない②エネルギー制約がある場合に使えないといった課題があります。①は概ね速度面の課題や安全面の課題で吸収でき、②はまだ日本で課題として顕在化していないと判断しています。

*2:コスト面の課題に対する対処法として本記事では触れませんが、①定額課金制のサービスを使用する②性能が高く安価なモデル(例: Gemini 2.5 Flash)を使用するなどがあります。

*3:速度面の課題に対する対処法として本記事では触れませんが、CerebrasやGroqなどの高速なプロバイダーを使うなどがあります。

*4:Chen et al., 2025内では、紹介したパターン以外にIntegration/Fusionが紹介されています。しかしアーキテクチャレベルや重みレベルのモデル統合は本記事の対象外であるため、紹介していません。

LLMで"何でも"できる時代のAIエンジニア生存戦略 - LLMのグラウンディング能力について

結論

  • LLM/VLMで"何でも"できる時代に、LLMにはグラウンディングという苦手な事があります
  • LLM/VLMを、グラウンディングができるモデルとうまく組み合わせるといいかもしれません
  • この「グラウンディングをどうするか」が次世代のAIエンジニアに求められるスキルの一つかもしれません

結論は以上です。


こんにちは。 AlgomaticのAXカンパニーでは現在AIエージェントネイティブなデザインツールネオデザインAIを開発しています。

neodesign-ai.com

今回は、AIエンジニアとしてこのプロダクトのAI技術開発に携わる中で得られた知見について、皆さんにお伝えしたいと思います。


* この記事は現在進行形で発展している技術領域についての考察であり、また、筆者の個人的な見解や推測を含んでいます。AI技術の進歩は非常に速く、記事執筆時点での情報や分析が将来的に変わる可能性があります。また、技術的な内容については間違いや不正確な部分が含まれている場合もありますので、重要な判断を行う際は最新の情報や専門的な資料もあわせてご確認いただければと思います。


ネオデザインAIとは

ネオデザインAIの対象ドメインは、広告クリエイティブのデザインです。 クリエイティブとは、SNSの広告などで使われる画像のことです。

このようにイベントの広告や商品の宣伝で使われるものがあります。

クリエイティブを制作するときには様々なステップがあります。 例えば、クリエイティブを制作するための情報が載った企画書を理解し、テンプレートを選ぶ、細かくデザインを修正するなど、そのステップは多岐にわたります。

私たちが開発しているネオデザインAIでは以上のようなプロセスにおいて人の作業コストを減らすことを目標としています。 今まではデザイナーが担当していた箇所をプロダクトが代わりに行うことで、非デザイナーでもクリエイティブの作成を行うことができるようになることを目指しています。


レイアウト理解タスクとは

私たちが開発しているプロダクトにおいて重要なのは、AIがクリエイティブのレイアウトを深く理解する能力です。 私たちはレイアウトの理解タスクを以下の要素を検出することと定義します。

要素
画像 位置・大きさ
テキスト 位置・大きさ・フォント・ウェイト・カラー
図形 形状・位置・サイズ
コンポーネント 画像+商品名テキストなどのまとまり
変数判定 クリエイティブの要素の中でよく変更されるであろう要素

"深く"理解するとは?: 以下の図に示すように、レイアウトを理解するには位置や大きさといったピクセルレベルのものから、フォントやコンポーネントといった抽象度の高いものまで検出・理解する必要があります。

変数判定: レイアウト理解タスクにおける変数とは、あるクリエイティブのレイアウトを全く同じものを用いて、別のことを宣伝したい時に変更すべき箇所です。 例えば、この猫フェスのクリエイティブのテンプレートを用いて犬のフェスの宣伝を行いたい場合には、「猫の画像」と「ねこフェスというテキスト」を変更する必要があることが考えられます。

これらがなぜ私たちのプロダクトにおいて重要かというと、例えば「会社が持つ既存のルールを守った高品質テンプレート生成」や「デザイン品質保証」には 精密なレイアウト理解 が不可欠だからです。

しかし、以上のようにAIがデザインをうまく扱うにはいろいろな課題があると私たちは考えました。 その中でも今回は、

VLMのグラウンディング能力の欠如

について解説したいと思います。

従来手法の課題

レイアウト理解タスクにおいて既存のAIが直面する最大の困難は、単一の技術では解決できない複合的な能力が要求されることです。具体的には、①グラウンディング能力、②セマンティックな理解能力、そして③推論能力という、異なる性質を持つ高度な能力を同時に必要とします。

①グラウンディング能力 "グラウンディング能力"とは、"AIが言葉や概念を、具体的なものや実際の世界と結びつけて理解する能力"のことです。 LLMの"グラウンディング能力"として身近なものとしては、検索結果を利用して事実に基づく、という意味で聞いたことがあるかと思います。 この「グラウンディング」という単語は他の分野、例えば画像分野でも使われます。 画像分析におけるグラウンディング能力の一つは、AIが画像内で「どこに」オブジェクトが配置されているかを正確に特定する能力のことです。これは空間的な位置関係の理解に関わる基礎的な視覚認識能力です。

②セマンティックな理解能力 AI分野におけるセマンティックとは、単純な物体認識を超えた抽象度の高い意味性の理解を意味します。 例えば、クリエイティブの中に、「猫の画像」がある、などをいうことを意味します。 例えば、猫という認識をせずにオブジェクトの位置だけを検出する場合はそれはセマンティックなタスクとは言わないことが多いでしょう。

③推論能力 さらに、近年話題になっているReasoningという概念があります。LLMの場合だと、これは複雑な問題に対して理由をつけて(トークンを消費して)回答をする能力を一般的には指しています。例えば、「画像の中で喉が渇いた時に欲しい物はどこにある?」という指示に対して、水の入ったペットボトルを見つけるには、喉が渇いた時に欲しい物とは何かを推論する必要があります。 例えば、上記の例の画像の「ねこ」と「フェス」のテキストはグループになる、などというには、フォントが同じだから、とか、猫フェスで繋がるから、など推論能力が必要とされます。

このような技術が要求されるため、従来の手法ではレイアウト理解タスクにおいて十分な性能を発揮できませんでした。以下に具体的な事例を解説します。

LLM/VLM

私たちは開発当初、大規模言語モデル(LLM)と視覚言語モデル(VLM)を活用したレイアウト理解手法の開発に着手しました。最も直接的なアプローチとして、VLMにクリエイティブ画像を入力し、画像内の要素の位置情報を座標ベースで出力させる手法を試行しました。

しかし、この手法では期待された精度を得ることができませんでした。 VLMやLLMは言語や画像のコンテキストでの理解に最適化されているため、「ここに商品画像が配置されている」といった定性的な記述は可能である一方、座標値(x, y)やサイズ情報(h, w)を数値として定量的に正確に出力することに本質的な困難を抱えていることが予想されます。 この結果は、言語モデルの設計思想が連続的な数値処理よりも離散的なトークン処理に特化していることに起因すると考えられます。

GoogleはGeminiを用いてSpatial Understanding、つまり物体検出ができることを提案しています。 これはGeminiに画像を与えてBoundingBoxをJSON形式で出力させるというものです。 Bounding Boxとは物体検出において広く用いられる座標の羅列形式です。 例えば (x_min, y_min, x_max, y_max) という羅列です。これを用いると検出対象の物体を囲む四角形を描画することができます。 以下に示すように私たちはこれを試しましたまだ精度が不十分です。

Set-of-Mark Promptingではこれらの課題をスマート解決しています。

Set-of-Markではまず、画像に対してSAMなどのモデルを用いて"すべてに適当に"セグメントを行います。 その後、セグメント領域全てにIDを振り、そのIDを画像に直接描画します。 その数字が描画された画像をクローズドなVLM(論文ではGPT4V)に直接入力することで、出力のテキストの中でIDを用いて回答をセグメントマスクでグラウンディングできるようにします。 こうすることで、VLM(GPT4V)にセグメントの情報が入力・出力できない問題を解決しています。

しかし、以下の問題が論文で指摘されています。

  • 小さいセグメントの上に大きなセグメントが被る
  • 番号が別のセグメントの上に重なる
  • セグメントの数が多くなったり、セグメント自体が小さくなるとIDの数が膨大になり、画像に正確にIDを記載させるのが難しくなる

特にクリエイティブは、要素の数が多いのでこの手法では問題があります。

言語モデルでBoundingBoxを出力させることは"正しい"のでしょうか?

LLMの基本的な動作原理は次トークンの確率分布を出力させて、高い確率を持つ単語を選択するというものです。(サンプリングの説明を省きます。)

この処理方式をBounding Boxの出力に適用した場合座標の出力をする際に 例えば座標値「123.45」を出力する場合、現代の言語モデルは「123」「.」「45」といった個別のトークンを再帰的に順次予測します。(というトークナイザーがあるとします。)

この画像の例のように、次のトークン予測になるため、「1.0」の「0」を出力する時には、「1.」の次に何が来るか、ということを考えることになります。 これは従来の物体検出のモデルとは全く異なる仕組みです。 従来の物体検出モデルは直接座標を出力するように学習されます。

実はGemini Spatial Understandingでは0から1000の値で座標値を出力させることで小数点をなくし、全ての数値を一つのトークンで表しています。 つまり内部では擬似的に分類タスクになっているとも言えるかもしれません。 しかし、ここで気になるのは「物体検出タスクを分類タスクとして解くことは精度が出やすいか?」ということです。

OCR

OCR(Optical Character Recognition)とは、画像上に存在するテキストの内容を検出・認識する技術です。しかし、従来のOCRは主にテキストの文字内容の識別に特化しており、位置情報や視覚的属性の正確な把握には本質的な限界があります。 フォント属性認識における課題 OCR技術が抱える主要な問題点として、以下が挙げられます:

  1. 位置・サイズ情報の不正確性 - テキストの配置や大きさを精密に捉えることが困難
  2. フォント差異の認識限界 - フォントサイズやウェイト(太さ)の細かな違いを識別できない
  3. 視覚階層の理解不足 - デザイン上の重要度やレイアウト構造を把握できない

OCRはすでにたくさんのAPIベースのサービスとして展開されています。 しかし、これらの既存のOCRサービスを用いた実験においても、文字サイズの正確な検出において顕著な精度不足が確認されました。これは、OCR技術の根本的な設計思想が文字認識に重点を置いており、レイアウト解析には適していないことを示しています。

クリエイティブの画像内にあるテキストのフォントやフォントの色を検出するというタスクも必要です。 フォントを検出することは、クリエイティブでは色々なフォントが使われるため、対応が難しいです。 フォントカラーに関しては、理論上セグメントが100%の精度で可能であればテキストを切り取って、ルールベースで色を判定することができます。しかしそもそも先述したように、日本語のテキストに対するセグメントの精度を高めるのは難しいでしょう。

物体検出・セグメンテーション

物体検出・セグメンテーションタスクはグラウンディングと密接な関係があります。 これは位置を検出すること自体がグラウンディングと言えるからでしょう。 物体検出やセグメントに関してはこれまでたくさんの研究がされ、OSSの訓練済みのモデルも発表されてきています。 これらのモデルは一般的な物体検出タスクにおいて優れた性能を示すと考えられますが、 クリエイティブ分野での応用や複雑な推論の要求されるタスクにおいて、これらのモデルのみを用いることは以下のような理由から重要な限界を抱えています。

セグメンテーション:セグメントに関しては、例えばSegment Anything Modelのようなモデルを用いるとセグメントができますが、どのような物体へのセグメントができているかが理解できていないのでこの結果を直接利用してレイアウトの分析をするのが難しいという課題があります。

推論能力・知識量の限界 さらに、これらのモデルの課題は推論能力や知識量の不足であると考えます。 例えば、お菓子の〇〇(商品名)を宣伝するクリエイティブの画像に対して、「〇〇(商品名)の画像をセグメントして」のような固有名詞を含む指示がある場合、これらの従来のモデルは適切に対応できません。 また、「右にある三つの商品画像のうち、真ん中にある商品だけをセグメントして」といった空間的関係性や順序性を要求する複雑なクエリの処理も困難です。このような高度な推論タスクに対応するためには、言語モデルのような推論能力が必要と予想されます。

クリエイティブの画像データとしての複雑性クリエイティブ分野特有の問題として、複雑で多様なレイアウト構造があります。一般的な物体検出モデルは一般的なオブジェクトカテゴリで事前学習されているため、クリエイティブデザインの独特な要素や配置パターンに対する理解が不十分です。この学習データの偏りと実際のクリエイティブ制作現場でのニーズとの乖離が、実用性の阻害要因となっていると考えられます。

セグメントが可能なLLMモデル

LLMの推論能力とセグメントのグラウンディング能力を統合しようという取り組みが多くされています。 多数の手法がある中でもここでは2つ簡単にご紹介します。 一つ目は事前学習済みのLLMと別のセグメントができるモデルを組み合わせてLLMの出力をデコードしてセグメントにするようなアーキテクチャで、どちらのモデルも学習させる方法です。(LISA, GLaMM) 二つ目の方法として、一つ目の方法の中のマスク生成モデル(例えばSAM2)をフリーズして、LLMのみをチューニングし、最適なセグメントのマスクを得るために、マスク生成モデルに入力されるプロンプトを最適化するという手法があります。(Seg-R1, SAM-R1)

セグメントが可能なLLMの主なアーキテクチャ(かなり単純化されており、省略されていることが多いので注意してください)

弱点: 二つ目の手法に関してはこのアーキテクチャで学習させたとしてもセグメントモデル自体の能力はパラメータレベルでは変わらないことがわかります。一つ目の手法に関してはLLMの推論能力が、訓練されるOSSのLLMの能力に依存してしまいます。

Document AI

Document AIとは、書類を理解するためのAIであり、基本的には文章や画像がどこにあるかを理解することを目的としています。 例えば、LayoutParserは書類について理解することを目的としています。クリエイティブを対象としていません。 この文脈において私たちは、クリエイティブとDocumentの違いは、複雑性にあると考えています。クリエイティブでは例えば、多様なフォントが使われたり、テキストの配置に一定のルールが見られなかったりします。そのためDocument AIの対象のドキュメント、よりも「複雑」なものを対象とします。

デザインに関するエージェントの研究

既存研究デザインに対するエージェントには以下のようなものがあります。 BannerAgencyでは、デザインのデータをJSON形式で表現しLLMが生成できるようにしています。 COLEは、デザインをJSON形式で表し、そのデータ構造で、OSSのLLMモデルを訓練しています。StepbyStepで生成し、最初にレイアウト構成、画像は後から生成しています。 PosterLlamaでは、背景画像を生成した上でHTMLのような形式でテキストを生成しています。 いずれもレイアウトを詳細に深く理解して分析するというグラウンディングの話はしておらず、一般的なレイアウト生成の話をしています。

興味深い点としては、BannerAgencyではVLMを用いてフィードバックを行うプロセスを導入しています。しかしそもそもVLMが精度よく検出できる能力には限界があります。 例えば、「テキストを3px左に動かせば背景画像の顔と被らない」などといったような細かな検出は不得意である事が予想されるため、そもそもフィードバックのシグナルを生成するのが難しいという課題があります。

学習コストの問題: 一般的にこれらのAIモデルを開発するには、学習コストがかかります。 セグメンテーションのモデルや物体検出のモデルを学習するのはとてもコストがかかりますし、学習したモデルには以下の2点の問題があります

  • 精度が悪いリスクがある: 特にクリエイティブの場合には、検出対象が多様で特徴量が安定しないだろうという仮説があるため、学習に大量のデータが必要と予想される。
  • 柔軟性がなくなる: 検出するものがデータセットに依存するため、例えば新しく検出したいものが変更された時に、新たなデータセットを作成して、再学習させる必要がある。

手法

従来のAIには以上のような問題があるため私たちは独自の方法で解決しました。 従来のAIとは違い、LLM、 VLMでは抽象度が高いことが柔軟にできるようになってきています。 AIという分野の歴史において、初期の頃に可能だったことは抽象度の低いタスクでした。もしくは、抽象度が高い事象を低い次元に落とし込む、特徴量の抽出を行うことで対処してきました。 当時と比較すると、現在は自然言語の高度な質問に対応するといった抽象度がとても高いことができるようになってきています。 私たちはこの時代において、レイアウト分析のように、抽象度の低いタスクと抽象度の高いタスクを同時に行うことが必要な場合、LLM(特にクローズドなモデル)と他の専門家モデル、例えば専門性のある、物体検出のモデルを組み合わせることでゼロショット解決できる可能性があるということを提案します。

そこで、LLMモデルと物体検出のようなモデルを組み合わせるアプローチを採用しました。

End-to-Endではない方向性にした理由: 私たちが開発したAIモデルは、前述のように、一つのモデルではなく、複数のステップから成り立っています。 それに対して、AIの分野においては、End-to-Endなモデル、が存在します。 End-to-EndなAIとは、中身を全てをブラックボックス化し、単純に入力と出力のペアを用意して、一つのAIモデルを学習させることです。 End-to-Endなモデルを開発することはAIの業界において長らく行われてきました。 しかし、①現在エージェントが台頭しつつあることと、②クリエイティブの理解には様々な能力が要求される、③学習コスト削減のため、私たちはこちらの方向性をとっています。 ですが将来的にはデータセットを自動で作成するなどを行い、End-to-Endなモデルを開発することは考えています。

学習コストがゼロ: 私たちのAIの優位性は、学習なしで汎用性があることです。これは汎用性が高く、別分野への応用もしやすいことが予想できます。学習させないゼロショットの推論をするモデルであるため、例えば新しく検出したいものが増えたり、検出したくないと思った場合にすぐに対応できます。

ノイズの問題: 物体検出のようなプロンプトエンジニアリングのような即時性のある調整の効かないモデルの弱点は、 時々異常なノイズを出力することです。 このノイズを含んだままその後のプロセスに進むとその後のプロセスに大きく影響します。 一般的にこのようなノイズを修正したい場合にはモデルを学習しなければなりません。 それと比較してLLM・VLMと組み合わせる場合は、「プロンプトエンジニアリング」を用いることで時間をかけずに学習なしで出力を制御できるという利点があります。 そのため組み合わせることで専門的なモデルで出力されたノイズを、VLM側で「プロンプトエンジニアリング」を通して吸収できるという利点があります。

以下に他のモデルとの違いを簡単に図にしたものです。定量的なものではないので参考程度にしていただければと思います。

私たちはさまざまな手法を検証したうえでプロダクトに実装しました。 今回は私たちが開発している中でも簡単な例として、いくつかの事例を紹介します

結果

以上の考え方を応用して、私たちはさまざまな手法を提案・開発し、プロダクトに実装しています。 今回は私たちが開発している中でも簡単な例として、いくつかの事例を紹介します。 (技術保護の観点から詳しい方法はお伝えすることができないことをご了承ください。)

画像要素の検出

画像変数とはクリエイティブの中で入れ替えられる素材、のことです。 例えば、この猫のクリエイティブにおいては、他のフェス、例えば、犬のフェスティバルなどを宣伝する場合には、「猫の画像」は犬の画像に入れ替える必要があります。 これを見つけるためには大きく二つの要素が重要です。 ①VLMなどの推論能力を用いて変数となる物体を認識して、 ②グラウンディングできるモデルを用いて位置を特定する必要があります。

私たちは以下の図に示されるように、LLMだけではなく従来の検出モデルを用いて、LLMの推論能力と物体検出系のモデルのグラウンディング能力を組み合わせる手法を提案しました。

実際の結果

こちらの結果を見ると画像変数となる箇所を自動で判断して、検出を行うことができていることがわかります。

以下のように複雑な「推論」能力と、どこにあるかという「グラウンディング」が必要とされます。

この猫のクリエイティブにおいて難しいのは どこを検出すべきか、という点です。 例えば、右上のリボンの装飾だけを検出対象として認識して、 他の丸の装飾などは変数ではなく、背景画像として認識したいという気持ちがあります。 そのため「高度な推論能力」が必要とされるのです。

このクリエイティブの場合は、人・手持ち扇風機・バックなどを認識するのではなく 右側にある画像を人まとまりに変数としたいのであっています。

私たちの開発しているAIの特徴として「ほぼプロンプトエンジニアリングのみで検出対象を柔軟に変えることができる」があります。例えば、上のクリエイティブで顔や扇風機を検出したいような要件が出てきた場合に、モデルを再学習させることなく」、プロンプトエンジニアリングのみで要件変更に対応できるという強みがあります。

テキストの位置の検出

テキストの位置を検出できる低レベルのモデルとVLMを組み合わせました。 検出モデルを用いてVLMの能力を補完し、その過程で起きたノイズをVLMで吸収するという手法です。 OCRやその他検出系のモデルは特にノイズが出やすいです。 前述した通り、それらのノイズをVLMなどのモデルでうまく吸収するという方針になっています。

実際の結果

まだ改善途中ではあるもののそれぞれの文字に対して精度よくbounding boxが検出できていることがわかります。

今後は定量的に評価できる実験を行っていく予定です。


これからのAI開発に重要かもしれないこと

LLM時代のAI開発

現代のAI開発において、私たちは「抽象度ドリブン開発(Abstraction-Driven Development)」という名前を提案したいと思います。これは、独立したモデルを用いて低レベルのタスクを高精度で処理し、LLM/VLMのタスクと明確に分離することに焦点を当てた開発手法です。 LLMには得意分野と苦手分野が明確に存在します。例えば、文章の感情分析や内容理解は非常に得意ですが、文字数を正確に数えるような単純な作業は意外にも苦手としています。数学の問題かどうかを判定することはできても、実際に数式を解くことになると精度が落ちる傾向にあります。 日常的な推論においても同様の傾向が見られます。「喉が渇いたから水が欲しい」という論理的な推論は得意でも、実際に水を取りに行くためにロボットのモータをどの程度動かすべきかという具体的な制御信号を出力するのは困難です。クリエイティブな領域でも、商品画像の存在を認識することはできても、その画像が画面上のどの位置にあるかを正確に特定することは課題となります。 理想的には、ある単一のモデルですべての課題を解決できれば素晴らしいことでしょう。実際に、近い将来にはそのような汎用的なモデルが登場する可能性も十分にあります。現在もLLMにグラウンディング能力を付与する研究は活発に行われており、着実に進歩を遂げています。 しかし現実的には、まだ多くの困難なタスクが残されているのが現状です。この課題の根本的な原因は、現在のAIが言語という抽象的で処理しやすい文脈に特化して発展してきたため、物理的な世界との対応関係(グラウンディング)が必要な文脈との親和性が低いことにあると考えられます。 そこで私たちが提案したいのは、目の前のタスクに取り組む際に「これは言語の文脈で解くべき問題なのか?」という視点から問題を見直すことです。この問いかけによって、より適切なアプローチを選択し、効率的な解決策を見出すことができるのではないでしょうか。

Tool-Driven Development(ツールドリブン開発)

私たちは、このエージェントの時代におけるAI開発の新たな開発方針としてさらに「Tool-Driven Development」を考案しました。 従来のアプローチでは、複雑なタスクを一つの大きなE2Eモデルで解決しようとしていました。私たちが提案する手法では、「最終的に実現したい複雑なタスクを小さな単位に分解し、それぞれのタスクに特化したAIモデルを開発することで、最終的に高度な機能を持つエージェントを構築する」ことを目指します。 具体例として、私たちのネオデザインAIプロジェクトでは、「クリエイティブに特化した物体検出モデル」を独立したAIモデルとして開発し、それをエージェントがツールとして活用することで、より高度な機能を持つエージェントの開発が可能になると考えています。 このアプローチにより、各コンポーネントの専門性を高めつつ、全体としてより柔軟で拡張性の高いAIシステムを構築することができます。

"LLMで何でもできる時代”のAIエンジニア生存戦略

昨今、生成AIの進化は本当に目覚ましく、従来は専門的な知識や技術を必要としていた様々なタスクが、誰でも気軽に取り組めるような時代になってきているように思います。文章を書いたり、画像を作ったり、プログラムを組んだりといったことが、生成AIを使えば驚くほど簡単にできるようになっています。 ただ、この記事でお話ししてきたように、言語や画像の理解においてLLMが素晴らしい能力を見せてくれる一方で、現実世界の物理的な部分や具体的な制御との間には、まだまだギャップがあるのが実情かもしれません。 このギャップこそが、AIエンジニアの皆さんにとって腕の見せどころになるのではないでしょうか。LLMが中心となっている今の時代だからこそ、あえてLLM以外の技術やアプローチを上手に使って、LLMではカバーしきれない部分を補っていく。そんなスキルが、これからのAIエンジニアには重要になってくるかもしれません。 LLMを使いこなすだけでなく、その得意不得意をしっかりと理解して、必要に応じて他の技術と組み合わせながら、より実用的で信頼できるAIシステムを作り上げていく。AI技術がどんどん身近になっていく中でも、そういった専門的な視点と技術力こそが、エンジニアとしての価値を保ち続ける鍵になっていくのかもしれません。


採用情報

Algomaticでは現在積極的に採用活動を行っています。

jobs.algomatic.jp


著: Shure, 実験:Ootsuka

Gemini CLI のサンドボックス機能とは

はじめに

GoogleからGeminiをコマンドラインで対話的に利用できる「Gemini CLI」が登場しましたね!

基本的な使い方については、すでに多くの方が素晴らしい解説記事を公開されていますので、ぜひそちらもご覧ください。

参考 zenn.dev

この記事では、Gemini CLIが備える機能の中でも、Claude Codeにはない「サンドボックス」機能に焦点を当てます。

リポジトリはこちら

github.com

この記事でわかること

  • Gemini CLIのサンドボックス機能がなぜ必要なのか
  • サンドボックスが有効になると、具体的に何が起きるのか
  • -sフラグを付けるだけの簡単な使い方
  • macOSとコンテナベース、2つのサンドボックス方式の違い
続きを読む

Neovim & Claude Code でCursorっぽく開発したい

はじめに

Claude Codeがめちゃくちゃ伸びています。 この背景には、特定のIDEへの依存度を下げたいという需要があるのだと思います。

確かに特定のIDEに依存しないClaude Codeは高い柔軟性を持ちますが、CursorやWindsurfのような気の利いた機能(Diff表示やGUIでの設定管理などなど)はありません。

本記事ではこれらの課題に対する解決策として、Neovimの--listen機能を活用したClaude Codeとの効率的な連携方法を提案します。これにより、CLIベースの柔軟性を維持しながら、直感的で快適な開発体験を実現できます。

今回紹介する方法を使えば、Claude Codeの支援を受けながらNeovimを操作することができるようになるので、Vimに慣れていない方にこそ試してみて欲しいです。

続きを読む

Azure Functionsで長時間かかるタスクを実行したいあなたへ 〜Durable Functions入門〜

こんにちは、Algomatic ネオセールスカンパニーCTOのきくち (@_pochi)です。

Azure Functions便利ですよね。そして、Azure Functionsをゴリゴリ使っていると、「長時間実行したい」というニーズが出てくるのではないでしょうか。簡易的には、Functionのタイムアウト設定を伸ばすことである程度対応できるものの、APIサーバーとしてはタイムアウトは短く保ちたいし、そもそも「タイムアウト伸ばしてどうこうする」のは本質的な解決にならないので、避けたいですよね。ではどうするべきでしょうか。

「長い処理」を任せる選択肢

まず、Azure環境で「何らかの処理を長時間実行する」ための選択肢をいくつか挙げてみました。このように選択肢は複数ありますが、今回はDurable Functionsを取り上げます。

他の手段では、Azure Functions以外の異なるAzureリソースの構築が必要で複雑になりがちですが、Durable FunctionsはAzure Functionsのコードを追加実装するだけで長時間実行が実現可能なのです。*1

*1:Storage Accountの設定だけは必要です

続きを読む