Skip to content

執筆プロセス検出

Potatoのキーストロークログを、貼り付け・書き写し・機械生成された自由記述回答の検証可能なフラグに変えます。閾値は読むことも上書きすることもできます。

執筆プロセス検出は、キーストロークロギングが取得したタイピングの動態を読み、根拠を添えた名前付きフラグを生成します。どの特徴量の値が各フラグを発火させたかを確認でき、納得できないものは捨てられます。

Potato 2.7.2以降が必要で、キーストロークロギングが既に有効なプロジェクトでのみ動作します。keystroke_logging.enabledのデフォルトはfalseなので、一度も有効にしていないプロジェクトには検出する対象がありません。

警告: フラグは人がレビューするための材料です。不正の証明ではありませんし、自動的な却下、報酬の差し止め、参加者のアカウント停止に結び付けてはいけません。速く流暢に打つ人がきれいな初稿を書けば、それは実際に書き写しと似ます。スマートフォンで作業しているアノテーターは、実際に貼り付けをした人と似ます。以下のルールはそうした衝突を減らすように作られていますが、それでも衝突は起こります。偽陽性のセクションは、免責事項ではなくこの機能の一部です。

3つの層

内容ラベル付きデータが必要かデフォルト
1. ルール明示的な閾値と可視の根拠を持つ6つの名前付きフラグいいえオン
2. キャリブレーション自分のプロジェクトのアノテーターに合わせて再フィットした閾値いいえオフ
3. 教師あり自分のラベルで学習させる分類器はいオフ

Potatoに学習済みモデルは同梱されていません。リポジトリにラベル付きコーパスがないため、係数を同梱すれば、それはこちらででっち上げた検証値と一緒に届くことになります。代わりに、読んで議論できる6つのルールが手に入ります。実際のラベルがあるなら、文献の精度を再現する道筋は第3層です。

第1層:ルール

どのフラグも発火の根拠となった特徴量の値を返すので、個々のフラグについて妥当性を主張することも、捨てることもできます。

paste_dominant

深刻度:suspect。pasted_fraction >= 0.5のとき、つまり最終テキストの半分以上が貼り付けで入ったときに発火します。

すべての貼り付けがself(自分の下書きの並べ替え)またはinstance_text(アノテーション対象の文章の引用)に分類された場合は抑制されます。

silent_insertion

深刻度:suspect。external_insert_ratio >= 0.3のとき、つまり挿入された文字のうち3分の1近くに対応するキーストロークがなかったときに発火します。

これは単独の信号としては最も価値の高いものです。貼り付け、オートフィル、音声入力、プログラムによる注入はすべてここに現れます。貼り付けイベント自体がページ側で抑制されている場合でも同じです。Asherらが言う「回答の長さに対してキーストローク数が異常に少ない」を直接そのまま実装したものです。

ソフトキーボード(virtual_keyboard)とIMEでの変換中は抑制されます。これらではkeydownが確実には発生せず、そうしなければすべての挿入が無音に見えてしまうためです。このルールはソースを考慮した比率を使うので、正当な引用は数えられません。

transcription_rhythm

深刻度:review。次の3つがすべて成り立ったときに発火します。

  • iki_log_cv <= 0.06、一定のリズムのタイピング
  • revision_ratio <= 0.02、削除がほぼない
  • 100文字あたり2秒以上のポーズが0.5回未満

連言にしているのは設計上の判断です。どれか1つだけなら、それぞれ問題のない読み方ができます。3つが揃ったとき、Crossleyらが述べる書き写しの特徴、つまり直線的でバースト中心、ばらつきが小さいという形になります。

読み取れるリズムがない80文字未満または40キーストローク未満の回答は、最初から対象外です。

offscreen_composition

深刻度:suspect。ページから10秒以上離れた直後に、外部由来の大きな挿入(80文字以上)があったときに発火します。「ChatGPTに切り替えて、戻ってきて、貼り付けた」というパターンです。

挿入のソースが対象の文章またはアノテーター自身のテキストだった場合は抑制されます。席を外してから文章を引用するのはごく普通の振る舞いだからです。

implausible_speed

深刻度:review。回答全体を通じて毎分900文字(およそ180 wpm)を超え続けたときに発火します。

synthetic_input

深刻度:suspect。isTrusted === falseのイベントがあったときに発火します。これは、その入力が人ではなくスクリプトによって生成されたとブラウザが報告している状態です。ブラウザの自動操作、注入されたスクリプト、一部のアクセシビリティツールがこれを生じさせます。

判定レベル

レベル意味
okフラグは発火しなかった
reviewreview深刻度のフラグが1つ以上
suspectsuspect深刻度のフラグが1つ以上

閾値の上書き

yaml
keystroke_logging:
  detection:
    thresholds:
      paste_dominant.pasted_fraction: 0.4
      silent_insertion.ratio: 0.25
      transcription_rhythm.iki_log_cv: 0.05
      transcription_rhythm.revision_ratio: 0.02
      transcription_rhythm.pause_2s_per_100_chars: 0.5
      offscreen_composition.blur_ms: 15000
      offscreen_composition.insert_chars: 100
      implausible_speed.chars_per_min: 1000

閾値はサーバー側で評価され、ブラウザには一切送られません。公開すれば、フラグに引っかからないためにはどのくらいゆっくり貼り付ければよいかを、アノテーターに正確に教えることになります。

第2層:プロジェクトごとのキャリブレーション

キーストロークの特徴量は執筆課題によって大きく変わり(Conijnら 2019)、混合分布に従う量に対する固定閾値には偏りが生じます(Roeserら 2021)。1文の根拠説明でうまくいくカットオフは、5段落のエッセイには合いません。

キャリブレーションは、各閾値を自分のプロジェクトのセッションの裾のパーセンタイルに設定します。

bash
# Inspect the fit without saving it
python -m potato.typing_detect calibrate config.yaml --dry-run
 
# Save it
python -m potato.typing_detect calibrate config.yaml
yaml
keystroke_logging:
  detection:
    calibrate: true    # use the saved fit

キャリブレーションには使用可能なセッションが最低30件必要です(80文字以上、モバイル以外)。それを下回るとinsufficient_dataを返し、デフォルト値がそのまま使われます。

警告: パーセンタイルによるカットオフは、相対的な外れ値の定義です。その性質上、誰も不正をしていない集団であっても、およそtail_fraction(デフォルト5%)のセッションにフラグが立ちます。どこから見ればよいかを教えてくれるだけで、証拠ではありません。さらにキャリブレーション後の閾値は組み込みデフォルトの3倍以内に収められるため、均質な集団がカットオフを自分たちの中央値まで引き寄せて正直なアノテーターにフラグを立て始めることはありません。

明示的なthresholds:の上書きは常にキャリブレーション値に優先し、キャリブレーション値は常に組み込みデフォルトに優先します。

第3層:教師あり分類器

ラベル付きのセッションがあるなら、実際のモデルを学習させてください。

python
from potato import typing_store
from potato.typing_detect import fit_supervised
 
rows = typing_store.feature_matrix(task_dir, project)
labels = [...]   # 1 = non-composed, 0 = composed
 
result = fit_supervised(rows, labels, model="random_forest")
print(result["cv_accuracy_mean"], result["feature_importances"])

scikit-learnが必要ですが、遅延インポートされ、Potatoの依存関係には入っていません。

外部の研究なしにラベルを得る

Potatoのトレーニングフェーズでラベルを作れます。ウォームアップの課題として、用意した文章を書き写すようアノテーターに依頼してください。その書き写しのセッションは本物の書き写しの実例になり、通常の回答が作成の実例になります。こうして、自分のプロジェクトの中で、自分のタスクで、自分のアノテーターによるラベル付きデータが得られます。これはCrossleyらがコーパスを作った方法と同じで、キャリブレーションの例にこの手順が一通り用意されています。

偽陽性

この機能の失敗の形は、正直なアノテーターを咎めてしまうことです。以下は、上記のパターンに正当な理由で似てしまうケースです。

状況似てしまうルールPotatoの扱い
アノテーション対象の文章を引用するpaste_dominantsilent_insertionoffscreen_compositionpaste_source: instance_textにより抑制
自分の下書きを動かす同上paste_source: selfにより抑制
スマートフォンやタブレットでの入力silent_insertionvirtual_keyboardにより抑制
IMEによる非ラテン文字の入力silent_insertioncomposition_eventsにより抑制
速く流暢なタイピストのきれいな初稿transcription_rhythmimplausible_speed連言のルール、suspectではなくreview、キャリブレーション
非常に短い回答transcription_rhythm80文字/40キーストローク未満は対象外
音声入力や音声認識silent_insertion未対応。フラグが立ちます。該当するアノテーターを除外するか、閾値を上げてください。
スクリーンリーダーや一部の支援技術synthetic_input完全には対応できていません。一部のツールは信頼されないイベントを生成します。
モバイルの自動修正silent_insertion部分的に対応。insertReplacementTextは外部として数えられます。
文法チェックなどのブラウザ拡張機能silent_insertionsynthetic_input未対応。フラグが立ちます。

最後の4つは見落としではなく、実際の制約です。参加者に音声入力の利用者、支援技術の利用者、執筆用の拡張機能を使う人が含まれるなら、レビュー基準からそれらのルールを外すか、どのフラグも行動を起こす根拠ではなくアノテーターに尋ねるきっかけとして扱ってください。

アクセシビリティ

synthetic_inputisTrustedを手がかりにしていますが、一部の支援技術もこれに触れます。仕事に必要な道具を使っている障害のあるアノテーターにフラグを立てることは、受け入れられない結果です。

このルールに閾値はないので、到達不能にできる値もありません。支援技術の利用者に開かれた研究であれば、書き下すレビュー基準からsynthetic_inputを除くか、検出そのものをオフにして、エクスポートした特徴量を自分で分析してください。

yaml
keystroke_logging:
  enabled: true
  detection:
    enabled: false

閾値のあるルールは、極端なカットオフを設定すれば到達不能にできます。例えばimplausible_speed.chars_per_min: 1000000です。

リアルタイムの介入

yaml
keystroke_logging:
  detection:
    on_external_insert: flag   # allow | warn | block | flag
振る舞い
allow記録する以外は何もしない
warn外部からの貼り付け時に、操作を妨げない通知を出す。自分のテキストや対象文章の引用では出さない
block計測対象のフィールドへの貼り付けとドロップを禁止する
flagデフォルト。黙って記録し、判断は後で行う

blockは大雑把な手段です。正当な引用も同時に止めますし、その気になれば参加者は手で打ち直せます。flagにしておいて後からレビューするほうが、たいていは良い選択です。

管理者ダッシュボード

管理者ダッシュボードの行動タブにある執筆プロセスパネルには、アノテーター別の中央値、貼り付け率、無音挿入率、そしてフラグが立ったすべてのセッションが根拠付きで表示されます。

ここではwriting_process_riskを報告します。これは、あるユーザーのセッションのうち各フラグが発火した割合を、問題のない説明が付きにくい信号ほど重く重み付けしたものです。並べ替えの補助であり、既存のsuspicion_scoreとは意図的に分けてあります。どちらかの数値が他方の意味をひそかに変えてしまわないようにするためです。

研究上の裏付け

以下の引用文献はすべてCrossrefまたはDataCiteのレジストリで確認しています。

Crossley、Tian、Choi、Holmes、Morris(2024)は500本の議論文エッセイを集め、別のワーカーにそれを書き写させた上で、ランダムフォレストによって本人の執筆と書き写しを99%の精度で分離しました(他のモデルでは96〜98%)。彼らが使った特徴量のまとまりが、Potatoが取得しているものです。文と単語の前のポーズ時間、挿入と削除の回数、プロダクト対プロセスの比率、バースト、修正、プロセスのばらつき。彼らの知見が設計上の目標になっています。本人の執筆ではポーズが長く、挿入と削除が多く、ばらつきが大きい。書き写しは直線的でバースト中心である、というものです。

Deane、Zhang、Hao、Liと、別途Zhang、Feng、He、Li、Zhuは、書き写しと自然な執筆の分離をそれぞれ独立に確認しており、後者は深層学習モデルによるものです。Asher、Gold、Chen、Carvalhoはクラウドソーシングに特化した事例で、Prolific上のキーストロークツールが、回答欄に貼り付けた参加者や、回答の長さに対してキーストローク数が異常に少ない参加者にフラグを立てています。

その基礎となるプロセス指標については、標準的なログ指標についてLeijten and Van Waes(Inputlog)、バーストという概念についてChenoweth and Hayes、キーストローク特徴量の課題依存性についてConijn, Roeser and van Zaanen、固定的なポーズ閾値に偏りが生じる理由についてRoeser, De Maeyer, Leijten and Van Waesを参照してください。

References

  1. Crossley, S., Tian, Y., Choi, J. S., Holmes, L., & Morris, W. (2024). Plagiarism Detection Using Keystroke Logs. EDM 2024 (Short Papers). doi:10.5281/zenodo.12729864
  2. Deane, P., Zhang, M., Hao, J., & Li, C. Using Keystroke Dynamics to Detect Nonoriginal Text. Journal of Educational Measurement, 63(1). doi:10.1111/jedm.12431
  3. Asher, M. W., Gold, G., Chen, E., & Carvalho, P. F. (2026). Chatbots Are Undermining Crowdsourced Research in the Behavioral Sciences: Detecting Artificial Intelligence-Assisted Cheating With a Keystroke-Based Tool. Advances in Methods and Practices in Psychological Science, 9(1). doi:10.1177/25152459261424723
  4. Zhang, M., Feng, L., He, X., Li, C., & Zhu, M. (2026). Disentangling copy typing and natural writing behaviors using keystroke logs and deep learning model. Assessing Writing. doi:10.1016/j.asw.2026.101070
  5. Leijten, M., & Van Waes, L. (2013). Keystroke Logging in Writing Research: Using Inputlog to Analyze and Visualize Writing Processes. Written Communication, 30(3), 358-392. doi:10.1177/0741088313491692
  6. Chenoweth, N. A., & Hayes, J. R. (2001). Fluency in Writing: Generating Text in L1 and L2. Written Communication, 18(1), 80-98. doi:10.1177/0741088301018001004
  7. Conijn, R., Roeser, J., & van Zaanen, M. (2019). Understanding the keystroke log: the effect of writing task on keystroke features. Reading and Writing, 32(9), 2353-2374. doi:10.1007/s11145-019-09953-8
  8. Roeser, J., De Maeyer, S., Leijten, M., & Van Waes, L. (2021). Modelling typing disfluencies as finite mixture process. Reading and Writing. doi:10.1007/s11145-021-10203-z
  9. Lee, M., Liang, P., & Yang, Q. (2022). CoAuthor: Designing a Human-AI Collaborative Writing Dataset for Exploring Language Model Capabilities. CHI 2022. doi:10.1145/3491102.3502030

参考情報

実装の詳細については、ソースドキュメントを参照してください。