Inside of LOVOT

GROOVE X 技術ブログ

Cloud Run (Next.js) と Cloud SQL の接続構成

はじめに

こんにちは、junya です。Cloud Run上で動作するNext.jsアプリケーションから、Cloud SQL (PostgreSQL) データベースへ接続しようとしたところ、思いのほか苦戦したので、記録として残しておきます。

技術的選択肢と接続ライブラリ

選択肢が多々あり、その選択肢の意味を理解し、適切なものを選び、設定していくのが大変でした。Cloud RunとCloud SQLの連携には、主に以下の要素の組み合わせで構成が決まります。ここでは、Cloud Runからの接続方法を主軸に、それぞれの技術的選択肢とDrizzle ORM (Node.js) で利用するライブラリを整理します。

  • 前提となる選択肢

    • ネットワーク構成:

      • Public IP: Cloud SQLインスタンスにパブリックIPアドレスを割り当てます。

      • Private IP: VPCネットワーク内にのみIPアドレスを割り当てます。VPCコネクタが別途必要となります。

    • PostgreSQL接続方式:

      • TCP: localhost:5432のようなホスト名とポート番号で接続します。

      • Unix Socket: /cloudsql/[INSTANCE_CONNECTION_NAME]のようなファイルシステムのパスで接続します。

    • 認証方式:

      • パスワード認証: データベースにユーザー名とパスワードを設定します。

      • IAMデータベース認証: Google CloudのIAMプリンシパルを利用します。接続方法には主に以下の2種類があります。

        • Cloud SQL Auth Proxy: Proxy(またはConnectorライブラリ)が認証トークンの取得と利用を自動化します。

        • gcloud sql generate-login-token: gcloudコマンドで一時的な認証トークン(パスワードとして使用)を手動で生成します。

  • Cloud Runからの接続方法の選択肢

    • Cloud SQL Auth Proxy経由

      • 概要: Cloud Runの機能として、アプリケーションコンテナと同一環境でCloud SQL Auth Proxyコンテナを起動します。アプリケーションは、TCP (localhost) またはUnixソケット経由でこのProxyに接続します。

      • 利用ライブラリ (Drizzle):

        • drizzle-orm

        • pg (node-postgres) または postgres (postgres.js)

        • @google-cloud/cloud-sql-connector
      • 備考:
        • Cloud Run には Cloud SQL Auth Proxy を自動で動かすオプションがあります。
        • pg (または postgres) 単体では、IAM 認証がうまくいかず、 @google-cloud/cloud-sql-connector の力を借りました。
    • VPC経由の直接接続

      • 概要: VPCコネクタを利用してCloud RunとCloud SQL間のネットワーク経路を確立します。データベースのPrivate IPに直接接続します。認証にはユーザー名とパスワードを使用し、これらの認証情報はSecret Managerで管理するのが一般的です。

      • 利用ライブラリ (Drizzle):

        • drizzle-orm

        • pg (node-postgres) または postgres (postgres.js)

      • 備考: Secret Manager 等で認証情報を管理

    • @google-cloud/cloud-sql-connector の活用

      • 概要: Cloud SQL Proxy の代わりに、 @google-cloud/cloud-sql-connector で proxy する方法です。詳しくは知らないので、気になる方は調べて下さい。

これらの選択肢の組み合わせによって設定方法が異なり、特にライブラリと認証方式の相性によって問題が発生することがあります。

動作した構成

最終的に動作した構成を共有します。

  • 接続方式: Cloud SQL Auth Proxy
    • Cloud Run : Cloud Run 設定で有効化
    • 作業マシン : cloud-sql-proxy コマンド
  • 認証方式: IAMデータベース認証

    • Cloud SQL : IAM認証を有効化
    • Cloud Run : 利用するサービスアカウントに roles/cloudsql.instanceUser 権限を付与
  • ネットワーク構成:

    • Cloud SQL  : Public IPを有効化

    • Cloud Run : 特別な設定なし
  • Cloud Runからの接続: 公式コネクタライブラリ (@google-cloud/cloud-sql-connector) をアプリケーションに組み込みます。

  • Next.jsからの接続:

ハマりポイント

  • Cloud SQL はマネージドサービスなので、GCPプロジェクト下にあるように見えて、実際はGoogleが管理するネットワーク下にあり、VPC Peering 設定をして VPC アクセスコネクタを作らないと、Private ネットワーク経由で Cloud Run から Cloud SQL に接続することは出来ません。これは、Cloud SQL Proxy を利用する場合にも同様です。(今回は Public IP を利用したので、この設定はしませんでしたが、Private ネットワーク経由での接続のほうが、よりセキュアです) 
  • Cloud SQL Proxy を利用するには、Cloud SQL側でIPアドレスが必要ですが、IPさえ発行されていればよく、承認済みネットワークの設定は不要です。
  • IAMグループ認証によって、グループ単位で認証が可能になりますが、接続時に利用するのは、個人のメールアドレスです。
  • Cloud SQL Proxy を利用する場合、Unix Socket 接続になります。アプリケーション側の設定で、TCP 接続を想定した記述になっていると接続できないので、注意してください。また、なぜか node-postgres 単体では接続ができず、 @google-cloud/cloud-sql-connector による補助的なクライアント設定が必要でした。
  • IAMグループ認証で追加されたユーザは、自動で cloudsqlsuperuser 権限が付与されるので、特別なことなどしなくとも、grant 文など発行できます。Cloud SQL で superuser 権限を持つユーザは作れません。

3.1. 本番環境 (Cloud Run)

terraform の google_cloud_run_v2_service リソースで Cloud SQL Auth Proxy を有効化できます。

resource "google_cloud_run_v2_service" "main" {
  ...
  template {
    # Cloud SQL Proxy volume
    volumes {
      name = "cloudsql"
      cloud_sql_instance {
        instances = ["<instance name>"]
      }
    }     containers {       ...
      # Cloud SQL Proxy volume mount
      volume_mounts {
        name       = "cloudsql"
        mount_path = "/cloudsql"
      }
   ...
}

3.2. ローカル開発環境

cloud-sql-proxy --auto-iam-authn <project>:<region>:<instance> --impersonate-service-account <service_account_email>

このように service account になりすまして、

psql "host=127.0.0.1 sslmode=disable dbname=<db_name> user=<service_account から gserviceaccount.com を削除したもの>"

のように接続できます。

Drizzle 設定

動作したコードだけ貼っておきます。

import { AuthTypes, Connector } from '@google-cloud/cloud-sql-connector';
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool, type PoolConfig } from 'pg';
import * as schema from './schema';

let client: Pool;

// see: https://github.com/drizzle-team/drizzle-orm/issues/4165
if (process.env.POSTGRES_INSTANCE_CONNECTION_NAME) {
  // Cloud Run
  const connector = new Connector();
  // @ts-ignore
  const clientOpts = await connector.getOptions({
    instanceConnectionName: process.env.POSTGRES_INSTANCE_CONNECTION_NAME,
    authType: AuthTypes.IAM,
  });
  const poolOptions: PoolConfig = {
    ...clientOpts,
    user: process.env.POSTGRES_USER,
    database: process.env.POSTGRES_DATABASE,
    max: 5,
    idleTimeoutMillis: 30000,
    connectionTimeoutMillis: 2000,
    ssl: false,
  };
  client = new Pool(poolOptions);
} else {
  // localhost
  const connectionString =
    process.env.DATABASE_URL || 'postgres://postgres:password@localhost:5432/db?sslmode=disable';
  client = new Pool({ connectionString });
}

export const db = drizzle(client, { schema });

export type Database = typeof db;

まとめ

Cloud Run + Cloud SQL なんて、枯れたパターンだと思っていたのですが、思いのほか大変でした。どなたかのお役に立てると幸いです。

参考情報

LOVOT QA効率化の話:シニア+ジュニア+AI最強説

こんにちは、junya です。前回に引き続き、QAツール開発の第3回をお届けします。

今回は、QAツール開発で、インターンの方とAI(主に Claude Code)を使って開発したら、生産性がバク上がりしたというお話です。

シニア+ジュニア+AI 最強説

はじめに結論から書きますが、シニア+ジュニア+AIは最強です。互いに相補的な関係があるからです。

  • シニア
    • 技術選定やアーキテクチャ設計
    • 難しめのタスクの実装
  • ジュニア
    • 仲間とコミュニケーションできる
    • 柔軟な動作確認など、AIにできないことができる
  • AI
    • 技術に詳しい
    • 実装が速い

これによって、シニアが1つの難しいタスクに取り組んでいる間に、ジュニア+AIで、平易だけど大切なタスクを5つ解決できます。そして、意外とこの「平易なタスク」の範囲は広く、要件や実装方針をシニアが明示できるものは、だいたいジュニア+AIで実装可能です。

では具体的に、QAツール開発プロジェクトで何が起きたか、順番に見ていきましょう。

関係者のご紹介

  • シニア わたし。業務プログラミング歴22年。3月からClaude Codeにどっぷりハマり、2週間でQAツールの基本機能を実装しました。
  • ジュニア 公的機関から出向のインターン生。社会人3年目。理系大学出身ですが、業務プログラミング経験はありません。数学オリンピック、謎解きが大好きで地頭が良い方です。
  • AI Claude Code を開発で利用しつつ、何でもまずは Gemini に聞いてみる、という使い方です。Claude Code は devcontainer で動かしていました。途中から Devin も活用しました。

1ヶ月間の成果

ジュニアのインターン生が来てから、1ヶ月間での彼女の成果はこちらです。

  • 期間: 22日間
  • PR: マージ済みPR 30個

実装機能:

  • UI/UX改善
    • 自動テスト関数引数の表示改善
    • 画面レイアウト調整(全幅利用、レスポンシブ表示等)
    • 入力欄の末尾空白除去
    • リロードボタン追加
    • 添付/キャプチャ画像のモーダル表示
    • ブラウザタブ用faviconアイコン作成
  • 機能追加・連携強化
    • Slack連携機能
    • スマホ画面Inspect機能
    • テスト対象機体の誤設定時の警告機能
    • LOVOTリモート接続機能
  • 自動テスト支援関数の実装
    • 画面一覧表示機能
    • モバイル操作(ページ遷移、クリック、スワイプ、要素検証など)

これらを、残業なし、他のタスクもやりながら達成しました。

なお、その間に私は、彼女からの質問に答えたり、PRを見てアドバイスをしたり、AIを活用するコツの情報交換などしながら、アプリケーションのElectron化や、添付ファイルの仕組み、Poco agent の nuitka ビルドなどを実装しました。

うまくいった秘訣

うまくいった秘訣がいくつかあるので、ご紹介します。

  • 新規の社内向けツール
    1つは、開発対象が新規の社内向けツールだったことです。新規ツールということで、平易だけど重要な、小さな開発要件がたくさんあり、AIコーディングにぴったりでした。また、社内向けツールということで、デザインや機能の自由度が高かったことも大きいです。

  • Devcontainer
    devcontainer の開発環境を用意しておいたのが便利でした。IDE(GoLand でしたが、VSCodeも可能)をインストールして Docker を入れれば、devcontainer の立ち上げだけで環境が出来上がります。セキュリティリスクも低いです。 今回の実習では、2日目の午前中には環境構築が完了し、2日目の午後から1つ目のタスクのペアワークができました。参考までに、利用した devcontainer 設定を共有します。Microsoft のベースイメージと、Claude Code の feature ファイルを利用するのがポイントです。

// .devcontainer/devcontainer.json
{
  // Dev Containerの表示名(例)
  "name": "TS/Go Claude Code Dev Container (GoLand)",

  // ベースとなるイメージ。Microsoft提供のUbuntu 24.04ベースイメージを使用。
  // デフォルトで 'vscode' ユーザー (UID/GID 1000) と基本的な開発ツールが含まれます。
  "image": "mcr.microsoft.com/vscode/devcontainers/base:ubuntu-24.04",

  // --- Dev Container Features: 追加のツールやランタイムを簡単に導入 ---
  "features": {
    // Claude Code 連携機能 (Anthropic 提供)
    "ghcr.io/anthropics/devcontainer-features/claude-code:latest": {},

    // Bun ランタイム (コミュニティ提供のfeatureを使用)
    "ghcr.io/prulloac/devcontainer-features/bun:latest": {
      "version": "latest" // または特定のバージョンを指定
    },
    // Go 言語環境
    "ghcr.io/devcontainers/features/go:1": {
      "version": "latest" // または特定のバージョンを指定
    },
    // Node.js 環境 (LTS版を推奨)
    "ghcr.io/devcontainers/features/node:1": {
      "version": "lts"
    },

    // --- 開発補助ツール ---
    // aqua: 開発ツールのバージョン管理
    "ghcr.io/aquaproj/devcontainer-features/aqua-installer:0.1.3": {
      "aqua_version": "v2.51.2" // 使用するaquaのバージョン
    },
    // direnv: ディレクトリごとの環境変数管理
    "ghcr.io/devcontainers-community/features/direnv": {},
    // GitHub CLI: GitHub操作の効率化
    "ghcr.io/devcontainers/features/github-cli:1": {},

    // 共通ユーティリティ (Zshの導入とデフォルト設定など)
    // ベースイメージの 'vscode' ユーザーが使用されるため、ユーザー作成関連の設定は基本的に不要です。
    // Git設定の継承など、便利な機能も含まれます。
    "ghcr.io/devcontainers/features/common-utils:2": {
      "installZsh": "true",                // Zshをインストール
      "configureZshAsDefaultShell": "true", // Zshをデフォルトシェルに設定
      "installOhMyZsh": "true",            // Oh My Zshをインストール (任意)
      "installOhMyZshConfig": "true",      // Oh My Zshの設定を導入 (任意)
      "upgradePackages": "false",          // コンテナビルド時のパッケージアップグレードはスキップ (任意)
      "configureGpg": "false"              // GPGキーの設定は行わない (任意)
    }
  },

  // ホストマシンのファイルをコンテナ内にマウントする設定
  "mounts": [
    // ホストの .gitconfig をコンテナ内の 'vscode' ユーザーのホームに読み取り専用でマウント
    // これにより、ホスト側のGitユーザー設定をコンテナ内で利用できます。
    // readonly設定は、コンテナ内からホストの設定ファイルを誤って変更しないために強く推奨されます。
    "type=bind,source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,readonly"

    // 他にもマウントしたいファイルやディレクトリがあればここに追加します。
    // 例: ホストのSSH鍵をコンテナにマウントして、プライベートリポジトリへのアクセスなどに使用する場合
    // "type=bind,source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,readonly"
  ],

  // 特定のネットワーク機能が必要な場合のDocker実行時引数 (例: Claude Codeの特定の機能やデバッグ時)
  // 通常はコメントアウトしておき、必要な場合のみ有効化します。
  // "runArgs": [
  //   "--cap-add=NET_ADMIN", // ネットワークインターフェースの管理権限
  //   "--cap-add=NET_RAW"    // RAWソケットへのアクセス許可
  // ],

  // コンテナ作成「後」に実行したいカスタムコマンド
  // 例: プロジェクト固有のセットアップスクリプトを実行
  "postCreateCommand": "chmod +x .devcontainer/setup.sh && .devcontainer/setup.sh",

  // コンテナ内で使用するユーザーの指定
  // この設定を省略すると、ベースイメージのデフォルトユーザー ('vscode') が自動的に使用されます。
  // "remoteUser": "vscode", // 明示的に指定することも可能です。

  // --- IDE固有のカスタマイズ設定 (ここではJetBrains GoLandの例) ---
  "customizations": {
    "jetbrains": {
      // GoLandがGo SDKを自動検出できない場合にパスを指定 (通常は自動検出されるため不要)
      // "goSdkPath": "/usr/local/go/bin/go"
      // GoLandにインストール推奨のプラグインリスト (例)
      "plugins": [
        "com.github.biomejs.intellijbiome",
        "com.github.copilot",
        "com.github.shiraji.findpullrequest",
        "com.intellij.tailwindcss",
        "intellij.nextjs",
        "intellij.vitejs",
        "org.toml.lang",
        "PythonCore" // Pythonサポートが必要な場合
      ]
    }
    // VSCode固有の設定は "vscode": { ... } のように記述します。
  },

  // --- コンテナ内の環境変数設定 (オプション) ---
  "containerEnv": {
    // Go Modules Proxyの設定 (Goプロジェクトで必要に応じて設定)
    "GOPROXY": "direct", // direct以外に、プロキシサーバーを指定することも可能
    // プライベートリポジトリへのアクセス設定 (自社のリポジトリなどに合わせて変更)
    "GOPRIVATE": "github.com/your-repo"
  }
}
#!/bin/bash
# .devcontainer/setup.sh
# 日本語ロケールのインストールと設定
sudo apt-get update
sudo apt-get install -y --no-install-recommends locales language-pack-ja
sudo locale-gen ja_JP.UTF-8
sudo update-locale LANG=ja_JP.UTF-8

# プロファイルにロケール設定を追加
echo 'export LANG=ja_JP.UTF-8' | sudo tee -a /etc/profile.d/locale.sh
echo 'export LC_ALL=ja_JP.UTF-8' | sudo tee -a /etc/profile.d/locale.sh

## Claudeファイアウォール初期化
#sudo /usr/local/bin/init-firewall.sh

# aquaのパスを各シェルの設定ファイルに追加
echo 'export PATH="/home/vscode/.local/share/aquaproj-aqua/bin:$PATH"' >> ~/.bashrc
echo 'export PATH="/home/vscode/.local/share/aquaproj-aqua/bin:$PATH"' >> ~/.zshrc
  • Claude Code の使い方
    普段の実装も、基本、このやり方で実装しています。

    1. Claude と壁打ちして、実装方針を決める(コードはまだ書かせない)
    2. 実装方針をチェックリストとともに、Markdownに書かせる
    3. それを元にClaudeのコードを書かせる

    コードの配置や利用ライブラリなど、提出されたコードがシニアの実装意図と異なる場合は、シニアからジュニアに、PRや口頭やチャットでフィードバックしました。

  • ステップに分解する

    • スマホのスナップショットをPocoでキャプチャして、
    • Poco agent が仲介し、
    • TypeScript で受け取って画面に表示

    というような、やや複雑なタスクの場合、

    • まずは、スマホのスクリーンショットだけを取得してファイル保存するスクリプトをClaudeに実装させて
    • 次に、APIを叩いてスクショ撮るスクリプト書かせて

    などと段階を踏んでAIに実装をさせるといいよ、とアドバイスしました。ステップを踏めば、どこで躓いたかがわかり、ジュニアでも自身で問題解決できます。

  • 検証用スクリプトを書く
    前項の「ステップに分解する」と関係しますが、いきなり機能をアプリケーションに組み込むのではなく、「スクショを撮るスクリプト」のような単体スクリプトやテストをAIに書かせると、実装がスムーズになりました。

  • 難しいものは巻き取る
    どうしても難しそうなものは、巻き取ったり、保留したりしました。今回の場合、録画機能は実装に詰まったので、深追いせずに保留して他のものを進めてもらいました。後で自分の方で対応します。

  • 困ったときはペアワーク
    ジュニアがAIとの対話で行き詰まったり、より複雑な実装の理解が必要な際には、シニアとジュニアでペアワークを行い、一緒に問題解決や仕上げを行いました。これにより、知識移転もスムーズに進みました。

  • スタイリングはAIに任せる
    社内ツールということもあり、スタイリング(Tailwind CSS)は、はじめの大枠だけ整備して、あとは原則としてレビュー対象とせず、AIの実装をそのまま信じると割り切りました。

  • うまくいかないときはゼロからやり直す
    試行錯誤を進めると、Claude が堂々巡りしてしまうことがあります。そういうときは、一度それを捨てて、改めて必要な条件を伝えて実装方針を作り直し、コードを一から書き直させていました。これ結構、大切です。

まとめ

以上、シニア+ジュニア+AIで生産性が非常に高くなった事例をご紹介しました。 AIの足りないところを人間が補い、技術面をAIが担当し、難しい部分をシニアが巻き取ることで、相補的に生産性を上げることができます。

いろいろチャレンジしていて楽しい職場なので、よかったら開発チームに参加しませんか?

学生さん向けには、サマーインターンシップも開催しますので、是非ご応募ください。

tech.groove-x.com

GROOVE X のサマーインターンシップで LOVOT の開発に携わってみませんか

概要

こんにちは。ソフトウェアエンジニアの id:iizukak です。

GROOVE X では今年からサマーインターンシップの形式でインターン生の一括募集を行うことにしました!

今までも、参加されたインターン生の新鮮なアイディアに社員が影響されたり、独自性の高い成果が出たりと、インターン生による良い影響が多くありました。現在、GROOVE X では AI を活用した開発を推し進めている最中であり、AI の支援によってインターン生が活躍していただける機会はどんどん増加していると感じています。

また、GROOVE X では、OS レイヤーからクラウドレイヤーまで、多様なエンジニアが密に連携を行って LOVOT を作っています。日常の仕事の中で、これほど多様なエンジニアと交流できる会社はそれほど多くないかもしれません。

興味を持たれた方は以下の求人票をチェックしてみてください!

↓↓↓

インターンシップ 求人一覧 | GROOVE X株式会社

↑↑↑

プロジェクト一覧

サマーインターンシップでは、以下にリストするプロジェクトに取り組んでいただきます。興味のあるプロジェクトがありましたら、ぜひリンク先で詳細をご覧ください。

AI技術を活用したテクニカルサポートシステムの開発

AI技術を活用した、新しいテクニカルサポート用の支援システムを開発していただきます。

LOVOTのテクニカルサポートでは、お問い合わせ内容、検査結果、ログ、メトリクスなどの様々なデータを用いて、トラブルの原因を探ります。 本テーマでは、今まで分散していた各種データを一箇所に集約して表示し、さらにAIによって得られた示唆を表示したり、ユーザがAIとの対話で新しい示唆を得られることを目標とします。

AI技術を活用したテクニカルサポートシステムの開発(本社)の採用情報 | GROOVE X株式会社

画像認識モデルの精度評価とエッジデバイス上での推論速度評価

LOVOTに搭載する機械学習モデルを評価していただきます。 LOVOT 上では機械学習を利用した様々な画像認識モデルが動作しています。 本テーマでは、物体検出および顔識別をターゲットタスクとして、様々なモデルの精度と、LOVOT に搭載されている Jetson 上での推論速度を評価します。

具体的には以下のような仕事が含まれる想定です。

  • エッジデバイスにデプロイ可能なモデルの調査
  • LOVOT で撮影した画像による精度評価
  • TensorRT への変換プログラムの実装
  • Jetson 上での推論速度評価

画像認識モデルの精度評価とエッジデバイス上での推論速度評価(本社)の採用情報 | GROOVE X株式会社

Development of Robotics Localization System

This role is centered on optimizing the localization and mapping system for LOVOT and developing essential monitoring tools to track its performance. LOVOT perceives its environment using a variety of sensors, with cameras providing rich data for understanding surrounding space and people. Operating within diverse home environments presents unique challenges, making the continuous enhancement of LOVOT's spatial awareness, navigation accuracy, and overall performance critically important. In this theme, you will build and demonstrate software to improve LOVOT's localization system, or evaluate the system, on the following topics: Develop a "ground truth" data collection system to compare LOVOT's localization with actual measurements. Implement image recognition to identify moving objects and furniture and mark these items on the map. Implement a Visual Place Recognition task based on neural networks. Optimize LOVOT Visual SLAM.

Development of Robotics Localization System(本社)の採用情報 | GROOVE X株式会社

強化学習によるLOVOTの移動能力の向上

強化学習を用いて、LOVOTの移動能力の向上に取り組んでいただきます。 LOVOTは家庭環境という多種多様な環境で転倒することなく、かつ生物らしい特性を持った動作をし続ける必要があります。 本テーマでは、移動性能にフォーカスして、多種多様な環境に適用させていくために、強化学習を使って、以下のような内容に挑戦していただきます。

  • 移動中に発生する障害物との衝突によってバランスを崩さないような方策を学習すること
  • 他のLOVOTや人から押されたときや、不安定な足場に置かれたときに転倒しないための方策を学習すること
  • 移動の機能上の要求を達成するだけではない生物らしい性質を持った動作を、教師データを元に学習すること

応募要件

応募要件はそれぞれのプロジェクトごとに異なるため、プロジェクトごとの求人票をご参照ください。共通した要件として、

2027年に卒業予定である学生、大学院後期課程に在籍されている方

という学年の制約があるので、ご留意ください。

最後に

GROOVE X で、LOVOT というユニークな家庭用ロボティクスの開発に参加してみませんか? きっと興味深い体験になると思います!

↓↓↓

インターンシップ 求人一覧 | GROOVE X株式会社

↑↑↑

LOVOTech Night 2025春開催報告

こんにちは。ソフトウェアエンジニアの id:iizukak です。

GROOVE X では、LOVOTech Night という技術イベントを定期的に開催しています。先日 "LOVOTech Night 2025春: 春の技術祭り" を開催しましたので、報告させていただきます。

開催概要

今回も、オンサイト約 30 名、オンライン約 60 名の大勢の方にご参加いただけました。LOVOT の開発に関する技術にご興味を持っていただける方が、これほど多くいらっしゃることに感動しました。ご参加された皆様、本当にありがとうございました!

今回はソフトウェア開発を中心に、6 件の発表がありました。

発表

GROOVE Xにおける生成AI活用事例

GROOVE X きっての AI 活用者である林さんの、生成AI活用事例について発表です。GROOVE X にも、AI の活用の波は押し寄せています。社内アンケートの結果でも、既に開発に大活躍しており、AI に合わせた業務フローの変更も視野に入れているとのことです。

また、生成 AI を活用することで、インターン生でもハイアウトプットを達成できているとのことでした!

Google Colab + Driveで100GB↑のデータ学習を動かそうとしたら…

GROOVE X の音声エンジニアといえばの遠藤さんが、Google Colab + Driveで100GB↑のデータ学習を動かそうとしたら…の話をしてくれました。

Google Colabは比較的安価に学習が行えるということで利用しているが、大規模なデータセットの利用に課題があるとのことです。そこを Google Drive API を工夫して利用することで、解決したそうです。世間的にも最近は Colab で大規模なモデル学習を行うことも多いと思うので、活用できそうな内容でした。

クラウド+ミドルウェアの話

LOVOT のソフトウェア開発の要、KIBAN チームの id:atotto さんが、LOVOT 3.0 のクラウド開発とミドルウェア開発の類似点等について発表してくれました。"LOVOTをささえる基盤はあちこちにあり" ということで、LOVOT 内部からクラウドまで様々な基盤技術に支えられているということが分かりました。

gRPC も活用されているそうです。

OSビルドが3倍早くなった話

LOVOT たちのオペレーティングシステムの面倒を見てくれている、 LOVOT Framework チームの bucchi さんが、OSビルドが3倍早くなった話を発表してくれました。

LOVOT 3.0 では、2.0 と比べて OS のビルドが低速になっていたそうなのですが、ビルドに利用するクラウドのインスタンスを最適なものを選ぶことで高速化を達成したそうです。よりスピーディーな開発で LOVOT にアップデートをお届けできると思うと、素晴らしい成果ですね。

視覚言語モデル BLIP の量子化と性能評価

LOVOT 上で動作する画像認識開発をしているスマラボチームの id:iizukak が、視覚言語モデルの量子化のお話をしました。LOVOT のような計算資源が限られている環境で、言語モデルを動かすための工夫について、皆さんに知っていただければと思いました。

今後 LOVOT に量子化した機械学習モデルがどんどん搭載されていくことで、LOVOT たちの認識がますます賢くなると思うとワクワクしますね!

LOVOT が置かれた状況を LLM に説明させてみた話

GROOVE X で小型 LLM を最も深堀りしている、ふるまいチームのエンジニア橋本さんが、LOVOT 上で LLM を動かし、状況を説明させるための工夫について発表してくれました。LLM への入力フォーマットの工夫や、ファインチューニングなどを駆使して、LOVOT がどのような状況に置かれているのかアウトプットさせてみるという発表でした。お~そんなことも分かるのか~と驚きがありました。

サマーインターンシップのお知らせ

GROOVE X 人事チームより、サマーインターンシップの募集に関するお知らせがありました。今年から、GROOVE X でも学生を対象としたサマーインターンシップを実施します!

興味のあるかたはぜひ↓をチェックしてみてください。

インターンシップ 求人一覧 | GROOVE X株式会社

懇親会

発表のあとは、懇親会を開催しました。懇親会では多くの皆さまと交流が持て、大変楽しく有意義な時間を過ごせました。

乾杯の様子。楽しそうですね。

美味しいお料理も出ました。

筆者感想

OS のビルドから機械学習・クラウドまで、幅広い技術によって LOVOT の開発が支えられていることを再認識できました。日々の業務で、自然と多様な領域のエンジニアと関わることになるのも、GROOVE X で働く魅力のひとつかもしれません。

GROOVE X では、エンジニア採用を実施しています。LOVOT の開発に興味を持たれた方、LOVOTech Night に参加された方もそうでない方も、ぜひ求人票をチェックしてみてください↓

採用情報 | GROOVE X株式会社

前回の LOVOTech Night のブログ記事もこちらにあります↓

LOVOTech Night 2024 開催報告!! - Inside of LOVOT

(LOVOT も発表を聞いていたようです)

LOVOT QA効率化の話:LOVOT QA App のアーキテクチャ

はじめに

こんにちは。junya です。昨日の LOVOTech Night での登壇を終え、肩の荷がおりたところです。 さて、今日は QA 効率化の話の第2弾、LOVOT QA App のアーキテクチャおよび、主要機能についてご紹介したいと思います。

我ながら、なかなか良くできた仕組みだと思うので、よかったら読んでやってください。 前回ご紹介した「セミオートメーション」の詳細となります。

LOVOT QA App のアーキテクチャ

まずはじめに、LOVOT QA App のアーキテクチャについてご説明します。

LOVOT QA App は、Qase をバックエンドとして Qase API を利用し、Qase のテストラン機能*1だけを抽出した、セミオートメーションのQAツールです。

テストの実行画面を抽出しただけだと、そのまま Qase を利用するのと比べてなんのメリットがあるのかわからなそうですが、テスト実行ツールを LOVOT 本体やスマートフォンと接続することで、テスト項目の一部を自動化することができるのが利点です。

LOVOT QA App の3つの使い方

前節の図にもあるように、LOVOT QA App は以下の3種類の方法で利用できます。

  • デスクトップアプリ
  • デスクトップアプリ + Poco Agent
  • 実機内で動作するデーモン

デスクトップアプリ

作業者のPC上でデスクトップアプリ(Electron)として動かす方法です。 LOVOT に対してリモート接続してテストを実行したり、後述する Poco Agent との連携で便利です。

デスクトップアプリ + Poco Agent

LOVOT QA App の横で、スマートフォンへのアクセスをブリッジする Poco Agent*2 を動かすことで、LOVOT QA App からスマートフォンを制御できます。

手動試験のときと比べて、

  • 試験中のアプリのスクリーンショットをワンクリックで記録できる
  • 自動でアプリ要素の検証テストができる

などのメリットがあります。

実機内で動作するデーモン

debian パッケージを実機に転送して実行し、ブラウザからポートにアクセスすることで、テストを実行します。 LOVOT QA App の自動試験において、LOVOT QA App から直接機体を操作できるので、効率的・安定的に自動テストを実行することができます。

LOVOT QA App の自動テストの仕組みについて

LOVOT QA App では、Qase のテストステップ(テストケースを構成する要素)のタイトル名に、一定のルールで関数名を組み込むことで、テストステップに自動テストを紐付けることができます。 例えば、このような感じです。

関数名 テストステップ記述例
Clickbutton [AUTO:ClickButton(HomeButton)] ホームボタンをクリック
GetDatabaseValue [AUTO:GetDatabaseValue(identity)] identity 値を取得

内部的には TypeScript で AutoFunctionRegistry に関数を紐付けて管理しています。自動テスト関数には「モバイル用」「LOVOT本体用」「LOVOTリモート接続用」「クラウド操作用」の4種類のカテゴリを用意しています。

合わせて、LOVOT QA App の画面では、自動関数を利用しやすいように以下の機能や画面を提供しています。

  • テスト自動実行: テスト実行画面において、ボタン1つで関連する処理を自動実行する、メイン機能
  • 自動テストの一覧画面: 登録されている自動テスト関数の一覧を閲覧し、テスト実行できる画面
  • 設定画面: テスト実行対象のスマートフォンやLOVOTを設定・接続する画面

その他の便利な機能

以上に加え、以下のような便利機能を実装しました。

  • プレビュー画面: モバイルアプリの画面を表示し、UI要素を確認できます。
  • ファイル添付: 任意のファイルをテスト結果に添付できます。
  • スクショ: モバイルアプリのスクショをワンクリックでテスト結果に添付できます。
  • Slack連携: Slack のスレッドを設定することで、テスト結果をSlackスレに送信できます。
  • 整合性チェック: テストランに紐づくタグをもとに、接続デバイスの整合性を確認します。
    • 例: LOVOT 3.0 を対象とした試験を、LOVOT 3.0 に対して行っているかを確認

まとめと今後の展望

本記事では、LOVOT QA App の提供するセミオートメーション機能について説明しました。 セミオートメーションは、単なる中途半端な自動化ではなく、以下の様なメリットがあります。

  • 試験の効率化: 手動で行うと複雑な処理をワンクリックで効率的に実行できます。デバイスの識別子やバージョンを自動連携できるので、転記ミスが減り、工数も削減できます。
  • 段階的な自動化: 手動テストを段階的に自動化できます。
  • 粒度の小さな自動化: 1つ1つの自動化要素をメンテナンス・再利用しやすい小さな粒度に保つことができます。
  • 柔軟な運用: 接続が不安定な際のリトライ処理など、イレギュラー発生時にもユーザが柔軟に対応できます。
  • 様々なテスト対象への応用 : LOVOT やスマホなど、様々なテスト対象に対して、共通の枠組みでテストの自動化を進められます。
  • 手動実行のサポート: 困ったときは手動試験にフォールバックできます。

また、テストケース自体の管理を Qase のようなテスト管理サービスに委ねることで、「テスト実行」だけにフォーカスして機能を実装することができました。

このような仕組みは、LOVOTのような複雑な製品の試験における現実的な解ではないかと思います。

同じような課題に取り組んでいる方がいましたら、ぜひご意見ご感想をお聞かせください。 次回は、LOVOT QA App の開発において、どのようにAIを活用したか、ご紹介したいと思います。

*1:試験対象のテストケースを集めたテストセットに対して、テストを実行する機能

*2:pocoui を gRPC のサービスでラップして、TypeScript から呼び出せる仕組みを実装しました

【LOVOTech Night 2025春: 春の技術祭り】開催のお知らせ

こんにちは、SWチーム・エンジニアのaoikeです。

昨年の開催に引き続き、エンジニアの方向けにLOVOT内部のトークを聞けたり、GROOVE X エンジニアとの交流ができるイベントを開催します!

昨年の開催の様子を知りたい方は是非開催レポートをご覧になってください。

今回の記事は、開催にあたって内容をご紹介します!

テーマ

私たちGROOVE Xは、次のMISSION, VISIONを掲げて、家族型ロボット「LOVOT(らぼっと)」の開発をはじめ、機械学習やAI、クラウド、アプリケーションなど、幅広いソフトウェア技術の開発に取り組んでいます。

MISSION: ロボティクスで、人間のちからを引き出す

VISION: 人間とロボットの信頼関係を築き、生活を潤いと安心で満たす存在をつくる

私たちは、GROOVE Xのビジョンに共感し、LOVOTをさらに進化させるために、機械学習・AI・アプリ開発・クラウドインフラなど、あらゆる分野で挑戦してくれるソフトウェアエンジニアを募集しています。

このイベントでは、日頃からLOVOTの開発に携わるエンジニアたちが登壇し、生活に寄り添うプロダクトをどのような技術で実現しているのか、実際の開発事例を交えてお話しします。

開催概要

オフライン

日時: 2025年05月21日 水曜日 19時00分~21時30分ごろ(開場:18時30分)
場所: GROOVE X 本社 住友不動産浜町ビル7階

オンライン

日時: 2025年05月21日 水曜日 19時00分~20時30分ごろ youtube (参加者にのみ提示)

タイムテーブル

トーク予定の紹介

●GROOVE Xにおける生成AI活用事例●
発表者:林 淳哉
GROOVE Xでは生成AIをどのように活用しているのか、事例を交えてご紹介します。

●Google Colab + Driveで100GB↑のデータ学習を動かそうとしたら…●
発表者:sutetako
Google Colabでモデル学習する際、データセットのコピーは切り離せませんよね?100GB超えデータを Google Drive からコピーしようとした際に起きたことと、どう対応したかのお話です。

●クラウド+ミドルウェアの話●
発表者:atotto
LOVOTのミドルウェア開発とクラウドの開発の紹介と、その先の基盤開発についてお話します。

●OSビルドが3倍早くなった話●
発表者:bucchi
LOVOTのOSのビルドの概要を説明しつつ、ボトルネックを解消してビルド時間を1/3に短縮したお話をします。

●視覚言語モデル BLIP の量子化と性能評価●
発表者:iizukak
ローカル環境でLLM/VLMを実行するために、ニューラルネットワーク量子化技術は重要です。今回の発表では、BLIPというVLMを量子化したときの計算リソースのと実行速度の変化を計測した結果を報告します🤗

●LOVOT が置かれた状況を LLM に説明させてみた話●
発表者:橋本 大世
LOVOT の機体上で LLM を動かし、周囲の状況を説明させる試みをご紹介します。多様な認識情報を LLM にどう入力するか、またファインチューニングで精度を改善した点などについてお話しします。

さいごに

皆様のご来場・ご参加、お待ちしています! 申し込みはコチラから。

LOVOT QA効率化の話:半自動テストのススメ

はじめに

こんにちは。昨年秋からQAチームでQA効率化に取り組んでいる junya です。 半年ほどQA効率化に取り組んできたのですが、最近ブレイクスルーがあったのでご紹介します。

  • LOVOT QA効率化の話:半自動テストのすすめ
  • LOVOT QA Appのアーキテクチャ(仮)
  • AIと共に加速するLOVOT QA App開発(仮)

全3回でお届け予定ですが、1本目の今回は、ブレイクスルーまでの道のりをご紹介します。

LOVOT のソフトウェア QA における課題

LOVOTには数十のセンサーと十数自由度の可動部があり、独自OS上で認識・ふるまいなどの複数のソフトウェアコンポーネントが動作しています。それらの各レイヤーのQAをしているわけですが、特にふるまいにおいては、「LOVOTが人と目を合わせてくれるか」といった、人の目で確認しなければ判断しづらいテスト項目がたくさんあります(詳しくは、以下の記事をご覧ください)。また、LOVOTを充電するネストや、LOVOTと通信するスマートフォンアプリのQAもあります。

tech.groove-x.com

tech.groove-x.com

これらのテストは複雑で、新しいソフトウェアをリリースする際のQA工程が、開発の足かせになっていました。

QAにおける3つのテストアプローチ

はじめに結論から書きますが、私たちのQA効率化のキーは「半自動テスト」でした。 以下、手動テスト・自動テスト・半自動テストを比較します。

手動テスト

テスト項目をスプレッドシートなどで管理し、様々な条件下でのLOVOTのふるまいを手動および目視で確認する方法です。 LOVOT のソフトウェアリリース前のテストでは、人の目でなければ確認しにくい部分が多く、手動で確認しています。 テスト項目を一つひとつ手動で実行するため、どうしても時間がかかってしまいます。

自動テスト

ソフトウェアの単体テストや結合テストの多くは、テストコードによって自動化していますが、ここではそれとは別に、LOVOTの完成品に対して行われる end-to-end (e2e) のテストを自動テストと呼ぶこととします。

「QA効率化」を考えた時に、真っ先に取り組んだのは、「既存の手動テストの自動化」でした。 自動テストが確立し、安定して実行できればQA工程は効率化されます。

しかし実際には、「自動テスト自体の開発・維持コスト」という課題が常に伴います。また、テストが失敗した際に、その原因がテスト対象の不具合なのか、テストコード自体の問題なのかの切り分けが難しい場合もあります。

半自動テスト

テスト項目を一つ一つ実行するプロセスは手動で行いつつ、その中で自動実行できる特定の操作(例:データ取得、環境設定など)についてはプログラムの支援を得るテスト方法です。 自動実行の部分は、個別のコマンドやスクリプトによる自動化も考えられますが、QAツールにその機能が統合されていれば、テスト担当者はワンクリックで適切な自動処理を呼び出せます。

半自動テストは、完全自動テストと比較して、自動化のロジックを小さく保ち、再利用しやすくできるというメリットがあります。これは手動テストと自動テストのハイブリッドと言えますが、単に「テストの一部を自動化する」という以上に、「人間の判断が不可欠な箇所」と「機械的に処理できる箇所」を戦略的に分離し、それらをテスト実行ツールを通じてスムーズに連携させる点が重要です。このアプローチにより、テスト全体の効率と品質のバランスを取ることが可能になります。

今回、この「半自動テスト」の考え方と、それを支援するツールを整備することで、LOVOTのQA工数を大幅に削減することができました。

(参考:Semi-Automated Testing - TestMatick

QA効率化の道のり

Try1: 手動テストの自動化

はじめに取り組んだのは、既存のe2eテストのリファクタリングと、自動テストカバレッジの拡充です。 手動テスト・自動テスト(e2e)両方の結果を Qase (テスト管理システム)に集約することを目標とし、Go言語やPythonで LOVOT の e2e テストを実行するためのフレームワークを実装しました。

その際に実装した特徴的な機能の一つが、LOVOT のセンサー入力をシミュレーションする仕組みです(私たちは「水槽の中の脳」と呼んでいました)。 例えば、あらかじめ、「抱っこ」したときのセンサー情報を記録しておき、それを再生しながら自動テストを実行することで、実際にLOVOTを抱っこしなくても、抱っこ時のテストができます。

@qase.id(222)
@pytest.mark.parametrize(
    "mcap_file, expected_behavior",
    [
        ("happy_cat.mcap", "HappyCatArrival"),
        ("wobbly_cat.mcap", "WobblyCatSafe"),
    ],
)
async def test_cat_teleportation_scenario(
    overwrite_input, # このfixtureによって、parameterizeのmcapファイルでセンサ入力を上書き
    mcap_file: str,
    expected_behavior: str,
):
    """
    物質転送装置を使って、ネコがご機嫌かつ安全に転送されるかテスト。
    指定されたmcapファイルでセンサー情報を再生し、期待されるビヘイビアが発動するか確認します。
    """
    print(f"\n--- ネコ転送テスト開始! シナリオ: {mcap_file} ---")
    current_behavior = "不明な状態"

    with trio.move_on_after(30):
        while True:
            current_behavior = await get_current_behavior()
            print(f"現在の様子: {current_behavior}")
            if current_behavior == expected_behavior:
                print(f"成功!期待通り「{expected_behavior}」を確認しました!")
                return
            await trio.sleep(0.5)

    assert False, f"失敗…期待「{expected_behavior}」に対し、結果「{current_behavior}」でした。"

これは一見理想的ですが、

  • データの作成に手間がかかる
  • データの妥当性確認が難しい
  • 苦労してデータを作成しても、LOVOTの仕様が変わると、また一からデータを取り直す必要がある
  • そもそも個々のテストの自動化が困難(例えば、どうやって「LOVOTが見つめてくれる」ことを自動テストで判定するのか? その判定ロジックの作り込みは現実的か?)

といった課題があり、個々の技術的知見は価値があるものの、QA効率化の主要な手段としては適切でないと判断しました。

Try2: 半自動テストの記述(テスト実行支援ツールの試作)

次に取り組んだのは、 TypeScript と Next.js を用いたフロントエンド実装による、半自動テストの記述です。 Qase には、API や SDK を介してテストケースを登録し、テスト結果を記録する機能がある点に注目しました。

以下のように TypeScript でテストケースを記述します。

{
  "id": 101,
  "categoryId": 20,
  "name": "最重要!ネコ転送テスト - モフモフは無事に転送されるか?",
  "status": "Active",
  "description": "吾輩たちにとって、一番大事なお客様である生き物(ネコ)を、あんしん安全に転送できるか確かめるテスト。",
  "preconditions": [
    "物質転送装置の全システムが正常にオンラインであること。",
  ],
  "postconditions": [
    "ネコ様がターゲット座標に寸分の狂いもなく、穏やかな表情で転送されていること。",
  ],
  "steps": [
    {
      "id": 1,
      "action": "ネコを転送チャンバーへ案内",
      "expected_result": "ネコがチャンバー内でリラックス"
    },
    {
      "id": 2,
      "action": "転送シーケンス「にゃんともワープ」を開始",
      "expected_result": "全パラメータが許容範囲内"
    },
    {
      "id": 3,
      "action": "[AUTO:VerifyIntegrity()] 自動検証",
      "expected_result": "質量差は許容範囲内、残留物質なし。"
    }
  ]
}

このアプローチでは、TypeScript のコード内に各テスト項目が記述されていて、それらがGUI上に表示され、各テスト項目を手動または一部自動で実行することができます。

これにより、例えば、

  • 機体のバージョン情報を取得する
  • データベースから特定の値を取得する

といった定型的な操作をテストの途中で自動化し、効率化を図ることができました。 (試作段階で Try3 へと移行したため、実運用はしていません)

Try3: Qase をバックエンドとし、フロントエンドのみを実装(LOVOT QA Appの実装)

Try2 の半自動テストの仕組みは一見良さそうでしたが、今度は「テストケースの二重管理」という問題が顕在化しました。 TypeScript 上に記述されたテストケースは、テストを実行すると Qase に同期される仕組みでした。

この場合のマスターデータはテストコード側にあるため、テストコード上でテストケースのタイトルを変更すると、Qase上でもそれに追従してタイトルが変更されます。しかし、Qase 上でテストケースを直接参照・編集する機会が増えるにつれ、「テストケースの管理はQaseで行う方が、TypeScriptで記述するよりも便利ではないか」という気づきがありました。

そこで、アーキテクチャを逆転させました。

  • テストケースのマスターデータは Qase
  • テスト実行のフロントエンドは、Next.js で開発したカスタムアプリケーション(LOVOT QA App

というアプローチです。

LOVOT QA App 画面

これにより、テストケースを追加・編集するために QA アプリのコードを修正する必要はなくなり、QA 実行のプラットフォームは汎用的なGUIアプリケーションとして進化しました。 自動テストのトリガーは、テストケースやテストステップのタイトルに特定の命名規則(例: 「[AUTO:GetDeviceInfo()] デバイス情報を取得」)を設けることで実現し、LOVOT QA App側で対応する関数(この例では GetDeviceInfo())が呼び出されるようにしました。

まとめ

本記事では、LOVOTのような複雑なデバイスのテストにおいて、半自動テストが有効であることを、私たちの試行錯誤の道のりと共にご紹介しました。 ここでは詳細を割愛しますが、テストの自動化・半自動化と並行してテスト管理ツールの選定も進めており、今回のようなユースケースにおいて、API が充実している Qase は非常に相性が良く、結果としてQaseを選んでおいて良かったと感じています。

次回は、今回作成した LOVOT QA App のアーキテクチャや、その応用可能性について詳しくご紹介したいと思います。 お楽しみに。