Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキゲームスが運営しています。

Redashで見栄えを良くしよう

この記事は Akatsuki Games Advent Calendar 2025 16日目の記事です。

はじめに

サーバエンジニアの井出です。今年新卒で入社して、主に新規機能開発を行っています。また自分自身のサブタスクとして、チームのデータ分析も行っています。本日は自分がデータ分析のタスクの中で、「これ良いTipsだな」って思ったことを書かせていただきます!

注意書き

本記事では、実際にタスクを進める中で学んだ事を記事にしています。そのため、一部内容を変更している箇所があります。伝えたい内容に影響はないのでご了承ください...。

概要

データ分析のタスクは、年間の売上分析、使用キャラランキングから、お問い合わせ対応時の調査まで、多岐にわたります。これらの多様なデータ分析タスクに対応するため、エンジニアやプランナーなど職種を問わず誰でもデータにアクセスし、クエリを叩いて調査できるようにする環境を整えられるよう、BIツールとしてRedashを導入しています。

Redashとは

Redashとは、ブラウザ上でSQLなどのクエリを実行し、結果をグラフや表として可視化できるオープンソースのBI(ビジネスインテリジェンス)ツールです。

ある日...

分析タスクとして「あるプレイヤーの戦闘ログから、どのキャラクターがどのスキルを使用したかを調べてほしい」という依頼が来ました。

そのため、BigQueryで以下のようなクエリを作成して調査を始めました(内容は少し省略しています)。

SELECT
  player_id,
  skills,
  timestamp
FROM
  <戦闘ログのテーブル>
WHERE
  player_id = <player_id>
ORDER BY
  timestamp DESC

実際に上記クエリを実行すると、以下のような実行結果を得られました。

上記の結果から、「最近の戦闘で、キャラクターIDが2351のキャラクターは200331000のスキルを発動した/キャラクターIDが7128のキャラクターは200469000,200183000のスキルを発動した...」などのことがわかります。

Redash上でクエリ作成して実行した結果

上記のクエリをRedashで作成し、実行すると以下のようになってしまいます。

skillsカラムのフィールド情報が崩れてしまっています。 これでは「skillsカラムが何を表しているのか」がぱっと見で分からない状態です。

原因調査

なぜ崩れてしまったか調べていると、公式ドキュメントの[Table Visualization Options] → [Formatting Columns]で以下のように説明がありました。

Redash is sensitive to the data types that are common to most databases: text, numbers, dates and booleans. But it also has special support for non-standard column types like JSON documents, images, and links.

上記の文章から、Redashは、データベースから返ってくる型情報をそのまま表示させるが、型が不明確なRECORD型は「とりあえずテキスト」として扱われてしまいそうな事が分かりました。

そのため、skillsカラムのフィールド情報を綺麗に表示するには、RECORD型をそのまま出力するSQLを書くのではなく、SQL内でRECORD型の中身を展開する必要があります。

「なんかうまく表示できるような展開方法ないかなぁ〜」ってRedash設定を色々見ていたら、カラムの出力設定に以下のような記述があり、カラム毎にHTMLコンテキストを埋め込めそうな雰囲気があります。

HTML埋め込んでみる

この機能をskillsカラムに応用して、見やすい形式にしたクエリが以下です。

SELECT
  player_id,
  '<ul>' || (
    SELECT
      ARRAY_TO_STRING(
        ARRAY(
          SELECT 
            '<li>Character ID: ' || CAST(s.character_id AS STRING) || 
            ' / Skills: ' || 
            (SELECT ARRAY_TO_STRING(ARRAY(SELECT CAST(id AS STRING) FROM UNNEST(s.ability_ids) AS id), ', ')) || 
            '</li>'
          FROM UNNEST(skills) AS s
        ), 
        ''
      )
  ) || '</ul>' AS skills,
  timestamp
FROM
  <戦闘ログのテーブル>
WHERE
  player_id = <player_id>
ORDER BY
  timestamp DESC

Redashで上記を実行すると、以下のように出力されます。

無事HTMLを埋め込む事ができました! 最初の出力結果と見比べると、断然見やすく、分かりやすくなっていると思います!

最後に

今回はRedashで出力カラムを見やすくする方法を解説しました。
普段Redashでは「誰が見ても分かりやすい状態を作る/誰でも触れるような状態を作る」という事を心掛けてクエリを作成しています。

こういった、誰かを思いやるような「気づき」の精神は会社全体の様々な場所で見受けられます。
例えば、過去に作成された莫大な量の仕様書を、AI活用して誰でもすぐ見つけられるようにする、データ入稿を一部自動化して工数を削減する、データ入稿に間違いがないか差分を正確にチェックするツールを作るなど、様々な工夫がなされています。

このような精神をこれからも大事にして仕事をしていければと思っています!

免責事項

掲載している情報の正確性には細心の注意を払っておりますが、執筆時点(2025年)の情報であり、今後のツール(Redash/BigQuery等)のアップデートにより仕様が変更される可能性があります 。

Unity を用いた開発で発見しづらい場所に溜まっていた不要データの大掃除

この記事は Akatsuki Games Advent Calendar 2025 - Adventar 17日目の記事です。

  • はじめに
  • 概要
  • 事例紹介
    • 事例1: YAML に忍びこむ合計600万文字のテキストを除去!🧹
      • 問題発見
      • 原因
      • 対処
      • 結果
    • 事例2: ゲームに影響を与えずにVFXのデータを2000万行削減!✨
      • 問題発見
      • 原因
      • 対処
      • 結果
  • おわりに

はじめに

クライアントエンジニアの渡邊です。新卒で入社して4年目で、主にゲームの新規機能開発と運用向けの内部ツール等を開発しています!

概要

ゲームの見た目、面白さ、演出、UI などさまざまな用途で用いられるアセットですが、開発中、様々な要因で不要なデータが知らず知らずのうちに蓄積していきます。例えば、ゲームの要件・仕様変更に伴って使わなくなったデータをエンジニアが削除し忘れる、アセットを作成してくださるアーティストさんそれぞれの経験値・制作手順の微妙な違いで不要なデータが生じてしまうといった人的要因などが挙げられます。

今回は、私が所属する開発現場で生じた不要データの事例を二つ紹介します。

続きを読む

自動E2Eリグレッションテストのレポート、通知の具体例のご紹介

この記事は Akatsuki Games Advent Calendar 2025 11日目の記事です。

はじめに

アカツキゲームスサーバーエンジニアの @haruby863 です。
自動E2Eリグレッションテストの運用をしています。
CEDEC 2025にて 「長期運営ゲームをあと10年続けるための、0から始める自動テスト ~4000項目を50%自動化し、月1→毎日実行にした3年間~」(発表資料) で登壇させていただきました。
この発表の際にご質問をいただいた、レポートや通知の具体的な内容についてご紹介します。

レポートの種類

現在2種類のレポートを使用して運用しています:

  1. Airtest内蔵のレポート

  2. Slack通知でのレポート

続きを読む

AIで人の認知限界を超えろ、運営型モバイルゲームのマスターデータ品質を高める3つのアプローチ

この記事は Akatsuki Games Advent Calendar 2025 10日目の記事です。

はじめに

QAエンジニアの山﨑(@tomo_tk11)です。 私のチームでは、生成AIを活用した業務効率化や、品質保証プロセスのシフトレフトに取り組んでいます。

今回は、運営型モバイルゲームの開発において避けては通れない「マスターデータ」の品質を、生成AI(GitHub Copilot / Claude)*1を活用してどのように高めていくか、という事例を紹介します。なお本事例は、学習データとして利用されないオプトアウト設定済みの環境で行っています。

目次

マスターデータという「生き物」との戦い

運営期間が長いタイトルほど、その裏側にあるマスターデータは複雑怪奇な進化を遂げがちです。 サービス開始当初はシンプルだったテーブル構造も、数多のイベントや新機能の実装を経て、「この表現をするためにカラムAに特殊なフラグを立て、カラムBにはJSONを入れる」といった複雑な運用ルールが積み重なっていきます。

こうなると何が起きるか。「人の認知限界」を超えてしまいます。

ドメイン知識を豊富に持つベテランプランナーなら回避できる落とし穴に、チームにジョインしたばかりのメンバーは為す術なく落ちてしまい、結果として設定ミスによる不具合が混入します。 それを防ぐQAチームもまた、テストを行うために高度なドメイン知識が要求され、疲弊してしまいます。

「人の理解を超えた複雑なデータを、人が目で見てチェックする」

これには限界がありますし、何より関わるメンバー全員が辛い状況になりがちです。

そこで、AIを活用して品質と生産性を向上させる方法はないか? と模索した結果、一つの解に辿り着きました。

プロンプトの設計思想

なぜ「ドキュメント」ではなく「コードと実データ」なのか

AIを活用しようと考えた際、最初に思いつくのは「詳細な仕様書やルールブックをAIに読み込ませる」ことかもしれません。 しかし、私はその道を選びませんでした。理由は単純で、「ドキュメントをメンテナンスしたくないから」 です。

マスターデータは生き物です。日々変化する仕様に対し、ドキュメントを常に最新に保つコストは計り知れません。古いドキュメントをAIに参照させれば、それは嘘を教えることになってしまいます。

では、「絶対に嘘をつかない最新の情報」 はどこにあるのでしょうか? 私は、答えは以下の2つだと考えています。

  • データベースのスキーマ定義(構造)
  • 過去のマスターデータ(実例)

「こういうデータを設定したい」という意図に対し、AIには「スキーマ定義ファイル」と「過去のマスタデータファイル」を探索させ、そこからルールを逆算してもらいます。

必要な情報がどこにあるかという「地図(指示書)」 だけを渡し、あとはAgentに任せる、これが今回紹介したいアプローチの肝になります。

AIへの「地図」自体も、AIに描かせる

ここで一つ、疑問が浮かぶかもしれません。「AIに参照させるための『指示書(プロンプト)』を書くのが大変ではないか?」と。 複雑なテーブル構造やリレーションのルールを、人間が一つ一つプロンプトに書き起こしていては、それこそドキュメント作成と同じ手間が発生してしまいます。

そこで、その「指示書(地図)」の作成自体もAIに行わせています。指示書の型さえ決まればメタプロンプトによる指示書の自動生成を行うことができるので、抽象度の高さは重要視しています。

実践: AI Agentへの「指示書」と3つのアプローチ

実際に私が使用しているプロンプト(指示書)の設計を紹介します。 ポイントは、テーブル単位ではなく「運用仕様(やりたいこと)」 単位で指示書を作成することです。今回は、ゲームによくある「ミッション機能」の運用を例にお話しします。

マスターデータの品質を高めるアプローチ

事前準備:AIへの「コンテキスト(地図)」の共有

作業を開始する前に、AIに対して「どのファイルを、どのような観点で読み込むべきか」を定義します。

# ミッションデータ設計・検証用 AI Agent 指示書

## 役割(Role)
あなたは熟練のデータ設計スペシャリストです。DBスキーマと過去のマスターデータを参照し、正確なデータ設計・検証を行います。

## 事前準備:データ参照先の学習
作業開始前に、以下の情報を読み込んで「ミッションデータの構造」と「実運用ルール」を学習してください。

### 1. 構造の理解(スキーマ定義)
**参照先**: データベース定義ファイル(スキーマファイルなど)
**確認内容**:
- ミッションを構成するテーブルの定義
- 各カラムのデータ型、NULL制約、デフォルト値

### 2. パターンの学習(実データ)
**参照先**: 現在稼働しているマスターデータのリポジトリ(CSV/JSON/YAMLなど)
**学習内容**:
- ミッション系テーブルに入っている実際のデータ
- 報酬設定の組み合わせパターンや、説明文のフォーマット

### 3. リレーション解決ルールの定義(IDの逆引き手順)
**目的**: ミッション条件に設定されたIDと、ユーザー向け説明文の整合性をチェックするため。
**探索ルート(例: 特定コンテンツの達成条件の場合)**:
1. ミッションデータの条件値から `target_content_id`(対象コンテンツID)を取得
2. `contents_master`(参照先テーブル)を参照して `id`が一致するレコードを特定
3. そのレコードの `content_name`(コンテンツ名称) を取得

## データ参照の優先順位
1. **最優先**: スキーマ定義 (構造の絶対的な真実)
2. **第2優先**: 実マスターデータ (実際に使われている正解パターン)
3. **第3優先**: ロジックコード (ビジネスロジック上の制約)

このように、単に「データを作って」と言うのではなく、「リレーションの辿り方」や「参照ファイルの優先順位」を明確にした指示書(地図)を読み込ませた上で、以下の3つのアプローチを実行します。

アプローチ1:仕様相談(「これ、実現できる?」の壁打ち)

プランナーが「こういうイベントミッションをやりたい」と思いついた時、データ構造やロジックの観点から実現可能性を即座に判定させます。

プロンプト(指示書)の構成例

## 概要
**目的**: 企画案の実現可能性を判定し、実現可能であればマスターデータ案を提示

### 実行手順
1. **スキーマ定義**で関連テーブルの構造を確認
2. **過去のマスターデータ**から類似するミッションタイプを検索
3. 必要に応じて**ビジネスロジック**を確認し、制約を把握

### 入力形式
企画案を自然言語で記述
(例:「指定のコンテンツを、特定の条件(種別や属性など)を満たす対象を用いて10回達成する」)

### 出力形式
**判定**: [可能 / 条件付きで可能 / 不可能]

**根拠**:
- スキーマ上の制約(必要なカラムの有無)
- 過去データ内の類似実装例
- ロジック上の制限事項

**懸念点**:
- パフォーマンスリスク
- 複雑すぎる条件設定による不具合リスク

このアプローチの利点

単に「できます」と答えるだけでなく、「過去に類似事例があるか」「スキーマ的に無理がないか」を根拠に回答させる点が重要です。これにより、実装不可能な企画がデータ作成段階まで進んでしまう手戻りを防げます。

アプローチ2:データチェック(見落としがちな「矛盾」の検知)

ここが最もQAコストを下げられる部分だと感じています。単なる型チェックだけでなく、「意味的な整合性」 まで踏み込めるからです。 例えば、「特定のコンテンツ『A』を攻略する」 というミッションの場合、データ上の設定ミスにより、内部で指定している参照IDと、ユーザーに見せる説明文の内容が食い違っていることがあります。 これを人がチェックするには、IDから参照先の定義テーブルなどを跨いで確認する必要がありますが、AIなら一瞬で判断できます。

プロンプト(指示書)の構成例

## 概要

**目的**: 作成したマスターデータの整合性を検証し、問題があれば指摘

### 入力形式

新規マスターデータ(CSVまたはJSON形式)

### チェック項目

**1. スキーマ整合性**:
- カラム定義、NULL制約、データ型、カラム順序の遵守

**2. 外部キー参照**:
- 設定されたIDが、参照先テーブルの実データとして存在するか

**3. JSON構文と論理**:
- 達成条件を記載するJSONカラムの構文エラーチェック
- 該当するミッションタイプで使用可能なキーが含まれているか

**4. 過去データとの整合性(外れ値検出)**:
- 報酬量や数値設定が、過去の類似データと比較して極端に逸脱していないか
- 日付の前後関係(開始日が終了日より前か)

**5. 高度な整合性チェック(リレーション逆引き)**:
- **例:特定コンテンツ参照型ミッションの整合性**
  - 手順: 条件定義内の `target_content_id` をキーに、参照先の `contents_master` テーブルを逆引き
  - 検証: ミッションの `description`(説明文)に記載された「コンテンツ名称」が、逆引きした実情報と一致しているか確認
  - 判定: 不一致の場合は「説明文と設定IDが食い違っています(IDはXXを指していますが、説明文はYYになっています)」と警告を出力

### 追加ルール記述欄

※ 絶対にバリデーションしたいルールがある場合は、ここに追記してください。
※ 基本的には過去データから自動的にルールを理解します。

### 出力形式
**判定**: [OK / NG / WARNING]
**指摘事項**:
- [カテゴリ] [エラー箇所]: [修正案またはエラー理由]

このアプローチの利点

「IDは正しいが、コピペ元の説明文が残っている」「報酬の桁を間違えている」といったミスは、人間が大量のデータを目視していると見落としがちです。 AIに「データが意味するところ(Semantics)」を解釈させ、レビューさせることで、こうしたヒューマンエラーを機械的に検出できます。

アプローチ3:データ生成支援(「いつものやつ」を爆速で作る)

過去のデータ(実データファイル)は、最高のテンプレートです。AIに面倒な一括変換やID採番を任せることで、プランナーは「値の設計」に集中できます。

プロンプト(指示書)の構成例

## 概要
**目的**: 既存データをベースに、変更点を反映した新しいマスターデータをCSV形式で生成

### 入力形式
**ベースデータの指定**:
- ベースとして利用するデータのID

**変更点**: 自然言語で指示(例:「イベントIDを変更」「報酬をアイテムXに変更」)

### 実行ルール
**1. アイテムIDの調査**:
- 指示された「アイテム名」から、アイテムマスタを検索してIDを特定する
- 見つからない場合は `[要調査: アイテム名]` として出力

**2. ID採番ルール**:
- **重要**: 既存データの最大IDを確認し、重複しないように連番で採番すること
- ユーザーがIDを指定しない場合は、「新規IDの開始番号は〇〇からで良いですか?」と確認を求める(勝手に採番して重複させないため)

**3. CSV/JSON出力フォーマット**:
- 区切り文字: タブ(`\t`- NULL値: `NULL` または空欄
- **JSONのエスケープ処理**:
  - JSONフィールドはダブルクォートで囲む
  - 内部の `"``\` でエスケープし、改行なしの1行で出力すること

### 出力形式
以下のテーブルをCSV形式(ヘッダーあり)で出力:
※ ミッションに関連するテーブル名を指定してください

このアプローチの利点

複雑なJSONの変更やミッション開始時間の一括変更を手作業でやるとミスが頻発します。 「フォーマットはAIに任せ、人は中身(企画意図)だけを指示する」という分業により、データ作成の速度と品質を同時に向上させることができます。

まとめ

今回紹介した事例で最もお伝えしたかったのは、AIアプローチそのものではなく、AIへの情報の渡し方(コンテキスト設計) についてです。

運営型モバイルゲームのように仕様が絶えず変化する(追加される)環境において、AIに「現在の正しいルール」をすべて教え込もうとするアプローチはあまり取りたくありません。プロンプトに細かな仕様を書けば書くほど、そのプロンプト自体のメンテナンス性が人の限界を超えてしまうからです。 だからこそ、アプローチを変える必要があると考えています。

  1. 静的な「ドキュメント」を捨て、動的な「コードと実データ」を知識源とする
  2. AIには答えを教えず、答えがある場所への「地図(指示書)」だけを渡す
  3. そして、その「地図」すらもAIに描かせることで、メンテナンスコストを極小化する

この「地図を渡す」というアプローチの最大の利点は、高い汎用性と拡張性 にあります。 今回は「ミッション」を例にしましたが、この手法はログインボーナスやコンテンツ報酬設定など、あらゆる機能に適用可能です。なぜなら、どのような機能であっても、そこには必ず「スキーマ(構造)」と「過去データ(実例)」が存在するからです。

私たちが設計すべきは、個別のルールではありません。AIが自律的にリポジトリ内を探索し、ロジックを逆算するための「探索ルート」 です。

「正解は常にコードとデータの中にある」。

この前提に立ち、AIを「データを検索・模倣・検証するAgent」として振る舞わせることこそが、複雑化・巨大化する運営開発において、品質と速度を維持し続けるための普遍的な解になるのではないか、と信じています。

この記事が、複雑なマスターデータと戦うプランナーやQAの皆さんの助けになれば嬉しいです。

*1:要件を満たせばCopilotにこだわる必要はありません。

Photoshopスクリプト(ExtendScript)を書いてみた

こんにちは! アカツキゲームス クライアントエンジニアのSuです。
この記事は Akatsuki Advent Calendar 2024 11日目の記事です。
昨日の boke0 さんの踊り文字についての記事は面白かったです。一歩一歩 → 一歩々々という書き方は初めて知りました。とても勉強になりました!25日の解決編も楽しみですね!

はじめに

自分は学生時代からエディターの拡張に興味があり、Blenderエディターの関連研究も少し関わりました。現在もチーム内のクリエイターさん達が効率的に作業できるように改善活動を日々頑張っています。

今回はデザイナーさんからちょっと複雑な自動化要望があったので、Photoshopスクリプトを書いてみました。本記事はPhotoshopスクリプトを書くための環境構築、デバッガー、実際に書くの流れを紹介したいと思います。

Photoshop の自動化

Photoshopの中にすでに自動化機能があります。簡単かつ重複的な操作ならアクション、バッチ、変数・データセット機能でカバーできると思いますが、もし操作が条件によって分岐したい場合、スクリプトを書くには一つの手と思います。

ここの「スクリプト」というのは、Adobe社が開発したスクリプト言語および関連ツールキット ExtendScript です。ベースは  ECMAScript 3 なので JavaScript や ActionScript に似ている。Photoshop、InDesign、After Effects などのアプリケーション内のツールにアクセスしてプロジェクトをバッチ処理することができます。

ExtendScript IntelliSense

テキストエディターさえあれば書けますが、快適に書ける方法を紹介します。
公式拡張機能があるので、エディターは Visual Studio Code がおすすめです。

自動補完が大事なのでまずは IntelliSenese ですね!こちらの動画を参考しました。

www.youtube.com

下記の ExtendScript の TypeScript をプロジェクトフォルダに入れて、jsconfig.json ファイルを設定し、IntelliSenese を実現する方法です。

github.com

ExtendScript デバッガー

現在、Apple Sillicon ネイティブでデバッガーを実行できないため、Intel 版の Visual Studio Code をインストールして Rosetta で起動する必要があります。

Mac → zip「Intel chip」の方をダウンロードし、展開した実行ファイルを Visual Studio Code(Intel) にリネームして実行します。

code.visualstudio.com

次は「ExtendScript Debegger」という拡張機能をインストールします。現時点最新の v2.0.3 は自分の環境で問題なく動きました。

VSCode のデバッグボタンをクリックします。launch.jsonを作成します。

ExtendScriptを選択します。

 launch.json が作成されて、左のパネルに「Launch Script in ExtendScript Engine」の選択肢があればそれに切り替えして、これで設定完了です!

では実際にコードにブレイクポイントをセットします。

ここではウィンドウを出すコードの2行目の2の左をクリックすると、ブレイクポイントをつけます。

さっきのデバッグパネル「Launch Script in ExtendScript Engine」左の実行ボタンを押して、使用するPhotoshopを選んでコードが実行されます。

ちゃんとブレイクポイントに止まりました!

ウォッチ式も使えますね。便利です!

実行し続けるなら下記のようなダイアログが出てきます。

楽しく ExtendScript を書ける環境セットアップは以上です!

Github repo

今回の記事で使ったコードをGithubにまとめました。よかったらどうぞ!

github.com

最後に

この記事読んだ君の役に立てればいいですね〜

明日は周さんのAI Chatと関連する内容です。楽しみですね!

アカツキでは一緒に働くエンジニアを募集しています。
カジュアル面談もやっていますので、気軽にご応募ください。

games.aktsk.jp