プロンプトエンジニアリング

プロンプトエンジニアリングでは、モデル呼び出し以前に入力設計と評価設計を固める習慣を作ります。

同じモデルでも、入力の置き方で仕事のしやすさが変わる

LLM は魔法の黒箱ではなく、与えられた入力から次トークンを選ぶ機械です。だから、何を先に書き、何を制約として固定し、何を参考文脈として渡すかで、かなり素直に挙動が変わります。

このノートでは、まず入力長の感覚をつかみ、そのあとで制約付きプロンプト、参考文脈の差し込み、簡易評価、コスト見積もりへ進みます。狙いは「良い prompt を当てる」ことではなく、入力設計を反復改善できる形にすることです。

中心にあるのは、指示を書くことより仕様を作ること

短い依頼文をその場で思いつくより、期待する出力形式、禁止事項、評価軸を先に決めた方が改善が速くなります。この notebook では prompt engineering を文章術ではなく、入出力仕様の設計として扱います。

まず見るのは token ではなく、入力予算です

長すぎる入力はコストも品質も崩します。最初の節では粗い近似しか使いませんが、それでも「何を残して何を削るべきか」を考える癖を作るには十分です。

制約は窮屈にするためではなく、モデルの迷いを減らすために書く

出力形式、含める観点、長さ、根拠の要求を明示すると、モデルは探索範囲を狭められます。後半では、その制約が本当に回答品質を整えているかを軽い評価で確かめます。

この notebook では、評価も軽量に回す

ここで使う採点は本格ベンチマークではありません。ただ、毎回人手で全文を読み切らなくても改善方向を揃えられるように、簡易チェックを先に置いています。

先に全体像を言うと、良い prompt は単独で完結しない

入力長の管理、文脈の入れ方、出力チェック、コスト見積もりまで含めて運用設計です。以後の tool-use-ragfine-tuning は、この設計で埋まらない部分を別の手段で補う notebook だと考えてください。

検証 1: トークン近似を体験する

最初に、入力長とトークン量の関係を簡易計測します。コスト管理の第一歩です。

text = '大規模言語モデルは文脈の与え方で応答品質が大きく変わる。'
char_len = len(text)
space_tokens = text.split()
rough_tokens = max(1, char_len // 2)
print('chars=', char_len, 'space_tokens=', len(space_tokens), 'rough_tokens=', rough_tokens)

厳密なトークン化ではありませんが、入力を短く保つ設計感覚を作るには十分です。

検証 2: 制約付きプロンプト設計

プロンプトは長く書くより、制約を明確化する方が効果的です。ここではテンプレート化を練習します。

task = '連鎖律を初学者向けに説明する'
rules = ['120字以内', '式は1つまで', '最後に確認問題を1問']
template = f"課題: {task}\n制約: {'; '.join(rules)}\n出力形式: 段落1つ"
print(template)
print('template_len=', len(template))

この設計は生成APIを呼ばなくても、入力仕様の品質点検として価値があります。

定義の確認

  1. pθ(xtx<t)p_{\theta}(x_t \mid x_{<t})
  2. LCE=tlogpθ(xtx<t)L_{CE} = -\sum_t \log p_{\theta}(x_t \mid x_{<t})

検証 3: 検索文脈を結合する

ここで RAG の最小形を実装します。質問と関連文を結合し、回答入力を作る流れを確認します。

question = 'ベルマン方程式を高校生向けに説明して'
retrieved = ['価値は将来報酬の割引和で定義する', '現在価値は次状態価値で再帰的に更新できる']
context = '\n'.join(f'- {c}' for c in retrieved)
final_input = f"質問:\n{question}\n\n参考文脈:\n{context}\n\n回答:"
print(final_input)

検索文脈を入れる目的は、モデルの記憶に頼りすぎないことです。根拠付き応答を作りやすくなります。

検証 4: 評価項目を数値化する

次に、回答を点検するための簡易スコアを定義します。評価軸を言語化すると改善が継続できます。

answer = 'ベルマン方程式は、今の価値を次の価値で更新する再帰式です。'
checks = {'length_ok': len(answer) <= 120, 'has_keyword': '価値' in answer, 'has_recurrence': '再帰' in answer}
score = sum(1 for v in checks.values() if v) / len(checks)
print('checks=', checks)
print('score=', round(score, 3))

このような軽量評価でも、改善方向を揃える効果があります。実務ではこの評価軸をチームで共有します。

検証 5: 推論コストを見積もる

最後に、入力と出力の長さから概算コストを計算します。モデル選択は性能だけでなく費用とのバランスが必要です。

input_tokens = 320
output_tokens = 180
price_per_1k = 0.0012
cost = (input_tokens + output_tokens) / 1000 * price_per_1k
print('estimated_cost=', round(cost, 6))

この見積もりを運用前に作ると、スケール時の予算超過を防ぎやすくなります。

まとめ

今回のノートで押さえておくべき誤解しやすい点を整理します。

  1. プロンプトだけで全問題を解決しようとする
  2. 評価指標を決めずに改善を繰り返す
  3. コストと品質のバランスを見ない