The experiment: turning my huge datasheet library into a smart AI reviewer for schematics and component choices using DeepSeek + RAG.
What initially looked like a simple task that would deliver great results quickly turned into an open field of experimentation. Then again, that might just be my nature.
Distiller harness
The first attempts at extracting parameters into JSON format showed that the harness I applied was too general:
"(…)identify the component type, then extract the part number, manufacturer, and all parameters important for evaluating schematics." (plus some additional requests regarding output format).
The model handled the interpretation of catalog data quite well, but it had to guess which criteria would decide whether something counted as an “important parameter” or not. Maximum supply voltage or collector current were obvious things. But pinout? It does not describe any specific physical value, so from that point of view it could be considered unimportant. However, since we want to use the agent to perform cross-checks on our schematic, this data is actually essential. It was an obvious oversight on my part, and after processing 15% of my dataset I decided to stop the process and create a new, more specific harness. This time I added:
"(…)identify the component type, then extract the part number, manufacturer, pinouts and the parameters important for evaluating schematic for design issues. Reject files that are not referring to the components."
VRAM limit
There was also a second reason to interrupt the data distillation process: half of the DeepSeek R1 model was sticking out of VRAM into CPU (I was using an RTX 4060Ti with 8GB VRAM, model deepseek-r1:14b). When the model does not fit entirely in VRAM, a so-called System RAM Fallback occurs and part of the model layers are processed on the GPU while the rest is processed on the CPU. For comparison: data transfer speed in VRAM is around 270GB/s, whereas when data between model layers has to be pushed through the PCIe bus, inference speed drops drastically (less than 16GB/s for PCIe x8) and instead of achieving 25-30 tokens per second, it drops to a painful 1-2 tokens per second.
In practice, this solution turned out to be inefficient. The distiller processed only about 200 datasheets per day. At that rate, I would need about a week and a half to process the entire collection of PDFs.
Theoretically, I could have used a lighter and faster model to analyze the datasheet’s collection, but I did not want to do that for a simple reason: the quality of the distilled data could suffer. To be honest, I would rather wait a week and a half for a proper dataset than put something together hastily and expect spectacular results.
In the end, I decided to buy a more powerful GPU: RTX 5060Ti with 16GB VRAM. 16GB + 8GB gives a total of 24GB, which finally gives some space to work with models.
In relation to the PCIe bus itself, it is worth noting that when splitting PCIe channels between multiple GPUs, we lose data transfer speed to / from the GPU. What does this mean in practice? Large neural network models, weighing several or even over a dozen gigabytes, will take longer to load into VRAM, but once loaded, the inference speed will be comparable. To put it simply: the cold start of the model will take a bit longer.
Pro tip: In the case of low PCIe bandwidth, it is worth configuring our code (or the Ollama server) to keep the model in GPU memory instead of immediate offloading, in order to minimize cold start time.
PCIE sharing - how my dual GPU dreams confronted hardware reality
When I tried to install the second card in the motherboard, it turned out that it does not allow splitting PCIe x16 into 2x PCIe x8.
Pro tip: Not all motherboards support dual GPU installation, and it is not only about having enough PCIe slots. The motherboard must support splitting PCIe channels between slots (bifurcation).
Therefore, in order to use two GPUs, I would have to replace my several-year-old hardware with something more modern (which, with current RAM prices, would require putting around $2500 on the table), or find a used motherboard compatible with the rest of my peripherals that would allow such a split. Since I did not find such a used board and I could not internally convince myself of the validity of replacing the hardware, I left the RTX 5060Ti 16GB in the computer, while the RTX 4060Ti is currently sprouting the idea of setting up a box on the LAN to host a separate Ollama server (something like clustering).
On a side note: the old RTX 4060Ti GPU was running in PCIe GEN3 standard (because that is what the motherboard and CPU allowed), while the new GPU is already PCIe GEN5 standard. My hardware falls back to PCIe GEN1 and the setup is starting to resemble something held together with power tape and a bunch of zip ties.
Benchmark of the new GPU
Even though in the end I was left with one GPU instead of two, as I had wanted, I do not regret this step. The moment DeepSeek R1 fit entirely into VRAM, the iteration speed of the model increased dramatically and it processed my entire pool of data into JSON format in a day and a half (instead of a week and a half). Performance increased tenfold. Not only did we get rid of the model fallback through the PCIe bus to the CPU, but the new GPU on GDDR7 memory achieves transfers on the order of 450GB/s.
Pro tip: It is quite convenient to use cron to automatically distille new datasheet s. If you use crontab, make sure to block the parallel run of the process if the previous one is still running. Check that you are not placing duplicate JSON data in the database (always choose the more complete dataset).
We have JSON files - what now?
The JSON files we distilled contain the properties of individual components and they need to be collected into some kind of database. If you are used to the order found in relational databases, this will not work here. Why? The reason is quite simple: it is possible to group electronic components by maximum operating voltage or current. But what is the relationship between the series resistance characteristic of a capacitor and the switching time of a semiconductor diode? Or: what connects the drain current of a MOSFET transistor with the breakdown voltage of a TVS diode? The answer is simple: absolutely nothing (at least nothing that could be relatively systematized).
Tensor databases (vector databases)
That is why the appropriate system for storing the chunks of information we have is not relational databases (such as MariaDB) but tensor databases: Qdrant. In my case, I chose Qdrant running directly from Docker:
- lightweight and fast
- data is processed locally and does not travel over the network as in the case of cloud solutions
For some, it may be an advantage that it is written in Rust, but I am not a big fan of it, so I mention this fact only out of a sense of duty as a chronicler.
Saving data to the database: Naive Ingester / Naive Agent
Using the MiniLM model, I started converting the first processed chunks of information into tensors (tokenization) and saving them to the database while the PDF files were still being processed. MiniLM converted JSON structures into tensors and saved them in Qdrant. The effect? Really impressive!
Unfortunately, the “wow” effect did not last very long. What gave excellent results with a small number of tensors started to diverge more and more from reality as their number grew.
Embedding data (tokenization)
The MiniLM model created multidimensional tensors in the database space, describing them using 384 features. When we asked it to find related content in the database, the model determined the direction of the tensor’s placement in multidimensional vector space and returned those with similar polar values. However, as the number of distilled pieces of information grew, the number of tensors described by a small number of features also increased proportionally, and suddenly everything started to look similar to the model. Technically speaking: vector collisions occurred. The model was embedding tensors containing divergent data that produced identical feature representations. As a result, their representation for the model was geometrically identical (they were indistinguishable).
Context window overflow
The context window of the MiniLM model is 256 tokens. In the case of larger PDFs, for example something from a microcontroller, context window overflow occurred: the model cut off everything that exceeded the limit.
The Top-K trap - the biggest sin of Agent #1
Agent #1, using the MiniLM model, extracted data from the database, but received only a small, finite number of tensors (Top-K) and blindly passed them to the DeepSeek R1 model. This meant that when dealing with a few diodes or transistors, the system worked flawlessly, but in the case of dozens of diodes or transistors, the solution became useless. The system found only the first few (or dozen) elements and passed only that much to the DeepSeek R1 model. The result? The agent started claiming that it had no information, even though I knew it did. If we started increasing the limits and retrieving larger amounts of data, we would quickly overload not only our VRAM.
Why did the Naive Ingester / Naive Agent turn out to be a failure?
The MiniLM model could not handle my data tokenization properly. With a small number of features, all tensors looked similar. When queried, the agent asked it to find Top-K vectors with almost identical angles, and the model returned the first tensors found in the database that appeared to be related, without any content analysis. As a result, DeepSeek R1 received a bunch of nonsense on the basis of which it was impossible to formulate a sensible answer. In addition, without reviewing the resources from beginning to end.
Hybrid Ingester / Hybrid Agent
Since we have already identified the causes of our initial failure, it is time to introduce a corrective plan. What we need is:
- A model that gives us a much larger feature space dimension to avoid vector collisions.
We can solve problem number 1 by replacing MiniLM, which turned out to be really “mini”, with something stronger, for example bge-large-en-v1.5. If that turns out to be not enough, we can go with bge-m3.
Problem number 2 means introducing a reranker model that will analyze a dense batch of candidates extracted from the database (for example Top-35) and precisely arrange them from the most relevant.
The devil is in the details
What can go wrong with the plan? Instead of two models, MiniLM and DeepSeek R1, we now have three, and we are replacing MiniLM with two beefier ones. Our theoretical considerations collided with the size of 16GB VRAM - again something started sticking out to the CPU. A sensible solution was to organize the architecture:
- The DeepSeek R1 model should remain in VRAM memory,
- but the embedding and reranker models are relatively small networks, and modern multi-core processors handle them very quickly. Moving the vectorization and reranking processes to the CPU recovers valuable megabytes of VRAM. And every recovered megabyte reduces the chance of System RAM Fallback of the DeepSeek R1 model during thought generation.
Pro tip: When using models like MiniLM or BGE, it is worth using the option to save the model from HF on a local drive. This way we limit network traffic, speed up startup, and can work offline.
This worked really correctly, but then I realized one certain, although important detail. When I ask the model, for example, for a Schottky diode with forward current above 3A, I get a group of a dozen or so components in response. If in the next step I wanted to ask for a summary of their parameters in table form or ask which of them are in SMD version, then… our model would treat our question as a completely separate, new query. Our solution does not have conversation memory and does not know what we were talking about a moment ago.
At this point, it is time for a certain digression: as you have probably noticed, the issue of context size appeared in relation to the tensors stored in the Qdrant database. Each chunk of information takes up the context space offered by the model, and depending on the number of extracted chunks and their size, the solution must provide sufficient context space for the model to process them correctly. Now, if we wanted to equip our model with the memory of our conversation, we would have to increase this space even further. And that means one thing: our model starts swelling in VRAM memory like yeast dough.
It was time to rethink the optimization of the entire architecture and so I arrived at the next solution.
Ingester #3 and Agent #3
I concluded that perhaps, instead of using three models, two of which work in CPU space, I could use DeepSeek also in the role of a reranker and limit the solution to two models. In theory, it might not be as efficient as combining dedicated model intended for reranking data. But theory did not take into account the limitations of my hardware: VRAM availability, transferring gigabytes through PCIe, and prolonged inference calculations on the CPU. On the other hand, I would be trying to use DeepSeek R1 for a purpose other than what it was created for. Fairly easy to find out.
So:
- For handling Qdrant, we keep the same layer as in the hybrid model,
- We will not use a separate reranker model, but we will use DeepSeek from the upper layer for this purpose,
- We will create a sliding context window so that our model remembers the n-last queries. Additionally, we allow it to rewrite the new query itself into what it considers the most appropriate, taking into account the conversation context (Agentic RAG mode).
Aftermath
I really liked experimenting with my own RAG system. First of all, because it requires a certain creative inventiveness - how to correctly design and optimize the structure so that it is not only consistent with theoretical assumptions but also sufficiently lightweight and efficient. It is no finesse to buy a sufficiently powerful and VRAM-rich graphics card - but true mastery is a project that will run efficiently on typical geek’s setup and deliver equally good results. Here a wide field for further exploration opens up: why, for example, not go back to the beginning and try with a model other than DeepSeek R1? Or another version of it…? Something that at first glance seemed like a trivial task promising super effects in a short time turned into a field of experiments. But it could just as well be my nature.
| System version | Embedding engine | Database strategy | Reranking and Memory | Main problem / Bottleneck |
|---|---|---|---|---|
| #1 Naive | MiniLM (256 tokens) | Qdrant (Pure vector, Top-K) | None | Vector collisions with small number of features, truncation of long documents. |
| #2 Hybrid | BGE (512 tokens) | Qdrant (Dense vectors on CPU) | Hybrid CPU / GPU | Every query treated from scratch (no conversation memory). |
| #3 Agentic | BGE | Qdrant (Dense vectors on GPU) | DeepSeek R1 + Sliding history window | High time overhead of R1 on thinking process and rapid growth of KV Cache in VRAM. |
The possibilities offered by RAG are truly incredible. Over the years I have repaired thousands of different electronic boards - and I have everything recorded: device model, fault symptoms, and discovered damages. I am not able to remember and recall everything from memory. This just begs to be turned into the form of an assistant suggesting typical causes of problems.