ストアの多言語説明文を直す日の朝、私は前日のメモをそのままエージェントに貼りました。箇条書きが三十行ほど、思いつきの順に並んだメモです。返ってきた結果は、丁寧で、長くて、そして私が欲しかったものとは少しずつずれていました。
直してもらい、またずれて、三往復目でようやく気づきました。ずれていたのはエージェントではなく、私の頼み方だったのです。メモには「何が起きているか」は書いてあっても、「何を、どこまで、どんな形で欲しいか」が書かれていませんでした。
最初にお伝えしたいのは、依頼文は長くするより畳むほうが手戻りが減る、ということです。ここから、私が使っている5行の型と、その型を機械的に確かめる小さなスクリプトを書き残します。コードを書かない作業にも、そのまま使えます。
長いメモが手戻りを生む理由
メモは自分のための記録です。経緯、迷い、途中で捨てた案まで入っていて、読み返す私には意味が通じます。ところが、初めて読むエージェントには、どの行が「依頼」でどの行が「背景」なのか見分けがつきません。
結果として何が起きるか。全部の行を同じ重さで受け取り、全部に応えようとします。三十行に応えた文章が、長くて平らになるのは当然でした。
もう一つ、見落としやすい点があります。メモにはやらないことが書かれていません。「この言語の説明文は触らないでほしい」は、私の頭の中では自明でも、紙の上には存在しないのです。
5行の型
私は頼みごとを、次の5行に畳んでから渡しています。順番にも意味があります。
| 行 | 書くこと | 空欄のときに起きること |
|---|---|---|
| 1. 目的 | 何のために、誰に向けて | 丁寧だが的外れな文章が返る |
| 2. 材料 | 読んでほしいファイルや文章 | 推測で補われ、事実が混ざる |
| 3. 範囲 | 触ってよいもの・触らないもの | 頼んでいない箇所まで直される |
| 4. 完成形 | 返してほしい形(表、差分、一覧など) | 読み解く作業がこちらに戻る |
| 5. 確認 | 終わる前に見せてほしいもの | どこが変わったか追えない |
5行目の「確認」だけは、少し説明が要ります。ここには結果の品質ではなく、私が確かめる入口を書きます。たとえば「変更した箇所の一覧を先に見せてください」「迷った箇所は決めずに質問してください」といった一文です。
Before / After — 多言語説明文の更新
冒頭の依頼を、5行に畳み直してみます。まず、貼ってしまったメモの一部です。
- 説明文が古い気がする
- 英語は前に直した
- ドイツ語とフランス語もたぶん直したい
- 壁紙の枚数は増えている
- レビューで「広告が多い」と言われた
- 日本語は触らない(これは確か)
...(以下20行ほど)これを畳むと、次のようになりました。
1. 目的: 壁紙アプリのストア説明文を、最近の更新内容に合わせて読みやすくしたい。読者は初めて見る人。
2. 材料: store/ja.md(正本)と、store/de.md・store/fr.md の現行文。
3. 範囲: de と fr の説明文だけ。ja は触らない。アプリ名と法的な記載も触らない。
4. 完成形: 現行文と新案を左右に並べた表。変えた理由を1行ずつ添えて。
5. 確認: 書き換える前に、変える予定の段落の一覧を見せて。迷う表現は決めずに質問して。同じ内容なのに、返ってくるものがまるで違いました。表で戻ってくるので、私は新案を一段落ずつ読めばよく、触っていない言語が変わっていないことも一目で分かります。
依頼文は、相手が迷う余地を先に私が引き受ける文章です。
5行がそろっているか確かめる
型を知っていても、忙しい日は4行で渡してしまいます。私自身、「範囲」を飛ばした日に限って手戻りが増えました。そこで、渡す前に5行が埋まっているかを確かめる小さなスクリプトを置いています。
何を解決するか。番号付きの5項目が、空欄や「あとで」のまま残っていないかを、渡す前に機械的に拾います。
#!/usr/bin/env python3
"""brief_check.py — 依頼文の5項目がそろっているか確かめる。
使い方: python3 brief_check.py brief.txt
終了コード: 0 = そろっている / 1 = 不足あり
"""
import re
import sys
LABELS = ["目的", "材料", "範囲", "完成形", "確認"]
PLACEHOLDERS = {"", "あとで", "後で", "未定", "tbd", "todo", "-", "なし"}
def parse(text: str) -> dict:
"""「1. 目的: 本文」形式の行を拾って {ラベル: 本文} にする。"""
found = {}
for line in text.splitlines():
m = re.match(r"^\s*\d+[.).]\s*([^::]+)[::]\s*(.*)$", line)
if m:
found[m.group(1).strip()] = m.group(2).strip()
return found
def main(path: str) -> int:
with open(path, encoding="utf-8") as f:
items = parse(f.read())
problems = []
for label in LABELS:
body = items.get(label)
if body is None:
problems.append(f"{label}: 行がありません")
elif body.lower() in PLACEHOLDERS:
problems.append(f"{label}: 中身が空のままです")
elif len(body) < 8:
problems.append(f"{label}: 短すぎます({len(body)}字)。具体を足してください")
if problems:
print("渡す前に見直してください:")
for p in problems:
print(f" - {p}")
return 1
print("5項目そろっています。")
return 0
if __name__ == "__main__":
if len(sys.argv) != 2:
print(__doc__)
sys.exit(2)
sys.exit(main(sys.argv[1]))なぜ8字の下限を置いたのか。「範囲: de と fr だけ」のように、短くても意味が通じる行は確かにあります。それでも、短すぎる行の多くは「書いたつもり」で止まっていました。立ち止まるきっかけとしては、このくらいの粗さがちょうどよいと考えています。
「範囲」の行でつまずいたときの3つの書き方
5行のうち、いちばん空欄になりやすいのが3行目です。何を書けばよいか分からないときは、次の3つの型から選びます。
一つ目は対象を名指しする書き方です。「de と fr の説明文だけ」のように、触ってよいものを先に挙げます。二つ目は除外を名指しする書き方で、「ja とアプリ名は触らない」と、触らないものだけを挙げます。三つ目は変える量を縛る書き方です。「1段落につき2文まで」のように、直しの大きさに上限を置きます。
私は最初、除外だけを書いていました。すると、除外に載っていない場所が広く直されてしまうのです。いまは対象と除外の両方を1行に収めるようにしています。長くなるときは、対象のほうを優先します。
5行にしても残るもの
型を使っても、全部が解決するわけではありません。背景が重要な依頼では、5行に畳むことで、かえって大事な事情が落ちることがあります。
そのときは、背景を6行目に足すのではなく、2行目の「材料」にファイルとして渡します。依頼と背景を分けておけば、エージェントはどちらが指示で、どちらが参考かを迷いません。
もう一つ。5行の型は、小さな作業ほど効きます。数日にわたる大きな作業では、1回の依頼を5行に収まる大きさまで割るところから始めるほうが、うまくいきました。
明日から試すなら
次に何かを頼む前に、メモを貼る手を止めて、「範囲」の1行だけを先に書いてみてください。触らないものを言葉にするだけで、返ってくる結果の輪郭が変わります。
残りの4行は、その1行に引かれて自然に埋まっていくはずです。私もいまだに、急いだ日には飛ばしてしまいます。だからスクリプトを置いているのです。