Claude Media
Claudeでプレイテストのフィードバックを集計し改修順を決める — Steamの感想ログを回数付きで並べる

Claudeでプレイテストのフィードバックを集計し改修順を決める — Steamの感想ログを回数付きで並べる

Steam PlaytestやDiscordに溜まった自由記述を、Claude Codeの非対話モードで離脱・操作・バランスに分類し、人数付きの改修リストにする手順です。

プレイテストの感想は「読む」と「数える」を分けると優先度が決まる

Steam Playtestを回すと、Discordの感想チャンネル、フォーラム、バグ報告フォームに自由記述が散らばります。数十件なら通読できますが、数百件になると「声が大きい不満」だけが記憶に残り、改修の順番が印象で決まりがちです。

この記事では、Claude Codeの非対話モードで1件ずつ分類させ、数える作業はスクリプトに任せる構成を組みます。Claudeの仕事は「この一文はどの種類の指摘か」を決めることだけです。件数の集計と並べ替えは、毎回同じ結果が出るPythonに寄せます。チャットとExcelで少量を分析する手順はClaudeでユーザーフィードバックのパターンを分析する方法にあり、ここでは数百件を毎回同じ手順で回す構成を扱います。

最終的に手に入るのは、次の形の改修リストです。

順位分類指摘の中身件数発言者数
1分類離脱指摘の中身ステージ3のボス前で進め方が分からない件数18発言者数11
2分類操作指摘の中身ジャンプとダッシュが同じボタンで暴発する件数14発言者数9
3分類バランス指摘の中身回復アイテムが序盤に出すぎる件数7発言者数6

上の数値は形を示すための例です。実際の件数は、手元のログから出た値に置き換わります。

Steam Playtestの感想はどこから集まるか

先に、集める側の前提を押さえます。Steam Playtestの仕組み上、感想の受け皿はValveが用意してくれません。Steamworksのドキュメントには「Collecting feedback from players is up to you」とあり、ゲーム内のメインメニューに大きな「feedback」ボタンを置き、Steamフォーラム、Discordチャンネル、バグ追跡ツール、自前のWebサイトなど好きな場所へ誘導する例が挙がっています。

つまり集計の入口は開発者が決めます。典型的には次の3系統です。

  • Discordの感想チャンネル(自由記述、スクリーンショット付き)
  • バグ追跡ツールやフォームの不具合報告(再現手順つき)
  • Steamフォーラムの投稿

Playtestの仕様で、集計の設計に効く点が2つあります。

1つ目は、参加者の選ばれ方です。既定の限定サインアップでは、サインアップした中からSteamがランダムに選びます。国を絞る設定もありますが、用途は主にサーバー容量やレイテンシへの配慮です。ランダム抽出なので、感想の偏りは「開発者が意図した層」ではなく「応募した人」の偏りだと考えておくと、件数の読み方がぶれません。

2つ目は、機密性です。Playtestの参加者はNDAを結んでいません。感想がそのままSNSに出る前提で、Discordの発言をClaudeに渡す前にも個人が特定される情報を落としておきます。

感想ログを1行1件のファイルに整える

Claudeに渡す前に、ログをfeedback.tsvのような1行1件の形にします。必要な列は4つです。

列内容理由
id内容連番理由分類結果と元の発言を突き合わせる
tester内容発言者の匿名ID理由件数と別に「何人が言ったか」を数える
source内容discord / form / forum理由経路ごとの偏りを見る
text内容本文(1件の改行は半角スペースに)理由分類の対象

発言者名はハンドルネームのまま渡さず、T001のような連番に置き換えます。同じ人が10回書いた不満と、10人が1回ずつ書いた不満は、改修の優先度が違うからです。この区別のために発言者の列を残します。

ここまでは、Claude Codeに整形スクリプトを書かせると速く済みます。Discordの感想チャンネルから発言を自動で拾うBotの作り方はClaude CodeでDiscord Botを作るにあります。Discordのログがどの形式で手元にあるか(コピーしたテキスト、書き出したCSVなど)を伝え、列の定義を渡すだけです。

discord_log.txt を feedback.tsv に変換するPythonスクリプトを書いてください。
- 列は id, tester, source, text の4つ(タブ区切り)
- tester は元のユーザー名を T001, T002 の連番に置き換える
- 対応表は mapping.json に保存し、feedback.tsv には元の名前を残さない
- text 内の改行は半角スペースに直す

分類の物差しと出力スキーマを先に決める

分類の軸は、プレイテストで知りたいことから逆算します。ここでは5つにします。

分類拾う内容
離脱拾う内容進め方が分からない、先に進めない、やめた理由
操作拾う内容ボタン配置、UIの読みにくさ、チュートリアル不足
バランス拾う内容難しすぎる・易しすぎる、入手量、強すぎる要素
不具合拾う内容クラッシュ、表示崩れ、進行不能バグ
要望拾う内容新機能、追加してほしい要素

どれにも当てはまらない発言のために「その他」も用意します。無理に既存の分類へ押し込ませないためです。

Claude Codeの非対話モードは、--json-schemaでJSON Schemaを渡すと、結果がstructured_outputフィールドに入って返ります。出力の形が固定されるので、後段のスクリプトが読みやすくなります。schema.jsonは次のとおりです。

{
  "type": "object",
  "properties": {
    "results": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "category": {
            "enum": ["離脱", "操作", "バランス", "不具合", "要望", "その他"]
          },
          "topic": { "type": "string" }
        },
        "required": ["id", "category", "topic"]
      }
    }
  },
  "required": ["results"]
}

topicには、同じ指摘をまとめるための短い見出しを入れさせます。「ステージ3のボス前で進め方が分からない」のように場所と症状を書かせると、後で数えるときに同じ指摘が束ねやすくなります。

バッチに分けて非対話モードで分類する

非対話モードはclaude -pで動き、標準入力にデータをパイプで渡せます。パイプ入力の上限は10MBです。感想ログのテキストなら十分に収まりますが、一度に大量に渡すと分類の取りこぼしが増えるため、40件ずつに分けます。

# feedback.tsv の1行目(見出し)を除き、40件ずつ分割する
tail -n +2 feedback.tsv | split -l 40 - batch_
 
for f in batch_*; do
  cat "$f" | claude -p \
    "各行は id, tester, source, text のタブ区切り。
     text を分類し、全行について results に1要素ずつ返す。
     分類は schema の enum から選ぶ。当てはまらなければ その他。
     topic は『場所+症状』を20字以内で書く。" \
    --output-format json \
    --json-schema "$(cat schema.json)" \
    | jq '.structured_output.results' > "out_$f.json"
done

--bareを付けると、フックやCLAUDE.md、MCPサーバーなどを読み込まず、どのマシンでも同じ条件で動かせます。ただしbareモードはサブスクリプションのログインを使わないため、ANTHROPIC_API_KEYを環境変数に設定してから実行します。対話で使っている設定を引き継ぎたいなら、--bareは付けずに回します。

件数と発言者数を数えて優先度の表にする

分類結果は元のTSVとidで突き合わせ、Pythonで集計します。Claudeに「集計して」と頼まず、数える部分をコードに任せるのがこの構成の要点です。

import csv, json, glob
from collections import defaultdict
 
rows = {}
with open("feedback.tsv", encoding="utf-8") as f:
    for r in csv.DictReader(f, delimiter="\t"):
        rows[int(r["id"])] = r
 
labels = []
for path in sorted(glob.glob("out_batch_*.json")):
    labels += json.load(open(path, encoding="utf-8"))
 
# 件数の取りこぼしがないか確認する
ids = [x["id"] for x in labels]
missing = set(rows) - set(ids)
print("入力", len(rows), "分類済み", len(set(ids)), "漏れ", sorted(missing))
 
groups = defaultdict(lambda: {"n": 0, "testers": set()})
for x in labels:
    key = (x["category"], x["topic"])
    groups[key]["n"] += 1
    groups[key]["testers"].add(rows[x["id"]]["tester"])
 
ranked = sorted(groups.items(),
                key=lambda kv: (-len(kv[1]["testers"]), -kv[1]["n"]))
for (cat, topic), g in ranked[:20]:
    print(f'{cat}\t{topic}\t{g["n"]}件\t{len(g["testers"])}人')

並べ替えの第1キーは発言者数、第2キーが件数です。1人が繰り返し書いた不満を、多くの人が踏んだ問題より上に置かないためです。重みづけをするなら、不具合のうち進行不能に当たるものを別枠で先頭に出すなど、プロジェクトの事情で決めます。

topicの表記ゆれを寄せる

バッチごとに別々に分類させると、同じ指摘が「ボス前で詰まる」「ステージ3のボスの攻略法が不明」のように別のtopicになり、件数が分散します。次の追加依頼で寄せます。

out_*.json の topic を全部読み、意味が同じものに統一した見出しを付け直してください。
- 統一後の見出しと、元の topic の対応表を topic_map.json に書く
- 迷うものは統一せず、そのまま残す
- 元の id と category は変えない

対応表をJSONとして残させると、どの見出しにどの発言が束ねられたかを後から見直せます。集計スクリプトはtopic_map.jsonを通した見出しで数え直します。

結果を信じる前の3つの確認

分類結果をそのまま改修判断に使うのは避け、次の3点を確かめます。

  1. 漏れの確認: 集計スクリプトが出す「入力件数」と「分類済み件数」を比べます。差があれば、そのバッチだけ再実行します
  2. 抜き取り: 分類ごとに無作為で10件ずつ抜き、元の発言と見比べます。「その他」に偏りすぎていれば、分類の定義を見直します
  3. 上位項目の原文確認: 上位5項目は、束ねられた発言を実際に読みます。件数が多くても、中身が別の問題の寄せ集めということがあります

特に「操作」と「離脱」は境目が曖昧です。「UIが分かりにくくて先に進めなかった」はどちらにも読めるため、分類の定義に「進行が止まった発言は離脱」と一行足しておくと揺れが減ります。

参加経路ごとにテスターの性質が違う

Playtestには、参加者を増やす経路が3つあります。限定サインアップでの抽選、Steamキーの配布、フレンド招待です。経路が混ざったテストでは、感想の傾向も混ざります。

フレンド招待は、1人あたり1・2・3人のいずれかの招待枠を設定でき、招待された人がさらに友人を招く形で広がります。マルチプレイ向けの機能なので、同じグループの人が似た感想を書く可能性があります。キー配布は、開発者が渡す相手を決めているため、抽選とは母集団が違います。

集計表にsource列を持たせたように、参加経路もmapping.jsonの対応表に1列足しておくと、「抽選で入った人にだけ多い不満」のような切り分けができます。経路を足す手間は、対応表を作る時点で済ませておくのが楽です。

改修の優先度にするときの見方

集計表はあくまで入力です。改修の順番は、次のような見方で組み合わせます。

見るもの分かること
離脱の発言者数分かること続けられなかった人の多さ。最優先で潰す
操作の件数が多く発言者が少ない分かること一部の人が強く気にしている。再現手順で確認する
バランスの賛否が割れる分かること難しすぎる・易しすぎるの両方が出る場合は、調整より選択肢の追加を検討する
不具合のうち進行不能分かること件数が少なくても先頭に置く

参加者を数十人に絞ったテストでは、1人の発言だけで順位が入れ替わります。順位の僅差に意味を持たせず、上位と下位の大きな差だけを見ます。改修そのものに進む段階では、Claude CodeでUnityゲーム開発を進めるやClaude CodeでGodotゲーム開発を始めるが続きの手順になります。

Playtestを繰り返すときの運用

Steam Playtestは、同じappIDで何度でも回せます。終了したいときは「Not Playable」に切り替え、再開は再びVisibleにします。いったん参加した人は再度サインアップしなくても入れます。

参加者をまるごと入れ替えたいときはリセットがあります。リセットは元に戻せず、参加者と待機中の人がPlaytestから外れます。リセットの前に、今回の集計表とmapping.json(匿名IDと元のアカウントの対応)を保存しておくと、次回のテストと同じ指摘が出たかを比較できます。

回を重ねるときは、前回のtopic_map.jsonを次回の分類依頼に渡し、同じ見出しに寄せます。前回の上位項目が今回の感想に残っているかを並べると、改修の効果が見えます。

まとめ

Playtestの感想集計は、Claudeに「読んで分類させる」ことと、コードで「数えて並べる」ことを分けると安定します。分類のスキーマを固定し、発言者数を件数と別に数え、漏れ・抜き取り・上位の原文確認を挟めば、印象でなく根拠のある改修順が作れます。感想の入口を作る段階では、Steamの仕組みはあくまで受け皿を用意しないので、フォームやDiscordの導線を先に決めておくのが出発点です。

この記事を共有:XはてブLinkedIn