neo4j-genai-plugin-skill について
neo4j-genai-plugin-skillは、CypherからGenAIプラグインを使いたいNeo4jユーザー向けのガイドです。埋め込み、テキスト生成、構造化出力、チャット、テキスト分割を扱い、別途Pythonの処理系を用意せずにLLMを呼び出せます。
主な機能
- 01Cypher内でテキスト埋め込みを生成
- 02埋め込みのバッチ処理とLLM呼び出し
- 03構造化出力と集約要約の生成
- 04Cypherでチャットセッションを管理
- 05トークン数の計測と上限に応じた分割
活用シーン
- 01取り込み時にノードやテキストチャンクを埋め込む
- 02クエリ内でテキストを要約する
- 03グラフデータから構造化フィールドを抽出する
- 04長文をトークン上限に合わせて分割する
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ neo4j-contrib/ neo4j-skills --skill neo4j-genai-plugin-skillインストール後、Claude Code で/neo4j-genai-plugin-skillを入力して読み込まれたか確認します。
同梱ファイルREADME.mdreferences/providers.md
詳細
使用する場面
- 外部の Python を使わずに Cypher 内で埋め込みを生成する場合(
ai.text.embed()) - 取り込み時にノード/チャンクを一括で埋め込む場合(
ai.text.embedBatch()) - 補完や GraphRAG のために Cypher から LLM を直接呼び出す場合(
ai.text.completion()) - Cypher 内で LLM から構造化 JSON マップを抽出する場合(
ai.text.structuredCompletion()) - グループ化した行に対する LLM の要約を集約する場合(
ai.text.aggregateCompletion()) - Cypher でステートフルなチャットセッションを行う場合(
ai.text.chat()) - トークン数を数える場合、またはトークン上限に基づいてテキストをチャンク化する場合(
ai.text.tokenCount()、ai.text.chunkByTokenLimit())
使用しない場面
- Python ベースの GraphRAG パイプライン(VectorCypherRetriever、HybridCypherRetriever)→
neo4j-graphrag-skill - ベクトルインデックスの CREATE/kNN 検索/SEARCH 句 →
neo4j-vector-index-skill - GDS の埋め込み(FastRP、Node2Vec)→
neo4j-gds-skill - 全文検索/キーワード検索 →
neo4j-cypher-skill
前提条件
すべての ai.* 関数で CYPHER 25 が必要です。有効にする方法は 2 つあります。
// Per-query prefix (self-managed, no admin rights needed):
CYPHER 25 MATCH (n:Chunk) ...
// Per-database default (admin; applies to all sessions):
ALTER DATABASE neo4j SET DEFAULT LANGUAGE CYPHER 25
インストール:
- Aura:GenAI プラグインはデフォルトで有効です。操作は不要です
- セルフマネージド JAR:プラグイン JAR を
plugins/ディレクトリにコピーします - Docker:
--env NEO4J_PLUGINS='["genai"]'
プロバイダー設定のクイックリファレンス
すべての ai.text.* 関数は、最後の引数として configuration :: MAP を受け取ります。
| プロバイダー文字列 | 必須キー | 備考 |
|---|---|---|
'openai' | token, model | token = OpenAI API キー |
'azure-openai' | token, resource, model | token = OAuth2 ベアラートークン、resource = Azure リソース名 |
'vertexai' | model, project, region, token または apiKey | publisher のデフォルトは 'google' です |
'bedrock-titan' | model, region, accessKeyId, secretAccessKey | 埋め込みのみ |
'bedrock-nova' | model, region, accessKeyId, secretAccessKey | 補完のみ |
すべてで任意指定可能:vendorOptions :: MAP を使うと、プロバイダー固有の追加オプションを渡せます(例:OpenAI の場合は { dimensions: 1024 })。
❌ API キーをリテラルとしてハードコードしないでください。✅ ドライバーのパラメーター辞書で渡す $param を必ず使用してください。
プロバイダー設定の全表 → references/providers.md
埋め込み
単一の埋め込み [2025.11]
CYPHER 25
MATCH (c:Chunk)
WHERE c.embedding IS NULL
WITH c
CALL {
WITH c
SET c.embedding = ai.text.embed(c.text, 'openai', {
token: $openaiKey,
model: 'text-embedding-3-small'
})
} IN TRANSACTIONS OF 500 ROWS
ai.text.embed() は VECTOR を返します。ベクトルインデックスに直接保存して検索できます。
一括埋め込みプロシージャ [2025.11]
CYPHER 25
MATCH (c:Chunk) WHERE c.embedding IS NULL
WITH collect(c) AS chunks
UNWIND chunks AS c
WITH c.text AS text, c AS node
CALL ai.text.embedBatch(text, 'openai', { token: $openaiKey, model: 'text-embedding-3-small' })
YIELD index, resource, vector
MATCH (c:Chunk {text: resource})
SET c.embedding = vector
プロシージャのシグネチャ:CALL ai.text.embedBatch(resource, provider, config) YIELD index, resource, vector
設定済みの埋め込みプロバイダーを一覧表示する
CYPHER 25
CALL ai.text.embed.providers()
YIELD name, requiredConfigType, optionalConfigType, defaultConfig
RETURN name, requiredConfigType
テキスト補完 [2025.11]
CYPHER 25
RETURN ai.text.completion(
'Summarize: ' + $text,
'openai',
{ token: $openaiKey, model: 'gpt-4o-mini' }
) AS summary
STRING を返します。
補完の集約 — 行をまたいで要約する [2026.03]
CYPHER 25
MATCH (c:Chunk)-[:PART_OF]->(a:Article {id: $articleId})
RETURN ai.text.aggregateCompletion(
c.text,
'Summarize the following article chunks in 3 sentences',
'openai',
{ token: $openaiKey, model: 'gpt-4o-mini' }
) AS summary
value パラメーターには、LLM に渡す各行の STRING を指定します。文字列以外の値には toString() を使用します。
Cypher のみで行う GraphRAG パターン
質問を埋め込み → ベクトル検索 → グラフをたどる → LLM 補完――すべてを 1 つの Cypher クエリで実行します。
CYPHER 25
WITH ai.text.embed($question, 'openai', { token: $openaiKey, model: 'text-embedding-3-small' }) AS qEmbedding
MATCH (chunk:Chunk)
SEARCH chunk IN (VECTOR INDEX chunk_embedding FOR qEmbedding LIMIT 10) SCORE AS score
// SEARCH preferred on 2026.x; db.index.vector.queryNodes() deprecated 2026.04 — SEARCH syntax → neo4j-vector-index-skill
MATCH (chunk)<-[:HAS_CHUNK]-(article:Article)
OPTIONAL MATCH path = shortestPath((article)-[*..3]-(other:Article))
WITH chunk, article, collect(DISTINCT other.title) AS related, score
ORDER BY score DESC LIMIT 5
WITH collect(chunk.text + '\n[Source: ' + article.title + ']') AS context, $question AS question
RETURN ai.text.completion(
'Answer based on context:\n' + reduce(s='', c IN context | s + c + '\n') + '\nQuestion: ' + question,
'openai',
{ token: $openaiKey, model: 'gpt-4o-mini' }
) AS answer
重要なポイント(Bergman):シードノード間の最短パスによって、直接の近傍だけでは見つからない関係が明らかになります。
構造化出力 [2026.02]
MAP を返します。ノードのプロパティとして直接保存したり、Cypher の後続処理で使用したりできます。
CYPHER 25
MATCH (p:Product {id: $productId})
WITH p,
ai.text.structuredCompletion(
'Extract key attributes from: ' + p.description,
{
type: 'object',
properties: {
category: { type: 'string' },
tags: { type: 'array', items: { type: 'string' } },
priceRange: { type: 'string', enum: ['budget', 'mid', 'premium'] }
},
required: ['category', 'tags', 'priceRange'],
additionalProperties: false
},
'openai',
{ token: $openaiKey, model: 'gpt-4o-mini' }
) AS extracted
SET p.category = extracted.category,
p.priceRange = extracted.priceRange
WITH p, extracted.tags AS tags
UNWIND tags AS tag
MERGE (t:Tag {name: tag})
MERGE (p)-[:TAGGED]->(t)
構造化補完の集約 — 複数の行から抽出する [2026.03]
CYPHER 25
MATCH (:User {id: $userId})-[:ORDERED]->(o:Order)-[:CONTAINS]->(p:Product)
RETURN ai.text.aggregateStructuredCompletion(
p.name + ': ' + p.category,
'Build a shopping profile for this user',
{
type: 'object',
properties: {
preferredCategories: { type: 'array', items: { type: 'string' } },
spendingTier: { type: 'string', enum: ['economy', 'standard', 'premium'] }
},
required: ['preferredCategories', 'spendingTier']
},
'openai',
{ token: $openaiKey, model: 'gpt-4o-mini' }
) AS profile
チャット [2025.12]
対応プロバイダー:openai と azure-openai のみです。
// Start new conversation (chatId = null → new session)
CYPHER 25
WITH ai.text.chat(
'Hello, who are you?',
null,
'openai',
{ token: $openaiKey, model: 'gpt-4o-mini' }
) AS result
RETURN result.message AS reply, result.chatId AS sessionId
// Continue conversation (pass returned chatId)
CYPHER 25
WITH ai.text.chat(
'What did I just ask you?',
$chatId,
'openai',
{ token: $openaiKey, model: 'gpt-4o-mini' }
) AS result
RETURN result.message AS reply, result.chatId AS sessionId
MAP { message: STRING, chatId: STRING } を返します。セッションを継続するには chatId を保存してください。
トークナイズとチャンク分割 [2026.04]
// Count tokens before sending to LLM
CYPHER 25
RETURN ai.text.tokenCount($text, 'openai', { token: $openaiKey, model: 'gpt-4o-mini' }) AS tokenCount
// Chunk text by token limit (no external dependencies)
CYPHER 25
UNWIND ai.text.chunkByTokenLimit($longText, 512, 'gpt-4', 50) AS chunk
MERGE (c:Chunk { text: chunk })
// List providers supporting tokenCount
CYPHER 25
CALL ai.text.tokenCount.providers() YIELD name, requiredConfigType
RETURN name, requiredConfigType
シグネチャ:
ai.text.tokenCount(input, provider, configuration = {}) :: INTEGER— プロバイダーに基づくトークナイザーです。プロバイダーの設定(トークン/モデル)を使用します。'openai'の場合はローカルトークナイザーを使用し(API 呼び出しなし)、'Bedrock'と'VertexAI'の場合は無料の API 呼び出しを行います。ai.text.chunkByTokenLimit(input, limit, model = 'gpt-4', overlap = 0) :: LIST<STRING>—modelに基づくローカルの OpenAI トークナイザーです。プロバイダー呼び出しはなく、tokenも必要ありません。改行、スペース、トークン数の順に基づいてチャンク分割します。プロンプトのオーバーヘッド分を確保するため、limitはプロバイダーの最大値より小さく設定してください。
ai.text.embedBatch [2026.04] は、API リクエストあたりのデータ量を制限する maxBatchSize(設定キー)に対応しています。'openai' と 'azure-openai' ではデフォルト値は 8192 です。'vertexai' にはデフォルト値がありません(トークン制限エラーが発生する場合は設定してください)。
書き込みゲート
SET node.embedding = ai.text.embed(...) と SET node.* = ai.text.structuredCompletion(...) はグラフに書き込みます。
一括書き込みの前に:
- まずノード数を数えます:
MATCH (c:Chunk) WHERE c.embedding IS NULL RETURN count(c) - バッチ処理の前に、1 つのテストノードで設定を検証します
- 1000 ノードを超えるバッチには
CALL { ... } IN TRANSACTIONS OF 500 ROWSを使用します - 実行前に明示的な確認を必須にします
非推奨 — 使用しないでください
| 旧関数 | 置き換え先 |
|---|---|
genai.vector.encode() [deprecated] | ai.text.embed() |
genai.vector.encodeBatch() [deprecated] | CALL ai.text.embedBatch() |
genai.vector.listEncodingProviders() [deprecated] | CALL ai.text.embed.providers() |
よくあるエラー
| エラー | 原因 | 修正方法 |
|---|---|---|
Unknown function 'ai.text.embed' | CYPHER 25 プレフィックスがない、またはプラグインがインストールされていない | CYPHER 25 プレフィックスを追加します。プラグインがインストールされていることを確認します |
Cypher version not supported | Neo4j < 5.20 で CYPHER 25 を使用している、またはプラグインがない | Neo4j をアップグレードします。GenAI プラグインが読み込まれていることを確認します |
Configuration key 'token' missing | プロバイダー設定マップが不完全 | プロバイダーに必要なキーを確認します(上の表を参照) |
null returned from embed | モデル名が間違っている、またはプロバイダーの認証に失敗した | RETURN ai.text.embed('test', 'openai', {token:$k, model:'text-embedding-3-small'}) を単独でテストします |
Unsupported provider | プロバイダー文字列の入力ミス(大文字と小文字を区別します) | 'OpenAI' ではなく 'openai' を使用します。CALL ai.text.embed.providers() を実行します |
ai.text.chat fails on VertexAI | チャットは openai/azure-openai のみ対応 | チャットには openai/azure-openai を使用します |
チェックリスト
- すべての ai.text.* クエリに
CYPHER 25プレフィックスがある - GenAI プラグインがインストールされている(Aura:自動、セルフマネージド:plugins/ 内の JAR)
- API キーは
$paramとして渡し、リテラル文字列として渡さない - 設定に
modelキーを明示する(暗黙のデフォルト値を使用しない) - プロバイダー文字列は小文字(
'openai'、'vertexai'、'bedrock-titan') - 一括書き込みでは
IN TRANSACTIONS OF 500 ROWSを使用し、まず対象ノード数を数える -
genai.vector.encode()をai.text.embed()に置き換える [2025.11+] - チャットセッション:継続用に返された
chatIdを保存する。対応しているのは openai/azure-openai のみ - 幻覚によるキーの生成を防ぐため、構造化出力スキーマで
additionalProperties: falseを使用する
参考資料
- プロバイダー設定の全項目 — プロバイダーごとの必須キー/任意キー
- 公式ドキュメント
- API リファレンス