業務用スクリプトの依頼文に入力・出力・エラー処理のルールを入れる
「これを自動化して」を、実行可能な task description に変えます。sensitive data を含まない合成 sample と、手作業で確認した expected result を添えて、team ごとの work logs を集計する script request を完成させます。
AI要約を個別の主張に分け、それぞれを具体的な原文の文に結び付け、再利用する前に根拠のない表現や言い過ぎた表現を確認します。小さな合成文書を使って、自然に読める要約でも根拠確認が必要な理由を示します。
この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 English
対象読者AIを使ってレポート、メモ、研究資料を要約し、文ごとに追跡可能なレビューを行いたい人向けです。
AI要約は文法的に自然でも、原因を変えたり、制約条件を落としたり、原文にない結論を追加したりすることがあります。そのため、実用的なレビューでは各要約文について、どの原文部分がこの文を裏付けているのかを確認します。
このチュートリアルでは3つの判定を使います。SUPPORTEDは原文がその文を直接裏付けている場合です。PARTIALは文の一部だけが裏付けられているか、重要な条件が欠けている場合です。UNSUPPORTEDは原文がその主張を裏付けていないか、内容と矛盾する場合です。
以下の原文と要約は合成データで、このページ専用に作成したものです。最初のブロックをsource.txt、2つ目をai_summary.txtとして保存してください。
S1|The pilot processed 20 test cases.
S2|Eighteen cases completed successfully.
S3|Two cases stopped during input validation before the solver started.
S4|Among the 18 completed cases, the median runtime was 42 seconds.
S5|The test was performed on one workstation under the same software configuration.
S6|No production deployment or long-term reliability test was performed.
A1|The pilot processed 20 cases, and 18 completed successfully.
A2|Two cases failed because the solver crashed.
A3|The median runtime for completed cases was 42 seconds.
A4|The results show that the automation is reliable enough for production use.
原文は6文、AI要約は4文です。ソフトウェアを使わなくても確認できるよう、数値は意図的に小さくしています。
A1はS1とS2で裏付けられます。A2はS3と矛盾します。原文では、2件はsolverが開始する前のinput validationで停止したとあり、solver crashが原因とは書かれていません。A3はS4で直接裏付けられます。A4は根拠の範囲を超えています。S6にはproduction deploymentもlong-term reliability testも実施していないと明記されています。
| 要約ID | 判定 | 根拠 | 理由 |
|---|---|---|---|
| A1 | SUPPORTED | S1;S2 | ケース数と成功完了数が原文と一致しています。 |
| A2 | UNSUPPORTED | S3 | 原文では、停止原因をsolver開始前のinput validationとしています。 |
| A3 | SUPPORTED | S4 | 完了した18件のmedian runtimeが42秒と記載されています。 |
| A4 | UNSUPPORTED | S6 | production readinessはテストされていません。 |
したがって、期待されるレビュー結果はSUPPORTEDが2文、UNSUPPORTEDが2文です。この4つの合成文ではPARTIAL判定は必要ありません。
以下をsummary_review.csvとして保存してください。evidence列には段落全文ではなく原文の文IDを記録します。これにより、レビューを簡潔に保ちながら追跡可能性を維持できます。
summary_id,verdict,evidence,reason
A1,SUPPORTED,S1;S2,The case count and successful completions match the source.
A2,UNSUPPORTED,S3,The source attributes the stops to input validation before solver start.
A3,SUPPORTED,S4,The 42-second median is stated for the 18 completed cases.
A4,UNSUPPORTED,S6,Production readiness was not tested.
このレビュー自体は人による判断です。次のスクリプトは主張が正しいかどうかを判断しません。各AI要約文に有効な判定が付いているか、引用した原文IDが実際に存在するかを確認します。
以下のスクリプトをcheck_summary_review.pyとして保存してください。原文、要約、完成したレビューCSVを読み込み、IDと判定を確認し、入力ファイルを変更せずに新しい検証済みレポートを書き出します。
import csv
from pathlib import Path
SOURCE = Path("source.txt")
SUMMARY = Path("ai_summary.txt")
REVIEW = Path("summary_review.csv")
OUTPUT_DIR = Path("outputs") / "summary_source_check"
OUTPUT = OUTPUT_DIR / "validated_review.csv"
VALID_VERDICTS = {"SUPPORTED", "PARTIAL", "UNSUPPORTED"}
def read_id_text(path: Path) -> dict[str, str]:
result = {}
with path.open("r", encoding="utf-8") as stream:
for line_number, line in enumerate(stream, start=1):
line = line.rstrip("\n")
if not line:
continue
item_id, separator, text = line.partition("|")
if not separator or not item_id or not text:
raise ValueError(f"Invalid line {line_number} in {path}.")
if item_id in result:
raise ValueError(f"Duplicate ID {item_id} in {path}.")
result[item_id] = text
return result
def main() -> None:
for path in (SOURCE, SUMMARY, REVIEW):
if not path.is_file():
raise FileNotFoundError(f"Missing input: {path}")
if OUTPUT_DIR.exists():
raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")
source = read_id_text(SOURCE)
summary = read_id_text(SUMMARY)
reviewed = {}
with REVIEW.open("r", encoding="utf-8-sig", newline="") as stream:
reader = csv.DictReader(stream)
required = {"summary_id", "verdict", "evidence", "reason"}
if reader.fieldnames is None or not required.issubset(reader.fieldnames):
raise ValueError("Review CSV is missing a required column.")
for row in reader:
summary_id = row["summary_id"].strip()
verdict = row["verdict"].strip()
evidence_ids = [x.strip() for x in row["evidence"].split(";") if x.strip()]
if summary_id not in summary:
raise ValueError(f"Unknown summary ID: {summary_id}")
if summary_id in reviewed:
raise ValueError(f"Duplicate review: {summary_id}")
if verdict not in VALID_VERDICTS:
raise ValueError(f"Invalid verdict for {summary_id}: {verdict}")
if not evidence_ids:
raise ValueError(f"No evidence listed for {summary_id}.")
unknown = [item for item in evidence_ids if item not in source]
if unknown:
raise ValueError(f"Unknown source IDs for {summary_id}: {unknown}")
if not row["reason"].strip():
raise ValueError(f"Missing reason for {summary_id}.")
reviewed[summary_id] = {
"summary_id": summary_id,
"summary_text": summary[summary_id],
"verdict": verdict,
"evidence": ";".join(evidence_ids),
"reason": row["reason"].strip(),
}
missing = [item for item in summary if item not in reviewed]
if missing:
raise ValueError(f"Summary sentences not reviewed: {missing}")
OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
OUTPUT_DIR.mkdir()
fields = ["summary_id", "summary_text", "verdict", "evidence", "reason"]
with OUTPUT.open("x", encoding="utf-8", newline="") as stream:
writer = csv.DictWriter(stream, fieldnames=fields)
writer.writeheader()
for summary_id in summary:
writer.writerow(reviewed[summary_id])
counts = {verdict: 0 for verdict in VALID_VERDICTS}
for row in reviewed.values():
counts[row["verdict"]] += 1
print(f"Summary sentences checked: {len(summary)}.")
print(
f"Supported: {counts['SUPPORTED']}; partial: {counts['PARTIAL']}; "
f"unsupported: {counts['UNSUPPORTED']}."
)
print(f"Output: {OUTPUT.as_posix()}")
if __name__ == "__main__":
main()
上記の合成レビューでは、4つの要約文すべてに有効な判定と有効な原文参照があります。以下に期待されるコンソール出力を示します。これは手作業で導いたもので、実際の実行ログではありません。
Summary sentences checked: 4.
Supported: 2; partial: 0; unsupported: 2.
Output: outputs/summary_source_check/validated_review.csv| 問題 | 対応方法 |
|---|---|
| 1つの要約文に2つの別々の主張がある | 文を主張単位に分けるか、それぞれの主張を個別にレビューします。 |
| 根拠が文の一部しか裏付けていない | PARTIALを使い、不足している条件をreason列に記録します。 |
| 原文に結論を裏付ける記述がない | もっともらしい推測を出典付きの事実として扱わず、UNSUPPORTEDとします。 |
| 原文の文を引用しているが実際には主張を裏付けていない | 人によるレビューを修正します。有効なIDだけでは意味的な裏付けを証明できません。 |
| 異なる出典が食い違っている | 根拠のない1つの結論に無理にまとめず、相違点を明示的に記録します。 |
Pythonスクリプトが検証するのは、レビューがすべて揃っているかと参照IDが有効かどうかであり、真偽そのものではありません。意味的な裏付けには、依然として人による読解または別の根拠評価プロセスが必要です。人の判定が間違っていても、構造チェックは通る可能性があります。
長いレポートでは、曖昧な参照ではなくページ番号、段落ID、表番号、引用位置を使ってください。また、原文の直接的な記述、計算結果、解釈、外部知識を区別してください。要約の中で、これらの区分を暗黙に入れ替えないようにします。
2026-09-20 · 手作業で確認した例 · 対象: Python 3.12 · 標準ライブラリ: csv, pathlib · 未実行
説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。