Kennis via de API¶
Het concept achter kennis staat in Kennis.
Op deze pagina maak je met de API documenten van je organisatie doorzoekbaar, van collectie tot zoektool: je slaat bronnen op in een collectie, maakt een index over die collectie en doorzoekt de index direct of biedt haar aan een model aan als tool. De stappen staan in de volgorde waarin je ze uitvoert.
Je sleutel heeft de capability knowledge nodig voor deze endpoints. Een bestand uploaden vraagt
in sommige collecties ook files (stap 1). Grafen
hebben een eigen pagina: Grafen via de API.
De console gebruiken¶
Je kunt collecties, indexen, zoektools en pipelines ook beheren in het onderdeel Kennis van de console. De API en de console gebruiken dezelfde resources. Een beheerder kan bijvoorbeeld documenten bijhouden in de console terwijl je applicatie ze via de API doorzoekt.
Collecties, indexen, pipelines en tools¶
| Wat het is | |
|---|---|
| Collectie | waar bronnen staan. Een bron hoort bij precies één collectie en verhuist niet. |
| Bron | één document, tabel of geüpload bestand. |
| Index | kiest een of meer collecties en bepaalt hoe hun bronnen worden gesplitst en ingebed. Dit is wat je doorzoekt. |
| Zoektool | een benoemde zoekopdracht die het model kan aanroepen. Ze draait één versie van een zoekpipeline en bereikt de indexen, collecties en grafen die die versie noemt. |
Het beleid van je sleutel kan beperken welke collecties en indexen die sleutel bereikt, op naam.
Wat het beleid niet noemt, bestaat niet voor die sleutel: lijsten laten het weg, een aanvraag met
het id antwoordt 404, en dat geldt ook voor alles wat eraan hangt -- de bronnen van een
collectie, de statistieken, runs, zoekopdrachten en geheugenrecords van een index. Een collectie of
index aanmaken of hernoemen naar een naam die het beleid niet noemt, geeft 403; er wordt dan
niets opgeslagen. Een zoektool is daarop geen uitzondering: het beleid moet de tool toestaan én
elke index, collectie en graaf die haar pipeline noemt
(Welke regels gelden). Zie sleutels.
1. Een collectie en bron maken¶
curl -s -X POST "$CORE_URL/knowledge/collections" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"name": "handboek", "description": "Intern handboek"}'
curl -s -X POST "$CORE_URL/knowledge/collections/col_2Pf7.../sources" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"kind": "text", "title": "Declaratiebeleid",
"text": "Declaraties dien je binnen 30 dagen in...",
"metadata": {"afdeling": "finance"}}'
Een bestand gaat er in één aanroep in. Post het bestand zelf naar .../sources/upload in
plaats van het eerst te uploaden en daarna het id te noemen:
curl -s -X POST "$CORE_URL/knowledge/collections/col_2Pf7.../sources/upload" \
-H "Authorization: Bearer $CORE_KEY" \
-F "file=@handboek.pdf" \
-F 'metadata={"afdeling": "finance"}'
title (standaard de bestandsnaam), retention en metadata -- een JSON-object met
stringwaarden, als string, omdat een multipartformulier zelf geen typen kent -- zijn optionele
velden ernaast. De bytes worden één keer opgeslagen, waar uploaden naar /files en daarna een
file-bron maken van het id ze twee keer opslaat en een upload achterlaat.
Wat de upload wordt, volgt de collectie. In de eigen collectie van een sleutel en in de
collectie uploads van je organisatie is het een bestand: je sleutel heeft de
capability files nodig, anders geeft de upload 403, en de naam moet er een zijn die het
bestandsbeleid van je sleutel noemt
(Wat een bestands-id bereikt). In elke andere collectie is
het een kennisdocument, zonder controle op de naam. Een title of bestandsnaam met
een stuurteken geeft 422.
Een groot bestand gaat in delen. Een bestand dat groter is dan één upload mag zijn, of dat een
weggevallen verbinding moet overleven, gaat naar binnen via een uploadsessie die eindigt als bron.
Je sleutel heeft de capability knowledge nodig, en de bestanden van je organisatie moeten in een
object store staan:
curl -s -X POST "$CORE_URL/uploads" \
-H "Authorization: Bearer $CORE_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "handbook.pdf", "media_type": "application/pdf", "size_bytes": 157286400,
"target": {"kind": "source", "collection_id": "col_2Pf7...",
"title": "Handbook", "metadata": {"department": "finance"}}}'
De sessie wordt geweigerd om wat de upload in één aanroep weigert, voordat er een deel is
verstuurd: een mediatype dat geen pijplijn leest (422), een collectie die je sleutel niet bereikt
(404), een gekoppelde kopie (409). Stuur de delen, rond de sessie af en vraag haar op zoals
Een groot bestand in delen uploaden laat zien; is ze
completed, dan draagt ze de source_id. Een bron boven de gewone uploadlimiet wordt opgeslagen
en is te downloaden; een index leest haar toch in delen als ze tekst, een PDF, Word, PowerPoint of
Excel is tot 100 MiB (Een groot bestand wordt in delen geïndexeerd),
en elk ander bestand van die grootte komt in geen enkele index.
De bronroutes van een collectie tonen een sleutel alleen de bronnen waarvoor ze de capability
heeft: zonder artifacts staat er geen artefact tussen de bronnen van een collectie, en zonder
files geen upload.
Kies een van deze brontypen voor de JSON-body:
kind |
Verzoek | Goed voor |
|---|---|---|
text |
title, text (het hele verzoek hoogstens 1 MiB; voor meer tekst upload je een bestand) |
proza dat je al als string hebt |
file |
file_id van een bestand of artefact dat je al hebt |
kopiëren van bytes die deze organisatie al heeft naar deze collectie; tekst, markdown, HTML, PDF, Word, PowerPoint, Excel, CSV, JSON en een afbeelding (PNG, JPEG, GIF, BMP, WebP), iets anders is 422 |
records |
title, records (tot 50.000 platte JSON-objecten) |
een tabel die je per veld wilt bevragen |
Een file-bron kopieert de bytes naar een eigen blob, dus het verwijderen van het origineel of van
de kopie laat de ander ongemoeid. Een artefact kopiëren is het downloaden ervan: dat antwoordt
403 als geen regel je sleutel toestaat artefacten te downloaden. En een collectienaam mag niet met key_
beginnen: dat is de naam van de collectie die Core per API-sleutel bijhoudt.
Word-bestanden, presentaties, webpagina's en PDF's worden gelezen door de pipeline die de index
draait. De standaardpipeline leest ze alle vier, dus je kiest pas zelf een pipeline als je iets
anders wilt dan de standaard. Een ouder Word-bestand (.doc, niet .docx) is de uitzondering:
alleen een pipeline met de stap llama_parse leest het, zoals de sjablonen ingest/llama-parse
en ingest/rag-with-tables, en elke andere pipeline laat het mislukken met needs_parse. Een
spreadsheet komt juist als tabellen binnen: elk werkblad wordt rijen die je per veld kunt
bevragen, net als een CSV.
Voeg metadata toe om bronnen te filteren bij indexeren en zoeken.
De bronnenlijst filteren. GET .../sources neemt folder, q (titel bevat,
hoofdletterongevoelig) en het herhaalbare status (ingestiestatus van een van de indexen die de
bron heeft opgenomen). folder matcht hele padsegmenten van de folder-metadata, dus beleid
geeft beleid en beleid/2026 en nooit beleid-oud; met recursive=false krijg je alleen de
eigen bronnen van de map. Een lege folder is de hoofdmap: met recursive=false geeft die de
bronnen zonder map. Bijvoorbeeld:
curl -s "$CORE_URL/knowledge/collections/col_2Pf7.../sources?folder=beleid&status=ready&status=failed" \
-H "Authorization: Bearer $CORE_KEY"
Een bron downloaden. GET .../sources/{source_id}/content geeft de bytes die Core voor een
bron bewaart, als bijlage met de titel van de bron als naam: het bestand dat is geüpload, de tekst
van een text-bron, of de records van een records-bron als JSON-array.
curl -s "$CORE_URL/knowledge/collections/col_2Pf7.../sources/src_9Qd2.../content" \
-H "Authorization: Bearer $CORE_KEY" -o handboek.pdf
Een document later wijzigen¶
De titel, de metadata en de bewaarkeuze van een bron wijzig je later met een PATCH. metadata vervangt de hele
map, net als bij een collectie, dus stuur elke sleutel mee die je wilt houden — ook folder en de
sleutels die een connector schreef:
curl -s -X PATCH "$CORE_URL/knowledge/collections/col_2Pf7.../sources/src_9Qd2..." \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"title": "Declaratiebeleid 2026",
"metadata": {"afdeling": "finance", "folder": "beleid/2026"}}'
Core bewaart het folder-pad genormaliseerd (/beleid//2026/ wordt beleid/2026), en een .- of
..-segment is een 422.
Een nieuwe map is geen veldwijziging maar een routeringsmoment: elke index die deze collectie kiest, wordt opnieuw langs haar eigen filter gelegd. Past de bron nu wel, dan wordt zij daar alsnog verwerkt; past zij niet meer, dan verdwijnt zij daar. Blijft zij passen, dan worden alleen de labels op haar fragmenten bijgewerkt en hoeft er niets opnieuw verwerkt te worden. De soort, de vorm, de bytes en de collectie van een bron liggen vast en staan niet op deze body.
retention zegt of het bewaarvenster van je organisatie dit document omvat: window laat het
verwijderen zodra het ouder is dan het venster dat je beheerder instelde, keep houdt het tot iets
het verwijdert. Een collectie die je zelf maakt staat standaard op keep en bepaalt met
retention_default wat de documenten erin krijgen; de eigen collectie van je sleutel -- waar je
uploads via /files en de bestanden van je tools terechtkomen -- staat op window. Eén document
mag altijd afwijken van zijn collectie:
curl -s -X PATCH "$CORE_URL/knowledge/collections/col_2Pf7.../sources/src_9Qd2..." \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"retention": "keep"}'
DELETE .../sources/{source_id} legt een document in de prullenbak: het is meteen weg uit elke
zoekopdracht en lezing, en zijn bytes blijven 30 dagen bewaard, tenzij je operator een ander aantal
instelde. De eigen lijst van de collectie toont haar prullenbak, en terugzetten zet een document
terug en leest het opnieuw in:
curl -s "$CORE_URL/knowledge/collections/col_2Pf7.../sources?trashed=true" \
-H "Authorization: Bearer $CORE_KEY"
curl -s -X POST "$CORE_URL/knowledge/collections/col_2Pf7.../sources/src_9Qd2.../restore" \
-H "Authorization: Bearer $CORE_KEY"
Een document in de prullenbak draagt deleted_at en purge_at. Een tweede DELETE verwijdert het
definitief. Een gesynchroniseerd document dat je verwijdert, blijft in de prullenbak, ook als zijn
bron het wijzigt: de nieuwe versie vervangt het daar onder een nieuw id, dus zoek het op in de lijst
van de prullenbak voor je het terugzet. Een sleutel die ook files heeft, bereikt dezelfde prullenbak via /files
(Een bestand verwijderen, terugzetten of definitief weggooien).
Een collectie synchroniseren met een systeem dat je hebt¶
In plaats van elke bron zelf aan te maken, geef je een collectie een connector en haalt Core de documenten op. Elk document wordt een gewone bron van die collectie, dus alles hierboven — indexen, zoeken, tools — werkt precies zoals bij een bron die je zelf hebt gepost.
Een collectie draagt één connector, en de soort ligt na schrijven vast: website (gecrawld via
Firecrawl), sharepoint, gdrive, s3 en zendesk.
Firecrawl draait in de Verenigde Staten. Beperkt je sleutel waar aanroepen mogen draaien
(policy.settings.regions_allow) tot plaatsen zonder us, dan mislukken de synchronisatie en de
test van een website-connector met region_denied en wordt er niets verstuurd; noem
vendor:firecrawl in policy.settings.region_exceptions om het toe te staan (beperkt je organisatie
ook de regio's zonder us toe te laten, dan moet haar beleid hem ook noemen). Hetzelfde geldt voor
de stap llama_parse, waarvan de dienst in de EU draait tenzij je operator een andere regio
instelde: een sleutel die elders is vastgelegd, laat de bron mislukken met region_denied, tenzij
hij vendor:llamacloud noemt. Een connector of bron die iemand in de console heeft ingesteld, en
een zoekopdracht daar, volgen op dezelfde manier de regio's en uitzonderingen van je organisatie
(Aanroepen binnen je regio's houden).
curl -s -X PUT "$CORE_URL/knowledge/collections/col_2Pf7.../connector" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"config": {"kind": "sharepoint",
"site_url": "https://contoso.sharepoint.com/sites/Docs",
"tenant_id": "8f1c...", "client_id": "b3d2...",
"client_secret": "<het applicatiegeheim>",
"exclude_path_regex": "^/Archief/"},
"schedule_minutes": 1440}'
PUT schrijft de hele connector, dus een geheim dat je weglaat is een geheim dat je wist. PATCH
wijzigt een deel: stuur de instellingen die je wilt en laat het geheim weg om het opgeslagen geheim
te behouden, of stuur het mee om het te vervangen. Het leesmodel heeft helemaal geen veld voor een
credential — has_credentials zegt alleen of er een is opgeslagen — en kind kun je niet met een
PATCH wijzigen; vervang de connector met een PUT.
include_path_regex en exclude_path_regex filteren wat wordt meegenomen, en moeten expressies
zijn die RE2 accepteert: een backreference of een lookaround geeft 422 met het veld erbij.
Afbeeldingen, video, archieven en andere binaire bestanden worden bovenop jouw regel altijd
overgeslagen. schedule_minutes is het aantal minuten tussen geplande synchronisaties, of null
voor alleen handmatig.
In plaats van schedule_minutes kan een connector ook schedule_cron dragen: een expressie van
vijf velden -- minuut, uur, dag-van-de-maand, maand, dag-van-de-week -- gelezen in
schedule_timezone (een IANA-zone, standaard UTC). De twee sluiten elkaar uit: beide zetten
geeft 422 met beide velden erbij.
curl -s -X PATCH "$CORE_URL/knowledge/collections/col_2Pf7.../connector" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"schedule_minutes": null,
"schedule_cron": "0 6 * * 1-5", "schedule_timezone": "Europe/Amsterdam"}'
curl -s -X POST "$CORE_URL/knowledge/collections/col_2Pf7.../connector/test" \
-H "Authorization: Bearer $CORE_KEY"
curl -s -X POST "$CORE_URL/knowledge/collections/col_2Pf7.../connector/sync" \
-H "Authorization: Bearer $CORE_KEY"
curl -s "$CORE_URL/knowledge/collections/col_2Pf7.../connector/runs" \
-H "Authorization: Bearer $CORE_KEY"
test benadert het systeem en haalt hoogstens één item op, op het requestpad, en slaat niets op.
sync antwoordt 202 met een run in de wachtrij, of 409 als er al een loopt; POST
.../connector/sync/cancel stopt de lopende run tussen twee items. Elke run draagt discovered,
added, updated, removed, skipped en failed, bijgewerkt tijdens de run, en een vaste
error_code als zij mislukte — een van auth_failed, not_found, rate_limited, egress_denied,
too_many_items, provider_error, cancelled, deadline_exceeded, region_denied of
tenant_unavailable (de organisatie, of een organisatie erboven, is opgeschort). Het eigen foutbericht van
de leverancier wordt nooit teruggegeven. Een document dat een index toch niet kan inlezen wordt
niet opgeslagen: een document groter dan wat de index leest (standaard 100 MiB voor tekst en JSON,
en 25 MiB voor elk ander type, HTML-pagina's en afbeeldingen inbegrepen), of dan de eigen synchronisatiegrens van de installatie (standaard
50 MiB), telt mee in skipped, nooit in failed.
De connector verwijderen (DELETE .../connector) laat de bronnen die zij heeft aangemaakt in de
collectie staan. Een connector die je daarna op die collectie instelt neemt ze over: wat zij ook
aanbiedt werkt zij bij, wat zij niet aanbiedt verwijdert zij. Bronnen die je zelf hebt aangemaakt
dragen geen connector-uri, dus een synchronisatie verwijdert ze nooit.
De console koppelt en ontkoppelt niet los van de collectie: daar kies je de bron wanneer je de collectie aanmaakt, en die keuze ligt vast — zie Collecties .
2. Een index maken¶
curl -s -X POST "$CORE_URL/knowledge/indexes" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"name": "handboek", "collection_ids": [{"collection_id": "col_2Pf7..."}]}'
Een index kan meerdere collecties bevatten. Een collectie kan ook meerdere indexen voeden, elk met
andere splitsinstellingen. Voeg "metadata_filter": {"afdeling": "finance"} toe aan een
collectiekoppeling om alleen overeenkomende bronnen te selecteren.
Bronverwerking gaat door nadat het verzoek is beantwoord. Controleer GET
/knowledge/indexes/{id}/sources voor queued, processing, ready of failed. Bij fouten staat
er een vaste error_code. Bestaande bronnen worden niet automatisch verwerkt zodra je hun collectie
koppelt. Start POST /knowledge/indexes/{id}/reindex om ze op te nemen en volg de voortgang met
GET /knowledge/indexes/{id}/runs.
Een pdf die de parseerdienst weigert, wordt uit zijn tekstlaag gelezen. Stuurt de stap
llama_parse een pdf naar de parseerdienst en weigert de dienst die om een reden die een nieuwe
poging niet oplost, dan leest Core de eigen tekstlaag van de pdf. De bron is dan ready en
doorzoekbaar, en haar rij in GET /knowledge/indexes/{id}/sources draagt parse_fallback met de
reden: credits_exhausted, api_key_rejected, api_key_missing of file_rejected; het veld is
null als de dienst het document heeft gelezen. Werkt de dienst weer, start dan een volledige
herindexering van de index om deze documenten alsnog door de dienst te laten lezen; een pdf met
file_rejected wordt opnieuw geweigerd. Een document dat de dienst voor deze index al heeft
gelezen, wordt nooit door zijn tekstlaag vervangen: een herindexering tijdens een storing mislukt
voor dat document, en de fragmenten die de dienst maakte blijven doorzoekbaar. Een time-out, een
rate limit of een serverfout leidt nooit tot de tekstlaag, en een pdf zonder leesbare tekstlaag
evenmin: de bron mislukt dan met haar error_code.
Een groot bestand wordt in delen geïndexeerd. Een tekstbestand -- platte tekst, Markdown, CSV of
JSON -- een PDF, en een Word-, PowerPoint- of Excel-bestand, groter dan 4 MiB en tot 100 MiB, wordt
deel voor deel gelezen en ingebed: een PDF per reeks pagina's, een Word-bestand per reeks alinea's,
een presentatie per reeks dia's, een werkmap per reeks rijen, en een tabel die over twee delen valt
houdt aan beide kanten haar kopregel. De fragmenten worden samen doorzoekbaar zodra het laatste
deel binnen is; tot dan antwoordt een zoekopdracht met wat de index daarvoor had. Terwijl zo'n bestand opnieuw
wordt geïndexeerd, kan een zoekopdracht een paar minuten lang zowel de oude als de nieuwe
fragmenten vinden, dus in die tijd kunnen resultaten dubbel voorkomen. Een groter bestand, en een
bestand van een ander type boven 25 MiB, wordt opgeslagen en is te downloaden, maar geen index
neemt het op: het heeft in geen enkele index een status en geen error_code. Alleen een index die
zijn collectie later via een herindexering opneemt, toont het, als failed met too_large. Een
tekst-, PDF-, Word-, PowerPoint- of Excel-bestand boven 25 MiB in een index waarvan de pipeline meer
doet dan laden, parsen, splitsen, inbedden en opslaan -- een samenvatting, verrijking, tabellen,
afbeeldingen, een graaf of geheugen -- mislukt met too_large_for_pipeline; net als een Word-,
PowerPoint- of Excel-bestand boven 25 MiB in een pipeline zonder parse-stap, die zo'n bestand tot
25 MiB laat mislukken met needs_parse. De standaardpipeline leest ze allemaal. Een Word-,
PowerPoint- of Excel-bestand waarvan de inhoud uitgepakt veel groter is dan het bestand zelf,
mislukt met too_large, en een dat niet te lezen is met parse_error. Een kennisgraaf leest een
bron in zijn geheel, dus neemt er een tot 25 MiB en laat een grotere mislukken met too_large. Dit
zijn de standaardlimieten van de installatie; de beheerder kan de 100 MiB verhogen.
Elk antwoord met een index bevat reindex_required: true vanaf het moment dat je het model, de
pipeline of de gekoppelde collecties wijzigt, totdat een volledige herindexering is afgerond. Een
collectie weghalen of een metadata_filter vernauwen werkt meteen door in zoekopdrachten; de
herindexering verwijdert wat achterblijft. Een herindexering wordt in rekening gebracht zoals elk
ander gebruik van de modellen. Een run die liep toen je de index wijzigde, eindigt met status
cancelled en error_code superseded; zolang Core hem nog niet heeft beëindigd, antwoordt een
nieuwe herindexering met 409.
3. De index doorzoeken¶
curl -s -X POST "$CORE_URL/knowledge/indexes/idx_8Bd3.../search" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"query": "hoe lang heb ik om te declareren", "top_k": 5,
"metadata": {"afdeling": "finance"}}'
Zoeken combineert ranglijsten op trefwoorden en betekenis. Daarmee kun je zowel exacte termen als
verwante formuleringen vinden. Het filter metadata beperkt de resultaten tot bronnen met
overeenkomende waarden.
Core embedt je vraag voor de ranglijst op betekenis, en die embedding-tokens worden gemeten op je
sleutel (Verbruik). Heeft je sleutel of je organisatie de
maandlimiet bereikt, dan antwoordt de zoekopdracht
met 429 en Retry-After, tenzij het embeddingmodel niets kost.
Een werkblad of een bestand met records wordt één tabel per werkblad, body of tabel in het
document, elk met een eigen afgeleid schema. GET /knowledge/collections/{id}/sources/{sid}/tables
somt ze op; POST /knowledge/collections/{id}/sources/{sid}/query filtert er één op velden, met
table_id erbij — bij een bron met precies één tabel mag die weg. Een onbekend veld geeft 422
met de veldnaam.
Een sleutel waarvan het beleid een agent vereist (settings.agents_required)
kan deze routes niet gebruiken, en ook POST /knowledge/retrieval-tools/{id}/query en
POST /knowledge/pipelines/{id}/test niet: elk antwoordt 403 voordat er iets wordt opgezocht,
omdat het je kennis leest buiten een beurt en dus buiten elke agent. Zijn agents zoeken nog wel,
binnen hun beurten.
Een beleid waarvan de regels beperken welke modellen een sleutel mag aanroepen, moet ook het
embedding-model toestaan: zonder die toestemming antwoorden deze routes 403 met The embedding
model is not allowed for this key., en draait een beurt zonder in je kennis te zoeken.
Afbeeldingen gevonden met woorden¶
Een index kan afbeeldingen doorzoekbaar maken: een PNG of JPEG die je uploadt, en de afbeeldingen
in een PDF of een Word-bestand. Kies de pipeline ingest/with-images als je de index maakt:
curl -s -X POST "$CORE_URL/knowledge/indexes" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"name": "rapporten", "collection_ids": [{"collection_id": "col_2Pf7..."}],
"ingest_pipeline": {"template": "ingest/with-images"}}'
De tekst wordt geïndexeerd zoals met de standaardpipeline, en elke afbeelding -- hooguit 50 per
document, geen groter dan 20 MB -- wordt als afbeelding ge-embed. Een tekstvraag vindt hem dan:
"een staafdiagram van de omzet" kan het diagram zelf opleveren. De index heeft een
embeddingmodel nodig dat afbeeldingen leest; heeft de installatie er geen, dan geeft een pipeline
maken van dit sjabloon 422, en faalt een document in een index waarvan het model geen
afbeeldingen leest met image_embedding_unavailable.
Een index maken of wijzigen zodat hij deze pipeline draait op een embeddingmodel dat geen
afbeeldingen leest, geeft 422. Een afbeelding die je in een collectie uploadt, wordt opgeslagen
welke pipeline de indexen ook draaien; een index op een tekstpipeline zet hem op failed met
unsupported_media_type. Een gescande PDF zonder tekst wordt opgeslagen om zijn afbeeldingen.
Afbeeldingen in bestanden die een connector synchroniseert worden overgeslagen, zoals op het
platform; afbeeldingen in de PDF's en Word-bestanden die hij binnenhaalt worden gelezen.
Een paar grenzen voorkomen dat één document te veel werk vraagt: hooguit 200 afbeeldingen per document worden bekeken, een afbeelding groter dan 5000 bij 5000 pixels wordt overgeslagen, en de inhoud van de afbeelding zelf bepaalt het type, hoe het bestand ook heette.
Een afbeelding komt terug als treffer met een lege text en een veld image, nooit de bytes:
{"chunk_id": "chk_...", "source_id": "src_...", "text": "",
"image": {"media_type": "image/png",
"path": "/knowledge/indexes/idx_8Bd3.../chunks/chk_.../image"}}
Haal de afbeelding op door path achter de basis-URL van de API te zetten, met dezelfde sleutel:
curl -s "$CORE_URL/knowledge/indexes/idx_8Bd3.../chunks/chk_.../image" \
-H "Authorization: Bearer $CORE_KEY" -o diagram.png
Dat geeft 404 overal waar de zoekopdracht je de treffer niet had kunnen tonen. Is het document
sinds het indexeren zo veranderd dat de afbeelding niet meer op haar plek staat, dan geeft het ook
404 en vraagt het je opnieuw te indexeren. De tekst in een afbeelding leest deze pipeline niet;
een index waarvan de pipeline de stap llama_parse bevat, leest de tekst in een geüploade
afbeelding, zoals bij een gescande pagina.
4. Het model laten zoeken¶
Een zoektool is een zoekpipeline met bronnen: hij draait één versie van een pipeline van jezelf, en bereikt precies de bronnen die die pipeline noemt -- een index, een collectie. Je maakt dus eerst de pipeline, registreert daarop de tool en biedt de tool daarna op naam aan. Wat een tool mag bereiken bepaal jij; het model kiest alleen de vraag.
Begin bij een sjabloon en vul de index in. De bronblokken van een sjabloon zijn leeg, en een kopie komt er pas als elk ervan iets noemt:
curl -s -X POST "$CORE_URL/knowledge/pipelines/from-template" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"template": "retrieval/hybrid",
"name": "handboek-zoeken",
"sources": {"index": "idx_8Bd3..."}}'
Je krijgt de nieuwe pipeline terug met zijn versie 1. Registreer de tool op die versie:
curl -s -X POST "$CORE_URL/knowledge/retrieval-tools" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"name": "handboek",
"description": "Doorzoek het interne handboek.",
"pipeline": {"pipeline_id": "pip_...", "version": 1},
"filter_keys": ["folder"]}'
{
"model": "<een model-id>",
"tools": [{ "type": "tool", "name": "knowledge__handboek" }],
"input": "Hoe lang heb ik om te declareren?"
}
Een tool zet altijd een versie van een eigen pipeline vast: een sjabloon op de tool zelf noemen geeft
422, want een sjabloon bereikt niets tot je het invult. Een nieuwe versie van de pipeline verandert
niets tot je de pipeline van de tool er met PATCH op zet. Elke index en collectie die de versie
noemt wordt tegen je sleutel gecontroleerd als je de versie schrijft, en opnieuw als je hem
vastzet. De tool heeft geen eigen chatmodel — elke LLM-stap van zijn pipeline noemt die zelf, en
valt anders terug op het model van de beurt. Een toolnaam is kleine letters en maximaal 48 tekens;
het model ziet knowledge__<naam>.
| De pipeline leest | Met het bronblok | Sjablonen |
|---|---|---|
| een index, op trefwoord en op betekenis | index |
retrieval/hybrid, retrieval/keyword, retrieval/semantic en de andere |
| hele documenten achter de beste passages | collection, aangesloten op fetch_documents |
retrieval/hybrid-documents |
| documenten van een collectie die geen index selecteert, op de woorden in hun titel | collection, aangesloten op collection_lookup |
-- |
| één tabel van een werkmap, een CSV of een JSON-body, per veld bevraagd | collection of index, aangesloten op tabular_query |
retrieval/tables |
Elke sleutel in filter_keys wordt één optioneel tekstargument op de tool, dus de tool hierboven
wordt aan het model aangeboden als {"query", "top_k", "folder"}. De waarde die het model meegeeft
geldt binnen het eigen metadata_filter van de tool: die versmalt de vraag en kan hem nooit
verbreden, en een waarde die het eigen filter tegenspreekt levert geen treffers op. Met de
echo-provider kun je die aanroep zelf sturen:
{
"model": "<een echo-model-id>",
"tools": [{ "type": "tool", "name": "knowledge__handboek" }],
"input": "call:knowledge__handboek {\"query\": \"declareren\", \"folder\": \"hr\"}"
}
Een tool die geen filter_keys noemt wordt aangeboden als {"query", "top_k"}. Een tool op
retrieval/tables biedt ook table_query aan: het model kiest een van de tabellen die de tool
bereikt -- elk beschreven met de titel van het document, de naam van de tabel en de kolommen -- en
geeft een vraag per veld over die tabel mee. Een argument dat de tool nooit aanbood, een tabel die
hij niet aanbiedt en een vraag die niet bij de kolommen van de tabel past komen bij het model terug
als "Tool arguments were not valid." of "Unknown table.", niet als een mislukte beurt.
Eén zoektool registreer je nooit. Elke beurt van je sleutel krijgt ook knowledge__uploads
aangeboden, een zoekopdracht over de eigen collectie van je sleutel -- de bestanden die je
uploadde en de bestanden die je tools maakten. Je noemt hem niet in
tools[] en er valt niets aan te maken; een forbid-regel van de soort tool in je beleid die knowledge__uploads noemt haalt hem weg, net als het
uitzetten van index_uploads in de files-configuratie van die sleutel, op POST
/tenants/{id}/keys of PATCH /tenants/{id}/keys/{key_id} (de console heeft er vandaag geen veld
voor).
Welke regels gelden als het model voor een persoon zoekt. Noemt een verzoek een persoon (Bouwen voor personen), dan komen in één zoekopdracht meerdere regels samen:
- Elke index, collectie en graaf die de pipeline van de tool noemt gaat langs de regels van de
soort
knowledge_index,knowledge_collectionenknowledge_graph, voor die persoon en evengoed voor een verzoek dat niemand noemt. Weigeren die er een, dan wordt een verzoek dat de tool aanbiedt geweigerd met404, alsof de tool niet bestaat, of het de tool nu bij naam noemt of via een toolset. De weigering komt in het auditspoor. - De treffers worden versmald door de regels van de soort
knowledge_source, die delabelsvan elke bron lezen, en voor uploads en artefacten door die van de soortstored_file. De regels over collecties en indexen halen nooit losse treffers weg.
Wil je een zoektool voor sommige mensen helemaal onbereikbaar maken, label dan de zoektool en
schrijf een regel van de soort tool (Labels op alles).
Geen regel over knowledge_collection verbergt de eigen collectie van je sleutel, waar haar
uploads heen gaan, voor die sleutel, en geen regel over knowledge_index verbergt de index die
Core erover bijhoudt voor knowledge__uploads: die zoekopdracht gaat langs geen van beide soorten,
dus het eerste punt hierboven geldt er niet voor. Hij doorzoekt de eigen collectie van je
sleutel: een PATCH die de labels of collection_ids van die index zou wijzigen, krijgt 409,
vanaf een sleutel en vanuit de console, tenzij hij de index terugzet naar alleen die collectie,
zonder filter en zonder labels. Wil je sommige mensen erbij weghouden, schrijf
dan een forbid-regel van de soort tool die knowledge__uploads noemt. Je kunt hem ook een label
geven met PUT /labels/tool/knowledge__uploads, vanaf elke sleutel of vanuit de console, en de
regel over dat label schrijven; het label is van je organisatie en geldt voor de uploadtool van
elke sleutel. De regels over
knowledge_source en stored_file versmallen de treffers nog steeds. Een verzoek dat die index op
id leest of doorzoekt, op de routes onder /knowledge/indexes, gaat wel langs de regels over
knowledge_index, net als elk ander.
Eigen zoekpipelines¶
Bouw een eigen pipeline als geen sjabloon is wat je wilt, en noem zijn bronnen als blokken: een
blok index voor elke index die een zoekstap leest (een zoekstap heeft er minstens één nodig), een
blok collection voor elke collectie waarvan een stap de documenten heel leest. De naam en
omschrijving van de tool vertellen het model wanneer het hem moet gebruiken:
curl -s -X POST "$CORE_URL/knowledge/pipelines/from-template" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"template": "retrieval/hybrid-documents",
"name": "handboek-heel",
"sources": {"index": "idx_8Bd3...", "collection": "col_2Pf7..."}}'
Test de tool buiten een modelbeurt met POST /knowledge/retrieval-tools/{id}/query. Je krijgt
dezelfde zoekuitvoer terug, en hij neemt dezelfde table_query aan die een model zou meegeven.
POST /knowledge/pipelines/{id}/test draait een versie nog voor een tool hem vastzet. Bekijk ingebouwde pipelines met GET /knowledge/pipeline-templates en
beschikbare stappen met GET /knowledge/pipeline-components. De componentcatalogus toont voor welke
modelafhankelijke stappen een model is ingesteld. Een niet-beschikbare component kiezen geeft 422.
Maak eigen pipelines aan met POST /knowledge/pipelines. Net als prompts hebben
pipelines onveranderlijke versies. Een tool zet de gebruikte versie vast.
GET /knowledge/pipelines/{id}/models toont elke stap van de nieuwste versie die een chatmodel
aanroept: de node_id en node_type van de stap, het model dat hij noemt, waar dat model draait
(region, country) en of het beleid van je sleutel het toelaat (allowed). Een stap die je beleid
weigert, faalt met policy_denied zodra hij draait; hier vind je hem vooraf. Een stap die geen model
noemt, gebruikt dat van de beurt en staat erin met model: null. Een ingest-pipeline draait onder de
sleutel die de bron aanmaakte, dus daar is allowed het antwoord voor bronnen die jouw sleutel
aanmaakt. Een verzegeld gedeelde pipeline toont zijn modellen zonder stap-id's of -typen.
Wil je een pipeline binnen één map of één label houden, geef hem dan een filter-stap:
input -> filter -> semantic_search -> output, met als metadata_filter een JSON-object dat tegen
de metadata van een fragment wordt gematcht, bijvoorbeeld {"folder": "hr"}. Het sjabloon
retrieval/filtered is precies die vorm. De stap versmalt elke vraag die de pipeline draait, ook de
varianten van een herschrijfstap, en twee stappen stapelen waarbij de laatste een gedeelde sleutel
wint. De eigen metadata_filter van een zoekstap wint van wat de stap zette, en het filter van de
tool zelf geldt nog boven beide: een andere waarde vragen voor een sleutel die de tool vastzet,
levert niets op in plaats van een bredere zoekopdracht.
Resultaten en bronverwijzingen¶
Zoekresultaten bevatten genummerde passages en bronvermeldingen. Opgehaalde passages zijn een
toolresultaat: het model gebruikt ze voor het antwoord en ze krijgen geen instructie-autoriteit.
Het model krijgt te horen dat het gegevens zijn als je sleutel
trust_envelope heeft.
De lijst citations van het resultaat bevat één vermelding per passage, in de volgorde waarin de
passages genummerd zijn: kind: "file", het id van het tekstblok als ref -- of het eigen id van
het document, voor een heel document dat een collectieblok las -- en de titel van de bron. Schrijft het model daarna [n] in zijn antwoord, dan lost Core die markering op tegen
diezelfde nummering en geeft die terug als annotatie bij de tekst van de assistent, zodat je de zin
zelf kunt markeren in plaats van een lijst onderaan. Een tweede zoekopdracht in dezelfde beurt
nummert door waar de eerste ophield ([4] na drie passages), zodat het model nooit één nummer
voor twee bronnen ziet. Een markering die een passage noemt die geen zoekopdracht teruggaf, blijft
gewone tekst (waar de bronnen van een antwoord staan).
Mislukt het zoeken tijdens een beurt, dan geeft de tool een vaste melding, zoals "Retrieval
failed.", "Retrieval budget exhausted." of "Denied by policy.". De beurt gaat door.
Een aangehaalde passage lezen¶
Een bronvermelding noemt een passage bij het id van het tekstblok: ref in de citations van een
resultaat, file_id in een file_citation-annotatie, chunk_id in een zoekresultaat. Wil je de
passage zelf tonen, lees dan het tekstblok:
curl -s "$CORE_URL/knowledge/chunks/chk_..." -H "Authorization: Bearer $CORE_KEY"
{
"id": "chk_...",
"index_id": "idx_8Bd3...",
"source_id": "src_...",
"collection_id": "col_...",
"source_title": "Declaratiebeleid",
"position": 4,
"text": "Declaraties moeten binnen 30 dagen worden ingediend ...",
"truncated": false,
"image": null
}
text is hoogstens 32.768 tekens lang, en truncated zegt of het tekstblok langer was. Een
afbeelding heeft een lege text en een image-link, net als in een zoekresultaat. Een
bronvermelding die een heel document noemt in plaats van een tekstblok -- een id dat niet met
chk_ begint -- is geen tekstblok en krijgt 404.
Je leest een tekstblok overal waar je de zoekopdracht had kunnen doen die het vond: via een index
waarin je sleutel mag zoeken, uit een bron die de persoon die je verzoek noemt mag lezen. Al het
andere krijgt 404, net als een id dat nooit heeft bestaan, zodat de route nooit verraadt dat er
een passage is die je niet mag zien. Een
subject-token leest het als zijn
persoon, zodat een browser de passages kan openen die zijn eigen antwoorden aanhaalden.
Verbruik¶
Indexeren registreert embedding-tokens, 258 per afbeelding. Zoeken registreert één retrieval per zoekstap, embedding-tokens voor de zoekvraag en modeltokens voor stappen die een model aanroepen. Hybride zoeken telt twee retrievals omdat het twee ranglijsten berekent. Zie Wat Core meet.