- Authors

- Name
- Youngju Kim
- @fjvbn20031
- ふたたび、コミットなき6ポイント
- ハーネスはバージョンの付くデプロイ物です
- 指紋を作る:正規化が半分です
- 何が入り、何が外れるか
- 結果に指紋が付いて初めて比較が成立します
- ロールバックとリグレッションの二分探索
- 実際に練習する
- 参考資料
ふたたび、コミットなき6ポイント
この連載の出発点になった以前の記事は、構成した事例ひとつから始まりました。成功率が先週より6ポイント上がったのに、プロンプトのコミットもモデル変更もなく、調べてみるとツール説明の1行、再試行上限、ファイル読み込みの行数上限が、それぞれ別の人の手で変わっていたという話です。来週成功率が落ちたら、何を戻すべきでしょうか。記録がなければ答えられません。
この記事は、その事件を答え可能にする最小の装置、ハーネス指紋を扱います。先に断っておくと、指紋という装置はLilian Wengのハーネスの記事が提案したものではなく、あの記事が引いてくれた境界を運用に移すためにこのブログが構成した接近です。
ハーネスはバージョンの付くデプロイ物です
指紋の前提は視点の転換です。ハーネスを散らばった設定の山ではなく、ひとつのデプロイ物として見ます。デプロイ物ならバージョンがあり、バージョンがあれば2つの時点の差を問えます。Wengの定義が役に立つのはここです。モデルの思考と行動、コンテキスト、成果物、評価を調律する層の全部という境界があって初めて、「この変更はハーネスの変更か」という問いに一貫して答えられます。ツール説明の1行を磨くのも、再試行上限を上げるのも境界の中なので、どちらもバージョンを動かす変更です。
指紋を作る:正規化が半分です
指紋そのものは短い話です。ハーネスを構成する決定を直列化してハッシュを取るだけです。難しい半分は正規化です。意味が同じハーネスは同じ指紋を持たなければなりませんが、素朴に直列化すると、ツールの登録順が変わっただけで指紋が変わります。だからツールの一覧は名前で整列し、JSONのキーは整列順に固定し、意味に影響しない空白やフィールドの順序は直列化の前に統一します。逆に、実行ごとに変わる値、タイムスタンプや実行IDのようなものは指紋に入れてはいけません。入れた瞬間、すべての実行が互いに比較不能なハーネスになってしまいます。
何が入り、何が外れるか
入るのは、エージェントの行動を変えるすべての決定です。モデルの識別子、システムプロンプト、ツールスキーマ全体、再試行上限と停止条件、コンテキストポリシー、権限の範囲、そして評価者のバージョンまで。評価者を入れる理由は第5回と第6回で見たとおりです。採点基準が変われば同じハーネスでも違うスコアになるので、採点基準の変更も追跡対象です。
外れるのは2種類です。ひとつは実行属性です。課題の入力、実行時刻、乱数シードは実行のメタデータであって、ハーネスではありません。もうひとつのほうが重要です。ロギングと観測の設定は指紋から外します。あなたに何が見えるかは、エージェントが何をするかを変えないからです。観測設定を指紋に入れると、行動が同じ結果たちが比較不能な破片に割れてしまいます。この原則はこのブログのハーネスRPGにもそのまま実装されています。観測装備は進行に応じて開きますが、指紋は動きません。
結果に指紋が付いて初めて比較が成立します
指紋の用途は、評価結果に印を押すことです。
{
"run_id": "2026-08-12T03:14:07Z-a41",
"harness_fingerprint": "3f9c1d2ab714",
"suite": "issues-50",
"success_rate": 0.62,
"counter_metrics": { "deleted_tests": 0, "avg_tool_calls": 11.4 }
}
この1行ができると、ルールが2つ付いてきます。第一に、比較は同じ指紋同士でのみ成立します。指紋の違う2つの成功率を並べるのは比較ではなく実験であり、実験ならば何が違ったのかdiffを言えなければなりません。第二に、指紋を動かすすべての変更は、評価を回し直すべき変更です。ツール説明1行の修正がプロンプト改編と同じ格で扱われ始め、それこそが意図された効果です。
ロールバックとリグレッションの二分探索
成功率のグラフに段差ができたら、指紋の履歴が容疑者リストを作ってくれます。
def regression_boundary(runs):
"""成功率が折れた地点の指紋の境界を探す(構成した例)。"""
runs = sorted(runs, key=lambda r: r["ts"])
for prev, cur in zip(runs, runs[1:]):
if cur["success_rate"] < prev["success_rate"] - 0.03: # ノイズの余裕
return prev["harness_fingerprint"], cur["harness_fingerprint"]
return None
# 境界の2つの指紋に対応するスペックのdiffが、そのまま容疑者リストになる。
# 容疑者が複数なら、半分ずつ戻して二分探索する。
2つの指紋の間のスペックdiffが候補の変更たちです。候補がひとつならそれを戻して再評価し、複数ならgit bisectと同じ要領で半分ずつ絞ります。ロールバックも同じ履歴の上で定義されます。以前の指紋のスペックを再デプロイし、デプロイされたものの指紋が目標の指紋と一致するかを確認すれば、ロールバックは完了です。指紋がなかった時代の「たぶんこの設定だったはず」が「ハッシュが一致する」に変わります。
実際に練習する
ハーネスエンジニアリングRPGのティア1「観測と指紋」の最初のシナリオが、まさにこの記事の冒頭の事件です。先週の6ポイントを再現するためにハーネスを組み立てるうちに、指紋がどの変更に反応し、どの変更に反応しないかを手で覚えることになります。
参考資料
- Harness engineering for self-improvement — Lilian Weng, 2026-07-04 — ハーネスの境界、つまり何がハーネスの中の変更に数えられるかの定義がこの記事にあります。
- このブログの以前の記事: ハーネスは設定ではなくデプロイ物です — 指紋の接近の最初の紹介とスペック直列化のコードがあります。
- ハーネス指紋という装置そのもの、6ポイントの事例、本文のコード例はいずれも原文の内容ではなく、このブログが運用のために構成したものです。