Knowledge Graph Search(ナレッジグラフ検索)
ドキュメントからエンティティと関係のグラフを抽出し、裏付けとなる事実が複数のドキュメントに分散している質問に agent が回答できるようにします。
Knowledge Graph を使用する理由
Vector search は、質問に最も似ている passage を取得します。これは 1 つの passage に答えが含まれている場合には機能しますが、答えが複数の passage から組み立てられる場合には失敗します。
会社の filings を含む knowledge base を考えてみましょう。「Aldous Corporation はどの薬を販売していますか?」という質問の答えは 2 つに分かれています。あるドキュメントには Aldous が Bfarma Labs を買収したと書かれており、別のドキュメントには Bfarma Labs が Zalofen を製造していると書かれています。2 つ目のドキュメントには Aldous について一切触れられていないため、その内容は質問に似ているようには見えません。どのような規模の corpus でも、単に質問の文言を繰り返しているドキュメントに top-k の競争で負けてしまいます。
Knowledge graph は、共有されるエンティティを通じて passage をリンクします。
Aldous Corporation --[acquired]--> Bfarma Labs --[manufactures]--> Zalofen
Graph search は、質問に含まれるエンティティから開始し、それらの関係をたどり、到達した各エンティティの背後にある source passage を返します。そのドキュメントが取得されるのは、質問に似ているからではなく、質問に接続されているからです。
概要
Graph をオンにすると、2 つの点が変わります。
- Ingest 時。 各 chunk は追加の LLM pass を通り、エンティティ(people、organizations、products、locations)とそれらの関係が抽出されます。複数のドキュメントに現れるエンティティはマージされるため、graph は 1 つのファイルではなく knowledge base 全体にまたがります。
- Search 時。 新しい retrieval mode である
searchMode: 'graph'は、クエリから vector search によってエンティティを seed し、その関係を展開し、到達したエンティティを source chunk にマッピングし、それらの結果を標準の hybrid search と融合します。Hybrid search と比べて失われるものはありません。Graph channel は passage を追加するものであり、置き換えるものではありません。
エンティティ graph の上に、Squid は concept layer を構築します。document node、entity graph からクラスタリングされた themes(topics)、context metadata から派生した facet tree です。この layer は queryGraph() operations を支え、agent が passage の取得だけでなく、構造的な質問(「この knowledge base には何があるか」「この topic の下にどの documents があるか」「この 2 つはどのようにつながっているか」)を尋ねられるようにします。
使用するタイミング
| 状況 | 推奨事項 |
|---|---|
| 共有エンティティでリンクされた複数のドキュメントに回答がまたがる | ✅ Knowledge graph |
| 「A は B とどうつながっていますか」「X には何が関わっていますか」 | ✅ Knowledge graph |
| Agent が corpus を引用するだけでなく、説明またはナビゲートする必要がある | ✅ Knowledge graph、queryGraph() 経由 |
| Exact tokens: error codes、SKUs、file names | Keyword search |
| 1 つの passage が質問に答える | デフォルトの hybrid search で十分 |
要件
- Knowledge base は
vectorDbType: 'mongoAtlas'で作成されている必要があります。Vector store は作成後に immutable であるため、デフォルトの'postgres'store 上の knowledge base に後から graph を追加することはできません。Creating a Knowledge Base を参照してください。 graphRag自体は mutable なので、既存の Atlas knowledge base でいつでも graph をオンまたはオフにできます。- Graph extraction は ingest 時にすべての chunk に対して LLM を実行するため、embedding に加えて token cost がかかります。大規模 corpus で graph を有効にする前に予算を見積もり、実際の支出を
getGraphStatus()で追跡してください。 - Graph APIs は TypeScript SDK と Python SDK の両方で利用できます。このページの例は TypeScript を使用しています。Python client は、
squid.ai().knowledge_base(...)上でget_graph_status()、rebuild_graph()、query_graph()、explore_graph()、search_with_graph_context()として同じ surface を公開しています。
Quick Start
Knowledge base の管理には API key が必要なため、backend code から実行し、executable を通じて frontend に公開してください。
import { SquidService, executable } from '@squidcloud/backend';
export class KnowledgeGraphService extends SquidService {
@executable()
async createGraphKnowledgeBase(): Promise<void> {
await this.squid
.ai()
.knowledgeBase('filings-knowledgebase')
.upsertKnowledgeBase({
description: 'Company filings, acquisitions, and product lines',
embeddingModel: 'text-embedding-3-small',
chatModel: 'gpt-5.5',
metadataFields: [],
// Required: the graph is only built on the MongoDB Atlas vector store.
vectorDbType: 'mongoAtlas',
graphRag: {
enabled: true,
// Optional domain hint. Steers extraction toward the entity kinds you care about.
entityTypes: ['ORGANIZATION', 'PRODUCT', 'LOCATION'],
},
});
}
@executable()
async addFilings(): Promise<void> {
await this.squid
.ai()
.knowledgeBase('filings-knowledgebase')
.upsertContexts([
{
contextId: 'acquisition-2019',
type: 'text',
title: 'Acquisition',
text: 'Aldous Corporation acquired Bfarma Labs in 2019 for two billion dollars.',
},
{
contextId: 'product-line',
type: 'text',
title: 'Product line',
text: 'Bfarma Labs manufactures a migraine drug called Zalofen at its Dublin plant.',
},
]);
}
}
Entity extraction は ingestion と inline で実行されるため、graph を queryable にするための rebuild は不要です。Indexing の bookkeeping は upsertContexts() が解決した少し後に落ち着くため、Monitoring the graph で示すように、graph が ready であると assert する前に待機してください。
Search には API key は不要で、client から実行できます。
- TypeScript
- Python
// 'graph' is the default mode on a graph-enabled knowledge base, so searchMode is optional here.
const chunks = await squid.ai().knowledgeBase('filings-knowledgebase').search({
prompt: 'Which drugs does Aldous Corporation sell?',
searchMode: 'graph',
});
# 'graph' is the default mode on a graph-enabled knowledge base, so searchMode is optional here.
chunks = await squid.ai().knowledge_base('filings-knowledgebase').search(
'Which drugs does Aldous Corporation sell?',
options={'searchMode': 'graph'},
)
Traversal は Aldous Corporation から Bfarma Labs を経由して Zalofen に到達するため、product-line chunk は Aldous Corporation に言及していなくても取得されます。たどった chain は searchWithGraphContext() で確認できます。
2 つの document だけの knowledge base で search modes の違いが見えるとは期待しないでください。競合するものがない場合、どの mode もすべてを返します。Graph が真価を発揮するのは、top-k を争うのに十分な document があり、接続されているが類似していない passage が通常なら押し出されてしまう場合です。
設定
graphRag の各 field のうち、enabled 以外はすべて optional です。
| Field | Type | Description |
|---|---|---|
enabled | boolean | Extraction と searchMode: 'graph' をオンにします。必須です。 |
entityTypes | string[] | Extraction prompt に注入される domain taxonomy hint です。例: ['ORGANIZATION', 'PRODUCT']。抽出を制限するのではなくガイドします。 |
extractionModel | AiChatModelSelection | Per-chunk extraction に使用される chat model です。デフォルトは server の graph model です。 |
autoBuildDebounceMs | number | automatic build が実行される前の quiet window です。正の整数で、デフォルトは server の 5 分 window です。 |
concepts | object | Concept layer configuration です。concepts.facets はどの metadata fields を facets にするかを選択し(デフォルトは 'auto'、無効化は [])、concepts.pathFacets は hierarchical path field から navigable tree を構築します。 |
Path facet は folder path を graph 内の browsable hierarchy に変換します。
await this.squid
.ai()
.knowledgeBase('filings-knowledgebase')
.upsertKnowledgeBase({
description: 'Company filings, acquisitions, and product lines',
embeddingModel: 'text-embedding-3-small',
chatModel: 'gpt-5.5',
metadataFields: [],
vectorDbType: 'mongoAtlas',
graphRag: {
enabled: true,
concepts: {
// Build a folder tree from the folderPath metadata stamped by folder-aware uploads.
pathFacets: [{ field: 'folderPath', type: 'path' }],
},
},
});
graphRag を upsert すると object 全体が置き換えられるため、省略した field は失われます。1 つの field だけを変更したい場合は、getKnowledgeBase() で現在の configuration を読み取り、spread してください。
既存の Knowledge Base で Graph を有効にする
すでに content を保持している Atlas knowledge base で enabled を true に切り替えると、Squid が graph を backfill します。Squid は knowledge base が quiet になるのを待ってから、まだ graph indexed されていないすべての context を抽出し、その上に concept layer を構築する structural build を実行します。rebuildGraph() を呼び出す必要はありません。
const kb = this.squid.ai().knowledgeBase('filings-knowledgebase');
const existing = await kb.getKnowledgeBase();
// Spread the current configuration so enabling the graph does not drop any other field.
await kb.upsertKnowledgeBase({ ...existing!, graphRag: { enabled: true } });
自動 build
Concept layer(themes と facets)は corpus 全体から派生するため、document ごとではなく batch で rebuild されます。Build は、content の ingest、content の delete、または graph の enable といった graph activity の後に自動的に scheduled されます。
- Build は、最後の graph work の完了時点から測定される quiet window を待ちます。まだ進行中の ingestion は deadline を先延ばしし続けるため、長い bulk upload では document ごとに 1 回ではなく、最後に 1 回の build が生成されます。
- Window のデフォルトは 5 分 で、
graphRag.autoBuildDebounceMsによって knowledge base ごとに設定できます。 - Sweep は due の knowledge base を毎分チェックするため、経過した window は期限切れからおよそ 1 分以内に拾われます。
- Build が pending の間、
getGraphStatus()はnextAutoBuildAtを報告します。Activity が続く限り、これは先に進みます。
Entity extraction はこの schedule の一部ではありません。Ingestion と inline で実行されるため、searchMode: 'graph' は concept layer が追いつく前の freshly ingested documents でも機能します。遅れるのは、queryGraph() が読み取る theme と facet structure です。
Build を強制する
Quiet window を待ちたくない場合は rebuildGraph() を呼び出します。デフォルトの 'structural' mode がほとんどの場合に必要なものです。以下の 'full' に関する warning を参照してください。
// Runs a structural build (the default): folds newly ingested documents into topics and
// facets now, reusing the extracted entities. Same build the automatic schedule runs.
await this.squid.ai().knowledgeBase('filings-knowledgebase').rebuildGraph();
| Mode | 再計算する内容 | Cost |
|---|---|---|
'structural' (default) | Entity resolution、themes、facets。Extraction は graph indexed されたことがない contexts に対してのみ実行されます。 | Full rebuild のごく一部です。 |
'full' | すべて。すべての chunk の LLM re-extraction を含みます。 | Re-extraction が大部分を占めます。Initial ingest と同程度です。 |
'full' rebuild が必要になることはまれであり、destructive で slow でもあります。既存の graph を最初に wipe し、その後すべての chunk を LLM で re-extract するため、initial ingest と同程度の tokens と時間がかかります。また job が完了するまで、searchMode: 'graph' と queryGraph() は incomplete graph に対して実行されます。Extraction はすでに ingestion と inline で実行されるため、新規または更新された documents に full rebuild は不要です。Structural build がそれらを取り込みます。mode: 'full' を明示的に request するのは、entityTypes または extractionModel を変更した後など、extraction 自体をやり直す必要がある場合のみにしてください。
Knowledge base ごとに同時に実行される rebuild は 1 つだけです。getGraphStatus().buildJob で追跡してください。
Graph で検索する
Graph-enabled knowledge base では searchMode: 'graph' がデフォルト mode であるため、searchMode を省略すると graph が使用されます。他の modes も引き続き利用可能で、Searching a Knowledge Base で説明されています。
graphOptions で traversal を調整します。
| Option | Default | Limit | Description |
|---|---|---|---|
seedLimit | 8 | 25 | Expansion 前に vector search によって seeded される entities。 |
maxHops | 2 | 3 | Traversal が各 seed からどこまで expand するか。 |
includeGraphContext | false | Traversed subgraph を response に添付します。 |
const chunks = await squid
.ai()
.knowledgeBase('filings-knowledgebase')
.search({
prompt: 'How is Aldous Corporation connected to Dublin?',
searchMode: 'graph',
graphOptions: { seedLimit: 12, maxHops: 3 },
});
maxHops を上げると net が広がり、より弱い associations も取り込まれるため、本当に multi-hop な質問の場合にのみ上げてください。
Search を concept に scope する
graphFilter は、検索を graph の 1 つの concept 配下の documents に制限します。これは、user がすでに subject を絞り込んでいる場合に便利です。すべての search mode および contextMetadataFilter と合成できるため、thematic scope と metadata filter を組み合わせることができます。
const chunks = await squid
.ai()
.knowledgeBase('filings-knowledgebase')
.search({
prompt: 'What was the purchase price?',
// A theme name, a facet value, or a facet nodeId. Names are resolved server side.
graphFilter: { underConcept: 'Acquisitions' },
});
Facet scopes は exact metadata membership で filter します。Theme scopes は thematic であるため recall-safe ですが fuzzy です。Theme の現在の membership の外にある document は、関連していても除外されます。解決できない concept は CONCEPT_NOT_FOUND と最も近い matching names で失敗します。
Traversal を検査する
search() は chunks のみを返します。どの entities と relationships がそれらを生み出したかを確認するには、includeGraphContext 付きで searchWithGraphContext() を使用します。これは retrieval の debugging や、なぜ passage が返されたのかを users に示すのに役立ちます。
const response = await squid
.ai()
.knowledgeBase('filings-knowledgebase')
.searchWithGraphContext({
prompt: 'Which drugs does Aldous Corporation sell?',
searchMode: 'graph',
graphOptions: { includeGraphContext: true },
});
for (const entity of response.graphContext?.entities ?? []) {
console.log(`${entity.name} (${entity.type}): ${entity.description}`);
}
for (const rel of response.graphContext?.relationships ?? []) {
console.log(`${rel.source} --[${rel.type}]--> ${rel.target}`);
}
graphContext は、search が graph mode で includeGraphContext: true とともに実行された場合にのみ存在します。
Graph を直接 Query する
queryGraph() は passage を取得するのではなく、graph の structure を読み取ります。各 operation は単一の round trip で complete answer を返します。
| Op | Required input | Returns |
|---|---|---|
overview | Knowledge base の rendered map: themes、facets、counts。 | |
resolve | ref | Documents、entities、themes、facets 全体で name に一致する nodes。 |
describe | ref | 1 つの node と、その ancestors および immediate neighbors。 |
subtree | ref | depth(default および cap は 3)までの、document counts 付き node subtree。 |
docsUnder | ref | Node の closure 配下の documents。totalDocs は full size を報告します。 |
conceptsOf | contextId | 1 つの document が属する facets と themes。 |
neighborhood | ref | Entity 周辺の entity subgraph。hops(default 1、max 2)で expand。 |
pathBetween | ref and refB | 2 つの nodes を接続する relationship chain、またはそれらが共有する concepts。 |
globalSummary | query | 質問に対して ranked された knowledge base の theme summaries。 |
const kb = this.squid.ai().knowledgeBase('filings-knowledgebase');
// What is in this knowledge base?
const overview = await kb.queryGraph({ op: 'overview' });
console.log(overview.overview);
// How are two things connected?
const path = await kb.queryGraph({
op: 'pathBetween',
ref: 'Aldous Corporation',
refB: 'Zalofen',
});
if (path.pathBetween?.tier === 'entity') {
// An explanatory chain: Aldous Corporation acquired Bfarma Labs, which manufactures Zalofen.
for (const step of path.pathBetween.steps ?? []) {
console.log(`${step.from} --[${step.type}]--> ${step.to}`);
}
} else {
// No entity chain exists, so the answer falls back to the concepts both refs sit under.
console.log(path.pathBetween?.sharedConcepts);
}
ref は name(Squid が server side で exact match、次に alias、次に similarity によって解決)または facet nodeId を受け付けます。Persist する価値のある stable handles は、facet nodeIds と document contextIds のみです。Theme と entity ids は rebuild のたびに変わるため、毎回 name で resolve してください。
Graph を Explore する
exploreGraph() は visualization 用に entity graph の bounded slice を返します。最も degree の高い entities と、それらの間の relationships です。
const subgraph = await this.squid.ai().knowledgeBase('filings-knowledgebase').exploreGraph({
nodeLimit: 100, // Default 200, max 1000.
});
console.log(`${subgraph.nodes.length} nodes, ${subgraph.edges.length} edges`);
// topics maps each node's topicPath ids to names, so a visualization can group by theme.
console.log(subgraph.topics?.map((topic) => topic.name));
topicId を渡すと、slice を 1 つの theme に制限できます。Theme ids は getGraphStatus().topics または以前の exploreGraph() response から取得され、次の rebuild までのみ有効です。
Graph を Monitoring する
getGraphStatus() は build state、coverage、cost を報告します。
const status = await this.squid.ai().knowledgeBase('filings-knowledgebase').getGraphStatus();
console.log(`${status.contextsIndexed}/${status.contextsTotal} contexts graph indexed`);
console.log(`${status.entityCount} entities, ${status.relationshipCount} relationships`);
console.log(`Graph ingest cost so far: $${status.ingestUsage?.estCostUsd ?? 0}`);
if (status.buildJob?.status === 'in_progress') {
console.log(`Build running since ${new Date(status.buildJob.startedAt!).toISOString()}`);
} else if (status.structureStale) {
console.log(`${status.staleDocCount} documents changed since the last build`);
}
if (status.nextAutoBuildAt) {
console.log(`Next automatic build around ${new Date(status.nextAutoBuildAt).toISOString()}`);
}
知っておくべき fields:
| Field | Meaning |
|---|---|
enabled | この knowledge base で graph がオンかどうか。 |
contextsIndexed / contextsTotal | Extraction coverage。値が等しい場合、すべての context が graph に含まれています。 |
entityCount / relationshipCount | Entity graph のサイズ。 |
topics / facets | Concept layer。build が実行されると populated されます。 |
structureStale / staleDocCount | 前回の concept build 以降に graph indexed された documents。Themes は次の build まで content より遅れます。 |
buildJob | 最新の build: 失敗時の status、startedAt、error。 |
lastStructureBuildAt | Build が最後に正常完了した時刻。まだ一度もない場合は存在しません。 |
nextAutoBuildAt | Pending automatic build の予定時刻。scheduled されていない場合は存在しません。 |
ingestUsage / lastRebuildUsage | LLM tokens と estimated cost。byModel の下で model ごとに分割されます。 |
Graph が完全に ready になるのを待つには、contextsIndexed === contextsTotal かつ buildJob が 'in_progress' ではなくなるまで poll してください。
Console から Graph を使用する
Squid Console は、同じ機能を code なしで公開しています。
- Create a knowledge base で Vector Store を
mongoAtlasに設定し、Knowledge Graph toggle をオンにします。この toggle は、Server default を含む他の store では disabled のままです。これは store が作成後に変更できないためです。Server default で作成された knowledge base が Atlas に解決される場合は、後から編集して graph を有効にできます。 - Knowledge base page には Knowledge Graph card が表示され、last build time、その後に変更された documents の数、次の automatic build の estimated time、そして structural build を即座に実行する Build now button が表示されます。
Agent Behavior
接続された agents は自動的に graph を利用します。Graph-enabled knowledge base では次のようになります。
- Knowledge base search tool は他の modes と並んで
'graph'を提供し、それを default として扱うため、multi-hop questions はこちらで prompt しなくても graph retrieval を使用します。 - Tool description には graph の compact overview が含まれ、agent は search 前に corpus の themes と counts を得られます。
- Agent は、上記の operations に backed された
queryKnowledgeGraphtool を取得するため、passage の取得だけでなく corpus structure をナビゲートできます。
Knowledge base を agent に接続する方法については、Agent abilities を参照してください。
Error Handling
| Error | Cause | Fix |
|---|---|---|
CONCEPT_NOT_FOUND | queryGraph() の ref が何にも一致しませんでした。Message には nearest names が一覧表示されます。 | まず op: 'resolve' で names を resolve するか、suggested names のいずれかを使用します。 |
TOPIC_NOT_FOUND | exploreGraph() の topicId が不明です。通常は rebuild によって ids が churn したためです。 | Persist するのではなく、各 rebuild 後に getGraphStatus() から theme ids を再読み込みします。 |
JOB_ALREADY_EXISTS | この knowledge base で rebuild がすでに実行中です。 | getGraphStatus().buildJob が 'in_progress' ではなくなるまで待ちます。 |
| Graph calls succeed but return empty | Knowledge base が mongoAtlas 上にない、または graphRag.enabled が false です。そこでは graph operations は no-op です。 | getGraphStatus().enabled と knowledge base の vectorDbType を確認します。 |
buildJob.status === 'failed' | Build が error に遭遇し、buildJob.error に記録されました。 | 根本原因を修正し、rebuildGraph() を再実行します。次の automatic build でも retry されます。 |
graphRag を無効にすると、knowledge base の graph data が削除されます。再度有効にすると、full extraction cost をかけて最初から rebuild されます。
Best Practices
- Knowledge base を作成する前に graph を使うかどうかを決めてください。
vectorDbTypeは immutable であるため、'postgres'knowledge base は後から graph を追加できません。 - Domain に合った
entityTypesを渡してください。Extraction は、generic product categories よりも、organizations、people、locations などの proper nouns に対して著しく信頼性が高くなります。 - Bulk ingest の前に graph を有効にし、後で full rebuild を必要とするのではなく、extraction が inline で行われるようにしてください。
maxHopsは default のままにしてください。本当に数 hop 深い質問の場合に上げ、そうすると結果がより緩くなることを想定してください。- まず小さな corpus で
ingestUsage.estCostUsdを確認し、すべてに graph を有効にした場合の cost を見積もってください。 - Continuous ingestion 中の knowledge base では
autoBuildDebounceMsを広げ、build が moving target を追いかけないようにします。小さな updates 後に themes をすばやく refresh したい場合は短くしてください。 - Rebuild をまたいでは、theme ids ではなく theme names を resolve してください。Stable なのは facet nodeIds と document contextIds のみです。