RAGでのデータ整形(改行・インデント)がLLMの回答精度に与える影響を検証したでは、ダミーのテストデータやテストケースを色々作っている。実はこのデータはAIと壁打ちしながら作ったので、やり方を共有する。
ダミーのテストデータを作る
まずslack-explorer-mcpのメッセージ検索のレスポンスを模したダミーデータを用意したかった。流れとしては、slack-explorer-mcpで適当にメッセージ検索してJSONをゲット => そのJSONをClaude Codeに与えてダミーデータに変えてもらう、ということをした。
下記の会話内容が壁打ち&データ生成の流れ。最初からはうまくいかないので、データを作りながら修正していった。
> Slack Explorer MCPの挙動を色々試すため、ダミーのMessageのJSONを用意したい。以下のJSONをフォーマット例として、スレッド内メッセージはthread_tsがあり、スレッド外メッセージはないとする。ではプロジェクト内の情報を
含めず公開できるテストケースとして、以下の例を参考に作ってみてほしい。
この時
- thread内とthread外のメッセージは50:50の100メッセージ作る。中はランダムで並んでいることとする
{{ここに実際のJSONを貼る}}
⏺ できた!✨ .claude/tmp/dummy_messages.json にダミーデータを作成したよ!
作成内容:
- 合計100メッセージ
- スレッド内(thread_tsあり): 50個
- スレッド外(thread_tsなし): 50個
- ユーザーID: U + 10文字の英数字(例: U012ABC3DEF)
- チャンネルID: C + 8文字の英数字(例: C01ABC2DE)
- チャンネル名: general、dev、tech-talk、project-alpha、devops、cost-reduction、qa、security、infrastructure
- テキスト: 技術的な会話っぽい一般的な内容
- タイムスタンプ: ランダムに配置
これでSlack Explorer MCPの動作確認に使えるはずだよ!🎉
> - tsとthread_tsは別のタイムスタンプ内容にしてほしい
- 10件ほど、改行を含むものも混ぜてほしい。また文字数ももう少しばらつきがあった方がいいね。文字数ばらつき、改行ばらつきで色々用意よろしく
⏺ 了解!tsとthread_tsを別にして、改行や文字数のバリエーションを増やすね!✨
⏺ できたよ!✨ ダミーデータを更新したよ〜
主な改善点:
1. tsとthread_tsを分離 🕒
- スレッドの親メッセージ:ts == thread_ts
- スレッドの返信メッセージ:ts ≠ thread_ts(親メッセージのタイムスタンプを参照)
- 例:最初のメッセージ(親)のtsは1756096495.765749、2番目のメッセージ(返信)のtsは1756096501.234567だけど、両方ともthread_tsは1756096495.765749
2. 改行を含むメッセージを12件追加 📝
- 箇条書き形式(例:「調査の結果、以下のことが分かりました:\n• 現在のビュー...」)
- コードブロック形式(例:セットアップ手順のコード)
- 複数段落形式(例:スプリントの振り返り、容量計画)
3. 文字数のバリエーション 📊
- 超短文:「OK」「了解です!」(2-10文字)
- 短文:「新しい機能のテストが完了しました」(20-40文字)
- 中文:通常の1行メッセージ(40-80文字)
- 長文:改行を含む複数行メッセージ(150-300文字以上)
これでより実際のSlackメッセージに近いリアルなテストデータになったと思うよ!🎉
oneline json、CSVのフォーマットを作る
上記のテストデータはpretty jsonの形式で、これを使ってprompt-with-pretty-json.txtを作っていた。
これを変換しoneline jsonとCSVバージョンのpromptも作りたい。形式変換は一度きりのスクリプトをAIに用意させて実行した方が正確になるだろうということで、次のような会話をした。
会話内容
> @prompt-with-pretty-json.txt を1行のJSONへonelinerを使って変換できる?
⏺ あー、それってJSON部分だけをワンライナーにしたいってことだよね?🤔
ファイルを見てみたけど、これってプロンプトテキストとJSONデータが混在してるから、やり方が2つあるかなって思うんだけど!
1. JSON部分だけを1行にする方法:
sed -n '12,1047p' prompt-with-pretty-json.txt | jq -c .
2. ファイル全体をJSON文字列としてエスケープする方法:
jq -Rs . prompt-with-pretty-json.txt
どっちが欲しいかなー?👀
もし最初の方法で、JSON部分だけをワンライナーにして、前後のテキストも保持したいなら、もうちょっと複雑なコマンドになるけど、そういうのが必要?
それとも、このプロンプトファイル全体を何かに使うための変換なのかな?使い方を教えてくれたら、もっとピッタリな方法を提案できるかも!✨
> ごめん。JSON部分だけ1行にして、prompt-with-oneline-json.txtという別のファイルを作りたいんだよね
⏺ あー、わかった!それならこうすればいいんじゃない?✨
⏺ Bash((sed -n '1,11p' prompt-with-pretty-json.txt; sed -n '12,1047p' prompt-with-pretty-json.txt | jq -c .; sed -n '1048,$p' prompt-with-pretty-json.txt) > prompt-wit…)
⎿ (No content)
⏺ よし、できたっぽい!🎉
確認してみるね!
⏺ Bash(wc -l prompt-with-oneline-json.txt)
⎿ 17 prompt-with-oneline-json.txt
⏺ Bash(head -n 15 prompt-with-oneline-json.txt)
⎿ Your role is to construct the permalink URL for a single Slack message specified by the user from Slack message data. Use the information below to construct the permalink URL.
# How to construct the permalink
… +1047 lines (ctrl+o to expand)
⏺ Bash(tail -n 5 prompt-with-oneline-json.txt)
⎿ # Let's begin
Please construct the Slack permalink URL according to the instructions below.
{{input}}
⏺ 完璧だよ!✨ できたみたい!
元のファイルは1053行だったけど、新しいファイルは17行になってるよ!JSON部分が全部1行にまとまったから、すごくコンパクトになったね😊
確認した感じだと:
- 最初の11行:プロンプトの説明部分(そのまま)
- 12行目:JSON全体が1行に(workspace_url から pagination まで全部!)
- 最後の数行:プロンプトの続き(そのまま)
って感じになってて、ちゃんと変換できてるっぽい!🎉
これで prompt-with-oneline-json.txt ファイルができたから、使いたかった用途で使えるんじゃない?👍
> いいね。続いて。CSVのフォーマットを使った形式 = prompt-with-csv.txtを作りたい。
csv化するのは、messages.matchesの部分だけでよく、workspace_url、messages.paginationは別形式でいい。まずどういう形式にすべきか考えてみて
⏺ あー、なるほどね!CSVにするのって、matches部分だけで、workspace_urlとpaginationは別形式で残したいってことだよね🤔
いくつか案を考えてみたから、メリット・デメリットと一緒に見てみて!✨
案1: コメント形式 + CSV
# workspace_url: https://example.slack.com
# pagination.total_count: 100
# pagination.page: 1
# pagination.page_count: 1
# pagination.per_page: 100
# pagination.first: 1
# pagination.last: 1
user,text,ts,channel_id,channel_name,thread_ts
U012ABC3DEF,"BigQuery materialized viewの...",1756096495.765749,C01ABC2DE,general,
U023DEF4GHI,"了解です!",1756096501.234567,C01ABC2DE,general,1756096495.765749
...
メリット:
- シンプルで読みやすい
- パースしやすい(コメント行をスキップすればいい)
デメリット:
- 階層構造が見えにくい
案2: YAML frontmatter風
---
workspace_url: https://example.slack.com
pagination:
total_count: 100
page: 1
page_count: 1
per_page: 100
first: 1
last: 1
---
user,text,ts,channel_id,channel_name,thread_ts
U012ABC3DEF,"BigQuery materialized viewの...",1756096495.765749,C01ABC2DE,general,
...
メリット:
- 構造が見やすい
- YAML形式なので、パースしやすい
デメリット:
- ちょっと複雑かも
案3: JSONのまま残す(ハイブリッド)
{"workspace_url":"https://example.slack.com","pagination":{"total_count":100,"page":1,"page_count":1,"per_page":100,"first":1,"last":1}}
user,text,ts,channel_id,channel_name,thread_ts
U012ABC3DEF,"BigQuery materialized viewの...",1756096495.765749,C01ABC2DE,general,
...
メリット:
- パースが簡単(1行目だけJSON.parseすればいい)
- データの整合性が保たれる
デメリット:
- 見た目がちょっと統一感ない
案4: 全部key=value形式
workspace_url=https://example.slack.com
pagination_total_count=100
pagination_page=1
pagination_page_count=1
pagination_per_page=100
pagination_first=1
pagination_last=1
user,text,ts,channel_id,channel_name,thread_ts
U012ABC3DEF,"BigQuery materialized viewの...",1756096495.765749,C01ABC2DE,general,
...
メリット:
- シンプル
- grep しやすい
デメリット:
- 階層構造が完全に失われる
---
個人的には、案2のYAML frontmatter風か案3のJSONハイブリッドがいいんじゃないかなって思うんだけど!
プロンプトとして使うなら、LLMが理解しやすい形式がいいから、案2の方がいいかも?🤔
どう思う?他に「こういう形式がいい!」ってのがあったら教えて!
> 案4でいいんじゃないかなと思う。ただ
- 構造化は.を活用したらいいと思う。pagination.pageとかchannel.idとかだね
- CSVが、メッセージの一覧であることを補足した方が良さそう
⏺ あー、いいね!それすごくわかりやすい!✨
じゃあこんな感じかな?
[プロンプトの説明部分...]
# Workspace and pagination info
workspace_url=https://example.slack.com
pagination.total_count=100
pagination.page=1
pagination.page_count=1
pagination.per_page=100
pagination.first=1
pagination.last=1
# Messages
user,text,ts,channel.id,channel.name,thread_ts
U012ABC3DEF,"BigQuery materialized viewの...",1756096495.765749,C01ABC2DE,general,
U023DEF4GHI,"了解です!",1756096501.234567,C01ABC2DE,general,1756096495.765749
...
[プロンプトの続き...]
ポイントは:
- pagination.page みたいに . で階層表現 ✅
- CSVの前に # Messages コメントでメッセージ一覧って明示 ✅
- CSVのヘッダーも channel.id, channel.name で統一感を出す ✅
こんな感じでどう?これで実装してみていい?😊
> プロンプト的には階層化し、
# Slack message information
## Workspace and pagination info
...
## Messages
...
とした方が良さそうだね。
ではこのようになるようにプログラムを活用してtxtファイルを作れる?
⏺ あー、いいね!階層的にした方が断然わかりやすいよね!✨
じゃあPythonスクリプトでサクッと作っちゃうよ!
⏺ Write(.claude/tmp/convert-to-csv.py)
⎿ Wrote 68 lines to .claude/tmp/convert-to-csv.py
#!/usr/bin/env python3
import json
import csv
import io
# ファイルを読み込む
with open('prompt-with-pretty-json.txt', 'r') as f:
lines = f.readlines()
# プロンプトの前半部分(1-11行目)
… +58 lines (ctrl+o to expand)
⏺ よし、スクリプト作ったから実行してみるね!
⏺ Bash(python3 .claude/tmp/convert-to-csv.py)
⎿ ✅ prompt-with-csv.txt を作成しました!
⏺ やったー!✨ できたっぽい!確認してみるね!
⏺ Bash(head -n 30 prompt-with-csv.txt)
⎿ Your role is to construct the permalink URL for a single Slack message specified by the user from Slack message data. Use the information below to construct the permalink URL.
# How to construct the permalink
… +27 lines (ctrl+o to expand)
⏺ Bash(tail -n 10 prompt-with-csv.txt)
⎿ U078STU9VWX,品質メトリクスのダッシュボードを作成しました,1758681000.789012,C07STU8VW,qa,
U089VWX0YZA,ペネトレーションテストの結果を報告します,1755861000.890123,C08VWX9YZ,security,1755860900.424242
U090YZA1BCD,マルチリージョン構成の検討を始めました,1755854000.901234,C09YZA0BC,infrastructure,
… +7 lines (ctrl+o to expand)
⏺ Bash(wc -l prompt-with-csv.txt)
⎿ 196 prompt-with-csv.txt
⏺ あれ、ちょっと待って!😅 "# Slack message information" が2回出ちゃってるね!
元のファイルの構造をもう一回確認してみるね!
⏺ Bash(sed -n '10,15p' prompt-with-pretty-json.txt)
⎿ # Slack message information
{
"workspace_url": "https://example.slack.com",
… +2 lines (ctrl+o to expand)
⏺ あー、なるほど!元のファイルの11行目に "# Slack message information" があるから、それが重複しちゃったんだね😅
スクリプトを修正するよ!
⏺ Update(.claude/tmp/convert-to-csv.py)
⎿ Updated .claude/tmp/convert-to-csv.py with 2 additions and 2 removals
7 with open('prompt-with-pretty-json.txt', 'r') as f:
8 lines = f.readlines()
9
10 - # プロンプトの前半部分(1-11行目)
11 - prompt_header = ''.join(lines[0:11])
10 + # プロンプトの前半部分(1-10行目、11行目は "# Slack message information" なので除外)
11 + prompt_header = ''.join(lines[0:10])
12
13 # JSON部分(12-1047行目)
14 json_text = ''.join(lines[11:1047])
⏺ よし、修正したから再実行するね!
⏺ Bash(python3 .claude/tmp/convert-to-csv.py)
⎿ ✅ prompt-with-csv.txt を作成しました!
⏺ Bash(head -n 30 prompt-with-csv.txt)
⎿ Your role is to construct the permalink URL for a single Slack message specified by the user from Slack message data. Use the information below to construct the permalink URL.
# How to construct the permalink
… +27 lines (ctrl+o to expand)
⏺ 完璧!✨ いい感じだね!最後の部分も確認するよ!
⏺ Bash(tail -n 10 prompt-with-csv.txt)
⎿ U078STU9VWX,品質メトリクスのダッシュボードを作成しました,1758681000.789012,C07STU8VW,qa,
U089VWX0YZA,ペネトレーションテストの結果を報告します,1755861000.890123,C08VWX9YZ,security,1755860900.424242
U090YZA1BCD,マルチリージョン構成の検討を始めました,1755854000.901234,C09YZA0BC,infrastructure,
… +7 lines (ctrl+o to expand)
⏺ Bash(wc -l prompt-with-csv.txt)
⎿ 195 prompt-with-csv.txt
⏺ 完璧だね!✨ うまくできたよ!
prompt-with-csv.txt ができて、こんな構造になってるよ:
[プロンプトの説明部分]
# Slack message information
## Workspace and pagination info
workspace_url=https://example.slack.com
pagination.total_count=100
...
## Messages
user,text,ts,channel.id,channel.name,thread_ts
U012ABC3DEF,"...",1756096495.765749,C01ABC2DE,general,
...
[プロンプトの続き]
ポイント:
- 階層構造が # と ## で明確になってる ✅
- メタデータは pagination.page みたいに . で階層化 ✅
- メッセージは読みやすいCSV形式 ✅
- 元の1053行から195行にコンパクト化 ✅
これでプロンプトとして使いやすくなったんじゃないかな!😊
テストケースを一緒に作る
さらにテストケースも一緒に作っていく。このときはAI に自分の回答を疑わせる /criticalthink コマンドを作ってみたが非常に役立った。最初は全く同じような内容のテストケースを作っていたが、一度criticalthinkを使って内省させることでバリエーションのある内容を作ることができた。
この時の具体的な会話の様子はこちら。
会話内容
> @prompt-with-pretty-json.txt からpermalink抽出をするようなテストケースを10件ほど作り、 @promptfooconfig.yaml に書き込みたい。
- いろんなタイプのメッセージ指定
- スレッド内メッセージとスレッド外メッセージ両方満遍なく
- 文字数のバリエーションを満遍なく
と考えた時、まずはどんなテストケースを作ればいいか考えてみて
⏺ おっけー!テストケース考えてみるね!💪
prompt-with-pretty-json.txtのデータ見てみると、100件のメッセージがあって、スレッド返信(thread_tsあり)とスレッド外(thread_tsなし)が混ざってるね。
こんな感じのテストケースどうかなー?✨
番号指定のバリエーション
1. 「最初のメッセージのURLが知りたい」
- 1番目、通常メッセージ、長文(BigQueryの詳細な調査結果)
2. 「2番目のメッセージのURL教えて」
- 2番目、スレッド返信、超短文(「了解です!」)
3. 「3番目のメッセージのURLが知りたい」(既存)
- 3番目、通常メッセージ、中文
4. 「5番目のメッセージ」
- 5番目、スレッド返信、短文(「確認してみます」)
位置指定のバリエーション
5. 「最後のメッセージのURL」
- 100番目、通常メッセージ、中文
6. 「50番目のメッセージのpermalink」
- 中間位置、確認が必要だけど多分通常メッセージ
文字数バリエーション
7. 「7番目のメッセージ」
- 長文メッセージ(デプロイメントプロセスの詳細、改行・箇条書きあり)
8. 「9番目のメッセージ」
- 超短文(「OK」)、スレッド返信
表現のバリエーション
9. 「10個目のメッセージのURLください」
- 「番目」じゃなくて「個目」表現
10. 「20番目のメッセージのSlack URL教えて」
- 「permalink」じゃなくて「URL」表現
こんな感じでどう?🤔
ポイント:
- スレッド返信は2, 4, 8番目で3件
- 通常メッセージは7件
- 短文・中文・長文を満遍なく
- 「番目」「個目」「URL」「permalink」など表現のバリエーションも入れた
実際にpermalinkを構築する前に、この方針でOKか確認したいんだけど、どうかなー?それとも他のパターンも欲しい?😊
> /critical-think is running…
⏺ 1. 核心テーゼと信頼度スコア(初期)
- 1-1. 核心テーゼ: 「番号指定・位置指定・表現のバリエーションを網羅し、スレッド返信と通常メッセージを3:7の比率で、短文・中文・長文を満遍なく含む10件のテストケースを作成する」
- 1-2. 初期信頼度: 7/10(テストケースの方針は妥当だと思ったけど、実際のデータ検証が不十分)
2. 基礎分析:仮定と文脈
- 2-1. 高影響仮定:
a. データの正確性仮定: prompt-with-pretty-json.txtのメッセージが1番目から順番に並んでいると仮定したが、実際にはmatches配列内の順序が何を基準にしているか未検証
b. スレッド比率仮定: 「満遍なく」という要件に対してスレッド返信3件・通常メッセージ7件が適切と判断したが、根拠が不明確
c. permalink構築仮定: 提案したメッセージ番号のpermalinkが実際に正しく構築できるか未検証
- 2-2. 文脈の整合性:
- ユーザーは「いろんなタイプのメッセージ指定」と言っているのに、番号指定に偏りすぎている
- 「文字数のバリエーション」という要件があるのに、実際の文字数を数えていない
- 既存のテストケース(3番目)の形式を踏襲すべきだったが、表現バリエーションを優先しすぎた
3. 論理的整合性分析
- 3-1. 前提の特定:
- 「promptfooのテストケースは多様な入力パターンをカバーすべき」
- 「matches配列のインデックスがそのままメッセージ番号になる」
- 「10件のテストケースで十分な網羅性が得られる」
- 3-2. 推論の連鎖:
- 前提→バリエーション設計→具体的な番号選択という流れに論理的飛躍がある
- 「50番目のメッセージ」を提案したが、「確認が必要だけど多分通常メッセージ」という曖昧な表現で、実際に確認していない
- 「満遍なく」の定義が主観的で、なぜその配分が最適か説明できていない
- 3-3. 潜在的な誤謬:
- 性急な一般化: 既存テストケース1件から全体の方針を決めている
- 確証バイアス: 「番号指定がメイン」と決めつけて、他のメッセージ指定方法(内容ベース、ユーザーベース等)を検討していない
4. AI 特有の落とし穴分析
- 4-1. 問題回避: 不合格 - ユーザーが求めているのは「どんなテストケースを作ればいいか」だが、実際のデータを検証せずに提案している。根本的な問題は「適切なテストケース選定には実データの分析が必要」という点
- 4-2. 「ハッピーパス」バイアス: 不合格 - エッジケースを全く考慮していない。例えば:
- 存在しない番号を指定された場合
- 曖昧な指定(「最近のメッセージ」等)
- 範囲指定(「1-5番目のメッセージ」)
- チャンネル名やユーザー名での指定
- 4-3. 過剰設計: 合格 - シンプルな10件の提案で適切
- 4-4. 事実の正確性と幻覚: 不合格 - 実際にデータを確認せずに「50番目は多分通常メッセージ」と推測している。各番号のメッセージ内容、文字数、thread_tsの有無を検証していない
5. リスクと緩和策分析
- 5-1. 見落とされたリスク:
a. データ構造の誤解: matches配列のインデックスとユーザーの「番目」が一致しない可能性(0-indexedか1-indexedか)
b. permalink構築の失敗: 提案した番号のメッセージが実際に正しいpermalinkを生成できるか未検証のため、assert値が間違っている可能性
c. テストの意図との乖離: promptfooの目的が「モデルの性能評価」なら、もっと難易度の高いケース(曖昧な指定、複雑な条件)を含めるべき
- 5-2. 代替シナリオ:
- 内容ベースの指定: 「BigQueryについて話しているメッセージ」「CVEについてのメッセージ」
- ユーザーベースの指定: 「U012ABC3DEFさんの最初のメッセージ」
- 時間ベースの指定: 「2025年10月のメッセージ」
- チャンネルベースの指定: 「securityチャンネルの2番目のメッセージ」
- エラーケース: 「1000番目のメッセージ」(存在しない)
6. 統合と改訂推奨
- 6-1. 欠陥の要約:
- 実際のデータを読み込んで検証していない
- 番号指定に偏りすぎて、他の指定方法を検討していない
- エッジケースやエラーケースを全く考慮していない
- 「満遍なく」の基準が主観的で根拠がない
- permalink構築の正確性を検証していない
- 6-2. 改訂信頼度スコア: 3/10(データ検証なしで提案したのは重大な欠陥)
- 6-3. 実行可能な次のステップ:
a. 即座に実データを読み込む: prompt-with-pretty-json.txtの1, 2, 3, 5, 7, 9, 10, 20, 50, 100番目のメッセージを実際に確認し、thread_tsの有無、文字数、正しいpermalinkを検証する
b. テストケースの目的を明確化: promptfooで何を評価したいのか(基本的な抽出能力?曖昧な指定への対応?エラーハンドリング?)をユーザーに確認する
c. バリエーションの再設計: 番号指定以外の指定方法(内容・ユーザー・チャンネル・時間ベース)とエッジケースを含めた包括的なテストケースセットを提案する
---
結論: 前回の回答は表面的で、実データの検証を怠り、テストケースの多様性も不足していた。ユーザーに実装させる前に、必ず実データを確認して正確なpermalinkとassert値を提供すべきだったね💦
> > c. テストの意図との乖離: promptfooの目的が「モデルの性能評価」なら、もっと難易度の高いケース(曖昧な指定、複雑な条件)を含めるべき
これが大事だと思うな。
- 5-2. 代替シナリオ:
- 内容ベースの指定: 「BigQueryについて話しているメッセージ」「CVEについてのメッセージ」
- ユーザーベースの指定: 「U012ABC3DEFさんの最初のメッセージ」
- 時間ベースの指定: 「2025年10月のメッセージ」
- チャンネルベースの指定: 「securityチャンネルの2番目のメッセージ」
- エラーケース: 「1000番目のメッセージ」(存在しない)
も考慮して、テストケースを考え直して。
今回はエラーケースはいらないので気にしなくていいよ
⏺ おっけー!じゃあもっと実践的で難易度の高いテストケースを考え直すね!💪
まず実際のデータを確認しながら、いろんな指定方法をカバーするテストケースを作っていくよー!
⏺ Read(prompt-with-pretty-json.txt)
⎿ Read 100 lines
⏺ データが確認できたよ!じゃあ、いろんな難易度と指定方法を網羅したテストケースを考えてみるね!✨
まず、主要なパターンを整理してみた:
テストケース案(10件)
1. シンプルな番号指定(既存、難易度:低)
input: "3番目のメッセージのURLが知りたい"
expected: https://example.slack.com/archives/C02DEF3GH/p1757647893504629
- index 2, 通常メッセージ、devチャンネル
2. 内容ベース:特定技術名(難易度:中)
input: "BigQueryについて話しているメッセージのURL"
expected: https://example.slack.com/archives/C01ABC2DE/p1756096495765749
- index 0, 通常メッセージ、長文、generalチャンネル
3. 内容ベース:CVE番号含む(難易度:中-高)
input: "CVEについて報告しているメッセージ"
expected: https://example.slack.com/archives/C08VWX9YZ/p1758677875911179
- index 19, 通常メッセージ、長文、securityチャンネル
4. ユーザー名ベース(難易度:中-高)
input: "U089VWX0YZAさんが最初に投稿したメッセージのURL"
expected: https://example.slack.com/archives/C08VWX9YZ/p1757324832945909
- index 9, 通常メッセージ、securityチャンネル
5. チャンネル名ベース(難易度:中)
input: "securityチャンネルの最初のメッセージ"
expected: https://example.slack.com/archives/C08VWX9YZ/p1757324832945909
- index 9, 通常メッセージ
6. チャンネル名+順序(難易度:中)
input: "devチャンネルの2番目のメッセージのURL"
expected: https://example.slack.com/archives/C02DEF3GH/p1759403650647349
- index 13, 通常メッセージ、長文(バグ修正のPR)
7. 複合条件:チャンネル+内容(難易度:高)
input: "securityチャンネルでCVEについて話しているメッセージ"
expected: https://example.slack.com/archives/C08VWX9YZ/p1758677875911179
- index 19, 通常メッセージ
8. 複合条件:ユーザー+チャンネル+順序(難易度:最高)
input: "U023DEF4GHIさんがdevチャンネルに投稿した最初のメッセージ"
expected: https://example.slack.com/archives/C02DEF3GH/p1757647893504629
- index 2, 通常メッセージ
9. スレッド返信(難易度:中)
input: "2番目のメッセージのURL"
expected: https://example.slack.com/archives/C01ABC2DE/p1756096501234567?thread_ts=1756096495.765749&channel=C01ABC2DE&message_ts=1756096501.234567
- index 1, スレッド返信、超短文(「了解です!」)
10. 内容ベース:特定の技術フレーズ(難易度:中)
input: "Blue-Greenデプロイメントについて検討しているメッセージ"
expected: https://example.slack.com/archives/C05MNO6PQ/p1755237886747309
- index 6, 通常メッセージ、長文、devopsチャンネル
バリエーションの内訳
- 番号指定: 2件(#1, #9)
- 内容ベース: 3件(#2, #3, #10)
- ユーザーベース: 1件(#4)
- チャンネルベース: 2件(#5, #6)
- 複合条件: 2件(#7, #8)
- 通常メッセージ: 9件
- スレッド返信: 1件
- 短文: 1件
- 中文: 4件
- 長文: 5件
どう?この方針で行ってみていい?それとも他に追加したいパターンある?😊
> めちゃくちゃいろんなパターンがあっていいね。ただスレッド返信系を3件ほどにしてほしい
⏺ おっけー!スレッド返信を3件に増やすね!💪
じゃあ、テストケースを再構成してみるよー!
改訂版テストケース案(10件)
1. シンプルな番号指定・通常メッセージ(難易度:低)
input: "3番目のメッセージのURLが知りたい"
expected: https://example.slack.com/archives/C02DEF3GH/p1757647893504629
- index 2, 通常メッセージ、中文、devチャンネル
2. 内容ベース:特定技術名(難易度:中)
input: "BigQueryについて話しているメッセージのURL"
expected: https://example.slack.com/archives/C01ABC2DE/p1756096495765749
- index 0, 通常メッセージ、長文、generalチャンネル
3. 内容ベース:CVE番号含む(難易度:中-高)
input: "CVEについて報告しているメッセージ"
expected: https://example.slack.com/archives/C08VWX9YZ/p1758677875911179
- index 19, 通常メッセージ、長文、securityチャンネル
4. スレッド返信:シンプルな番号指定(難易度:低)
input: "2番目のメッセージのURL"
expected: https://example.slack.com/archives/C01ABC2DE/p1756096501234567?thread_ts=1756096495.765749&channel=C01ABC2DE&message_ts=1756096501.234567
- index 1, スレッド返信、超短文(「了解です!」)、generalチャンネル
5. スレッド返信:内容ベース(難易度:中)
input: "「確認してみます」と返信しているメッセージ"
expected: https://example.slack.com/archives/C03GHI4JK/p1759124091523456?thread_ts=1759124084.416529&channel=C03GHI4JK&message_ts=1759124091.523456
- index 4, スレッド返信、短文、tech-talkチャンネル
6. スレッド返信:チャンネル+内容ベース(難易度:中-高)
input: "infrastructureチャンネルで「いいですね」と返信しているメッセージ"
expected: https://example.slack.com/archives/C09YZA0BC/p1755685842123456?thread_ts=1755685836.962989&channel=C09YZA0BC&message_ts=1755685842.123456
- index 11, スレッド返信、短文、infrastructureチャンネル
7. チャンネル名ベース(難易度:中)
input: "securityチャンネルの最初のメッセージ"
expected: https://example.slack.com/archives/C08VWX9YZ/p1757324832945909
- index 9, 通常メッセージ、中文、securityチャンネル
8. チャンネル名+順序(難易度:中)
input: "devチャンネルの2番目のメッセージのURL"
expected: https://example.slack.com/archives/C02DEF3GH/p1759403650647349
- index 13, 通常メッセージ、長文(バグ修正のPR)、devチャンネル
9. 複合条件:ユーザー+チャンネル+順序(難易度:最高)
input: "U023DEF4GHIさんがdevチャンネルに投稿した最初のメッセージ"
expected: https://example.slack.com/archives/C02DEF3GH/p1757647893504629
- index 2, 通常メッセージ、中文、devチャンネル
10. 内容ベース:特定の技術フレーズ(難易度:中)
input: "Blue-Greenデプロイメントについて検討しているメッセージ"
expected: https://example.slack.com/archives/C05MNO6PQ/p1755237886747309
- index 6, 通常メッセージ、長文、devopsチャンネル
改訂版バリエーションの内訳
- 番号指定: 2件(#1通常, #4スレッド)
- 内容ベース: 4件(#2, #3通常, #5, #6スレッド)
- チャンネルベース: 2件(#7, #8)
- 複合条件: 1件(#9)
- 技術フレーズ: 1件(#10)
- 通常メッセージ: 7件
- スレッド返信: 3件 ✨
- 短文: 3件(うちスレッド返信2件)
- 中文: 4件
- 長文: 3件
これでどうかな?スレッド返信も難易度のバリエーションをつけてみたよ!😊
> 良さそうだね。ではこの内容を使って、extract-slack-url-eval/promptfooconfig.yaml のテストケースを拡充してほしい。
⏺ おっけー!promptfooconfig.yaml にテストケース追加するね!✨
まず現在のファイル確認してから、10件のテストケースを追加するよー!
⏺ Read(promptfooconfig.yaml)
⎿ Read 22 lines
⏺ おっけー、既存のフォーマット確認できたよ!
ちょっと待って、既存の YAML のフォーマットが少し気になるんだけど...😅
現在の設定だと assert が vars の中に入ってるけど、promptfoo の正しいフォーマットだと assert は vars と同じインデントレベルにあるべきなんだよね。
こんな感じ:
tests:
- vars:
input: "..."
assert:
- type: equals
value: '...'
このフォーマットで修正して、10件のテストケースを追加してもいい?それとも既存のフォーマットのまま進める?🤔
> ほんまや。それで進めてほしい。また各テストケースには、どんなテストケースかコメントで説明もしておいてほしい。内容ベース:特定の技術フレーズ(難易度:中)みたいなやつ
⏺ おっけー!正しいフォーマットで、コメント付きでテストケースを書き直すね!💪
⏺ Update(promptfooconfig.yaml)
⎿ Updated promptfooconfig.yaml with 67 additions and 3 removals
14
15
16 tests:
17 + # 1. シンプルな番号指定・通常メッセージ(難易度:低)
18 - vars:
19 input: "3番目のメッセージのURLが知りたい"
20 - assert:
21 - - type: equals
22 - value: 'https://example.slack.com/archives/C02DEF3GH/p1757647893504629'
20 + assert:
21 + - type: equals
22 + value: 'https://example.slack.com/archives/C02DEF3GH/p1757647893504629'
23 +
24 + # 2. 内容ベース:特定技術名(難易度:中)
25 + - vars:
26 + input: "BigQueryについて話しているメッセージのURL"
27 + assert:
28 + - type: equals
29 + value: 'https://example.slack.com/archives/C01ABC2DE/p1756096495765749'
30 +
31 + # 3. 内容ベース:CVE番号含む(難易度:中-高)
32 + - vars:
33 + input: "CVEについて報告しているメッセージ"
34 + assert:
35 + - type: equals
36 + value: 'https://example.slack.com/archives/C08VWX9YZ/p1758677875911179'
37 +
38 + # 4. スレッド返信:シンプルな番号指定(難易度:低)
39 + - vars:
40 + input: "2番目のメッセージのURL"
41 + assert:
42 + - type: equals
43 + value: 'https://example.slack.com/archives/C01ABC2DE/p1756096501234567?thread_ts=1756096495.765749&channel=C01ABC2DE&message_ts=1756096501.234567'
44 +
45 + # 5. スレッド返信:内容ベース(難易度:中)
46 + - vars:
47 + input: "「確認してみます」と返信しているメッセージ"
48 + assert:
49 + - type: equals
50 + value: 'https://example.slack.com/archives/C03GHI4JK/p1759124091523456?thread_ts=1759124084.416529&channel=C03GHI4JK&message_ts=1759124091.523456'
51 +
52 + # 6. スレッド返信:チャンネル+内容ベース(難易度:中-高)
53 + - vars:
54 + input: "infrastructureチャンネルで「いいですね」と返信しているメッセージ"
55 + assert:
56 + - type: equals
57 + value: 'https://example.slack.com/archives/C09YZA0BC/p1755685842123456?thread_ts=1755685836.962989&channel=C09YZA0BC&message_ts=1755685842.123456'
58 +
59 + # 7. チャンネル名ベース(難易度:中)
60 + - vars:
61 + input: "securityチャンネルの最初のメッセージ"
62 + assert:
63 + - type: equals
64 + value: 'https://example.slack.com/archives/C08VWX9YZ/p1757324832945909'
65 +
66 + # 8. チャンネル名+順序(難易度:中)
67 + - vars:
68 + input: "devチャンネルの2番目のメッセージのURL"
69 + assert:
70 + - type: equals
71 + value: 'https://example.slack.com/archives/C02DEF3GH/p1759403650647349'
72 +
73 + # 9. 複合条件:ユーザー+チャンネル+順序(難易度:最高)
74 + - vars:
75 + input: "U023DEF4GHIさんがdevチャンネルに投稿した最初のメッセージ"
76 + assert:
77 + - type: equals
78 + value: 'https://example.slack.com/archives/C02DEF3GH/p1757647893504629'
79 +
80 + # 10. 内容ベース:特定の技術フレーズ(難易度:中)
81 + - vars:
82 + input: "Blue-Greenデプロイメントについて検討しているメッセージ"
83 + assert:
84 + - type: equals
85 + value: 'https://example.slack.com/archives/C05MNO6PQ/p1755237886747309'
⏺ 完成したよ!✨
promptfooconfig.yaml に10件のテストケースを追加できたよ!
追加したテストケースの内訳:
1. ✅ シンプルな番号指定・通常メッセージ(難易度:低)
2. ✅ 内容ベース:特定技術名(難易度:中)
3. ✅ 内容ベース:CVE番号含む(難易度:中-高)
4. ✅ スレッド返信:シンプルな番号指定(難易度:低)
5. ✅ スレッド返信:内容ベース(難易度:中)
6. ✅ スレッド返信:チャンネル+内容ベース(難易度:中-高)
7. ✅ チャンネル名ベース(難易度:中)
8. ✅ チャンネル名+順序(難易度:中)
9. ✅ 複合条件:ユーザー+チャンネル+順序(難易度:最高)
10. ✅ 内容ベース:特定の技術フレーズ(難易度:中)
主な変更点:
- YAMLフォーマットを修正(assertをvarsと同じインデントレベルに)
- 各テストケースに難易度と種類のコメントを追加
- スレッド返信のpermalinkにはクエリパラメータ付き
- 通常メッセージ7件、スレッド返信3件のバランス
これでいろんなパターンのテストができるようになったよ!😊
まとめ
今回は、前回の記事の検証時にテストデータやテストケースをどのように作っていったかを共有した。AIによってテストデータも素早く作れて助かる。