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点を確かめます。
- 漏れの確認: 集計スクリプトが出す「入力件数」と「分類済み件数」を比べます。差があれば、そのバッチだけ再実行します
- 抜き取り: 分類ごとに無作為で10件ずつ抜き、元の発言と見比べます。「その他」に偏りすぎていれば、分類の定義を見直します
- 上位項目の原文確認: 上位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の導線を先に決めておくのが出発点です。