固有表現抽出のプロンプト
非構造化テキストから名前、日付、場所、カスタムエンティティを抽出します。
「固有表現抽出のプロンプト」はCoddyKit上の無料AI Prompt Engineeringレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Prompt Engineering学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Prompt Engineeringコースには全4レッスンが含まれています。
固有表現抽出とは
固有表現抽出(NER)とは、テキスト中で言及されている特定の実世界のエンティティを識別し、カテゴリーに分類するタスクです。従来のNLPではNERに統計モデルを使用しますが、LLMでは適切に設計したプロンプトによって実行できます。
一般的なエンティティの種類:
- PERSON:人名(Elon Musk、Dr. Jane Smith)
- ORG:企業や組織(Apple、WHO)
- DATE:日付や時間表現(January 15、last Tuesday、Q3 2024)
- LOCATION:場所(New York、the Amazon River)
- MONEY:金額($4.2 billion)
基本的なNERプロンプト
最も簡単なNERプロンプトでは、すべてのエンティティを指定した形式で抽出するよう求めます。
import anthropic, json
client = anthropic.Anthropic(api_key='YOUR_API_KEY')
text = 'Apple CEO Tim Cook met with European Commission President Ursula von der Leyen in Brussels on March 15, 2025 to discuss the Digital Markets Act.'
prompt = f'''
Extract all named entities from the text below.
Return ONLY a JSON object with no other text:
{{
"people": ["string"],
"organizations": ["string"],
"locations": ["string"],
"dates": ["string"]
}}
Text: {text}
'''
r = client.messages.create(
model='claude-opus-4-5', max_tokens=300,
messages=[{'role': 'user', 'content': prompt}]
)
print(json.loads(r.content[0].text))抽出に型制約を追加する
基本的な抽出ではエンティティ文字列が返されます。型制約を追加すると、日付が特定の形式になっていることや、組織名から一般的な語が除外されていることを検証できます。
prompt_typed = '''
Extract named entities from the text below with type constraints.
Return JSON:
{
"people": ["Full name as written in text"],
"organizations": ["Official organization name only, no articles (the, a)"],
"dates": ["ISO 8601 format if possible: YYYY-MM-DD, else exact text as written"],
"money": ["Include currency symbol and amount: $4.2B, EUR 500K"],
"locations": ["City, Country format if applicable"]
}
If a category has no entities, use an empty array [].
Text: {text}
'''
print(prompt_typed[:200])
print('\nConstraints enforce consistent output format per entity type.')スキーマ駆動型の抽出
本番環境で使用する場合は、あらかじめエンティティのスキーマを定義し、プロンプト内で参照します。これにより、出力の契約が明確になります。
ENTITY_SCHEMA = '''
{
"entities": [
{
"text": "exact text as it appears in the document",
"type": "PERSON | ORG | DATE | LOCATION | MONEY | PRODUCT | EVENT",
"normalized": "canonical form (e.g., full name, ISO date)",
"start_char": "integer, character offset in source text",
"confidence": "high | medium | low"
}
]
}
'''
def extract_entities(text):
prompt = f'Extract all named entities. Return JSON matching this schema exactly:\n{ENTITY_SCHEMA}\n\nText: {text}'
r = client.messages.create(
model='claude-opus-4-5', max_tokens=500,
messages=[{'role': 'user', 'content': prompt}]
)
return json.loads(r.content[0].text)
result = extract_entities('Tesla stock rose 5% after Elon Musk announced the Cybertruck delivery on December 1.')
print(result['entities'][0])曖昧なエンティティへの対応
一部のエンティティ文字列は曖昧です。Appleは企業にも果物にもなり得ますし、Jordanは人にも国にもなり得ます。文脈を使って曖昧さを解消するようモデルに指示します。
prompt_disambiguation = '''
Extract named entities from the text. For ambiguous entities, use the surrounding
context to determine the correct type. Include your reasoning in an "evidence" field.
Return JSON:
{
"entities": [
{
"text": "string",
"type": "PERSON | ORG | LOCATION | OTHER",
"evidence": "brief reason for type assignment"
}
]
}
Text: Jordan and Apple signed a distribution deal for the new Air Jordan shoes.
'''
# Expected output: Jordan = PERSON (context: Air Jordan), Apple = ORG (context: signed a deal)
print(prompt_disambiguation)フィールド定義を使った抽出
ドメイン固有のカスタムエンティティタイプには、何が該当するのかをモデルが正確に理解できるよう、プロンプト内にフィールド定義を記述します。
prompt_custom = '''
Extract entities from the medical text below using these custom entity types:
Entity Types:
- MEDICATION: Any drug name, trade name, or generic name
- DOSAGE: Amounts and frequencies (mg, mcg, units/day)
- CONDITION: Diagnoses, symptoms, or medical conditions
- PROCEDURE: Medical tests, surgeries, or treatments
- PROVIDER: Doctor names and medical professionals
Return JSON: {"entities": [{"text": str, "type": str}]}
Text: Dr. Patel prescribed Metformin 500mg twice daily for Type 2 Diabetes.
A follow-up HbA1c test is scheduled for next month.
'''
print(prompt_custom)エンティティの一括抽出
複数のドキュメントを処理する場合は、一括抽出のほうが効率的です。複数の入力を処理し、ドキュメントごとに構造化された結果を返すようプロンプトを設計します。
def batch_extract(documents):
docs_formatted = '\n'.join(
f'<document id="{i+1}">\n{doc}\n</document>'
for i, doc in enumerate(documents)
)
prompt = f'''
Extract named entities from each document below.
Return JSON: {{
"results": [
{{"doc_id": int, "entities": {{"people": [], "organizations": [], "dates": []}}}}
]
}}
{docs_formatted}
'''
r = client.messages.create(
model='claude-opus-4-5', max_tokens=1000,
messages=[{'role': 'user', 'content': prompt}]
)
return json.loads(r.content[0].text)
docs = [
'Satya Nadella presented at Microsoft Build 2025.',
'The WHO released guidelines on May 10.'
]
print(batch_extract(docs))抽出したエンティティの後処理
抽出したエンティティは、使用する前に後処理が必要になることがよくあります。
from datetime import datetime
def normalize_entities(raw_entities):
normalized = {'people': [], 'organizations': [], 'dates': [], 'money': []}
for person in raw_entities.get('people', []):
normalized['people'].append(person.strip().title())
for org in raw_entities.get('organizations', []):
normalized['organizations'].append(org.strip())
for date_str in raw_entities.get('dates', []):
# Try to parse to ISO format
for fmt in ['%B %d, %Y', '%Y-%m-%d', '%b %d, %Y']:
try:
parsed = datetime.strptime(date_str.strip(), fmt)
normalized['dates'].append(parsed.strftime('%Y-%m-%d'))
break
except ValueError:
pass
else:
normalized['dates'].append(date_str.strip())
return normalized
raw = {'people': ['tim cook', 'URSULA VON DER LEYEN'], 'dates': ['March 15, 2025']}
print(normalize_entities(raw))抽出品質の評価
NERの品質は、ラベル付きテストセットに対する適合率、再現率、F1スコアで測定します。
- 適合率:抽出したすべてのエンティティのうち、正しいものの割合
- 再現率:実際に存在するすべてのエンティティのうち、抽出できたものの割合
- F1:適合率と再現率の調和平均
def evaluate_extraction(predicted, ground_truth):
pred_set = set(predicted)
true_set = set(ground_truth)
true_positives = len(pred_set & true_set)
false_positives = len(pred_set - true_set)
false_negatives = len(true_set - pred_set)
precision = true_positives / (true_positives + false_positives) if pred_set else 0
recall = true_positives / (true_positives + false_negatives) if true_set else 0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) else 0
return {'precision': round(precision, 3), 'recall': round(recall, 3), 'f1': round(f1, 3)}
predicted = ['Tim Cook', 'Apple', 'Brussels', 'March 15 2025']
ground_truth = ['Tim Cook', 'Apple', 'Ursula von der Leyen', 'Brussels', 'March 15, 2025', 'European Commission']
print(evaluate_extraction(predicted, ground_truth))幻覚によるエンティティの抽出を減らす
モデルは、ときどき元のテキストに存在しないエンティティを抽出します。これが幻覚です。対策は次のとおりです。
- 次のように指示します:テキスト内で明示的に言及されているエンティティだけを抽出してください。存在しないエンティティを推測したり追加したりしないでください。
- 次のように指示します:各エンティティについて、テキスト内でそのエンティティが現れる箇所を正確に引用してください。
- 後処理として、抽出した各エンティティ文字列が元のテキストに実際に含まれていることを検証します
def anti_hallucination_extract(text):
prompt = f'''
Extract ONLY entities that are explicitly present in the text below.
Do NOT infer, add, or supplement with external knowledge.
For each entity, include the exact quote from the text.
Return JSON: {{"entities": [{{"text": str, "type": str, "quote": str}}]}}
Text: {text}
'''
r = client.messages.create(model='claude-opus-4-5', max_tokens=400, messages=[{'role': 'user', 'content': prompt}])
extracted = json.loads(r.content[0].text)
# Post-process: verify each entity appears in original text
verified = [e for e in extracted['entities'] if e['text'].lower() in text.lower()]
return {'entities': verified}
result = anti_hallucination_extract('Google announced a $5B investment in AI infrastructure.')
print(result)共参照解決とエンティティリンキング
生のエンティティ文字列を抽出した後、さらに2つのタスクを行うと、後続処理での有用性が高まります。
- 共参照解決:彼、その会社、それを、それらが指している固有表現に結び付けます
- エンティティリンキング:抽出した名前を正規の識別子に対応付けます(例:知識ベース内で「Apple」→ apple_inc)
どちらも、初回の抽出後に追加のプロンプトステップとして処理できます。
coref_prompt = '''
Resolve coreferences in the text below.
For each pronoun or definite reference (he, she, it, the company, the CEO),
identify which named entity it refers to.
Return JSON: {"coreferences": [{"text": str, "refers_to": str, "position": int}]}
Text: Apple released its new chip. The company said it would ship in Q4.
Tim Cook announced that he would present it at the fall event.
'''
print(coref_prompt)クイックチェック
元のテキストに存在しないエンティティをモデルが抽出するのを防ぐ最も効果的な方法は何ですか。
固有表現抽出 — 重要ポイント
プロンプトを適切に設計すれば、LLMベースの固有表現抽出は柔軟で強力です。
- エンティティタイプを明示的に定義します。PERSON、ORG、DATE、LOCATION、MONEY、およびドメイン固有のタイプを定義します
- プロンプト内でJSONスキーマを使用し、一貫した出力構造を強制します
- カスタムエンティティタイプにはフィールド定義を追加し、何が該当するのかをモデルが正確に理解できるようにします
- エンティティの幻覚を防ぐため、元のテキストの引用を必須にします
- 後処理でエンティティの形式を正規化します(日付をISO形式に、名前をタイトルケースにします)
- ラベル付きテストセットに対する適合率、再現率、F1で品質を評価します
- バッチ処理では、1回の呼び出しで複数のドキュメントを処理し、ドキュメントごとに構造化された出力を返します
よくある質問
「固有表現抽出のプロンプト」レッスンは無料ですか?
はい。「固有表現抽出のプロンプト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Prompt Engineeringコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Prompt Engineeringコースには全4レッスンが含まれています。
「固有表現抽出のプロンプト」で何を学びますか?
非構造化テキストから名前、日付、場所、カスタムエンティティを抽出します。 ブラウザで直接実行するハンズオンコードでAI Prompt Engineeringを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Prompt Engineeringを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Prompt Engineeringは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「固有表現抽出のプロンプト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Prompt Engineeringレッスンでコードを書いて実行できますか?
はい。すべてのAI Prompt Engineeringレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 固有表現抽出のプロンプト
- スキーマ駆動のデータ抽出
- テキスト分類器としての LLM
- 分類における確信度と不確実性