Carpathian
AI Chat
AI
Software
Cloud
Security
About
Pricing
Contact
Log InSign Up

Subscribe to publications

Research notes, engineering write-ups, and platform updates, sent when we publish.

Verification code: AAAAAA

Carpathian

Carpathian is a software development and cloud hosting company with a research focus on efficient AI. We design and build custom software: web applications, iOS and Android apps, APIs and backend systems, database and systems integration work, and the deployment pipelines that carry it all to production. On the infrastructure side, we run managed cloud VPS on our own US-based hardware and help clients architect, build, and host their workloads, whether that is an application, a database, or an AI model. Our AI engineers work alongside client teams to add AI to the products they ship. Our research goes toward making AI models lighter and cheaper to run, and the tools we build along the way are open source and free to use.

Services

  • AI Chat
  • AI Image Generation
  • Software Development
  • Security
  • Cloud Hosting
  • Managed VPS
  • Object Storage
  • Carpathian AI
  • LLM Harness
  • Documentation
  • Contact Us

Company

  • About Us
  • Our Team
  • Our Work
  • Open Source
  • The Models We Train
  • AI Research
  • Veritate
  • Partnerships
  • Data Centers
  • Privacy Policy
  • Company Policies

Resources

  • Pricing
  • Service Availability
  • Carpathian Status
  • Publications
  • Research
  • Threat Intelligence Feeds
  • The Graveyard
  • Get Outside
  • Feedback
  • Store
  • Sitemap
© 2026 Carpathian, LLC. All rights reserved.Infrastructure hosted in the United States
  1. Home
  2. Publications
  3. How to build semantic RAG AI search

How to build semantic RAG AI search

A walkthrough of how to build semantic search with embeddings using RAG AI to index and chat with your docs, and when keyword search still wins.

GeneralBy Samuel Malkasian | FounderAugust 2, 20268 min read
How to build semantic RAG AI search

Semantic search with embeddings finds text by meaning, not by matching exact words. You turn each document into a vector, which is a long list of numbers that captures what the text is about. You store those vectors. When a query arrives, you embed it the same way and compare it against every stored vector. The closest ones come back as your results. The comparison is a small piece of math called cosine similarity. That is the whole idea, and it is most of what I built for retrieval at Carpathian.

Keyword search asks which documents contain these words. Semantic search asks which documents mean the same thing. Someone can type "my card was declined" and match a help page titled "payment failed at checkout," even though the two share no words. This guide covers what an embedding is, how the ranking works, how to index your own content, and where the approach falls short. By the end you can build a small version yourself.

Weak search costs money. A Google Cloud-commissioned Harris Poll survey of nearly 13,500 shoppers found that search abandonment costs retailers more than $2 trillion a year worldwide, and that 76% of US shoppers ran a search that did not return the item they wanted (Google Cloud). Matching on meaning is one way to close that gap.

What is an embedding?

An embedding is a list of numbers that stands in for a piece of text and captures its meaning. A model reads the text and prints out the numbers. Text with a similar meaning gets similar numbers, so it lands in a similar place. The numbers themselves are not readable. You never look at them by hand. What matters is that meaning turns into position, and position is something a computer can compare fast. Each number is one coordinate. Put enough coordinates together and you have a point in a very high-dimensional space. Two texts that mean the same thing sit close together in that space. Two texts about different topics sit far apart. That single property is what makes search by meaning possible at all.

How does semantic search with embeddings rank results?

Semantic search with embeddings ranks results by how close each stored vector sits to the query vector, using cosine similarity. First you embed the query into the same kind of vector as your documents. Then you score every stored vector against it. The score is a number between minus one and one. Higher means more alike. You sort by that score, high to low, and keep the top few. In my retrieval code the default is the closest twelve chunks. Those go to the model or straight back to the user. There is no keyword step in the middle. The vectors do all the matching, so a result can rank first even when it shares no words with the query.

Cosine similarity sounds fancier than it is. It measures the angle between two vectors and ignores their length. Point the same direction, and the score is one. Point at right angles, and the score is zero. In plain terms, it asks whether two pieces of text lean the same way in meaning, not how long either one is. My version walks every stored chunk, does a little arithmetic per pair, and sorts the results. That is a brute-force scan. It is exact, easy to reason about, and quick when you have thousands of chunks. When you reach millions, you swap the scan for an approximate nearest-neighbor index, which trades a sliver of accuracy for a large jump in speed.

How do you turn your documents into a searchable index?

You break each document into chunks, embed every chunk, and store the vectors next to the text they came from. A whole PDF is too big to embed as one unit, so you split it. In my indexer I aim for chunks of about 1,800 characters, cut on paragraph boundaries where I can, with a 250-character overlap between neighbors. The overlap matters. An answer that straddles the seam between two chunks would otherwise get sliced in half and lost. Each chunk gets embedded and saved with its page numbers, so a match can cite where it came from. For scanned or image-only pages, the text gets pulled out with OCR first, then chunked and embedded like anything else.

Keeping the index fresh is the part people forget. An embedding describes the text as it was on the day you indexed it. Change the document and the old vector is now wrong. When someone edits a page in my system, I re-embed only that document rather than rebuilding everything, which keeps the cost small. A background sweep also retries anything that stalled, so a single failed upload does not sit broken forever. The rule to carry with you: if content can change, you need a plan to re-index it, or your search quietly drifts out of date while looking perfectly healthy.

What else can you build with embeddings?

Once you can embed text and rank by similarity, you have a single primitive that does four different jobs. Find-similar takes one item and returns its nearest neighbors. Recommendations do the same thing from a user's history instead of a single item. Deduplication flags two records whose vectors sit almost on top of each other. Retrieval-augmented generation, or RAG, pulls the closest chunks and hands them to a language model as context. The mechanics underneath are identical every time: embed, compare, rank. Only the input and what you do with the output change. Learn the primitive once and you get all four.

This is why the same step keeps turning up across features that look unrelated on the surface. The retrieval I built for grounded question answering is the same embed-and-rank move you would reach for to power a "more like this" widget. It also shows up when you score content for quality or moderate what users submit, where you compare new text against known examples. If you have built one of these, you are most of the way to the others.

Why run inference through an OpenAI-compatible endpoint?

An OpenAI-compatible endpoint lets you swap the model behind your search without rewriting your app. It is a shared request-and-response shape that many tools already speak. You send messages to a path like /v1/chat/completions, and you get back a standard reply with the answer and a token count. Your code targets that shape, not a specific vendor. On Carpathian's managed inference, the API key you send picks the model, so pointing at a different one is a settings change rather than a code change. The embedding side speaks the same language through /v1/embeddings, so both halves of your search stack share one contract.

The payoff is freedom to change your mind later. A better or cheaper model shows up, and you move to it without touching the app that calls it. My proxy even normalizes replies from a local engine back into the standard shape, so the caller cannot tell the difference. That is how Veritate, our open model work, plugs into the same interface a hosted model would use. Pick the compatible surface early. It costs nothing today, and it saves you a painful rewrite the first time you want to switch models, which you will.

When should you still use keyword search?

You should still use keyword search whenever the query is an exact string that has to match exactly. Embeddings are built to blur near-meanings together, and that is precisely the wrong behavior for an order number, a SKU, an error code, or a person's last name. Search for ticket "INC-4471" and a meaning-based system may happily return "INC-4470," because the two look almost the same to it. That is not a bug you can tune away. It is what matching on meaning does. For identifiers and precise terms, plain keyword lookup is faster, cheaper, and correct.

The fix most teams land on is hybrid search: run both, then blend the scores. Keyword catches the exact hits, embeddings catch the fuzzy ones, and together they cover far more queries than either alone. Two more honest limits are worth stating plainly. Embeddings cost compute to create, so re-indexing a large, fast-changing corpus adds up. And a stale index looks fine while quietly returning yesterday's answers, which is worse than an obvious error because nobody notices.

Embeddings get you most of the way to reliable search without relying on ctl-f searches, with a surprisingly small amount of code. Keep the exact-match cases on keyword search, keep your index fresh, and let meaning do the rest. If you would rather have this built and tuned for your own data, that is the kind of work our team takes on through our AI application development practice.

Samuel Malkasian | Founder
Written by
Samuel Malkasian | Founder

Samuel Malkasian is the founder and lead cloud architect at Carpathian, where he designed the platform's core architecture along with a range of client enterprise systems and open-source tools for AI workflows and integration. He serves as a Cyber Warfare Officer in the U.S. Army and has a background in machine learning, data science, and LLM architecture. He is currently focused on building AI infrastructure that is secure, efficient, and sustainable.

ProfileLinkedInXInstagramThreads

Related publications

Carpathian Threat Intelligence Feeds

Carpathian Threat Intelligence Feeds

Carpathian's threat intelligence feeds list hostile IPs, domains, and URLs at a fixed address, so your firewall can fetch them on a schedule and block them.

Oct 23, 2026
N

Not Receiving Carpathian Emails?

If your signup code or password reset never showed up, your email provider most likely stopped it. School and work addresses are the usual cause.

Oct 12, 2026
Prompts That Get AI to Build Better Websites

Prompts That Get AI to Build Better Websites

How to prompt an AI coding agent to build a website: what a first prompt needs, how to give it your facts, how to ask for changes, and the prompts that go wrong

Oct 11, 2026
Which AI Model Is Best for Building Websites?

Which AI Model Is Best for Building Websites?

The best AI model for building a website depends on your budget. Here's how to run a test on your own, what to compare, and how to weigh cost against quality.

Oct 10, 2026
How to Build a Website With AI, Step by Step

How to Build a Website With AI, Step by Step

How to build a website with an AI coding agent: what to build, how to instruct it, how to preview and review its work, and to take the files and put them online

Oct 9, 2026
How to Shorten Branded URLs on Your Own Domain

How to Shorten Branded URLs on Your Own Domain

How branded short links work, how to set one up on your own domain with a TXT and a CNAME record, which redirect to use, and how to pick slugs people can retype

Oct 8, 2026
Browse all publicationsTalk to the team