Knowledge Graph Search
document から entity と relationship の graph を抽出し、根拠となる事実が複数 document に分散する質問に agent が回答できるようにします。
Knowledge Graph を使用する理由
vector search は、質問に最も似ている passage を取得します。1 つの passage に答えが含まれている場合は機能しますが、複数の passage から答えを組み立てる場合は機能しません。
company filing の knowledge base を考えてみましょう。「Aldous Corporation はどの drug を販売していますか?」という質問の答えは 2 つに分かれています。1 つの document には Aldous が Bfarma Labs を買収したこと、もう 1 つには Bfarma Labs が Zalofen を製造していることが記載されています。2 つ目の document には Aldous が一切登場しないため、質問との類似性はありません。ある程度の規模の corpus では、質問の文言を単に繰り返す document との top-k 競争に負けます。
knowledge graph は、共有する entity を通じて passage を結び付けます。
Aldous Corporation --[acquired]--> Bfarma Labs --[manufactures]--> Zalofen
graph search は質問に含まれる entity から開始し、relationship をたどり、到達したすべての entity の背後にある source passage を返します。document は質問に似ているからではなく、質問に接続されているから取得されます。
概要
graph を有効にすると、次の 2 つが変わります。
- Ingest 時。 各 chunk は追加の LLM pass を通過し、entity(person、organization、product、location)と、それらの関係を抽出します。複数 document に出現する entity は merge されるため、graph は単一 file ではなく knowledge base 全体にまたがります。
- Search 時。 新しい retrieval mode である
searchMode: 'graph'は、vector search を使用して query から entity を seed し、その relationship を expand して、到達した entity を source chunk に map し、その result を標準 hybrid search と fuse します。hybrid search と比べて失われるものはありません。graph channel は passage を追加するものであり、置き換えるものではありません。
entity graph の上に、Squid は document node、entity graph から cluster 化された theme(topic)、context metadata から導出された facet tree で構成される concept layer を構築します。この layer は queryGraph() operation を支え、agent は passage を取得するだけでなく、「この knowledge base には何があるか」、「この topic に含まれる document は何か」、「この 2 つはどのように接続されているか」といった structural question を尋ねられます。
使用する場合
| 状況 | 推奨 |
|---|---|
| shared entity で接続された複数 document に答えがまたがる | ✅ Knowledge graph |
| 「A は B とどのように接続されているか」「X に関係するものは何か」 | ✅ Knowledge graph |
| agent が passage を quote するだけでなく corpus を説明・navigate する必要がある | queryGraph() を使用する ✅ Knowledge graph |
| error code、SKU、file name などの exact token | Keyword search |
| 1 つの passage が質問に回答できる | default の hybrid search で十分 |
要件
- knowledge base は
'mongoAtlas'vector store 上にある必要があります。store は作成後 immutable であるため、'postgres'上で作成された knowledge base に後から graph を追加することはできません。deployment により異なる server default に依存せず、vectorDbType: 'mongoAtlas'を明示的に渡してください。既存 knowledge base に設定された値はgetKnowledgeBase()で確認できます。Creating a Knowledge Baseを参照してください。 graphRag自体は mutable であるため、既存の Atlas knowledge base で graph をいつでも有効・無効にできます。- graph extraction は ingest 時にすべての chunk で LLM を実行するため、embedding に加えて token cost が発生します。大規模 corpus で graph を有効にする前に budget を考慮し、実際の費用は
getGraphStatus()で追跡してください。 - graph API は TypeScript と Python の SDK で利用できます。この page の例は TypeScript を使用しています。Python client は
squid.ai().knowledge_base(...)でget_graph_status()、rebuild_graph()、query_graph()、explore_graph()、search_with_graph_context()と同じ surface を公開します。
クイックスタート
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 によって trigger され、request path 外で asynchronous に実行されます。そのため graph を query 可能にするための rebuild は不要ですが、upsertContexts() の resolve は graph の準備完了を意味しません。Monitoring the graphで示すように、graph retrieval に依存する前に、すべての context が index 化されるまで getGraphStatus() を poll してください。extraction は knowledge base ごとの limit までの context を対象とします。Graph indexing capを参照してください。
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 は Bfarma Labs を通じて Aldous Corporation から Zalofen に到達するため、Aldous Corporation に一切言及していない場合でも product-line chunk が取得されます。たどった chain は searchWithGraphContext() で確認できます。
2 document の knowledge base では search mode 間の違いは期待しないでください。競合するものがなければ、すべての mode がすべてを返します。graph が有用になるのは、connected ではあるものの類似しない passage が通常は除外されるほど、top-k を競う document が十分にある場合です。
Configuration
enabled を除く graphRag のすべての field は optional です。
| Field | Type | 説明 |
|---|---|---|
enabled | boolean | extraction と searchMode: 'graph' を有効にします。必須です。 |
entityTypes | string[] | たとえば ['ORGANIZATION', 'PRODUCT'] のように extraction prompt に inject する domain taxonomy hint。extraction を guide しますが、制限はしません。 |
extractionModel | AiChatModelSelection | chunk ごとの extraction に使用する chat model。default は server の graph model です。 |
autoBuildDebounceMs | number | automatic build の実行前の quiet window。positive integer で、default は server の 5 分 window です。 |
concepts | object | concept layer の configuration。concepts.facets は facet にする metadata field を選択します(default は 'auto'、disable するには [])。concepts.pathFacets は hierarchical path field から navigable tree を構築します。 |
path facet は folder path を graph 内の browse 可能な 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 は失われます。単一 field を変更する場合は、getKnowledgeBase() で current configuration を読み取り、spread してください。
既存 Knowledge Base で Graph を有効にする
すでに content を持つ Atlas knowledge base で enabled を true にすると、Squid が graph を backfill します。Squid は knowledge base が quiet になるまで待機してから、まだ graph index 化されていないすべての 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 } });
Automatic build
concept layer(theme と facet)は corpus 全体から導出されるため、document ごとではなく batch で rebuild されます。content の ingestion・deletion、または graph の有効化後に、build は自動で schedule されます。
- build は最後の graph work が完了してから測定するquiet windowを待機します。進行中の ingestion は deadline を先送りし続けるため、長い bulk upload では document ごとではなく最後に 1 回だけ build が実行されます。
- window の default は 5 分で、knowledge base ごとに
graphRag.autoBuildDebounceMsで構成できます。 - sweep は毎分、due になった knowledge base を確認するため、window が経過してからおおむね 1 分以内に検出されます。
- build の保留中は、
getGraphStatus()がnextAutoBuildAtを報告します。activity が続く間は、この値も先に進みます。
entity extraction はこの schedule の一部ではありません。ingestion 自体によって trigger されるため、searchMode: 'graph' は concept layer の更新よりずっと前、extraction が完了すると新しく ingestion された document をカバーします。遅れるのは、queryGraph() が読み取る theme と facet structure です。
Build を強制する
quiet window を待ちたくない場合は、rebuildGraph() を呼び出します。default の '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、theme、facet。まだ graph index 化されていない context に対してのみ extraction を実行します。 | full rebuild のごく一部。 |
'full' | すべて。すべての chunk の LLM re-extraction を含みます。 | re-extraction が大部分を占めます。initial ingest と同程度です。 |
'full' rebuild が必要になることはまれで、destructive かつ低速です。既存 graph を最初に wipe してから、LLM ですべての chunk を再抽出するため、initial ingest と同程度の token と時間がかかります。job の完了まで、searchMode: 'graph' と queryGraph() は incomplete graph に対して実行されます。extraction はすでに ingest 時に実行されるため、新規または更新済み document に full rebuild は不要です。structural build がそれらを取り込みます。entityTypes または extractionModel を変更した後など、extraction 自体を再実行する必要がある場合にのみ、mode: 'full' を明示的に request してください。
knowledge base ごとに、一度に実行できる rebuild は 1 つだけです。getGraphStatus().buildJob を通じて追跡してください。
Graph Indexing Cap
graph extraction は、knowledge base ごとの chunk cap で停止します。cap は knowledge base ごとの option ではなく deployment-level limit であり、value は変更される可能性があります。そのため固定数を前提に設計せず、以下の signal で検出してください。cap を超えて ingestion された context は通常どおり保存され、vector、hybrid、keyword mode で完全に search 可能です。graph coverage のみが存在しないため、graph traversal はそこに到達できず、queryGraph() も表示しません。
skip は silent ではなく報告されます。
upsertContexts()は影響を受けた context をgraphIndexingSkippedContextIdsに list 化し、単一 context のupsertContext()はgraphIndexingSkipped: trueを設定します。getGraphStatus()はcontextsIndexed < contextsTotalとして継続する gap を表示します。
const result = await this.squid
.ai()
.knowledgeBase('filings-knowledgebase')
.upsertContexts([
{
contextId: 'annual-report-2026',
type: 'text',
title: 'Annual report',
text: 'Aldous Corporation reported record revenue in 2026.',
},
]);
// The listed contexts are stored and fully searchable; they are only absent from the graph.
const skippedIds = result.graphIndexingSkippedContextIds ?? [];
if (skippedIds.length > 0) {
console.warn(`${skippedIds.length} contexts were stored without graph coverage`);
}
Console および CLI の bulk upload、connector-driven sync など、upsert result を受け取らない ingestion path では、getGraphStatus() の gap が唯一の signal です。
すでに graph に含まれている document を update しても、graph から追い出されることはありません。更新後 content が context の既存 chunk 数以下になる reupsert は cap の対象外であるため、同じ size の replacement は graph coverage を維持します。context が増加する replacement は新しい content として count され、cap が適用されます。
cap を超える corpus 全体で完全な graph coverage を維持するには、corpus を複数 knowledge base に分割してください。
Graph を使用した Search
searchMode: 'graph' は graph-enabled knowledge base の default mode です。そのため、searchMode を省略すると graph が使用されます。他の mode も引き続き利用でき、Searching a Knowledge Baseで document 化されています。
traversal は graphOptions で調整します。
| Option | Default | Limit | 説明 |
|---|---|---|---|
seedLimit | 8 | 25 | expansion 前に vector search で seed する entity 数。 |
maxHops | 2 | 3 | 各 seed から traversal を expand する距離。 |
includeGraphContext | false | traversal した 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 を増やすと範囲が広がり、弱い association も取得されるため、本当に multi-hop の質問にのみ増やしてください。
Search を concept に scope する
graphFilter は search を graph の 1 concept 配下の document に限定します。user がすでに subject を絞り込んでいる場合に有用です。これはすべての search mode および contextMetadataFilter と compose できるため、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 scope は exact metadata membership で filter します。theme scope は thematic であるため recall-safe ですが fuzzy です。theme の current membership 外にある document は、relevant であっても除外されます。resolve できない concept は CONCEPT_NOT_FOUND と最も近い matching name で failure します。
Traversal を確認する
search() は chunk のみを返します。それらを生成した entity と relationship を確認するには、includeGraphContext とともに searchWithGraphContext() を使用します。retrieval の debugging や、passage が返された理由を user に示す場合に役立ちます。
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 は、includeGraphContext: true を指定した graph mode の search でのみ存在します。
Graph を直接 Query する
queryGraph() は passage を取得するのではなく、graph の structure を読み取ります。各 operation は complete answer を返す single round trip です。
| Op | Required input | Returns |
|---|---|---|
overview | knowledge base の render 済み map: theme、facet、count。 | |
resolve | ref | document、entity、theme、facet 全体から name に一致する node。 |
describe | ref | ancestor と immediate neighbor を含む 1 つの node。 |
subtree | ref | depth(default および cap は 3)までの document count を含む node subtree。 |
docsUnder | ref | node closure 下の document。totalDocs は full size を報告します。 |
conceptsOf | contextId | 1 つの document が属する facet と theme。 |
neighborhood | ref | entity 周辺の entity subgraph。hops(default 1、max 2)で expand されます。 |
pathBetween | ref と refB | 2 node を接続する relationship chain、または共有する concept。 |
globalSummary | query | 質問に対する relevance で rank 付けされた knowledge base の theme summary。 |
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 または facet nodeId を受け取ります。name は Squid が server-side で exact match、alias、similarity の順に resolve します。永続化する価値がある stable handle は facet nodeId と document contextId のみです。theme および entity ID は rebuild のたびに変わるため、毎回 name で resolve してください。
Graph を探索する
exploreGraph() は visualization 用に entity graph の bounded slice を返します。degree が最も高い entity と、それらの relationship が対象です。
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));
slice を 1 つの theme に限定するには、topicId を渡します。theme ID は 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()}`);
}
知っておくべき field:
| Field | 意味 |
|---|---|
enabled | この knowledge base で graph が有効かどうか。 |
contextsIndexed / contextsTotal | extraction coverage。value が等しい場合、すべての context が graph に含まれます。継続する gap は、graph indexing cap により context が skip されたことを示します。 |
entityCount / relationshipCount | entity graph の size。 |
topics / facets | build 実行後に設定される concept layer。 |
structureStale / staleDocCount | 最後の concept build 以降に graph index 化された document。次の build まで theme は content に遅れます。 |
buildJob | 最新 build: failure 時の status、startedAt、error。 |
lastStructureBuildAt | build が最後に正常完了した時刻。これまでに存在しない場合はありません。 |
nextAutoBuildAt | 保留中 automatic build の予定時刻。schedule されていない場合はありません。 |
ingestUsage / lastRebuildUsage | byModel で model ごとに分けられた LLM token と estimated cost。 |
graph の完全な準備完了を待つには、contextsIndexed === contextsTotal かつ buildJob が 'in_progress' でなくなるまで poll します。graph indexing cap に達した knowledge base では、contextsIndexed は永続的に contextsTotal を下回ります。status には差し引くべき skipped count が含まれないため、wait に上限を設定してください。buildJob が 'in_progress' でない状態で poll 間の contextsIndexed の進行が停止したら、graph は settled と扱います。
Console から Graph を使用する
Squid Console では code なしで同じ feature を利用できます。
- Vector Store を
mongoAtlasに設定してknowledge base を作成し、Knowledge Graph toggle を有効にします。store は作成後に変更できないため、Server default を含む他の store では toggle は disabled のままです。Server default で作成され Atlas に resolve された knowledge base は、編集により後で graph を有効にできます。 - knowledge base page には Knowledge Graph card が表示され、最後の build time、それ以降に変更された document 数、次の automatic build の推定時刻、structural build をすぐに実行する Build now button が表示されます。
Agent Behavior
接続された agent は graph を自動的に取得します。graph-enabled knowledge base では以下のようになります。
- knowledge base search tool は他の mode とともに
'graph'を提供し、これを default として扱います。そのため multi-hop question は特別な prompt なしで graph retrieval を使用します。 - tool description には graph の compact overview が含まれるため、agent は search 前に corpus の theme と count を把握できます。
- agent は上記 operationを基盤とする
queryKnowledgeGraphtool を取得するため、passage を取得するだけでなく corpus structure を navigate できます。 - agent は処理中に status update を broadcast します。
queryKnowledgeGraphの実行時はQuerying Knowledge Base Graphtitle が報告され、通常の knowledge base search のAccessing Knowledge Basetitle とは区別されます。そのため chat UI は graph navigation を独自の step として表示できます。
knowledge base を agent に接続する方法については、Agent abilitiesを参照してください。
Error Handling
| Error | 原因 | 修正 |
|---|---|---|
CONCEPT_NOT_FOUND | queryGraph() の ref が何にも match しません。message には最も近い name が list 化されます。 | 最初に op: 'resolve' で name を resolve するか、suggest された name のいずれかを使用します。 |
TOPIC_NOT_FOUND | exploreGraph() の topicId が不明です。通常は rebuild により ID が churn したためです。 | ID を永続化せず、rebuild のたびに getGraphStatus() から theme ID を再読み取りします。 |
JOB_ALREADY_EXISTS | この knowledge base ではすでに rebuild が実行中です。 | getGraphStatus().buildJob が 'in_progress' でなくなるまで待機します。 |
| Graph call は成功するが空を返す | knowledge base が mongoAtlas 上にない、または graphRag.enabled が false です。rebuildGraph() を除き、graph operation はそこで no-op です。 | getGraphStatus().enabled と knowledge base の vectorDbType を確認します。 |
buildJob.status === 'failed' | build が buildJob.error に記録された error に到達しました。 | underlying cause を修正し、rebuildGraph() を再実行します。次の automatic build でも retry されます。 |
contextsIndexed が contextsTotal 未満で停止する | knowledge base が graph indexing cap を超えています。upsertContexts() は skip された context を graphIndexingSkippedContextIds に list 化し、upsertContext() は graphIndexingSkipped を設定します。 | failure ではありません。context は graph 外では完全に search 可能です。完全な graph coverage のために corpus を複数 knowledge base に分割します。 |
graphRag を disable すると graph search は利用できなくなりますが、抽出された graph data は保持されます。そのため再度 enable する cost は低くなります。structural build は、まだ index 化されていないものを取り込み、すでに抽出済みの data を再利用します。graph data を実際に削除するには、graphRag.enabled が false の状態で rebuildGraph() を呼び出します。これは disabled knowledge base にも作用する唯一の graph call であり、disabled 時には graph を構築する代わりに wipe します。knowledge base を delete した場合も graph は削除されます。
ベストプラクティス
- knowledge base を作成する前に graph を使用するか決定し、
vectorDbTypeを明示的に渡します。これは immutable であるため、'postgres'knowledge base に graph を追加することはできません。 - domain に合う
entityTypesを渡します。organization、person、location などの proper noun では、generic product category より extraction の信頼性が大幅に高くなります。 - bulk ingestion 前に graph を有効にします。これにより、knowledge base が quiet になり automatic backfill build が完了するまで待つのではなく、ingestion に応じて graph を query 可能になります。後から有効にしても機能します。backfill は backlog に対して structural build を実行します。
maxHopsは default のままにします。本当に複数 hop を必要とする質問でのみ増やし、その場合は result が緩くなることを想定してください。- まず小規模 corpus で
ingestUsage.estCostUsdを確認し、全体で graph を有効にした場合の cost を見積もります。 - continuous ingestion 中の knowledge base では
autoBuildDebounceMsを広げ、build が moving target を追い続けないようにします。小規模 update 後に theme をすばやく refresh したい場合は短くします。 - rebuild をまたいで theme ID ではなく theme name を resolve します。stable なのは facet nodeId と document contextId だけです。