| name | narrative-extractor |
| description | 母親・支援者の語り(ナラティブ)や添付ファイルから、支援に必要な構造化データを抽出し Neo4j に登録するスキル。抽出は Claude 自身が行い、外部 LLM API は不要。「テキストから抽出」「情報を抽出して」「ナラティブから登録」「この文章を構造化して」「データベースに登録して」「面談記録を入力」「聞き取り内容を登録」などの発言時、および .docx/.xlsx/.pdf/.txt ファイル添付時に必ずこのスキルを使用すること。 |
narrative-extractor: テキストから構造化データを抽出するスキル
概要
母親・支援者の語り(ナラティブ)やファイルから、支援に必要な構造化データをJSON形式で抽出し、Neo4jデータベースに登録するためのスキル。
構造化抽出は Claude 自身がこの SKILL.md の指示に従って直接行う(外部 LLM API は不要)。Claude が抽出した JSON を、neo4j MCP の execute_query(書き込みクエリ)で本スキルの Cypher テンプレートを使って登録する。
トリガーワード
- 「テキストから抽出」「情報を抽出して」「ナラティブから登録」
- 「この文章を構造化して」「データベースに登録して」
- 「面談記録を入力」「聞き取り内容を登録」
- ファイル添付時(.docx, .xlsx, .pdf, .txt)
使用方法
Step 1: テキストの提供
ユーザーがテキストを直接入力するか、ファイルを添付する。
Step 2: 構造化データの抽出
以下のルールに従って、テキストからJSON形式のデータを抽出する。
抽出ルール(厳守)
-
絶対に入力テキストにない情報を創作・推測しない
- テキストに明示的に書かれていない情報は出力しない
- 「一般的にこうだろう」という推測は禁止
- 不明な項目は null または空配列 [] とする
-
暗黙知の抽出を優先する
- 「〜すると落ち着く」「〜が好き」→ carePreferences
- 「〜は嫌がる」「〜するとパニック」→ ngActions(最重要)
- 「今日〜した」「〜の対応で効果があった」→ supportLogs
-
禁忌事項(NgAction)は最優先
- 「絶対に〜しないで」「〜するとパニック」を漏らさない
- riskLevel を適切に判定:LifeThreatening / Panic / Discomfort
-
日付の変換
- 元号(和暦)→ 西暦(YYYY-MM-DD)に変換
- 明治元年=1868, 大正=1912, 昭和=1926, 平成=1989, 令和=2019
-
Entity Resolution(同一対象の統合)
- テキスト中の表記揺れは同一エンティティに統合すること
- 例:「健太」「けんた」「山田健太」「山田くん」→ 同一 Client
- 例:「お母さん」「母」「花子」→ 同一 KeyPerson
- 既存クライアントへの追記時は、Neo4j を検索して既存ノードと突合する
- 統合に確信が持てない場合はユーザーに確認すること
JSONスキーマ
{
"client": {
"name": "氏名(必須)",
"dob": "生年月日(YYYY-MM-DD形式、不明なら null)",
"bloodType": "血液型(不明なら null)",
"kana": "ふりがな(不明なら null)",
"aliases": ["通称やニックネーム"]
},
"conditions": [
{ "name": "特性・診断名", "status": "Active" }
],
"ngActions": [
{
"action": "絶対にしてはいけないこと",
"reason": "その理由(なぜ危険か)",
"riskLevel": "LifeThreatening | Panic | Discomfort",
Step 3: ユーザー確認
抽出したJSONをユーザーに提示し、修正点がないか確認する。
Step 4: Neo4jへの登録
確認後、neo4j MCP の execute_query を使って以下のCypherテンプレートで登録する(書き込みクエリも同じ execute_query ツールを使う)。
Cypherテンプレート
クライアント基本情報:
MERGE (c:Client {name: $name})
SET c.dob = CASE WHEN $dob IS NOT NULL THEN date($dob) ELSE c.dob END,
c.bloodType = COALESCE($blood, c.bloodType),
c.kana = COALESCE($kana, c.kana),
c.aliases = $aliases
特性・診断:
MATCH (c:Client {name: $client})
MERGE (con:Condition {name: $name})
SET con.status = $status
MERGE (c)-[:HAS_CONDITION]->(con)
禁忌事項(NgAction)- 最重要:
クライアント配下のノードとしてリレーションごと MERGE する(再実行で重複せず、他クライアントとノードを共有しない)。
MATCH (c:Client {name: $client})
MERGE (c)-[:MUST_AVOID]->(ng:NgAction {action: $action})
ON CREATE SET ng.reason = $reason, ng.riskLevel = $risk
ON MATCH SET ng.reason = COALESCE($reason, ng.reason),
ng.riskLevel = COALESCE($risk, ng.riskLevel)
推奨ケア(CarePreference):
MATCH (c:Client {name: $client})
MERGE (c)-[:REQUIRES]->(cp:CarePreference {category: $cat, instruction: $inst})
ON CREATE SET cp.priority = $pri
ON MATCH SET cp.priority = COALESCE($pri, cp.priority)
手帳・受給者証(Certificate):
手帳種別(type)×等級(grade)ごとに1ノード(SCHEMA_CONVENTION §10.3 の複合キー。
等級未指定は「不明」)。更新期限はノード側を上書きする。
発行日・状態はスキーマ規約どおりリレーション側(HAS_CERTIFICATE {issuedDate, status})に持つ。
MATCH (c:Client {name: $client})
MERGE (c)-[r:HAS_CERTIFICATE]->(cert:Certificate {type: $type, grade: COALESCE($grade, '不明')})
SET cert.nextRenewalDate = CASE WHEN $renewal IS NOT NULL THEN date($renewal) ELSE cert.nextRenewalDate END,
r.status = COALESCE(r.status, 'Active')
訂正(2026-07-12): 旧テンプレートは {type} のみを MERGE キーとしていたが、
SCHEMA_CONVENTION §10.3 の複合キー ["type","grade"] に合わせて修正した(DRIFT-08)。
キーパーソン(KeyPerson):
MATCH (c:Client {name: $client})
MERGE (c)-[r:HAS_KEY_PERSON]->(kp:KeyPerson {name: $name})
SET kp.phone = COALESCE($phone, kp.phone),
kp.relationship = COALESCE($rel, kp.relationship),
kp.role = COALESCE($role, kp.role),
r.rank = COALESCE($rank, r.rank)
後見人(Guardian):
MATCH (c:Client {name: $client})
MERGE (c)-[:HAS_LEGAL_REP]->(g:Guardian {name: $name})
SET g.type = COALESCE($type, g.type),
g.phone = COALESCE($phone, g.phone),
g.organization = COALESCE($org, g.organization)
医療機関(Hospital):
MATCH (c:Client {name: $client})
MERGE (h:Hospital {name: $name})
SET h.specialty = $spec, h.phone = $phone
MERGE (c)-[:TREATED_AT]->(h)
// かかりつけ医は Doctor ノードで表現(Hospital.doctor プロパティは廃止)
FOREACH (_ IN CASE WHEN $doc IS NULL OR $doc = '' THEN [] ELSE [1] END |
MERGE (d:Doctor {name: $doc})
MERGE (h)-[:HAS_DOCTOR]->(d))
生育歴(LifeHistory):
MATCH (c:Client {name: $client})
CREATE (h:LifeHistory {era: $era, episode: $episode, emotion: $emotion})
CREATE (c)-[:HAS_HISTORY]->(h)
願い(Wish):
MATCH (c:Client {name: $client})
CREATE (w:Wish {content: $content, status: 'Active', date: date($date)})
CREATE (c)-[:HAS_WISH]->(w)
支援記録(SupportLog):
MERGE (s:Supporter {name: $supporter})
WITH s
MATCH (c:Client {name: $client})
CREATE (log:SupportLog {
date: date($date),
situation: $situation,
action: $action,
effectiveness: $effectiveness,
note: $note
})
CREATE (s)-[:LOGGED]->(log)-[:ABOUT]->(c)
Step 5: 監査ログの記録(必須)
すべての書き込み操作の後、AuditLog ノードを作成して監査証跡を残すこと。
監査ログ(AuditLog):
CREATE (al:AuditLog {
timestamp: datetime(),
user: $user,
action: $action,
targetType: $targetType,
targetName: $targetName,
details: $details,
clientName: $clientName
})
RETURN al.timestamp AS 記録日時
パラメータ:
$user: 操作者名(不明なら "narrative-extractor")
$action: "CREATE" または "UPDATE"
$targetType: ノード種別(例: "Client", "NgAction", "SupportLog")
$targetName: 内容の要約
$details: 登録した主要フィールドの概要
$clientName: 対象クライアント名
運用ルール: 1回の抽出・登録操作で複数ノードを作成した場合、クライアント単位で1件の AuditLog にまとめてよい(details に登録内容の一覧を記載)。
命名規則(厳守)
- ノード: PascalCase (
Client, NgAction)
- リレーション: UPPER_SNAKE_CASE (
MUST_AVOID, HAS_KEY_PERSON)
- プロパティ: camelCase (
riskLevel, nextRenewalDate)
- 廃止名 (
PROHIBITED, PREFERS, EMERGENCY_CONTACT, RELATES_TO, HAS_GUARDIAN, HOLDS) は書き込み禁止
使用例
基本的な使い方
ユーザー: 以下の文章からクライアント情報を抽出してデータベースに登録してください。
健太は1995年3月15日生まれです。血液型はA型。
自閉スペクトラム症と診断されています。
後ろから急に声をかけないでください。パニックになります。
ファイルからの抽出
ユーザー: [ファイル添付] この面談記録から情報を抽出して登録してください。
追記モード
ユーザー: 山田健太さんの情報に以下を追加してください。
かかりつけは産業医科大学病院の中村先生(精神科)です。