Knowledge Base
A common bottleneck of LLMs is imposed by their limited context windows. In medium to big coding projects this limitation can be easily observed through the high number of hallucinations the models make when dealing with complex tasks.
Project specific information such as architecture documents, coding standards, and design guidelines are often too large to fit in the context window, yet they are essential for the LLM to deliver accurate responses.
The Knowledge Base addresses this problem by acting as an external, searchable memory for your project documents. Instead of stuffing everything into the prompt, documents are indexed once and made available to the LLM on demand through dedicated search tools that have RAG capabilities.
Usage
The Knowledge Base is populated manually by the user. Documents such as architecture docs, coding standards, design guidelines are indexed once, then made available to the LLM on demand.
The indexing pipeline follows these steps:
Documents are converted to plain text using a converter.
The text is split into chunks and each chunk is transformed into a vector embedding using the configured Embedding Model.
The resulting index is stored locally and persists across sessions.
Adding documents
To add documents to the knowledge base, click the Load Files… button located in the dedicated chat page. Documents are indexed automatically upon addition if an embedding model is configured.
Note
If no embedding model is configured, documents are still added to the knowledge base, but only the textual_search_knowledge_base tool will be available during retrieval.
Managing the embedding model
Use the DVT AI: Set Embedding Model command to change the embedding model.
You can enforce the usage of a specific embedding model (See Advanced Configuration).
Note
Changing the embedding model requires reindexing all documents.
Advanced Configuration
The Knowledge Base can be customized to support more advanced use cases. For instance:
Selecting which converter to use for each document format
Adjusting how documents are split into chunks (size, overlap)
Sharing a knowledge base with team members
Converters
A converter transforms a file from its original format into plain text (usually Markdown), making its content available for indexing and retrieval.
Converter Configuration
Converters can be configured through a dedicated configuration object that defines specific options for each converter. AI Assistant looks for the converter configuration file in the following locations:
$DVT_HOME/config/ai/converters.{json,jsonc,js,ts}
$DVT_AI_DIR/converters.{json,jsonc,js,ts}
$HOME/.dvt/ai/converters.{json,jsonc,js,ts}
<project>/.dvt/ai/converters.{json,jsonc,js,ts}
{
"version": 10,
"configs": [
{
"strategy": "tika",
"from": ["pdf", "docx", "pptx", "xlsx"],
"maxFileSizeBytes": 52428800
},
{
"strategy": "internal-converter",
"from": ["pdf", "docx"],
"maxFileSizeBytes": 52428800,
"strategyOptions": {
"endpoint": "http://parsing.internal.service/parse"
}
}
]
}
import { ConvertersConfig } from "./@api/v10"
export default {
version: 10,
configs: [
{
strategy: "tika",
from: ["pdf", "docx", "pptx", "xlsx"],
maxFileSizeBytes: 50 * 1024 * 1024
},
{
strategy: "internal-converter",
from: ["pdf", "docx"],
maxFileSizeBytes: 50 * 1024 * 1024,
strategyOptions: {
endpoint: "http://parsing.internal.service/parse"
}
}
]
} satisfies ConvertersConfig
export default {
version: 10,
configs: [
{
strategy: "tika",
from: ["pdf", "docx", "pptx", "xlsx"],
maxFileSizeBytes: 50 * 1024 * 1024
},
{
strategy: "internal-converter",
from: ["pdf", "docx"],
maxFileSizeBytes: 50 * 1024 * 1024,
strategyOptions: {
endpoint: "http://parsing.internal.service/parse"
}
}
]
}
Properties
version- required, numberconfigs- required, array of dynamic configuration
Each dynamic configuration has the following properties:
strategy- required, string representing the converter strategy name. Must correspond to an available predefined or custom converterfrom- required, list of file formats (extensions) this converter handlesmaxFileSizeBytes- required, number representing the maximum file size in bytes that this converter will processstrategyOptions- optional, strategy-specific options passed to the converter factory at runtime. Converter factories can use this to receive additional data they require (e.g. API keys, endpoint URLs).
Predefined Converters
AI Assistant comes with a set of predefined converters for converting popular file formats (e.g pdf, docx, pptx).
Use the following values to set the converters through file-base dynamic configurations.
Tika
strategy: tika
from: defaults to
pdf,xlsx,pptx,docxmaxFileSizeBytes: defaults to 50MB
Llama-Cloud
This converter uses the LlamaParse cloud API. See the Official Documentation for more details.
strategy: llama-cloud
from: defaults to
pdf,maxFileSizeBytes: defaults to 50MB
- strategyOptions:
apiKey: defaults to the value of LLAMA_CLOUD_API_KEY environment variable
Note
All of the converters work out of the box except Llama-Cloud, which requires the LLAMA_CLOUD_API_KEY to be set.
Custom Converters
AI Assistant allows you to define custom converters by providing a converter factory. A converter factory is a module that registers a new conversion strategy and provides the logic for converting documents into Markdown.
AI Assistant looks for converter factories in the following locations:
$DVT_HOME/config/ai/converter-factories/*.{ts,js}
$DVT_AI_DIR/converter-factories/*.{ts,js}
<project>/.dvt/ai/converter-factories/*.{ts,js}
$HOME/.dvt/ai/converter-factories/*.{ts,js}
The strategy field exported by the factory must match the strategy value used in the converter configuration.
import { ConvertedDocument, Converter, ConverterFactory, DefaultConverterConfig } from "../@api/v10"
const INTERNAL_SERVERL_URL = "http://parsing.internal.service";
export default {
version: 10,
strategy: 'internal-converter',
getDefaultConverterConfig: async (): Promise<DefaultConverterConfig> => {
return {
from: ["pdf", "docx"],
maxFileSizeBytes: 50 * 1024 * 1024
}
},
getConverter: async (config, abortSignal): Promise<Converter> => {
return {
config,
convert: async (inputDocument): Promise<ConvertedDocument> => {
const filePath = inputDocument.filePath;
const response = await fetch(`${INTERNAL_SERVERL_URL}/parse`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ filePath }),
signal: abortSignal,
});
if (!response.ok) {
const errorBody = await response.json().catch(() => ({}));
throw new Error(
errorBody.error ?? `Parsing server error: ${response.status} ${response.statusText}`
);
}
const result = await response.json();
return {
text: result,
filePath: inputDocument.filePath,
documentId: inputDocument.documentId
};
},
}
}
} satisfies ConverterFactory
const INTERNAL_SERVERL_URL = "http://parsing.internal.service";
export default {
version: 10,
strategy: 'internal-converter',
getDefaultConverterConfig: async () => {
return {
from: ["pdf", "docx"],
maxFileSizeBytes: 50 * 1024 * 1024
}
},
getConverter: async (config, abortSignal) => {
return {
config,
convert: async (inputDocument) => {
const filePath = inputDocument.filePath;
const response = await fetch(`${INTERNAL_SERVERL_URL}/parse`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ filePath }),
signal: abortSignal,
});
if (!response.ok) {
const errorBody = await response.json().catch(() => ({}));
throw new Error(
errorBody.error ?? `Parsing server error: ${response.status} ${response.statusText}`
);
}
const result = await response.json();
return {
text: result,
filePath: inputDocument.filePath,
documentId: inputDocument.documentId
};
},
}
}
}
Knowledge Base Pipeline Configuration
The Knowledge Base can be configured through a dedicated configuration object. AI Assistant looks for the knowledge base pipeline configuration file in the following locations in this exact order:
$DVT_HOME/config/ai/rag_pipeline.{json,jsonc,js,ts}
$DVT_AI_DIR/rag_pipeline.{json,jsonc,js,ts}
<project>/.dvt/ai/rag_pipeline.{json,jsonc,js,ts}
$HOME/.dvt/ai/rag_pipeline.{json,jsonc,js,ts}
{
"version": 10,
"converters": [
{ "from": "pdf", "strategy": "tika" },
{ "from": "docx", "strategy": "tika" },
{ "from": "xlsx", "strategy": "tika" }
],
"embeddingConfig": {
"maxChunkSize": 1000,
"chunkOverlap": 40,
"embedder": {
"providerName": "openai",
"modelName": "text-embedding-3-small"
}
},
"storageConfig": {
"storagePath": "$HOME/.dvt/ai/vector_db"
}
}
import { RAGPipelineConfig } from "./@api/v10"
export default {
version: 10,
converters: [
{ from: "pdf", strategy: "tika" },
{ from: "docx", strategy: "tika" },
{ from: "xlsx", strategy: "tika" },
],
embeddingConfig: {
maxChunkSize: 1000,
chunkOverlap: 40,
embedder: {
providerName: "openai",
modelName: "text-embedding-3-small"
}
},
storageConfig: {
storagePath: "$HOME/.dvt/ai/vector_db"
}
} satisfies RAGPipelineConfig
export default {
version: 10,
converters: [
{ from: "pdf", strategy: "tika" },
{ from: "docx", strategy: "tika" },
{ from: "xlsx", strategy: "tika" },
],
embeddingConfig: {
maxChunkSize: 1000,
chunkOverlap: 40,
embedder: {
providerName: "openai",
modelName: "text-embedding-3-small"
}
},
storageConfig: {
storagePath: "$HOME/.dvt/ai/vector_db"
}
}
Properties
version - required, number
converters - optional, array of objects having the following properties
from(string) - The source file format (e.g.pdf,docx,md).strategy(string) - The converter strategy name. Must correspond to an available configured converter. If multiple entries match the same format, the first one takes precedence.
embedding - optional, object
maxChunkSize(number) - The maximum size of a chunk in tokens. Controls the granularity of the input data. This value must be less than the max input size of the configured embedding model.chunkOverlap(number) - The number of tokens that overlap between consecutive chunks. Overlapping chunks help preserve context across boundaries.embedder.providerName(string) - The provider name. Must match a provider configured in the model configuration.embedder.modelName(string) - The embedding model name. Must exist in the provider’s configured models list.
storage - optional, object
storagePath(string) - Absolute file path to the locally stored database file. Supports environment variable expansion (e.g.$HOME,$DVT_HOME).
Note
When you change the embedding model using the DVT AI: Set Embedding Model command or by modifying the configuration, all previously indexed documents must be reindexed to remain compatible with the new model.
Examples
Configuring the Knowledge Base to use a custom converter
{
"version": 10,
"converters": [
{ "from": "pdf", "strategy": "docling" },
{ "from": "docx", "strategy": "tika" },
{ "from": "xlsx", "strategy": "tika" }
],
"storageConfig": {
"storagePath": "$SHARED_DIRECTORY/.dvt/ai/vector_db"
}
}
import { ConvertedDocument, Converter, ConverterFactory, DefaultConverterConfig } from "../@api/v10";
const DOCLING_SERVER_URL = "http://127.0.0.1:8001";
export default {
version: 10,
strategy: 'docling',
getDefaultConverterConfig: async (): Promise<DefaultConverterConfig> => {
return {
from: ['pdf'],
maxFileSizeBytes: 50 * 1024 * 1024,
}
},
getConverter: async (config, abortSignal): Promise<Converter> => {
return {
config,
convert: async (inputDocument): Promise<ConvertedDocument> => {
const filePath = inputDocument.filePath;
const response = await fetch(`${DOCLING_SERVER_URL}/parse`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ filePath }),
signal: abortSignal,
});
if (!response.ok) {
const errorBody = await response.json().catch(() => ({}));
throw new Error(
errorBody.error ?? `Docling server error: ${response.status} ${response.statusText}`
);
}
const result = await response.json();
return {
text: result.text,
filePath: inputDocument.filePath,
documentId: inputDocument.documentId
}
},
}
},
} satisfies ConverterFactory;
from flask import Flask, request, jsonify
from pathlib import Path
from docling.document_converter import DocumentConverter, PdfFormatOption
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions, TableStructureOptions, TableFormerMode
import hashlib
app = Flask(__name__)
SUPPORTED_EXTENSIONS = {".pdf"}
PAGE_BREAK = "<!-- page break -->"
ARTIFACTS_PATH = "~/.cache/docling/models"
def get_pdf_pipeline_options():
return PdfPipelineOptions(
enable_remote_services=False,
do_ocr=False,
do_table_structure=True,
table_structure_options=TableStructureOptions(
mode=TableFormerMode.ACCURATE
),
artifacts_path=ARTIFACTS_PATH
)
def convert_document(file_path: str) -> dict:
"""Convert a document to markdown and return a ConvertedDocument dict."""
path = Path(file_path).resolve()
if not path.exists():
raise FileNotFoundError(f"File not found: {path}")
converter = DocumentConverter(
format_options={
InputFormat.PDF: PdfFormatOption(
pipeline_options=get_pdf_pipeline_options(),
)
}
)
result = converter.convert(str(path))
doc = result.document
content = doc.export_to_markdown(
image_placeholder="",
page_break_placeholder=PAGE_BREAK,
include_annotations=True,
mark_annotations=True
)
document_id = hashlib.sha256(content.encode("utf-8")).hexdigest()
if path.suffix.lower() == ".pdf" and PAGE_BREAK in content:
text = [page.strip() for page in content.split(PAGE_BREAK)]
else:
text = content
return {
"documentId": document_id,
"filePath": str(path),
"text": text,
}
@app.route("/parse", methods=["POST"])
def parse():
data = request.get_json(silent=True)
if not data or "filePath" not in data:
return jsonify({"error": "Missing 'filePath' in JSON body"}), 400
file_path = data["filePath"]
path = Path(file_path)
if not path.exists():
return jsonify({"error": f"File not found: {file_path}"}), 404
if path.suffix.lower() not in SUPPORTED_EXTENSIONS:
return jsonify({"error": f"Unsupported file type: {path.suffix}"}), 400
try:
result = convert_document(file_path)
return jsonify(result), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8001, debug=False)