Blog
ー
最新のプロンプトエンジニアリング - 書く技術から、評価する技術へ
2026-08-08 11:36:57

「プロンプトエンジニアリングはもう古い」とよく言われます。半分は本当で、半分は誤解です。単発の文言を磨く職人芸の多くは、モデルとインフラの進化で確かに要らなくなりました。プロンプトを書く作業そのものも、今はモデルと相談しながら進められます。しかし、出来上がったものを継続的に評価するためのプロンプトは依然として必要です。
これまで、ループ・コンテキスト・ハーネス・メモリ と紹介してきましたが、この記事ではプロンプトを正しく扱うための知識を整理します。もう書かなくていいテクニック、公式ドキュメントが推奨している作法、今後も必要な「採点表(rubric)」を利用する機能まで見ていきます。想定モデルは最新世代(Fable5, Opus5, Sonnet5, GPT5.6)、対象はエージェントを設計・運用する人です。
プロンプトはコンテキストの一部になった
かつてプロンプトエンジニアリングとは、1回の入力の文言を磨く作業でした。代表格が CoT(Chain of Thought・思考の連鎖)です。「ステップバイステップで考えて」と唱えて、答えの前に途中の思考過程を書かせると正答率が上がる、というプロンプト技法で、一時期はあらゆるプロンプトの枕詞でした。他には「JSONだけで返して。マークダウンの囲みは不要」と何度も念を押すなど、モデルが弱かった時代は、こうした工夫が効きました。
しかし、モデルは賢くなり、CoT推論も構造化出力も標準機能になりました。 Anthropic は「コンテキストエンジニアリングは、より高性能なエージェントに向けたプロンプトエンジニアリングの自然な発展形だ」と述べています(参考: 「Effective context engineering for AI agents」)。

だからといってプロンプトの層が消えたわけではありません。「何を・どのような目的で・どのような制約で渡すか」は、結果を大きく左右します。
何が要らなくなり、何が効き続けるか
不要となったテクニック
ここを削るだけでプロンプトは短く・確実になります。
- 思考手順: Claude はデフォルトで adaptive thinking となり、シンプルな指示を推奨しています。OpenAIも同様です。
- 深く考えてのお願い: 思考の深さはパラメータで設定します。OpenAI は
reasoning.effort(デフォルト medium)で設定し、出力の詳しさはtext.verbosityで設定します。同様に、Claude はeffort(デフォルト high)で設定し、text.verbosityに相当するパラメータはないため、出力の長さはプロンプトで指示します。 - 最後に検証しての念押し: 最新モデルでは指示がなくても十分に検証します。同じ理屈で、「CRITICAL: 必ず〜せよ」のような強い言い回しも通常の言い方へ戻すよう推奨されています。
- 出力形式の指定: 構造化出力の機能があります。ツール呼び出し引数に型定義をしたい場合は、
strict: trueを付けることで指定できます。
参考リンク
- Prompting best practices - Claude
- Effort - Claude
- Structured outputs - Claude
- Reasoning best practices - OpenAI
- Prompting best practices - OpenAI
- Structured model outputs - OpenAI
今も有効なテクニック
両社の公式ガイドを項目ごとに突き合わせてみました。結論を先に言うと、ほぼ一致します。以下はすべて、両社が揃って書いていることです。
- 到達点を書く: 何ができていれば完成か。文脈を知らない新しいメンバーに仕事を頼むつもりで、望む成果と制約を具体的に伝える。手順はモデルが選びます。
- 境界を決める: どこまでやってよいか、どこで止まるか、判断に迷ったらどうするか。取り返しのつかない操作や、外部に影響する操作は、実行前に確認させます。
- 役割を与える: 「あなたは〜の担当です」と一文添えるだけで、振る舞いと話し方が定まります。プロンプトの冒頭に置くのが定番です。
- 区切りで囲んで、種類を分ける: 指示・資料・例・その回だけの入力を、混ぜずに渡します。資料のように塊で渡すものは
<document>...</document>のようなXMLタグで囲む。こうしておけば、モデルはどれが指示でどれが資料かを取り違えません。タグ名に決まりはないので、意味が伝わる名前を決めて、最後まで揺らさなければ十分です。 - 例を見せて、それも囲む: 言葉で説明するより、良い例を数個見せるのが一番速い。出力の形式・トーン・構造は、例で伝わります。例も他の部分と区別できるよう囲んでおきます。
- 評価を回して直す: 勘で書き直すのではなく、動くプロンプトから始めて、指示や例を一つずつ外しながら同じ評価を回します。効いていない指示は削れます。
モデルごとに別々の作法を覚える必要はありません。両社のベストプラクティスはほぼ同じです。
各社がプロンプト自動改善ツールを提供終了
プロンプトは評価データで自動的に鍛えるものとされ、各社も公式ツールを提供してきましたが、2026年現在、その多くが提供を終了、または終了予定です。 Anthropicは、Console にプロンプトを自動改善する prompt improver と、テストケースを生成して出力を比較する Evaluate を持っていました。現在、どちらも公式ドキュメントから記載が消え、当時の告知記事「2024年10月 prompt-improver」・「2024年7月 evaluate-prompts」だけが残っています。 OpenAIの prompt optimizer も、「Legacy APIs」に置かれ、評価データと連動する版は2026年11月30日に停止予定です。 残っているのは Google の Vertex AI Prompt Optimizer くらいです。
代わりにAnthropicが公式に案内しているのは、モデル自身と作る方法です。叩きとなるプロンプトが欲しければ Cookbook の metaprompt レシピ(Claudeにプロンプトを書かせるプロンプト)を使い、評価は自分で書く。その評価ドキュメントには「テストケースを何百も手で書くのは大変。ベースラインの例からClaudeに増やしてもらおう」「どんな評価手法が良いか分からないなら、Claudeとブレストしてもいい」「このページをチャットに放り込んでガイドにするとよい」と書かれています。(参考: 「Define success criteria and build evaluations」)
面白いのは、消えたものと残ったものの対比です。プロンプトを改善するツールは無くなり、評価のためにLLMを活用するドキュメントは残りました。
実検証: 採点表(rubric)だけ書いて、あとは任せる
ここまでの話をまとめると、プロンプト作成はモデルに任せられる一方で、「何ができていれば完成か」を決めるのは人の仕事として残ります。この分担がそのまま機能になっているのが、Managed Agents の outcome です(参考: 「Define outcomes」)。
使い方は単純で、セッションに「何を作るか」と採点表(rubric)を渡すだけです。すると自動で採点役が用意され、成果物も生成されます。
裏側で何が起きているか
送るのは最初の1回だけです。順に見ていきます。
user.define_outcomeを送る: 作るもの(description)と採点表(rubric)、それに反復の上限(max_iterations)を渡します。ユーザーメッセージは要りません。このイベントを受け取った時点で、エージェントが作業を始めます。- エージェントが作業する: サンドボックスの中でツールを使って作業し、成果物を
/mnt/session/outputs/に書き出します。この間の様子はagent.*イベントとして流れてきます。 - 採点役が立つ: 一区切りつくと、ハーネスが採点役を用意します。ここが肝で、採点役は本体とは別のコンテキストウィンドウで動きます。本体がどう考えて実装したかの経緯を知らないまま、出来上がった成果物と採点表だけを見て採点します。身内に採点させない、という設計です。
- 判定が返る:
span.outcome_evaluation_endイベントで結果が届きます。satisfied(満たした)、needs_revision(作り直し)、max_iterations_reached(上限に到達)、failed(採点表がそもそもこの成果物に対応していない)のいずれかです。 - 差し戻しなら、説明が本体に戻る:
needs_revisionの場合、どの基準をどう外したかの説明がエージェントに渡され、次の反復が始まります。ここでiterationが1つ進みます。 - 終わったら成果物を取り出す:
satisfiedか上限到達でセッションが終わります。成果物は会話の本文ではなくファイルなので、Files API をセッションスコープで引いて取得します。
見えるものと見えないものがあります。エージェントの作業も採点のタイミングもイベントとして観測できますが、採点役が内部で何を考えたかは見えません。返ってくるのは結論と説明だけです。採点結果に納得できないときに直すのは採点表です。
採点表を2つ用意して比べる
人が用意するのは採点表だけですが、その採点表の粒度で結果がどう変わるかを検証します。 お題は、議事録からアクションアイテムの一覧を作ることです。渡す議事録には、担当者が明示されない発言、期限が「今週金曜」のような相対表現になっている箇所、そして次回に持ち越された議題を混ぜてあります。
- 採点表A(ざっくり)
- 議事録の内容が漏れなくまとまっていること
- 読みやすく、実務で使える形式であること
- 全体としてよくできていること
- 採点表B(具体的)
- 誰かがやると述べた作業がすべて挙がっているか
- 各項目に担当者と期限があるか(特定できない場合は「未定」「期限なし」と明記されているか)
- 期限が日付で書かれているか
- 決定事項と持ち越し議題が分かれているか
- 議事録に書かれていない担当者・期限・数値・結論が追加されていないか
成果物だけを眺めても良し悪しを判定できず、元の議事録と突き合わせて初めて分かる。コードでの計測は難しく、人が毎回読むには重い。まさにLLMに採点させたいタスクです。
import static java.nio.charset.StandardCharsets.UTF_8;
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.beta.agents.AgentCreateParams;
import com.anthropic.models.beta.agents.BetaManagedAgentsAgentToolset20260401Params;
import com.anthropic.models.beta.agents.BetaManagedAgentsModel;
import com.anthropic.models.beta.agents.BetaManagedAgentsModelConfigParams;
import com.anthropic.models.beta.environments.EnvironmentCreateParams;
import com.anthropic.models.beta.files.FileDownloadParams;
import com.anthropic.models.beta.files.FileListParams;
import com.anthropic.models.beta.sessions.SessionCreateParams;
import com.anthropic.models.beta.sessions.events.BetaManagedAgentsTextRubricParams;
import com.anthropic.models.beta.sessions.events.BetaManagedAgentsUserDefineOutcomeEventParams;
import com.anthropic.models.beta.sessions.events.EventSendParams;
import java.io.IOException;
import java.io.InputStream;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* Managed Agents の Memory を使い、共通ポリシーと顧客別トーンを分離して保持するデモ。
*
* 初回セットアップ: mvn -q compile exec:java -Dexec.args="setup"
* 通常実行: mvn -q compile exec:java
*/
public final class OutcomeRubricDemo {
private static final int MAX_ITERATIONS = 5;
private static final String MINUTES =
"""
# 定例ミーティング議事録
日時: 2026年8月3日(月)10:00-10:40
出席: 田中(PM)、佐藤(開発)、鈴木(デザイン)、高橋(CS)
## 新規登録画面のリリースについて
田中: 先週のβで登録完了率が62%だった。目標の75%には届いていない。
鈴木: 入力項目が多すぎるのが原因だと思う。項目を削る案を出したい。
田中: では鈴木さん、今週金曜までに削減案をお願いします。
佐藤: 削るならバックエンドのバリデーションも直す必要がある。案が出てから見積もります。
## 問い合わせ対応の状況
高橋: 登録できないという問い合わせが先週12件。うち8件は同じエラーだった。
佐藤: そのエラーは把握している。原因はまだ特定できていない。ログを追う。
田中: 原因が分かった時点で共有してください。期限は切らないが、優先度は高い。
## 次回の広告出稿
田中: 来月の予算をどうするか決めたいが、今日は判断材料が足りない。
高橋: CVRのデータを揃えます。
田中: 次回に持ち越しましょう。
""";
private static final String TASK =
"渡した議事録から、アクションアイテムの一覧を "
+ "/mnt/session/outputs/actions.md として作成してください。\n\n"
+ MINUTES;
private static final String RUBRIC_VAGUE =
"""
# アクションアイテム一覧の採点表
- 議事録の内容が漏れなくまとまっていること
- 読みやすく、実務で使える形式であること
- 全体としてよくできていること
""";
private static final String RUBRIC_SPECIFIC =
"""
# アクションアイテム一覧の採点表
次の各項目を、成果物と元の議事録を突き合わせて個別に判定してください。
## 網羅
- 議事録で誰かがやると述べた作業が、すべて項目として挙がっている
## 各項目の要素
- 担当者が書かれている。議事録から特定できない場合は「未定」と明記されている
- 期限が書かれている。議事録から特定できない場合は「期限なし」と明記されている
- 期限は「今週金曜」ではなく「yyyy-MM-dd」のように日付で書かれている
## 決定と未決の分離
- 決まったことと、次回に持ち越された議題が、別の節に分かれている
## 事実の忠実さ
- 議事録に書かれていない担当者・期限・数値・結論が追加されていない
- 議事録にある数値(登録完了率62%、問い合わせ12件、うち8件)が改変されていない
""";
private final AnthropicClient client;
private OutcomeRubricDemo(AnthropicClient client) {
this.client = client;
}
public static void main(String[] args) {
var demo = new OutcomeRubricDemo(AnthropicOkHttpClient.fromEnv());
if (args.length > 0 && args[0].equalsIgnoreCase("setup")) demo.setup();
else demo.runComparison();
}
private void setup() {
var environment =
client
.beta()
.environments()
.create(EnvironmentCreateParams.builder().name("minutes-actions-environment").build());
var agent =
client
.beta()
.agents()
.create(
AgentCreateParams.builder()
.name("minutes-to-actions")
.model(
BetaManagedAgentsModelConfigParams.builder()
.id(BetaManagedAgentsModel.CLAUDE_SONNET_5)
.build())
.system(
"あなたは議事録を整理する担当です。"
+ "議事録に書かれていないことを補わないでください。"
+ "担当者や期限が不明なら、推測せず『未定』『期限なし』と記してください。")
.addTool(
BetaManagedAgentsAgentToolset20260401Params.builder()
.type(
BetaManagedAgentsAgentToolset20260401Params.Type
.AGENT_TOOLSET_20260401)
.build())
.build());
System.out.println("# Managed Agents セットアップ結果");
System.out.println();
System.out.println("- Environment ID: `" + environment.id() + "`");
System.out.println("- Agent ID: `" + agent.id() + "`");
System.out.println();
System.out.println("## 環境変数");
System.out.println();
System.out.println("```bash");
System.out.println("export ANTHROPIC_ENVIRONMENT_ID=\"" + environment.id() + "\"");
System.out.println("export ANTHROPIC_AGENT_ID=\"" + agent.id() + "\"");
System.out.println("```");
}
private void runComparison() {
var environmentId = System.getenv("ANTHROPIC_ENVIRONMENT_ID");
var agentId = System.getenv("ANTHROPIC_AGENT_ID");
var vague = run(environmentId, agentId, "採点表A(ざっくり)", RUBRIC_VAGUE);
var specific = run(environmentId, agentId, "採点表B(具体的)", RUBRIC_SPECIFIC);
System.out.println("# Outcome Rubric 比較結果");
System.out.println();
System.out.println("生成日時: " + OffsetDateTime.now());
System.out.println();
System.out.println("## まとめ");
System.out.println();
System.out.println("| 採点表 | 最終結果 | 評価回数 |");
System.out.println("|---|---:|---:|");
printSummaryRow(vague);
printSummaryRow(specific);
printReport(vague);
printReport(specific);
}
private RunReport run(String environmentId, String agentId, String label, String rubric) {
var session =
client
.beta()
.sessions()
.create(
SessionCreateParams.builder()
.environmentId(environmentId)
.agent(agentId)
.title(label)
.build());
client
.beta()
.sessions()
.events()
.send(
EventSendParams.builder()
.sessionId(session.id())
.addEvent(
BetaManagedAgentsUserDefineOutcomeEventParams.builder()
.type(
BetaManagedAgentsUserDefineOutcomeEventParams.Type.USER_DEFINE_OUTCOME)
.description(TASK)
.rubric(
BetaManagedAgentsTextRubricParams.builder()
.type(BetaManagedAgentsTextRubricParams.Type.TEXT)
.content(rubric)
.build())
.maxIterations(MAX_ITERATIONS)
.build())
.build());
var evaluations = new ArrayList<Evaluation>();
String finalResult = "unknown";
int iterations = 0;
boolean evaluationSeen = false;
try (var response =
client.beta().sessions().events().streamStreaming(session.id())) {
var events = response.stream().iterator();
while (events.hasNext()) {
var event = events.next();
if (event.isSpanOutcomeEvaluationEnd()) {
var evaluation = event.asSpanOutcomeEvaluationEnd();
finalResult = evaluation.result();
iterations = Math.max(iterations, evaluation.iteration() + 1);
evaluationSeen = true;
evaluations.add(
new Evaluation(
evaluation.iteration() + 1, evaluation.result(), evaluation.explanation()));
}
if (evaluationSeen && event.isSessionStatusIdle()) {
break;
}
if (event.isSessionError()) {
throw new IllegalStateException("Managed Agents session error: " + event.asSessionError());
}
if (event.isSessionStatusTerminated()) {
break;
}
}
}
List<Deliverable> deliverables = downloadDeliverables(session.id());
return new RunReport(label, session.id(), finalResult, iterations, evaluations, deliverables);
}
private List<Deliverable> downloadDeliverables(String sessionId) {
var files =
client
.beta()
.files()
.list(
FileListParams.builder()
.scopeId(sessionId)
.limit(1000)
.addBeta(AnthropicBeta.MANAGED_AGENTS_2026_04_01)
.build());
var deliverables = new ArrayList<Deliverable>();
for (var file : files.data()) {
deliverables.add(new Deliverable(file.filename(), download(file.id())));
}
return deliverables;
}
private String download(String fileId) {
try (InputStream body =
client
.beta()
.files()
.download(
FileDownloadParams.builder()
.fileId(fileId)
.addBeta(AnthropicBeta.MANAGED_AGENTS_2026_04_01)
.build())
.body()) {
return new String(body.readAllBytes(), UTF_8);
} catch (IOException exception) {
return "(取得に失敗しました: " + exception.getMessage() + ")";
}
}
private static void printSummaryRow(RunReport report) {
System.out.println(
"| "
+ report.label()
+ " | "
+ report.result()
+ " | "
+ report.iterations()
+ " |");
}
private static void printReport(RunReport report) {
System.out.println();
System.out.println("## " + report.label());
System.out.println();
System.out.println("- Session ID: `" + report.sessionId() + "`");
System.out.println("- 最終結果: `" + report.result() + "`");
System.out.println("- 評価回数: " + report.iterations());
System.out.println();
System.out.println("### Grader評価履歴");
System.out.println();
if (report.evaluations().isEmpty()) {
System.out.println("評価イベントを取得できませんでした。");
} else {
for (Evaluation evaluation : report.evaluations()) {
System.out.println(
"#### Iteration " + evaluation.iteration() + " — `" + evaluation.result() + "`");
System.out.println();
System.out.println(evaluation.explanation());
System.out.println();
}
}
System.out.println("### 成果物");
System.out.println();
if (report.deliverables().isEmpty()) {
System.out.println("成果物はありません。");
return;
}
for (Deliverable deliverable : report.deliverables()) {
System.out.println("#### " + deliverable.filename());
System.out.println();
System.out.println("```markdown");
System.out.print(deliverable.content());
if (!deliverable.content().endsWith("\n")) {
System.out.println();
}
System.out.println("```");
System.out.println();
}
}
private record Evaluation(int iteration, String result, String explanation) {}
private record Deliverable(String filename, String content) {}
private record RunReport(
String label,
String sessionId,
String result,
int iterations,
List<Evaluation> evaluations,
List<Deliverable> deliverables) {}
}実行すると、こうなります(出力例。反復回数と採点役の説明は実行ごとに変わります)。
## まとめ
| 採点表 | 最終結果 | 評価回数 |
|---|---:|---:|
| 採点表A(ざっくり) | satisfied | 1 |
| 採点表B(具体的) | satisfied | 2 |
## 採点表A(ざっくり)
### Grader評価履歴
#### Iteration 1 — `satisfied`
An independent grader found all criteria met:
- 議事録の内容が漏れなくまとまっていること (すべてのアクションアイテムが網羅されている) (met): 議事録に含まれる全てのアクションアイテムが抽出されている: (1)鈴木の入力項目削減案(金曜期限)、(2)佐藤のバリデーション見積もり、(3)佐藤のエラー原因調査(ログ追跡)、(4)原因判明時の共有、(5)高橋のCVRデータ準備。次回に持ち越しとなった広告予算の議題も備考で言及されており、漏れは見られない。
- 読みやすく、実務で使える形式であること (met): 会議名・日時・出席者を明記した上で、No./アクション項目/担当者/期限/備考の列を持つMarkdownテーブル形式でまとめられており、実務でそのまま使える見やすい形式になっている。期限が明記されている項目とそうでない項目(期限なし)も明確に区別されている。
- 全体としてよくできていること (met): 各アクションの担当者・期限・背景(備考)が正確に議事録の発言内容と対応しており、誤った情報の追加や誤字も見られない。項目の分割(例:佐藤の見積もりとログ調査を別項目にする)も適切で、全体として整理された高品質なアウトプットになっている。
### 成果物
#### actions.md
```markdown
# アクションアイテム一覧
会議名: 定例ミーティング
日時: 2026年8月3日(月)10:00-10:40
出席: 田中(PM)、佐藤(開発)、鈴木(デザイン)、高橋(CS)
| No. | アクション項目 | 担当者 | 期限 | 備考 |
|---|---|---|---|---|
| 1 | 新規登録画面の入力項目の削減案を出す | 鈴木 | 今週金曜まで | 登録完了率62%が目標75%に届いていないため |
| 2 | 削減案が出た後、バックエンドのバリデーション修正の見積もりを行う | 佐藤 | 期限なし | 鈴木の削減案が前提 |
| 3 | 「登録できない」問い合わせで発生している同一エラーの原因調査(ログを追う) | 佐藤 | 期限なし | 優先度は高い |
| 4 | エラー原因が判明した時点で田中に共有する | 佐藤 | 期限なし | 優先度は高い |
| 5 | 広告出稿の予算判断に向けてCVRのデータを揃える | 高橋 | 期限なし | 来月の広告予算は次回会議に持ち越し |
```
## 採点表B(具体的)
### Grader評価履歴
#### Iteration 1 — `needs_revision`
An independent grader found the following criteria are not fully met:
- アクションアイテム一覧が議事録の内容を網羅し、担当者・期限(日付形式)・決定/未決の分離・事実の忠実さを満たしている (partially met): 成果物 (/mnt/session/outputs/actions.md) を確認した。
良い点:
- 網羅性: 議事録内で誰かが「やる」と述べた作業(鈴木の削減案、佐藤の見積もり、佐藤のログ調査・原因特定・共有、高橋のCVRデータ準備)は5項目としてすべて挙がっており、抜け漏れはない。
- 事実の忠実さ: 登録完了率62%、問い合わせ12件・うち8件などの数値は本文に含まれておらず改変もない。担当者も概ね議事録の発言者と整合しており(鈴木→削減案、佐藤→見積もり・ログ調査、高橋→CVRデータ)、存在しない担当者・数値・結論の追加は見当たらない。
問題点(複数の必須要件を満たしていない):
1. 期限の日付形式: rubricは「今週金曜」ではなく「yyyy-MM-dd」のような具体的日付で書くことを明確に求めているが、項目1の期限は「今週金曜まで」のままで、会議日(2026年8月3日月曜)から算出できる具体的日付(例: 2026-08-07)に変換されていない。
2. 「未定」と「期限なし」の表記不統一: 項目5の期限列は「未定(次回ミーティングに持ち越し)」となっており、rubricが求める「期限なし」という明記になっていない(「未定」は担当者不明時に使う語であり、期限欄で混用されている)。
3. 決定事項と未決事項の分離: 「次回の広告出稿」は明確に「次回に持ち越し」と述べられた未決の議題だが、成果物では他の確定した3件のアクション(削減案、見積もり、ログ調査)と同じ1つの表に混在しており、決定事項と未決事項を別セクションに分ける構成になっていない。
以上より、網羅性と事実の忠実さは満たしているが、期限の日付形式化・期限なし表記の統一・決定/未決の節分離という複数の明示的要件を満たしておらず、部分的達成にとどまる。
Please revise your work to address these gaps.
#### Iteration 2 — `satisfied`
An independent grader found all criteria met:
- アクションアイテム一覧の正確性・網羅性・構成 (met): 成果物(/mnt/session/outputs/actions.md)を確認した。
網羅性: 議事録中で「やる」と明言された作業(鈴木の削減案作成、佐藤の見積もり、佐藤のログ調査、佐藤の原因共有、高橋のCVRデータ収集)がすべて表に含まれている。漏れは見当たらない。
担当者・期限: 各項目に担当者が明記されている(鈴木、佐藤、佐藤、佐藤、高橋)。期限が議事録から特定できない項目(バリデーション見積もり、ログ調査、原因共有、CVRデータ収集)はいずれも「期限なし」と明記されている。鈴木の削減案の期限は「今週金曜までに」を、会議日が2026年8月3日(月)であることから正しく計算し「2026-08-07」というyyyy-MM-dd形式で記載しており、これは正しい変換(8/3が月曜なので同週金曜は8/7)である。
決定と未決の分離: 「決定事項(アクションアイテム)」と「未決事項(今回のミーティングでは結論に至らず、次回へ持ち越しとなった事項)」という2つの節に明確に分かれており、広告出稿予算の議題は未決事項として別枠にまとめられている。
事実の忠実さ: 議事録に記載のない担当者・期限・結論の追加は見当たらない。優先度列(「高い」「言及なし」)も田中の発言「優先度は高い」に基づく正当な抽出であり、脚注で根拠も説明されている。登録完了率62%、問い合わせ12件・8件といった数値はアクションアイテムに直接関係しないため記載されていないが、記載されている範囲において数値の改変や誤記は見られない。
以上、ルーブリックの各観点(網羅、担当者/期限の明記、期限の日付形式化、決定/未決の分離、事実の忠実さ)を高い精度で満たしている。
### 成果物
#### actions.md
```markdown
# アクションアイテム一覧
出典: 定例ミーティング議事録(2026年8月3日(月)10:00-10:40)
## 決定事項(アクションアイテム)
| No. | 内容 | 担当者 | 期限 | 優先度 |
|---|---|---|---|---|
| 1 | 新規登録画面の入力項目の削減案を出す | 鈴木 | 2026-08-07 | 言及なし |
| 2 | 入力項目削減案が出た後、バックエンドのバリデーション修正の見積もりを行う | 佐藤 | 期限なし | 言及なし |
| 3 | 登録できないという問い合わせで発生している同一エラーの原因をログを追って特定する | 佐藤 | 期限なし | 高い |
| 4 | エラーの原因が分かった時点で共有する | 佐藤 | 期限なし | 高い |
| 5 | 次回の広告出稿の予算判断に向けて、CVRのデータを揃える | 高橋 | 期限なし | 言及なし |
(注: No.3・No.4は担当者から「優先度は高い」と明言された項目のため、優先度欄に反映しています。それ以外は議事録内で優先度への言及がないため「言及なし」としています。)
## 未決事項(今回のミーティングでは結論に至らず、次回へ持ち越しとなった事項)
| No. | 内容 | 決定/担当 | 備考 |
|---|---|---|---|
| 1 | 来月の広告出稿の予算 | 未定 | 田中より「今日は判断材料が足りない」との発言があり、次回ミーティングに持ち越しとされた。 |
```Aは見た目が整っていて、担当者も期限も埋まっていますが、「田中に共有する」という共有先は原文には存在しません。それでも「整理されていて実務で使える」ので合格しました。
Bは一度どの基準をどう外したかを示した上で差し戻しているため、次の反復で直しています。needs_revision が返ってくること自体が、採点表が仕事をしている合図になります。
注意点:
max_iterationsはデフォルト3・最大20です。上限に達するとmax_iterations_reachedで終わるので、通らないときは採点表が厳しすぎるのか、そもそも矛盾しているのかを疑います。採点表がタスクに対応していない場合はfailedが返ります。- 成果物は会話の本文ではなく、サンドボックス内のファイルとして出てきます。判定が satisfied でも中身は必ず自分の目で確かめてください。採点表に書き忘れた観点は、当然ながら誰も見ていません。
評価は、どこまでコードに寄せられるか
今回の検証は採点をまるごとLLMに任せる例でしたが、評価のすべてをLLMにやらせる必要はありません。むしろ実務では、書かずに済むならその方が良いです。Anthropicの公式ドキュメントでも採点方法の優先度を順位づけています。
- コードベース: スキーマ検証、テストの成否、必須フィールドの有無、完全一致など。ツールやスキルとして実装する。
- 人手: 最も柔軟で高品質だが、遅くて高い。可能なら避ける。
- LLM: 機械的な条件に落とせない判断は、LLMに採点させるしかありません。基準を具体的・経験的に書くこと、スコアの前に理由を書かせること。
コードに寄せられるものは全部寄せ、残った部分だけをLLMに判定させる。この線引きができると、評価は速く安く回り、プロンプトを書く量も最小で済みます。
まとめ
プロンプトエンジニアリングは終わっていません。役割が変わりました。
人による監修のもと、判断基準を採点表(rubric)としてLLMに渡すことです。
プロンプトエンジニアリングの知識は、良いrubricを書くために要る。
elatt では、この「rubric設計」を実運用の中で日々やっています。設計や事業の相談などお気軽にお問い合わせからご連絡ください。