ナレッジベース
AI agent のための検索可能なコンテキストを保存し、メタデータスキーマ、自動抽出、クエリ時フィルタリングで管理します。
ナレッジベースを使用する理由
ナレッジベースは、AI agent が質問に回答するときに参照するコンテキストを保存するもので、Agent Studio の Knowledge Base ability と同じです。コンテキストを追加すると、基盤となる AI model に含まれていない可能性がある特定のトピックについて、agent が関連性の高い回答を提供できるようになります。
以下はシンプルなコード例ですが、追加できるコンテキストはさらに複雑にできます。コンテキストの良い例としては、コードドキュメント、製品マニュアル、ビジネス運用情報(例: 営業時間)、ユーザー固有データなどのリソースがあります。コンテキストの種類を組み合わせることで、AI agent のための堅牢なナレッジベースを作成し、ユーザーが必要とするあらゆる情報を提供できるようにできます。
ナレッジベースの作成
agent コンテキストを追加または更新するには、まずナレッジベースを作成して接続する必要があります。
最初に、すぐに利用できる embedding model を使用して新しいナレッジベースを作成します。
await squid.ai().knowledgeBase('banking-knowledgebase').upsertKnowledgeBase({
description: 'This Knowledge Base contains information on card data',
embeddingModel: 'text-embedding-3-small',
chatModel: 'gpt-5.5',
metadataFields: [],
});
または、connector ID、model 名、dimensions を含むオブジェクトを渡すことで、integration ベースの embedding model を使用できます。セットアップ手順については、OpenAI Compatible Embedding connector を参照してください。
await squid
.ai()
.knowledgeBase('banking-knowledgebase')
.upsertKnowledgeBase({
description: 'This Knowledge Base contains information on card data',
embeddingModel: {
integrationId: 'my-embeddings',
model: 'text-embedding-3-small',
dimensions: 1536,
},
chatModel: 'gpt-5.5',
metadataFields: [],
});
ナレッジベースは、次の 2 つのバックエンドのいずれかに vector を保存します。'mongoAtlas' は native hybrid fusion、ranked keyword search(Keyword search を参照)、および knowledge graph search をサポートします。'postgres' はこれらをサポートしません。vectorDbType を省略すると、アプリケーションが実行されているデプロイメントに応じたサーバーのデフォルトが使用されます。アプリケーションが特定のバックエンドに依存する場合は、明示的に渡してください。バックエンドは作成後に変更できません。また、getKnowledgeBase() で読み取ることができます。
await squid.ai().knowledgeBase('banking-knowledgebase-atlas').upsertKnowledgeBase({
description: 'This Knowledge Base contains information on card data',
embeddingModel: 'text-embedding-3-small',
chatModel: 'gpt-5.5',
metadataFields: [],
vectorDbType: 'mongoAtlas',
});
const kb = await squid.ai().knowledgeBase('banking-knowledgebase-atlas').getKnowledgeBase();
console.log(kb?.vectorDbType); // 'mongoAtlas'
getKnowledgeBase() は、保存されているナレッジベースレコード(vectorDbType を含む)に解決されます。その ID のナレッジベースが存在しない場合は undefined に解決されます。既存のナレッジベースに異なる vectorDbType を upsert すると、バックエンドを変更するのではなくエラーがスローされます。
バックエンドは作成時に固定されるため、knowledge graph search を有効化できるかどうかも決まります。'postgres' で作成されたナレッジベースに graph を追加することはできません。後で必要になる可能性がある場合は、サーバーのデフォルトに依存せず、vectorDbType: 'mongoAtlas' を渡してください。
コンテキストの Upsert
ナレッジベースにコンテキストを追加するには、upsertContext() method を使用し、コンテキストとその type を渡します。
upsertContext() method は context ID を受け取ります。context ID を指定すると、後で変更したいときにコンテキストへより簡単にアクセスできます。
const data = `Platinum Mastercard® Fair Credit, No annual fee. Flexible due dates...`;
await squid.ai().knowledgeBase('banking-knowledgebase').upsertContext({
type: 'text',
title: 'Credit Card Info',
text: data,
contextId: 'credit-cards',
});
または、upsertContexts() を使用して、コンテキストの配列を upsert します。
const creditCard1 = `Platinum Mastercard® Fair Credit, No annual fee. Flexible due dates...`;
const creditCard2 = `Gold Mastercard®, $50 annual fee. Due dates once a month...`;
await squid
.ai()
.knowledgeBase('banking-knowledgebase')
.upsertContexts([
{
type: 'text',
title: 'Credit Card 1 Info',
text: creditCard1,
contextId: 'credit-cards1',
},
{
type: 'text',
title: 'Credit Card 2 Info',
text: creditCard2,
contextId: 'credit-cards2',
},
]);
Agent への接続
ナレッジベースは、その agent に接続されて初めて agent の回答に影響します。ナレッジベースを接続し、agent がそれをどのように使用するかを設定する方法については、ナレッジベースを Agent に接続する を参照してください。
コンテキストの種類
サポートされるコンテキストの種類は text と file の 2 つです。
Text context は、コンテキストを含む文字列で作成します。
const data = `Platinum Mastercard® Fair Credit, No annual fee. Flexible due dates...`;
await squid.ai().knowledgeBase('banking-knowledgebase').upsertContext({
type: 'text',
title: 'Credit Card Info',
text: data,
contextId: 'credit-cards',
});
File context は、upsertContext() method の 2 番目のパラメーターとして File object を指定して作成します。その後、ファイルは Squid にアップロードされ、ファイル内容からコンテキストが作成されます。
const file = new File([contextBlob], 'CreditCardList.pdf', { type: 'application/pdf' });
await squid.ai().knowledgeBase('banking-knowledgebase').upsertContext(
{
type: 'file',
contextId: 'credit-cards',
},
file
);
コンテキストの長さに制限はありません。ただし、LLM prompt には文字数制限があるため、ユーザーの問い合わせと一緒に実際に含まれるのはコンテキストの一部だけの場合があります。prompt を構築するとき、Squid は提供されたコンテキストのどの部分がユーザーの質問に最も関連しているかを判断します。
Spreadsheet ファイル
file context としてアップロードされた spreadsheet ファイル(.csv、.tsv、.xlsx、.xlsm、.xls、.xlsb)は、専用の ingestion pipeline によって処理されます。生のセルテキストを chunking する代わりに、Squid は workbook の構造(sheet 名とサイズ、header row、hidden sheet、およびファイル形式で提供されている場合は chart と pivot table)を抽出し、workbook 全体の生成された summary を embedding します。そのため、spreadsheet context の検索結果は、セルデータの断片を返すのではなく、workbook に何が含まれているかを説明します。
summary は preview であるため、agent は正確な数値について summary に依存しません。接続されたナレッジベースに spreadsheet context が含まれている場合、agent は自動的に querySpreadsheetsWithAi tool を取得します。この tool は、sandbox 内で Python を実行して、実際にアップロードされたファイルに対する質問に回答します。
- 正確な値: count、sum、average、特定の行またはセルの lookup、filtering、sorting。
- 複数の workbook にまたがる質問。たとえば、ファイル間でデータを join または compare する質問を 1 回の呼び出しで処理できます。
- 構造と provenance に関する質問: sheet に実際に何が含まれているか、どの sheet が live calculation に入力されているか、どのセルが formula でどれが hardcoded input か。Formula と dependency の inspection は
.xlsx/.xlsmで最も完全に利用でき、.xlsでは部分的、.xlsb(cell value のみ)および CSV/TSV(formula metadata なし)では利用できません。
設定は不要ですが、専用 pipeline と agent tool は保持された元ファイルに依存します。context が discardOriginalFile: true(upsertContext() の file option。デフォルトは false。reprocessing と download のために保持する代わりに、テキスト抽出後に保存された元ファイルを破棄するよう Squid に指示します)でアップロードされた場合、その spreadsheet は plain extracted text として取り込まれ、querySpreadsheetsWithAi は提供されません。
コンテキストの取得
すべてのコンテキストの一覧を取得するには、listContexts() method を使用します。この method は、contextId を含む agent context object の配列を返します。
await squid.ai().knowledgeBase('banking-knowledgebase').listContexts();
特定の context item を取得するには、getContext() method を使用し、context ID を渡します。
await squid.ai().knowledgeBase('banking-knowledgebase').getContext('credit-cards');
コンテキストのページを一覧表示する
listContexts() はナレッジベース内のすべてのコンテキストを返しますが、ナレッジベースに数千件のエントリが含まれるようになると扱いにくくなります。代わりに listContextsPage() を使用してページングし、ID または title で検索できます。
- TypeScript
- Python
const page = await squid
.ai()
.knowledgeBase('banking-knowledgebase')
.listContextsPage({
offset: 0,
limit: 50,
// Truncates each entry's text so a listing stays small.
truncateTextAfter: 500,
// Case-insensitive substring match on context ID and title only, not on the text.
search: 'credit',
});
page = await squid.ai().knowledge_base('banking-knowledgebase').list_contexts_page(
offset=0,
limit=50,
search='credit',
)
すべての option は任意です。response には要求された contexts と、offset および limit を無視した totalCount が含まれるため、2 回目の呼び出しなしでページ数を表示できます。
search は context ID と title のみを照合するため、内容でエントリを見つけるには searching を使用してください。truncateTextAfter は TypeScript client でのみ利用できます。
コンテキストの削除
context entry を削除するには、deleteContext() method を使用します。
await squid.ai().knowledgeBase('banking-knowledgebase').deleteContext('credit-cards');
指定された context ID のエントリがまだ作成されていない場合、この method はエラーになります。
Context Metadata
AI ナレッジベースのコンテキストを追加または更新するときに、任意で context metadata を指定できます。Metadata は object であり、key の type には string、number、boolean を使用できます。metadata を追加すると、コンテキストに関する追加情報を提供でき、その後 agent とやり取りするときに利用できます。次の例では、PDF をコンテキストとして追加し、metadata として 2 つの key/value pair を指定しています。
const file = new File([contextBlob], 'CreditCardList.pdf', { type: 'application/pdf' });
await squid
.ai()
.knowledgeBase('banking-knowledgebase')
.upsertContext(
{
contextId: 'credit-cards',
type: 'file',
metadata: { company: 'Bank of America', year: 2023 },
},
file
);
その後、metadata でコンテキストをフィルタリングするセクション に示すように、AI agent と chat するときに metadata を使用できます。
メタデータスキーマの定義
ナレッジベースで metadata schema を宣言すると、metadata が構造化され、自己管理されるようになります。ナレッジベースを upsert するときに metadataFields で field definition を渡します。
- TypeScript
- Python
await squid
.ai()
.knowledgeBase('banking-knowledgebase')
.upsertKnowledgeBase({
description: 'This Knowledge Base contains information on card data',
embeddingModel: 'text-embedding-3-small',
chatModel: 'gpt-5.5',
metadataFields: [
{ name: 'author', dataType: 'string', required: true, description: 'The full name of the person who wrote the document.' },
{ name: 'publishedAt', dataType: 'date', required: false, description: 'The date the document was published.' },
{ name: 'category', dataType: 'string', required: false, description: 'The document category, for example report, memo, or guide.' },
],
});
await squid.ai().knowledge_base('banking-knowledgebase').upsert(
description='This Knowledge Base contains information on card data',
embedding_model='text-embedding-3-small',
chat_model='gpt-5.5',
metadata_fields=[
{'name': 'author', 'dataType': 'string', 'required': True, 'description': 'The full name of the person who wrote the document.'},
{'name': 'publishedAt', 'dataType': 'date', 'required': False, 'description': 'The date the document was published.'},
{'name': 'category', 'dataType': 'string', 'required': False, 'description': 'The document category, for example report, memo, or guide.'},
],
)
各 field definition には次の項目があります。
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | 文字、数字、underscore のみ。text や contextId などの reserved name は拒否されます。 |
dataType | 'string' | 'number' | 'boolean' | 'date' | Yes | validation と filtering に使用されます。date 値は epoch milliseconds に正規化されるため、range filter が機能します。 |
required | boolean | Yes | field とともに agent に提示される hint です。extraction や ingestion には影響しません。required value が見つからない場合でも context は ingest されます。 |
description | string | No | document から値を抽出し、agent が metadata filter を構築するときのガイドとして使用されます。 |
TypeScript type では 'array' data type も宣言されていますが、まだサポートされておらず、ナレッジベース schema の保存時に拒否されます。
schema を宣言すると、次の 3 つが有効になります。提供された metadata の validation(type が誤っている値はその context のみ拒否されます)、欠落値の自動抽出、そして agent-driven filtering です。
Metadata の自動抽出
宣言された field の値なしで context が upsert されると、field が required とマークされているかどうかにかかわらず、Squid が自動的に値を補完します。file upload では、まず document property が使用されます。よく知られた property 名に基づく field(title/docTitle、author/docAuthor、createdAt/docCreatedAt、modifiedAt/docModifiedAt、docType)は、PDF と Office document property、markdown front matter、HTML metadata から補完されます。残りのすべての field は、各 field の description に guided されて、document text に対する LLM pass によって処理されます。指定した値は常に優先され、上書きされることはありません。ただし例外が 1 つあります。空文字列は値なしとして扱われ、extraction の対象のままになります。抽出された field の名前は、保存された context の autoExtractedMetadataFields に記録されます。extraction は best-effort であり、見つからない値は upload を失敗させることなく absent のままになります。
ナレッジベースにすでに保存されている値に基づいて Squid に field description を作成させるには、generateMetadataFieldDescriptions() を呼び出します。これは生成された description を保存せずに返します。確認したうえで、upsertKnowledgeBase() を使用してナレッジベースに保存してください。
const { fields } = await squid.ai().knowledgeBase('banking-knowledgebase').generateMetadataFieldDescriptions({ overwriteExisting: false });
Metadata によるナレッジベースコンテキストのフィルタリング
コンテキストに metadata を追加している場合、contextMetadataFilterForKnowledgeBase chat option を使用して、AI agent に特定のコンテキストのみを参照するよう指示できます。filter requirement を満たすコンテキストだけが、client prompt への応答に使用されます。
次の例では、metadata value "company" が "Bank of America" と等しいコンテキストのみを含めるようにフィルタリングしています。
await squid
.ai()
.agent('banking-copilot')
.ask('Which Bank of America credit card is best for students?', {
contextMetadataFilterForKnowledgeBase: {
['banking-knowledgebase']: { company: { $eq: 'Bank of America' } },
},
});
次の metadata filter がサポートされています。
| Filter | Description | Supported types |
|---|---|---|
| $eq | metadata value が指定値と等しい vector に一致します | number, string, boolean |
| $ne | metadata value が指定値と等しくない vector に一致します | number, string, boolean |
| $gt | metadata value が指定値より大きい vector に一致します | number |
| $gte | metadata value が指定値以上の vector に一致します | number |
| $lt | metadata value が指定値より小さい vector に一致します | number |
| $lte | metadata value が指定値以下の vector に一致します | number |
| $in | metadata value が指定された array に含まれる vector に一致します | string, number |
| $nin | metadata value が指定された array に含まれない vector に一致します | string, number |
| $exists | 指定された metadata field を持つ vector に一致します | boolean |
$underPath で folder にスコープする
$underPath は、document の folderPath などの階層的な string field を subtree と照合します。値が operand と完全に一致する場合、または operand の後に / が続く形で始まる場合に一致します。
await squid
.ai()
.agent('banking-copilot')
.ask('What changed in the 2023 reports?', {
contextMetadataFilterForKnowledgeBase: {
['banking-knowledgebase']: { folderPath: { $underPath: 'reports/2023' } },
},
});
この filter は reports/2023 と reports/2023/q1/deck を許可しますが、sibling である reports/2023 drafts は許可しません。/ separator が segment boundary を提供するため、生の prefix match では起こり得る、単に prefix を共有する folder への subtree scoping の漏れを防ぎます。
知っておくべき詳細:
- operand の先頭と末尾の slash は無視されるため、
reports/2023/とreports/2023は同じ subtree を指します。 - 空の operand は、その field を持つすべての context に一致します。
- matching は case-sensitive であるため、
Reportsとreportsは別の folder です。 folderPathは reserved key ではなく通常の metadata key です。POSIX/separator を使用し、先頭または末尾の slash なしで書きます。upload root にある file には、absent value ではなく空文字列を使用してください。$underPathはナレッジベースにのみ適用されます。metrics tag filter や matchmaking では受け入れられず、unknown operator として拒否されます。
bare scalar value は $eq の shorthand であるため、{ company: 'Bank of America' } と { company: { $eq: 'Bank of America' } } は同等です。filter は $and および $or と組み合わせることもできます。
- TypeScript
- Python
await squid
.ai()
.agent('banking-copilot')
.ask('Summarize recent card reports', {
contextMetadataFilterForKnowledgeBase: {
['banking-knowledgebase']: {
$and: [{ category: 'report' }, { publishedAt: { $gt: Date.parse('2026-01-01') } }],
},
},
});
await squid.ai().agent('banking-copilot').ask(
'Summarize recent card reports',
options={
'contextMetadataFilterForKnowledgeBase': {
'banking-knowledgebase': {
# 1767225600000 is 2026-01-01 as epoch milliseconds
'$and': [{'category': 'report'}, {'publishedAt': {'$gt': 1767225600000}}],
},
},
},
)
dataType: 'date' で宣言された field は epoch milliseconds として保存されるため、range filter には数値(例: Date.parse('2026-01-01'))を渡してください。
Agent-driven metadata filtering
ナレッジベースが metadata schema を宣言 している場合、接続された agent は metadata filter を自分で構築できます。ナレッジベース search tool には filter parameter が追加され、model はユーザーの質問に基づいてそれを入力します。このとき、各 field の description と、tool description に表示される少数の sample value が guide になります。
contextMetadataFilterForKnowledgeBase で設定した filter は常に適用され、agent の filter と AND で結合されます。agent は許可された scope を狭めることはできますが、広げることはできないため、app-level filter は security boundary のままです。
接続されたナレッジベースで enableMetadataInspection: true を設定すると、さらに agent に inspection tool が提供されます。この tool は必要に応じて field の保存済み value を列挙および検索し、正確な filter の構築を支援します。value は最近更新された document から sample されるため、sample に値が存在しないことは、その値がまったく存在しないことを証明するものではありません。
Source Permissions の尊重
connector から index された content には、通常、それ自体の access rule があります。SharePoint document、Confluence page、Slack conversation は、組織内の一部の人には見え、他の人には見えない場合があります。ナレッジベースはそれらの rule を尊重できるため、agent は chat している人が閲覧を許可されている content のみを根拠に回答します。
同じ agent に同じ質問をした 2 人のユーザーは、それぞれが source system で開ける document のみから導かれた回答を受け取ります。ユーザーがアクセスできない content は取得されず、model に到達せず、citation に表示されることもありません。
これは、誰が質問しているかではなく topic や attribute によって結果を絞り込む metadata filtering とは別のものです。両者は組み合わせられ、permissions は常に適用されます。
ユーザーの認証は引き続きアプリケーションの責任です。Squid は、アプリケーションが確立した authenticated user identity の permissions を適用します。設定方法については Authentication を参照してください。
ナレッジベースの検索
search() method を使用してナレッジベースに直接 query し、一致する chunk を取得します。
- TypeScript
- Python
const chunks = await squid.ai().knowledgeBase('banking-knowledgebase').search({
prompt: 'Which credit cards have no annual fee?',
});
chunks = await squid.ai().knowledge_base('banking-knowledgebase').search(
'Which credit cards have no annual fee?',
)
Keyword search
Semantic (vector) search は、identifier、error code、SKU、file name などの exact token のように、precision が最も重要な場面で特に弱くなります。任意の searchMode option は、match の見つけ方を選択します。各 mode の挙動は、ナレッジベースの search backend、つまり ナレッジベース作成時に固定され、getKnowledgeBase() で読み取れる vectorDbType('mongoAtlas' または 'postgres')に依存します。
| Mode | Description |
|---|---|
'hybrid' | graph のないナレッジベースでの default です。'mongoAtlas' では semantic と keyword の candidate を native に fuse します。'postgres' では semantic search に fallback します。 |
'vector' | semantic similarity のみ。 |
'keyword' | embedding-free lexical search。'mongoAtlas' では ranked full-text (BM25) matching で、partial match でも best result を返します。'postgres' では unranked filter で、whitespace-separated term のすべてが chunk 内に literal かつ case-insensitive substring として存在する必要があります。 |
'graph' | entity graph 上の multi-hop retrieval で、hybrid search と fuse されます。graph が有効な 'mongoAtlas' ナレッジベースでのみ利用でき、そこでの default でもあります。Knowledge Graph Search を参照してください。 |
- TypeScript
- Python
const chunks = await squid.ai().knowledgeBase('banking-knowledgebase').search({
prompt: 'ERR_0000_4F2A',
searchMode: 'keyword',
});
chunks = await squid.ai().knowledge_base('banking-knowledgebase').search(
'ERR_0000_4F2A',
options={'searchMode': 'keyword'},
)
接続された agent は自分で search mode を選択します。ナレッジベース search tool は backend がサポートする mode を提供し、質問が exact token を対象としている場合、agent は keyword search に切り替えます。knowledge graph を持つナレッジベースでは、さらに 'graph' mode が提供され、searchMode が省略された場合の default になります。
grep による literal scan
上記のすべての search mode は chunk に対して機能します。chunk は ingestion によって text が分割および処理された後に生成されます。grep() は chunking 前の raw extracted text を scan し、一致する各行とその出どころの file を返します。意味ではなく文字が必要な場合や、price list 内の特定の SKU や spreadsheet row 内の値を見つける場合など、周囲の行が重要なときに使用してください。
const result = await squid
.ai()
.knowledgeBase('banking-knowledgebase')
.grep('ERR_0000_4F2A', {
// Scopes the scan to matching contexts before any text is read.
metadataFilter: { category: 'runbooks' },
maxMatches: 100,
});
for (const match of result.matches) {
// e.g. "CreditCardList.pdf, page 4, line 12: ..."
console.log(`${match.fileName}, ${match.part}, line ${match.lineNumber}: ${match.line}`);
}
どちらの option も任意です。
| Option | Type | Description |
|---|---|---|
metadataFilter | object | $and、$or、$underPath を含む metadata filtering と同じ grammar を使用し、metadata が一致する contexts に scan を限定します。text matching の前に適用されます。 |
maxMatches | number | 返す matches の最大数。デフォルトは 50 で、上限は 200 です。 |
各 match には、それが由来する contextId と fileName、part(extractor が提供する場合は sheet または section title、そうでない場合は page N)、1-based の lineNumber、一致した line、そして一致行と周辺行の小さな window である context が含まれます。
覚えておくべき 2 つの挙動:
- pattern は常に literal です。 Regular expression metacharacter は escape されるため、punctuation と symbol はそのまま一致します。pattern は複数行にまたがることがあります。
- matching は ASCII letter のみ case-insensitive です。
acmeはACMEを見つけますが、caféはCAFÉを見つけません。text が ASCII でない場合は、正確な casing で検索してください。
空の matches array は、response に limitation が含まれていない場合にのみ、その string が存在しないことを証明します。要求された scope を scan しきれなかった場合、limitation は以下のいずれかに設定されます。そのため、空の result から何かを結論づける前に確認してください。
| Limitation | Meaning |
|---|---|
timedOut | Scan が server-side deadline に達しました。大きな knowledge bases では通常起こり得ることであり、pattern が存在するかどうかについては何も示しません。 |
noIndexedText | Scope 内に stored text がありません。literal search が存在する前に ingest された contexts は、再 ingest されるまでここに残ります。 |
filterMatchedNoContexts | metadataFilter が contexts を 1 つも許可しなかったため、何も読み取られませんでした。 |
scopeTruncated | metadataFilter が 1 回の scan で対象にできる数を超える contexts を許可したため、一部のみが検索されました。filter を絞り込んでください。 |
partsCapReached | Scan が matching pages または sheets の per-call budget に達したため、さらに一致する場所が存在します。 |
partialCoverage | Scope 内の一部 contexts に stored text がありません。unscannedContextCount がその数を報告します。 |
truncatedContent | Scope 内の一部 text が ingest 時に切り詰められ、検索可能になっていません。truncatedContentFileNames は影響を受けた files の sample を示します。 |
coverageUnknown | Scan は成功しましたが、scope のうちどれだけが stored text を保持しているかを判定できませんでした。 |
別個の truncated flag は、返された list が maxMatches で停止し、さらに matches が存在することのみを意味します。
ナレッジベースに接続された agents は、この scan を grepKnowledgeBase tool として取得し、実行中は status updates を broadcast します。grepKnowledgeBase は title Searching Knowledge Base Text を報告し、これは ranked retrieval の title Accessing Knowledge Base とは区別されます。
grep() は TypeScript client で利用できます。Python または REST の equivalent はありません。
Bulk Ingestion
upsertContexts() は inline で ingest し、context が searchable になると解決されます。これは数十件の document に適しています。数千件の場合は bulk ingestion を使用してください。これは AI provider の batch API を通じて context を処理する、durable で asynchronous な lane です。
重要な違いは return contract です。bulkUpsertContexts() は request が staged されるとすぐに解決され、ingestion の完了時には解決されません。そのため、返された job を別途追跡します。
CLI で directory を ingest する
最も手早い方法は CLI です。directory を巡回し、file を batch 化し、upload し、各 job が完了するまで polling します。
squid kb-upload --dir ./docs --knowledgeBase banking-knowledgebase
| Option | Description |
|---|---|
--dir | 必須。再帰的に巡回する local directory。 |
--knowledgeBase | 必須。ingest 先のナレッジベース。 |
--extensions | comma-separated allow-list。default は pdf, docx, txt, md, html, csv, xlsx, xls, xlsm, xlsb, pptx。 |
--batchSize | job ごとに staged される file 数。default は 200、maximum は 1000。 |
--dryRun | upload される予定の file を一覧表示し、server に接続せずに終了します。 |
--timeoutMinutes | 各 job を待機する時間。超過すると server-side でまだ実行中として報告し、次へ進みます。default は 120。 |
--appId、--apiKey、--region、--environmentId は、SQUID_APP_ID、SQUID_API_KEY、SQUID_REGION、SQUID_ENVIRONMENT_ID に fallback します。Ctrl-C を押すと、進行中の job がキャンセルされます。
コードから context を stage する
Bulk ingestion には API key が必要なため、backend code から実行してください。
const { jobId, contextIds, duplicates } = await this.squid
.ai()
.knowledgeBase('banking-knowledgebase')
.bulkUpsertContexts(contexts, files);
contextIds は、渡した context と index-aligned です。content duplicate として拒否された context も slot を占有するため、実際に staged されたものを確認するには context ID で duplicates と cross-reference してください。duplicate とは、ナレッジベースがすでに保持している content、または同じ呼び出し内の earlier context が導入した content です。
job の追跡
const kb = squid.ai().knowledgeBase('banking-knowledgebase');
// Poll for the job's current state.
const status = await kb.getBulkIngestionJob(jobId);
console.log(status.state, status.counts);
// Or subscribe to server-side updates.
kb.observeBulkIngestionJob(jobId).subscribe((update) => {
console.log(update.state, update.counts);
});
// Already-finalized contexts are kept when a job is cancelled.
await kb.cancelBulkIngestionJob(jobId);
observeBulkIngestionJob() は、job が completed、failed、または cancelled に達すると完了します。terminal な failed または cancelled state は error ではなく通常の emitted value として届くため、next callback で処理してください。observable は transport failure の場合にのみ error になります。
計画時に考慮すべき 2 つの詳細:
- observable は cold であるため、各 subscription は独自の server-side subscription を登録します。複数の consumer が 1 つの job を監視する場合は、たとえば RxJS
share()を使用して共有してください。 - job が in flight の間に application または knowledge base が削除されると、job record は final update なしで purged され、observable は完了しません。その可能性がある場合は、RxJS
timeout()で bound してください。
大規模な file set の upload
file を直接 bulkUpsertContexts() に渡すと Squid 経由で送信され、Squid は request を memory に buffer するため、1 回の呼び出しは 合計 50 files および 256 MB に制限されます。それを超える場合は、presigned URL を発行し、storage に直接 upload してください。この方法にはどちらの制限もありません。
const kb = this.squid.ai().knowledgeBase('banking-knowledgebase');
// At most 500 file names per call.
const { uploads } = await kb.createBulkUploadUrls(['statement-2026-01.pdf', 'statement-2026-02.pdf']);
for (const upload of uploads) {
await fetch(upload.uploadUrl, {
method: 'PUT',
body: fileBytesFor(upload.fileName),
// Required headers are empty on S3, but Azure Blob rejects the PUT without them.
headers: upload.requiredHeaders,
});
}
// Reference the staged objects instead of sending bytes through Squid.
const staged = uploads.map(upload => ({
type: 'file' as const,
contextId: upload.fileName,
stagedObjectKey: upload.stagedObjectKey,
}));
await kb.bulkUpsertContexts(staged);
Presigned URL は発行後まもなく期限切れになるため、すべてを事前に発行するのではなく、各 wave を速やかに upload してください。
Best Practices
- 大きな document は topic ごとに focused knowledge base に分割してください。これにより、agent が適切なコンテキストを選択するための signal が向上します。
- context に metadata を追加して query time の filtering を有効にし、response の noise を減らしてください。