Getting started with ToolUp.KnowledgeBase
Getting started with ToolUp.KnowledgeBase
End-to-end walkthrough: enable KB in your app, upload a document, watch the assistant ground its answers.
Prerequisites
- A working ToolUp Platform app with both
ToolUp.AIandToolUp.RAGenabled — see AI getting-started and RAG getting-started.
KB is the canonical RAG consumer; without RAG in place, KB has no place to write the indexed content.
1. Add the packages
In your server project's .fsproj:
<ItemGroup>
<PackageReference Include="ToolUp.KnowledgeBase.Server" />
</ItemGroup>
In your client project's .fsproj:
<ItemGroup>
<PackageReference Include="ToolUp.KnowledgeBase.Client" />
</ItemGroup>
ToolUp.KnowledgeBase.Core is pulled in transitively.
2. Wire the KB module + ingestion observer
In your server composition root:
open ToolUp.KnowledgeBase
let kbModule =
ServerModule.create "KnowledgeBase"
|> ServerModule.withGuardedApi KnowledgeBase.Server.knowledgeApi
|> ServerModule.withDataTypes [ KnowledgeBase.Server.kbDataType ]
let ingestionStatusObserver = KnowledgeBase.Server.makeIngestionStatusObserver()
RAGServerApp.create (aiProviderFactory, aiConfigStore, embedder)
|> RAGServerApp.withConfig serverConfig
|> RAGServerApp.withAuth authProvider
|> RAGServerApp.withStorage blobStorage
|> RAGServerApp.addModules [ kbModule ]
|> RAGServerApp.withIngestionStatusObserver ingestionStatusObserver
|> RAGServerApp.withVectorisationHandler KnowledgeBase.Server.kbVectorisationHandler
|> RAGServerApp.run
The vectorisation handler runs on every KB document save and turns the extracted text into chunks for the ingestion queue. The observer surfaces per-document status to the UI via SSE.
3. Wire the client wrapper + narrative-commit
open ToolUp.KnowledgeBase
// Install the narrative-commit handler before module registration —
// other modules' "Save to Knowledge Base" buttons resolve through this.
KnowledgeBaseView.installNarrativeCommit ()
let modules = [
KnowledgeBaseView.register ()
// ... your other modules
]
AIClientConfig.withAIAssistant aiMode clientConfig modules
|> Program.withReactSynchronous "elmish-app"
|> Program.run
4. Optional — wire the standing AI context builder
The KB module supports a "Standing AI Context" page where the team can write persistent instructions for the assistant (e.g. "The team focuses on Q3 marketing analysis. Brand names are case-sensitive."). Wire the builder into the AI compose:
let standingContextBuilder =
KnowledgeBase.Server.standingContextBuilder blobStorage (Some logger)
RAGServerApp.create (aiProviderFactory, aiConfigStore, embedder)
|> ...
|> RAGServerApp.withAIConfig {
AIAssistantServerConfig.defaults with
SystemPrompt = Some (SystemPromptBuilder.compose [
SystemPromptBuilder.fromStatic "You are a helpful assistant. ..."
standingContextBuilder
// ... other builders (active module, RAG retrieval, etc.)
])
}
|> RAGServerApp.run
The builder reads the team's standing context per outer turn (cheap blob read) and prepends it to the system prompt. KB never auto-injects — the deployment's composition root is the only place that sees both AI and KB.
5. Verify the wiring
Start the server. Visit the app; sign in. The "Knowledge Base" sidebar entry should appear with three pages:
- Documents — drag-drop upload area, list of uploaded documents with per-document status.
- Notes — text input area, list of saved notes.
- AI Context — team-level standing context for the assistant.
6. Upload a document
Drag a PDF onto the Documents page. Watch the status panel update through:
Pending— queuedExtracting— multi-format extractor runningChunking— text split into indexed chunksEmbedding— embedding provider called per chunkIndexed— chunks visible to retrieval
Status updates flow over SSE; the UI shows live progress. Failed jobs show Failed with a one-line reason.
7. Chat with the assistant
Open the AI side panel. Ask a question about the document. The retrieval pipeline retrieves matching chunks from the team scope, injects them into the system prompt, and the assistant answers grounded in the retrieved content.
If the assistant doesn't use the retrieved content, check:
MinScoreis too high — trywithMinScore 0.2.- The document didn't extract well — check the Documents page status; failed extractions show
Failed. - The embedding model is mismatched —
/health/ragshows the active embedder'sProviderId/ModelId. If you changed it post-ingestion, you'll need to re-embed (see RAG concepts).
8. Save from another module — narrative-commit
When another module has content worth indexing (analysis output, generated text, etc.), add a "Save to Knowledge Base" button:
Html.button [
prop.text "Save to Knowledge Base"
prop.onClick (fun _ ->
Toolup.NarrativeCommit.submit {
Title = "Sales Q3 Analysis"
Body = analysisBody
SourceModule = "SalesAnalysis"
})
]
The narrative-commit handler installed by KnowledgeBaseView.installNarrativeCommit () receives the submit, persists the narrative, runs it through the vectorisation handler, and indexes the chunks. Appears in the user's Documents list with KnowledgeSource.FromNarrative.
9. Notes
Quick text snippets that don't justify a full document. Type into the Notes page input, hit Enter. The note is persisted, indexed, and visible alongside documents in retrieval. Useful for capturing one-off observations the assistant should know about ("we measure sales in units, not value").
10. AI Context (standing instructions)
Visit the AI Context page. Add entries like:
- "Brand names are case-sensitive."
- "The current quarter is Q3 2026."
- "Default analysis window is 4 weeks."
When the standing context builder is wired (Step 4), every chat turn includes these entries in the system prompt. Useful for team-level conventions the assistant should always know.
Next steps
- concepts.md — upload → extract → chunk → ingest pipeline, ingestion-status flow, narrative-commit mechanism.
- api-reference.md — the full
KnowledgeApicontract + handler shape. - extending.md — replacing the built-in module, adding new extractors.