{"slug": "hard-negative-mining-teaching-an-llm-what-almost-right-looks-like", "title": "Hard Negative Mining: Teaching an LLM What \"Almost Right\" Looks Like", "summary": "Shrijith Venkatramana, an engineer building the AI code review tool LiveReview, explains hard negative mining — training retrieval and embedding models on examples that are almost right rather than obviously wrong. He traces the technique from FaceNet's online triplet mining in 2015 through Dense Passage Retrieval and Microsoft's ANCE work, arguing that production retrieval systems fail from semantic confusion rather than semantic ignorance.", "body_md": "*Hello, I'm Shrijith Venkatramana, and I'm building LiveReview — a blast-radius aware AI code review built for your business-critical systems. [Star us](https://github.com/HexmosTech/LiveReview/) to help devs discover the project, give it a try, and share your feedback to help improve the product.*\n\nA model learns surprisingly little from examples that are obviously wrong.\n\nSuppose you are training a retrieval model with:\n\nQuery: \"How do I rotate an AWS IAM access key?\"\n\nAnd your negative example is:\n\n\"How do I resize a Kubernetes pod?\"\n\nThe model can separate these easily. One is about IAM credentials; the other is about Kubernetes.\n\nNow give it:\n\n\"How do I create an AWS IAM access key?\"\n\nThat is a much more interesting negative.\n\nIt uses the same vocabulary. It concerns the same object. It may even appear in the right neighborhood of the embedding space.\n\nBut it answers a different question.\n\nThis is the basic idea behind **hard negative mining**: instead of teaching a model merely what is wrong, deliberately show it things that are *almost right* and force it to learn the distinction.\n\nThe technique became important in computer vision with work such as FaceNet, and later became a major component of dense text retrieval. The interesting part for LLM developers is that the same idea now appears in RAG, semantic search, reranking, embedding training, preference data, and other systems where the model must distinguish between closely related alternatives. ([CV Foundation](https://www.cv-foundation.org/openaccess/content_cvpr_2015/html/Schroff_FaceNet_A_Unified_2015_CVPR_paper.html))\n\nImagine you have a query `q`, a relevant document `d+`, and an irrelevant document `d-`.\n\nA contrastive training objective wants:\n\n```\nsimilarity(q, d+) > similarity(q, d-)\n```\n\nAn easy negative might already be far away:\n\n```\nsimilarity(q, d+) = 0.82\nsimilarity(q, d-) = 0.12\n```\n\nThere is little ambiguity.\n\nThe model already knows that the two things are different.\n\nA hard negative could look like:\n\n```\nsimilarity(q, d+) = 0.82\nsimilarity(q, d-) = 0.76\n```\n\nNow the model has a real problem.\n\nWhy does this matter?\n\nBecause retrieval systems rarely fail by retrieving something completely unrelated.\n\nThey fail by retrieving:\n\nIn production, the enemy is usually **semantic confusion**, not semantic ignorance.\n\nHard negative mining turns that confusion into training data.\n\nThe underlying idea is older than language models.\n\nIn 2015, Florian Schroff, Dmitry Kalenichenko and James Philbin published FaceNet. They trained a neural network to map faces into an embedding space where images of the same person were close together and different people were far apart.\n\nThe important engineering problem was choosing which examples to train on.\n\nSuppose you have:\n\n```\nanchor   = Alice's face\npositive = another image of Alice\nnegative = Bob's face\n```\n\nA completely different-looking Bob is not particularly useful.\n\nThe interesting negative is a Bob who looks sufficiently similar to Alice to make the distinction difficult.\n\nFaceNet therefore used online triplet mining, progressively selecting difficult examples during training. The paper describes this as a way of increasing the difficulty of the triplets as the network improves. ([CV Foundation](https://www.cv-foundation.org/openaccess/content_cvpr_2015/html/Schroff_FaceNet_A_Unified_2015_CVPR_paper.html))\n\nA few years later, the same logic became important in text retrieval.\n\nKarpukhin and colleagues' 2020 Dense Passage Retrieval work showed that a relatively simple dual-encoder could produce effective dense retrieval for open-domain question answering. But there was a problem: what you use as a negative during training determines what distinctions the retriever learns. ([ACL Anthology](https://aclanthology.org/2020.emnlp-main.550/))\n\nThen came ANCE from Microsoft researchers including Lee Xiong and Chenyan Xiong.\n\nTheir observation was particularly important:\n\n**The negatives used during training often did not resemble the documents the model would actually confuse during inference.**\n\nTheir solution was to use an approximate-nearest-neighbor index to retrieve difficult negatives using the model itself, and periodically refresh that index as the model changed. In other words, the model was used to discover the mistakes that the next version of the model needed to learn from. ([arXiv](https://arxiv.org/abs/2007.00808))\n\nThat creates an interesting feedback loop:\n\n```\ntrain model\n    |\n    v\nmodel retrieves difficult documents\n    |\n    v\nuse those as negatives\n    |\n    v\ntrain model again\n    |\n    v\nmodel discovers new difficult documents\n```\n\nHard negative mining is therefore partly a **data-generation strategy** and partly an **optimization strategy**.\n\nYou do not usually \"hard-negative mine an LLM\" in the same sense that you mine negatives for a classifier.\n\nThe technique is most useful when an LLM system has to **rank, retrieve, compare, or distinguish** things.\n\nConsider a typical RAG pipeline:\n\n```\nuser query\n    |\n    v\nembedding model\n    |\n    v\nvector database\n    |\n    v\ntop 20 passages\n    |\n    v\nreranker\n    |\n    v\ntop 5 passages\n    |\n    v\nLLM\n```\n\nThere are several places where hard negatives matter.\n\nYou train:\n\n``` php\nquery -> relevant passage\n```\n\nand contrast it against:\n\n``` php\nquery -> similar but irrelevant passage\n```\n\nThis teaches the embedding space to preserve the distinctions your application actually cares about.\n\nSuppose the retriever returns:\n\n```\n1. PostgreSQL deadlock troubleshooting\n2. PostgreSQL transaction rollback\n3. PostgreSQL isolation levels\n4. PostgreSQL connection pooling\n```\n\nA reranker needs to understand why #1 answers the query while #3 is merely related.\n\nThat makes #2 and #3 substantially more useful negatives than an article about Kubernetes.\n\nThe same pattern appears in:\n\n``` php\nquery -> document\nuser -> product\nquestion -> answer\nbug report -> solution\ncode change -> relevant documentation\n```\n\nWhenever the challenge is distinguishing nearby alternatives, hard negatives are valuable.\n\nThis is also why systems such as RocketQA explicitly incorporated denoised hard negatives alongside cross-batch negatives and data augmentation when training dense passage retrievers. ([ACL Anthology](https://aclanthology.org/2021.naacl-main.466/))\n\nThe simplest method is almost embarrassingly straightforward.\n\nTake your current model and ask:\n\n\"What documents does this model think are relevant?\"\n\nSuppose your training example is:\n\n```\nq  = \"How do I configure PostgreSQL connection pooling?\"\nd+ = \"PgBouncer configuration guide\"\n```\n\nRun the query through your retriever.\n\nIt produces:\n\n```\n1. PgBouncer configuration guide       0.91\n2. PostgreSQL connection pooling       0.89\n3. PostgreSQL connection management    0.87\n4. PostgreSQL authentication           0.71\n5. PostgreSQL installation             0.62\n```\n\nAfter removing the known positive, candidates #2 and #3 are excellent places to look for hard negatives.\n\nA basic mining procedure is:\n\n```\nfor each (q, d+):\n\n    candidates = retrieve(q, corpus, top_k=100)\n\n    candidates = remove(candidates, d+)\n\n    hard_negatives = top candidates\n```\n\nBut there is a major trap.\n\nA document can be highly similar because it is actually relevant.\n\nThat gives you a **false negative**.\n\nFor example:\n\n```\nQuery:\n\"How do I rotate an AWS access key?\"\n\nPositive:\n\"Rotating IAM access keys\"\n\nCandidate:\n\"IAM access key security best practices\"\n```\n\nYou might classify the candidate as irrelevant simply because it does not contain the exact answer.\n\nBut it may still be legitimately useful.\n\nTraining the model to push it away could damage the retrieval space.\n\nThis is one of the reasons RocketQA introduced **denoising** for hard negatives rather than simply taking the nearest documents blindly. Later work on dense retrieval has continued to treat false-negative removal as an important part of hard-negative construction. ([ACL Anthology](https://aclanthology.org/2021.naacl-main.466/))\n\nA practical production pipeline therefore looks more like:\n\n```\nBM25 / embedding retrieval\n          |\n          v\n    100 candidates\n          |\n          v\nremove known positives\n          |\n          v\ncross-encoder / LLM judge\n          |\n          v\nremove probable false negatives\n          |\n          v\n     hard negatives\n```\n\nThis is considerably more useful than simply selecting the nearest vectors.\n\nConsider a simple contrastive objective.\n\nFor query `q`, positive `d+`, and negatives `d1 ... dn`:\n\n```\nL = -log(\n      exp(sim(q,d+) / T)\n      --------------------------------\n      exp(sim(q,d+) / T) +\n      sum_i exp(sim(q,di) / T)\n    )\n```\n\nwhere:\n\n```\nsim(q,d) = similarity between query and document\nT        = temperature\n```\n\nYou do not need to memorize the equation.\n\nThink of it as a competition.\n\nThe model gets rewarded when the positive takes most of the probability mass.\n\nSuppose:\n\n```\npositive = 0.90\nnegative A = 0.20\nnegative B = 0.10\nnegative C = 0.05\n```\n\nThe positive is already winning comfortably.\n\nNow consider:\n\n```\npositive = 0.90\nnegative A = 0.87\nnegative B = 0.25\nnegative C = 0.10\n```\n\nNegative A is creating a much larger training signal.\n\nThe model must figure out:\n\n\"What feature distinguishes these two things?\"\n\nThat is exactly the behavior we want.\n\nThere is a useful geometric interpretation.\n\nImagine the embedding space as a map:\n\n```\n                       unrelated\n                          *\n                    *\n              *             *\n\n        positive *\n                  \\\n\n                   * hard negative\n```\n\nEasy negatives teach the model about broad regions.\n\nHard negatives teach it about the **decision boundary**.\n\nThat distinction becomes especially important as the model gets better.\n\nEarly in training:\n\n``` php\neasy negatives -> useful\n```\n\nLater:\n\n``` php\neasy negatives -> mostly redundant\nhard negatives -> increasingly valuable\n```\n\nThis is the same basic intuition behind ANCE's dynamic mining: use the evolving model to find examples near its current retrieval boundary. ([arXiv](https://arxiv.org/abs/2007.00808))\n\nHard negative mining costs compute.\n\n```\n1,000,000 training queries\n```\n\nand you want:\n\n```\n20 hard negatives / query\n```\n\nYou now have roughly:\n\n```\n20,000,000 candidate relationships\n```\n\nThe expensive part is often not training itself.\n\nIt is **finding and validating those negatives**.\n\nThere are several ways to control the cost.\n\nUse BM25 or an existing embedding model to retrieve:\n\n```\ntop 100\n```\n\nThen only send a small candidate set to a more expensive judge.\n\nYou do not need an LLM to examine one million documents per query.\n\nYou also rarely need to regenerate the negatives after every optimization step.\n\n``` php\ntrain\n -> mine\n -> train\n -> mine\n -> train\n```\n\nrather than:\n\n``` php\ntrain\n -> mine\n -> train\n -> mine\n -> train\n -> mine\n```\n\nANCE is an interesting example of this engineering compromise: it uses an asynchronously refreshed approximate-nearest-neighbor index instead of rebuilding everything synchronously after every parameter update. ([arXiv](https://arxiv.org/abs/2007.00808))\n\nSuppose an expensive cross-encoder can score a candidate at:\n\n```\n0.97 relevant\n0.84 relevant\n0.31 relevant\n0.02 relevant\n```\n\nThe useful region may be around:\n\n```\n0.4 - 0.8\n```\n\nThe 0.02 example teaches almost nothing.\n\nThe 0.97 example may actually be another positive.\n\nThe middle examples are where the information density is.\n\nSo the goal is not:\n\n\"Find the hardest possible negative.\"\n\nIt is:\n\n**Find negatives that are difficult enough to produce useful learning without becoming mislabeled positives.**\n\nThat is a much better engineering objective.\n\nSuppose you are building a retrieval system for a company's internal engineering documentation.\n\nYou have:\n\n```\n10,000 queries\n50,000 documents\n```\n\nStart with ordinary positive examples:\n\n```\n(query, relevant_document)\n```\n\nThen:\n\n**Step 1: Retrieve candidates**\n\nFor every query:\n\n```\ntop 50 using BM25\ntop 50 using embeddings\n```\n\nUnion them.\n\n**Step 2: Remove obvious positives**\n\nRemove the labeled document and documents known to answer the same question.\n\n**Step 3: Score candidates**\n\nUse a cross-encoder or sufficiently capable LLM judge.\n\nAsk something like:\n\n```\nGiven the query and document,\ndoes this document directly answer the query?\n\nReturn:\nRELEVANT\nIRRELEVANT\n```\n\n**Step 4: Keep the confusing ones**\n\nConstruct something like:\n\n```\npositive:\n\"How to rotate PostgreSQL credentials\"\n\nhard negative:\n\"How to rotate PostgreSQL TLS certificates\"\n\nhard negative:\n\"How to reset PostgreSQL passwords\"\n\neasy negative:\n\"How to install PostgreSQL\"\n```\n\n**Step 5: Train**\n\nUse the positive and selected negatives in your contrastive objective.\n\n**Step 6: Re-mine**\n\nAfter the model improves, ask it again what it gets confused by.\n\nThe old hard negatives may become easy.\n\nNew hard negatives will emerge.\n\nThat gives you a virtuous cycle:\n\n``` php\nbetter model\n    ->\nbetter mistakes\n    ->\nbetter training data\n    ->\nbetter model\n```\n\nAnd that is the deeper lesson of hard negative mining.\n\nYou are not merely collecting more examples.\n\nYou are collecting **the examples that expose the current limits of the model**.\n\nFor LLM systems, that can be more valuable than adding another 10 million random training examples.\n\nThe interesting question is therefore:\n\n**When building your next RAG or retrieval system, would you rather collect more data—or deliberately collect the mistakes your current model is already making?**\n\nYour team's attention is limited, and the deluge of AI-generated code is making it harder to keep production reliable and secure without slowing you down.\n\nI'm building **LiveReview**, a blast-radius aware AI code review built for your business-critical systems.\n\nInstead of presenting every diff with equal emphasis, **LiveReview scores each change by blast radius — how far its impact reaches through your call graph — so you can focus attention where it actually matters.**\n\nSpend code review effort where business risk is highest — not spread evenly across every diff.\n\n⭐ Star it on GitHub: \n\nLiveReview is an AI code reviewer that scores every hunk of a diff by **blast radius**: how far a change reaches through your call graph, how much persistent state it touches, and how well-tested it is. A 3-line change to a shared auth check can outrank a 300-line UI tweak. Your team's attention goes to the highest-risk code first, not spread evenly across every diff.\n\n*LiveReview's Blast Radius & Review Priority scoring, live in the diff viewer.*\n\n| The exact math, not a black box | Visualize blast radius at a glance | Every factor that feeds the score | \n|---|---|---|\n\n**Here's the goal:**\n\n**Click below to try LiveReview with your codebase:**", "url": "https://wpnews.pro/news/hard-negative-mining-teaching-an-llm-what-almost-right-looks-like", "canonical_source": "https://dev.to/shrsv/hard-negative-mining-teaching-an-llm-what-almost-right-looks-like-37k8", "published_at": "2026-09-27 19:48:07+00:00", "updated_at": "2026-09-27 20:31:08.231975+00:00", "lang": "en", "topics": ["machine-learning", "natural-language-processing", "ai-research", "large-language-models"], "entities": ["Shrijith Venkatramana", "LiveReview", "HexmosTech", "FaceNet", "Florian Schroff", "Dmitry Kalenichenko", "James Philbin", "ANCE"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/hard-negative-mining-teaching-an-llm-what-almost-right-looks-like", "markdown": "https://wpnews.pro/news/hard-negative-mining-teaching-an-llm-what-almost-right-looks-like.md", "text": "https://wpnews.pro/news/hard-negative-mining-teaching-an-llm-what-almost-right-looks-like.txt", "jsonld": "https://wpnews.pro/news/hard-negative-mining-teaching-an-llm-what-almost-right-looks-like.jsonld"}}