{"data":{"nucesLogo":{"totalCount":1,"nodes":[{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFGElEQVQ4y2VVCUxUVxR9gJa61bZqbJuKpaVWbWu1GGmiNXWpsTbEmmpt1JqotY0aqyGNdrfBulaJorINwwwDssg2wDAIFGVABGb5MzArzMAIE9GgNi6xRv7nnd4/I5i0P/mZl/f+Pe/ce8+5w8ZlCmz4iVQIEcPrCZlC1KgM867wdHN2RLq5/hmFpflZhUXNUk376HfGSFC6OeI9jT24fCbDMrLNKCAEds44jaWZM1ma6R5TuxB802yIutCJaUU+hGk8oEsejc6w5BPwrGBMqin8ZXX7UzDaCII9l2VdOjbTcjNW34fxKhtoX1xf4xO/bfBLKyo80k8tAXFRmVtkZ4xgKvki072wdPMXISJt4bNznbRICYGxs8ZlxEyK1XrxodY9uK+5b2hhmZu/S++qGh9foOviay718PmlLh5zvoOvqfYOTsmxgynbQUw3hogZw9kTsKkvqKwDb1Ba+68GxC31PYgucPB9LQGecMHB1QY/flUL2JPXjs+ruvjWpl6+jb5ZrfeKL2o6QGV6FJlheftpymmmrImFPqzUdQ6est1AXLmHJ9b6eOLxRvx+zABD8zUUlLmQdK4Vh/9sRJK+i0cXOvhB03XMLLAPTivuxgSloAt1UynMoFo9nKppJ3Z9fFaxk/9Y7sZhAjIS+H8fwT2AxCMNSK71Yg6lv6exlydc6eUv5VL6yW2LGOW/nWXa8Wa+XdxLBxvqe3hWtoAW080ggPvuHbQMBPCPOIQhSQruefvuIi/Phm1U29fy7JxIiXKTSGaJcrr5kTkefFbtFcOVAj9U5YFO64OuvwWbdBvg6T6Nv6xfY/BxIAjGnzC93OjHaV0nRqus/NOqLmnCeY+simpGbb/MsuxYUOKSphc5+QG1GbX6Xpzu0mOrdjoCZXGwlc6H5+p+PPrbgluBq0HAptZepJc4EUv1XnvROzRW45Bl1C4DXhmlcmDdRa8UT+n+nGVBUbkzGPRHyy6sP7kOdxy/ofbCbjzoTIC+YGfwzGwLILmgAyso7aOWfmmcxikzJKukmQsn5sly6RPXks5+0bqQmmkMBj0Y8GO3Mh2Vlp2oK49Dn+EdFKj2Bs/S1UZ8T5fHkT6/quuWxuW4ESFny1KM383W9mBekVNcTPQ3Vnv5mZRW+PvvhoolAvcf3oOqKAlnVcdQ39iM2/clHDzagO0VHr6a5LW3qVd8S+sHefkwG6MQ5hBViYCRZL3BVxKgpi2AQ6TB9q5b/5NN/+3HOJvWhhOlTnyk9/Ijpus8ttg5xFIFjFFYlge1SGYvGJXbidmFjkGSAF4nlxwpc/JDRw3IzLGiss6LFnMvqmo7cSq5GafLXPxjEndciQsxeR0iUzpkyTSPGGWsQoihDj1gGQLmF7vEpRUezNN6+Cay2YFCOxKON+Fkrg3JlR7sqPHyybkdfMslP+RmUHZgCgE0rT4Ytl3I0CmmL6ecd2J5lQ87DNcGdzT4ZZFjCZXgfarVZsM1/kq+ncdf9OEH8viyCo8Yk0/uyHbL7PaEsMzhLF7bw1hyawj0VOuGqNz2h9El3ZhEgv1E1yl+c9kvba7rHlqi9UjPKwWJ2Ivxeu/Q3IoevJrbIUtld2jAtIVNUlpDJGfmORg70RwCTW6dSx9VUl05UzgRU9qNaJpCkdkkXBVpLUuegxbQdDIQgcXBmBNXwsYPT/7IJ2N7VXmXPK1H/gJIArEEemyy2lpB4rfRJVbSWQ1N6iTy/8KRBpwzhkdpQtOazti/toi+fZ6LUBwAAAAASUVORK5CYII=","aspectRatio":1,"src":"/static/69feb01fbcc4fcdda65890a8ce987c97/704a2/nuces.png","srcSet":"/static/69feb01fbcc4fcdda65890a8ce987c97/630fb/nuces.png 300w,\n/static/69feb01fbcc4fcdda65890a8ce987c97/704a2/nuces.png 315w","sizes":"(max-width: 315px) 100vw, 315px"}},"name":"nuces"}]},"slides":{"totalCount":5,"nodes":[{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHZh1hqoTlwCuwGf//EABsQAAICAwEAAAAAAAAAAAAAAAECAAMQERIT/9oACAEBAAEFAnblGssOFPQVQBuVE+RZtz//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAaEAACAwEBAAAAAAAAAAAAAAABEQAQIiFh/9oACAEBAAY/AmnGM+UYFQ7Bo1//xAAdEAADAAAHAAAAAAAAAAAAAAAAAREQITFBUWFx/9oACAEBAAE/IaitGyGayWCanqFUtVqZ2KKrBaGpyI//2gAMAwEAAgADAAAAEDsPPv/EABcRAAMBAAAAAAAAAAAAAAAAAAEQQRH/2gAIAQMBAT8QGVRf/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxBmX//EABwQAQADAAMBAQAAAAAAAAAAAAEAESExQVFxwf/aAAgBAQABPxC+1ptTrF1HQECvu971Eb4YL6ayjj39gUCSNb+wJi49ghaDd7DoIjB+xKNq7P/Z","aspectRatio":1.1320754716981132,"src":"/static/e901c61353f0fd199e591f2e4832bac0/47498/FB_IMG_1515092551888.jpg","srcSet":"/static/e901c61353f0fd199e591f2e4832bac0/9dc27/FB_IMG_1515092551888.jpg 300w,\n/static/e901c61353f0fd199e591f2e4832bac0/4fe8c/FB_IMG_1515092551888.jpg 600w,\n/static/e901c61353f0fd199e591f2e4832bac0/47498/FB_IMG_1515092551888.jpg 1200w,\n/static/e901c61353f0fd199e591f2e4832bac0/ac53a/FB_IMG_1515092551888.jpg 1360w","sizes":"(max-width: 1200px) 100vw, 1200px"}}},{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQDBf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAAB6mGUTVOQi6QzrIJ//8QAHhAAAgIABwAAAAAAAAAAAAAAAQMAAgQQERIhMTL/2gAIAQEAAQUCr4ey1Fg6ireMQ/dBcjJnc//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABwQAAIBBQEAAAAAAAAAAAAAAAABEgIRICFxQf/aAAgBAQAGPwJEqbPojwin008P/8QAGxABAAIDAQEAAAAAAAAAAAAAAQARITFBcYH/2gAIAQEAAT8hxe6KmzA1DKSlNRKgoIlPmQ+lCGArE0PYd9n/2gAMAwEAAgADAAAAEHAXA//EABcRAQADAAAAAAAAAAAAAAAAABABQWH/2gAIAQMBAT8QjSj/xAAXEQADAQAAAAAAAAAAAAAAAAABEDFh/9oACAECAQE/EDiFX//EABsQAQEBAQEAAwAAAAAAAAAAAAERADEhQWHB/9oACAEBAAE/EK8SG+XAqvAgCfWkXhQ2OOVoODjjQFQZyQ/ckIng4jgJ7MRQFPr8uJfJn//Z","aspectRatio":1.1320754716981132,"src":"/static/150eac7073652be0a042d63ab07aedbf/47498/FB_IMG_1550250911592.jpg","srcSet":"/static/150eac7073652be0a042d63ab07aedbf/9dc27/FB_IMG_1550250911592.jpg 300w,\n/static/150eac7073652be0a042d63ab07aedbf/4fe8c/FB_IMG_1550250911592.jpg 600w,\n/static/150eac7073652be0a042d63ab07aedbf/47498/FB_IMG_1550250911592.jpg 1200w,\n/static/150eac7073652be0a042d63ab07aedbf/ac53a/FB_IMG_1550250911592.jpg 1360w","sizes":"(max-width: 1200px) 100vw, 1200px"}}},{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAGQABAAMBAQAAAAAAAAAAAAAAAAMEBQEC/8QAFwEAAwEAAAAAAAAAAAAAAAAAAQIDAP/aAAwDAQACEAMQAAABqerEapK6wwZg21QY/wD/xAAbEAADAAIDAAAAAAAAAAAAAAAAAQIDERIhM//aAAgBAQABBQKcI9RXFCaL06juSGYfP//EABcRAQADAAAAAAAAAAAAAAAAAAERIDH/2gAIAQMBAT8BJdp//8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHRAAAgEEAwAAAAAAAAAAAAAAAAEQAhESITFhcf/aAAgBAQAGPwLYljeORdTV4I//xAAdEAEAAgEFAQAAAAAAAAAAAAABABEQITFBUWGR/9oACAEBAAE/IQotCJduSeUPuPs0g32jrcIFFwX/2gAMAwEAAgADAAAAELjoPf/EABgRAQEBAQEAAAAAAAAAAAAAAAEAMRFB/9oACAEDAQE/EGkens5O3//EABgRAAMBAQAAAAAAAAAAAAAAAAABETEQ/9oACAECAQE/ELcIxbz/xAAcEAEBAQACAwEAAAAAAAAAAAABEQAhMWFxsdH/2gAIAQEAAT8QYlaYodFQJWdaHE4I4fruAK5R5/NZ22/XAXrFYimDk9r1v//Z","aspectRatio":1.1320754716981132,"src":"/static/4ba8c3df1d34c8fe14a6f05c4bacbf67/47498/FB_IMG_1552064209043.jpg","srcSet":"/static/4ba8c3df1d34c8fe14a6f05c4bacbf67/9dc27/FB_IMG_1552064209043.jpg 300w,\n/static/4ba8c3df1d34c8fe14a6f05c4bacbf67/4fe8c/FB_IMG_1552064209043.jpg 600w,\n/static/4ba8c3df1d34c8fe14a6f05c4bacbf67/47498/FB_IMG_1552064209043.jpg 1200w,\n/static/4ba8c3df1d34c8fe14a6f05c4bacbf67/ac53a/FB_IMG_1552064209043.jpg 1360w","sizes":"(max-width: 1200px) 100vw, 1200px"}}},{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAGQABAQADAQAAAAAAAAAAAAAAAAQBAgUG/8QAFwEBAQEBAAAAAAAAAAAAAAAAAQACA//aAAwDAQACEAMQAAAB6s2YxpCVaFefGO3/xAAbEAEAAwADAQAAAAAAAAAAAAACAAEDERIxM//aAAgBAQABBQK65QVOPK0k7RB1OvcS/Km31//EABYRAAMAAAAAAAAAAAAAAAAAAAAQEv/aAAgBAwEBPwEh/wD/xAAXEQADAQAAAAAAAAAAAAAAAAAAARAS/9oACAECAQE/ATbv/8QAHRAAAgIBBQAAAAAAAAAAAAAAAAECESEQEjFBUf/aAAgBAQAGPwIlhqi91DcPKSL6fOTMtWf/xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhQTFRsaH/2gAIAQEAAT8h2SQjIOqWJDQ6hVWth3BD5tUpxlMOZ4TmT7X2f//aAAwDAQACAAMAAAAQwNDC/8QAGREAAwADAAAAAAAAAAAAAAAAAAERECEx/9oACAEDAQE/EGo4yHuYXD//xAAYEQADAQEAAAAAAAAAAAAAAAABESEAEP/aAAgBAgEBPxAUMZEff//EAB0QAQADAQACAwAAAAAAAAAAAAEAESExUWGhwdH/2gAIAQEAAT8QwkwXjVxkev3eXKuQK14Pc0MOAVbt3zY9wWQsJXalMM7ljSEQu6nwn6iSlT9k/9k=","aspectRatio":1.1320754716981132,"src":"/static/cc7b134a5b5ab3b16314d53bb56a79e9/47498/IMG-20191123-WA0027.jpg","srcSet":"/static/cc7b134a5b5ab3b16314d53bb56a79e9/9dc27/IMG-20191123-WA0027.jpg 300w,\n/static/cc7b134a5b5ab3b16314d53bb56a79e9/4fe8c/IMG-20191123-WA0027.jpg 600w,\n/static/cc7b134a5b5ab3b16314d53bb56a79e9/47498/IMG-20191123-WA0027.jpg 1200w,\n/static/cc7b134a5b5ab3b16314d53bb56a79e9/ac53a/IMG-20191123-WA0027.jpg 1360w","sizes":"(max-width: 1200px) 100vw, 1200px"}}},{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAGQABAQADAQAAAAAAAAAAAAAAAAMBAgUE/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgAB/9oADAMBAAIQAxAAAAGULec700WnoZAthX//xAAZEAACAwEAAAAAAAAAAAAAAAAAAgEREgP/2gAIAQEAAQUCd9zqRetRCPhUe8sXJZZ//8QAFhEAAwAAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/ASP/xAAWEQADAAAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8BK//EAB0QAAEEAgMAAAAAAAAAAAAAAAABAhEhIjEQMpH/2gAIAQEABj8ClKNkUOwU6O8FxN8//8QAGxAAAgMBAQEAAAAAAAAAAAAAAAERITFRYXH/2gAIAQEAAT8hcx1OCdjkDCtWxBDl+G+BT2bVHoE06yXWf//aAAwDAQACAAMAAAAQPzdD/8QAGBEBAAMBAAAAAAAAAAAAAAAAAQAQETH/2gAIAQMBAT8Q1MCJXl//xAAZEQEAAgMAAAAAAAAAAAAAAAABABEQITH/2gAIAQIBAT8QobWGnc//xAAdEAEAAgIDAQEAAAAAAAAAAAABABEhMUFRsWGh/9oACAEBAAE/ECig0jafv7EeHu11KQwexC7XdZ1xDquUbWIG8RblyS4L2dyz9phPaf/Z","aspectRatio":1.1320754716981132,"src":"/static/3f08cf65322c8c251b8549e8d3d4f311/47498/nuces.jpg","srcSet":"/static/3f08cf65322c8c251b8549e8d3d4f311/9dc27/nuces.jpg 300w,\n/static/3f08cf65322c8c251b8549e8d3d4f311/4fe8c/nuces.jpg 600w,\n/static/3f08cf65322c8c251b8549e8d3d4f311/47498/nuces.jpg 1200w,\n/static/3f08cf65322c8c251b8549e8d3d4f311/ac53a/nuces.jpg 1360w","sizes":"(max-width: 1200px) 100vw, 1200px"}}}]},"site":{"siteMetadata":{"title":"M.Hassan Ahmed","description":"AI engineer and full-stack builder. LLM agents, RAG systems, and production ML.","social":{"fiverr":"https://www.fiverr.com/hassanahmed19","freelancer":"https://www.freelancer.com/u/hassan11196"}}},"allMarkdownRemark":{"edges":[{"node":{"excerpt":"You have eight cache nodes, and you spread keys across them with . It works: reads are fast, load is even, everyone is happy. Then traffic…","fields":{"slug":"/2026-09-29-consistent-hashing-sharding-without-reshuffle/"},"frontmatter":{"date":"2026-09-29T00:00:00.000Z","title":"Consistent Hashing: Sharding Without the Reshuffle","description":"Add a cache node with plain modulo hashing and almost every key moves. Consistent hashing moves only one arc. How the hash ring and virtual nodes work.","tags":["Distributed Systems","Caching","Computer Science","DevOps","Scaling"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACRElEQVQozz2RSWsUQRSAGySTpZfpfd+me3qp3tfpmcxMDwOJyYQkM1k0RgzizYt4DAS8iiB4UvCUi4qXHLx49uy/sqIgfHw8XtXjvVeFAFcNXDX0Na8vDWvQjtPJKJ5uJ7NJ1o6zeVvATLudjpsQejbOqtz1HTnwVAjSIYwOoXdwfaPbU/u1HU4sMIbuR1M3bkE2N/2RE7c9sG2HU4hs1RukBe9DEIzWCNZCWZvgHU4LaRkQgovzziZtYYyFUjrB2RhrU6LDyfcIqkeJLsH1YRWCkhopAkXPJC0F5W45PgTpXLUqWUtYJcZZm1ZiUopMryqaWT6AtIKRUkpMSQBZIxRHT25mizezxcvhzvV0/9Pe8u384Lpd7EWjB11D0HOpVwtmxRk1pQ0odUBrA8YYkGKArOGyZyafD06/HZ3/vrz6efrk16Ond8vHd6uLZ9UMITRWLUWrkaym59dZnsdpDh2lJasAZIuQGSl4t3v8/ej8x8nFl8Ozr0dnV83O+93lRTFFUK1IAxCXtDYsq/TVpfnixIJ+vrJV00U2CQnu/Hqy//Hh8e3B6sPO4e1iddPuw7GX6RjB9CgM+6DgjEowS1qtKbVm9Jq/Hxt2xkVC8DEpCvtV7DWVPyr8YeU1qpZ0xQCndZSPGSWM4jDPw7II6ipw/ICUY1LwkU1cgJ9Bij4tAV5PRCOVjIxTIlIO4HvijEnLAYTXIsGIRSOWzIRRQFf0cM5GNjD+H+so19liIWtb7DrGY6SCkjL030D5fwqB8d8S7g9uB2ycZjzc+QAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2c0ce2e88edfe52b5e0b160cc8fdb467/40a76/hero.png","srcSet":"/static/2c0ce2e88edfe52b5e0b160cc8fdb467/c972b/hero.png 340w,\n/static/2c0ce2e88edfe52b5e0b160cc8fdb467/27625/hero.png 680w,\n/static/2c0ce2e88edfe52b5e0b160cc8fdb467/40a76/hero.png 1360w,\n/static/2c0ce2e88edfe52b5e0b160cc8fdb467/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"At some point the model does not fit. You try to load a 70B-parameter checkpoint onto a single 80GB card. The weights alone want around…","fields":{"slug":"/2026-09-28-tensor-vs-pipeline-parallelism-llm/"},"frontmatter":{"date":"2026-09-28T00:00:00.000Z","title":"Splitting an LLM Across GPUs: Tensor vs Pipeline","description":"A model too big for one GPU has to be split. How tensor and pipeline parallelism divide an LLM, what each costs, and when to reach for which.","tags":["LLM","GPU","Inference","HPC","DevOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB8UlEQVQozy1Ra5OaMBTlU8szCbo8DIEECBhBrYovkHVqt7t1q9ap0///WxrUmTOZe2/OOZOcqzDaPhCzdjG/bNa3xfzc1P/ms0u1+CPbqrrKYr36O5udl9VVcqKweUgUFeIHoJsko5WY7fh4U1b7bLLNxpti/pqNt3IymrWyHX5r8kkNnPghUUw7Mnu0g011GKkg1GCoo8iQLYruxbOW8w4gfPJ7VDFQCNwMeDnhiyhfJkVNxQr6ueWk0tdARJoCN0cDIW+ZWCdlHeaV5XJJUHRIoJtjsqasTdPvcbqPk31Im4BsdEQ0gOWJ/BEJaxa3PD3cCa8R3fl4oRiQWG4m+FGknyI58vgnZ29ldi74yXqhfT+3PY680SS/ZvH7KP3krCNMxS1lB8UAgeXwNHljdI+DDSabAV4m8SFL36HDMJu6pICeGPJjENYB2QZk7eMqTz8o3SnyYcDJpM14eJ6Xt3J4mopLkf3m7IeGMHJiHQXIEyL9NRbneXEr89O4I5wiUiua5cs/Q18QLsNoqWhItoYDYTpcA4MvutO5u0NJiPJtUrRMNAFfAW/YBaZZ3j1SuRUiYdih1WfgJQb92ESBAbGJyLPtUXmro1Bm/FiEopruV8ORUE1HNRzNdE07MBE2kJQFHWzyLBDWLFe9MzuJ6fwHDq9T9VH8IXwAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/91cf0860c00031917c8d46f337d29dee/40a76/hero.png","srcSet":"/static/91cf0860c00031917c8d46f337d29dee/c972b/hero.png 340w,\n/static/91cf0860c00031917c8d46f337d29dee/27625/hero.png 680w,\n/static/91cf0860c00031917c8d46f337d29dee/40a76/hero.png 1360w,\n/static/91cf0860c00031917c8d46f337d29dee/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"At some point while running LLM agents you hit an error that reads . You go looking for a bigger window and find a config knob named , or a…","fields":{"slug":"/2026-09-27-rope-position-embeddings-context-length/"},"frontmatter":{"date":"2026-09-27T00:00:00.000Z","title":"RoPE: How LLMs Encode Position and Extend Context","description":"How rotary position embeddings encode token order by rotating query and key vectors, and how position interpolation and YaRN stretch a model's context window.","tags":["LLM","Transformers","AI","GPU","Inference"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4UlEQVQozz2P226bQBCGURUblmVZdmEBm6PBgKE+KnYt22DnohdVlKSOFaXqA/SqUtWrPH8Ho1r6NJr55yyxYm9VTfVwyevv4/1z0ZzL02W8e8oOz6C0/v4pr18mp9fJ8ZxedbNsWHHgk4Ok6kOse58Xh9mqAQtMl01Rbav5fr46zpZNVn6p5qDXk+luuqizcgP1XZeEeYR5qFBfZZHKY2yEKsDCNmQhMgKwmMdt2PoRKLhVgEjC1MdGC1IYIa5sBH3dw0aAYBzUXUEKx9iGBlio/ReBdnM72wjE6Wf6+KseL3OvkKln2okOKeoT6jn1W/T+wZMNYXBaAGKHhM1YE6l/+SsOF93JLDPapYv7eMbEyLBihMz49Y/38pumazIsCY91u1Cp1yEpfSp2Z+f4LksyIm6PDCTVadKFa43uetSaPgQ/PvqSrFkj4uZIE7qVET5CZAAvSIrC7fpNc4s7ZHLDi0TkMr/y8jKserIh1t/48mv/E8Zurg0KGZlwrQbNuov0gQQzFCyw4aWT+2q6zfJVnM7hBIW4qn5N8YBnW5au2XjD4iWxU6Q5UABAM3gOpkNuJ8xJDHhVxJ3YoTGf2gkVI2rFhp0QM0Sa3aUkRbM7+qp14yYCMhayarXgzopb6h9fyUchAON0IQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/a41f34b118fd6bd6384dbfccfd2c22a3/40a76/hero.png","srcSet":"/static/a41f34b118fd6bd6384dbfccfd2c22a3/c972b/hero.png 340w,\n/static/a41f34b118fd6bd6384dbfccfd2c22a3/27625/hero.png 680w,\n/static/a41f34b118fd6bd6384dbfccfd2c22a3/40a76/hero.png 1360w,\n/static/a41f34b118fd6bd6384dbfccfd2c22a3/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"How many distinct things are in this stream? Distinct users today, distinct error signatures this hour, distinct workflow IDs that touched a…","fields":{"slug":"/2026-09-26-hyperloglog-count-distinct-at-scale/"},"frontmatter":{"date":"2026-09-26T00:00:00.000Z","title":"HyperLogLog: Count Distinct at Scale in 12KB","description":"Counting unique items exactly costs memory that grows with your data. HyperLogLog estimates the cardinality of billions in about 12KB. Here's how it works.","tags":["Algorithms","OpenSearch","Observability","Redis","Data Structures"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB7ElEQVQoz12RyZKbMBCGOWbACCSBEBZm38xuYxvHYI+XmZrjpHLP+79GGjunVP3V1VL3V7+6JeG8BqG0cPpjfn1E4yV/fyTTNTpdvMMpe7/DMThO2flW3D79YURJAf36k5Jk1ZFVgbDvRduyOVfdpWwveXlK8yHODutqLJpzlO7zaoRqEO90GsoLAZSCVtKCBsiMNStRjUghoUJDhQSIxZhniCWzzBhKMgnedA+qGoNjCJRCXAmxlIoG26Vm5U+tEcssr3WzwXQ7w2ksbwMNzGncaC/8rWakmplrLFN0B+BE52sqqhcMOQh41YT7wnRbnuyIqKxm8O8f7vVuTRMtd8hIZA1gM8F2QZbVi4QIJCTM39jpniVbErYaz42fJ/b7y/r1Jf58s+mMcCTrYoZ1u6CifjnDE0Q6pP3N7yYr7TW3xH6t2Wte7OPr52o38e6IoxYZsYyWkmrGeFnSZU3tigdbHvdG2FG/NsOO57OzlfV4VbFVG9XTMtjq88A5WL4hPjuDIS8Oznhjh5PRH58a+HH07g/3evMeH0a2tb2NE+/ndViZBtGM31TrNXPJvE4Xpb4sDbclqwbegkVNIRE1cWoi6n+LhNFgL7yYnVUmKdhVaaASXyXBf9JZQniGwQq+mvpzGw1fcYHdHwv2F7XYUxz50t48AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/d8c408d0f784bb15fc0ce20a2f9339e1/40a76/hero.png","srcSet":"/static/d8c408d0f784bb15fc0ce20a2f9339e1/c972b/hero.png 340w,\n/static/d8c408d0f784bb15fc0ce20a2f9339e1/27625/hero.png 680w,\n/static/d8c408d0f784bb15fc0ce20a2f9339e1/40a76/hero.png 1360w,\n/static/d8c408d0f784bb15fc0ce20a2f9339e1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The math everyone does first is the one that gets them in trouble. An 8-billion-parameter model in fp16 is sixteen gigabytes of weights. You…","fields":{"slug":"/2026-09-25-gpu-memory-serve-llm/"},"frontmatter":{"date":"2026-09-25T00:00:00.000Z","title":"How Much GPU Memory to Serve an LLM","description":"Pick a GPU for an LLM and it 'fits' on paper, then OOMs under load. A quick way to estimate the VRAM a model needs: weights, KV cache, and overhead.","tags":["AI","LLM","GPU","Inference","DevOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3klEQVQoz22PSW/bMBSEdWusjaJIidpILbYsa7VsWbLlJHbaBG5SxGh77qH//1/0yQ16KvBhMCDfcB4lzEfACPY0Ohb7n3n/Peuu6eYdTLJ+A5M0r8vt+3J7na+/FcMPuMX8cGOUZOQryAelTlq293V3Ssshb8ZifcwbYMyqQ7V5AAXa/qloHywvU40AIpKCBYCdzOaV6WRgqF8YLFPMRCU3zHiGOCBjManBNRqr5pSSFIPLiPuLYbl+Spvzoj6DEdkBexUJGsrXyEphRjUj5ZacoQBQcAjA2rAAp6JlcQejhltq9gq5JRg36cLVqFtzBUcGH/zsmZdfRfXKiwuJRo2V058BFu3C/OTEgx12pl9Drek3TjLE5ROyU5Uukd+x+TGsnu3k6GcnzHf6FNY9gMW9yGHbk1idoJ8EtcVbdz6K/DOENbs0gp3uwnOHZftiRTvda6fwTHdl5JnBxkqOJNxjMQCwFeY9PI+DnUZi2RBG0BMBBef6cPXSe+RvNVZJM82RNUbiR2N+cYq3+vHX5stvUAAvXkh60e1shnydVcitdadS6Ao5FaCSBYSZrDPsNVBi8o6GgxUNNOyp6HHQASqJ71QbxiZV2YfRJiOBm1CsO4UCn2Tyj78nHwP/4w+mY1Bmjk8PsAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/f0e6f8f9a0350d817628ba6769b60933/40a76/hero.png","srcSet":"/static/f0e6f8f9a0350d817628ba6769b60933/c972b/hero.png 340w,\n/static/f0e6f8f9a0350d817628ba6769b60933/27625/hero.png 680w,\n/static/f0e6f8f9a0350d817628ba6769b60933/40a76/hero.png 1360w,\n/static/f0e6f8f9a0350d817628ba6769b60933/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Every filter you type into a search box turns into a set of integers somewhere. Ask OpenSearch for documents where  and , and each clause…","fields":{"slug":"/2026-09-24-roaring-bitmaps-fast-filters/"},"frontmatter":{"date":"2026-09-24T00:00:00.000Z","title":"How Roaring Bitmaps Make Filters Fast","description":"Roaring bitmaps store integer sets in three container types so filters stay small and fast. How they work, why OpenSearch leans on them, and the tradeoffs.","tags":["OpenSearch","Search","Data Structures","RAG","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACCUlEQVQozzWPS27bMBCGtWgi60VRFk1REvWwXpZly3EsJ7FsJxGahYPGTtCk6GPXAF22B+i6J+gBuu0BesKOohb4QXwznG9ACnmwGYfb1Kvrk7vm/O22ul+f7puLx8vqYT3fbxcH6NTzu+3iHsqz6W7kr0HpIhzrjoicI4050Swt63hyEU9XRXU1Otkk5Qp4NN9AczTfwi1P50eaLequCJbuCpoZIjKE8yUtqP1Qwp78PxLiks4BFMNXMMRTDf8lgaCTqM9SO5gN3HHfSvssG/ACWNY5TIMDt7CxlbGHzCEMdAwRBtYkDOosuqbunDonb06fm/LD7eLzofryfvXt5+Pvrzc/fn3883z5HbOxyUsanBp2gUgiI1eAZcYgs1mpkwSReOidBW6VeCuA1F9vxw/L9LYpnorhldr9i0QA7aPaP+vcwH5gl5YZY+zLGqMk5vZY0Zii2a8kg5iRqBJJs2BaRo6sOS28sGAYYWYtFsPrkteumftkuk52u/JpxjfUTK6T/aH8tMvfpfZSRAyZoUFjBXOQJWQLGAdFcD5LN2Vce7RwSV5lzVn+OudLgqMyWlejZpk3AStF1cI0Is5Iwa0paUxAOmdm5jtTl+bEiCAuG3vOhJGsr4cOzbk98diEmnErIAec9vGtbAk9lYoqPZaJqAzEjpVBV/Y6VggE+j3N6qnWvxNKlf4FaQlS6xVSP4EAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/64f59be93a1aa438e69ee401c93c2449/40a76/hero.png","srcSet":"/static/64f59be93a1aa438e69ee401c93c2449/c972b/hero.png 340w,\n/static/64f59be93a1aa438e69ee401c93c2449/27625/hero.png 680w,\n/static/64f59be93a1aa438e69ee401c93c2449/40a76/hero.png 1360w,\n/static/64f59be93a1aa438e69ee401c93c2449/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"An operator pings me: “the request I sent around 14:05 came back with a 500, can you check?” I open the logs, and there are forty other…","fields":{"slug":"/2026-09-23-fastapi-correlation-id-logging/"},"frontmatter":{"date":"2026-09-23T00:00:00.000Z","title":"Correlation IDs in FastAPI Logs","description":"One async request scatters a dozen log lines through concurrent traffic. Thread a correlation ID through FastAPI with contextvars and trace it in OpenSearch.","tags":["FastAPI","Observability","OpenSearch","Python","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACJklEQVQozyWPSU/bUBSFvSKTE89+o5+fx3hIXjzFMSFAIAwFytSq3SGx6C/othK/vUZIR2dx7v2kcyREdoh+CuBtkt8X1asonkX5kovHXqJ4WayessV3UbyK8jUXT3F6139+IdJYxSMFDWdwolEvqeLlJhFdWmyj5SbM1qI5T4uTPvSzKszX8XLtzlcDBQym1lAB0kRjKpgrIJxZngKiWS87nBi+bAWy4Y1VNlKoZi0w3WHaQdxhcszcHYCtYZXSRHWg18arl2X3Hizu3XjPoj1gG4s2Kkj7XmOFGPYyDG7z/CEIrqLoRognn19Z1qaHmUmaYvV2d/hIkh+E793g2vEOmJ2ZqFaMeKRAWfMNvNJwToIGeaVs9gXnCoz7zVTHgiftotmSsLbcGvC1xSoVpzoUBB1klU81H7DWdAQOGhzUyK8grzSUSxOFWrQVq7eri3/z9KfjXfLwlvILSE8sXCNwjtG5YQmbNbZb8OTYy7Zu0kG/1nAm9ZNMXCWL38e7v378iNxT4u0xO7VpZ6KSwIOqJ7IWAFIBmjO/csMau8KEiQnn0niGTFKm2fNp9yeIbiHbEn5GeA+3Bix1Iz+STV2jnZdueFRRv3XDHDopoBlgn7DtbKr6/eHbR7b4xfxrP7qn/BI7ZzpYDmVzNIXjKdRVTFHIacadzCFzAkNNxdJQtqeGp6PUdoQG54oVKnbU+8wMJprTX790NLGPZHswBQMZfHmf/Ac+i1te6gdHzAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/fd1d62f8a9974fed0f894db38d842403/40a76/hero.png","srcSet":"/static/fd1d62f8a9974fed0f894db38d842403/c972b/hero.png 340w,\n/static/fd1d62f8a9974fed0f894db38d842403/27625/hero.png 680w,\n/static/fd1d62f8a9974fed0f894db38d842403/40a76/hero.png 1360w,\n/static/fd1d62f8a9974fed0f894db38d842403/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most LLM apps send every request to one model, usually the biggest one the budget allows, because that setup never embarrasses you in a demo…","fields":{"slug":"/2026-09-22-llm-model-routing-cut-cost/"},"frontmatter":{"date":"2026-09-22T00:00:00.000Z","title":"LLM Model Routing: Send Easy Prompts to Small Models","description":"Most prompts hitting an LLM app are simple. Route those to a small model and escalate only the hard ones to a large model to cut cost and keep quality.","tags":["LLM","AI","FastAPI","RAG","Cost"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3ElEQVQoz2WQ2Y7TQBBF/QBxvLb3dLvb7SW24zh2FmcxCQmZzIRBSCMhFqFB4oH//woq0wIekI5Kt8r3ltolzeIx0CR5xZLDfHXtD8fl+qE/nFab83onKrSXbX/qtiD62XwapSIlDRCXEYeqOBmf9PX6Pm+P0+6St6difkqmexDAZHkuF2eY03wDTpGSdJsDqhXpDh+aVDZC0IbDTTdB7q2aXoa8RLO5ZkWqxQwnhqFISTACTId7pEyKLspay09pVDZ117R9mtWr7pSNZ2BQUSTMmsWEkFTEAA9nXljm9RuXFLodKYgGrMJxQ+MpiSrCa9kEGwWnYlLFDEVKehndetg0RNT3eMGSz8vJl0XxbTX51BZPi/ornImnCopg78uPJCIlqbDGDHWLwWuRn7rB2HZjjBNGUkpuNefjinGOI9W+3QLzxiWlYhBISYpJBEMDA7KOXScMbOI7IQ2ijGUjj9oIQ6sYGPnjMF2ReG7jCo4nwegPsIwMdBKPWJflm8n0ut099rtDM1/n5SLNZC3waFutH5f7J1bubwdTjNFfVGM00IIwoN8vx58f7p+vd8/X84/3d78+Xg9t80rxHFKl9du8fcfLXkOhNNSD/xmo/mvV+4cC1RefZM0XgP4NWMtLbYMsY20AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/803406d105e34dff0c63b26210f7f8ab/40a76/hero.png","srcSet":"/static/803406d105e34dff0c63b26210f7f8ab/c972b/hero.png 340w,\n/static/803406d105e34dff0c63b26210f7f8ab/27625/hero.png 680w,\n/static/803406d105e34dff0c63b26210f7f8ab/40a76/hero.png 1360w,\n/static/803406d105e34dff0c63b26210f7f8ab/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The bill for a vector index is mostly RAM, and RAM is the resource you notice last and pay for first. A modern embedding model hands you a…","fields":{"slug":"/2026-09-21-binary-quantization-vector-search/"},"frontmatter":{"date":"2026-09-21T00:00:00.000Z","title":"Binary Quantization for Vector Search","description":"Float32 embeddings make a vector index expensive to keep in RAM. Binary quantization cuts them 32x; Hamming search plus rescoring keeps recall high.","tags":["RAG","VectorSearch","Embeddings","OpenSearch","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3ElEQVQozz2QW3ObMBSEeQugGwiEAAHCgLkZ2xg3ZuzUtdtkmsn//0M92J3MfA/L2V1JB4PUBwDXI6p26Xyvfn3ml3cgm3+vLh/V9TM/v5fXv839K3m92eWW1OMjv7QMRBObKMZzXzbrdt5N93ZzGfbXbrh0w1u//dlv3w7HP7vDbd2ePFkzN4c8tAADc424xl5O/RXmOWIZdnMQVJRMlFQU4JpUWU6KXE15vuTdbIFrwySxRRVyUpsq4uUk63Da8m6icU3DisG5WYvXe4QjxBJb1YhnyNOQBwxdjTLtTBzhpHabiRzO7PbhzXd8upL+SIZXMl3Y+xcpBhB0f6bnO9me4Di4zHCDwgkKi0bEX4XFkcctFrnUI096ofc82QBu2MjVxLPBizsnbrnqnbC2SGRwVbthiZjCLHFEZZPIQtLCEsNk2SWGuYkC2JY4KcwBRGNEFViGnzSuLC0S2kwhb9kH+/D/FuDzoTPi66f1f2Evsx0FjzWCrHNk8WILHORye/KHH14/ifXo9UexWbTfTovujmKcw2YKdie5m1law3MMEwdwrUUkYGLJgzyIKhGVUq0dLxNx5YdFEFeu0OA+kt9IKEMnePKCBJSjtIGm0h0XOnxomPjhCtzv5JN/DidGDyZRRRAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3c2717ac11b2d145c93f39416ca41a5a/40a76/hero.png","srcSet":"/static/3c2717ac11b2d145c93f39416ca41a5a/c972b/hero.png 340w,\n/static/3c2717ac11b2d145c93f39416ca41a5a/27625/hero.png 680w,\n/static/3c2717ac11b2d145c93f39416ca41a5a/40a76/hero.png 1360w,\n/static/3c2717ac11b2d145c93f39416ca41a5a/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time I looked at deploying a Mixture-of-Experts (MoE) model, the spec sheet confused me. Mixtral 8x7B is described as an 8×7B…","fields":{"slug":"/2026-09-20-mixture-of-experts-explained/"},"frontmatter":{"date":"2026-09-20T00:00:00.000Z","title":"Mixture of Experts: Sparse Compute, Dense VRAM","description":"Mixture of Experts routes each token to a couple of expert layers, so the model runs cheaper per token yet still needs every expert sitting in GPU memory.","tags":["AI","LLM","GPU","Inference","Machine Learning"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4ElEQVQoz0WQ227TQBCGjYDE9q69u453fVh7N7ZzdtLEdYmiqDmgVAIJlbY3CHGBhAQS4im4g2t4H654MCZxaaVPvzwz/z+2x5ioKVCqGehQjs/79WF52FTby/lmNV3vzvf7+iUolFfLq6pfg+fBb7RI2iZpy00wL1g8Fno2qffDapuX66xcDRfbUbUbzDfZZDVabIWauUEf+Tn4IWVgphrQEW3TtIVj0FOpbJLaVEEJmK6EjuN10f+IgcAHM5L6Qa/fq7JsVuRzx9OIJs2oATpeUHiiYKKgPAc/NA2bJA0s6As58o46dv3soQ9YroSAHl1EvcVgspTdmenE0IewRCR57oRa5H/eff37/tuP3Y1hcUwhJhsQkW2alvrsslc/9TLiw5shLA3bjQHTifLu2ffXH36+/fRlf2f7XQuHlhO1ndByIxuHLS+7vnj1+83HzfzA1dx2QkgZMGuAZU+QeOZpWxRcjvx4CAzUlPEcszTOqrDc36yvf91+ZlmNThHDgt0nIOxQid0IBsfPcSLEklhXTPTgSHCOWJVhWppU0o5CbgwRCAcNpKOJrwnvUp5hevxVFo19/YIEQ0Tijpd0OqnvK8E155owaTqBYWLxCHrU5iQ2idBxUdzG4h50/wCef14NSLeaKCNzAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/af4d473859fb3f274c785c8efe369f46/40a76/hero.png","srcSet":"/static/af4d473859fb3f274c785c8efe369f46/c972b/hero.png 340w,\n/static/af4d473859fb3f274c785c8efe369f46/27625/hero.png 680w,\n/static/af4d473859fb3f274c785c8efe369f46/40a76/hero.png 1360w,\n/static/af4d473859fb3f274c785c8efe369f46/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time retrieval quality on Archi dropped for no obvious reason, the cause turned out to be embarrassingly mundane: duplicates. The…","fields":{"slug":"/2026-09-19-minhash-lsh-near-duplicate-detection-rag/"},"frontmatter":{"date":"2026-09-19T00:00:00.000Z","title":"Dedupe a RAG Corpus with MinHash and LSH","description":"Exact md5 hashing misses near-duplicate documents; comparing every pair is O(n²). How MinHash and LSH find and cluster them across a RAG corpus.","tags":["RAG","LLM","Python","Search","Data Engineering"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACDUlEQVQoz02PW2+bMBiGuVhOgDEHGxswhnAMJKQkKLRJIUnTbqu0dZo0bVOlSpN2sV3tF+zPz+m0atJj6/2Ory2VGStSbz7zT/um3y537bzbVoeuPh2aw3UtwtentttV15eLY7/qrqoy94uMlc9IIy0cggCSYlbfpFUfz7t0sRe62rwp6lNUdvP1XTzvk0VfrE5ptddJOQBcTAkk1eQCYAWyzgR/Q8XwhVYMIbisc8UMZSMQWjUDgMJz/3ObJGoTTYz5qhGImuXkNpubNJMhkzVnrDnISVgQO35ikhS7M6AHE+CMIFN0X/KSTV7f2MHKdCud5JjXdriGJEPBJjv+rJuv3z9sH59+3z7+KHef+fEBtJfl7be3ix6argTtxKA5wImGE/E8RLNiegGsqYaiMS5cP46ikLI8jGPKogmOFDsEJDFQJENPcqMmXe6j8tpiS4BTxJZuuNZwavhNd3Gq63df7tv797/6j49V+7CqP4XlvmmfdkWr6Y4ESWo6M2EunCGOkJOLD5t2Au2M+wvCLqoi6bZXSdUgf0XZ2nBKyi8ZzRToSGOVvKDpLsKBafmWxRWNvpLxREU68jgnGNtAs6BhQh3phgF0PAFUEueFMSBDxR6pZ8aAyiKjkjz113VaFZ7j8ek05EGYxKHrehNAhLP9H0TM/7vPGbFFBhhA4WMPFTpQ6FAhA5kO5HPDH8eyT3LwxOXyAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/4aa6b11a00da437300ba4f3109b953d1/40a76/hero.png","srcSet":"/static/4aa6b11a00da437300ba4f3109b953d1/c972b/hero.png 340w,\n/static/4aa6b11a00da437300ba4f3109b953d1/27625/hero.png 680w,\n/static/4aa6b11a00da437300ba4f3109b953d1/40a76/hero.png 1360w,\n/static/4aa6b11a00da437300ba4f3109b953d1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The bug does not show up in the demo. You wire a chat box to a streaming endpoint, tokens land, text appears, and it looks fine because the…","fields":{"slug":"/2026-09-18-fix-react-rerenders-streaming-chat/"},"frontmatter":{"date":"2026-09-18T00:00:00.000Z","title":"Fix Unnecessary React Re-Renders in a Chat UI","description":"An LLM streams tokens and React repaints your whole chat history on every one. How to keep the message list still while a single reply streams in.","tags":["React","Frontend","LLM","Performance","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACPElEQVQoz02Qy27TUBRFrYrGbzu242tf29ev+hE7cdLYTuIkTh8iaUC0pEWCUgnBLzBAQswYMWCKKG1VOkWAmPJ93GaEtLQmZ28daROuU7vO3HPnjj0Ldg6mk+ej4dk95VmRPx2Png12j8tiveF0WJ763h5Oblo1QYlGQ4BbnLYtmrIZh71JmE38zijqT4KsindnO1nld8dhb4pp92cqShgJkQIkRYNgmkiHke90DbPdBKGkx7IeSXooaSE+MZLDyh42JSK6iVjJFhSPk2yMIDsEwcGLrPq9fnlztL5enNyuzq72H3+rjy4xs+XX8ezLsLicHfx4ePxpfOABZ+iG0yAtnSiBLkGw8CIpfy5PrqaLu/nRTb28nS2vp4vv9eqymt+tP/568+dt/eo8HTwJdj0VFX573i3GcS+BNkEKhqe6lREVRjg0o9IMxygurahCSQ7daf/1av+zZtVEQ8BvLNWOdadthbHhhppNMLzBSBbTspkWohWLlky8HyXe+wFekVW26SbNAVaALA9pQSc50GBbDValeJ0gWaA53SCfo2SI4sIMct3uQW+g2VnLSPFygubLMFatrgwjRYlcc+RZIx9VUO0RFAtkPUZBBb1Cd3LdHUAPOzf8Erj9YnC+2nsXJQtgZ4qRanLa8Q8HyaM8WTmgICgOiKoPULdlpqrVaZmdjVOAMh64J/WH9y/+ZuHxFsnTvAbkxFD6+C3Scyhn92WK0zD0Bup/8xrJqZhNBqOygiE2XUG0RdHhm/Y/TbhmN17DKOUAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/5137398b75e04b7554db72bb2d3bcbd7/40a76/hero.png","srcSet":"/static/5137398b75e04b7554db72bb2d3bcbd7/c972b/hero.png 340w,\n/static/5137398b75e04b7554db72bb2d3bcbd7/27625/hero.png 680w,\n/static/5137398b75e04b7554db72bb2d3bcbd7/40a76/hero.png 1360w,\n/static/5137398b75e04b7554db72bb2d3bcbd7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"For years, the sidecar pattern in Kubernetes rested on a lie of omission. You put two containers in a pod, called one of them a “sidecar…","fields":{"slug":"/2026-09-17-kubernetes-native-sidecar-containers/"},"frontmatter":{"date":"2026-09-17T00:00:00.000Z","title":"Kubernetes Native Sidecars: Fix Startup Order","description":"Kubernetes native sidecars are init containers that keep running. They start before your app, restart on their own, and get shut down last. Here is how.","tags":["Kubernetes","DevOps","Sidecar","Reliability","ArgoCD"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACA0lEQVQozz2Qa2/aMBiFo3YCX2Lj3O2EJBQSCLcB41YILQyiUrZCR/dl09Am1v3/3zAD3aRHR5bfc+TXR9GTVKLVpkZ9Fqe7arprLF5uxptq+hxPt+XJ5/p8X5k8JfN9NN2enel/VTD1EHWlalY5Sob19rTTn9dat9XmpN6ZNbp37d590rptdmZJc6LblYv5ogrWQ6wHUolRkoq0AGAHqg5ENkDWGRuqHGoB+uc5+08RBTP/DS2QAUwEqwyM/idneeDZT2f5w+hvCuU+UjnCjvScnW8RBRWKJ5gPoaXVJuLhKFaHOPvudz+K9l3Yzyqrb3x5EOsji8cQmSenXPuckmEPsSKAhjl6Eo+vhNcgMCjzKtVenAzi+kClHEGTuInY/DFHW+pEVtAgRgipewoDoOutBc9+wTzLAd3yavNsN55mveFilGaL7NngUQ4YIM/E+lVvzTG2MSvKzhRIOGIefzjKAoDqEM1frb+IIMlh2ys130HTCxurxz0quHKKjRJf/5YHSIVEkQvTmw9W+gJy7AqY1eaoO7hXrohml00eMaukXNN2b1Z/P7nOm/LPZvqVBG2k2qcwxBbzm2bcR0SWWSxFXTdsYOZByk8vyL2o8MJWGPfkGVNhVoea31CZC4mjANUmepFZsgBOjUDVihKq+/L+jCV9RPclmLmoIOQuBTO4TP8CyY1NprMB3wIAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/40a76/hero.png","srcSet":"/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/c972b/hero.png 340w,\n/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/27625/hero.png 680w,\n/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/40a76/hero.png 1360w,\n/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most of the bugs I have chased in a FastAPI backend were not in the interesting code. They were at the boundary. A client sent  as a string…","fields":{"slug":"/2026-09-16-fastapi-pydantic-v2-request-validation/"},"frontmatter":{"date":"2026-09-16T00:00:00.000Z","title":"FastAPI Request Validation with Pydantic v2","description":"FastAPI validates request bodies with Pydantic v2 before your handler runs. Models, Field constraints, custom validators, the 422 response, and failure modes.","tags":["FastAPI","Pydantic","Python","API","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB1UlEQVQoz1WQa2+bMBSG+ZQABttgbCAYsLkXwiXptClpk3btqlb7/z9oh0SqNOnRq1c+57ElG7QbAa8bcd2L6dj//qifX6unF8jidGkvb9ChlOdr9/Lev/5h/UTawbtZho0lwing8SpO9/v52o/P3XB+GJ+q7tcwX6H306UZztCH+cLjB8LKu2UgP7vjBtplyg1KzCuHaSIqImqXaSpKwkscaLpmQXjhBsrxM8BANEVEIrKmTaTIpkgvVDSRmoWa/bBN8jFORzCTfIrk3vXVFssNliZJDRAQS+0VibwUBRmKtE0Sm+dOqCySeCwPhWJhEQkthMJelvNsSSstcpATtvTl11l/nPy5p8PoHQ+kG+g4e/OMu4ENo5wO6XJM54NcDkLWS6z+dsNRaviwnSuVXzcAFGen3bxCPCO6YeOeZR3NWjtUdphbIodi0gTDe56kVBoWji03Mp0VC0WgOUlhotDmKUq06cRbHG/dCNZsmqyQ2MSx6a4YYFq3GSTMfD352SSKx/bxrfvxXh9fx9PndP7aNT/hnOWzG5emE94tkMNv4FacNGTXMrUXegJ4MYflAgRqorLDuxZ+1HLEfd8wHfE/HNiiYGMHm3vabAUF29vIRPx7+R/odUZAaloa9wAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/8007290a8ca1a8e6e05f5955fe127fe7/40a76/hero.png","srcSet":"/static/8007290a8ca1a8e6e05f5955fe127fe7/c972b/hero.png 340w,\n/static/8007290a8ca1a8e6e05f5955fe127fe7/27625/hero.png 680w,\n/static/8007290a8ca1a8e6e05f5955fe127fe7/40a76/hero.png 1360w,\n/static/8007290a8ca1a8e6e05f5955fe127fe7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A retrieval-augmented answer that sounds right is worth very little if the person reading it can’t check where it came from. On Archi, the…","fields":{"slug":"/2026-09-15-grounded-citations-rag/"},"frontmatter":{"date":"2026-09-15T00:00:00.000Z","title":"RAG Citations: Make the LLM Cite Its Sources","description":"How to make a RAG system cite its sources: force the model to reference chunks by ID, then verify each citation against the source text before trusting it.","tags":["RAG","LLM","AI","FastAPI","Citations"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB6UlEQVQozzWR7ZKaMBSG+edKwAABCSQBFMKHCooiorW62467s1tvodPW+7+IHth25pl3Ts5n5hzFFMeBDrOWhCdZ3+P1R7z5CJevsv7xz9jewQ85Bj+A/i85KggzdeJjEhGaOH6Wrbq8OmZllxR7sBfrL3LRruqveXWCKKFStwIVMzSgIDNQDYHMcGLPdTJTjUDtPQGywt74xBCATiIAmQIZHA0lChE7Grd0tsVuMXFzUMAAvIVBC0jSzAiRRLUAqdmZ7uQ9dgohZRpuuTyweE/nOzfaQhc625Fka7LK9FYq9mEXov4dFd95+mx4G0w3oIa/Q9ZMoWEd5h2Xe5F2LNkH6YGlBzvdWryE4Sr2INvP30Vx4/nNky+AHZ0N3iEzUtywFukhyKC+FbL15UkeHzZvLN6YvG+PWRfVv5L2AcT7R9z88cufdnLvv+0EayZbL268eQMaxE2YtAYrTR8mL+EQOi3dxYWVV391ZeWzm59JcjDDFpaqiLgpNy+L8rKsrovqKmXLeIW9leVXUDzWXN0v3eNNnN7Y8ZWf3tzdN7K+WPlZnQjFnKaEFsTNba8gNNccqU9TPM2wm02mcqy7KoarzFUMV+wBG1kx6Finygg5I83pdeBJm/agAe3zCX77CdAGRfZoAEJ/AcmbURXYoUZ7AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/dea034eb79a4b0ee218da87ab715cee7/40a76/hero.png","srcSet":"/static/dea034eb79a4b0ee218da87ab715cee7/c972b/hero.png 340w,\n/static/dea034eb79a4b0ee218da87ab715cee7/27625/hero.png 680w,\n/static/dea034eb79a4b0ee218da87ab715cee7/40a76/hero.png 1360w,\n/static/dea034eb79a4b0ee218da87ab715cee7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most RAG (retrieval-augmented generation) tutorials open a new account somewhere the moment they need vector search. They spin up Pinecone…","fields":{"slug":"/2026-09-14-opensearch-vector-store-rag/"},"frontmatter":{"date":"2026-09-14T00:00:00.000Z","title":"OpenSearch as a Vector Store for RAG","description":"Run RAG retrieval inside the OpenSearch cluster you already operate. Set up a knn_vector index, pick faiss vs lucene, and avoid the memory traps.","tags":["OpenSearch","RAG","VectorSearch","AI","DevOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB7UlEQVQozzWP246bMBRFeWkA24BNANtgMLckJJCrkqFJpiiVpqp6mYvatz71pf//Cz1Mp9LS1tbR2pJtNPoKzNPzYflpOL5c948fjs/D8fl6eIR+3n0b+/77rf8xnF6284+L7PJvAhimlwDvXMnzbrY5zzcXyMX2WnV91fbl8q7Z3dfr993ptjwMYbYE83USQxqEaeK/gWmGWQYJ3eOVG41gNt6RlyKaOdP8TWYZDA0MV5LYgKMITTFNbU9hloa6AYJ0AR15CmwwbTyayBk1wCChDtqlaJqgrLE/SozPfD5zpwVhueMXXljRsIYlEXnUrnjTUK3BRK4y0FSxsp7mlae0TaUX1Xp1rdZDMuu9uJXlKS77qd6RaY6DlBUVmG6cIpYg+DNypGnyicUtLG0iWDQr6otI9iLeyWSfFn1Z338+/ZayM1FkWdy0uI1j5I4YNkuornxVOJEyXR6L9sv250P3dMyGu/x2a74+tE+/+j+KdyYTNCuZKlypkSdtVxooSMJ1wxdzN1XYjyc4xrQktMAekJOxl6abmVhgngXtQjRzvywQFfBMwybctMOJHSJHTLCoM7mpeVPwVcnbSkCuCr7MwzAILSzABCwc2Q4HDMuJLIePkGiCI8F5roROpFYjWSzy1/RoYJL/JkzIyF9mDEg/kt3NYwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/5b138803918816bc6564009524360289/40a76/hero.png","srcSet":"/static/5b138803918816bc6564009524360289/c972b/hero.png 340w,\n/static/5b138803918816bc6564009524360289/27625/hero.png 680w,\n/static/5b138803918816bc6564009524360289/40a76/hero.png 1360w,\n/static/5b138803918816bc6564009524360289/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first RAG (retrieval-augmented generation) system you build retrieves on every turn. A question comes in, you embed it, pull the top-k…","fields":{"slug":"/2026-09-13-agentic-rag-when-to-retrieve/"},"frontmatter":{"date":"2026-09-13T00:00:00.000Z","title":"Agentic RAG: When Should It Retrieve?","description":"Naive RAG retrieves on every turn, even when it shouldn't. How agentic RAG lets the model route, grade its own context, and re-retrieve, plus the tradeoffs.","tags":["RAG","LLM","AI","Agents","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACBklEQVQoz22Ry27TQBSGvSmN7fHM+DYXX8Z2bCe+x46b0KSWQIKyaWkLC8SOd2DNU7DlZTnphg3Sp6Ojf+bXf+aMJsJFRhdEeDeMz+P8dRhf+vF5t//S9J/b4WmYXrrhqekf6/ZhBLF7ZPIUxIsMF02noU6CFZbYS8ruthrP7bTUu3Mz3W2H07Y/NdNSDaeiPZbdsR7P0JhOrBNp0FAzbUX83HIzg4IUrXCk48ggsUGTK8tdUf8K2aCYdkJZYVAF1ywnJV4OjWaSyA0akUxcDV7YUVHZsiF+ucJsU37/+O73PP5ETmp5GWEFVOQkftyF+Wzzjabj0JFVsN7HxcxUT/jWeTVfW15d/Xi4/3N7+IVohqgyaYIAO5Fql5ZHV1RgDi7mdBLJLsgmcNqiwV4OOoxqsw0MaXoKZ5VTtCTdmq7CSUnyGgVrTbekTKduvu8Pn9r5nqnJV5PNK90STB6r9jlW75EscDOw/YE2O5NnbrcXb88kbyAZ9rx2ZQ1QtiGstPkW9gdm7OS+GKlXURrFfK1EEbE1pmEYKBUlPou1FeLw+v35YX9+XDeLG40subFFtUKMybe7/lucfuBedluMS32Yi1EwNQ/13c1QlwWMzXUsDPg3/A+IBd0kQrox92LhJ9xTjhMZWEDYG4NdGezaZJDM/ss1YohI6kSA81oBiwaXU4tfQOwvRmRODAajbqYAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/c912980bcf337b4612f77538821ce496/40a76/hero.png","srcSet":"/static/c912980bcf337b4612f77538821ce496/c972b/hero.png 340w,\n/static/c912980bcf337b4612f77538821ce496/27625/hero.png 680w,\n/static/c912980bcf337b4612f77538821ce496/40a76/hero.png 1360w,\n/static/c912980bcf337b4612f77538821ce496/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most LLM chat backends start with Server-Sent Events (SSE), and for good reason. You open a  response, push tokens as they come off the…","fields":{"slug":"/2026-09-12-fastapi-websockets-streaming-llm-chat/"},"frontmatter":{"date":"2026-09-12T00:00:00.000Z","title":"FastAPI WebSockets for Streaming LLM Chat","description":"SSE streams one direction only. When an LLM chat needs the browser to interrupt a running response, FastAPI WebSockets give you a full-duplex channel.","tags":["FastAPI","WebSockets","LLM","Python","React"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABtUlEQVQoz03Oa3OiMBQGYD5VRQlBJORiEiCRq9KlRVtvrd3tzn7Y//9/9ljcjjPPnAnhfZM4jTagkumubn+9HD62r5f+5eduD/Ptafv5ejx3/fvzDha/D6e+XNcqGyrAGfkKPCBJ0x95ewamOazas92czfpUdh9ZvTebo92cqu7C7TMkr/mvljMLFPDmGsdFyOto2fgkd4Nk4i9dLCdIzMJsIRoiNzBxnENyqABniuVVoKCjVn39+KZXWyLqkGR+qK8iq2xvm4PMd4isbvkvjgs33Iixx3CoGbdcFJznghnJQQaLVFjJ0gU1KNTfFSiLwcwX8FTDlKUiISKJhY5FQiXsSKb/dE/7skLEBlH6XXFcxEGn2DFXWUxbW3ZFUyizTm2TWMuVoUtNxKVZ10I6Y+J6dKgAZ4IYnLHKqtKUUuWQLpZJlRVlWhRpUWZlbSuTln9P721mH5DAC+X6HFrAmXgUjBEfefDNg4CHAfM94iMCc47pYs5BYjtlHpluFsxMfTa0oBzfmyHqY0aJojHQMVFRJDFm8NopFihU15tmZAg7sLo3mhIX0Zhq+l9EFOyMbn+j+/A/YwZGwBp7r5QAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/f592754569a19a404a61ee0fa9a91ca8/40a76/hero.png","srcSet":"/static/f592754569a19a404a61ee0fa9a91ca8/c972b/hero.png 340w,\n/static/f592754569a19a404a61ee0fa9a91ca8/27625/hero.png 680w,\n/static/f592754569a19a404a61ee0fa9a91ca8/40a76/hero.png 1360w,\n/static/f592754569a19a404a61ee0fa9a91ca8/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Every vector database asks you to pick a distance metric when you create the index. Most tutorials wave past the choice with “use cosine…","fields":{"slug":"/2026-09-11-cosine-dot-product-euclidean-vector-search/"},"frontmatter":{"date":"2026-09-11T00:00:00.000Z","title":"Cosine, Dot Product, or Euclidean for Embeddings?","description":"Cosine, dot product, and Euclidean rank vector search results the same on normalized embeddings, differently otherwise. How to pick and configure one.","tags":["RAG","Embeddings","VectorSearch","OpenSearch","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAByElEQVQozz2R3XKbMBCFuQsgrYQACRAIgUAY/+DYvohjJ+1Fmk7f/426Np3OfLNzNNpztAsBnc7whPoT1vHHH/v+5T5/u4/v7vbd37+7+68Hty+8wiPfXtZONAaENf/gTVb4ze42bt6W08/98dPPb6i3hzuyWz7mw93P11xN/y0BSVuS2li0CM06mlrjTpDaEGqStHW/2PEMeR/yRjbbYXu1/gJ5t7oCkhiEZR2XLmY1l305vEI5EtkT5WS/6OnMEhODFnlfmYPUMxXt6gpi3iBEtIkaUfBikMd3cAv0B+j2dHwVy5W6PTFzJLtYuTh59j/MDZprJGL6mddEUBXmyFILiYGk4WmfyJFKB3qi3Y7Pl0R77AlpiTWImV4BXAODmFZmD4/lW4xjueNyoLiXeMQJOcasSrVv5kvWTEHEKiSEkgicR6NOK9zqMRUCmWWyx1wUGCcKjz2QtVnlWW6DCHCAknDNMrvqVHmKHwKqiJaUG3w2JAUeMQsHec5cvBCFFc1FSBUVNWQGRZxoIlsiDdOO10NSD8J4BAVVLRT4k2q0rM8EaEBeiERCoiKhadkhotvkwy7r59zv1XTI3ExLSytL8ibEzqfrL2TMQD9kW0U8AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/253f7d1c56e9e7b3fd4601ef40351ea0/40a76/hero.png","srcSet":"/static/253f7d1c56e9e7b3fd4601ef40351ea0/c972b/hero.png 340w,\n/static/253f7d1c56e9e7b3fd4601ef40351ea0/27625/hero.png 680w,\n/static/253f7d1c56e9e7b3fd4601ef40351ea0/40a76/hero.png 1360w,\n/static/253f7d1c56e9e7b3fd4601ef40351ea0/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"An operator asks the copilot “what is the retry limit before a transfer job gives up?” Retrieval does its job. The top five chunks come back…","fields":{"slug":"/2026-09-10-maximal-marginal-relevance-rag/"},"frontmatter":{"date":"2026-09-10T00:00:00.000Z","title":"Maximal Marginal Relevance for RAG","description":"Top-k vector search keeps returning near-duplicate chunks that fill the context window. How Maximal Marginal Relevance reranks for relevant, diverse results.","tags":["AI","LLM","RAG","Retrieval","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB8klEQVQozz1RaXObMBDlS2NjCQmQEIcQhzgNBhIfLT5qO8nkS///D+qSznTmzc7uap/eHkaX7AB9MoDdxt1j//w4fd6m38/jO/jX8fY8vD8OT8i8Hz8uw7WV3f9644WqFY1fiERcE78udpft/qn783b/qKdbNV7btztY3c+700c5XGjYIF68kHhFlYGdxGKZxXLCtS1K5GQbO8VujpwUuUseuxkAOYlJJbIVWTIJsmPkKANiixUWLwGYlW7Ui2SifgO+xStIgr+8upkX91x21Cu+ZSr4xdjQGP8js8IJWi8eg+TVVxMRNfEqKiobyFDgZlIfgvQ1SCcuez+d3LAFssRMLwqiBqYddMzf/tl/5fUcZFPezlANr9AkZqnlwThqTUKASSJjQyKLabzIdm7Yx/o47T8jOQj1aouGejU0j3lBHJX5hRJasJTYMcCi0jBJCMqEl16w5dFOpm95M4toJ+LBZAViMGGFmGYsvXeXc3U8N7/m+nRt5z4dDNMKkJuzoP0a71ofnKiHFqB/IpqD3jfJuHY1zExduOzPcTeXehQ89XnOXAVkH5TtoFX6LUhg5tYJOyoa0By250gNaFl7CbfxZMtlw2W9puEP5K2wMNZYwOiw8xWGNSwOrBAsnHBtx6Ydb2wF4Rr7KyB8A3yQNLH/FwJLSj8v5LHiAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/42035b5990649c4308fa5035902519cc/40a76/hero.png","srcSet":"/static/42035b5990649c4308fa5035902519cc/c972b/hero.png 340w,\n/static/42035b5990649c4308fa5035902519cc/27625/hero.png 680w,\n/static/42035b5990649c4308fa5035902519cc/40a76/hero.png 1360w,\n/static/42035b5990649c4308fa5035902519cc/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Chunk size is the setting people tune last and regret first. Make chunks big and retrieval gets vague. A 2,000-token chunk embeds down to…","fields":{"slug":"/2026-09-09-parent-document-retrieval-rag/"},"frontmatter":{"date":"2026-09-09T00:00:00.000Z","title":"Parent Document Retrieval: Search Small, Answer Big","description":"Small chunks search precisely but read like fragments. Parent document retrieval matches on child chunks, then feeds the whole parent to the model.","tags":["RAG","LLM","Retrieval","Embeddings","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACE0lEQVQozy3R2W6jMBQGYK7SLBgIYDYvmMVgwEmhkzYkhaTppKmq6eRmpF5W8/5PMW410qff25Fl+Wh1iZWqQMehez7cbTfV09Adh1blYy9Phx/7h+Z0uBv3a7W538oyD+tC1WOV2gTQiU4BLHI5FqsjEzvRnvjq8O3I109JNRTrJy6P9d2Zif3C4RMQTwC7MZhmwszyctPLdSdRDJjpdrxYkrmF1WTpp3aQLb0E2AjY2HSpBRmwKXCIblMN0jbKege3LulstLYiaXrlwsJzk5gOlu397WaU3Q4ltY8LD5dxmssmpyxTNZodVVHSobSL0hbi2kW15fEpiKYAGQ6Oiw0qRlQ8BtnOT3slyvsouw9IqVtIK3giKoFjQVjFsjLJCkwT20sMVz0VM7GlzSVuzkxemHyNm5+oOLjxvY+5bkXatqPXc/Z+ys8j/3hLP9+RrLNS7op6gwm9PtO/V/z5+7+PV/xxQX9eyK1kMxBqufrmVVPVZSmqbp1fn+O2IX6I/ABREg4P6tL858C/jHzYlmNfHvpClGxmBJqNVpBtzahdog4E6zmUps8DIkyYzg01Dqj5heo3JSwvkXgJ+MkivYv4wvA0KxCQdjDuVNpIKgbMbxbwZuGZdhBnFc5byr+gpAnjKoxFQEVEkhnwtLkZ6UuiGqt/9Rap5cwIp7o3Bb7KBXCNpe945Bt1/VglsLw5gOr0H3xmWlqUGuSYAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/73688f50ebb030dd3cc9f68a43db401a/40a76/hero.png","srcSet":"/static/73688f50ebb030dd3cc9f68a43db401a/c972b/hero.png 340w,\n/static/73688f50ebb030dd3cc9f68a43db401a/27625/hero.png 680w,\n/static/73688f50ebb030dd3cc9f68a43db401a/40a76/hero.png 1360w,\n/static/73688f50ebb030dd3cc9f68a43db401a/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The HNSW post and the product quantization post both circled the same fact from different sides. The naive way to find a query’s nearest…","fields":{"slug":"/2026-09-08-ivf-index-vector-search/"},"frontmatter":{"date":"2026-09-08T00:00:00.000Z","title":"IVF Vector Search: Search Fewer Vectors","description":"Brute-force vector search compares every embedding. How an IVF index partitions vectors into cells, probes only the nearest, and where the nprobe knob bites.","tags":["AI","RAG","VectorSearch","Embeddings","FAISS"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABy0lEQVQoz12RS2+bQBCAudTBwO6yPHd5eNcstsFOTeIYg7ErK6pyaXpIeui59+QP9N93FjdSVenTaEbLp3lgSHGWUjMTw7p66tof7f5l//ACyf3d9659hRI4tK/N9vk0/Fwtv87yk7bE2TBJYmIOTJyYsmKz+6LWbVHv62YoN119d6qaYXHbr5pBrnafHy4eKyeIaYskhkNnOCzduHbjisQVjnQkEKOV482nJJ+6uUWF7QmbCpNklps7VIAFGBbJKN8wdYznXVz0QATJiONL4qu5Oubz+/nyIBdtKhovKkGx3RwwLJxSvtaOPIxOryl6VvQoKJAnQl5jX7qBoqECE3sS5CsgJyAzLXeB3F+G92+Pv5kauDriQGF/FiTljcNuEB9hJk4skl4xLMQpq6FbJNpAtn376+n8BjJTPQ4VohljirMyZipNFpyXXiCniENLwDARc7XcgQyTw8LXqHeGCTEnvnDc1CYJRCh1PgK5YToxyOPYh49T/U3gJIjm+eIYZk2YbYNsy+VOVme1uZS3j26oQI5G+fhxMM1Vhr+Cae6FJUwHG04x9yIVsmXEV3FSITfVsu7gK+QX/wFfw+u/TOxgYgWfLH9i+VD+AUBdTY02lx04AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/ce304b9c360b6d8df5372e94a8ea8897/40a76/hero.png","srcSet":"/static/ce304b9c360b6d8df5372e94a8ea8897/c972b/hero.png 340w,\n/static/ce304b9c360b6d8df5372e94a8ea8897/27625/hero.png 680w,\n/static/ce304b9c360b6d8df5372e94a8ea8897/40a76/hero.png 1360w,\n/static/ce304b9c360b6d8df5372e94a8ea8897/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most RAG (retrieval-augmented generation) demos start with a folder of clean Markdown. Most real RAG projects start with a shared drive full…","fields":{"slug":"/2026-09-07-parsing-pdfs-for-rag/"},"frontmatter":{"date":"2026-09-07T00:00:00.000Z","title":"Parsing PDFs for RAG: Text, Tables, and OCR","description":"How to parse PDFs for a RAG pipeline: detect born-digital vs scanned files, pull out tables without flattening them, and reach for OCR only when you must.","tags":["RAG","LLM","Python","FastAPI","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACAklEQVQoz0WQWVPbMBSF81JI7HiT5D22LG+yvMUEShzbIQkM9KGFKXT6QP//D+kNzLQz35w5vjpndK2ZwUejGFExGnzQst5pT+L4lg7P+fgCmo3Pye57Nr4kux/l8c1p79Wsh+RHfpxJqiervqR4OmbYTm1frK+PdbcX9a5eT931kVe9aHZF1Zft6IU1tjOdMMhDayajUDbOLBFVCFuiaKGtFloAOgdUf6GfvaSHcy1Y4ugzIxkhMJP1QEGRiiIFMwX6OFI/DHIyyxfEL0yXY5crKNQIHAEUFDwkYW1fj2+s7hvKelKdMB9IfSLijhR7a/1Eyr07/LLSr4wVIc1plEdxSWkaJ6XtxVB2UTF5+3dSHuztT7N5cO/e3cMfs3tyx9+4PDj7d7ucymqTZnWeN1xs4jiv2q23Ss4PptMrzCcjuUVpD5jrRwBWwNmA0i1pHkh6w5iIYs4Yj5MqDNM4rV24ea44qpVi2mqeQKtKdbjuCc0tlnaOglrzChQ2qpOFQeT71LRXlDJs+nEUY3M1WygO/DOpjrC81ZyS6TWdXs+6f7Pbexga4uBVQyt4U9bT9vo43NxedbUosziBsrV0CzXq1LA12MbKt1Z+C9i8N+INDBXaobCiQcRYniY8+SCiiesGs/nSmsvmJ5cSuVjgf8Dn/7lkXkjkC7AATy5l80I2/wIPgFRej56GUAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2cd1baef737ff704c51e7dc49d568c7e/40a76/hero.png","srcSet":"/static/2cd1baef737ff704c51e7dc49d568c7e/c972b/hero.png 340w,\n/static/2cd1baef737ff704c51e7dc49d568c7e/27625/hero.png 680w,\n/static/2cd1baef737ff704c51e7dc49d568c7e/40a76/hero.png 1360w,\n/static/2cd1baef737ff704c51e7dc49d568c7e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time this bit me, no deploy was involved. A platform engineer was upgrading the kubelet across the cluster, node by node, the way…","fields":{"slug":"/2026-09-06-kubernetes-poddisruptionbudget-node-drains/"},"frontmatter":{"date":"2026-09-06T00:00:00.000Z","title":"PodDisruptionBudgets: Survive a Node Drain","description":"A cluster upgrade drains a node and evicts every replica of your service at once. How a PodDisruptionBudget caps voluntary disruptions and keeps you online.","tags":["Kubernetes","DevOps","Reliability","ArgoCD","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB8ElEQVQozzVSaW/qMBDMR0oOJ3Z827nIhRMngZaGUkoP9f//pmeKnjQaj7Q72tmVvaS3DnE36tPb/uu3/fjeXW7N9dOJ5vpVnq/d7eehzfdvvl5AOzwsDt42VBufB5Eum5fp8NWPl9Zc2uHamPe9vdX79268menWmrf9+F53q+vfhtIPlR9pL0yrVJqYtSGug7Ty0ypCWmUlFRmmIs8yJVUINWBdwroQ7wCpHQeo9GHmJbyv7Y3oJaYGSgv4yJgyjc45Kjn4mOlqEMJS1mvRXwIyAG6hmgBpfaC8CDfA2aoF9S+JHAEfKBFQ4Lbvr2WRplByhKkOqUFybFqryjEWFuBmG8m7GSqb2ld8usBiBmygmNJxIOsnl1RJl5xRlidyLrrX89EOxqWzgDiz8NwD5USaZz6cXexYjJRyXbK8LzgOcsUqjTAWbh1X7cxRVUsipvvkkHsBzAPkDlABXEdpHSa7BGqGOSMiJYpSyRiPoHQ9oavej1pHjmH+FDEvJjtz/DHHb6Itqga0WDRMybzQ0fY7zXSD9SJyh1nk03/MIK02AXXmWrfnrH2l2YLbGa8HvCzpeizWw6GXKm9k+Vw2J4eifrmL+lQ0JzdyExBvC8Q2Vlsgg0QHsXa/5cEx3T3FhZ9kvqvG6ukBcOe/fuHM/wCVkE+S52BpGwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/6f73cc52999ecdead939a70ceb07cead/40a76/hero.png","srcSet":"/static/6f73cc52999ecdead939a70ceb07cead/c972b/hero.png 340w,\n/static/6f73cc52999ecdead939a70ceb07cead/27625/hero.png 680w,\n/static/6f73cc52999ecdead939a70ceb07cead/40a76/hero.png 1360w,\n/static/6f73cc52999ecdead939a70ceb07cead/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You asked the model for a JSON object, and you stream the response so the UI feels alive. The problem shows up on the first render. Until…","fields":{"slug":"/2026-09-05-parse-partial-json-llm-streaming/"},"frontmatter":{"date":"2026-09-05T00:00:00.000Z","title":"Parsing Partial JSON While an LLM Streams","description":"LLM structured output isn't valid JSON until the last token. Here's how to complete and parse a streaming buffer so you can render fields as they arrive.","tags":["AI","LLM","JSON","React","Streaming"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABz0lEQVQozzWQW4+bMBSEeeoWG2zAYGNj7pcEQwikmzSbVH2s1O1W+97//0N6IIr0aTT28RxGWH769uRaHX93p7/N/Gf/+pmPv8C0y0e3fDxMM7/vvsH0nSaXR8RCNME0QUTRsGjNeVx+9tPNHO9Nf94frsPyYzjeh/lu5ls3XOC4n26EFYgqSFnYz7CfgzpBAQZ5KfJy5BcOaxzW4qDBbCOoYGpTjf3UZcWWyizspU80ptoJKoi5rHb8dZfz2AuwmsQTAA/WslsEausnCQ5K4OGRt+kGbCFiXJdGe6pOTtghAvfaer5QyIP1DSbJWsFLbQI3YDT8DhIf1hF8DTTsqf5ubykLZiuuhHpxcYqzUWRD3i678SqzgWsjUhOlrzKbmOzT6lj1t+78j0lju8KyicRUuVQRqiJeRaIOeSlkw+LG46UXV4hp21eYaRQkmCU8N6I6BEn3lcTWF0cophddznU/Fe1UdkZXbSRDKCZTr8/TxcjDTs99ZKp4bMO+xLlwa+XIFMJcs+Re7W6teWvNvRuOWb3nSrHMzQqxNPps8rcRVC4dqL6YeGn9PsMqtV4c7hLBfcU9ueLLyF8VO/yFCiwSmyskEvTQDRxrUJvG/wHFjUdA3AcjkAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/6075141fc24c832e20f8bc8a74a39ebe/40a76/hero.png","srcSet":"/static/6075141fc24c832e20f8bc8a74a39ebe/c972b/hero.png 340w,\n/static/6075141fc24c832e20f8bc8a74a39ebe/27625/hero.png 680w,\n/static/6075141fc24c832e20f8bc8a74a39ebe/40a76/hero.png 1360w,\n/static/6075141fc24c832e20f8bc8a74a39ebe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A client sends , and the handler runs. Somewhere between the database commit and the response reaching the browser, the connection drops…","fields":{"slug":"/2026-09-04-idempotency-keys-fastapi-safe-retries/"},"frontmatter":{"date":"2026-09-04T00:00:00.000Z","title":"Idempotency Keys: Safe API Retries in FastAPI","description":"A network retry can submit the same request twice. How idempotency keys in FastAPI make POST endpoints safe to retry without duplicate side effects.","tags":["FastAPI","Backend","Reliability","API","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACBElEQVQozyWQSW/bMBCFdUmT2BIXkZS4aCO1UJvlJXEqK3Z7CZqgKBrk0FP///8onQIPgzcDfngz9Nr82clmi1OdzMfx9fvx43z4vex/zdPPy8P75fH9ZflzaF+a9OTetNnzf8TJu4XyCxBrWiBeu8r1pp6WcvjqatE9VtNcTadmt8R69CPtx2ZFshvIb6C4hcoDxATEAFriuI6SHkW1H+qriAahjomluOasy+U2V7tcbZ2PiGXM+jj3AK0wb1HsZHU7s2SEkcWiA1EdkiqnY8IGmx531WWqzl32ZMQ+pYOivY8zL6AlURuWToi3zmDeEzVG2dbBKDQpHbUD5LHgDzY/p2yqslnxSYR2jVIHG+hCeOu7zV0gq1yLuPWpwaSUoWVAR9BMyfIx/R3EPIinQRxd+BolnjvYLUzUAFkZpRscN0S0VA1XODQOplATUAhq++bs4Ev59q181Wy7gtJzH6PKp7Q7i8i8maYT+pBUP3RDmYahVp8wCwzpO3zZctVleMjIIEl7hQOi3cGxPpi0v5T9Ju/H1O5VRZiBuJC4IUERoVKOkzjuRd67LUKQx7haA+kBZgJWhdw23cnY2faLLHYrWrshxkVGhxhWJt2P/aWrT2N/TqNBIqtItwLcuwdyjdQKqjsg74C4BeIeqjV0E7kCgqAi/BQKMgQyV50nSCOU3fnRPyWKUHOhjkAHAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/2f02f9ab751572adeacc0c1abc490f53/40a76/hero.png","srcSet":"/static/2f02f9ab751572adeacc0c1abc490f53/c972b/hero.png 340w,\n/static/2f02f9ab751572adeacc0c1abc490f53/27625/hero.png 680w,\n/static/2f02f9ab751572adeacc0c1abc490f53/40a76/hero.png 1360w,\n/static/2f02f9ab751572adeacc0c1abc490f53/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The failure mode is boring, and it always happens the same way. You point your services at an OpenSearch cluster, ingestion works, the…","fields":{"slug":"/2026-09-03-opensearch-ism-index-lifecycle/"},"frontmatter":{"date":"2026-09-03T00:00:00.000Z","title":"OpenSearch ISM: Automate Index Rollover","description":"Log indexes grow until a data node runs out of disk. How OpenSearch ISM rolls indexes over by size, ages them through hot and warm, then deletes on schedule.","tags":["OpenSearch","Observability","DevOps","Kubernetes","Reliability"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB80lEQVQoz02RW4/aMBCF80ZCnItzsePEsXMn5AYhYaEUVNFu0Wpb2lV3H6qV+tj/1J9bA9Wq0qejM2MfzViWvGBPgr1QPzx0y6em+9b1T1Xzdbn6UXXndvm9H5/r7jxvvjTduR+eRYfQwy0lKWagGL6se8AO8+auaDfNah+XQ7nYzdpt0YjyMOu2WbUu2q3w8+V7zWYiMjUDSYUMWLHhFJqVAgFMVTPWnUQwNbkK+VUj1YqAUMhV6wpkAkkxAtfritnngG4wWTtoZTkLXoxlt0e0xqy1/RLi3PJyoQITZaoZ3pAU3YdOPS9/ZtkjZRvLbS23gbgwUXoJeLnhii3iNww3nRp0agRCRZiI8HH3pyp/U3oMw5MffLDJjEQLzBqPtSTq8EUXHm8J7wwnVk0KIBN5SdE8aNd59iuJXhL+kievjD7SdKjHh/nqVA2nengo+083X/b3AIa2m7Bs1K1QkjUEnSZLXzk/e96e+vfY22G+wHwZpGsBiYcgW3tRH2R3JFqJybqbYH820Yg0UV2bVCw5+uwdYRvCtoRv/Hgk8egnozB+PJArt9IO6hhHO5pmiEkyQLr4Nx1NgCu2kIGrGkSDdKIiWcMTgAAUL6TCyADLKgI2D3H0MckjN7yE5dvBm9HQP69dmopQDf9/R9UwMgnQ8F/xRFB8eplDiQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/0e6d058ccf250e8146224cb217027f5b/40a76/hero.png","srcSet":"/static/0e6d058ccf250e8146224cb217027f5b/c972b/hero.png 340w,\n/static/0e6d058ccf250e8146224cb217027f5b/27625/hero.png 680w,\n/static/0e6d058ccf250e8146224cb217027f5b/40a76/hero.png 1360w,\n/static/0e6d058ccf250e8146224cb217027f5b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"When I wrote about hybrid search for RAG, I ran a keyword search and a vector search side by side, then hand-waved the last step: “fuse the…","fields":{"slug":"/2026-09-02-reciprocal-rank-fusion-hybrid-search/"},"frontmatter":{"date":"2026-09-02T00:00:00.000Z","title":"Reciprocal Rank Fusion for Hybrid Search","description":"Reciprocal Rank Fusion merges two ranked lists without tuning score weights. The RRF formula, why the k constant matters, and how to run it in OpenSearch.","tags":["AI","RAG","OpenSearch","Search","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACI0lEQVQoz02QvW/TQBiHvcSfZ9+d7xyffbZjOx9N4qSkSRqSNp+tUJUSqYpECUPUAgKpYUPdWNjYmJDYmBnKwsDEwMIfxqWFCumZfvo9d+/7SlmheE8tTJpJebbfn3R6o73uUW8waLamnYezbn/Y6ozb+424JDr3fUmGkSBnBjpJLXcHsmqpOSzvjuNaf6c1SeoHaXZYeTDehs0R9uuiI5qyFSowkgCOTBILIE1RvgidFNiFW2IDhf8R6XZk0QTRVJSFJZB0GLCkXWs/KjYnSTaq7B2Xdmcs6WK+i1ndQMGdLGqk1KFhnfpV6teEKUIhc+iUKM94mPlhxqOGHzZsVrNo0SSJcP7BEasjt4ycVEx399xWVgFTDdsjeUZcFzsEUlm3NcvTof/3WxwIRKJBT0NcKGILA4eSZjLTjodPvxy9/EGiQdp9frL51Zhcq8DRTFfWoKIjVSEW4AhFCIVAZ4pq5xRTVi1JBXngpL3N19H1T1qbpcdvJu9+V5fvcyp0Cv3Zi5vB2Sd2cha83eRPH3vPVt7VZWG4ml3ctBcfJA24wObukzm7XNppmfY63utzZzpUFOTEhwfrb53F5/x8Sa7W9umcnC/Jq1U4vRiuv7cWHyXVdA2LxW5Y8UKKPY/yKo8Y8XWLyQalLMY0UDQaFTJVd2xSYKycU7DLixb2tmNvfSwOw2XgatAHt7fZ5oYDxHkspgIXkkgkBvJNO1AMx8Tb/A8dqVfhOKMvqAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/03c69b7b1f3f10ef17416f7f382600ae/40a76/hero.png","srcSet":"/static/03c69b7b1f3f10ef17416f7f382600ae/c972b/hero.png 340w,\n/static/03c69b7b1f3f10ef17416f7f382600ae/27625/hero.png 680w,\n/static/03c69b7b1f3f10ef17416f7f382600ae/40a76/hero.png 1360w,\n/static/03c69b7b1f3f10ef17416f7f382600ae/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most RAG bugs I have chased were not embedding-quality problems. They were filter problems. Someone asks the copilot about a transfer error…","fields":{"slug":"/2026-09-01-metadata-filtering-rag-vector-search/"},"frontmatter":{"date":"2026-09-01T00:00:00.000Z","title":"Metadata Filtering in RAG Vector Search","description":"Post-filtering vector search silently drops good results. Here is pre-filter vs filtered ANN for RAG, why filtered HNSW is hard, and how to choose.","tags":["AI","RAG","VectorSearch","Postgres","OpenSearch"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB30lEQVQoz02O666iMBRG+XMUW0oLlEuh5X4TFQV1xOPxGOPMZN7/iWaryWSSRfPt9lu0mlEPBGgGVPb+cKluf4qv38l0B2LgdE/Pj/q1CQFWsb/iagsKiBo2JYBIaFpJVozb4dZ2U92eVuvLcv3ZdFOznNbb66r/grHtzkm6o1aKydPSsB0TJ3OiJVcrJ1lZoiW8QHaC3Aw7GYaek8G4YDG2EygE7Z6JGiwYNUQl5bnIDkFxdI4XkR9lcQrzozNMbnMM4jHIDlxuqF9bfsPLHe9/ML+mXoWZesqIScOKMZOIJxDsoLb9ing5thQ0CFzCFNQwi007M1j8VF6AHGErhqcyr3LiFQ1q5leWX9mqs0QDGY4IzzBXBo9pWNAgx84zg6ghU8BtxC1d2cly5FEn0q1IelEMnloDpluZQUmLJuj3+fWeTle7WZO4fMoLUwCYiAUL55tRN8UMe3Pk6t1W9xIdefB3bEX0/El/Psj3t3m7sV8PUncLEmjwoRfYluk4RWEViSoMynA1hllHaQQFw5Fmt2G70T2d+OFI+x1J67fsv8E0VKIOo0apZSRbKSolW+rEOnYRCw1PmUHq5i1Pa8jYVaBouuH9Y4Zd4APxGXI/8JP5f6c69mYLDrwzrH8BI7BHFvWFfcIAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/1547a1eef22b6c181246160d46518c3d/40a76/hero.png","srcSet":"/static/1547a1eef22b6c181246160d46518c3d/c972b/hero.png 340w,\n/static/1547a1eef22b6c181246160d46518c3d/27625/hero.png 680w,\n/static/1547a1eef22b6c181246160d46518c3d/40a76/hero.png 1360w,\n/static/1547a1eef22b6c181246160d46518c3d/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You put a model behind an API, send it a handful of requests, and watch GPU utilization sit at something embarrassing like 30%. The card is…","fields":{"slug":"/2026-08-31-continuous-batching-llm-serving/"},"frontmatter":{"date":"2026-08-31T00:00:00.000Z","title":"How Continuous Batching Speeds Up LLM Serving","description":"A naive LLM server holds finished slots idle until the slowest request in the batch drains. Continuous batching refills them every step. How it works.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB80lEQVQozz2QWW+jMBSFeZnOJBAWgzEYzGawzRoITZu0TZqlM9K8jDTz2v//P+Y2lSp9ujqWfHyPj9YkXZv0QB23x+l4ub/AfFkfrg/X8/ZyWB8v2+v5/nKaT6+b02k+77snFTdwH4zancXurPibGRmY581OTce83fFuX29eQfP2SY3HangW6wPManjh/ZOOC7AAmuEkKze3cYkCYXnc9LiFSx1l3y22sNKlcwNlSyf7nDrKV5jrbm6gTNNtZuHKizov7hBtbqIngUrjPmV9wvrAl4EvKJFARBTwKRxcaUsrNtzCcDk8qaMPAQjazMVmKqYh6Qsn5y6P7CxyCmpnofUBQwUlAsyR6ZWWL5ywdmlr+sIN6iHur6H8zcf33dsfOZ+pmmgTp2Mz/+y3v5r5jcZDiEttaVL4pAXZ8k1UPthEWkTyQF0j9U/dv0+Hv2o+hUL60qVdUD4wuafVzqcdBfPCDFduYROF2YDZGvZDitQXPS47XL6y7jFUI5ElrmKvyoliWGDIjHjoV9piFRgoBwMKGygMIkAQ5lXULSMsGJYZqauwHbOppm1BVOZLIPGqj9iLFYHCVl51q6oETCwSIjv+OMrn9Y1e7FW+FWxUyQTU2aaKBgLmH4YPnelO8sXSYSZKkZs6KAEQ6BuOk3wBR92O/wOC1lN8rolhEwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/3113e5e31d17506d62c29098723d1894/40a76/hero.png","srcSet":"/static/3113e5e31d17506d62c29098723d1894/c972b/hero.png 340w,\n/static/3113e5e31d17506d62c29098723d1894/27625/hero.png 680w,\n/static/3113e5e31d17506d62c29098723d1894/40a76/hero.png 1360w,\n/static/3113e5e31d17506d62c29098723d1894/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most of the tokens in an LLM request are the same tokens you sent last time. Take CloudCanvasAI, where Claude edits  and  files inside a per…","fields":{"slug":"/2026-08-30-prompt-caching-claude-api/"},"frontmatter":{"date":"2026-08-30T00:00:00.000Z","title":"Prompt Caching with the Claude API","description":"Prompt caching reuses a stable prompt prefix to cut Claude API cost and latency. How breakpoints, TTLs, and cache reads work, and what quietly breaks a hit.","tags":["AI","LLM","Claude","FastAPI","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABw0lEQVQoz1WP6XKjMBCE+RMbEBK3bonLgMGOTRInqayvXb//Q+1gJ1u11FeqVk83U3KGTo+dHlq1Hezt8vb1sbn82v8+Teev3eW4Px9Bv4ADVxCnuwnJoZ1bzoIUS1I+BRbnfb+71sNxPf1Zbc/1eOq219X20j1fWxCb8zDdms0JBKHrJ2yh5QSJAfzIkLzx49INjRcaOFEMpgYfxF1/mwBOiyCeWw6axwVTtSo6U7Y513FmmNAusTB+pFFkSWrSXIW0r4Z3075ldgqS0vFDyBkuzeeO3j7z6zvdDfx6YEmuXKJRrO/7Z/ZrLnUR8U0qh5j1sBXKyiMqzvSm59PIxo4dnikwDZQk0Ff3gITTGn7YZiRiCyQ8wsFxfCJdLDOqqoJbywvLq4KVlvc1fRlzFAoIRan1Q2nUbL6OOY7l/DsiHY8IF4so1VoJJX9QQgjZNbI2kmVVo/ssMYJL+NpKFlbAi/xQOB7my0AUmsfcBnaFZY15FajaC4QfzQtRKBeYS1qqvPRCeIWBfbAWilBmKORK24SZUFSJbjKzwpl2EYUR4GLmE6FEA+BIusG3DzhwARaILhF1UQ7cBX34/1g+Av+bfwHdJ0MNNm91MgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/ee39d6bd9f6285aa6710ac73b9b54026/40a76/hero.png","srcSet":"/static/ee39d6bd9f6285aa6710ac73b9b54026/c972b/hero.png 340w,\n/static/ee39d6bd9f6285aa6710ac73b9b54026/27625/hero.png 680w,\n/static/ee39d6bd9f6285aa6710ac73b9b54026/40a76/hero.png 1360w,\n/static/ee39d6bd9f6285aa6710ac73b9b54026/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"In an earlier post on rate limits, retries, and backoff, I mentioned almost in passing that one reason to write your own retry loop, instead…","fields":{"slug":"/2026-08-29-circuit-breaker-llm-api-calls/"},"frontmatter":{"date":"2026-08-29T00:00:00.000Z","title":"Circuit Breakers for LLM API Calls","description":"When an LLM provider degrades, retries make it worse. A practical guide to adding a circuit breaker in Python: the three states, tuning, and failure modes.","tags":["LLM","FastAPI","Python","Reliability","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABwklEQVQoz12Qa2+bMBSG+VA1gDE2NxuMsWkIxJARwnKBNd32odqXqept+/+/ZYYom1bpkXWO/T7Hso1cPmikOJ+Ob+Pw67B/Oeyfh9Pb8fDa756G03u3/TlvvtyPv3WtkxdFY5iIXSg2g+ofyk/juruvd+eyHXO1r/vzajM0/df19kt7+L6sjwuX/VUMx5OOJxxfAk/YKLOxuBRBVHO+R345tTizULaATJ9Cf85PSAPg7ArXIRMLE3GARc7Hdv2DRBsb85Cobf2Uys4jpTWd6jsmxZin8guUFDJZ0UAAnN6AkNKuXT87WPhRVeTfAloGZAlgAlEKtY+4geN1Vg3LzTnItllSNrIuM4WDvFw+9vW71qCXW4jdOAS5iWL5rmp3RSNDLadaVrwaZX0Os86LK5I1IVdx2qrVo4Vi22VBpNxAwuDOx1zL/WrT3VUiTIGbzm+ev0SvFkwWgNyCyIacUAX9zHRiE1I9Ql/uoCT0Uh+zEDPPY5abGBaklkMtOIV0j0iJk4YXp0I9YKr8pNHTpwyMNYsr5twal90rFEdVJHZx/pkt91T0AWsBSi1IZv8jhumQ/4kWILq1Q40uTM3HwD/+AE3HRJtRV0csAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/0df538f83ed1b79f46a4c41b7c7bb925/40a76/hero.png","srcSet":"/static/0df538f83ed1b79f46a4c41b7c7bb925/c972b/hero.png 340w,\n/static/0df538f83ed1b79f46a4c41b7c7bb925/27625/hero.png 680w,\n/static/0df538f83ed1b79f46a4c41b7c7bb925/40a76/hero.png 1360w,\n/static/0df538f83ed1b79f46a4c41b7c7bb925/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Here is a chunk that once cost me an afternoon of debugging. It read, roughly, “The failure rate rose to 5.7% after the migration and stayed…","fields":{"slug":"/2026-08-28-contextual-retrieval-rag/"},"frontmatter":{"date":"2026-08-28T00:00:00.000Z","title":"Contextual Retrieval for RAG, Step by Step","description":"Vector search misses chunks that lost their document context. Contextual Retrieval prepends a short LLM-written summary to each chunk before you embed it.","tags":["AI","LLM","RAG","Embeddings","Search"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+0lEQVQoz02Q24+aQBTGeXOBAWaAAYbhIvdRUawXUNHV7ibNZhvttunFl762//9/0KP70uSXLyeT75vz5Uim6EnVW6N9ub8U+0t1+JJ0r+Lxa9Ff8t0ZKHrgApR3ffeDApKqc0XzdTMuxLqeH+r5PquW5agtxaoU62K0LsdtLpblpBPT7Wi2M6wY/JACJNWMVTNCVqySSMahgiPiCRo3zvADYPGahlPChEIiADzIHIL/TiypOPyPAJEoyDfTjz+mz9f6+ZrVj2L9EtZHBVa9e+5f3MChpOBAvaMYNxC0INFA57Kdyk6h0Ow2QzsrgV4PmicjV9GYrDEwS4ruy7oPqhgcgPBt0BiiGZ0ceXcO999Y+9mdnrzm2W9frfGB5J0xXEBEMmhC3EK3E/meN2gKlRSdIa+qnn41L7/Xb39Xb3/GT9e4O2eH76y9eP1POv8ECyQ7qCPRB8WGFx3PN0G5MfnUcCvVTrnYB9WOl9ug3Iaid9KVwSaEz6x4gaO5bPgSjWbJ5BiPD36xcYYLN1laYYNdodpJVJ+SyWlYn7ys89LWSVYkaEwADGEj60wiZmQ7GXUzi6a2k5o0UQlclcsG03llxmMSjnAgQGHW3BxugZxctYcyciSkuQZmOvYx8QnhBvYHKn1AgCPrjmb6CDNEGDJ9mOF9oNg3bh7nHzaWUIthr2VSAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/4ec5f89f4346f411a76181b4e06109fe/40a76/hero.png","srcSet":"/static/4ec5f89f4346f411a76181b4e06109fe/c972b/hero.png 340w,\n/static/4ec5f89f4346f411a76181b4e06109fe/27625/hero.png 680w,\n/static/4ec5f89f4346f411a76181b4e06109fe/40a76/hero.png 1360w,\n/static/4ec5f89f4346f411a76181b4e06109fe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A retrieval backend has a nasty traffic shape. For most of the day it sits nearly idle. Then a shift change lands and forty operators open…","fields":{"slug":"/2026-08-27-kubernetes-hpa-autoscaling-pods/"},"frontmatter":{"date":"2026-08-27T00:00:00.000Z","title":"Autoscaling a FastAPI Service with the Kubernetes HPA","description":"The Kubernetes HPA scales pods from a metric, but its defaults thrash and lag under real load. How the control loop works, how to tune it, and where it breaks.","tags":["Kubernetes","DevOps","FastAPI","Autoscaling","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3klEQVQoz12R25KiMBCGvVxPEA6aEMI5kICIs4oiBAWdqtld3/+Bthn3aqu+6urq/v9O0pkhuTe+QaLUxQ5Asky6e9aPXA2JusvhmfZj0g1atvsnEOXbMltobLFm8yVFVmxjYdgcYpo3xV7lpRJFK4sWcll05ia1sLCJ1M1ovnLBNVuavrZJdJwZTm5QabHCpPnaTlY2X01xYr3hACISEWEQAWINKnY8WyLPcAoc1Tg8GX5FxNnyK0RLRHcmqwxaAsiZeOff7KGFnHy20BnCEjk7ABo6zrF/9DPlxpcgUzQ8Y35iVcf2reVViEwyRIppIpFgduHCtn+YGmRnuGXUf6WPFx+AP3x84XOPa+V0903VmKTcBj8pv5CohiNhYVTH0vY/gqoPSuVWij9eUXGP9mO0H+LqsU1q06ss/0CaW/j55eUtSU6W9zGZ55qjw5JJicPj1j04BxV/vgLehXkfSAVTSFhrONdJodvSPjSbq4KnIVzok3lN9K1gxxtrn6wZo+FXdHyGog9lH+Y3APwsvXpZ50tFg7PfPKPnb68eYfNgxjDD4Q0THeBmLY0voPZFz9KWJg3lVxdI2zfQnTRZi0g++7HaLhCDD4O1TyAP8rUVGphrdjTV/8Pw3jJw/QUWP1bhWSFUPAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2b103420edc752bcbc021aafeeffcf81/40a76/hero.png","srcSet":"/static/2b103420edc752bcbc021aafeeffcf81/c972b/hero.png 340w,\n/static/2b103420edc752bcbc021aafeeffcf81/27625/hero.png 680w,\n/static/2b103420edc752bcbc021aafeeffcf81/40a76/hero.png 1360w,\n/static/2b103420edc752bcbc021aafeeffcf81/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time you try to serve a model on your own GPU node, the failure is quiet. You add a node with a shiny accelerator in it and deploy…","fields":{"slug":"/2026-08-26-scheduling-gpu-pods-kubernetes/"},"frontmatter":{"date":"2026-08-26T00:00:00.000Z","title":"Scheduling GPU Pods on Kubernetes","description":"A GPU node won't run your Pods until a device plugin advertises it. How Kubernetes discovers GPUs, how to share one across Pods, and where scheduling breaks.","tags":["Kubernetes","GPU","DevOps","MLOps","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/ElEQVQoz1WRW2/TMBiGc8O6tIkTO/EhB9s5nxdtpOvUNkVsaLTbaNguEHAD//9f4G5wgfTo1SPre2V9tgbFWmEFKy//WC2npH8o3h/bmxcl2eVTc/MSdftyOIr2vhwmmn5Qk5Cv39DmwNdNz0TCl23dr4t2pbIfdkWzzOqhaK/zZtldjWl1rdKXnY2TuRUsXtEMJ0F+RXkLWbVAieHEhpNatLFZa3udRWrodYZbLGwxt7npRMCNDSQWUCE1ixZRsy37OxJ24DR6oQry8me8/B1dfg/7H9HwC0ebuRXqlpgBcWZyJXNLLGyuATex/SuUfTGdGIk1Lp6AEyG5c9K92sVJ7lB8azoJdLlH1W445sSjjusyHagyKXF2wOlnN1Hcq3T+F5w9WP5ACA3J2ZAvbnszxO9ChnQQagCXXvUi22ecf2WletVnN5v8alLipEdeT0H7jcpVzFlA5tedvxtkygHDUAfBqRw2k6wPtDgG9aNsDqRQnUdRn0SlaCcUrgjGuQB16rYZrmIYUDQzfbVzFuZjXG1YsuXFmDQjTUZZjVGlZCvLjSx3tndhQ5pyFIcoCmAhHUbwzGDq5hyKEQQbkt761YGV+6C698o9Kz6z4pPFtxbf2azXTaamZwZ9y3OT6ibV1I8bUBpQnBIp3kSc/N+5+pVzg5wwXzH+8gfzwVSyekC+RgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/c0c1e4720da2467daade0fe540bb7ba0/40a76/hero.png","srcSet":"/static/c0c1e4720da2467daade0fe540bb7ba0/c972b/hero.png 340w,\n/static/c0c1e4720da2467daade0fe540bb7ba0/27625/hero.png 680w,\n/static/c0c1e4720da2467daade0fe540bb7ba0/40a76/hero.png 1360w,\n/static/c0c1e4720da2467daade0fe540bb7ba0/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Text generation from a transformer is stubbornly sequential. To produce the tenth token the model needs the ninth. So a 200-token answer…","fields":{"slug":"/2026-08-25-speculative-decoding-faster-llm-inference/"},"frontmatter":{"date":"2026-08-25T00:00:00.000Z","title":"Speculative Decoding: Faster LLM Inference","description":"Speculative decoding uses a small draft model to guess tokens a big model verifies in one parallel pass, cutting LLM latency with no change to output.","tags":["AI","LLM","GPU","Inference","Performance"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACO0lEQVQoz02QS2sTURiGx6TJZDJzbjOTyZxL5pqZXG1unaTmWopFi8HeEKFgXZSC4mXjQlBw47ZLf4Au/QEuRFy5EsSlO/+Lp7oRnsX7fbzP4eMoTX8maXjTdriYj+6uxkfLrcMbvTtXOTv6Ox5MB+udyfG0v5bjYuugEy1lX1qKipiKeBFSTOuNwbwzWjX7s7CVJde35djozeLupN7dlksZ2sNla7iweFoAVFqKQTzD9CXACnTsGdiHdgytEFoRtP8RGkQWApmBFepX2b/aEF/RcU2DvASYjoXM13SiWrxk8pIlYDUynAC7dRVR000IrZs0QXaoIS7vLWOhlJGwWcqDrjRVSB/OXtwfP1m2T/b7Z81gMW6sGevH4ZTY9ePe+SxZF4CDzVC4m4gEUuYs6MbNDNnBhuF8ufj58ezrh9NPny9+XB6+//b418tbl9+f/a57k9e7l6fZ0zysCL7ZjVeWkyplyFSjWtQd+YoGaddfpGKSiHHHm0ds1AtXPu1n8R7EHnPatpVokOlEfnBVx1yRArA8VAk1QGXOGWYO2HnM8sgtEVHAXDO9AhGAePNk3fFmRcPREYeWryGmaMCtiKaI+lj6iD3aeXO+fJVGq15jX9RGUTR3eJ/6me2kb/fePcie53TTpmnUmkhfytWSIXHKkKqgerNzb9U+zBq3dzonvhi0o0XFbdVqA2wHw3A3pkMVONDyJAbhitT+RylqeQ1uADsHTA3RIqzomGnINYjI6SRfJrKj6pV//AHvI13EQ+DzCAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/d9b4468e96fefd425a311dd41e3dc69b/40a76/hero.png","srcSet":"/static/d9b4468e96fefd425a311dd41e3dc69b/c972b/hero.png 340w,\n/static/d9b4468e96fefd425a311dd41e3dc69b/27625/hero.png 680w,\n/static/d9b4468e96fefd425a311dd41e3dc69b/40a76/hero.png 1360w,\n/static/d9b4468e96fefd425a311dd41e3dc69b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time I sat with the latency numbers behind Archi, the retrieval copilot I worked on for CMS computing operations at CERN, one…","fields":{"slug":"/2026-08-24-prefill-vs-decode-llm-inference/"},"frontmatter":{"date":"2026-08-24T00:00:00.000Z","title":"Prefill vs Decode: Two Phases of LLM Inference","description":"The first token is slow, the rest stream fast. Why LLM inference splits into a compute-bound prefill and a memory-bound decode, and what it costs you.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB5ElEQVQozz2RSY/TQBBGfUq8b+3eu+0sozi24yX2BMwkGTEoQsxhGAbBAXHl//8GyglCerK+qurncssGkycuT1Qcs+XTcPjZ9d+r5qU//Gj7t7J+afbfoGz3b3X3+j/I9JGJI1iGFQo7lFYgiN5u24e8+ZDX464/F90RMjw39VgN5ym3Ryir/oxVbgYcLMOJ0iuZhxYQ7HAqrVBDuGEFygyk6Qtg5tGZx5xYO5GCY4YTasAFP9Rzl9/KK+n1i7gf3wVow2TP9SCzUabvwySHJpwx7EABkJgu0nXjRqBNHdOnbrTg8qz0Raqn5epZpZe2/T2OfxiHO5/sYJIlCCFZqWW33Z3Vsmd6B52EDuu7VyYe4mQHhKikYtiUH5v+CyyPcQmiYfvCCWRE116UzV1m+RSRZrF4zrLPhO0RrhPSIdyipJFqFHLkYlR6eiOIhuVzOxARWZke4apPFxchP1F2T0XHxD2X75gY4qQGgqgI4zJCVRRXISpANCyPAbbPiThU5a9t/hU2aH1S+oRJBxvQ1cS41ek5zR4pGxBuoqS0vEmmlkdAjnHh+MKL0jBZE1kxtcO8uJHwgsoK0TxAKz9ewgVd+IUeNUyX3JjZaO6SuYNnTjJ3MfBv5GG4kTmNkmnk4Inr9C98Qksg9Y7QMwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/40a76/hero.png","srcSet":"/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/c972b/hero.png 340w,\n/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/27625/hero.png 680w,\n/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/40a76/hero.png 1360w,\n/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"One afternoon a RAG answer came back slow on Archi, the retrieval copilot I worked on for CMS computing operations at CERN. It was not…","fields":{"slug":"/2026-08-23-opentelemetry-tracing-rag-pipeline/"},"frontmatter":{"date":"2026-08-23T00:00:00.000Z","title":"Tracing a RAG Pipeline with OpenTelemetry","description":"Trace a RAG pipeline with OpenTelemetry: instrument FastAPI, put each retrieval and model step in its own span, and read the latency waterfall in OpenSearch.","tags":["OpenTelemetry","Observability","RAG","FastAPI","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB7ElEQVQoz22Qu47TQBSGvUGbxI49Hl8ytrOJPZ5x7NhOsL1xks1lQ3DYikueYBugWdHR0dHwGhR0iIfgTRASoqDmBTgOiAWB9Onon3/m1zlzhNTjQOyyTTbdFuVlMdvPV6tJvi1mQDVf7srFZV5Ws+X92cU6O09c9jMCCE3VPUUDSWdutODjdVTskmnlJ6tgsgmzLUDjCz9djYodaG+0aGu0iQYt1QUERfcAZPiKQWXd62guIOu0FrdHT8IDRXd1wgzCVNMHR9ZcAZkMk1AlwZGhah0ht+C6BqjL72DeMGPBGCEnUbtMUvuCDD27/DfoH8BUCW/p/Ply/LqavLm6O2ZhU6OdY5j+Gf4vmHABs4/X0y83+feX5aFIBUQVfFaHERmierC/gIGPgsMVJkFD4+8O6bcX+debfJ9EJ4jKqFeHYfIOVJMhAk+H0Aq0BNsy/aP24YcNjb19GH5+Fn16GlXx8ESlHWQLsNh+uKTJFvrQ5F5ZXTus1HtpPHt0FizAtLzcdictI3i15h+eBO8fByUPTjGVFEuQcJ+Pt6NiDyvt82l8/oAMJioJw3xvezmsOsp2PN0gbZCx8DCfXmVZ33JbMqnDomKJyBFVR0S2qDgSctqKXTu/sCXUE1GvLVsatk3dMTRHRhaE2zL5ASInVm+4pGA3AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/b6acffc732f92430e93409753d062d6e/40a76/hero.png","srcSet":"/static/b6acffc732f92430e93409753d062d6e/c972b/hero.png 340w,\n/static/b6acffc732f92430e93409753d062d6e/27625/hero.png 680w,\n/static/b6acffc732f92430e93409753d062d6e/40a76/hero.png 1360w,\n/static/b6acffc732f92430e93409753d062d6e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"An operator types “why is the spring transfer error back” into the copilot. The retriever hands back three chunks about transfers in general…","fields":{"slug":"/2026-08-22-hyde-hypothetical-document-embeddings-rag/"},"frontmatter":{"date":"2026-08-22T00:00:00.000Z","title":"HyDE: Hypothetical Document Embeddings for RAG","description":"Vector search fails when a short question looks nothing like its answer. HyDE has an LLM draft a fake answer, embeds that, and retrieves against it instead.","tags":["AI","LLM","RAG","Retrieval","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB80lEQVQoz0XRy3KbMBQGYFZtjNAFhAwIjG0wBoQwl0lwsOM4jttML4usOln0/d+jB2fRmW80kn6dAR0ZOO+sbUuLPj29rY/f0qe39eGaPH1fPr4mh2+rcZpnzz8W+xdIl48XUvTWtsM3BsKhaUlHpHV7LutjoUdVH3VzUrtj3Z0LNZZqVPqQF4OqDrDkYgPnEYmAQUXKvAxgsZmxBTDt+P/oZ2aUm0GGomIms5kdW+4a8RVyYmB4yy7bXYr2teyu0WbgUSMWrYg72y9NGmL9QMYr2b/gxwt9ONNqT6qB1CPOOkQjg7ipE5Rclo5fcKl4oG5LRcXmjoSiP3Xvf6uff+rfH82vj+313enPrHsmejSheIaDr2gOviBB3RUTa8xj6i6xE8+IpCsdtk+yPsjdIehP9ra3ksZKWxSXJpHw5YR5+Sc31ERsAHZTy16aOCBpwevWVQ1XO9EPbtWwvGJlTdMCUmOqidrpnovWjXZOqCdSw3Vm2Lezejm8pPtLMlzS4RLfn4S65/qBbTSkn8UNv3HCHQsq4MjqVuxRN3P82vY08ypABPxgaXuKOAmkBrJjeC0/yP1I+WExD3LuZZazRiyCGN6DzbN5pMWi4iH0sgBEJMieUgNadYcEJh5lcmJLTKGF4s6ag88JosGE3DA57VvT/j+Q/U9do1Ac+wAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/90f3785213ffc1873444a0b510a7d3fb/40a76/hero.png","srcSet":"/static/90f3785213ffc1873444a0b510a7d3fb/c972b/hero.png 340w,\n/static/90f3785213ffc1873444a0b510a7d3fb/27625/hero.png 680w,\n/static/90f3785213ffc1873444a0b510a7d3fb/40a76/hero.png 1360w,\n/static/90f3785213ffc1873444a0b510a7d3fb/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time I really understood prompt injection, it was not from a paper. It was from thinking about what happens when Archi, the…","fields":{"slug":"/2026-08-21-prompt-injection-defense-rag/"},"frontmatter":{"date":"2026-08-21T00:00:00.000Z","title":"Prompt Injection Defense for RAG Systems","description":"Retrieved documents are untrusted input. A practical guide to defending a RAG copilot against direct and indirect prompt injection, and why filters alone fail.","tags":["AI","LLM","RAG","Security","Prompt Injection"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQoz02P+26bMBSHkaYtTUhCAhgCvmBsYwjYXAxJ2oY0S/vH3mDv/yhzN02b9NOnc9Gno+M0RNdYDcI8xsetf3tM72/D/eP8YYu7uVt+Hx/Xbrb8M7kP399PHy3rreUsPPxlA58CmutX3s20ec7Vq+hulbnz9iraWXQz01fZ32Q3l/2b7G6yn92Aft0ix90TABiOOAoZjAU8SJTINBbAp1GQh2EehCwEbL0nqx1eemi1Q8stdHfYThy7vsnzSPspNzUzXXnuy5OpLjXRXT4YMY1iepbniSrXzzzAtkG+CbKNT90dcaIw7/gYJHWZ9z0fENZpchRZ15aXSowINRipDKsLVftYAqT9Q+lFwgP8UwYh7fmYQPVDvfyc7r0wGe0x6SDWEDY26WdUQ9Q+KgCsrRwk5RYwd4ccEGRWjmBTF6ORE+VdISdRTExMELfJX3mg7erz4cwetA8v1slymzhhQAY+xskxJdreh0ilRCFUE1RT3NBMZaQhRMusQBAzyvOMYUQtPR86oY81MyHSkA0RUQCrGKmEmwhrkOkY1of0CHFTUlEJduqbqa0rWdAs9/zUyuhavZTlS1vPsryUx/ORn3Q9V8VF1M8VMyXtj7kxtF240XITL9ex5bdV9LSOndUm5gfBYp7H3JLb/G7/1QdRJEXk44ULntbR//kFE0FZNhTam00AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/4ee9029b7de0dd2bab142f433a952db9/40a76/hero.png","srcSet":"/static/4ee9029b7de0dd2bab142f433a952db9/c972b/hero.png 340w,\n/static/4ee9029b7de0dd2bab142f433a952db9/27625/hero.png 680w,\n/static/4ee9029b7de0dd2bab142f433a952db9/40a76/hero.png 1360w,\n/static/4ee9029b7de0dd2bab142f433a952db9/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A while back I wrote about measuring RAG retrieval quality with recall@k (did a right chunk land in the top k results) and MRR (mean…","fields":{"slug":"/2026-08-20-llm-as-a-judge-rag-answers/"},"frontmatter":{"date":"2026-08-20T00:00:00.000Z","title":"LLM-as-a-Judge: Scoring RAG Answer Quality","description":"Retrieval metrics say the right docs came back, not that the answer is right. Build an LLM-as-a-judge to score RAG answers for faithfulness and quality.","tags":["AI","LLM","RAG","Evaluation","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACD0lEQVQozy2P2Y7TQBBF/QCTjNf20m67N6+dOF46sZNJHGfxMEiARgLxwDMS//8T9DBIR6Vbt+qqVNq6xNOpna/9862/T9tP90G190nOl91tktexu53l87W/jN3l1CoxX3eDLCtB6hXVPpjMi2sujnX/uWhum/6laK4r+bySs+jmfHMp21vVv6gqunvdv+TV2cf1g8UXdqpZfqK7TAfUcLnpJTpQmhlvzhumyw01cqiqj4AtHbawyNKmOlDLXENJT8sxzp5c3Hqks4JcJSFt4nQXp1uUdHaQWzAz/MSHNMIEohjFBEbMBEzzs120PSN5hpsnl3U2KnWXhlxScVQETAJUB3lv43WW0GLd7E+XYrPNyxQEVPPzXbifwuGs8IqtHRa6S0LW8dWRFHuFFzde2tlYcM5fZ/7rS/L7OxGr1PGJ5vEOisM7SltBpgPskybK9ijto2xwcQNSacWCMfbjW/r6Nfnzk3ab1Hax5qvH5Ii6EbZHN5EWzFUYs6YQh7wcSnEgpKWZ9OIy4YSPJzJf+sPUitLyIs2L2wBLhR936j3HSwOA94W81cdr9XQSQ5u0U9lXsSCcVJVYr1eiWheluhxphs/xMNLDOdgenLTSTbS0UBBwHpc0Knhc+B51ADbsyALI9UPgKaDjokcLaUsrNCAzIddD/giipQGXZvhgwI8GfPiPakNlLt589M7in/MXpRdTQrGmqsQAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/7084089adaa1a7af370ff3e404bd44b4/40a76/hero.png","srcSet":"/static/7084089adaa1a7af370ff3e404bd44b4/c972b/hero.png 340w,\n/static/7084089adaa1a7af370ff3e404bd44b4/27625/hero.png 680w,\n/static/7084089adaa1a7af370ff3e404bd44b4/40a76/hero.png 1360w,\n/static/7084089adaa1a7af370ff3e404bd44b4/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A retrieval request in Archi does not touch one source. To answer an operator’s question, it searches the logbook, runs a keyword pass over…","fields":{"slug":"/2026-08-19-concurrent-llm-calls-asyncio-gather/"},"frontmatter":{"date":"2026-08-19T00:00:00.000Z","title":"Fan Out Concurrent LLM Calls with asyncio.gather","description":"Awaiting retrieval and LLM calls one by one wastes seconds per request. Here's how to fan them out with asyncio.gather, bound it, and handle partial failures.","tags":["Python","AsyncIO","FastAPI","LLM","RAG"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3UlEQVQozyWR6Y6bMBSF+dVJ2IzNDsY2S8gEJguEkDSTqIumI02lblP1/V+lh0T6ZB0f+9x7DZqSF5Cr67D/dTy+H4bfffdjPPzZ9z+xwgQQx/H9dPyLIyme7xGgzUgCSFDU69Oquyx3z1V7bPpr1Y5tf11uz/X6Y9NdALZlO9p+/mDH95RmUgkspgwnY35BvUJ3sjnJdEdAYDWovGkB03DEdJMKc0JqyABsiF9VRafUFsJ0pcGEecNgqJXqDp8c+Lf7dzSdcN1OLa8gUZMtT1l9grDcXCep4fApQwVvuqhsUYJVDYSXLacU4Qinup1YrmLphlfHtBwhTKZg6iTBRDRpfbnxxYbGjeVh5tSgfEqRVMOluRVRt5LpuRCXUlwVPzushKlbMV7I+LZ6+qRWZyduUUu346nuDW2OT2eFrlsL7/BUvjT5VxGMqDWzIhwZNLOjJU2aMBtCvrdZ/sHw70dAQ4eZGTB3UfPPrXpt5AsEZSVMFLWIWOCXJqdd/X1TvfK0T0TrePnMDBFEOJyZPsJZMHSrt3X9LQsP9Db23I6Ik593/7b126P6UstrEm+9sKJejhTQpg5Tk8iPHmOxjrI1CxbTg6fnRDYTqhjycpB5L1VvOvzBDB7uETP4Dyi0SscBzjsMAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/8562546a0ec941aaf484051b6f70cfca/40a76/hero.png","srcSet":"/static/8562546a0ec941aaf484051b6f70cfca/c972b/hero.png 340w,\n/static/8562546a0ec941aaf484051b6f70cfca/27625/hero.png 680w,\n/static/8562546a0ec941aaf484051b6f70cfca/40a76/hero.png 1360w,\n/static/8562546a0ec941aaf484051b6f70cfca/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The HNSW post ended on a bill I did not pay. HNSW makes the search fast by walking a graph in a handful of hops instead of scanning the…","fields":{"slug":"/2026-08-18-product-quantization-vector-search/"},"frontmatter":{"date":"2026-08-18T00:00:00.000Z","title":"Product Quantization for Vector Search","description":"HNSW makes vector search fast, but the embeddings still fill your RAM. Product quantization compresses them ~32x with a small recall hit. Here is how it works.","tags":["AI","RAG","VectorSearch","Embeddings","FAISS"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB9klEQVQozz1Q2W7bMBDUmy1KlERRsg7qMnVbR2w39SH5StLEboIANdrH9lP6713ZQIHBYriYmeWuoOc9KXq92Knphm/e66dfxeHKNx/F/ke8/Ziu36vTT76G5zV4fFPTrV70JB8AREDYRdgBYM2Pkvms6au2T8vVrO3yap2WX8tmm83W9XwfxguVRqCXFBcpUJkg6aFsTLGVWVFr+JXOSmUSSyQQSYBIIJEQaQMRtUCmETamoP8PQXcqVr642cHLjizdqSaXSaAYsWIm+FaBS6qHKVcMjkk4EDOBdEnzBeq2QfPdK569/IllRxlGqQwbXJ2kxM6hQgRSPZlEmteQZK35rWLG4IQmmBu/vrD8aTCne1kfzLI+Nf120X3qzkymMdI8WWHGwyv//Ze9/MF0ejMzgTq1X59ZdvKykwtm2FBxZX1YT3cL+ALw4ZxwFxobfq1aGb4tAjLYGcyX+7fd9CARX1RsM1y6+cFNOpb2wMfYglEOXwTFKixW2iQRFQcgELv0ymeLd07cO3EHkSK2/OKYPF6j5pwsP4GPkKEED/byYs+/2YtXo9wjjYmyJcAcYDz/YrF8jG1xgAWp1EnzZkvtRMSOiCfI5FbVBauzVe/UsAEXyISxPAFoRogJG0nm/QkEYYuYESjuzRGiY0QlGkL6SNTvsn9m7U0QrDp1ngAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/4cc29e9488098aed49e7246f0af47f78/40a76/hero.png","srcSet":"/static/4cc29e9488098aed49e7246f0af47f78/c972b/hero.png 340w,\n/static/4cc29e9488098aed49e7246f0af47f78/27625/hero.png 680w,\n/static/4cc29e9488098aed49e7246f0af47f78/40a76/hero.png 1360w,\n/static/4cc29e9488098aed49e7246f0af47f78/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Two operators open the copilot within a minute of each other. One types “why is the transfer to T1USFNAL failing,” and the other types “T…","fields":{"slug":"/2026-08-17-semantic-caching-llm-apps/"},"frontmatter":{"date":"2026-08-17T00:00:00.000Z","title":"Build a Semantic Cache for LLM Apps","description":"Semantic caching for LLM apps: cache answers by embedding similarity in FastAPI, tune the cutoff, and avoid false cache hits. Working code and failure modes.","tags":["AI","LLM","RAG","FastAPI","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABwElEQVQoz1WN6ZKiQBCE+SdXNyAj2gdnQ3MrA4LgzBhqzPs/05ZjjLsb8UVGVnZWl2Lljdf25e1bfFyyz6s4X+TlniwXMPH8WV6/5dcNctB4/opOn2De6s7OG6doFR1xZId5tchqyeulqM9td83rMwDJ/v3WdNd9fyuajzgbEzllxQk7kYa4gX3FXAe6zVWLGY6v277uPNBsX7U46Aqzp/nJA2MdQFOzfMP2wStRehDFlORDlPWinPyk27FsqOV9bq5Tc5/b26md9vnQZMdGDnW2dOX91HbnDsEyiVs/63n6DoBhotuEFREySiT3BWMxQEhEWQIQmoCHxGOxYXPFjfYkOwJUAiPNRlccUFLgrdDsYGWyFWIq5qYbm+vYcCIYHwliusWUrehYduRyJOmASWGR0gorOy1cmiI3gAZcMGyo0ifgn+iYKm7YeMnBSzpQN2wdXllBicMUb0LD4dDQofda+OcXDRPFiw9wmYqeioGI3iHV47Is11Sgta+h3f+Qx3ewjCmMimaRF6pFdBsedqrhqeYWFIeSjjOfFj7ObFpwXKimp6HtEwWGn+ovL4/Ab3SXmbvowTYE1d/436bp/QEKhUqevXKzkQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/9d14570bff46c536f588658086d0da12/40a76/hero.png","srcSet":"/static/9d14570bff46c536f588658086d0da12/c972b/hero.png 340w,\n/static/9d14570bff46c536f588658086d0da12/27625/hero.png 680w,\n/static/9d14570bff46c536f588658086d0da12/40a76/hero.png 1360w,\n/static/9d14570bff46c536f588658086d0da12/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Here is a result that surprises people the first time they hit it. You load a 13B model onto a GPU with plenty of spare memory and point…","fields":{"slug":"/2026-08-16-pagedattention-vllm-kv-cache/"},"frontmatter":{"date":"2026-08-16T00:00:00.000Z","title":"How PagedAttention Powers vLLM's KV Cache","description":"A self-hosted LLM server wastes most of its GPU memory to KV cache fragmentation. Here is how PagedAttention in vLLM pages the cache like an OS.","tags":["AI","LLM","GPU","Inference","vLLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACGElEQVQozy2RXW/TMBSGewVN7Dh2bKf5dJLmo02aLF3TtM26rptg0wQb7IKJCyRuds0Nd/wRkPi1nALSK+uRdd5zXvuMWDj8lxqK1QNo1j0W3WO2fA8CSJr7sn9Kz+7j+u4E7TvT3/6zjHTT101PI57Bo/nZMGuGst0Xi21W9gDVcp9Xm/Vwu1hepvN1fX4AIDwCFzL9EWLK4AmmLmYOkSm2IpAhEmCdRRq0ZkozQ52eNCYBnFCAWAjGEaKh8OZp/yXdvNj+3E+3XrZzk5VlJxqymLvATCEzwFZiiNSUKTQlIgXGPIHYAXOr7PA9O/6A8E5xI+MdlNJgo9YvPGipnSEaEFlMknVYHlR5iBZXwMSejTTiiqiTqjXllDkVnWTUmROZhe3n+sPPMRLp/pucXo2ZKvPN8/rm7mz/dftmOu2wLEaa4cioF6ojdiGi3quf7ezo5NeT9II6M+bWzcdfzvwBMX/it8prVDzEfiPc+u9kw6FOCcMhPHWb5um3TK/hbcyrqbPg4Yr7DbYU4aloNuJ45NsrfnmQ3QUR+cmMWWhYMZG5iNZCncuos9SO+iuIg3lM7BwWY4jMqYZk91atjmp5dKsB6kdjbHPVe/mlCFsM2aY73bDt6pOd32Lq2UlvxxvYJSzGchfSa6Rfy6DhsAX4bTAjKzNgOAsMKzCYpxmTMeIAxAp14rxGYowl6DWSr5A4SRfAcPMHPTVTeXIlg6QAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/40a76/hero.png","srcSet":"/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/c972b/hero.png 340w,\n/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/27625/hero.png 680w,\n/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/40a76/hero.png 1360w,\n/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"In an earlier post on the KV cache, I listed grouped-query attention as the first lever to reach for when GPU memory runs out. Then I moved…","fields":{"slug":"/2026-08-15-grouped-query-attention-kv-cache/"},"frontmatter":{"date":"2026-08-15T00:00:00.000Z","title":"How Grouped-Query Attention Shrinks the KV Cache","description":"Grouped-query attention shares key/value heads across query heads to cut the KV cache. How GQA sits between MHA and MQA, with the memory math and code.","tags":["AI","LLM","GPU","Inference","Transformers"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2klEQVQoz22PWY+bMBSFeWjDjlltMBizJSEkEALJdLKRh1E1UqfJTF9aqf//h/RmaCtVqvTp6Pj6nGtZKPlx5Njd3rledt+Om+uh/Trs3s7bt3P/Cma/fjn1t337MmP7vxVBROHEoKrD89Wnqhumzb5sT+XmVNSPQFL2s/Vx0Z2z5QPMs+pBsWMRUWgBgmZz3eaGk4JRzFg1Y1DJCDU7MfEUVNJD1brPZcQUxDSLgwcFBEmnE9UfUU0GyEYYxHVc9CResbwDDxnVYibOEE5NkukOH5NCNu/rbqjWx2V7grOkB5DGUUXxkuHadWZRum6qi4pYvRj61VO3euJxK8I6xATHn/qsItECR6VsUOSmvNgGbtXE5yLcXeavnxffn4cfxC8nClGNSNFDBf1GEDXyUXE/yI6oYknzLS936bwgmyTcTsLiUF6H6Y0nbcwb/f5nKhsBoBgUEJJwU/L9MjkZNpd03/RSGtccNwt2oFFbskfqlCSu4OUvzU/qVxK6N8cVAnK44+W2l5tuoiIqaZilLXIS7tUzvwe1vCxK1rLuk6gK4pUTTMGPCJAWVe+OhmWdyBpWUMCyNoiWyE1AwcsGRIkEt/8C5fv0j+L3XVjUPJvkHp1bOB33Sv/jF5dTSoR2B0eaAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/737643482065a12c3b04d10612fdd8ce/40a76/hero.png","srcSet":"/static/737643482065a12c3b04d10612fdd8ce/c972b/hero.png 340w,\n/static/737643482065a12c3b04d10612fdd8ce/27625/hero.png 680w,\n/static/737643482065a12c3b04d10612fdd8ce/40a76/hero.png 1360w,\n/static/737643482065a12c3b04d10612fdd8ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most of my FastAPI services sit in front of something expensive: a model call that costs real money per request, a vector search that pins a…","fields":{"slug":"/2026-08-14-fastapi-token-bucket-rate-limiting/"},"frontmatter":{"date":"2026-08-14T00:00:00.000Z","title":"Rate Limiting a FastAPI Service with a Token Bucket","description":"Add per-user rate limiting to a FastAPI backend with the token bucket algorithm: an in-process version, an atomic Redis script, 429s, and the failure modes.","tags":["FastAPI","Python","Redis","Backend","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACEElEQVQozzWQ2W7UMBSGI3WZ7IkTO7FjZ0+afWmmdDrT0lbttIhFhUIFXCKehEseg0VccQGPiKct0nfx+0j/8WcLmJ4QeuKSVV48G6a33fimG1+Pcx5uhum2HW7q9tX+wbt+fzPvhg1JfuV6x7wlSKYnAzrTMEv7/aPLalhV43EzPc3bBQ/1eJI3h0W/LIdVOSz3ukU7PyVRI+pENqmggIAjm75kMNFgkuErgEomEQ13pqNdDXJ2VFvUPRXEupUoRqiCUDEDjqCYvmpFAO9xdCfT7Lhu7obxc1l9zIv3cXqbpLdpdsclTZKxZo6yxkpKg6WKFQiSTnWUsnyBo8lmveFkhwdfrs9+rU+/XZ//vDr7fnX+4/nF77L8pDDmTB0aGrstzSpXnFCQDSqbTN4Is3t5yq00K1ZBpFkJf9gDXJBfw+U50mOFCpJGdJiE5TGOD1A4AVysjr6+WP95uf6bVx9QMLnRkRsvIZ2bUeYtBjLvUF+BOleRz7UJ36HBWLVCGYR8JfGWQXDBAU7Nv8OECcewIhFQ0fEfQdzRE0TVVUGAw8HxOxr0AKWYVHBDUbKy8ivX61w6OKSmNiucIEd+Bv3UpqZBeNlRrQCy1iZVnj+Bbk5IjdmIaV+FbR22mHaYbcoeZA1NCxLt4SiGzHgoiyraVeBMQVuidR+geM+2grZlJP4/7ijOlryZ8DnPM9X5B06KUziMKam8AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/71976257c3eef0cc9cb8c8710a4c6c3c/40a76/hero.png","srcSet":"/static/71976257c3eef0cc9cb8c8710a4c6c3c/c972b/hero.png 340w,\n/static/71976257c3eef0cc9cb8c8710a4c6c3c/27625/hero.png 680w,\n/static/71976257c3eef0cc9cb8c8710a4c6c3c/40a76/hero.png 1360w,\n/static/71976257c3eef0cc9cb8c8710a4c6c3c/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You need to change the mapping of an index that is live. (The mapping is the index’s schema: each field’s type and how its text is analyzed…","fields":{"slug":"/2026-08-13-zero-downtime-reindexing-opensearch/"},"frontmatter":{"date":"2026-08-13T00:00:00.000Z","title":"Zero-Downtime Reindexing in OpenSearch","description":"Change an OpenSearch mapping without dropping writes or serving stale data. A step-by-step reindex with aliases, the Reindex API, and the failure modes.","tags":["OpenSearch","DevOps","Observability","Search","Elasticsearch"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB9UlEQVQoz03RWYvbMBAHcL80yUa2ZEuyDluWLB+Jc2dzbZLd5uim2y196lMLhX7/j1E5hVL4MQzD/IVgvIkp/2lSc17trtv9x8fNp+3hvN4d56vrZu8m++lilNmxKf7f97pIOx2Y+XEN+VA3+3pxspNjPT9VsxfTPA2XFzcxzT5gQ59WHZS1+/eU50f6LvOxAcQirCNiEDUB1g7mFaQW0TzABhJX75utNnUP49zHNiS5iLWVlouKisoFQJSnxZIkDZGNW2gRG7QKEGkQZh5itRocud0Wg833t28/bu+Hp9dm+2W2e5/u3pv154nrn77moyMSE6IWOJ1jNYdx1Yep5x5AcQlpgVgZpePMjN8WMyqbOBnyZJCbMU+GVNSzzZWpUQ8qEBn3BRBlfZR6D1A+BKLnC4SVtSOuhuuqzllKw2hRqENTNFowFCJeT9fXOBul5RJg0wtkHyYeQBIi5qCQo1AAxBWT10G+1PJ5oA+1fq6zpZG5ULeXy8hWA22tVD4UPSi9GMerKlkUiYmRptBQmJDgMcOvFTsV9FzG55JeXG/J21j9vu1/Xbc/z6uEyQ7gHoCcRBxjHoYxJoLGKaUJwjKIBGxJiGXbYOkj7oe8nUTSpR4C7nV91gGtD4D1wzQg7QGDKIP3OzuQaNhW44eqC9hfPb/1B023S6Sztnk7AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/b78a3a6b876e8bd49503a2378a13233e/40a76/hero.png","srcSet":"/static/b78a3a6b876e8bd49503a2378a13233e/c972b/hero.png 340w,\n/static/b78a3a6b876e8bd49503a2378a13233e/27625/hero.png 680w,\n/static/b78a3a6b876e8bd49503a2378a13233e/40a76/hero.png 1360w,\n/static/b78a3a6b876e8bd49503a2378a13233e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Every vector you store in a RAG (retrieval-augmented generation) system costs you twice: once on disk, and again in RAM. An approximate…","fields":{"slug":"/2026-08-12-matryoshka-embeddings-rag/"},"frontmatter":{"date":"2026-08-12T00:00:00.000Z","title":"Matryoshka Embeddings: Smaller Vectors for RAG","description":"Matryoshka embeddings front-load meaning into a vector's first dimensions, so you can truncate them for cheaper, faster RAG search without losing much recall.","tags":["AI","RAG","Embeddings","Vector Search","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQozz2R346TQBSHuZOZMzPlf6EwDIVCKW1pWW0DW9vaXeN2d9PEx9B7TfQhjFfGd/DGW298Nw+6MflyQs6Z7/Bj0FjRcGR6RSd1uDmku9equ8mP52hzRIrjvWpvku42P5xVe5rs33irDvIVKihqIKInBjItNtVyt2yO89W+qNpycV03h3J+jWATR/PlTo3XwCPgIaKBFYOlsDJLIdRKqCF7TEWNmBhSuCl3EjKIqKWIO2bDCRtm4KXgjjUw5BPoy5Ilc6z9sxGDGRteNqm2vpxREYKbsKSCuISkYukCwkKjuBLB2SjHL/9Lw6KSmTG+XzjjrHyBMuEjcBLUetNJ/q1GOaRGRFkAsuTrjtdbvm5ZPANcZ0puK5U3TpATHlBbgZ/1KzCXGWNYjYoRxYElWVbz7sRvz6I7iXyNJ3AkLJUWV7af4RlwFPNSbkTsv0xEQLgPcspnz8X9xXj/Tlze8sUW0jkxI+oqqkrdls+Iq7sxdROK+QcRM/DvhBqa6IOa8VVrfvrg/fphfv7IFxu8EhxhomHROOOFKUuslqpsVYmw6PO7CcpDwjwYTXj3yv72Zfj7p/39K98c8DIJOOCnSXeX7x+ylw/T4yXfP+aHR2+9F1XL80bTmaczVxc+CVIoa2i2tKxJkGFHh77fZ7aiHjPU+xphh7iKWNEfjoNO/UjSMDQAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/9564d1641bc95b0cb470629a8c950a45/40a76/hero.png","srcSet":"/static/9564d1641bc95b0cb470629a8c950a45/c972b/hero.png 340w,\n/static/9564d1641bc95b0cb470629a8c950a45/27625/hero.png 680w,\n/static/9564d1641bc95b0cb470629a8c950a45/40a76/hero.png 1360w,\n/static/9564d1641bc95b0cb470629a8c950a45/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"When I wrote about why GPU memory runs out during long LLM runs, the culprit was the KV cache: memory that grows with every token you keep…","fields":{"slug":"/2026-08-11-how-flashattention-speeds-up-attention/"},"frontmatter":{"date":"2026-08-11T00:00:00.000Z","title":"How FlashAttention Speeds Up the Attention Layer","description":"Attention is memory-bound, not compute-bound. Here's how FlashAttention uses tiling and online softmax to skip the N×N matrix and run exact attention faster.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB0klEQVQoz0XQa6+aQBAGYNK0gsIuiwJ7X64iyE2PtrX1cjym3/p/+vs7FpMmTybDsu/sgrU1HeiS4bq7fRwfj6+P++EO9f3tDs79GRbPw+W2v13G623/PplS1szXtq+hsnzc7G7VeCm6n3n3oxqv0Gfb02Z3zdpTvX8v+jNsWPcXsznOsIKU5QVmgsOMxIUf5UFcLmkJjy7RbmBsJGwkHSznvpo4WCx8uSDaeu4gGi0TU+51Psi0U9lgijHk1QzxMCoS06fJIGUbszrmNWU1FQ2XLaWVtXgOk3OiHF/ZWH5B4pPLfGLCVQoy3dWb07g95/kx5i0THRW91KPJDkr1EJYeUctVItla8srw6lf9XYktWmUk0IY3KqqyeMNWZUI3QETrkjcla+AK1hwLQpSKiyEb+rT/Vuz+nH9rPbhhYSPKWZWbXZ7stGhTPQDFt6kZ82QPB0CYO4g7UDH8FWFj8RnxBVFwI3iFiYLzg2UCojgXqqG8AqtV6gfamiMGFli4RE284Fkh7HgxDnORv6Fo7YUlYTXhjU+flYgWRQWE6T9s4YsnLF6NLxw3CmhV9neWHUCc7CEW6gFAH8A3w/gXRCfTOMej07rtxnPMXhD9v9+L/wIza0l/29XgfQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2d6b9a4a8b053eec65ba5b226b112ebe/40a76/hero.png","srcSet":"/static/2d6b9a4a8b053eec65ba5b226b112ebe/c972b/hero.png 340w,\n/static/2d6b9a4a8b053eec65ba5b226b112ebe/27625/hero.png 680w,\n/static/2d6b9a4a8b053eec65ba5b226b112ebe/40a76/hero.png 1360w,\n/static/2d6b9a4a8b053eec65ba5b226b112ebe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time a FastAPI service I ran fell over under load, nothing crashed. Requests just started hanging. A handful returned fast; the…","fields":{"slug":"/2026-08-10-async-connection-pooling-fastapi/"},"frontmatter":{"date":"2026-08-10T00:00:00.000Z","title":"Async Connection Pooling in FastAPI","description":"Your async FastAPI app stalls under load, then times out. Here is how SQLAlchemy pool_size and max_overflow really work, and how to size them for Postgres.","tags":["FastAPI","Python","PostgreSQL","SQLAlchemy","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACMElEQVQozz3Oy2/TMAAG8BzG2jiJEzupY8dxXk2yvh9sbKxdu62HCTgg9hLlgDhMGgN1PAYnEEzaJAQIBOIA/wESiAP8h7grQvopspTvsz+lmvu1C/KQl+nKUmXYb6+tNkfri4Nea3PQHfbaa1eba6utYb+z1M0WUvY/r8zDsAAj+VVRAknFT5ezxiCp9fPmMMxXFtobWXOQNoZ5a73SGXnJEiRV1YpnLUXHQsfBFBKGHalmoNlpKbiMWKMkOpi35Y2qJTQkgDVNysy/PBaKJn9cMJ0YkxCX/O0RPT0oHe24k33y4p5zeIt4ngdwGXt1N+yyqFsSbYtWdRwqwPQlFXJMU+aXCeUnY/T7rPBpon19An6+Ln58qEcBU3GG/WaSr97Y3JbjEW/qaFrmM3K25QSm7Y+3nDeHxvGe9WxsnR3AyR7iHlOtyOYNniyK9IoTdBCrybEKgJ6kGgy7ZS4S12WP99GvU/XDA+3Lsfb9JXh3ZESCXtI8YDLPTVbieubGBZ1q0FNUyKYMJl9Gjm9ifmfLfntff7RvPh+b5wfG8a7JPTqnMQf7vSC/nlR7Ip83KIBMUQ0qFXUXlWLPjyh1T26bf84Lnyfg21Pw41Xx/ZEWCqKolGC+ndV383pfZHOaCwwqy65U1AkiMRcxY2S0bB/eNHc2rLvXzMYCA1Zo2z5GPHKjBi+3/DRn8aylyNqMCuUSuYIAg2iQgAsGEtAOoR3IqGlx3fJ0i0PENcMt6OQvpL1eAoequOIAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/6be4c650659d2ce67014e656d7abb978/40a76/hero.png","srcSet":"/static/6be4c650659d2ce67014e656d7abb978/c972b/hero.png 340w,\n/static/6be4c650659d2ce67014e656d7abb978/27625/hero.png 680w,\n/static/6be4c650659d2ce67014e656d7abb978/40a76/hero.png 1360w,\n/static/6be4c650659d2ce67014e656d7abb978/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You count characters; the model counts tokens. That gap sits behind a surprising number of the bugs and bills that appear once an LLM is in…","fields":{"slug":"/2026-08-09-byte-pair-encoding-llm-tokenization/"},"frontmatter":{"date":"2026-08-09T00:00:00.000Z","title":"How Byte-Pair Encoding Tokenizes Text for LLMs","description":"Byte-pair encoding turns text into the tokens an LLM bills and reasons over. How BPE merges are learned, why token counts drive cost, and where it breaks.","tags":["AI","LLM","Tokenization","NLP","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2klEQVQoz21PyXKbQBTkJNZZQMyMEAwQNm0gAVoItmxXkoovsRPH5UMOueXk/P8H5I10TVVXV0/P67doaXK+om2fuvZp338/7H8cDy+n48/d7htowHB67btncA77F9Cb9WMS30JEM8gcoOMgrrqqGRfbG+BNf7dqb9PlPlsdwVm157L+uO4Ub/p7WewmKDBIqDlu7LiJRSPI6ygwaWSrp7w8VVOThDaNwTFJBGyRyKbygliFDRgrxy/jOyAKB3haNKwXz1/Pfz8P7zIadDTDfk54ifwcgFmBWQVCs4mEai62Q/tr7H4z3hh4buJ58eHTw/Cnr9/4bKsjQcUqLMeoGuXixgsbN9rS2UqzSAib6A4nXm4ROUEMHDiExzvY31DLc3AIr9ywZknP070Kzxs6W2qWmhN4fkn9YsoWNo2gFE8zKiq46OqYaOaKZZw/iKS/JGsPJoulBkkDCT+ssZ8hEiOa2K7kcgst4Au7KXFT2AtKZXaXre/DYvDjHeRV2HCE4yWUlwDCCk8sgWEsYbmCX1BWGjbDvHSjOshPcLmsRj/piFhAmCMvUQFekAtAYIhdtVBNTcSdaQpHsqhhsgEGjaaZCus2g976/2DhwCZzEwnDUTUTy78CNDj/AACtStyDvHSlAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/57c3759a1c497be2a52be92e9f658072/40a76/hero.png","srcSet":"/static/57c3759a1c497be2a52be92e9f658072/c972b/hero.png 340w,\n/static/57c3759a1c497be2a52be92e9f658072/27625/hero.png 680w,\n/static/57c3759a1c497be2a52be92e9f658072/40a76/hero.png 1360w,\n/static/57c3759a1c497be2a52be92e9f658072/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most of what you deploy to Kubernetes is meant to run forever. A Deployment keeps a web server alive: if a pod dies, the Deployment replaces…","fields":{"slug":"/2026-08-08-kubernetes-jobs-cronjobs-batch-workflows/"},"frontmatter":{"date":"2026-08-08T00:00:00.000Z","title":"Kubernetes Jobs and CronJobs for Batch Work","description":"Run finite and scheduled work on Kubernetes with Jobs and CronJobs: completions, parallelism, backoffLimit, cleanup, and the failure modes that bite.","tags":["Kubernetes","DevOps","Jobs","CronJobs","Batch"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4ElEQVQozy1Q2W7bMBAUUCCVRJEUD1HUQer0IVmyXbh24gtBgT61TZAez+3//0VXjoHBYrgzyx3S4cszW5xkf+2ffzXHH7Pz6/zy2k38e/X4bXF9g2b3/LM9TRWkm/8MFeAgknk4CUU5bq+L1VM3nvr1uR9Pi/6pXe7hOOsOw/Y67w6AbjhSXoIfpgAO4hbxAuAz64d2qsx6oYGKWOHfiEcNGHDUvJPbyDTlIJBp7pMsYBbzEo4u1ojmQN4BKkhR3hfLA5EVcJ9m/s3geCTFso7yUeajyIak3pXLY8ALD4LBZJgTbokoiCipLHlcY26pKDEkpbkTqkZXOyzKgMEeWGJiu1Z2C9fDEZ5HWCplZpOsMkZr6/ri7c+/l99/P7jSifKBRjWi6WpzHj5dinbz4EmedqFqXaSInrN6L4o+6fbMDsx0ftr3m4upRjfQDlWtSFewJIxKACSESEm1m5IHsai26fYrbfZs/BLOHmnzma+f42Z4wMojieMGcajmyqxF2pOoYXoRmRGLCtYimrG4DljuIfnRZa7LXSQ9FgdJgaSBqx0Pa/gSoVtdrJVZyaxjcTMN4BikKTk3oarha0JVAZiqA5JBHwywWflEQ3VRNCGIoOsCoBNMxLtD3wmY76r6Dy2ARUHKEGsOAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/cc4e4f17fbc960d6928d553d8582c8ce/40a76/hero.png","srcSet":"/static/cc4e4f17fbc960d6928d553d8582c8ce/c972b/hero.png 340w,\n/static/cc4e4f17fbc960d6928d553d8582c8ce/27625/hero.png 680w,\n/static/cc4e4f17fbc960d6928d553d8582c8ce/40a76/hero.png 1360w,\n/static/cc4e4f17fbc960d6928d553d8582c8ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"I wrote earlier about sync waves, which order the resources inside one ArgoCD . That post ended on a caveat. Waves say nothing about…","fields":{"slug":"/2026-08-07-argocd-applicationsets-many-clusters/"},"frontmatter":{"date":"2026-08-07T00:00:00.000Z","title":"ArgoCD ApplicationSets: One Template, Many Clusters","description":"ArgoCD ApplicationSets generate one Application per cluster or environment from a single template. How the generators work, a Git example, and where they bite.","tags":["Kubernetes","ArgoCD","GitOps","DevOps","ApplicationSets"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3ElEQVQoz1WP2XKjMBBFeQsIJDYh9k0SSAZjwHbGqdhJJpn8/zdNQ+Zlqm7d6mqd2602PD35uzx9dPsRJO8f6v1LvL5BIV7fwQ+f38Pnd/vyIP3gqhHInZ8MRAqblODEb2iiQWq8D6e3Xr9M82/wYXws569p+ZD65lNJE0WCFuEtZdhBtcmvnKDGtAUhv0J+iZIWl5LUnVNKi9WWW0Cf7ACQAEDEsL3S8SvwrfBK5OW2m8O4cND87db/eTT352DQCMJubuEUCuBJWIMbFsn9RKX8nItLLq60mHAoHFp5Xef1wtO7q94JqiDV8Jo0ayGucXv2UwU3ZySS0Mr4GUTLyWW9G3Msuc0r3HNb1KSTHhOsnDJ+ydpz0ixhOWEmDPiJy2TcrLm8JO2aiYsX905YYcEdiPXckTXuBA4qWowAwJoU4O66hU2cECrias3bS1qvUTbhQOD/w6TjJKhpNgLwo21zxA3TjkkhouMSjyc2nKLT7HGNwgLz1mkrrIXDaxhkB0Wgxnhe49PCpiU4TqSWhmUzOC98PtBVh7Nij9lfBxTmsBN3jTsrrDnuBYpKfz1Et4H+GsPrwbsqoqRhOsy02ROKdrEnKzLR1kFhhuLcohliOaKZ+Q/YZQMQA/MX3W1J0TzsEjEAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/a6a16269b53c8cca9bd20782d15167ce/40a76/hero.png","srcSet":"/static/a6a16269b53c8cca9bd20782d15167ce/c972b/hero.png 340w,\n/static/a6a16269b53c8cca9bd20782d15167ce/27625/hero.png 680w,\n/static/a6a16269b53c8cca9bd20782d15167ce/40a76/hero.png 1360w,\n/static/a6a16269b53c8cca9bd20782d15167ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Every endpoint in a real backend needs the same handful of things before it can do any work: a database session, the authenticated user, a…","fields":{"slug":"/2026-08-06-fastapi-dependency-injection-explained/"},"frontmatter":{"date":"2026-08-06T00:00:00.000Z","title":"How FastAPI Dependency Injection Actually Works","description":"A practical guide to FastAPI dependency injection: how Depends resolves a graph, yield setup and teardown, per-request caching, and where it leaks.","tags":["FastAPI","Python","Backend","AI","API"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB30lEQVQozy2Q6Y6bMBSF+TFqAtgGbLAxO4Q1kJUsk0VKmnamo7bTef+36SWJ9Onq2NfnLlas8EDDI/F3UftWrv9W/b9m+1WtP9PZRzr7Vaz+TBa/s/kHUPWfXvnd8PdgeaDohq8ZPqZRUq6bxbFdnheby3RxLtt91e2b+XG6PEGsutfF5ppVPTIDeK/fUXQr0mmEWYxorJmRChiQDkA/sZ6oRoRogmkyWAZixeC56ZZU1pZbAoQliKaI5boZ3Am1+2gq8YAxlo8jVIeU4pW3sv8S+c2MzqJ4N4Mt5h0WHXaqYTwzNEUJMFk7/tT2GmxnxJkAUFohvLHkDPMpchrCW51mKpEqFohlyC4NXrnZTk62k+5Sr37ks4tINna4tLxOt0JFRa6KhEZcADyDMDwANBRi2dXNXuPmWCzfJ/OffnEIigNPelNO751ZTGz4gxDT0HBSiCqW8GfD2iwnooY+PFnJbCvSnvozuDHd1pQNLKXY8SGob155ddITi09EdIi3yIHCsYq4bniwJ5WVJXJb1lSWVBS2V1s814insLAPq0tUX5x4bwY75NQqHuYHJwiNSOaCraBiwmTBZG7xDATMC2+Ubxp7GVsvYwpipA+MEb8jHmKk87F+F8gZoad4pP4DMNpGYwqfMVAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/df58b502e7deb0a3d25d6eacd0c715a6/40a76/hero.png","srcSet":"/static/df58b502e7deb0a3d25d6eacd0c715a6/c972b/hero.png 340w,\n/static/df58b502e7deb0a3d25d6eacd0c715a6/27625/hero.png 680w,\n/static/df58b502e7deb0a3d25d6eacd0c715a6/40a76/hero.png 1360w,\n/static/df58b502e7deb0a3d25d6eacd0c715a6/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Two of the retrieval posts on this site describe opposite failures. In hybrid search, a query for  came back with three paragraphs about…","fields":{"slug":"/2026-08-05-late-interaction-retrieval-colbert-rag/"},"frontmatter":{"date":"2026-08-05T00:00:00.000Z","title":"Late Interaction Retrieval for RAG with ColBERT","description":"A bi-encoder averages token detail away; a cross-encoder is too slow to rank a corpus. Late interaction with ColBERT sits between them. Here is how it works.","tags":["AI","LLM","RAG","VectorSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB6UlEQVQozz1R2W7bMBDUk62LpERKPERKsiWLVmXLVxwfsVMD7UtROHHz0P//la6QIsCA2B3O7nCXTlteAI05Hfpfl+3b69Pjsnu77t5vh4+X7f20+v19/3jdP14299vzn2370+bnzxKAM0JqhFWYTHK7a/pz059mA451f4Sg/LYf0uUJrubri2m2KK3GJBsTDXConDPVkrRCbBrEhU+MHxdCLIzacN5ptQbejcwIZR7JA1p4kfEjE8YlwEl0J4q1MisIImERnYRxkch5pntbn0XWAdrmOpseCZ1GrKonB5Za8Aii3CG8oVk3yQ9JtqR6EfEGLlysApL39kdIS8pmx9X9uvuIWc1ld9v/VWrhoswnueMTHcQ5oRNESwh8AqweyMgw1mCYhZYsnSdp69EiSuqYVmOsPjWOjwc1sJhVQyWkWHtYxqxKUgvtYBFctFJ2bqxTbmlS+5EGDSjBORsFqch72Nw44JB6sHxWSrWs8wPmM1hvpvrKPAfJxOanRLZAkrT2kHRcJMHH1DtR9hAABYAWMEiSNtAITGTWTqsNkOCMhh/RATFDsR9yXbS13dr2SRk7DlIfSzfkHhZUTHk247oR2kpjU1ULY4VuoGwQIOEgGC/WUawpNXAC+wUfnoAHDG/BwsP/0y/BP/HiRoxjo5RKAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/40eca43c663841ba2316288ccfdce514/40a76/hero.png","srcSet":"/static/40eca43c663841ba2316288ccfdce514/c972b/hero.png 340w,\n/static/40eca43c663841ba2316288ccfdce514/27625/hero.png 680w,\n/static/40eca43c663841ba2316288ccfdce514/40a76/hero.png 1360w,\n/static/40eca43c663841ba2316288ccfdce514/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You add a document endpoint. The upload is small, but indexing it means fetching the file, splitting it, calling an embeddings API a few…","fields":{"slug":"/2026-08-04-fastapi-background-tasks-vs-task-queue/"},"frontmatter":{"date":"2026-08-04T00:00:00.000Z","title":"FastAPI BackgroundTasks vs a Task Queue","description":"FastAPI BackgroundTasks run inside your web process and disappear on restart. When that is fine, when you need a real task queue, and how to move over.","tags":["FastAPI","Python","Backend","Redis","Architecture"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACBklEQVQoz2WRy27aUBCGXVUFbOO7fW62zzHY+AbYmEAugEJCqEqV0CbqqtuqfYJK3XdTVepDlF1eswPdtdKn0SzmP/PPfyTirygQQF165HKQvambp2G1hzqq3kEznryvmkegmX2I+htEr4i/BAkIJcX0ZYO1ulhzhUViPmjKZpWU58NmlVVXwGB4UdTLcrqq5msiSoskBuqBBIQgDi2c0HDIRImCTHNE1+ZdR8gma+sUhmQjhBmoshF0baE5PdUWqsVVS0iK4ds0jcerwXgTpWsaLVhvCWB+iYI5YhPklw6DhdlfPJojv4BGcyJJ0X3Ni51JNVt8e3x43t//fn17uFsftjeH7eb58uI7Ckc4OmP9ORJTwusmm2XDlZ/Mda8vyToDqx7LbTwwUQwYXmJ4sWKJiGUXyWiRjjHqKTbXwfPRtgDbuhupZiDJXWKTQX52I7IrImY0mgOYNyYqPDoUYR3xqUsrAxUmzk1cHEG5jlI4W5I1Ai85eRUkm7R4irM90E8fePw27O9EvIviHY/vCV8qLldhoRdpXt/EJYQndeCTbAHHuMcY0iM0s09AA+dgvzBJEvTWdfN5Mv1UT77ko4/h5FyzOYhR1wohT5vm/2DR3GUFpG3ihInF5vrn9vbH5vpXM/2KylqzwqP4BAbkU/0fyKWtulKrI73qvGi1X3YUVWOyhv8AdlFXAfSvsIkAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3e4ce285c6ea6a6c3330336b6ea44ef3/40a76/hero.png","srcSet":"/static/3e4ce285c6ea6a6c3330336b6ea44ef3/c972b/hero.png 340w,\n/static/3e4ce285c6ea6a6c3330336b6ea44ef3/27625/hero.png 680w,\n/static/3e4ce285c6ea6a6c3330336b6ea44ef3/40a76/hero.png 1360w,\n/static/3e4ce285c6ea6a6c3330336b6ea44ef3/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most RAG (retrieval-augmented generation) tutorials reach for a dedicated vector database on the first page: Pinecone, Qdrant, Weaviate…","fields":{"slug":"/2026-08-03-pgvector-rag-postgres/"},"frontmatter":{"date":"2026-08-03T00:00:00.000Z","title":"RAG Vector Search in Postgres with pgvector","description":"Store and query RAG embeddings inside Postgres with pgvector: HNSW indexing, distance operators, metadata filtering, hybrid search, and the tradeoffs I hit.","tags":["AI","RAG","pgvector","Postgres","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4klEQVQoz02QaW+bQBCG+dAkro25Dy/HLhgMC+wB2AkGx457qZH6oe3//zMdnKaq9AjNDPvwzqI0JGuSrMZbGpGnWrzsh+thOHeH6+Nwkv2lf3xu99B+Gaa+qKs4nc+/o9xp0b0W6z7VUeURkbFTIS9vT0IH2r5AvROXqvvkJq3qlcAHLb7T8IOOFWtTOEFpeJnubtcWWRrxysCqOReqhW9tvDJhEhs2Md10xiFQqyZWPNxFxQnTsxW2m+0AtYv3gEcOTtyHu4nQ8yY7cgqbX8ZunPrTUY51xpZ6pMDCdixRNhioceM2KiaUHQE/PZiI2ZF0cWtFkmb8s2ivXJ4ZqDLBdDXLXmEF3E8frZDboQhmcwDgQ7pfmUFjBcxArN4214Z95fx3L8aKJ3G50kNILu1IgAxHnUjcYgdoXdyZqIHwWQ447Pldsitjr5I/1zwFWUOQXFohOMOcHMkwn4J8BPz0CS5iweYhB5nl7JsQl4ZD+LEWOCqXs+zu7IDNF5tl7hP4Vf0NSK5MVFuo1jxKk+KHqH611U9ZvfKqwPlC3SgOKsO0RYQ7AY3zPkxlnHUIN4gIHzPNzXU3X6wRsv2xJMcyGQoylWQXbO5VX1moHvBx7f8r3liofyf/4S/e3z7cJn8A4m1V7m1z4lwAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/74e573a27101a4894857b92b08201f6b/40a76/hero.png","srcSet":"/static/74e573a27101a4894857b92b08201f6b/c972b/hero.png 340w,\n/static/74e573a27101a4894857b92b08201f6b/27625/hero.png 680w,\n/static/74e573a27101a4894857b92b08201f6b/40a76/hero.png 1360w,\n/static/74e573a27101a4894857b92b08201f6b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Here is a chunk pulled straight out of an operations logbook. It is the kind of text I index for Archi, the retrieval copilot I worked on…","fields":{"slug":"/2026-08-02-contextual-retrieval-for-rag/"},"frontmatter":{"date":"2026-08-02T00:00:00.000Z","title":"Contextual Retrieval for RAG Pipelines","description":"Chunking a document for RAG strips each piece of its context. Contextual retrieval adds an LLM-written note to every chunk before you index it.","tags":["AI","LLM","RAG","Retrieval","Search"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+klEQVQoz02QW2/aQBCF/Wh7ba9vu/Z6fb9hsIEQAhgbl9ICSRQ1VRu1qqrk//+NDvBS6dPRmbMz2p0V1NHiRtR+yT+dk+4Ytoe0P2X9KemPcfc1Gx6z3QlyCKP2gPKZWi6UcgEqIJXLimeYSVY+VHU3mfZVva1nO/BgRvUWktGkra5mPO2xlSDNvyGoJFNprtECVCU5MmPZCCUzgtxileWNTVYZrFJJodgpHKl2jMzwSiSQYpUPL+XwEm9O9rQ3orlix5Id0WQxXz3Xy9Ns9TyaHWh4T/hU1jxZ4wjAPtIDwQxnbLLjk4GWrZ1vDOjAHOm+TFJEc0QyFNUSKL0g2bFMEkRTBAb7gsWnLO3cpGXp1k02ptfIioOCUfH9T/P2Uf98b359NG/v4x9/s2+/2fHVGB7x+VVb72WVCbpT6k5huCNAI7nBxgrmml/Fq2O2OSfrE2jePqXro3+3DxZ7Wvd20+vlUtKYgK/DJnyMN8a0uAybIeaVV7S83PKrkvjeDOaY1did2MEdjZd62IgwbPHGKzqWtTcMVosKFTUXkRg5iRJWsIJsR4DipkoyQW4KXjIDSXUFWNLNWjfd0OgBgGFIAVEmOB/zbR/2g+YlIiJWM4+Gz37byRaXZCKpjnD92+A//MvNFxwJM2RxaIWHXEr9WpqeqDpQQs8/LHlTj3KqFbsAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/ab292b7169b3a72f3ade4c490cddf89c/40a76/hero.png","srcSet":"/static/ab292b7169b3a72f3ade4c490cddf89c/c972b/hero.png 340w,\n/static/ab292b7169b3a72f3ade4c490cddf89c/27625/hero.png 680w,\n/static/ab292b7169b3a72f3ade4c490cddf89c/40a76/hero.png 1360w,\n/static/ab292b7169b3a72f3ade4c490cddf89c/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time a metadata filter bit me, retrieval had been working fine for weeks. Then I scoped a query to one source,  on top of the…","fields":{"slug":"/2026-08-01-metadata-filtering-vector-search/"},"frontmatter":{"date":"2026-08-01T00:00:00.000Z","title":"Metadata Filtering in Vector Search for RAG","description":"Adding a metadata filter to a vector search can silently return fewer results or wreck recall. How post-filter, pre-filter, and filterable HNSW actually differ.","tags":["AI","LLM","RAG","VectorSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB20lEQVQoz12Ny07bQBRAvSCMnzOe+DGesT2xY2MnOO/ESRMBIUmholIfQqJLpKpSxa5qt/2nLtuf4KN6IYKiSkcjz/ice5VK9oFuVM2PF9t6e/HqYtVfberttt6dTzfryfmes/F6t3g9K+fduAL/WPbgVBCJgYYVerJ/NDgpR2etzrwYneaDk854DS9ptcz6q7y3Gi4vRT4+MAWy5eFjpZhUPtEybKmR2GW54+eGkyAq4YQrdVPdjnUSGf/kBxTDjgENh8DDN4kdlom4+7befdl8vJxs/LBjuakBJWjkSXtEgXkA9dtNloOBiGjJwa/rr/e3P35/uru//f7n5m7RHh5iATb1MzD3CQBxaNI4LWdpOdUwx34xWd5cjzaMZYTnhh39PH337eoz8nKTiKSctjtT4qYaFhAqOowkQrW4agaaFWTDK5bWSoMgzKO0hyyuHGAnrbPBG9VkoGkWN0gIFaDANkCH3mTEy8rZB/gHS0BqZUOTRgbmFpXF9D32MnCg2SeAAtv2qKYPK4JkgqygYTBksbK/UDFvGL5qBfCOnQScZx+AmD0DSzTChZtUsluI4ijsJLzIRMkcqROu4+ClDCgw7CXI9AnhXjNyaejQqEnDph1izJHh/WcCfwHoaksAlH9PDQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/7968701b169fe845aa0823b8b0577839/40a76/hero.png","srcSet":"/static/7968701b169fe845aa0823b8b0577839/c972b/hero.png 340w,\n/static/7968701b169fe845aa0823b8b0577839/27625/hero.png 680w,\n/static/7968701b169fe845aa0823b8b0577839/40a76/hero.png 1360w,\n/static/7968701b169fe845aa0823b8b0577839/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You push a new image, ArgoCD rolls the deployment, and for a few seconds a handful of requests come back as  or a reset connection. The app…","fields":{"slug":"/2026-07-31-graceful-shutdown-fastapi-kubernetes/"},"frontmatter":{"date":"2026-07-31T00:00:00.000Z","title":"Graceful Shutdown for FastAPI on Kubernetes","description":"A rolling deploy sends SIGTERM and kills your FastAPI pod mid-request, dropping live SSE streams. How to catch it, drain connections, and shut down cleanly.","tags":["FastAPI","Kubernetes","Python","DevOps","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQoz02P3W7aMBzFLbWFOP4KBIjtOHEgxIS0fGltByEB+jG6Vdplpe1iL7LH2NXu9yy73ivNYdVU6ae/jo/P+VsGU6OKE9MsrMv5oV5Vm9nD4Xq3XT4erqvNvLy9rDezfbWsN/NdudjcFHkmm7xRoE21pUVi7GfZ1W66uh8VlZ1pUeWrezPbW9POyeJufFlPFgedl8gfn1oJwN3IYVbFrpdYC7IIMgWZxJ0IktC1MOV6Eeo0WI1ohL0Ye80ENqSjIIkDrQbDOOgNBI8K1p9euIqGIzY0RI5c3GxBTBGesCSleoSVJmECSEcet+rTPn3cJtuVb4Ye8ounOitf1t2PFf+w5s9V8FRSnTlEDmb51XE9O5ZymVETAuxJk4a50ROjTSo8P7i/6f75eX67Hp8hhQiHVHaKIny5o8OMBlpMpyIvelmGoxi4VLaxhTtYXCDZ8eXvH+3Dux4AAlHRtn+moXPRZ6kRn2vXOog3YSLsRwCkwlp2PfYEOA+/Hr1f36EVDglGqdnv3g9E0rbvw2Bw3FAzcWDgMgmbigDQXpxAjIMz/u2Zf3ni4JxTP4oSs1zOw9iQrm45fb2cxcVl2+lD+lqx5eA/LuWkP+7wnPqxLSMvamGJPEW6EfPjUGRaTdym+ZoHDh68hXQV68Wncsx6mp22/DuSk4Bvwn8B/DZLUAfiRtMAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/0ed827f19ec7b4a87eeef897fe2b7026/40a76/hero.png","srcSet":"/static/0ed827f19ec7b4a87eeef897fe2b7026/c972b/hero.png 340w,\n/static/0ed827f19ec7b4a87eeef897fe2b7026/27625/hero.png 680w,\n/static/0ed827f19ec7b4a87eeef897fe2b7026/40a76/hero.png 1360w,\n/static/0ed827f19ec7b4a87eeef897fe2b7026/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The tool-calling loop is deceptively simple. The model asks to call a tool, your code runs it, you feed the result back, and you repeat…","fields":{"slug":"/2026-07-30-managing-context-window-llm-agents/"},"frontmatter":{"date":"2026-07-30T00:00:00.000Z","title":"Managing the Context Window in Long Agent Runs","description":"An LLM agent that runs long enough fills its context window and starts to slow or fail. How to prune, compact, and offload context so agents keep going.","tags":["AI","LLM","Agents","Python","RAG"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACDElEQVQoz03QSW/TQBgGYBcKcWJ7vLtOvIwd23EW21lsZ+2iJrQJBJJUZb0hlKpCICROHBESiBM3zkic+CtcOPJ/+NxEEdKjT9a8885YQ1j4EJjGMAxm3fQiTZZJvGo150m8TJNV3Fn0e5ed9qMsiiFaDvqP67UzbI6gRZBsCdxlVNVq+NGw2hwBL+jDrLeOnEa3Eg7cRrfeOYK0EvaD5KRUDmE/tAiaN29gmCSr51ljn1ZuUcIeJe4VBNhR4Iw8q5NIzzEapAXOpPgMVAiKMzagbOhVTas0/ekwejEInw7DZ9iIGR6rZqp7g0Zyr1hOBC0Q9Qgg2SMKrL7DcAaJlJfz79+u/35+9fvr+k8nuIRDTXukOT1oqlas4HbGbCPJhbK2wQjYsNuKUX1w+OHN6tfVwx/Xi5++d3aHlmjBZkRHLFY5xYPvjGhnv11ApQ1WsiTV52T7OF4/Of2yOv54cfLJKR9zomO7Y682DbozNzpVy2nJ7QFOqRB5VNxi1Byl5GgljZ6fD96Pe28nvXeWNSCRSgkmJeA8h+FOJDtIcpDsUrxBQGcLFQXV5RW7Hi+G569743V/cqWXU8RbBh55/sQNR7LZzB5MC0U9ZCQbygdbSGVFzAi64Q+9ztxtTr32falUg3Mr/qxeX8g4OrBuXgu3YDJSmSBpZSdHyeD/lWyRVvbz3O08u0l3IPoHh8lcRU/a7vMAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/2aaa682982a02a1e294ea1c41dfe55ce/40a76/hero.png","srcSet":"/static/2aaa682982a02a1e294ea1c41dfe55ce/c972b/hero.png 340w,\n/static/2aaa682982a02a1e294ea1c41dfe55ce/27625/hero.png 680w,\n/static/2aaa682982a02a1e294ea1c41dfe55ce/40a76/hero.png 1360w,\n/static/2aaa682982a02a1e294ea1c41dfe55ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time my RAG copilot returned a subtly wrong factual answer, I blamed retrieval. But the right document was in context. The model…","fields":{"slug":"/2026-07-29-llm-sampling-temperature-top-p-top-k/"},"frontmatter":{"date":"2026-07-29T00:00:00.000Z","title":"LLM Sampling: Temperature, Top-p, and Top-k","description":"Temperature, top-p, and top-k are the three knobs that shape how an LLM picks each token. How each one works, when to reach for it, and how they interact.","tags":["AI","LLM","Sampling","RAG"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABzklEQVQoz21QyY6bQBTkaKChVxbTzTbYbrMZMs4otsGeUXKKMusll/xA/v8L8tqWIkWKVGq9qq63WlRPAF7P2/P79vKhz+/V8Xl1egG6Oj3r89tmfl1PLyDWjx/r6XUzvwEVzZnqk+X4ietLx1tWej/un7phboZp2x0B7TD346XZTe1u0u2hNfoB9Gpzj7CERMtl2RW5jdUCpzbJXJo7Bpl5r9QmKdDra/SFryCAFMsFCSsSlLLoSihJUxcrgIMlYlmU1h41BrCBiILKW9Y47b2kcWlmOcan/GDNZM/lzmOFy0sUrqE2i3SQdCSuEcmcWzleEtnRbPSDFVCzsycqKkeqRiIHmvSuGTgN0kFUR7Y6iuIzi2sbToMlK/Z8deTVAQLECgtO5YeaLLv49FO0X0nceLx0cELjhuuL+v6bryeS9NAD0ZyqXfjpx/LxFy0ecKSthRcjfkflwIoHlt0bH1GOH4ukY9mebebg7gt0BhvMybJR1E9B+43n0Dm3bC8GwA7QE8c1zIyp4gKWTCBHyB6H2sXJ1RbBOUnSmp1FZaMIkiMAFjkN7wAeVTcFUcXCkkUVDcu/IgQkKACY50CtBQoBtz/AAvCv8j/RDAv0D2etR5Bw7PryAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/c7670afd8e01157c75428c788f6b297f/40a76/hero.png","srcSet":"/static/c7670afd8e01157c75428c788f6b297f/c972b/hero.png 340w,\n/static/c7670afd8e01157c75428c788f6b297f/27625/hero.png 680w,\n/static/c7670afd8e01157c75428c788f6b297f/40a76/hero.png 1360w,\n/static/c7670afd8e01157c75428c788f6b297f/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most RAG (retrieval-augmented generation) tuning happens on the wrong end of the pipeline. People spend a week on chunk sizes, bolt on a…","fields":{"slug":"/2026-07-28-choosing-embedding-model-rag/"},"frontmatter":{"date":"2026-07-28T00:00:00.000Z","title":"How to Choose an Embedding Model for RAG","description":"The embedding model sets the ceiling on RAG retrieval quality. How to choose one by task fit, sequence length, dimensions, and domain, plus the silent bugs.","tags":["AI","LLM","RAG","Embeddings","Search"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2klEQVQoz02RW2+jMBBGedsYjMFgsI3BXBIDuRC6aao0V0qqtqvt//8/O0mkaqWj0cz4fPaDLb/tANp2XrMM5p05vU0Pl+YyQlOfR8AcB9jcl1cYSb3wmxW9pyybpA7JEFZeUEWyNfPXeXdqV0eo9WK/6M7N4rC4b1ZPA8BEC6btKkhZTqBvhLnLSi+u7mNuU/0/yNeIahzkDtVeVIEJDpiWQzMbK1I00qxT0yvT6/aZqQbB3V4KIKIiXpqmr1enpjua5SFOl4RV2M8sG4xAQ9hThogZERURUxwVNtMPENNuXNBk5quapk2Qzb2kJnKKw9xCWAbr3+LzGr9d+HVg+60adtX3VX+cyz+X8u84/R6LryH/HNTbLtw/8/EMpvgYaddbtisdprGssChZ2bHZS2w2NDUkqUS94c2Om42nKj810ETmhVUdFoUrS4dlFiISuRJhMXF4KJeZOYhia7sJckWYdOnsFerEiW2iZLGF00DMYQQfUhZItzyRE5fzvDf9e97sbQJhHmX9bH2N9NMEx4gkuj3W/TtLVxPMYYQIhKG75W0i4SdIZPzYkDAHqKg9XlNek1B7rIS9FxlwHjK8asGtP/xyIseXLlXYV/hR/QRwaQpgeuvB+fH/ATL8SrjG2RNCAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/77b826ceb3b55af1c5bbd4bbb78df257/40a76/hero.png","srcSet":"/static/77b826ceb3b55af1c5bbd4bbb78df257/c972b/hero.png 340w,\n/static/77b826ceb3b55af1c5bbd4bbb78df257/27625/hero.png 680w,\n/static/77b826ceb3b55af1c5bbd4bbb78df257/40a76/hero.png 1360w,\n/static/77b826ceb3b55af1c5bbd4bbb78df257/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"From the model’s side, every turn of an agent looks roughly the same: a long system prompt, a list of tool definitions, a growing pile of…","fields":{"slug":"/2026-07-27-prompt-caching-cut-llm-cost/"},"frontmatter":{"date":"2026-07-27T00:00:00.000Z","title":"Prompt Caching: Cut LLM Cost and Latency","description":"Prompt caching reuses a request's prefix to cut LLM cost and latency. How the prefix match works, where to put the breakpoint, and the silent cache misses.","tags":["AI","LLM","Prompt Caching","FastAPI","Agents"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+UlEQVQozz2RW4+TQBiGuWo5zQDDucAApeVMW6i0drs96Ga72u662XhhTIw3mpi4Vyb+//hBE5M33zyTmWeOjOJt+txIzspN79L2eVo/xs3TZHHO2uegfIjmHYxnH9Llp2L94iTvJXd9tRhecgTJgYqIH8TLstmn1aZY7IrFbb16N8lX0K2afZyvquWh3Z7oZI5V/2oxgkIFxYcqkoCXXQ6PYAwq28WW9LBnm4PVVX8oWt184vNyZzGC7F2D1UBxWlo+ecWF0FtCt7S8QIi/I/TGK87AWnhEeiJrgaSFoMCxXWigg1VqJR+b09/y8OpUX+zic33/pzy+urOvdn7l3179XfXeTPPWogWLRt2dRcXT3FI2YiO6qw6/4vU3Iz6byWO1/9lxcjHjc7X/AWznL8goOGzBliAyPB5xyObkgCcR0qfyqMJmjs0MQtyFbFfYyCQz02gDAENw1YFgDEUTRIZFFiIeMSOkuIqVhOXBDBpspqpbJPXJz3ZSz+nyYVweiVPBE9Jo5k8WkuYzHLIgouyJsiObsTPdGH6tjErFSp3pW9WbS3ZO7IymW2vcgiwSqhhjeDMe2yCbHDLAxIoLX627he6VWI+QGmhujvWJqIZIC4md9jAGZ8jrQ8EAkWFFAzIU9GsGvDbg1P/cgaizPbM9dPORyYoQ4x+ZEFCYwqVGlgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/f3de8aa2c7ecc91722c578140feaab86/40a76/hero.png","srcSet":"/static/f3de8aa2c7ecc91722c578140feaab86/c972b/hero.png 340w,\n/static/f3de8aa2c7ecc91722c578140feaab86/27625/hero.png 680w,\n/static/f3de8aa2c7ecc91722c578140feaab86/40a76/hero.png 1360w,\n/static/f3de8aa2c7ecc91722c578140feaab86/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A 70B model in fp16 is 140 GB of weights. That is two 80 GB A100s, minimum, before you have spent a single byte on activations or cache…","fields":{"slug":"/2026-07-26-llm-quantization-int8-gptq-awq/"},"frontmatter":{"date":"2026-07-26T00:00:00.000Z","title":"LLM Quantization: INT8, GPTQ, and AWQ Explained","description":"The weights don't fit on the GPU you have. How LLM quantization shrinks them to INT8 or INT4, why GPTQ and AWQ beat naive rounding, and where it breaks.","tags":["AI","LLM","GPU","Quantization","Inference"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQozz2Q2W7bMBBF9dLYWiiStihRC62N8ibLm+RFdhAnNZygm+EUeShQIO1HFP2Ioh/dcZwGOBgQ93LukKP0wy3Q62w2s883i9Nu8bhbPt4uv9bTT9v5l339dD0/gg51tzitxh+6or60AMqV6b1Drt4O4+GyO9kkOdTtsNzJYp2N66yo03zVm27laJ2O1lG/gpsN7DWwDygmi7EdUy6xkxhnw9ewAHQaaqSj047aCrCdUEe2eIbaEWDQzguhIpNqOb4viz3U2eAu5NO2nRlUGEQ0kBuH5XH9XBQ7kU7i7pxYsYYDnYgLSsvKXGfs8BHjue1CHRos0dsReCr2aCtNvQqR8MrgDcNtmh6IgHZ+YKBg3ieikN3b6/m3zeypzI/L/JSlNxoJVNOFCNxOqCU1KjQiYJLFegCiIUQoppVCvwiqsTwU6X6cHcrex6izYqybiy138iCoonhzWP0ERLIm7sgKJrY9UJGrYCapP+JRGWYbL1owb2LyPoJvE0FoaNv9IChzuf/98PfX/Z+BvLP8whMVRDeRoxC7S4KiL98/zH/sJ98P0+coqhHv6ThoGLaKuGZ6VzqDg458nfiUpWYrVA0OiqKaHHZLnZT8BzNYqa8i50LTsBEVzMnatiQsRi3xZinNc7yjmVzDrmZe4E2Dgf7Gy/xXVz27r/o/W0VRIRtUeRcAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/f903aeb9cbb35378dc7a29620092b56f/40a76/hero.png","srcSet":"/static/f903aeb9cbb35378dc7a29620092b56f/c972b/hero.png 340w,\n/static/f903aeb9cbb35378dc7a29620092b56f/27625/hero.png 680w,\n/static/f903aeb9cbb35378dc7a29620092b56f/40a76/hero.png 1360w,\n/static/f903aeb9cbb35378dc7a29620092b56f/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A worker that pulls jobs off a queue is the most common shape of backend code I run on Kubernetes. For a long time it was also the thing I…","fields":{"slug":"/2026-07-25-keda-autoscale-kubernetes-queue-depth/"},"frontmatter":{"date":"2026-07-25T00:00:00.000Z","title":"Scale Kubernetes Workers on Queue Depth with KEDA","description":"A CPU-based HPA can't see a backed-up queue, so workers fall behind. How KEDA autoscales Kubernetes workers on queue depth, and where it breaks.","tags":["Kubernetes","KEDA","Autoscaling","DevOps","HPA"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACAUlEQVQoz02R6YvTQBiH86HadpOZzGQyyeRqmrSbzdl021xt0rIriKAoon73qJ9FVvBf8NjFA/9hJ7sihYeX37w87xyMwKyOY/S1pawJ48fL9YsofbI4f57lz1bFqyR7ykl5Ll/yPne4eet3whiZnBE0IPWQPvfDYlFcBOkmyDbx+S4vL5PVLlxseSfMWzdYcQeQ6RCysWwKInYlxREVHagm0pwTrA8kfB+Qe5LCGYh4ICp3y4GkDKEKVRsQC1EfEE8YAd31L9rt56b+sN1c1eXH8Ox1Eh6i8A0njt5H4ds4OsTRu74fH+ryU1NdzcMHin4qDAF1Jo/2zZ+m+LItr/fN767+vt/8aqvrturDrr7pa/Ozrb519U1X/9iWXzWrEpEjjKEBsG/Zl5StdaNhRkv1ghkbnlV9bZgd1UuNVczsiLY0zB3PlJW285BPCSfQkJBLtTUmiUIzRV0AFMo4kZUEkVjGKSIJUmJMMoACQpeKmmA1VbWVJE/6k8eQjYDGHz+UNAmbjpe482wySyGxvSCXVUdlc2oElpuJyOQON7nPp4QxYLfwLYyRpMtkcpbUp3HFK3PiOG8tL7O9pR/UQbSTkDO6k3v6Yf0IDVLf9As37LCRUiendub42XSe8es4Xoz12UjS/vsCXxwjIpv/IdJmkEwBcaHqQvIPRKciso7lv5mmWZvH4n2kAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/087e118db1fb141ff439e029fa956a73/40a76/hero.png","srcSet":"/static/087e118db1fb141ff439e029fa956a73/c972b/hero.png 340w,\n/static/087e118db1fb141ff439e029fa956a73/27625/hero.png 680w,\n/static/087e118db1fb141ff439e029fa956a73/40a76/hero.png 1360w,\n/static/087e118db1fb141ff439e029fa956a73/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Watch a large language model generate text on a GPU and something looks wrong. The card is expensive and the model is loaded, yet…","fields":{"slug":"/2026-07-24-speculative-decoding-llm-inference/"},"frontmatter":{"date":"2026-07-24T00:00:00.000Z","title":"How Speculative Decoding Speeds Up LLM Inference","description":"Speculative decoding uses a small draft model to guess tokens a big model verifies in one pass, cutting LLM latency 2-3x without changing the output.","tags":["AI","LLM","GPU","Inference","Performance"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACEElEQVQozz1Ry5KTQBRllRc0NDTvNA0ECCQ8Qgh5TDJJsFLzyEpLXY8Lp/wGLVf6B27nP/QDpvS/vBi16tSt2+f06dt1Lpe6ASCh3nKSNfX6uFjdbHb7eQ3Ni3pzqJZAwrGpW34RpxPHS73g4uI6EutiDxmxGVRRsU/mTbo4Bdl1VBzgGM+buDwG2S7M98nipPsVr4872O2CS2Icjx0eD0Xi8TLrS3Qg0bbiFsAgxRNkJiiuqDCN2Lrm2AbDCkgO8JyoBsSeIjUAiFrYQoUaCbKLiEusxPLnOptpduzYo5gF1BppZoDICKZyxCm97K5nlu+uynpaIbvQnBmQ8FZXMKDSyUlyN2U0fXq7/fZq8/Tm6vVq2dMSAVOO0JmbngZ0/fF2tc/nvAXmgtAC6xGxImzETtLg0b6Z1c+Pu+8P21+P2w+HZUcF85BTaDHKTqK//3y/PeTlxawMC9mM6WgmmwlLjmrU3Cx3z++3Px62P/+aY0GyYXLpZueBVb6s8nxcIitXaTsZEb8n6BCBk97K/vXUn3w5rz/dLL+eV3fzRV+NB6LFgSzbmaSPkR5jK2kbCEwfQ9Q9wYDYZDvF5gRroaCGPAn7JBioIQTWRyYHz/eRIRLmBkWQVAYd85INzH/0kEFUGlMvHLpj6jOTwWovUmuGD0iqi+Sh0C6ciYoD5D9oA6lVRZn+UV24gBQKPKi/AWwMWbQilyDRAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/b795063cc4996b8cbc2c4e853c552d50/40a76/hero.png","srcSet":"/static/b795063cc4996b8cbc2c4e853c552d50/c972b/hero.png 340w,\n/static/b795063cc4996b8cbc2c4e853c552d50/27625/hero.png 680w,\n/static/b795063cc4996b8cbc2c4e853c552d50/40a76/hero.png 1360w,\n/static/b795063cc4996b8cbc2c4e853c552d50/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"An operator on shift types “did it break again?” into the copilot. The retriever embeds that four-word string, searches the index, and hands…","fields":{"slug":"/2026-07-23-query-rewriting-rag-retrieval/"},"frontmatter":{"date":"2026-07-23T00:00:00.000Z","title":"Query Rewriting for Better RAG Retrieval","description":"Short, vague, follow-up questions don't match how your docs are written. How query rewriting, multi-query expansion, and HyDE fix retrieval before it runs.","tags":["AI","LLM","RAG","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+0lEQVQoz1WPa2+bMBSG+dCu2GAbjAHbmFsgkAuEpMqaNE2bLU2rrtKmTdq0af//h+ykUj9MenR0dPxeZMttVqQ94zZLp16wyXW1f8q2x/HDi7k5VPvncnfKb4+wFLtH0i6d8QBK0oB+ZTnUODTBrma8ELKN1KQbHtrZbb86NNPtYvVpvrif9XtYJt1OxE0oW8ZLTBIwWg7PSDhiUU2CkoYlTORl2M9sL0VeajPzNhPbMw4HQUVE4fIcXIDleMaTbZB0LGpIWHtRQ8MxRDCeeUHhi9L1Uz+sAt3xdOBm8OXM8TNwOV5qYZYI02fjrak+ZvVG5te+mlJRRqqRuo0lBBVZtRZmycWUyy5Il+AHF2bGQlQLNS1nu7Lfj/p9mC+ZqDBRiGmb6SsiHT/3VM91z5+++evPQdxBP5RjpqFZ21RdJDUu5ihtr9TI5gaLHO7nCFeSqBLtlnd3/o/ffHvy4zlPFi6YibIgW22Ow/e/sy8/h69/utdf2eGVrg9uM+C0wcUEZy2v1tAWxPNA9QF8W88RVYBlu3HQ3RR3z/nuNLp/Mdsj6za022AzRmqEdYUCg2niqbmn+zNyhliC3BgRaSESXznhJRKXWFwg8QEL+/wQo/dpu1Go62K8HE1ugLxe+CKHI7xCc2STN90bsJ8v/4OppEHKRAYTQO+af1+0SGyi03LaAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/16e70e892c537421cf56a7d2f5b2a2c6/40a76/hero.png","srcSet":"/static/16e70e892c537421cf56a7d2f5b2a2c6/c972b/hero.png 340w,\n/static/16e70e892c537421cf56a7d2f5b2a2c6/27625/hero.png 680w,\n/static/16e70e892c537421cf56a7d2f5b2a2c6/40a76/hero.png 1360w,\n/static/16e70e892c537421cf56a7d2f5b2a2c6/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A single agent request is not a single thing. It plans, retrieves, calls a tool, maybe retries that tool, calls the model again to write the…","fields":{"slug":"/2026-07-22-tracing-llm-agent-opentelemetry/"},"frontmatter":{"date":"2026-07-22T00:00:00.000Z","title":"Tracing an LLM Agent with OpenTelemetry","description":"An LLM agent request hides where the time and tokens went behind one flat log. Trace it with OpenTelemetry spans, the GenAI conventions, and where it breaks.","tags":["AI","LLM","Agents","Observability","OpenTelemetry"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+UlEQVQoz22Ry4/SQBzHq2KhtJ1OS6H0MTNQXlv6CktAHgVEWMjGBwuHXbJx4yMbPa1XEz168Kon75486d2/zh/LrhdNPjPznfl9v/ObZLgmDXwaNkkQluPlYDluTfrh4FFnBmIYDSeHD4Fpe5rEyaw722/DUgx+SHG8QtIKuY8cUXcPDse1aOj6/bh3VPZ77KBTiwb1OGnEo2owCLrzWpTU4xE4wQ8pTlLpX7KKI2IqqlQAoTgpTLEdCsgGncUEDkHvSpjs/Ryo/yKYzWnrqN95Wus8E51IyVdRrmSQoMgig/h7DwfdbsDX7HrayI4+P375a/26Hc8263fv51vsRBImSHcljQH7CITtPQKyYBaRdRfTF8nmx8mre2qJxwwe/HNzeTZYwTlWbFUl8m2EyyJLkE1No1XHY1bDMiqpQv3b+s2Jn+iV1nx5KhJ/FYy+bt6m9Aqz6i71i2Zt1wlZnIBMAJSSoyjHFI3c0cqfji+uesdcvhJEY7jrw3j1cfGcQ0SQjbRsZuQiAClOgOWajGQAgmTwshl649/nV+fxBFGvQhpfFtvQn/DIQhpFGsP5sqxRMEPYuOXmlqxc4FX2IJ5/f3I5vdi254tqqSvkXRlbzPVY2bOYB/mMVOBg/Isg5lOyyRcaBmtjK4C/zYj6riTqaVHnsztg+wel/VV3RVrUeAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/e5f3c00f4b4662e82b0b40efb94e8ed3/40a76/hero.png","srcSet":"/static/e5f3c00f4b4662e82b0b40efb94e8ed3/c972b/hero.png 340w,\n/static/e5f3c00f4b4662e82b0b40efb94e8ed3/27625/hero.png 680w,\n/static/e5f3c00f4b4662e82b0b40efb94e8ed3/40a76/hero.png 1360w,\n/static/e5f3c00f4b4662e82b0b40efb94e8ed3/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Here is a number that looks wrong the first time you see it. You put a GPU behind an LLM, send it one request at a time, and watch…","fields":{"slug":"/2026-07-21-continuous-batching-llm-inference/"},"frontmatter":{"date":"2026-07-21T00:00:00.000Z","title":"Continuous Batching for LLM Inference","description":"Static batching leaves the GPU idle when requests finish at different steps. How continuous batching schedules LLM inference per token to raise throughput.","tags":["AI","LLM","GPU","Inference","Serving"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACIUlEQVQoz02R24/SQBTGB9gtnU47baH0Rjud0nIrd0hBWOgCsm4kqw9qVHwyMSaazfpg5Nk3TTbxf/awGxOTX85MvnO+OSdnUNLwgFbdXc372cXg8mK4ycbZYgBxvRzN02S9Gq0WA1CePZ0tpp1m7EJ9+8GFipQLNJD0KEqWreGmM9kBcXdV72ZxJ6sly2S8a/bX7eG2l17Ve5dYj6AeXACSS0wu+dQIIAqKJ1Bf0jyiQ/SJzgC4yLonyE4eV7EWUIND5QMMkVPOL4iearbb3SEPayJ1QfwfTL1BN1pMWK9hSNQmGnvUkax5SPR3MyN70pyOwg/PPcVoYuqCQVKr0DMvsW2q3x+zd/vGr7tWtprlihb0k1QPnROvxu37L7LtuHnswpwVltJywHxHt+Jz2Y+4+fszKVccJLiuH//5+Z7x+jlxiFZFBez2Wu60b1t8mgzmYWvm+zzkYaPZdoKOoITLib+ZVuu9zeX2utFd7jfddNTMCZasukhULLkUlqojgXJRi5AUHQ90lBiiVivbESqak3H/ePsSYS6V4oIS/TgoSVyBGSXVQbCAArbTAbt9pQxb+rfX5NMNzRUdrJhF2XzIOl8Pvbs3Sr+hf39LPu7VnOgQamPFRlix4NDK7tXcepGZm6kNqwLlH5ZE4SH7emHeZOY6tUX4y5MCLguJsomprZRZXgqAM5nTMoOGoANFUiGqoxpBgfCzUzZQDQbKY/YvtmxSHW735VsAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/588d887e7adcb5259d4fec21c98da32d/40a76/hero.png","srcSet":"/static/588d887e7adcb5259d4fec21c98da32d/c972b/hero.png 340w,\n/static/588d887e7adcb5259d4fec21c98da32d/27625/hero.png 680w,\n/static/588d887e7adcb5259d4fec21c98da32d/40a76/hero.png 1360w,\n/static/588d887e7adcb5259d4fec21c98da32d/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You change a prompt, swap a model, or add a reranker, and now you need to know whether the answers got better. For retrieval, that is a…","fields":{"slug":"/2026-07-20-llm-as-a-judge-evaluating-outputs/"},"frontmatter":{"date":"2026-07-20T00:00:00.000Z","title":"LLM-as-a-Judge: Evaluating LLM Output Quality","description":"Human review does not scale for grading LLM answers. How to use an LLM as a judge: write a rubric, score with structured output, and control the biases.","tags":["AI","LLM","Evaluation","RAG","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABzUlEQVQoz22Qa2+bMBSGkbaFm23M1RiMuSxQQsOAXNo0ySZ16dRWUzd1lx+wP7D//3EHIuXTpEfW8TnPax1ZydIjkMpDmh7a5fP+7vd69W13+3Oz/r7dvN5sX4fhBWporoYXmexBO0cARbMilXDsZQ6v0qtVf/u56T/W/aFc7q66PRTvm5uq3dXd2KFsDib4kAIUZKfIltjNiFcQt5hhPsPhZQyFTmPkZKadgQkOmOBPpIpJkxFLwFnknxblU10+VsWpyI/L5iFJ1tQtdcJVwjTCz9oFxbDEGdNJYSU7qKhXOn6dJLu6eiqL+4lTVXxJ5Z1uxSYVl4hiUKHj0JF10R8deU0Xne4JDbMZ8pGfv0M+1G644MngR0uDJhrmhhWfUQwSmTgKymG+O8n24FdbGlfGuGHshjW2pYYYy7p6/cjz/vnY/rjv3PH1yCSRok8eDedO0gB2XBMvh+dniOGgVEmkosATrWxOcTH8+dr9/bVmLJ6h0LC4AjsDqhmohj9i+ipiDo2auNyWq0ZUthU50YIXG571H9p+aFvLjWEdSEGYnfMjZAQGFhVSXOf5IMWSUKGhwJi0t0b4RmdTckSBwX+AGXzkBNSXvo5HLtd/ha5G1wz7qLEAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/d98f85980960ee55fdf7a04ec405b51b/40a76/hero.png","srcSet":"/static/d98f85980960ee55fdf7a04ec405b51b/c972b/hero.png 340w,\n/static/d98f85980960ee55fdf7a04ec405b51b/27625/hero.png 680w,\n/static/d98f85980960ee55fdf7a04ec405b51b/40a76/hero.png 1360w,\n/static/d98f85980960ee55fdf7a04ec405b51b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most of the security thinking around chatbots starts and ends at the text box. Someone types “ignore your instructions and reveal your…","fields":{"slug":"/2026-07-19-indirect-prompt-injection-rag/"},"frontmatter":{"date":"2026-07-19T00:00:00.000Z","title":"Indirect Prompt Injection in RAG Systems","description":"A RAG copilot reads tickets and logs, so whoever writes them can plant instructions in the prompt. How indirect prompt injection works and how to contain it.","tags":["AI","LLM","RAG","Security","Agents"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/0lEQVQozz3Q227aQBAGYF8Fn7B37fX5BMZnbDC2sLGBAklDaJuQNE0v2vd/kI6DVOnTamZXv0Y7lJRuUdRNmkuyf4t212j3Gu/f0sPPoH+BIt6/htvrrPuRHt5n3fP89MuuzijqpWQLKHZs3LGqbiVZ0adFB+KsTfJNPG+zokvybr7YpUUPr1HWLuuj6c4ZXucEC1BIjbAeIW0gqiH4X3CSz+EJi1wWe6xoM4JJ8waHbE7yOMmFk1InlRk0ul9ZwVqfVoZfO1FjhUMt6pmgBBxyhjnYE6c1jjZjLWQFc7hEDmWf/kwf/mrtVWleVLB+lquLVJ7l1ZO6/cDpnhEMXgtJ+YjjjTir5NUj8muGN1gIG8W9V1+M/KSmey07qMlODjs52AA1/YLcJfwQ5UcctySoSbjGfokW97wWMWOD0t3SnjWqsyRmIRs51jOsJTeKvRBln5En1uLU5v22OoK+6JPVA+8ULKdS2rS2wg2xl8QpibOUrAIbc2wOFK+Ctd0Jhl+dr839x+7b++777/brunlizIzhlM9w0H4mS+KWkr3AZn6jeCsI04ws+BVeHAU3ByhqYR2wCGasU8QuVG8lmTlAeoqNTNQSUYuBbBUC8WlehSHjSYnyAxCijTRZjcmU5hVqxBFAcwo0I25A3wwtgRPCYMRItKDBwBFLABRw+Q9N5FYZ2kBO4gAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/20d9039dc8bd069316ddaa58c83980fa/40a76/hero.png","srcSet":"/static/20d9039dc8bd069316ddaa58c83980fa/c972b/hero.png 340w,\n/static/20d9039dc8bd069316ddaa58c83980fa/27625/hero.png 680w,\n/static/20d9039dc8bd069316ddaa58c83980fa/40a76/hero.png 1360w,\n/static/20d9039dc8bd069316ddaa58c83980fa/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Two users ask your app the same thing an hour apart. One types “how do I reset the FNAL transfer queue?” and the other types “what’s the way…","fields":{"slug":"/2026-07-18-semantic-caching-llm-apps/"},"frontmatter":{"date":"2026-07-18T00:00:00.000Z","title":"How to Build a Semantic Cache for LLM Apps","description":"Exact-match caching misses paraphrases, so LLM bills stay high. Here is how to build a semantic cache with embeddings, a similarity threshold, and its traps.","tags":["AI","LLM","Caching","Embeddings","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAByElEQVQoz13R2Y6bMBQGYK4awBuQDWOWYUvMFhLI0hQG0Eymrfr+D9STaZSqlT4d2b98DLYVQ1amrNi2FM0l7afoOmTTrXj7CM7f0n6EJOnHpBshTPop7oZ8uon2AuuhS9Gpi5inYsfxy2o/yaKr2zewya5FPW7LTpZduR+resiKrqyH3X7iolB1rmNXQZb/h24+qERoWCDDu0+hGr5m+oTHlCfUASlzEpgSO1Zg0T+ooH7K0pzYISIuMn1ketTfRON7dvsp33/k33+l083MDlbVKjpznxBzaShZ1Rq7I8v3RCTIgu97muVrPNJ5pH2CAeIxVGgWD9QhImZFS/yShJVRHFnV4LkP+Wr+0iRNuz2Cozzt0ybhcuNIuDDnAXMaZySuqTywr50V127WGG6CiSNW4Wt+HqormHZdX1zKoNgFpaJR/oBt7CWL08m+nNbXs30+zZujNvc0wlXKkeEiA27x/o9QsQnHFIpG7CedOTSrWN4w2bCyoZFkVoAgnIcvWR8Vr3E5ABisgoPpFNC8/guvNcaxF5Ngg/iLTmzEOOT3TRchW4LIWEZsEcITYNNXVLz6n75UteW94vUznKHFTL/78llnaAl+A8eDSl9/u1OAAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/6d3beb8303d887f41eb6c64e89f41154/40a76/hero.png","srcSet":"/static/6d3beb8303d887f41eb6c64e89f41154/c972b/hero.png 340w,\n/static/6d3beb8303d887f41eb6c64e89f41154/27625/hero.png 680w,\n/static/6d3beb8303d887f41eb6c64e89f41154/40a76/hero.png 1360w,\n/static/6d3beb8303d887f41eb6c64e89f41154/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A while back I wrote about the loop behind LLM tool calls. You hand the model a JSON Schema describing a function, the model asks to call…","fields":{"slug":"/2026-07-17-build-mcp-server-llm-agent/"},"frontmatter":{"date":"2026-07-17T00:00:00.000Z","title":"Build an MCP Server for Your LLM Agent","description":"MCP standardizes how LLM agents reach your tools and data. A hands-on guide to building an MCP server in Python, picking a transport, and where it breaks.","tags":["AI","LLM","Agents","MCP","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB5UlEQVQoz1WRa5OaMBSG+Va5JQQI4Zpwk5sIrLq64mp17NZ22+5+aP//b+mhznTamYdDMjxvDgckEu3v4GBrJ4fl/mex+jFffYeaDa/J8lau37L+Ne++5sO3cvNuidEId4RPEUnBgYoDBfvIEtQv6n4sl7tqua+7fdnu8uaxW38s26eqG7v1qelHGhTI4gryISWphAOaGROvZrwzvVq3c8XgqpUgVtpBo9O5aiYKOFZmuCU4xK1UM4aUpBoRoJkCvKx9FsWjwQrVCJGdWcEiWxzssNWtVCMRdoqo2CbVEzQAH1Lw2iGgGnyme4ifVaedBiFwsFBJQtLbnybTehrNW2F+hAX4kJpmhhtiDQ17JztbfKvTUqeVZpeILazkhJwGOfUELY1gZYoRBPBhbAkugISbdPUrar/Q7OwWVza/eOWVZWcnO1rpyYyPd+AsJz3R/Ir9QdFdSUaejHzsPTj5NWpe7PjZLy5R/Um0N6hecaHp0YoPAPRk+TlqPvv1C/b6mc4kWXenMGvceKiGE1SH916yZvGDHS7hF5h+8xf4hEwMjhgwW8y0Kcwgj92Wik1UjGY4UL520x1sDb8jQf8v96c234Ava1SaaQ4g41A2+AcUKYZQMJdxJGOuEDFt/we0qeJwptHfhjlOGA/Sx+sAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/fb69a747f6e4288dc2aab7f5ef430139/40a76/hero.png","srcSet":"/static/fb69a747f6e4288dc2aab7f5ef430139/c972b/hero.png 340w,\n/static/fb69a747f6e4288dc2aab7f5ef430139/27625/hero.png 680w,\n/static/fb69a747f6e4288dc2aab7f5ef430139/40a76/hero.png 1360w,\n/static/fb69a747f6e4288dc2aab7f5ef430139/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A user clicks a different conversation, hits the stop button halfway through a long answer, or just navigates away. The LLM stream you…","fields":{"slug":"/2026-07-16-cancel-llm-stream-react-abortcontroller/"},"frontmatter":{"date":"2026-07-16T00:00:00.000Z","title":"Cancelling an LLM Stream in React with AbortController","description":"A user hits stop or switches chats and the old LLM stream keeps writing tokens and running up cost. How to cancel a streaming fetch in React the right way.","tags":["React","LLM","Frontend","Streaming","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3klEQVQoz1WQaW+jMBCG+bINhw9uY8CYEBKuhABJkzQ0afu9rbrq//8vO7DaSis9HtnjeedSSjlW6fM4fN6PX7fHr2v//jx8vJ2/Xx5/A/fZMw4fYz/xdvl+6t434glUgLKg4YJGQdqU/VgNt3x3WbeX8nhb7k6b7lr1t1VzzurTur1mzbnoRl9Wv3AAEkBBlgR0KgwrMcxENwW1s0G8HtLX0G00E/wS/NhOTTejToptiQArARWIpw/DFMiagAu25DLYr4LOdda6+Tep8FguRB2LuszagOUajcGpGGaMbSgIj/ifjTQa6TQGCxEQBx1iSzA3zXm+FUXoZyqZApS5YKKR8AedRgiykBhm02ho2yJjy1282YuiitarYOU4yZw9UqibkWmShDgSQHaikgBDn7zIo6JPmqPctaJuRTMkTSfqOqp8J9Uw10mowIEdUG+JXUnc1OdlFGyXQS/SLhFN7Jfchz5L7hVVdhrK+6F6iXj1gJhOOIg5tIpw5Nl57G9Dr3LszCDhQmdaItyucNuN0268rmSH2lyvVMQ0GGdGUTHjfiX5nnkFdKviADwINkRj5MUklITLyc4gX+g4RLBRDCmYoiJfx1zF/gNy4a2T4Cexhphq/Ic2l0VWDJEg/APzg0crJbqYnAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/0ae2d35eba94c6cf5e371bebd166c7f2/40a76/hero.png","srcSet":"/static/0ae2d35eba94c6cf5e371bebd166c7f2/c972b/hero.png 340w,\n/static/0ae2d35eba94c6cf5e371bebd166c7f2/27625/hero.png 680w,\n/static/0ae2d35eba94c6cf5e371bebd166c7f2/40a76/hero.png 1360w,\n/static/0ae2d35eba94c6cf5e371bebd166c7f2/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A service that ran fine all week starts dying.  shows it restarting, and  has one part that matters: Nothing in the code changed, and the…","fields":{"slug":"/2026-07-15-kubernetes-oomkilled-requests-vs-limits/"},"frontmatter":{"date":"2026-07-15T00:00:00.000Z","title":"Kubernetes OOMKilled: Requests vs Limits","description":"Your pod died with OOMKilled and exit 137. What Kubernetes memory requests and limits actually do, what triggers the kill, and how to stop it happening.","tags":["Kubernetes","DevOps","Reliability","Observability","GitOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACJklEQVQozyVRy27TQBT1CvKo52mPZ8avafyIHduJ4zgpdVxaSlsEAipaBAiExJI9S36ADbsKVPGzjEG6ujq6M0fnnnsM4fW6mOh8ddZs366am3pzU9XX6/Z2qfvmdlG9rJs3dTMMpX/iyE64/f8yxkiOoQB26AR5lLdpdZSvuqTc6q7xoumjYpvX+/mqixZb288BOxwBMYZyglzDpDNgJ8iZQzYnIoMsndLItOIDGk1xCHGIcAhQYLGYOYllR9SaYaIACfWrAZ2UeEssSyyXZXulFidIlMStsFtCqjgJHRIyHCwXj453Tz2eaqyHFAcT5BuAJcRdQp5jN3VUi2Q2ZTGWFZYFIGpgEkWRI/mMWxEyLQo9hyqCgzH0NDlFsqDuet/9uDz/83h/v9l9scMSCU3WsopAVqUfnp/9Pj++uzj6HquKIp8STXaNwbDMz/pfTfMNiiovXnx89cmbVYAXUGtCu0zfX/X3oagxSV9vP989u7aQp5UnQBoT4sbZu777+YAIHpTzNGNeVhQt/KdsIX7R3Xl8jYAdsFlse183J3M5N6E7BsIwLcVVz8M9cRe7ts3LDeAlDwfPJhrsKbdjJFh52WWySpwYYyWsQ4zckcn12rE+LBD5LD/eHJ2ud6d2uEayQrIEyB8Oi0TqZk+Suo9WjSo5Ha5IkDcymTFFvk4V2JE2P9HZWjFkiWnNTHo4NTmGUv+zSYCwBzWgOiRPy5pAPDxgfwFwmlj+1mWLqQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/6399392464251e994ff9f039b0376535/40a76/hero.png","srcSet":"/static/6399392464251e994ff9f039b0376535/c972b/hero.png 340w,\n/static/6399392464251e994ff9f039b0376535/27625/hero.png 680w,\n/static/6399392464251e994ff9f039b0376535/40a76/hero.png 1360w,\n/static/6399392464251e994ff9f039b0376535/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first version always works. You write a prompt that ends with “respond with JSON like ”, call  on the reply, and it parses. You ship it…","fields":{"slug":"/2026-07-14-reliable-json-from-llms/"},"frontmatter":{"date":"2026-07-14T00:00:00.000Z","title":"Getting Reliable JSON Out of an LLM","description":"Getting an LLM to return JSON is easy; getting valid JSON every time is not. How to use JSON Schema, constrained decoding, and validation to make it reliable.","tags":["AI","LLM","Structured Outputs","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAByElEQVQoz12RW4/aMBCFs2hhA7GdCyHO1XbiBAgJNIE0yyIQsCtVVaW+tE997p/pQ5/6izskq6220qcja3zOzFhWCi57jlVzbffXj/vn9um8a18eD8ClaY/V7tI8nqrm+GHX1091s2IJRJSRzh50BurFVb69LOvLojonxWFZnfP6AoekPEAxWZ9Evk/Xx3x7jebNkESQUpDJeiZ6CIz1EE1jgy4MJ9OdFNRy5ybNXDfF01glQYffRxTNiN7oS2CKsy1PaxqVNCpcVlBWsDDDVmw60pjFyOK9X+kH3maSgNixPkuQGXl+6riS2BJZorsN1G4pjxW2N0cm7yMQDl6BZSwYy4fwGMzvCLvD4QCzoc41k2ngxv5oQlXkTTCYbxEFMm9oRgBrp4HYJbJO0g3nteBbwbHho2mkRQkRqRYIYGJH0EsZE6+ny3uaxX+2iz9f1r8+lb8/g65/1HPLDBzK5KZcNVuRL/xMmh5TsauMsfvKLe9NjPBJiu8b+bWQ39byZREPxhSubDNYOaL05JLGiRXMDL8P0/+AP783+L3OBwQezMyZMGxBbIGmfKQ5I0QfsKt2TkVFzjuwoxEX6S66KYXzu9YI9J/5LxqzRjEZv3uyAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/c4ceb8e65853708427d78040856e38b7/40a76/hero.png","srcSet":"/static/c4ceb8e65853708427d78040856e38b7/c972b/hero.png 340w,\n/static/c4ceb8e65853708427d78040856e38b7/27625/hero.png 680w,\n/static/c4ceb8e65853708427d78040856e38b7/40a76/hero.png 1360w,\n/static/c4ceb8e65853708427d78040856e38b7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"When an LLM streams its answer into a chat UI, the browser receives the text a few tokens at a time, and the model is usually writing…","fields":{"slug":"/2026-07-13-streaming-markdown-react-llm/"},"frontmatter":{"date":"2026-07-13T00:00:00.000Z","title":"Streaming LLM Markdown in React Without Flicker","description":"LLM tokens arrive one at a time, and re-parsing Markdown on every token flickers and drags. How to render streaming Markdown in React without the jank.","tags":["React","LLM","Frontend","Markdown","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4UlEQVQoz02R6W7iMBRG8zN4N3EScByHbA4hLAGGpYWyqHSqvv8L9TKVRpWOPl1dfedKTjzi1rRZE9fjejV5eS/Pf/PXR3H6qN4+i9PD7K/15RM2ze3LHu6oWlLXU7d+Wm7tYWYQ0VxmQezq6X6+epstTt3yDNnOX2HzM/w5fMBSxU4EOaIJWICHh5aogutWxA0OChJWNKwgiSqB56wqPMx8bpC0LMxJMAHlH5mHecJGTdKdTbWLJ/1Qd3I8+80wmfOoJjLFwiBhsEj/4w1YwlRl3aHoznn7GiTdUM/gxA9PWXcidlCFpk+1zzTi5nmIG5A1C6s43yf1OalPdnq17dW407jc6/IY2l7qGQ9rGkGnz9ze1jtlFqAgnngDOoZJmS6yczlyNCyfqJyonKoCko8aHlZCt5PFZbp5NOt3257EuEV07Pk0BlmOpirpAt3C83hUPTOuQYYr8CGhQKTFIkM8xdLS4QQLO2Agk4ipUuWbqDrE9XHkjuPmJSy3waQXpgNkuoACkgmJMxJlvtTAAKAjb4BDaqbp9T273O3lri831m/ZagPwfsv7jdgciJ2x5Sr/+rCPm9ptwpcdnc99Ens+DpE0zDYsdQBNHTH1b6hx8IdQbHnR8MLJshVVi3QO4jdXbk0MRLGiNgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/7fde826b4ceb97a0223355de964fb9fe/40a76/hero.png","srcSet":"/static/7fde826b4ceb97a0223355de964fb9fe/c972b/hero.png 340w,\n/static/7fde826b4ceb97a0223355de964fb9fe/27625/hero.png 680w,\n/static/7fde826b4ceb97a0223355de964fb9fe/40a76/hero.png 1360w,\n/static/7fde826b4ceb97a0223355de964fb9fe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time it happens, it makes no sense. A 7B model that served fine all week starts throwing  in the middle of a request, not at load…","fields":{"slug":"/2026-07-12-llm-kv-cache-gpu-memory/"},"frontmatter":{"date":"2026-07-12T00:00:00.000Z","title":"LLM KV Cache: Why GPU Memory Runs Out","description":"A long prompt or a long agent run can hit CUDA out of memory, and the KV cache is usually why. How it grows, the per-token math, and how to shrink it.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2UlEQVQoz0WO63KbMBBG+dUA5qogkEASMverb6FxYgjGaTLt+z9R12Y6nTmjWe1+ZyWlEV0j+lb0VVSf6/NtuI27aRlu8/G6vCzT/gOuH4cZ+tfTchs+T8VQsQbyICo/bP70wAzyMDtl/Zh27/VpSbtLvpuy/gIFNPPdWB7mbvik6dHAGeRBVAxXrFjPWwPFG4dvXPFkRaoVwak7HEbQgQLQbLZBMcTWvnJPPyoTumvU4Zw3Iu622x4FGawwHhnAQTHzU+ZnAU7AV3Sb6XYEAynaRDQIbzUrIkEW8zaJ4btHGaSWK3wvDrDwPOFhiX0JJ/xCeZjM8qRqR8hmDS3GpPtdHOe0/y52X2XHCSMBIyH3I+6HMoxzJvNQZJoVKppJTZcjPyvLw9d0/TMt03B52Q+n/dC1Q1IcnLhGsrF5bbDaCguHpm6YWVjqJlU0i+p2aCLB8jfRz0E94nwkxUTyO7SYwnIKkjccD748O0GlGgG8BxYALxO461boxYMnXrH4ycpZtr9EfYWC14tobiS7ePLVT94dUt9lMME3CciwCWSKaIXCBnBI5dLGizqP9c9Ra5PSJRWiNYxsnGqGvyqAohr+ytMGr6gbb+NQEzELcdONVAP/H/0Lr/wFUNZLWBRwh3EAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3532ef527ffd15a7acd37770357c598c/40a76/hero.png","srcSet":"/static/3532ef527ffd15a7acd37770357c598c/c972b/hero.png 340w,\n/static/3532ef527ffd15a7acd37770357c598c/27625/hero.png 680w,\n/static/3532ef527ffd15a7acd37770357c598c/40a76/hero.png 1360w,\n/static/3532ef527ffd15a7acd37770357c598c/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time a rate limit bites, it never looks like a rate limit. A demo that ran fine all week suddenly throws  in the middle of a live…","fields":{"slug":"/2026-07-11-llm-api-rate-limits-retries-backoff/"},"frontmatter":{"date":"2026-07-11T00:00:00.000Z","title":"Handling LLM API Rate Limits: Retries and Backoff","description":"Your LLM backend returns 429s the moment traffic bursts. How to retry with backoff and jitter, respect Retry-After, and pace fan-out to stay under the limit.","tags":["LLM","FastAPI","Python","Backend","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABvElEQVQoz22Q2XLbMAxF9WQt3EktpERSu+TYdVwvrSeebE7+/58K2X3MzCHmcoBLEAieJrsBZjf15nrZfn+er5dfry+7z7cD8Pby/NC3tyPE9+v+fJjWYwkWMAYrWoe0AUD48fJ0+Oq3r8D6921z/F7vb8P2fXP4Gncf0+5j3t9Md1qRGgBLgKUj0i+oGgkfMou4S4SLuY2ZTRbtE9Dc4qLDqlFZy/Oepg2WPoDSmJYhNhGtuPA266SsU9VI1UAKMUuEp3ekGXnaclmzfIBXEmYDOFW7Gzd/lZnytJ7tAA2pcEL6wY5zs9V5K6VTyj/ignTatFR5MFci7zI7c9WKesr3zwgbqhyipflzEkWLhQUQt0hYIi1llenmbJgRKYOEljExEdYAjIqzJqEVfAexCmVNDHHhfr0LqE+Ux2mdgDmmJsR6gWjJqiZzLNVcwQpKSP1IRHSINLQMoKFvBuuHiJS5bsZ+TEhW6pzxggqNmVng5r+4a55a51umqiAmBVOOZzWF2UxbHLf9rtuchvV5KnsfwyzMLNBH1FhaYbq0GmAv0DlfJRkQoixCeZjkLK2KyqfaRbiA7A9AGVrEPzB4P5h5opdNAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/30ff3f68b1dcfb1160e7300152411747/40a76/hero.png","srcSet":"/static/30ff3f68b1dcfb1160e7300152411747/c972b/hero.png 340w,\n/static/30ff3f68b1dcfb1160e7300152411747/27625/hero.png 680w,\n/static/30ff3f68b1dcfb1160e7300152411747/40a76/hero.png 1360w,\n/static/30ff3f68b1dcfb1160e7300152411747/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The bug looks impossible the first time you see it. Your FastAPI service handles hundreds of requests a second in load tests. Then someone…","fields":{"slug":"/2026-07-10-fastapi-blocking-event-loop/"},"frontmatter":{"date":"2026-07-10T00:00:00.000Z","title":"FastAPI Event Loop Blocking: Sync vs Async","description":"One blocking call in a FastAPI route stalls every other request, including live SSE streams. Here is how the event loop breaks, and how to keep it free.","tags":["FastAPI","Python","AsyncIO","Backend","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4klEQVQoz1WRa2+bMBSGkdYmBHzBGLAN2JhAWEISAgtJk3TT9mnStK3t1P//X3aSTtMmPRz58j6cI3Bs8fEvRl/63fdx/wzs90/97sfh8Gvcvwz9z8P4fHp4hVutL9b8yTsuTYEpUTi2gayb7XnZP1ab02J7brozbN9353r90GxP7fBYtcdAVCS2b5aDmEGsgIp5SaK5Fxgv0CSEQ42v1QI+ux7OaO6zAjI4tDfLOH6gAXTDpxnIqSovnR5WeWMVi2rK61isg2hBwrl/y7wpgOPRfEKyCc7ucYpDSDQoMCTMAY8ql6gpkTDFjJjS2MOm6FfG5JlL4DYHOatk2eb1Si925aZJS8I0jESCeSaGIj1moqdsPiOK8jQRqVKWx3ZGUhAdQrNPZfU09K/j+DJ++No0x3Jd5Usd9W3xZd9+a+3nLBr8IHNxeueriZ/yqPVAJqkDj4n0UtmNXnR6WcY5hmmxCliV8FbwTRKtobOLJWGKx2DqkBewhVmcGZb3SN4h8c5LEKsQg6+S4UB6JPapcLFwUTL146mvSq3PnWkrqVM5RRJEkIV3BdISFtBTJHps9aGbt7UJo4rxSog143NEtYuki8S1LRaAAy/+B3GrMeN5Ii1PCsIt4QXlBfx5Fyf/h5Pf8EtEs8CjTlAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/1e4adbb579bee59ab351a70e64eaa51f/40a76/hero.png","srcSet":"/static/1e4adbb579bee59ab351a70e64eaa51f/c972b/hero.png 340w,\n/static/1e4adbb579bee59ab351a70e64eaa51f/27625/hero.png 680w,\n/static/1e4adbb579bee59ab351a70e64eaa51f/40a76/hero.png 1360w,\n/static/1e4adbb579bee59ab351a70e64eaa51f/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Every RAG (retrieval-augmented generation) post I have written so far ends up calling the same function: give me the  chunks whose…","fields":{"slug":"/2026-07-09-hnsw-vector-search-explained/"},"frontmatter":{"date":"2026-07-09T00:00:00.000Z","title":"How HNSW Vector Search Actually Works","description":"Every RAG stack leans on HNSW but treats it as a black box. Here is how the layered graph index finds nearest neighbors fast, and the knobs that matter.","tags":["AI","LLM","RAG","VectorSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB60lEQVQoz1WR2W6bQBSGuWlihlmYzWyGAduYMWCb2E4cF2ibSr1JojR5/5fpIbmq9OnXz4Gz4gjb86qX22EzvNnxvezfVtcX8MvrK/hqfAe/ur7aHx/bnx/V+FfVI7e9+MRBNEYk9lhid9f2MDT7vt5d6/Zx2z7a5gK6O/Rlddo2l3b3fWPPHokQmoN6NHE8YQDEU9dPkZ8hnlG9JFFN4wYgUfPlJwMatyw9CDvQyHo8c/LymC47qgrMU89PMc+C4k7VT2IziE0vyn4y1SCrSafI+irsSOZrjy0cKnPIZKpA/gKxBVVrokqi1kyXPKyZ3lC5+g9eYGGwLBCMzVRORDaDTVjySQzN/ahm4RaUx41snmT7G3pKO05Ug9r/YYsWkcjJVl263PMAqhqXRFBVxDs/rAERtz6QdgxWBaIGoFGD1colIVza+Yb0jRdAQ3hwKSTnMBILrB81MtlJc+Jp58+tH1geNRBkwZbqksglfAyd94mpPX8aGOq5OIB3KjvPi4s2Dyq/hHfPYfes7S9h7qd4ftH5A5a5SwLY2fg6Z9J4kIzncDBl7nV2VtlJGdCzNvfBZgyPL6Z90ulRpkf4STOsp+QbpIBbT99iPcPB182+jufSmOkiXnfJqsMULhoneYN5cuupGQlmeP4PTIRMIYsQN60AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/19f8cb970a43134f4a3f984c45f292f7/40a76/hero.png","srcSet":"/static/19f8cb970a43134f4a3f984c45f292f7/c972b/hero.png 340w,\n/static/19f8cb970a43134f4a3f984c45f292f7/27625/hero.png 680w,\n/static/19f8cb970a43134f4a3f984c45f292f7/40a76/hero.png 1360w,\n/static/19f8cb970a43134f4a3f984c45f292f7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"An operator asks the copilot “what fixed the  transfer error last spring?” The chunk that answers it is in the index, and retrieval finds it…","fields":{"slug":"/2026-07-08-cross-encoder-reranking-rag/"},"frontmatter":{"date":"2026-07-08T00:00:00.000Z","title":"Cross-Encoder Reranking for RAG Pipelines","description":"Retrieval puts the right chunk at rank 8, but the generator only reads the top few. How a cross-encoder reranker reorders RAG candidates, and where it fails.","tags":["AI","LLM","RAG","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABzElEQVQoz4WQ6Y6bMBSFUTWZCTvYgLGNzb4kEAgQMglJJn3/p+ptRqpU9UelT9bR9TnHi7IT6bLrvsblMZ7WYboN07U7Pqfz2k9rP8LwfpyB60sDz/lzqvZ7mbVxrmwsYQYly0dZLbI+18dntl+r4Rk3l7y718efxeFe9g9Y092F51NUzBYpIfVhS0V3IsMVuisMV1peAkJ3XrgSJiA0V25NrsMZKNFs2JKmG+v2b79iegXNTsnuxvOFZYvHDwZKoPG7QnOEZUcsK+g65etS3M/xdSZjZ/IU8orLOtncw3R2aYtYh6MB6lSLaXak2pGFBPejKG/E+Sa6mdS9V3aobG1ZqRZXHLoXzYMkJxwdPTECJs5eYW7YXBBpOEzDKc+vtLhgPkA7eODZ4FHcoIybG00mzFqPd4CJJGyE2D+lZE5DirEB4fLKy0/EO8RaFB0sL9NMqhh+FRZ3LCabHhzWA/BDGyMMMJOEOy41HQpdBoqdILf93A4K0JrNVIsqBY+/+nYoq1rKWohGSh9z5NLQ5+9G+GGEWzNUv7Go+ke/UBgmO8ELmcSUyZAyzw8Q8RD4yN+E/2rlTQ9+aORNIxs9hNu+6eRdDzZ6sDX+zy/csEbw2u67jwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/8653045cf4c590d50d2952d56a05590d/40a76/hero.png","srcSet":"/static/8653045cf4c590d50d2952d56a05590d/c972b/hero.png 340w,\n/static/8653045cf4c590d50d2952d56a05590d/27625/hero.png 680w,\n/static/8653045cf4c590d50d2952d56a05590d/40a76/hero.png 1360w,\n/static/8653045cf4c590d50d2952d56a05590d/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The worst outages I have seen on Kubernetes were not caused by an app crashing. They were caused by the health check meant to protect the…","fields":{"slug":"/2026-07-07-kubernetes-liveness-readiness-startup-probes/"},"frontmatter":{"date":"2026-07-07T00:00:00.000Z","title":"Kubernetes Probes: Liveness, Readiness, Startup","description":"Kubernetes has three health probes and mixing them up causes outages. How liveness, readiness, and startup probes work, and the failure modes to avoid.","tags":["Kubernetes","DevOps","Observability","Reliability","GitOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABxElEQVQoz22Ra2+bMBSG+dQAvmBuNhgb43AJhGxJadIko+qSTfvSpZOW//9j5oQP06pJj458fJ7XlmzLl0cDEQdWvq4O12r9tnz+3Qzv9eNltb+221/l+s20zXDpD1fjGHOKGCzXywwO5iFvuvXYff7Sb8b207HfvCw342Z3qrpdvx6b/nm1eaHZwkEpuEdMtWBQwEC5RIJAAT93iXI8eYPkU3V9ZZN85okZFiAsQFAAX01YKkv3fXLe6m9bva4pZcLxFPRzMOEpXGu2bYrXQX8d6FBjXQByHxFpUcYbLVaLed9onXM/kq4ngS+nsfGQLOJukfRL1ndx2yCugBGI0YRlY/EAxVRnWNoux1Xn4gwwjVTtQo7nrdkEsrZhZhY2ymxPuDcyCwfCj0QQS3NnGItAlvHPM1muwv0u/j7iuqOXk1e18Y/Rf3oMeCmpppG6hTE3r83B/ekmzHlINyAqQFpCUYEgx+XCJQKJEvK5+RQa5qUZeZmNU8vB6T8ghuIu7c7103s1XJL2BMPGQYkD76CbM89qTDIbMhNOPobpIlA7Vh5ZdQjUFsbVLfzXSeypRcyyIf0IiGcgenBDwwzEpv2Pc+cP/rZDcQAr9q4AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/cfd174a30e720a223f3e3720fedfbc48/40a76/hero.png","srcSet":"/static/cfd174a30e720a223f3e3720fedfbc48/c972b/hero.png 340w,\n/static/cfd174a30e720a223f3e3720fedfbc48/27625/hero.png 680w,\n/static/cfd174a30e720a223f3e3720fedfbc48/40a76/hero.png 1360w,\n/static/cfd174a30e720a223f3e3720fedfbc48/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Someone asks the copilot “what is the retry limit before a transfer job gives up?” The answer is right there in the operations docs: “The…","fields":{"slug":"/2026-07-06-chunking-strategies-for-rag/"},"frontmatter":{"date":"2026-07-06T00:00:00.000Z","title":"Chunking Strategies for RAG Pipelines","description":"How to chunk documents for a RAG pipeline: why fixed-size splitting fails, structure-aware splitting, size and overlap tradeoffs, and the failure modes.","tags":["AI","LLM","RAG","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4ElEQVQozzWRCW+jMBCFWa2UJtwYsPFNuEsMOVvlJDTq7v//SeuQrfTp6c0bjWckGyvRtVx16frP8e+4f5z7y3V9u+/HYXu/78ZxP2q9boZx/zVsh3N30eXj46Fk3wplzDyuWfiCl5uyOxfqXHSXan3N1Kla3zRFr/253g71ZtAtUR9Itp77YuYxww6EDcTM578s/Nsmpi4DaQVCY/rc9Lg2DpA6fGE9Q/ZKDO28uNgVh2P5+Vl+oKSx49KFpe2zimS9bHKU4gDTkLKQUkAIIGzyKOTGwqVeXO7VeOofx/4hyyNcHlzUwJDLJCNccdlhvopgDqIU4oYJFSW17uqH9GYSwpK/D2I1ytVY9t9ZcwOoDgGXIUsCliVZTascZTlaVrRqeU1CwQFlgBqmi72kEuqe9l9PupHUp4C0lkeoSFmacg0XhDLKuFZCKMIE68OhPttJ3Dhn0+bncvVFypMHayuioMqJUhqQFS4TrpCeTD0hfZE6jNiEGAsbuVFOqzOrL6y6xHLnJe9uVOphP80i0cZLRdsdaTa42XB1SIoeLrtALl2mhx1o+sxHFcANwHWAqiCp9ectHGRDYkH8H/RU80WcWIiYETbmNpzb8QR84sCfBM5NOLcmTPhm/ZSTvk36DwfTTb+Bu/4VAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/5ce2db2f91119d288617245a689490cb/40a76/hero.png","srcSet":"/static/5ce2db2f91119d288617245a689490cb/c972b/hero.png 340w,\n/static/5ce2db2f91119d288617245a689490cb/27625/hero.png 680w,\n/static/5ce2db2f91119d288617245a689490cb/40a76/hero.png 1360w,\n/static/5ce2db2f91119d288617245a689490cb/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"There is a moment in building any code-writing agent when the model hands you a string of Python, and the question stops being “is this a…","fields":{"slug":"/2026-07-05-sandboxing-llm-generated-code/"},"frontmatter":{"date":"2026-07-05T00:00:00.000Z","title":"Running LLM-Generated Code in a Sandbox","description":"An LLM that writes and runs code needs real isolation, not a try/except. How to sandbox AI-generated code with E2B microVMs, and the failure modes.","tags":["AI","LLM","Agents","Python","Security"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4klEQVQoz12R627cIBCF/a+xvQzY+I4BAwbfN46aKNkoyW6q9v1fqWxWUaVKn0YHNGc4GgIybsm4kWFFdqr3J/f+OV5+69cPX9XLm3p516f38fxr+fyTrTu4mYzrtf/LFcTAI9QmeZ+VY83XYT6t+4ebTtt+9trNp2F5PT5cjvulYktSWKA6PLQR4t4YxIkIcXugHeQKZSokwte0HqDow4SHiYhSGRJ+53tyhXMFVEIqD6mMUxFkzaTH54KvlC2Q91cyg4g8UFnez+U6gO7yZWT7DKazwjyr8ciUzK8Tg6Qahv1ij+dc3Cf1QuoZKotFj5hKV0NGgSRLJkM3jTRTTL613QsTPGt93gAXttaPjXkq5ANlW9qsmA20H7CyYCUSDXYaegWGw9D1XH1wc+6syuUdsICUrlaPrH8s5E7qJW02SHUUVxFuUudSZ0FrYno6WDCmkEb2jitDSxmiJoDC0tY/OCX1RMqRVJNfmHdGlBWby0cNsqWzrTaHu9anyI8OWxE3PET1NXbOt8b8bPSVrF3Bm1EdJQ2eFZ47UD6wFxK6Bqwiq8K2RU0bHqoAUYUL58Pf8Np/Q4iqKKn9nkFy7AyoDkSLrQatQHBsOtSKMC6Cu0Ph+RHnN27Hb8ov/tP/Lv8CCRJIesEq3/EAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/276b514ff6dac30102034af9dd35cc27/40a76/hero.png","srcSet":"/static/276b514ff6dac30102034af9dd35cc27/c972b/hero.png 340w,\n/static/276b514ff6dac30102034af9dd35cc27/27625/hero.png 680w,\n/static/276b514ff6dac30102034af9dd35cc27/40a76/hero.png 1360w,\n/static/276b514ff6dac30102034af9dd35cc27/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"You swap the embedding model, add a keyword branch, bolt on a reranker, and the answers feel better, so you ship it. Two weeks later someone…","fields":{"slug":"/2026-07-04-measuring-rag-retrieval-quality/"},"frontmatter":{"date":"2026-07-04T00:00:00.000Z","title":"Measuring RAG Retrieval Quality: recall@k, MRR","description":"Changed your embeddings or added a reranker? Measure it. Build a golden set and score retrieval with recall@k, MRR, and nDCG before you trust the change.","tags":["AI","LLM","RAG","Evaluation","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB0ElEQVQoz22RyZKbMBRFWSSxjUGAmBGDGCSQ8YABt4fGbne7V51NKv//MXnY3iSVqlO3jl69u9GTFjwUPKzL6PK6eb+0w3EF+XpYvg3NddheThtIGI5ybs/HlWDkUYGUJohOUDLVKK1OfH3N66FuPxftjS0vYvtRNcB7Kk4wh2fEXr4r8aMCKc31UNbIPUNZH5khMqb2zCkK5PvO7C7PfSNScCwhOzeDSnMKxcwA1cphojlMNamCE+xX2C8VnOouwx4I1V1uEaGa6VyPJDvesOYjZHs7brysJ8U+KPYO7aCP7CIojm62R66wk85KdqotvGwX8AE5QkZEMoggZU/rgXDob61oY4ZrJ201l6kW86lgJfdjYUeLvs1pXiGvXtSMZsUPJZCsQMS8D6ujn/VGsNT9GoCyYnESpT+v+dcla5v8bV/8/qTNqjh0/Nct267Sb/JYLtPqJaqOQd5jsjSCGnCzDjnM8LLmzOsD1/3F8sDWFxAhOt7eSjNkE8WTjEB4vPeLHYDDNSYjTtppdgGfp6e9Tlsoa8nWyHoQPWn1fKd51Uxx4FTw6cm/mFQeT0UQpggncBgVJ+DKU2ASzlRHmszt/zJVnIkCYt15DP8SWPgD0OJOKSmqTUgAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/9561657ff6fc95d7f80513b82185e1c1/40a76/hero.png","srcSet":"/static/9561657ff6fc95d7f80513b82185e1c1/c972b/hero.png 340w,\n/static/9561657ff6fc95d7f80513b82185e1c1/27625/hero.png 680w,\n/static/9561657ff6fc95d7f80513b82185e1c1/40a76/hero.png 1360w,\n/static/9561657ff6fc95d7f80513b82185e1c1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time a database migration ran at the same time as the pods that depended on it, I learned what “declarative” actually costs you…","fields":{"slug":"/2026-07-03-argocd-sync-waves-ordering-rollout/"},"frontmatter":{"date":"2026-07-03T00:00:00.000Z","title":"ArgoCD Sync Waves: Ordering a Kubernetes Rollout","description":"ArgoCD applies your whole app at once, so a migration races the pods that need it. How sync waves and hooks order a Kubernetes rollout, and where they stall.","tags":["Kubernetes","ArgoCD","GitOps","DevOps","Observability"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABvElEQVQoz4VRbW/TMBDON5bEr01iO05jJ06ctHlrt45uHUPakBAwBOL//xquRdM+IIT06HT33HN+znbAzemM8p7o92b47K+/N7tvENv9i1u+9oef3eFHNX0Zjr9y/0SLIyhfR05BRHVIFE3tSja1vx53H4b5oR/vttOpH+628wmYpr9dbj7qamKyxUn9DuuQFjEtApS2RGy5nlk+Yulj5ZBqYlHH0iHdIojyzETSceXyoilKJ1W1EjbiNsBiZMUhtScs96Qccd0i26KqxbWnmwGScwmou7x2rVkv3vS1WWsT0TLAaZOtJ2lmnm9iZrjqlF2gzMoJr2phZlFCdwE+5hVTG2EXUOLERbA2FX3p77vds6wPVHTC7v3y5MZH3dzyfGv6h3Z5roZHaXfQVfVNt/+UN0ci+ojoIGKGqQHOjrmhiUVsHXGH5YyynskOFCHJQ6xx1nG9oFUD7xSRHPjLMLc4dWmxjRMfr1oAVTNTU0iKGKSJhxchcoqYvcKapM5VjgsPBvBHQYjlFQCJEKuLj74kCuK5RXK4FywV/hFgmWQGzEMM65yH1SvkX7iQKHvLsbpCb8oAPP8H+a/Wb3tdQtPhRG8pAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/072a9d5ad2239659e3f54544e74b3960/40a76/hero.png","srcSet":"/static/072a9d5ad2239659e3f54544e74b3960/c972b/hero.png 340w,\n/static/072a9d5ad2239659e3f54544e74b3960/27625/hero.png 680w,\n/static/072a9d5ad2239659e3f54544e74b3960/40a76/hero.png 1360w,\n/static/072a9d5ad2239659e3f54544e74b3960/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Someone asks the copilot “what fixed the  transfer error last spring?” The retrieval step returns three paragraphs about transfer errors in…","fields":{"slug":"/2026-07-02-hybrid-search-rag-bm25-vectors/"},"frontmatter":{"date":"2026-07-02T00:00:00.000Z","title":"Hybrid Search for RAG: BM25 + Vectors","description":"Vector search alone misses exact IDs and error codes. Here's how to combine BM25 keyword search with dense retrieval, fuse the rankings with RRF, and rerank.","tags":["AI","LLM","RAG","OpenSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB40lEQVQoz02PWY/aMBRG89LJQpwEKAnxTUycfSGELANMYKCqAKmsbacPfen//xs1g0pHOrqyfb/ja3MmrAy8pP52Wv8sqh/Z5DwuLvn0ytZ5cWHbsvk1Kb/fDosry2STS9m8jehXZnGSBoJqagalcZlM22S6TIo2mryk5Wpcr2+1emXnYb7I6/Wk2bhJ7caVplNmcZ0u6XRHkmbzCD8hS1DJE7J5xUY9Imnkk4xZS+5SQYEnhHkF2IJHwFrM4jqa/Q/SN5zuwAGgaeAF1PFGxHML21oQ+8WlSwNnPd3TPrsym/eucJJqMTqqJSDAtpdGUVsmdR6NwMqns/bIvroGs0njXTE++cGybwSiAneLyfBAQDiP/WkaWhgC6j/vzvX5NNvtXWdumlUW79N4z8vGI89JCr4jIqz2YFHE1TikFo6CbHa6bv78nh8PYbCwYZ7F2zTaqX0qouFd4UTFvCMgE2k49UehSxwLIj9ujufi7dwcvvneDPCz6yw957WjgqgM7wrHrnnAy8Pbg4nlAKaAy/ZLfTpU7cYyazBrAgtdH/PyQETmPc9k44GADEkxqG2z2Q5xAi+erbaetwBoiD0HXL07//OcIOsf4TsDSbU1PejjhNXuIOgN494w7BoB+yQb+zH8F4mGUab5x2CsAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/dd2bcaa9601c27b33c0e7510855e8462/40a76/hero.png","srcSet":"/static/dd2bcaa9601c27b33c0e7510855e8462/c972b/hero.png 340w,\n/static/dd2bcaa9601c27b33c0e7510855e8462/27625/hero.png 680w,\n/static/dd2bcaa9601c27b33c0e7510855e8462/40a76/hero.png 1360w,\n/static/dd2bcaa9601c27b33c0e7510855e8462/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A workflow pipeline fails quietly. Jobs move through states, get scheduled across a fleet of sites, retry, and mostly finish. Then one…","fields":{"slug":"/2026-07-01-opensearch-workflow-monitoring/"},"frontmatter":{"date":"2026-07-01T00:00:00.000Z","title":"OpenSearch Dashboards for Workflow Monitoring","description":"Build an OpenSearch dashboard that watches a job pipeline: structured logs, an index mapping, the queries behind each panel, and alerts that fire early.","tags":["OpenSearch","DevOps","Observability","Monitoring","Kubernetes"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACD0lEQVQozyWQx47bMBRFtfJYtkV1iU1dVqWaLTu25CJkCiabAMkmi+zT1lkHmK/Jf+TLQs8ABwcX7/GCBIVV0nGkpPOP78PhIbk8R6en6PTI7Q/3yfUD7s888Al3OD7S/RV242rd8oqwBPSGRByvKqpTvZnq7pqzoWov3GV9SotD2ZxZcy6qMa/GrDxSl4krzFvCUvOWqisCOpfpggfFWSjuGzzfAcLNV5zbSnX5+VffEBYyNQiLyguJd7KdarjUcGE4jU4rFWVBPnrZ4Oejnw0k2il2ztFgaZJGNhNBXGKz6IuXn1awhf5+BdnMqBTCJFSoMDdoc4PUptsafqf5jRZ11naEw2Q0O0EUobk5pH9/B/2X67d/fVt//9TbtImCDsBcTzZ6ujXY3mwP1m6E5yu8TnCa0MO90e35zVCPm+DrR5Lfl08vu7b+8bkvwv65Hpb2Wo9aLWjkN7waOBVHdirFqQFMBRFAyYhViykwlXRvZWYzJQYol3GpWAmwEl0PEitcwziG8RqtuV3T90wf6a4wW9p+xKbLCYdbg1Y6rSVrzdJDlh1lXKm0IWZ4oPEpZh2N3vnZPsgTywk1FOpUmK9sSJMiZ8hjFi01xPhDqNsit1X4n+HKMoJf5f5PP21InOKwIGFsOrFOgteyNZfQnYS5RQktALc955bxLQM+gaaMDRlrClZlxFEA1GQEAPwPi4NYmDI7eDAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/9c33da952bb8f40f57c05eb37a28efb1/40a76/hero.png","srcSet":"/static/9c33da952bb8f40f57c05eb37a28efb1/c972b/hero.png 340w,\n/static/9c33da952bb8f40f57c05eb37a28efb1/27625/hero.png 680w,\n/static/9c33da952bb8f40f57c05eb37a28efb1/40a76/hero.png 1360w,\n/static/9c33da952bb8f40f57c05eb37a28efb1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"The first time you wire a tool into a language model, the model seems to do something it cannot do. You ask a question, and partway through…","fields":{"slug":"/2026-06-30-llm-agent-tool-loop/"},"frontmatter":{"date":"2026-06-30T00:00:00.000Z","title":"How an LLM Agent Tool-Calling Loop Works","description":"A practical look at the agent loop behind LLM tools: how the model asks to call a tool, your code runs it, and the result feeds back until the answer is done.","tags":["AI","LLM","Agents","Python","Claude"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB0klEQVQoz02QWY/aMBSF81QgXuPETkK8ZCFJSTIzUAgMDGol2gppXkrb//9fepl2UKVPlu1zju7i5e50x7kXa45Df9nvfo3b63bzY7u57rY/d+ONrvtu9OF/vzdl8ztMlUiaJO+LbrsYdlU/lsNYP+yXq1PzeEjznqmKx+Xd7+HA4sC9YVlU9c2rUg/Ojk190noThR0Xtc8tAgJHo4KEBRYOCwt4iJu/+FyTwC3zi0v2hXkGSn2w8RiGLUiI6ZuHaZ/+AzHj3d7vzOg8lC0LK8JzFtTgFvIj5s7nGQqtTzMUaJI6pkumC6xu4eydOeY2iBomykX2udXnWD4xWYXJ0peGFg2OC9rWYnD5l3X23JGF9nw6RyxDb2Ea5FTkMuyX7uu6fXXJgaWLYN4gCTNrKIsjg2ODlEaxxlJ7M5pOiJqSZILVjKRUFIQ7LXcm2smow9xgZj4gOcExMMUxeO54sAmlhkg2cbKUcQt3LkrMNQ0cSLCCNHmKVAsqEEYNdDojCZSE0wvDelVdF/a46i5DczZqLUQNeVgy1AxE9an5XbuXx/bb0J5LfaTMTbGcEWgh9qATTDWhFhNDqKHMTmEKrHySTnAEl7uKqSHM+iSBMPwDfwCNBEUA8WM2TAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/7250ff100f79cc48a94fdb61a4cb4e3e/40a76/hero.png","srcSet":"/static/7250ff100f79cc48a94fdb61a4cb4e3e/c972b/hero.png 340w,\n/static/7250ff100f79cc48a94fdb61a4cb4e3e/27625/hero.png 680w,\n/static/7250ff100f79cc48a94fdb61a4cb4e3e/40a76/hero.png 1360w,\n/static/7250ff100f79cc48a94fdb61a4cb4e3e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"A language model takes a few seconds to write a paragraph. If your API waits for the full completion and returns it in one shot, the user…","fields":{"slug":"/2026-06-30-fastapi-sse-streaming-llm/"},"frontmatter":{"date":"2026-06-30T00:00:00.000Z","title":"Streaming LLM Responses from FastAPI with SSE","description":"Stream LLM output token by token from a FastAPI backend with Server-Sent Events: working code, the EventSource client, proxy buffering, and failure modes.","tags":["AI","LLM","FastAPI","React","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABk0lEQVQoz32P63KbMBCF+QnCuiJsg7gYHG4yJNgZ1zXGafwASZr2/d+lKxon7p/OfHNmdfastLJ4NUh91s+/q/NbcXqtn36W49vd8AJHKKrRmPr5V3l6bX68T4F3rxl5dRL1yUIknFFV1PuuPzftcfMwNt1Q6QMUuhvqzfdqc2h7Y97vnur2uK4eIQ9TLlGWK1IkEptGiCeAw+K/BWLJZwGmQ2OTYYlNlMsTg0gtRJWDA3MTi1wWT0RX4g/lMfcz4mfYA12DYrEC3yKhlvmjSHvXy+AiBI/A4zdAyCFREGuZaC9qRdhgvyB+YYZltq8PL2l3kastz3ue7+Z6YPlWNkdRfuPlXj5cvKRbZn2zvRTdyIIazwss17CUxVQrVMfje7wozE+8FQ1KurijyxL7uSuBDNaWSof5DpSolqoWNnepshwSOCScCODzDl4iEiAaouvRQAKXpwaRzrwVAAWY1kfbEHzW9pf5P2B4cWXuspDKFIuYeAn1UtAZj0CJSEChC5mb/MKyZ/MvJsu+ad86/yQn/gCzpkI6b86R9QAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/aa9d918b5ab39f1c4481960a11c4f9a9/40a76/hero.png","srcSet":"/static/aa9d918b5ab39f1c4481960a11c4f9a9/c972b/hero.png 340w,\n/static/aa9d918b5ab39f1c4481960a11c4f9a9/27625/hero.png 680w,\n/static/aa9d918b5ab39f1c4481960a11c4f9a9/40a76/hero.png 1360w,\n/static/aa9d918b5ab39f1c4481960a11c4f9a9/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Most RAG (retrieval-augmented generation) tutorials stop at “embed your documents, store the vectors, query them.” That works until the…","fields":{"slug":"/2026-06-29-incremental-rag-indexing/"},"frontmatter":{"date":"2026-06-29T00:00:00.000Z","title":"Incremental Indexing for RAG Pipelines","description":"How to keep a RAG index fresh without full rebuilds: detect changed files with checksums, re-embed only what changed, and handle deletions safely.","tags":["AI","LLM","RAG","FastAPI","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQozy1S226jMBDlZVUcsAEDBuMLOMHcIaYt1bZJmjQr7cv+//+s013pyD5nZo5mxrITdnPUzagZxfbeft4t9OVm0Vxu3fVXc/mypD5dLa/PNvg13n/TdQua0bqcHeIeEjvIk6yp220y134+d/NpWM6WtMNHP53G4+e83qwczed0vGBSA/hwOR6Wu0iAgLsBe4LU9ZnrcwAFQNxF7B+ATaEChBwg9gPk307phdLZBTwkmsgZ5y1mXTx2pNeoLgOlUz5h2oVZExd9woaI6Ej06dzjWqG6gkw5ABaY9qzeEjYm1ZK9m2KbolXH4ygPGy2PhE9ZZfJqTeiQ1IZ+LMm8D80eqb0DEI3ylu+3lI0pN3L5Q/QZlj8HffqQuiHSZLKUc6ZW/Og/5uVK1ZqwKUgPDvDzkGqyXzBvsBhzfU3VGxIvVfXc032Zloe0LFif8BHT1m5hd0lYj/MOxpXzBAg+DvJusFHRq2aHV16/EbmkchHte6FeUrHkahX6ESTyaBfMK2OzAXl0zvxMQCa8jPk5R3EJsfQj4dvzm8CQIywhLv3ISgltQVxZ6QXMPlgGPOLuiOtlKe3KZqNyCkSTa8O6F8p0oxYhBkIOhTLi8BwkyvVS1yfW6NjLhf8BsUBxZfv4sfBj6SclwjzCMoxEEHE7kZ3LC+1HyFyYWeNfAPpNAmAAtIcAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/815c0a626e8039a1fb7e0aacb5827bf8/40a76/hero.png","srcSet":"/static/815c0a626e8039a1fb7e0aacb5827bf8/c972b/hero.png 340w,\n/static/815c0a626e8039a1fb7e0aacb5827bf8/27625/hero.png 680w,\n/static/815c0a626e8039a1fb7e0aacb5827bf8/40a76/hero.png 1360w,\n/static/815c0a626e8039a1fb7e0aacb5827bf8/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"CloudCanvasAI An AI-powered document creation and editing platform that combines Claude AI with a real-time document preview. You chat with…","fields":{"slug":"/cloud-canvas-ai/"},"frontmatter":{"date":"2025-11-15T00:00:00.000Z","title":"CloudCanvasAI","description":"AI-powered document creation platform pairing Claude with a live .docx / .pptx / .pdf / .xlsx preview. Chat on the left, documents render live on the right, each user gets their own isolated E2B sandbox.","tags":["AI","LLM","Claude","RAG","FastAPI","React","E2B","Firebase","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAACD0lEQVQoz0VSy27TQBS1BOSdOI6f8auJJdslrdNFpFKE6Aak0j07ENANH1CBRPeVAIFgEUKy50OgEp/AH5RFlsWKYiclOcydyGako3mfOeeeEbxOAM/1YFkWTNPksG2b97quc6hyA4pUgSpVWV9Fu22wMw67Y7JxO7/nOA4Ez/PQ7Xbhui5arRbK5TJEUUS1WkWhUESxcAuiNYASHEPxj9DsHEI3HYThNkzLhqpq0DR62IButCH0ej30+31EUcQ2VVQqFU5Wr9fRaDTYvAx78ALB8TsER+dwD9/A92/jzmAX/Wgb/R0/x95uAIEkZ3ZbLQlbrgNS7fs+giCAYRjMZg2yWITcLEOq3cCWf4D9hy+x/+AEe/efo3fwBDt3nyK69wyCppFkjdeKLOv6Zq4oCgeplhUVGrNk2S4rwU08enyKz99+4e3kJ84+XeD0/Xe8+vADrz9eQMgKT5AkiSslEk4ky2g2m3y9VqtxCIKA8dchqCVJgv9tjTSJN4SkiKxRGJRUGIa5XSKhWmY9EQ6HXzhFmqZYLq9x/XeF+TzB1dWfjWVKiohJDakilURGtaUykMJsjwgnkwkjW2A6nSJdLDjpbDbjilkoOkwWDBHQJfo2lDKlTeNSqZQjtzweY70G4jjODaeLJeLZHMIg6jB7Pv+opCSznwWT1ZNA6/TYaDTCPElxefkbC6aQ2mq14vgHka1i8FciUU4AAAAASUVORK5CYII=","aspectRatio":2.0238095238095237,"src":"/static/0de17268883730afe1d095730e07f7f8/40a76/cloudcanvas.png","srcSet":"/static/0de17268883730afe1d095730e07f7f8/c972b/cloudcanvas.png 340w,\n/static/0de17268883730afe1d095730e07f7f8/27625/cloudcanvas.png 680w,\n/static/0de17268883730afe1d095730e07f7f8/40a76/cloudcanvas.png 1360w,\n/static/0de17268883730afe1d095730e07f7f8/1e49b/cloudcanvas.png 2040w,\n/static/0de17268883730afe1d095730e07f7f8/2d037/cloudcanvas.png 2528w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Competed in the Argusa AI Challenge 2025 alongside Eisha Tir Raazia and secured 2nd place out of 20 teams with our project ARGRAG. The…","fields":{"slug":"/argusa-ai-challenge-2025/"},"frontmatter":{"date":"2025-11-05T00:00:00.000Z","title":"Argusa AI Challenge 2025 · Runner-Up 🥈","description":"Secured 2nd place at the Argusa AI Challenge 2025 by building ARGRAG, a RAG system for complex enterprise document corpora with multi-modal analysis, metadata intelligence, and real-time performance.","tags":["AI","LLM","RAG","Multimodal AI","FastAPI","Python","Hackathon","EPFL","Argusa"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUCBv/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAHdCGLoEgP/xAAaEAEBAAIDAAAAAAAAAAAAAAACAQMSABEy/9oACAEBAAEFAgkbuu9pOK0s5sjOLx//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAbEAACAwADAAAAAAAAAAAAAAABEQACIRAiMf/aAAgBAQAGPwLKt+TtVAxExg7CLWY4/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARQSFRcf/aAAgBAQABPyHcBX1EhYal8ZXOgNilQNit6I+Z/9oADAMBAAIAAwAAABDwD//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EKf/xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARITFB8P/aAAgBAQABPxAFszEv1x8ohppUm3N+2Fngi1awkiYHnI/JJpDxzQuIqs//2Q==","aspectRatio":1.780104712041885,"src":"/static/0e012013c1c2686cf486cdc39f3accec/ac53a/argusa-ai-hackathon-runner-up-shot.jpg","srcSet":"/static/0e012013c1c2686cf486cdc39f3accec/722c4/argusa-ai-hackathon-runner-up-shot.jpg 340w,\n/static/0e012013c1c2686cf486cdc39f3accec/1d671/argusa-ai-hackathon-runner-up-shot.jpg 680w,\n/static/0e012013c1c2686cf486cdc39f3accec/ac53a/argusa-ai-hackathon-runner-up-shot.jpg 1360w,\n/static/0e012013c1c2686cf486cdc39f3accec/0e329/argusa-ai-hackathon-runner-up-shot.jpg 1600w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"CMS Workflow Operations I maintained the workflow management stack (WMCore + Unified) for the CMS experiment. This system handles scheduling…","fields":{"slug":"/cms-workflow-operations/"},"frontmatter":{"date":"2025-06-12T00:00:00.000Z","title":"CMS Workflow Management DevOps","description":"Developing, Operating and extending on WMCore + Unified, so CMS Monte Carlo and reconstruction workloads stay healthy across the WLCG sites.","tags":["CERN","WMCore","FastAPI","React","Kubernetes","OracleDB"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAWAQEBAQAAAAAAAAAAAAAAAAADAAH/2gAMAwEAAhADEAAAAdShQNJihl//xAAbEAABBAMAAAAAAAAAAAAAAAABAgMRIgATMf/aAAgBAQABBQIwM6CgSXa77KfhX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAQADAQAAAAAAAAAAAAAAAAEQESEg/9oACAEBAAY/AuASsyo//8QAGhAAAgMBAQAAAAAAAAAAAAAAAREAITFxEP/aAAgBAQABPyEQQBWZffMPc3yBxJmRHAn/2gAMAwEAAgADAAAAEDMv/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAERITH/2gAIAQMBAT8QyiUf/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEhMf/aAAgBAgEBPxDain//xAAdEAACAgIDAQAAAAAAAAAAAAABEQAhMUFRYaGx/9oACAEBAAE/EDslU4/K6J4hxn5DjbsqEGEUZ8gXm+o+Ct4M/9k=","aspectRatio":1.3654618473895583,"src":"/static/a2691b872fde247b75a40db137592976/ac53a/CMSAwards-04-Hassan.jpg","srcSet":"/static/a2691b872fde247b75a40db137592976/722c4/CMSAwards-04-Hassan.jpg 340w,\n/static/a2691b872fde247b75a40db137592976/1d671/CMSAwards-04-Hassan.jpg 680w,\n/static/a2691b872fde247b75a40db137592976/ac53a/CMSAwards-04-Hassan.jpg 1360w,\n/static/a2691b872fde247b75a40db137592976/6eda9/CMSAwards-04-Hassan.jpg 2040w,\n/static/a2691b872fde247b75a40db137592976/eb7b7/CMSAwards-04-Hassan.jpg 2720w,\n/static/a2691b872fde247b75a40db137592976/5b997/CMSAwards-04-Hassan.jpg 5322w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Archi · LLM Copilot for CMS Ops Archi is a collaboration between MIT and CMS to help operators access the vast amount of documentation and…","fields":{"slug":"/archi/"},"frontmatter":{"date":"2024-05-15T00:00:00.000Z","title":"Archi · LLM Copilot for CMS Ops","description":"Partnering with MIT to build an LLM-powered RAG copilot for CMS computing operations.","tags":["LLM","RAG","React","FastAPI","CMS","MIT"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABKElEQVQoz21Sy2rDMBDM/39I6TWn9tLk0jSBQqCHUkJbiu3Ypn5bOLh+TrWKV1hWBKtdraTZ0WhXTdNgPsZxVL7ve/i+D8dxtHddF57nYRgG4+w8XjEgHeq6zjhQFAWSJFE+jiKkaapsCcRr8hpQiBJhGFqVbw3eJwLEPggCMI4GLPIccRwb1TiukxR/WX7Ny5fM9+gFkWTPMmhAAqNqWp/Ji7OP42aHt80LLr+RpbMQAmVZqtjSkJOKwQQYf5yw275i/3RA/v1jFOM7ZBbDpchaR+kJNDl98lJNS52tXyaB27Y1NLyyGDGMPeRs7dHIsgx1Xdu/TBpSj936lPvHA+4e9la+qiqlO3UHkTEYUmJeiWyYLm6PX1g/v2vGDJjLzjhLEtTwjPMPMDoKgTtmA9UAAAAASUVORK5CYII=","aspectRatio":1.92090395480226,"src":"/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/40a76/archi.png","srcSet":"/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/c972b/archi.png 340w,\n/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/27625/archi.png 680w,\n/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/40a76/archi.png 1360w,\n/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/ca459/archi.png 1766w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"LLM DevMate A VSCode extension that removes the friction of feeding code context to an LLM. Copy and paste with a single click, and let LLM…","fields":{"slug":"/llm-dev-mate/"},"frontmatter":{"date":"2024-03-10T00:00:00.000Z","title":"LLM DevMate","description":"A VSCode extension that streamlines pasting code context into LLMs. One-click copy, token-aware, works with OpenAI and other providers.","tags":["AI","LLM","VSCode","OpenAI","Developer Tools","JavaScript"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAADV0lEQVQ4y42USW/bRhiGhThchpRIcZFEiaJIbdRiarEi1ZYc27KdpCgKtA1SFEUPRYEWPfTUQw8994+/fYeUohh1gB4ezJDWPN8yH11ShQWJonMtu1CcAEqtA6XZhxJPoPQXUNIV1Okl1MUN1NUe6quHgtU91OUdtNk1tOkVtHSNkipsqJTprR70yRpGZwyDAm39AG1+DXO2hXbzDdTbb6G8omDzFurllwWbdxQ/QjtI9fElSppRRelMYLG9x+P3P+Mt2f/wC+5++h3XP/6Gd7/+ie/++gf3f/wN7/EDznZfQ92/h3pHZKDtV1DXb6AtbqFPt8zQsKEwS9ttod4ZwApTVMIR7CRDdbCENVzBy3Zw5jcwstfQshvoiz305R5ifgsx3UGf3UC74LvzXZGhQly3jfYwhVkfwPZ6MJ0EwuvD4N6odvJny0vg+B3+PUbFiVGW2BHMaAZt9VAIVcokphvDbWWox3PEow3q7Qmc4RKV7hLVIIXPQ0E0QJK0EXa6qPgM6iYoM5ghhRf3xwwdCh1Gi1Brn8MkVnOCZpQi6YTwGzzkdplhnGMw02KfHIQRhRnbcMdLvSqEErPaRrXBTFrMrDGEE4xhBROU2QLT6VCaHIg/rscMZRL67DXESN6y6UIihRWPpbBn5XwtKHtFRv8VJidhOIWYbCGG66fC/EeH0j7lePg5cmFrDJFuIHrLo9CjMCoi57d3XJ/ybDApDEYQ/QuIeCaFXiF0orz5H0vLy/0fyEylkDLByciFetnnTXtQTZ8zyb1Zg1oJoDohND+GWutBa6b5ARGdQ3SyE/K5zR6ybIPjVZIyjbh+BMcLUW/2UOOoNMIB6tEIbjtFrZvxCxpBbwwgpLg1OtEcUTSEIaeBgXOhJM6+QLp9g+nVI4abPaaXD5gudxjPt1jyXcgh113OXK3Lw70TlBg+33lxPl4U1iB5GWd4wUl/wZs64wicJXO81PnvTPhc2We2wOAkGI6EYimnIN/zQs0DhbBSh2APhe7A4GoIwj4adpO0+MMwX4VVPBt2WCADkKOsyJAyicWPvhr0+YX0YdXlUPOZJUnyfaOfY8syPyN7IjSs4BD9hMysyC7MB1+OlpmX+LxMzmUuFJXGJwQsLcjLK2g9LdP+vEzyL6UjBNw1yo1VAAAAAElFTkSuQmCC","aspectRatio":1,"src":"/static/68919a0d82406a304baa414e88002b51/f3583/llm-dev-mate.png","srcSet":"/static/68919a0d82406a304baa414e88002b51/c972b/llm-dev-mate.png 340w,\n/static/68919a0d82406a304baa414e88002b51/27625/llm-dev-mate.png 680w,\n/static/68919a0d82406a304baa414e88002b51/f3583/llm-dev-mate.png 1200w","sizes":"(max-width: 1200px) 100vw, 1200px"}}}}}},{"node":{"excerpt":"Gemini Alchemy Mind mapping is an enduringly popular way to record, organize, and present information. LLMs like Gemini can quickly surface…","fields":{"slug":"/gemini-alchemy/"},"frontmatter":{"date":"2024-02-20T00:00:00.000Z","title":"Gemini Alchemy","description":"A Gemini-powered tool that turns abstract ideas and complex concepts into visually appealing mindmaps. FastAPI backend, Streamlit frontend.","tags":["AI","LLM","Gemini","Mindmap","FastAPI","Streamlit","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAAC/klEQVQ4y32UWU/bQBSF8xB7Zpx4zW5nXwiQBBCQthACUYEiSIGSVl3USnSR2v//C07vzGRxQO3D0dix/OXce+51whQOpAxuw1RyYnLpmadOZvlgqYwST2fnymnZ+bkKSCyAvNSAUe2C+yWw6ibM1g5EeQPpfBVWZw9G1HkOegITCmi5SDIbg+EYV7OvOLu6x/TjIw4n1xhd3mH6/hvO7z9jMv2A8+sZuv0hksKnl/PPYBooZFkuUk4WfjaCE5T06RVg+0V42TLcIISfqyBTbCAo1GFamRhwBRNOUTqkHpEM6lWS+mYQPEk9M8iF7J/B5fMAhhT3/wtbAnXDpQIlLhsvT68I7hb1vexdEEHI+3R+BYrBhFNCQsGsFUyJXmbkjEcUUr2vYV4IvjEkaFmFIZw4SMNWwDhMjgaVx+0cWKYC1twFq/XAWntg9QF4tqpcyrJFisD2Cma5IQHXYARq7ICV2mDFFlhjADYYgR2cgx1egPVH4PQHvNSB8MsQlW2IoKIcStgT4Hxo/UjDtl7AHF7CPLqB+eYLzItPYK+uweg33jsGl7DaQAGtuTvLjRZAgqVlEHpolcOtlzCPb2Dc/oA5+wPz4TdMumYndwoook1Vbhw2B8bWSQJduSnbYDtjmKfvYE4fYfXHpFOYbwl49gC+O6GwaJOC6hpsCVytlEyzpENYAO9+weqNFdS8/UnAGfjeBKKxC+sp0Csjsb6fWT2wYYcCONZAWfL0u3In4eyUHPZPaM+3FGABWiixtuyUFs9U1fyx3hHY/msdxGSmRQHxQwqF3GpgtAZMeRUJzKmZU/2TQ9s+oLMCXmyD0+zx3kj3jMpUzlr7EOEmrFwTojOEVerSdyBUsBhwvptpLSFF4Yh8A5ycyABUCHJUCi3tSKabbVAfawTS7lJ+lYBzmEOlevkm/EITbq4Om1zKe6/QhkMQP+zCpeug2KFnNV0ilRuHrQGtxbR74XLqU16ktXyxjLQvX64sexaHpfyaBq59Oez1ZRdu+GzW/gWT+gsWe/hr3++G7gAAAABJRU5ErkJggg==","aspectRatio":1,"src":"/static/f016772d810716e898c93843aba65547/f3583/gemini-alchemy.png","srcSet":"/static/f016772d810716e898c93843aba65547/c972b/gemini-alchemy.png 340w,\n/static/f016772d810716e898c93843aba65547/27625/gemini-alchemy.png 680w,\n/static/f016772d810716e898c93843aba65547/f3583/gemini-alchemy.png 1200w","sizes":"(max-width: 1200px) 100vw, 1200px"}}}}}},{"node":{"excerpt":"What’s Cooking? Predicting Cuisines from Recipe Ingredients Kaggle is an online platform for hosting data science competitions. On September…","fields":{"slug":"/whats-cooking/"},"frontmatter":{"date":"2020-05-11T00:00:00.000Z","title":"What’s Cooking? Predicting Cuisines from Recipe Ingredients","description":"Semester Project - Information Retrieval and Artificial Intelligence - CS317 & CS401 - FAST NUCES (Karachi)","tags":["AI","Classification Model","Exploratory Data Analysis","React","Django","REST","API","IR","Python","Jupyter","notebook","netlify"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABJ0AAASdAHeZh94AAADLElEQVQ4y3XS3U9bdRzH8dNH2o6ePh1aTp9LD2V9om0KrIUOS6GjQGk7ixvEonGMuSVmLkEL6OaMj7vwQpcs6rKNDqcX7kITbzTxyn/s7a/G+JDoxTffm/N7/b7f3+dIo73PMHY/wdD+CMPGhxjWPkC3fBtr+0uSG19QbO2ibNxhtnIDf3uPyPp9qlvXsS4dY82K79LH2KaOGE2I0g6RAvufs3znKY33Tmm8K/qxqMMT1o6+pfP2U3rH92n1B1y+9RXdwwdM1A4IzTTwVXqM515jrLCPO/c6Nm0XS2QHqXz9Y54/+JqHj5/z6NH3PBH95MkPDE5+ZDD4iZPBL3xz+jOnz37lu2e/MVPqIckLTE5fRiu8RDlVpjVdpqTG0ew+pGi3Tz4yj92Zx+0q4HIVUZR5fL4qfv8qoVCTaLRLPL6DFt9lbvFNOlfvsb77Puc7fZYyFW4uVbhVr7JdKiPFr/RZrJfR1LNMhgv4AyXC4UWisRWBrJNIdDibvEQm8zKpzD71+Qv0t8McbMe40YyizFWwbzVwbNWxV+eRcq++xXa5gNuvoUYzeNUCqjpHMFghEqkRizXQtJaAtwTaY8zbQpIW0BtL6AwzmIzTmA0pUQlGTBNI6d5dNlNNbEoSjy8n1k3h9eb/QsN/onGBJsWkXu8mesMiJvMCJtM50YuYzTnR06JPIWWv3OXFwiruURW3M4bTqf0vmki0UcZa6PU1gb0gagHjEDUVBZgTYBpJ3T8iVsrjc8oEfT4cjjBO13+g4Zp40zU8yhBcxWhcFti/0eGkUmzvgPy0hkH2iLX9nHEHkeWISFsTh/9GA4GKSLuG2z0EmwJcxfAPdLi+Wawv+a/dZiI7i9XqwiGrWG0KZ8T6smOITopJ03h9w6CG6Z/H5e6g018UkEBNDQGvCKwqLimj080gRa7eJO23YZYkbAYjJr0Fi1nGZlGQRwM45Rge1xRjIjR1PCsuXRMpd9Dr1gVy4Y/31OkWcTlXGB+vI7nabyD7IoSTBaxKiBFnEG8ki8ufJqidQwkUxS9VJKTN4o/m8KhdRuyvYJF3sNgvYZO7GC1NNi++w961T/kdfYWcKXqoFgUAAAAASUVORK5CYII=","aspectRatio":1.588785046728972,"src":"/static/f7860cd3340dd34dea20917fb2024f01/40a76/Annotation%202020-07-23%20082642.png","srcSet":"/static/f7860cd3340dd34dea20917fb2024f01/c972b/Annotation%202020-07-23%20082642.png 340w,\n/static/f7860cd3340dd34dea20917fb2024f01/27625/Annotation%202020-07-23%20082642.png 680w,\n/static/f7860cd3340dd34dea20917fb2024f01/40a76/Annotation%202020-07-23%20082642.png 1360w,\n/static/f7860cd3340dd34dea20917fb2024f01/06587/Annotation%202020-07-23%20082642.png 1391w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Repo: Click Here for Github Repository Implementation: Indexed Given Documents of Trump Speeches using a Vector Space Model. Pickled the…","fields":{"slug":"/IRA2/"},"frontmatter":{"date":"2020-04-11T00:00:00.000Z","title":"IR Vector Space Model","description":"Vector Space Model for Information Retrieval- Assignment 2 - CS317 - FAST NUCES (Karachi).","tags":["React","Django","Electron","REST","API","IR","Python","Vector Space Model","Jupyter","notebook","netlify"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAABJ0AAASdAHeZh94AAAEUUlEQVQ4y1WTeUxUVxSHXxORkXmzKEqpSdNal1ZLI7VUFlGpu1JwGUBQQxC3FmvLog4M6wiIgGDE4pJqIdqa+gcuKJrWXZBa05jWrTZpomFmmGGGGXEUXKB8vTOtVV/yy7v33Pu+87v3nCepE8rR6LagWbAZdWwJqugS1LOL0cwoQj2tENXUQtST8lGH5aL6WOgjA6pgPfIHQmM3onp3PfKoLOQRmSjfzEDSJFWgji/Dd1EFg2LEOLoYxbwSfGdvZlBUCfLUIgZOMTIwzIhyYg6KEAM+4wvwC8pmoJDPmByUIzegfCcD+e1MJNXSCgKS9xCZZGBS2mr8kqoJit1EyKdZjF76FcMWVhA8U0/wgjTemL+XMVGlRMxJIWBuPmND9QRFrkQbuZEhIaUoR6QjycmVBC7fiy5xPRPTV6FeU0NYTCFxC1cyfe1SAhMqiZm9jujkJIbH1xH+SRExC+IZritgVkQm82IT8NdlMCS8DOUo4VCzvBp18lb8llWhXFyFJn4Lsq6coQlbeT1OJFtUTsD8coZFl+M/s4jAOZsJmF4ijp+HX0guiuA8lOOzUb6/0XunknbVNjxQTbKALavEc6d+ujLGrdlFZOY+QtJ2E7xqJx+m1jJCV0lISi3vxVXhG2pAHZ7nLZQ8wYAcLKBBeuHws+08hw5OqWaAKNDaXU00td6gsfU2J678ScOlWzRcvClid2hsvs35X/8iTv8dr03Qo4nIfwUqadNqeA4dnFqNYkkFM43fo68/zbo9pyg+eJEDP11jv1DevjOk7zhJzu4fCU3diU94LurJBchhL5xK2i93oF1bg/YlqE/iFqSFpUiz8gnL2sexlhscabnNW0uqkcKEiwiDaKV8NNOMqKaIXo0ULv+DStqMWrzQtBfQISuqGZq6DXlJJZM2fENF/TFK9x5l3IoaVDGl+MeWoZ0rfoAZRtH8Rf82f2SBFyqpM2tRpn+N/MUO5M+3I68RWilgKVUMEE5HijZKLK4jwVhHYFIlPvM2oZgrNMuIYnoRiqgCFJPz8Y0Q1RaSEr89weHW36g7e5X6s79Qf0bo9BUOXrhG49U7NPz8Bwcu3GD/ud9paL7J0ZZbHGkWunSTI6JQh89f5/C56xwXhYtavQep8GQrPOzCdO8uTpuVLoed9rZ7OKwW3C4nXZ12nj5y86zbjbPDisvRgcPWjvu+E6fdxgNXJ/T34XmWFfyAlH28mb7ubtosVhydLu53PcDW4RCyY2m3YTJb6LA7sDuctJnMmEwWzOZ2zJZ2sW7FauvA/bCb3mfPWJx3ECmnqYXeh25MYkNnpxOX6z42sclqtXllEXGHoxOn0yVAlv/jVqvVu88ukvX0PBYm+0gsFA5zTl72AttEZs+iB/r8o3bhwGw2e+MeqEk49EA977Y2E3fv3vPOu7t76P9bAI2HkAynLovT9+N+1MPjx0+88mR8efzy3KMnT56+Mveov69XdMMh/gExfWfezjhUOgAAAABJRU5ErkJggg==","aspectRatio":1.152542372881356,"src":"/static/9dfc43e2f27e5b6a0b0978f89aaf8742/3225f/pic2.png","srcSet":"/static/9dfc43e2f27e5b6a0b0978f89aaf8742/c972b/pic2.png 340w,\n/static/9dfc43e2f27e5b6a0b0978f89aaf8742/27625/pic2.png 680w,\n/static/9dfc43e2f27e5b6a0b0978f89aaf8742/3225f/pic2.png 920w","sizes":"(max-width: 920px) 100vw, 920px"}}}}}},{"node":{"excerpt":"Solution Challenge 2020: TabdealIt is a solution for Recycling, Reusing personal items. ‘Tabdeal’ تبدیل means exchange.\nTabdealIt provides a…","fields":{"slug":"/TabDealit/"},"frontmatter":{"date":"2020-03-30T00:00:00.000Z","title":"TabDealit","description":"FAST-Barter (AKA TabDealit). A online Platform to build Communities by exchanging items the old barter way.","tags":["Angular","Firebase","RxJs","REST","API","Google","DSC","Solution Challenge 2020"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAACwklEQVQoz22Ra0iTARSGP0jKoijpR1BBEl0pQjKosKxlWjpN3RSnpsulc2vq5mXW0uk2nSWmXZQwi0TJWsW6aoWCrTITpbt2tytF/Spvi5R8+hT814GHw4H3vAfeI3iFJzI9JBbPoGimBSvwCJDhsSWSSRNIxoj4L2O6yaJ+hjSWKeKujyIRIarWSUTNOaRV9QRVnEJy8Dj+9kr8rIdZay5jjekAPjk2VhoKWKYzsUhtxFtlYH6CjlmyXUwNjWemVIH35m3M3RiEoL3VTsqNNnbWXiDKbEGebyEkM4fAND2BOj0BmnQkqTr8kzVsStaKaPBXaZCo09hbWUP5mYtIjQXMCovDKzQOQdfcgVo0TDp/g7iq08SKyMurkZVWEmY/wg57BVJrGXJxDi48yNb9RfgZctggElZgIaIwn9VaA7NjUvGSqxAMrkektXahdjShKqokMs1MtEEUZhWjrT5L3yi4gdPnziNTJJBozuPkRRm2Uj/WBfiSZwtAbZczJz6DOQo1grH9OZltz0g5e5ndeTYkvmtRJexik9JAdnUD/QP9HK2oQLkzkeAtgSgy1NQ7/MjN8sVzyjRWLV2IXBfNgpQc5om5Cqaul+R2vkXjqCNaF0hMnBJjvpX4jGSSSkqx2IpQJijJytiDq/kmjY/uc6mplMar18kyZLN183rk6dtZpMsTn5WJUPi0F9Pj9+xruiZePsa2HTGkavU4rjRwyOnE6bxM+YFiOttvM1bOB62UVYXzsLOJO657nDyhJL1EypJ0K4u1uQjFL79gevKe6mdv+fXzFy5XGy+6e/gzNETr614Gh0dwDw6MmyHm2dLzAldHPT3dt/j67QNvXl+jrtnBEr2FFXozgv3VV/K7P9Pw8QcT9Wd4eLy3ff5On/s3v91u+vr6GR0Z4e67TwyOiN5/YWBwaFzX0t3L8mwrPsYi/gEbCfsPZ6IJQAAAAABJRU5ErkJggg==","aspectRatio":2.035928143712575,"src":"/static/91be5a1c74b4d8217d953eb8641e94c4/40a76/pic1.png","srcSet":"/static/91be5a1c74b4d8217d953eb8641e94c4/c972b/pic1.png 340w,\n/static/91be5a1c74b4d8217d953eb8641e94c4/27625/pic1.png 680w,\n/static/91be5a1c74b4d8217d953eb8641e94c4/40a76/pic1.png 1360w,\n/static/91be5a1c74b4d8217d953eb8641e94c4/60d1f/pic1.png 1896w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"Repo: Click Here for Github Repository Implementation: Indexed Given Documents of Trump Speeches using a Inverted Index. Designed a Query…","fields":{"slug":"/IRA1/"},"frontmatter":{"date":"2020-03-10T00:00:00.000Z","title":"IR Inverted Index","description":"Inverted Index Based Boolean Information Retrieval Model - Assignment 1 - CS317 - FAST NUCES (Karachi).","tags":["React","Django","Electron","REST","API","IR","Python","Boolean Model","Posting Lists","Inverted Index","Jupyter","notebook","netlify"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABJ0AAASdAHeZh94AAAEOUlEQVQ4y0WTC1BUVRzGrzqy6L6uAolmM5qaogUqklCKEr5ISQfMIBQncVBREVfkIQgLLuzyEnfxQQqGKGBJjJWajuYDy9IynTHTnGo0S56yu7AqpvnruGt5Z775/ufcO7/7nf85R1pUVcHi/dUsra8lrr6O6NpqIvfuJrpuj0u1/6nquWqqeF/4/KpK5u7axbyKXURWVhJTswdp5LLt+MRtY2iMmWh9HaXVJ8i0HML3PTOj5m3GJ7wYn7AifGYUMirUxKgpRnwm5/Oyv54PVlRRUXGc8h1HKTR9hp+vHqlPlIk+840o3jHQL8LI4AUFeM/Lxz0kC7dJmbgFZeAWkI7buFTcfFPoPTqZ3iPX0XPIGl4KyGTiLBMTpuXh+2YOCo+VSNrFJWhjipCjClELoGJOHu5heajDNqGeLhSiRxWcjSpoI6qADSjHZ6DyS0P5ahqKYTp6vphIT+9EenmtQjkwUQCXbEYbW4JGQLVRRQxcYGTAu3rk8Hy8ZgkPy8EjVI9HyEb6BRvwCkpBOzGD/uPWoxFgzeg01CPWoR66DuXgJCQ5vhRZQDWxRfRbaGHWwo34JSYxPKqYiMh4xizT8cbsNKZEr+SVuRWER8QyLDyXsLeWMGS+DpV/DsoRwocL4BCdACaYkeO34EpajCySKiKN9BDJes3MQha99ZidhzwjB01INpJ/KtJrySjGpqARvVWKlKoxqahGrndCJXm1Be0KF/Rp0j4C6Je0k8UlDSwsaCBV7GJu9Wmyd59EZznMouxPiNv0Ka/HlOE+Lh21/wZXT59BJXntVuTVZcgJFvovN+O+qIgwQx35+78iZ98JDHWNpFceJ7n8KAYBLq45Q/G+08xesxuF2CRtYKYTqh7rSirJ67ehSdqKepUFzfItqJeW4iEkReQivZ2FZ3QBwavMBMaX4C1OQY/gDKTxOnoFiuVOzqJvYAbKCRvoK9IqfdOQ+qfvwDt9J94pH+KtE/WabbyQUMagFWV4xZkZm1ROouUAyVvrCUjYjjzXyKCIQgbMycdzpgHPabl4TtXjOSkbzQTxsyDzx5y5coNTl3/m5CWhi1c5f/0ml3+/w6Vf/+L7X25z9qdbNF65yYVrf3Dpxp9cvH6bi6L+8dptp364eotrvzURuqQcKXRnAw+6HHRZO4SsdNmsOOw2Hji6RG2j2+Hgnhjf77Q755++t4tvHZ02bB3tdNqtWDvuwpOHRKwVd3mqALbdtdLS2k5rewfNwpvbhFrbaG5pc3rTM7/T1OKsm5pbnW7vdNDpuI9N+OPHjwhP+ghpesVB7tvtWFtasLe3YWtt4dE9Bzzs5kn3g+cS43+e+t/d/0vEwvW4PCJlL9Lo0hpyjp0j60gjWYcbyf6ikfxj32E6dgHTl+cxHRH1oW8xfn4O08FzGBu+wVj/NcYDZ8XROkNe7WkMe09RWNuIX6yFfwHMMRzOZj+n8wAAAABJRU5ErkJggg==","aspectRatio":1.2408759124087592,"src":"/static/055be7250581a70a92da611ff180c2e7/dc180/pic2.png","srcSet":"/static/055be7250581a70a92da611ff180c2e7/c972b/pic2.png 340w,\n/static/055be7250581a70a92da611ff180c2e7/27625/pic2.png 680w,\n/static/055be7250581a70a92da611ff180c2e7/dc180/pic2.png 1260w","sizes":"(max-width: 1260px) 100vw, 1260px"}}}}}},{"node":{"excerpt":"AlgorithmsVisualized Binder A Jupyter Notebook with Different Graph Based Traversal and Search Algorithms Visualized. Current list of…","fields":{"slug":"/AlgorithmsVisualized/"},"frontmatter":{"date":"2019-12-29T00:00:00.000Z","title":"AlgorithmsVisualized","description":"A Jupyter Notebook with Different Graph Based Traversal and Search Algorithms Visualized.","tags":["Jupyter","Python","DFS","Astar","BFS","Best-First"],"thumbnail":null}}},{"node":{"excerpt":"NU-Forum is built on Django Web Framework which provides a extensible environment for Future Extension and Up-gradation. A Restful…","fields":{"slug":"/nu-forum/"},"frontmatter":{"date":"2019-12-01T00:00:00.000Z","title":"NU-Forum","description":"NUDESK is built to provide students a platform to seek help from seniors. built using React, Python Django, PostgreSQL.","tags":["React","Django","Webpack","REST","API","PostgreSQL","Python","DjangoORM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAACo0lEQVQoz3WRWU9TARCF758wBgktLZWCLJGt7aUULgUERJCWsARoC12AVmW3UJVdBWWHiDsRDRoNICpFowFZjBgNUXky/pnPS3n24cuZk8nMnGSEvBwzbRd9uOvsqFQqNBoNmijNkf6H6OhoYrVaEhMT0BvEEBnGdCqt5xC02hjMkoSUmRlaqI6KIkoeUqnVRCiUKJRHHNYRsioP/WGtUIRUrQgn7Pgx1GoVYloKQqFZR5YhjlxTElJ6EqaUU0hp8Zj1CeQaEshIjUdMjqfAmIQ1KxlJn4JoMGDQpWHM0JFju4h/8CZOt51MMR6hpsyIq0rCU5FJkSmByPAwTipPECsTHRFGjDKc2MhwtIow8uXDpTmpaORUKYknudBg4VJ3M6Nj1/C3O3BVSgiuyixqzhtwWCRGAj5a6qoZ7WlnpLcdn8dBY10tHlstzQ31zE/38erRcKjX2eplbqKH+dleAi0VVJTosRYZEHx1eZSfTWWozcby4ymmB7t4MjvM9toL/v7Y4PdOkC/rK/yS9efnNfY33/Ln20f2t9bZCi5z8G2DuckeaqvMeO1nEJxyzOKc0/jd57k7EqCvs4l7Y30sP33A6sJ91hbvEnw+x9L8DIv3Jnl2Z5Q3CzOsPJqW/QTvl+YZv9GKvTIbmyUDwVqgx1YqMn7VxdLjSaauB3g4PsD2u+d831hj6+1LPq2+CrETXGF3/TW7crKvH96wtxHkYG+T+1M91JRnkW1MRKg4q6f6TDJDl92MDQVobbLR5nVwu9/P6EA3w/1dTMhHQr63lVtdboY6XAy0OxmUdbDDTYfbSm2JSFluEoI9L47GEh2XncVc8ZTQ7yujz2sh4Cqi21lIV30Bfkc+XqsJd7FIW5UJnzUdn+UQMTTbUKzDU5RKg/yYf2c3qB1M07vKAAAAAElFTkSuQmCC","aspectRatio":2,"src":"/static/b87769bf3ed5668c4b75ee4e9ac58c4f/40a76/home.png","srcSet":"/static/b87769bf3ed5668c4b75ee4e9ac58c4f/c972b/home.png 340w,\n/static/b87769bf3ed5668c4b75ee4e9ac58c4f/27625/home.png 680w,\n/static/b87769bf3ed5668c4b75ee4e9ac58c4f/40a76/home.png 1360w,\n/static/b87769bf3ed5668c4b75ee4e9ac58c4f/90f55/home.png 1892w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"QR based Attendance system that consists of an online portal separate for teachers and students. Students can register themselves on the…","fields":{"slug":"/qras/"},"frontmatter":{"date":"2019-12-01T00:00:00.000Z","title":"QRAS","description":"QRAS is QR based Attendance System. built using Flask, and Basic JQuery, Js and Bootstrap.","tags":["SQLite","Jquery","Javascript","Flask","Python","SQLAlchemy"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAABSklEQVQoz61Ry07DQAzM53LkyI0v4MJfgJB6AKEKxAUQfEKBggA1UErbZF9JNpvdHbybRkopHJCwNLK9icdjO8kWC8zmS3xmEkKqDTAukDMefcirUmM0e8Lh3SmO7ocYPJzhYHSCi+cbFLJE4qyFtS5CqQKqKFCWJcUKdW3gvScg+s60Ncg1R14LMEJGsTAq/pOgZ+/TKcbjR0zSFGn6hskkRdM0KKiJMQZa69jM0tvPRoStghahiAvqylgsDERilQfFQkqwPMPHUmLvssH+dQ2mykjUcSTdKB2hpCIhJKqqopHr6APCt5iXCnOusTN02D23kJVZEWKTMIzEOY8IirpdhiatYsoFxzQrsDWw2D5uSKH+nTCYpSOFvfXfnXOrDYFiC914XL143L56WIe1+qSf9C/5PfethB8P0a9fU/gXWNeire+NjH+2L1NeCJA+CmwHAAAAAElFTkSuQmCC","aspectRatio":2.0118343195266273,"src":"/static/03e53cdc372f5f71844f5ff02025907f/40a76/home.png","srcSet":"/static/03e53cdc372f5f71844f5ff02025907f/c972b/home.png 340w,\n/static/03e53cdc372f5f71844f5ff02025907f/27625/home.png 680w,\n/static/03e53cdc372f5f71844f5ff02025907f/40a76/home.png 1360w,\n/static/03e53cdc372f5f71844f5ff02025907f/7eb01/home.png 1915w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}},{"node":{"excerpt":"QRSMS QRSMS - QR based Student Management System. built using React, Python Django, PostgreSQL. Three Portals. One for Teachers, One for…","fields":{"slug":"/qrsms/"},"frontmatter":{"date":"2019-12-01T00:00:00.000Z","title":"QRSMS","description":"QRSMS - QR based Student Management System. built using React, Python Django, PostgreSQL.","tags":["React","Django","Webpack","REST","API","Python"],"thumbnail":null}}},{"node":{"excerpt":"Working: Program starts by taking cache size,set associativity, cache block size and the user program size as input from user. Number of…","fields":{"slug":"/cache-size-over-miss-rate/"},"frontmatter":{"date":"2019-11-29T00:00:00.000Z","title":"CSoMR Study","description":"Cache Size Over Miss Rate Study.","tags":["Cache","CA"],"thumbnail":null}}},{"node":{"excerpt":"PyQt5, A Python GUI Library, was used to design the User Interface for our ‘MH Graph Solver’. It takes the provided netsim input files…","fields":{"slug":"/graph-plotting/"},"frontmatter":{"date":"2019-11-29T00:00:00.000Z","title":"Graph MST Plotting","description":"Cache Size Over Miss Rate Study.","tags":["Cache","CA"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAABbUlEQVQoz61S207CQBTcW2lLtwqkqBhJtUS8xJiYmPgh8gN8AJAQ5PL145ytCAiPbjI5t905s2dXWWvhnDtCFKxFHMfI8xxxowFtHdRvbQfhiKIIVVVBcYXAMWmtCUVtDJSufTmQJAljjY4z6LOJYt3JHsJwjxGfPEVR1IQNdhe7RaIVXpw6yInSoqlRxLtcSjhCSCVutVpsTEdTRY8qhonD+8cbht0MA+arQQnvs7C5KnvIUovrC49mRCKiZNOcytUPYbvdrgkVZ/PkPV6LDPm5r68sytmklxg8+1rRXb+Lx+EdypvLnXoS2n3CMEMq3L+eQO/ZVmw58BJXZwkio5FnuxHpk4R8lL+ERw3Y9Jbz84FERGwJ1SGhBGma1i994vsEyAFjcc8Z+4jfhnigH1kXzsmDCU+n06kV/hfC9xqPxxDM53Os12ssl8uA1WoVrOQ2mw3WjBdSo5Xal8SLBWbTKWazGSaTCUajT3wDdQ7t9M2xczgAAAAASUVORK5CYII=","aspectRatio":2.0238095238095237,"src":"/static/7212e3f1bff418a4ea75baadd1a83b0c/40a76/dijkstra.png","srcSet":"/static/7212e3f1bff418a4ea75baadd1a83b0c/c972b/dijkstra.png 340w,\n/static/7212e3f1bff418a4ea75baadd1a83b0c/27625/dijkstra.png 680w,\n/static/7212e3f1bff418a4ea75baadd1a83b0c/40a76/dijkstra.png 1360w,\n/static/7212e3f1bff418a4ea75baadd1a83b0c/eef2e/dijkstra.png 1501w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}}]},"allFile":{"nodes":[{"id":"10abbc74-b975-53f0-aaf8-e1394e382d6b","children":[{"__typename":"MarkdownRemark","id":"c242602d-b4c9-58d3-8f3f-697989a286fd","fields":{"slug":"/whats-cooking/"},"frontmatter":{"title":"What’s Cooking? Predicting Cuisines from Recipe Ingredients","date":"2020-05-11T00:00:00.000Z","description":"Semester Project - Information Retrieval and Artificial Intelligence - CS317 & CS401 - FAST NUCES (Karachi)","tags":["AI","Classification Model","Exploratory Data Analysis","React","Django","REST","API","IR","Python","Jupyter","notebook","netlify"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABJ0AAASdAHeZh94AAADLElEQVQ4y3XS3U9bdRzH8dNH2o6ePh1aTp9LD2V9om0KrIUOS6GjQGk7ixvEonGMuSVmLkEL6OaMj7vwQpcs6rKNDqcX7kITbzTxyn/s7a/G+JDoxTffm/N7/b7f3+dIo73PMHY/wdD+CMPGhxjWPkC3fBtr+0uSG19QbO2ibNxhtnIDf3uPyPp9qlvXsS4dY82K79LH2KaOGE2I0g6RAvufs3znKY33Tmm8K/qxqMMT1o6+pfP2U3rH92n1B1y+9RXdwwdM1A4IzTTwVXqM515jrLCPO/c6Nm0XS2QHqXz9Y54/+JqHj5/z6NH3PBH95MkPDE5+ZDD4iZPBL3xz+jOnz37lu2e/MVPqIckLTE5fRiu8RDlVpjVdpqTG0ew+pGi3Tz4yj92Zx+0q4HIVUZR5fL4qfv8qoVCTaLRLPL6DFt9lbvFNOlfvsb77Puc7fZYyFW4uVbhVr7JdKiPFr/RZrJfR1LNMhgv4AyXC4UWisRWBrJNIdDibvEQm8zKpzD71+Qv0t8McbMe40YyizFWwbzVwbNWxV+eRcq++xXa5gNuvoUYzeNUCqjpHMFghEqkRizXQtJaAtwTaY8zbQpIW0BtL6AwzmIzTmA0pUQlGTBNI6d5dNlNNbEoSjy8n1k3h9eb/QsN/onGBJsWkXu8mesMiJvMCJtM50YuYzTnR06JPIWWv3OXFwiruURW3M4bTqf0vmki0UcZa6PU1gb0gagHjEDUVBZgTYBpJ3T8iVsrjc8oEfT4cjjBO13+g4Zp40zU8yhBcxWhcFti/0eGkUmzvgPy0hkH2iLX9nHEHkeWISFsTh/9GA4GKSLuG2z0EmwJcxfAPdLi+Wawv+a/dZiI7i9XqwiGrWG0KZ8T6smOITopJ03h9w6CG6Z/H5e6g018UkEBNDQGvCKwqLimj080gRa7eJO23YZYkbAYjJr0Fi1nGZlGQRwM45Rge1xRjIjR1PCsuXRMpd9Dr1gVy4Y/31OkWcTlXGB+vI7nabyD7IoSTBaxKiBFnEG8ki8ufJqidQwkUxS9VJKTN4o/m8KhdRuyvYJF3sNgvYZO7GC1NNi++w961T/kdfYWcKXqoFgUAAAAASUVORK5CYII=","aspectRatio":1.588785046728972,"src":"/static/f7860cd3340dd34dea20917fb2024f01/40a76/Annotation%202020-07-23%20082642.png","srcSet":"/static/f7860cd3340dd34dea20917fb2024f01/c972b/Annotation%202020-07-23%20082642.png 340w,\n/static/f7860cd3340dd34dea20917fb2024f01/27625/Annotation%202020-07-23%20082642.png 680w,\n/static/f7860cd3340dd34dea20917fb2024f01/40a76/Annotation%202020-07-23%20082642.png 1360w,\n/static/f7860cd3340dd34dea20917fb2024f01/06587/Annotation%202020-07-23%20082642.png 1391w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"whats-cooking/index.md","relativeDirectory":"whats-cooking","ext":".md","sourceInstanceName":"project"},{"id":"96c84481-ccb3-5e68-a03d-af4f96098e12","children":[{"__typename":"MarkdownRemark","id":"0917f7c3-587b-5ede-b9d0-de0c67cb9423","fields":{"slug":"/qrsms/"},"frontmatter":{"title":"QRSMS","date":"2019-12-01T00:00:00.000Z","description":"QRSMS - QR based Student Management System. built using React, Python Django, PostgreSQL.","tags":["React","Django","Webpack","REST","API","Python"],"thumbnail":null}}],"relativePath":"qrsms/index.md","relativeDirectory":"qrsms","ext":".md","sourceInstanceName":"project"},{"id":"4325ef2a-eed1-5a63-abd5-d25bc6d38ee2","children":[{"__typename":"MarkdownRemark","id":"348e440b-eaee-5f26-8cd0-30f231935cca","fields":{"slug":"/qras/"},"frontmatter":{"title":"QRAS","date":"2019-12-01T00:00:00.000Z","description":"QRAS is QR based Attendance System. built using Flask, and Basic JQuery, Js and Bootstrap.","tags":["SQLite","Jquery","Javascript","Flask","Python","SQLAlchemy"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAABSklEQVQoz61Ry07DQAzM53LkyI0v4MJfgJB6AKEKxAUQfEKBggA1UErbZF9JNpvdHbybRkopHJCwNLK9icdjO8kWC8zmS3xmEkKqDTAukDMefcirUmM0e8Lh3SmO7ocYPJzhYHSCi+cbFLJE4qyFtS5CqQKqKFCWJcUKdW3gvScg+s60Ncg1R14LMEJGsTAq/pOgZ+/TKcbjR0zSFGn6hskkRdM0KKiJMQZa69jM0tvPRoStghahiAvqylgsDERilQfFQkqwPMPHUmLvssH+dQ2mykjUcSTdKB2hpCIhJKqqopHr6APCt5iXCnOusTN02D23kJVZEWKTMIzEOY8IirpdhiatYsoFxzQrsDWw2D5uSKH+nTCYpSOFvfXfnXOrDYFiC914XL143L56WIe1+qSf9C/5PfethB8P0a9fU/gXWNeire+NjH+2L1NeCJA+CmwHAAAAAElFTkSuQmCC","aspectRatio":2.0118343195266273,"src":"/static/03e53cdc372f5f71844f5ff02025907f/40a76/home.png","srcSet":"/static/03e53cdc372f5f71844f5ff02025907f/c972b/home.png 340w,\n/static/03e53cdc372f5f71844f5ff02025907f/27625/home.png 680w,\n/static/03e53cdc372f5f71844f5ff02025907f/40a76/home.png 1360w,\n/static/03e53cdc372f5f71844f5ff02025907f/7eb01/home.png 1915w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"qras/index.md","relativeDirectory":"qras","ext":".md","sourceInstanceName":"project"},{"id":"cbf38253-8b87-587e-86ec-f448c23d531f","children":[{"__typename":"MarkdownRemark","id":"5e3abc84-d116-5082-9046-d06a5ffef09a","fields":{"slug":"/nu-forum/"},"frontmatter":{"title":"NU-Forum","date":"2019-12-01T00:00:00.000Z","description":"NUDESK is built to provide students a platform to seek help from seniors. built using React, Python Django, PostgreSQL.","tags":["React","Django","Webpack","REST","API","PostgreSQL","Python","DjangoORM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAACo0lEQVQoz3WRWU9TARCF758wBgktLZWCLJGt7aUULgUERJCWsARoC12AVmW3UJVdBWWHiDsRDRoNICpFowFZjBgNUXky/pnPS3n24cuZk8nMnGSEvBwzbRd9uOvsqFQqNBoNmijNkf6H6OhoYrVaEhMT0BvEEBnGdCqt5xC02hjMkoSUmRlaqI6KIkoeUqnVRCiUKJRHHNYRsioP/WGtUIRUrQgn7Pgx1GoVYloKQqFZR5YhjlxTElJ6EqaUU0hp8Zj1CeQaEshIjUdMjqfAmIQ1KxlJn4JoMGDQpWHM0JFju4h/8CZOt51MMR6hpsyIq0rCU5FJkSmByPAwTipPECsTHRFGjDKc2MhwtIow8uXDpTmpaORUKYknudBg4VJ3M6Nj1/C3O3BVSgiuyixqzhtwWCRGAj5a6qoZ7WlnpLcdn8dBY10tHlstzQ31zE/38erRcKjX2eplbqKH+dleAi0VVJTosRYZEHx1eZSfTWWozcby4ymmB7t4MjvM9toL/v7Y4PdOkC/rK/yS9efnNfY33/Ln20f2t9bZCi5z8G2DuckeaqvMeO1nEJxyzOKc0/jd57k7EqCvs4l7Y30sP33A6sJ91hbvEnw+x9L8DIv3Jnl2Z5Q3CzOsPJqW/QTvl+YZv9GKvTIbmyUDwVqgx1YqMn7VxdLjSaauB3g4PsD2u+d831hj6+1LPq2+CrETXGF3/TW7crKvH96wtxHkYG+T+1M91JRnkW1MRKg4q6f6TDJDl92MDQVobbLR5nVwu9/P6EA3w/1dTMhHQr63lVtdboY6XAy0OxmUdbDDTYfbSm2JSFluEoI9L47GEh2XncVc8ZTQ7yujz2sh4Cqi21lIV30Bfkc+XqsJd7FIW5UJnzUdn+UQMTTbUKzDU5RKg/yYf2c3qB1M07vKAAAAAElFTkSuQmCC","aspectRatio":2,"src":"/static/b87769bf3ed5668c4b75ee4e9ac58c4f/40a76/home.png","srcSet":"/static/b87769bf3ed5668c4b75ee4e9ac58c4f/c972b/home.png 340w,\n/static/b87769bf3ed5668c4b75ee4e9ac58c4f/27625/home.png 680w,\n/static/b87769bf3ed5668c4b75ee4e9ac58c4f/40a76/home.png 1360w,\n/static/b87769bf3ed5668c4b75ee4e9ac58c4f/90f55/home.png 1892w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"nu-forum/index.md","relativeDirectory":"nu-forum","ext":".md","sourceInstanceName":"project"},{"id":"d5c3af50-3459-5fce-a61d-e26f12e56f5f","children":[{"__typename":"MarkdownRemark","id":"0030177e-88aa-5250-9a25-b19c5d8e5892","fields":{"slug":"/llm-dev-mate/"},"frontmatter":{"title":"LLM DevMate","date":"2024-03-10T00:00:00.000Z","description":"A VSCode extension that streamlines pasting code context into LLMs. One-click copy, token-aware, works with OpenAI and other providers.","tags":["AI","LLM","VSCode","OpenAI","Developer Tools","JavaScript"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAADV0lEQVQ4y42USW/bRhiGhThchpRIcZFEiaJIbdRiarEi1ZYc27KdpCgKtA1SFEUPRYEWPfTUQw8994+/fYeUohh1gB4ezJDWPN8yH11ShQWJonMtu1CcAEqtA6XZhxJPoPQXUNIV1Okl1MUN1NUe6quHgtU91OUdtNk1tOkVtHSNkipsqJTprR70yRpGZwyDAm39AG1+DXO2hXbzDdTbb6G8omDzFurllwWbdxQ/QjtI9fElSppRRelMYLG9x+P3P+Mt2f/wC+5++h3XP/6Gd7/+ie/++gf3f/wN7/EDznZfQ92/h3pHZKDtV1DXb6AtbqFPt8zQsKEwS9ttod4ZwApTVMIR7CRDdbCENVzBy3Zw5jcwstfQshvoiz305R5ifgsx3UGf3UC74LvzXZGhQly3jfYwhVkfwPZ6MJ0EwuvD4N6odvJny0vg+B3+PUbFiVGW2BHMaAZt9VAIVcokphvDbWWox3PEow3q7Qmc4RKV7hLVIIXPQ0E0QJK0EXa6qPgM6iYoM5ghhRf3xwwdCh1Gi1Brn8MkVnOCZpQi6YTwGzzkdplhnGMw02KfHIQRhRnbcMdLvSqEErPaRrXBTFrMrDGEE4xhBROU2QLT6VCaHIg/rscMZRL67DXESN6y6UIihRWPpbBn5XwtKHtFRv8VJidhOIWYbCGG66fC/EeH0j7lePg5cmFrDJFuIHrLo9CjMCoi57d3XJ/ybDApDEYQ/QuIeCaFXiF0orz5H0vLy/0fyEylkDLByciFetnnTXtQTZ8zyb1Zg1oJoDohND+GWutBa6b5ARGdQ3SyE/K5zR6ybIPjVZIyjbh+BMcLUW/2UOOoNMIB6tEIbjtFrZvxCxpBbwwgpLg1OtEcUTSEIaeBgXOhJM6+QLp9g+nVI4abPaaXD5gudxjPt1jyXcgh113OXK3Lw70TlBg+33lxPl4U1iB5GWd4wUl/wZs64wicJXO81PnvTPhc2We2wOAkGI6EYimnIN/zQs0DhbBSh2APhe7A4GoIwj4adpO0+MMwX4VVPBt2WCADkKOsyJAyicWPvhr0+YX0YdXlUPOZJUnyfaOfY8syPyN7IjSs4BD9hMysyC7MB1+OlpmX+LxMzmUuFJXGJwQsLcjLK2g9LdP+vEzyL6UjBNw1yo1VAAAAAElFTkSuQmCC","aspectRatio":1,"src":"/static/68919a0d82406a304baa414e88002b51/f3583/llm-dev-mate.png","srcSet":"/static/68919a0d82406a304baa414e88002b51/c972b/llm-dev-mate.png 340w,\n/static/68919a0d82406a304baa414e88002b51/27625/llm-dev-mate.png 680w,\n/static/68919a0d82406a304baa414e88002b51/f3583/llm-dev-mate.png 1200w","sizes":"(max-width: 1200px) 100vw, 1200px"}}}}}],"relativePath":"llm-dev-mate/index.md","relativeDirectory":"llm-dev-mate","ext":".md","sourceInstanceName":"project"},{"id":"fc441823-c717-5f2a-b92e-0e21b2c8ffdd","children":[{"__typename":"MarkdownRemark","id":"845c5c4d-ccfe-5c90-84ab-d103db96d1bb","fields":{"slug":"/gemini-alchemy/"},"frontmatter":{"title":"Gemini Alchemy","date":"2024-02-20T00:00:00.000Z","description":"A Gemini-powered tool that turns abstract ideas and complex concepts into visually appealing mindmaps. FastAPI backend, Streamlit frontend.","tags":["AI","LLM","Gemini","Mindmap","FastAPI","Streamlit","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAAC/klEQVQ4y32UWU/bQBSF8xB7Zpx4zW5nXwiQBBCQthACUYEiSIGSVl3USnSR2v//C07vzGRxQO3D0dix/OXce+51whQOpAxuw1RyYnLpmadOZvlgqYwST2fnymnZ+bkKSCyAvNSAUe2C+yWw6ibM1g5EeQPpfBVWZw9G1HkOegITCmi5SDIbg+EYV7OvOLu6x/TjIw4n1xhd3mH6/hvO7z9jMv2A8+sZuv0hksKnl/PPYBooZFkuUk4WfjaCE5T06RVg+0V42TLcIISfqyBTbCAo1GFamRhwBRNOUTqkHpEM6lWS+mYQPEk9M8iF7J/B5fMAhhT3/wtbAnXDpQIlLhsvT68I7hb1vexdEEHI+3R+BYrBhFNCQsGsFUyJXmbkjEcUUr2vYV4IvjEkaFmFIZw4SMNWwDhMjgaVx+0cWKYC1twFq/XAWntg9QF4tqpcyrJFisD2Cma5IQHXYARq7ICV2mDFFlhjADYYgR2cgx1egPVH4PQHvNSB8MsQlW2IoKIcStgT4Hxo/UjDtl7AHF7CPLqB+eYLzItPYK+uweg33jsGl7DaQAGtuTvLjRZAgqVlEHpolcOtlzCPb2Dc/oA5+wPz4TdMumYndwoook1Vbhw2B8bWSQJduSnbYDtjmKfvYE4fYfXHpFOYbwl49gC+O6GwaJOC6hpsCVytlEyzpENYAO9+weqNFdS8/UnAGfjeBKKxC+sp0Csjsb6fWT2wYYcCONZAWfL0u3In4eyUHPZPaM+3FGABWiixtuyUFs9U1fyx3hHY/msdxGSmRQHxQwqF3GpgtAZMeRUJzKmZU/2TQ9s+oLMCXmyD0+zx3kj3jMpUzlr7EOEmrFwTojOEVerSdyBUsBhwvptpLSFF4Yh8A5ycyABUCHJUCi3tSKabbVAfawTS7lJ+lYBzmEOlevkm/EITbq4Om1zKe6/QhkMQP+zCpeug2KFnNV0ilRuHrQGtxbR74XLqU16ktXyxjLQvX64sexaHpfyaBq59Oez1ZRdu+GzW/gWT+gsWe/hr3++G7gAAAABJRU5ErkJggg==","aspectRatio":1,"src":"/static/f016772d810716e898c93843aba65547/f3583/gemini-alchemy.png","srcSet":"/static/f016772d810716e898c93843aba65547/c972b/gemini-alchemy.png 340w,\n/static/f016772d810716e898c93843aba65547/27625/gemini-alchemy.png 680w,\n/static/f016772d810716e898c93843aba65547/f3583/gemini-alchemy.png 1200w","sizes":"(max-width: 1200px) 100vw, 1200px"}}}}}],"relativePath":"gemini-alchemy/index.md","relativeDirectory":"gemini-alchemy","ext":".md","sourceInstanceName":"project"},{"id":"b161e0d2-09a3-521b-a2ff-5777e287b46a","children":[{"__typename":"MarkdownRemark","id":"25ba9bb7-32ab-54c6-b4bb-2795ab4f69be","fields":{"slug":"/graph-plotting/"},"frontmatter":{"title":"Graph MST Plotting","date":"2019-11-29T00:00:00.000Z","description":"Cache Size Over Miss Rate Study.","tags":["Cache","CA"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAABbUlEQVQoz61S207CQBTcW2lLtwqkqBhJtUS8xJiYmPgh8gN8AJAQ5PL145ytCAiPbjI5t905s2dXWWvhnDtCFKxFHMfI8xxxowFtHdRvbQfhiKIIVVVBcYXAMWmtCUVtDJSufTmQJAljjY4z6LOJYt3JHsJwjxGfPEVR1IQNdhe7RaIVXpw6yInSoqlRxLtcSjhCSCVutVpsTEdTRY8qhonD+8cbht0MA+arQQnvs7C5KnvIUovrC49mRCKiZNOcytUPYbvdrgkVZ/PkPV6LDPm5r68sytmklxg8+1rRXb+Lx+EdypvLnXoS2n3CMEMq3L+eQO/ZVmw58BJXZwkio5FnuxHpk4R8lL+ERw3Y9Jbz84FERGwJ1SGhBGma1i994vsEyAFjcc8Z+4jfhnigH1kXzsmDCU+n06kV/hfC9xqPxxDM53Os12ssl8uA1WoVrOQ2mw3WjBdSo5Xal8SLBWbTKWazGSaTCUajT3wDdQ7t9M2xczgAAAAASUVORK5CYII=","aspectRatio":2.0238095238095237,"src":"/static/7212e3f1bff418a4ea75baadd1a83b0c/40a76/dijkstra.png","srcSet":"/static/7212e3f1bff418a4ea75baadd1a83b0c/c972b/dijkstra.png 340w,\n/static/7212e3f1bff418a4ea75baadd1a83b0c/27625/dijkstra.png 680w,\n/static/7212e3f1bff418a4ea75baadd1a83b0c/40a76/dijkstra.png 1360w,\n/static/7212e3f1bff418a4ea75baadd1a83b0c/eef2e/dijkstra.png 1501w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"graph-plotting/index.md","relativeDirectory":"graph-plotting","ext":".md","sourceInstanceName":"project"},{"id":"f6df416f-f303-5171-96a7-43c6dbd0295b","children":[{"__typename":"MarkdownRemark","id":"06f551fd-9ae0-5e38-bada-5b96e0776597","fields":{"slug":"/cms-workflow-operations/"},"frontmatter":{"title":"CMS Workflow Management DevOps","date":"2025-06-12T00:00:00.000Z","description":"Developing, Operating and extending on WMCore + Unified, so CMS Monte Carlo and reconstruction workloads stay healthy across the WLCG sites.","tags":["CERN","WMCore","FastAPI","React","Kubernetes","OracleDB"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAWAQEBAQAAAAAAAAAAAAAAAAADAAH/2gAMAwEAAhADEAAAAdShQNJihl//xAAbEAABBAMAAAAAAAAAAAAAAAABAgMRIgATMf/aAAgBAQABBQIwM6CgSXa77KfhX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAQADAQAAAAAAAAAAAAAAAAEQESEg/9oACAEBAAY/AuASsyo//8QAGhAAAgMBAQAAAAAAAAAAAAAAAREAITFxEP/aAAgBAQABPyEQQBWZffMPc3yBxJmRHAn/2gAMAwEAAgADAAAAEDMv/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAERITH/2gAIAQMBAT8QyiUf/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEhMf/aAAgBAgEBPxDain//xAAdEAACAgIDAQAAAAAAAAAAAAABEQAhMUFRYaGx/9oACAEBAAE/EDslU4/K6J4hxn5DjbsqEGEUZ8gXm+o+Ct4M/9k=","aspectRatio":1.3654618473895583,"src":"/static/a2691b872fde247b75a40db137592976/ac53a/CMSAwards-04-Hassan.jpg","srcSet":"/static/a2691b872fde247b75a40db137592976/722c4/CMSAwards-04-Hassan.jpg 340w,\n/static/a2691b872fde247b75a40db137592976/1d671/CMSAwards-04-Hassan.jpg 680w,\n/static/a2691b872fde247b75a40db137592976/ac53a/CMSAwards-04-Hassan.jpg 1360w,\n/static/a2691b872fde247b75a40db137592976/6eda9/CMSAwards-04-Hassan.jpg 2040w,\n/static/a2691b872fde247b75a40db137592976/eb7b7/CMSAwards-04-Hassan.jpg 2720w,\n/static/a2691b872fde247b75a40db137592976/5b997/CMSAwards-04-Hassan.jpg 5322w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"cms-workflow-operations/index.md","relativeDirectory":"cms-workflow-operations","ext":".md","sourceInstanceName":"project"},{"id":"34381a67-a596-57f6-b37d-06e9f1b249af","children":[{"__typename":"MarkdownRemark","id":"db247d3a-901b-5b27-8c23-b948afa15fbf","fields":{"slug":"/cloud-canvas-ai/"},"frontmatter":{"title":"CloudCanvasAI","date":"2025-11-15T00:00:00.000Z","description":"AI-powered document creation platform pairing Claude with a live .docx / .pptx / .pdf / .xlsx preview. Chat on the left, documents render live on the right, each user gets their own isolated E2B sandbox.","tags":["AI","LLM","Claude","RAG","FastAPI","React","E2B","Firebase","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAACD0lEQVQoz0VSy27TQBS1BOSdOI6f8auJJdslrdNFpFKE6Aak0j07ENANH1CBRPeVAIFgEUKy50OgEp/AH5RFlsWKYiclOcydyGako3mfOeeeEbxOAM/1YFkWTNPksG2b97quc6hyA4pUgSpVWV9Fu22wMw67Y7JxO7/nOA4Ez/PQ7Xbhui5arRbK5TJEUUS1WkWhUESxcAuiNYASHEPxj9DsHEI3HYThNkzLhqpq0DR62IButCH0ej30+31EUcQ2VVQqFU5Wr9fRaDTYvAx78ALB8TsER+dwD9/A92/jzmAX/Wgb/R0/x95uAIEkZ3ZbLQlbrgNS7fs+giCAYRjMZg2yWITcLEOq3cCWf4D9hy+x/+AEe/efo3fwBDt3nyK69wyCppFkjdeKLOv6Zq4oCgeplhUVGrNk2S4rwU08enyKz99+4e3kJ84+XeD0/Xe8+vADrz9eQMgKT5AkiSslEk4ky2g2m3y9VqtxCIKA8dchqCVJgv9tjTSJN4SkiKxRGJRUGIa5XSKhWmY9EQ6HXzhFmqZYLq9x/XeF+TzB1dWfjWVKiohJDakilURGtaUykMJsjwgnkwkjW2A6nSJdLDjpbDbjilkoOkwWDBHQJfo2lDKlTeNSqZQjtzweY70G4jjODaeLJeLZHMIg6jB7Pv+opCSznwWT1ZNA6/TYaDTCPElxefkbC6aQ2mq14vgHka1i8FciUU4AAAAASUVORK5CYII=","aspectRatio":2.0238095238095237,"src":"/static/0de17268883730afe1d095730e07f7f8/40a76/cloudcanvas.png","srcSet":"/static/0de17268883730afe1d095730e07f7f8/c972b/cloudcanvas.png 340w,\n/static/0de17268883730afe1d095730e07f7f8/27625/cloudcanvas.png 680w,\n/static/0de17268883730afe1d095730e07f7f8/40a76/cloudcanvas.png 1360w,\n/static/0de17268883730afe1d095730e07f7f8/1e49b/cloudcanvas.png 2040w,\n/static/0de17268883730afe1d095730e07f7f8/2d037/cloudcanvas.png 2528w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"cloud-canvas-ai/index.md","relativeDirectory":"cloud-canvas-ai","ext":".md","sourceInstanceName":"project"},{"id":"4120fed6-20a6-5543-bb27-680128d7dd68","children":[{"__typename":"MarkdownRemark","id":"d466fc08-2534-5d01-aecd-ffc1ed655b54","fields":{"slug":"/archi/"},"frontmatter":{"title":"Archi · LLM Copilot for CMS Ops","date":"2024-05-15T00:00:00.000Z","description":"Partnering with MIT to build an LLM-powered RAG copilot for CMS computing operations.","tags":["LLM","RAG","React","FastAPI","CMS","MIT"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABKElEQVQoz21Sy2rDMBDM/39I6TWn9tLk0jSBQqCHUkJbiu3Ypn5bOLh+TrWKV1hWBKtdraTZ0WhXTdNgPsZxVL7ve/i+D8dxtHddF57nYRgG4+w8XjEgHeq6zjhQFAWSJFE+jiKkaapsCcRr8hpQiBJhGFqVbw3eJwLEPggCMI4GLPIccRwb1TiukxR/WX7Ny5fM9+gFkWTPMmhAAqNqWp/Ji7OP42aHt80LLr+RpbMQAmVZqtjSkJOKwQQYf5yw275i/3RA/v1jFOM7ZBbDpchaR+kJNDl98lJNS52tXyaB27Y1NLyyGDGMPeRs7dHIsgx1Xdu/TBpSj936lPvHA+4e9la+qiqlO3UHkTEYUmJeiWyYLm6PX1g/v2vGDJjLzjhLEtTwjPMPMDoKgTtmA9UAAAAASUVORK5CYII=","aspectRatio":1.92090395480226,"src":"/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/40a76/archi.png","srcSet":"/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/c972b/archi.png 340w,\n/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/27625/archi.png 680w,\n/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/40a76/archi.png 1360w,\n/static/39c8dd0ef4dc6fe15f1d83c15a89c1bb/ca459/archi.png 1766w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"archi/index.md","relativeDirectory":"archi","ext":".md","sourceInstanceName":"project"},{"id":"725cbba4-672d-582e-8777-3747458b03d9","children":[{"__typename":"MarkdownRemark","id":"1c0bb05a-e532-5621-b469-7a4d9b9538f7","fields":{"slug":"/argusa-ai-challenge-2025/"},"frontmatter":{"title":"Argusa AI Challenge 2025 · Runner-Up 🥈","date":"2025-11-05T00:00:00.000Z","description":"Secured 2nd place at the Argusa AI Challenge 2025 by building ARGRAG, a RAG system for complex enterprise document corpora with multi-modal analysis, metadata intelligence, and real-time performance.","tags":["AI","LLM","RAG","Multimodal AI","FastAPI","Python","Hackathon","EPFL","Argusa"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUCBv/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAHdCGLoEgP/xAAaEAEBAAIDAAAAAAAAAAAAAAACAQMSABEy/9oACAEBAAEFAgkbuu9pOK0s5sjOLx//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAbEAACAwADAAAAAAAAAAAAAAABEQACIRAiMf/aAAgBAQAGPwLKt+TtVAxExg7CLWY4/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARQSFRcf/aAAgBAQABPyHcBX1EhYal8ZXOgNilQNit6I+Z/9oADAMBAAIAAwAAABDwD//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EKf/xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARITFB8P/aAAgBAQABPxAFszEv1x8ohppUm3N+2Fngi1awkiYHnI/JJpDxzQuIqs//2Q==","aspectRatio":1.780104712041885,"src":"/static/0e012013c1c2686cf486cdc39f3accec/ac53a/argusa-ai-hackathon-runner-up-shot.jpg","srcSet":"/static/0e012013c1c2686cf486cdc39f3accec/722c4/argusa-ai-hackathon-runner-up-shot.jpg 340w,\n/static/0e012013c1c2686cf486cdc39f3accec/1d671/argusa-ai-hackathon-runner-up-shot.jpg 680w,\n/static/0e012013c1c2686cf486cdc39f3accec/ac53a/argusa-ai-hackathon-runner-up-shot.jpg 1360w,\n/static/0e012013c1c2686cf486cdc39f3accec/0e329/argusa-ai-hackathon-runner-up-shot.jpg 1600w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"argusa-ai-challenge-2025/index.md","relativeDirectory":"argusa-ai-challenge-2025","ext":".md","sourceInstanceName":"project"},{"id":"8ee89610-570c-59ec-ac69-ec899d13ddf1","children":[{"__typename":"MarkdownRemark","id":"44cf08fb-dc3e-509e-8afa-ef64cb712ac8","fields":{"slug":"/cache-size-over-miss-rate/"},"frontmatter":{"title":"CSoMR Study","date":"2019-11-29T00:00:00.000Z","description":"Cache Size Over Miss Rate Study.","tags":["Cache","CA"],"thumbnail":null}}],"relativePath":"cache-size-over-miss-rate/index.md","relativeDirectory":"cache-size-over-miss-rate","ext":".md","sourceInstanceName":"project"},{"id":"8b947ad2-bedc-55c5-b078-0945f163d57d","children":[{"__typename":"MarkdownRemark","id":"d6cda43a-b7d4-5a2d-8cdc-4e3835d99ebb","fields":{"slug":"/TabDealit/"},"frontmatter":{"title":"TabDealit","date":"2020-03-30T00:00:00.000Z","description":"FAST-Barter (AKA TabDealit). A online Platform to build Communities by exchanging items the old barter way.","tags":["Angular","Firebase","RxJs","REST","API","Google","DSC","Solution Challenge 2020"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABJ0AAASdAHeZh94AAACwklEQVQoz22Ra0iTARSGP0jKoijpR1BBEl0pQjKosKxlWjpN3RSnpsulc2vq5mXW0uk2nSWmXZQwi0TJWsW6aoWCrTITpbt2tytF/Spvi5R8+hT814GHw4H3vAfeI3iFJzI9JBbPoGimBSvwCJDhsSWSSRNIxoj4L2O6yaJ+hjSWKeKujyIRIarWSUTNOaRV9QRVnEJy8Dj+9kr8rIdZay5jjekAPjk2VhoKWKYzsUhtxFtlYH6CjlmyXUwNjWemVIH35m3M3RiEoL3VTsqNNnbWXiDKbEGebyEkM4fAND2BOj0BmnQkqTr8kzVsStaKaPBXaZCo09hbWUP5mYtIjQXMCovDKzQOQdfcgVo0TDp/g7iq08SKyMurkZVWEmY/wg57BVJrGXJxDi48yNb9RfgZctggElZgIaIwn9VaA7NjUvGSqxAMrkektXahdjShKqokMs1MtEEUZhWjrT5L3yi4gdPnziNTJJBozuPkRRm2Uj/WBfiSZwtAbZczJz6DOQo1grH9OZltz0g5e5ndeTYkvmtRJexik9JAdnUD/QP9HK2oQLkzkeAtgSgy1NQ7/MjN8sVzyjRWLV2IXBfNgpQc5om5Cqaul+R2vkXjqCNaF0hMnBJjvpX4jGSSSkqx2IpQJijJytiDq/kmjY/uc6mplMar18kyZLN183rk6dtZpMsTn5WJUPi0F9Pj9+xruiZePsa2HTGkavU4rjRwyOnE6bxM+YFiOttvM1bOB62UVYXzsLOJO657nDyhJL1EypJ0K4u1uQjFL79gevKe6mdv+fXzFy5XGy+6e/gzNETr614Gh0dwDw6MmyHm2dLzAldHPT3dt/j67QNvXl+jrtnBEr2FFXozgv3VV/K7P9Pw8QcT9Wd4eLy3ff5On/s3v91u+vr6GR0Z4e67TwyOiN5/YWBwaFzX0t3L8mwrPsYi/gEbCfsPZ6IJQAAAAABJRU5ErkJggg==","aspectRatio":2.035928143712575,"src":"/static/91be5a1c74b4d8217d953eb8641e94c4/40a76/pic1.png","srcSet":"/static/91be5a1c74b4d8217d953eb8641e94c4/c972b/pic1.png 340w,\n/static/91be5a1c74b4d8217d953eb8641e94c4/27625/pic1.png 680w,\n/static/91be5a1c74b4d8217d953eb8641e94c4/40a76/pic1.png 1360w,\n/static/91be5a1c74b4d8217d953eb8641e94c4/60d1f/pic1.png 1896w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"TabDealit/index.md","relativeDirectory":"TabDealit","ext":".md","sourceInstanceName":"project"},{"id":"c7792848-9935-590b-bfa0-b27f9ace1dab","children":[{"__typename":"MarkdownRemark","id":"7ee4c435-ba8b-5ac4-9bb0-cb22b604313c","fields":{"slug":"/IRA2/"},"frontmatter":{"title":"IR Vector Space Model","date":"2020-04-11T00:00:00.000Z","description":"Vector Space Model for Information Retrieval- Assignment 2 - CS317 - FAST NUCES (Karachi).","tags":["React","Django","Electron","REST","API","IR","Python","Vector Space Model","Jupyter","notebook","netlify"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAABJ0AAASdAHeZh94AAAEUUlEQVQ4y1WTeUxUVxSHXxORkXmzKEqpSdNal1ZLI7VUFlGpu1JwGUBQQxC3FmvLog4M6wiIgGDE4pJqIdqa+gcuKJrWXZBa05jWrTZpomFmmGGGGXEUXKB8vTOtVV/yy7v33Pu+87v3nCepE8rR6LagWbAZdWwJqugS1LOL0cwoQj2tENXUQtST8lGH5aL6WOgjA6pgPfIHQmM3onp3PfKoLOQRmSjfzEDSJFWgji/Dd1EFg2LEOLoYxbwSfGdvZlBUCfLUIgZOMTIwzIhyYg6KEAM+4wvwC8pmoJDPmByUIzegfCcD+e1MJNXSCgKS9xCZZGBS2mr8kqoJit1EyKdZjF76FcMWVhA8U0/wgjTemL+XMVGlRMxJIWBuPmND9QRFrkQbuZEhIaUoR6QjycmVBC7fiy5xPRPTV6FeU0NYTCFxC1cyfe1SAhMqiZm9jujkJIbH1xH+SRExC+IZritgVkQm82IT8NdlMCS8DOUo4VCzvBp18lb8llWhXFyFJn4Lsq6coQlbeT1OJFtUTsD8coZFl+M/s4jAOZsJmF4ijp+HX0guiuA8lOOzUb6/0XunknbVNjxQTbKALavEc6d+ujLGrdlFZOY+QtJ2E7xqJx+m1jJCV0lISi3vxVXhG2pAHZ7nLZQ8wYAcLKBBeuHws+08hw5OqWaAKNDaXU00td6gsfU2J678ScOlWzRcvClid2hsvs35X/8iTv8dr03Qo4nIfwUqadNqeA4dnFqNYkkFM43fo68/zbo9pyg+eJEDP11jv1DevjOk7zhJzu4fCU3diU94LurJBchhL5xK2i93oF1bg/YlqE/iFqSFpUiz8gnL2sexlhscabnNW0uqkcKEiwiDaKV8NNOMqKaIXo0ULv+DStqMWrzQtBfQISuqGZq6DXlJJZM2fENF/TFK9x5l3IoaVDGl+MeWoZ0rfoAZRtH8Rf82f2SBFyqpM2tRpn+N/MUO5M+3I68RWilgKVUMEE5HijZKLK4jwVhHYFIlPvM2oZgrNMuIYnoRiqgCFJPz8Y0Q1RaSEr89weHW36g7e5X6s79Qf0bo9BUOXrhG49U7NPz8Bwcu3GD/ud9paL7J0ZZbHGkWunSTI6JQh89f5/C56xwXhYtavQep8GQrPOzCdO8uTpuVLoed9rZ7OKwW3C4nXZ12nj5y86zbjbPDisvRgcPWjvu+E6fdxgNXJ/T34XmWFfyAlH28mb7ubtosVhydLu53PcDW4RCyY2m3YTJb6LA7sDuctJnMmEwWzOZ2zJZ2sW7FauvA/bCb3mfPWJx3ECmnqYXeh25MYkNnpxOX6z42sclqtXllEXGHoxOn0yVAlv/jVqvVu88ukvX0PBYm+0gsFA5zTl72AttEZs+iB/r8o3bhwGw2e+MeqEk49EA977Y2E3fv3vPOu7t76P9bAI2HkAynLovT9+N+1MPjx0+88mR8efzy3KMnT56+Mveov69XdMMh/gExfWfezjhUOgAAAABJRU5ErkJggg==","aspectRatio":1.152542372881356,"src":"/static/9dfc43e2f27e5b6a0b0978f89aaf8742/3225f/pic2.png","srcSet":"/static/9dfc43e2f27e5b6a0b0978f89aaf8742/c972b/pic2.png 340w,\n/static/9dfc43e2f27e5b6a0b0978f89aaf8742/27625/pic2.png 680w,\n/static/9dfc43e2f27e5b6a0b0978f89aaf8742/3225f/pic2.png 920w","sizes":"(max-width: 920px) 100vw, 920px"}}}}}],"relativePath":"IRA2/index.md","relativeDirectory":"IRA2","ext":".md","sourceInstanceName":"project"},{"id":"3fbb5f31-e04f-5947-bdd9-af60aa216fbb","children":[{"__typename":"MarkdownRemark","id":"81bbabea-1a8a-543f-8415-9294082b19aa","fields":{"slug":"/AlgorithmsVisualized/"},"frontmatter":{"title":"AlgorithmsVisualized","date":"2019-12-29T00:00:00.000Z","description":"A Jupyter Notebook with Different Graph Based Traversal and Search Algorithms Visualized.","tags":["Jupyter","Python","DFS","Astar","BFS","Best-First"],"thumbnail":null}}],"relativePath":"AlgorithmsVisualized/index.md","relativeDirectory":"AlgorithmsVisualized","ext":".md","sourceInstanceName":"project"},{"id":"5d4c1b30-51e5-5406-aa25-bf78e46733e4","children":[{"__typename":"MarkdownRemark","id":"9306dc95-9b94-530a-85b4-ee42968d761c","fields":{"slug":"/IRA1/"},"frontmatter":{"title":"IR Inverted Index","date":"2020-03-10T00:00:00.000Z","description":"Inverted Index Based Boolean Information Retrieval Model - Assignment 1 - CS317 - FAST NUCES (Karachi).","tags":["React","Django","Electron","REST","API","IR","Python","Boolean Model","Posting Lists","Inverted Index","Jupyter","notebook","netlify"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABJ0AAASdAHeZh94AAAEOUlEQVQ4y0WTC1BUVRzGrzqy6L6uAolmM5qaogUqklCKEr5ISQfMIBQncVBREVfkIQgLLuzyEnfxQQqGKGBJjJWajuYDy9IynTHTnGo0S56yu7AqpvnruGt5Z775/ufcO7/7nf85R1pUVcHi/dUsra8lrr6O6NpqIvfuJrpuj0u1/6nquWqqeF/4/KpK5u7axbyKXURWVhJTswdp5LLt+MRtY2iMmWh9HaXVJ8i0HML3PTOj5m3GJ7wYn7AifGYUMirUxKgpRnwm5/Oyv54PVlRRUXGc8h1HKTR9hp+vHqlPlIk+840o3jHQL8LI4AUFeM/Lxz0kC7dJmbgFZeAWkI7buFTcfFPoPTqZ3iPX0XPIGl4KyGTiLBMTpuXh+2YOCo+VSNrFJWhjipCjClELoGJOHu5heajDNqGeLhSiRxWcjSpoI6qADSjHZ6DyS0P5ahqKYTp6vphIT+9EenmtQjkwUQCXbEYbW4JGQLVRRQxcYGTAu3rk8Hy8ZgkPy8EjVI9HyEb6BRvwCkpBOzGD/uPWoxFgzeg01CPWoR66DuXgJCQ5vhRZQDWxRfRbaGHWwo34JSYxPKqYiMh4xizT8cbsNKZEr+SVuRWER8QyLDyXsLeWMGS+DpV/DsoRwocL4BCdACaYkeO34EpajCySKiKN9BDJes3MQha99ZidhzwjB01INpJ/KtJrySjGpqARvVWKlKoxqahGrndCJXm1Be0KF/Rp0j4C6Je0k8UlDSwsaCBV7GJu9Wmyd59EZznMouxPiNv0Ka/HlOE+Lh21/wZXT59BJXntVuTVZcgJFvovN+O+qIgwQx35+78iZ98JDHWNpFceJ7n8KAYBLq45Q/G+08xesxuF2CRtYKYTqh7rSirJ67ehSdqKepUFzfItqJeW4iEkReQivZ2FZ3QBwavMBMaX4C1OQY/gDKTxOnoFiuVOzqJvYAbKCRvoK9IqfdOQ+qfvwDt9J94pH+KtE/WabbyQUMagFWV4xZkZm1ROouUAyVvrCUjYjjzXyKCIQgbMycdzpgHPabl4TtXjOSkbzQTxsyDzx5y5coNTl3/m5CWhi1c5f/0ml3+/w6Vf/+L7X25z9qdbNF65yYVrf3Dpxp9cvH6bi6L+8dptp364eotrvzURuqQcKXRnAw+6HHRZO4SsdNmsOOw2Hji6RG2j2+Hgnhjf77Q755++t4tvHZ02bB3tdNqtWDvuwpOHRKwVd3mqALbdtdLS2k5rewfNwpvbhFrbaG5pc3rTM7/T1OKsm5pbnW7vdNDpuI9N+OPHjwhP+ghpesVB7tvtWFtasLe3YWtt4dE9Bzzs5kn3g+cS43+e+t/d/0vEwvW4PCJlL9Lo0hpyjp0j60gjWYcbyf6ikfxj32E6dgHTl+cxHRH1oW8xfn4O08FzGBu+wVj/NcYDZ8XROkNe7WkMe09RWNuIX6yFfwHMMRzOZj+n8wAAAABJRU5ErkJggg==","aspectRatio":1.2408759124087592,"src":"/static/055be7250581a70a92da611ff180c2e7/dc180/pic2.png","srcSet":"/static/055be7250581a70a92da611ff180c2e7/c972b/pic2.png 340w,\n/static/055be7250581a70a92da611ff180c2e7/27625/pic2.png 680w,\n/static/055be7250581a70a92da611ff180c2e7/dc180/pic2.png 1260w","sizes":"(max-width: 1260px) 100vw, 1260px"}}}}}],"relativePath":"IRA1/index.md","relativeDirectory":"IRA1","ext":".md","sourceInstanceName":"project"},{"id":"3b145dac-c8d7-5f23-87c9-a5df5c5dd3d7","children":[{"__typename":"MarkdownRemark","id":"b67a1e42-0433-534b-b08c-7a4e06875996","fields":{"slug":"/2026-09-29-consistent-hashing-sharding-without-reshuffle/"},"frontmatter":{"title":"Consistent Hashing: Sharding Without the Reshuffle","date":"2026-09-29T00:00:00.000Z","description":"Add a cache node with plain modulo hashing and almost every key moves. Consistent hashing moves only one arc. How the hash ring and virtual nodes work.","tags":["Distributed Systems","Caching","Computer Science","DevOps","Scaling"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACRElEQVQozz2RSWsUQRSAGySTpZfpfd+me3qp3tfpmcxMDwOJyYQkM1k0RgzizYt4DAS8iiB4UvCUi4qXHLx49uy/sqIgfHw8XtXjvVeFAFcNXDX0Na8vDWvQjtPJKJ5uJ7NJ1o6zeVvATLudjpsQejbOqtz1HTnwVAjSIYwOoXdwfaPbU/u1HU4sMIbuR1M3bkE2N/2RE7c9sG2HU4hs1RukBe9DEIzWCNZCWZvgHU4LaRkQgovzziZtYYyFUjrB2RhrU6LDyfcIqkeJLsH1YRWCkhopAkXPJC0F5W45PgTpXLUqWUtYJcZZm1ZiUopMryqaWT6AtIKRUkpMSQBZIxRHT25mizezxcvhzvV0/9Pe8u384Lpd7EWjB11D0HOpVwtmxRk1pQ0odUBrA8YYkGKArOGyZyafD06/HZ3/vrz6efrk16Ond8vHd6uLZ9UMITRWLUWrkaym59dZnsdpDh2lJasAZIuQGSl4t3v8/ej8x8nFl8Ozr0dnV83O+93lRTFFUK1IAxCXtDYsq/TVpfnixIJ+vrJV00U2CQnu/Hqy//Hh8e3B6sPO4e1iddPuw7GX6RjB9CgM+6DgjEowS1qtKbVm9Jq/Hxt2xkVC8DEpCvtV7DWVPyr8YeU1qpZ0xQCndZSPGSWM4jDPw7II6ipw/ICUY1LwkU1cgJ9Bij4tAV5PRCOVjIxTIlIO4HvijEnLAYTXIsGIRSOWzIRRQFf0cM5GNjD+H+so19liIWtb7DrGY6SCkjL030D5fwqB8d8S7g9uB2ycZjzc+QAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2c0ce2e88edfe52b5e0b160cc8fdb467/40a76/hero.png","srcSet":"/static/2c0ce2e88edfe52b5e0b160cc8fdb467/c972b/hero.png 340w,\n/static/2c0ce2e88edfe52b5e0b160cc8fdb467/27625/hero.png 680w,\n/static/2c0ce2e88edfe52b5e0b160cc8fdb467/40a76/hero.png 1360w,\n/static/2c0ce2e88edfe52b5e0b160cc8fdb467/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-29-consistent-hashing-sharding-without-reshuffle/index.md","relativeDirectory":"2026-09-29-consistent-hashing-sharding-without-reshuffle","ext":".md","sourceInstanceName":"blog"},{"id":"177538b7-feda-5290-aecc-fd755b6fb74e","children":[{"__typename":"MarkdownRemark","id":"f6b2e53e-5260-549b-ac4b-949d5b5ec579","fields":{"slug":"/2026-09-25-gpu-memory-serve-llm/"},"frontmatter":{"title":"How Much GPU Memory to Serve an LLM","date":"2026-09-25T00:00:00.000Z","description":"Pick a GPU for an LLM and it 'fits' on paper, then OOMs under load. A quick way to estimate the VRAM a model needs: weights, KV cache, and overhead.","tags":["AI","LLM","GPU","Inference","DevOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3klEQVQoz22PSW/bMBSEdWusjaJIidpILbYsa7VsWbLlJHbaBG5SxGh77qH//1/0yQ16KvBhMCDfcB4lzEfACPY0Ohb7n3n/Peuu6eYdTLJ+A5M0r8vt+3J7na+/FcMPuMX8cGOUZOQryAelTlq293V3Ssshb8ZifcwbYMyqQ7V5AAXa/qloHywvU40AIpKCBYCdzOaV6WRgqF8YLFPMRCU3zHiGOCBjManBNRqr5pSSFIPLiPuLYbl+Spvzoj6DEdkBexUJGsrXyEphRjUj5ZacoQBQcAjA2rAAp6JlcQejhltq9gq5JRg36cLVqFtzBUcGH/zsmZdfRfXKiwuJRo2V058BFu3C/OTEgx12pl9Drek3TjLE5ROyU5Uukd+x+TGsnu3k6GcnzHf6FNY9gMW9yGHbk1idoJ8EtcVbdz6K/DOENbs0gp3uwnOHZftiRTvda6fwTHdl5JnBxkqOJNxjMQCwFeY9PI+DnUZi2RBG0BMBBef6cPXSe+RvNVZJM82RNUbiR2N+cYq3+vHX5stvUAAvXkh60e1shnydVcitdadS6Ao5FaCSBYSZrDPsNVBi8o6GgxUNNOyp6HHQASqJ71QbxiZV2YfRJiOBm1CsO4UCn2Tyj78nHwP/4w+mY1Bmjk8PsAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/f0e6f8f9a0350d817628ba6769b60933/40a76/hero.png","srcSet":"/static/f0e6f8f9a0350d817628ba6769b60933/c972b/hero.png 340w,\n/static/f0e6f8f9a0350d817628ba6769b60933/27625/hero.png 680w,\n/static/f0e6f8f9a0350d817628ba6769b60933/40a76/hero.png 1360w,\n/static/f0e6f8f9a0350d817628ba6769b60933/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-25-gpu-memory-serve-llm/index.md","relativeDirectory":"2026-09-25-gpu-memory-serve-llm","ext":".md","sourceInstanceName":"blog"},{"id":"96250fa5-b537-545b-9760-cd348e2b4f8e","children":[{"__typename":"MarkdownRemark","id":"5bf2fb34-7429-5537-b5a9-516a5dfe0ae6","fields":{"slug":"/2026-09-26-hyperloglog-count-distinct-at-scale/"},"frontmatter":{"title":"HyperLogLog: Count Distinct at Scale in 12KB","date":"2026-09-26T00:00:00.000Z","description":"Counting unique items exactly costs memory that grows with your data. HyperLogLog estimates the cardinality of billions in about 12KB. Here's how it works.","tags":["Algorithms","OpenSearch","Observability","Redis","Data Structures"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB7ElEQVQoz12RyZKbMBCGOWbACCSBEBZm38xuYxvHYI+XmZrjpHLP+79GGjunVP3V1VL3V7+6JeG8BqG0cPpjfn1E4yV/fyTTNTpdvMMpe7/DMThO2flW3D79YURJAf36k5Jk1ZFVgbDvRduyOVfdpWwveXlK8yHODutqLJpzlO7zaoRqEO90GsoLAZSCVtKCBsiMNStRjUghoUJDhQSIxZhniCWzzBhKMgnedA+qGoNjCJRCXAmxlIoG26Vm5U+tEcssr3WzwXQ7w2ksbwMNzGncaC/8rWakmplrLFN0B+BE52sqqhcMOQh41YT7wnRbnuyIqKxm8O8f7vVuTRMtd8hIZA1gM8F2QZbVi4QIJCTM39jpniVbErYaz42fJ/b7y/r1Jf58s+mMcCTrYoZ1u6CifjnDE0Q6pP3N7yYr7TW3xH6t2Wte7OPr52o38e6IoxYZsYyWkmrGeFnSZU3tigdbHvdG2FG/NsOO57OzlfV4VbFVG9XTMtjq88A5WL4hPjuDIS8Oznhjh5PRH58a+HH07g/3evMeH0a2tb2NE+/ndViZBtGM31TrNXPJvE4Xpb4sDbclqwbegkVNIRE1cWoi6n+LhNFgL7yYnVUmKdhVaaASXyXBf9JZQniGwQq+mvpzGw1fcYHdHwv2F7XYUxz50t48AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/d8c408d0f784bb15fc0ce20a2f9339e1/40a76/hero.png","srcSet":"/static/d8c408d0f784bb15fc0ce20a2f9339e1/c972b/hero.png 340w,\n/static/d8c408d0f784bb15fc0ce20a2f9339e1/27625/hero.png 680w,\n/static/d8c408d0f784bb15fc0ce20a2f9339e1/40a76/hero.png 1360w,\n/static/d8c408d0f784bb15fc0ce20a2f9339e1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-26-hyperloglog-count-distinct-at-scale/index.md","relativeDirectory":"2026-09-26-hyperloglog-count-distinct-at-scale","ext":".md","sourceInstanceName":"blog"},{"id":"1ee6b486-959b-5b42-a759-15b473b2630b","children":[{"__typename":"MarkdownRemark","id":"272ae290-a007-5a3e-890d-0647201d787d","fields":{"slug":"/2026-09-27-rope-position-embeddings-context-length/"},"frontmatter":{"title":"RoPE: How LLMs Encode Position and Extend Context","date":"2026-09-27T00:00:00.000Z","description":"How rotary position embeddings encode token order by rotating query and key vectors, and how position interpolation and YaRN stretch a model's context window.","tags":["LLM","Transformers","AI","GPU","Inference"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4UlEQVQozz2P226bQBCGURUblmVZdmEBm6PBgKE+KnYt22DnohdVlKSOFaXqA/SqUtWrPH8Ho1r6NJr55yyxYm9VTfVwyevv4/1z0ZzL02W8e8oOz6C0/v4pr18mp9fJ8ZxedbNsWHHgk4Ok6kOse58Xh9mqAQtMl01Rbav5fr46zpZNVn6p5qDXk+luuqizcgP1XZeEeYR5qFBfZZHKY2yEKsDCNmQhMgKwmMdt2PoRKLhVgEjC1MdGC1IYIa5sBH3dw0aAYBzUXUEKx9iGBlio/ReBdnM72wjE6Wf6+KseL3OvkKln2okOKeoT6jn1W/T+wZMNYXBaAGKHhM1YE6l/+SsOF93JLDPapYv7eMbEyLBihMz49Y/38pumazIsCY91u1Cp1yEpfSp2Z+f4LksyIm6PDCTVadKFa43uetSaPgQ/PvqSrFkj4uZIE7qVET5CZAAvSIrC7fpNc4s7ZHLDi0TkMr/y8jKserIh1t/48mv/E8Zurg0KGZlwrQbNuov0gQQzFCyw4aWT+2q6zfJVnM7hBIW4qn5N8YBnW5au2XjD4iWxU6Q5UABAM3gOpkNuJ8xJDHhVxJ3YoTGf2gkVI2rFhp0QM0Sa3aUkRbM7+qp14yYCMhayarXgzopb6h9fyUchAON0IQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/a41f34b118fd6bd6384dbfccfd2c22a3/40a76/hero.png","srcSet":"/static/a41f34b118fd6bd6384dbfccfd2c22a3/c972b/hero.png 340w,\n/static/a41f34b118fd6bd6384dbfccfd2c22a3/27625/hero.png 680w,\n/static/a41f34b118fd6bd6384dbfccfd2c22a3/40a76/hero.png 1360w,\n/static/a41f34b118fd6bd6384dbfccfd2c22a3/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-27-rope-position-embeddings-context-length/index.md","relativeDirectory":"2026-09-27-rope-position-embeddings-context-length","ext":".md","sourceInstanceName":"blog"},{"id":"d064ac8d-fb75-577f-a683-fa42a7cef108","children":[{"__typename":"MarkdownRemark","id":"ec62946e-7541-5b31-9045-106a25e1916d","fields":{"slug":"/2026-09-28-tensor-vs-pipeline-parallelism-llm/"},"frontmatter":{"title":"Splitting an LLM Across GPUs: Tensor vs Pipeline","date":"2026-09-28T00:00:00.000Z","description":"A model too big for one GPU has to be split. How tensor and pipeline parallelism divide an LLM, what each costs, and when to reach for which.","tags":["LLM","GPU","Inference","HPC","DevOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB8UlEQVQozy1Ra5OaMBTlU8szCbo8DIEECBhBrYovkHVqt7t1q9ap0///WxrUmTOZe2/OOZOcqzDaPhCzdjG/bNa3xfzc1P/ms0u1+CPbqrrKYr36O5udl9VVcqKweUgUFeIHoJsko5WY7fh4U1b7bLLNxpti/pqNt3IymrWyHX5r8kkNnPghUUw7Mnu0g011GKkg1GCoo8iQLYruxbOW8w4gfPJ7VDFQCNwMeDnhiyhfJkVNxQr6ueWk0tdARJoCN0cDIW+ZWCdlHeaV5XJJUHRIoJtjsqasTdPvcbqPk31Im4BsdEQ0gOWJ/BEJaxa3PD3cCa8R3fl4oRiQWG4m+FGknyI58vgnZ29ldi74yXqhfT+3PY680SS/ZvH7KP3krCNMxS1lB8UAgeXwNHljdI+DDSabAV4m8SFL36HDMJu6pICeGPJjENYB2QZk7eMqTz8o3SnyYcDJpM14eJ6Xt3J4mopLkf3m7IeGMHJiHQXIEyL9NRbneXEr89O4I5wiUiua5cs/Q18QLsNoqWhItoYDYTpcA4MvutO5u0NJiPJtUrRMNAFfAW/YBaZZ3j1SuRUiYdih1WfgJQb92ESBAbGJyLPtUXmro1Bm/FiEopruV8ORUE1HNRzNdE07MBE2kJQFHWzyLBDWLFe9MzuJ6fwHDq9T9VH8IXwAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/91cf0860c00031917c8d46f337d29dee/40a76/hero.png","srcSet":"/static/91cf0860c00031917c8d46f337d29dee/c972b/hero.png 340w,\n/static/91cf0860c00031917c8d46f337d29dee/27625/hero.png 680w,\n/static/91cf0860c00031917c8d46f337d29dee/40a76/hero.png 1360w,\n/static/91cf0860c00031917c8d46f337d29dee/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-28-tensor-vs-pipeline-parallelism-llm/index.md","relativeDirectory":"2026-09-28-tensor-vs-pipeline-parallelism-llm","ext":".md","sourceInstanceName":"blog"},{"id":"57dbf86e-c3de-5b58-bd2c-1a4ad28b387f","children":[{"__typename":"MarkdownRemark","id":"92b87049-09a6-5cb1-968b-cbd492cad17a","fields":{"slug":"/2026-09-22-llm-model-routing-cut-cost/"},"frontmatter":{"title":"LLM Model Routing: Send Easy Prompts to Small Models","date":"2026-09-22T00:00:00.000Z","description":"Most prompts hitting an LLM app are simple. Route those to a small model and escalate only the hard ones to a large model to cut cost and keep quality.","tags":["LLM","AI","FastAPI","RAG","Cost"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3ElEQVQoz2WQ2Y7TQBBF/QBxvLb3dLvb7SW24zh2FmcxCQmZzIRBSCMhFqFB4oH//woq0wIekI5Kt8r3ltolzeIx0CR5xZLDfHXtD8fl+qE/nFab83onKrSXbX/qtiD62XwapSIlDRCXEYeqOBmf9PX6Pm+P0+6St6difkqmexDAZHkuF2eY03wDTpGSdJsDqhXpDh+aVDZC0IbDTTdB7q2aXoa8RLO5ZkWqxQwnhqFISTACTId7pEyKLspay09pVDZ117R9mtWr7pSNZ2BQUSTMmsWEkFTEAA9nXljm9RuXFLodKYgGrMJxQ+MpiSrCa9kEGwWnYlLFDEVKehndetg0RNT3eMGSz8vJl0XxbTX51BZPi/ornImnCopg78uPJCIlqbDGDHWLwWuRn7rB2HZjjBNGUkpuNefjinGOI9W+3QLzxiWlYhBISYpJBEMDA7KOXScMbOI7IQ2ijGUjj9oIQ6sYGPnjMF2ReG7jCo4nwegPsIwMdBKPWJflm8n0ut099rtDM1/n5SLNZC3waFutH5f7J1bubwdTjNFfVGM00IIwoN8vx58f7p+vd8/X84/3d78+Xg9t80rxHFKl9du8fcfLXkOhNNSD/xmo/mvV+4cC1RefZM0XgP4NWMtLbYMsY20AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/803406d105e34dff0c63b26210f7f8ab/40a76/hero.png","srcSet":"/static/803406d105e34dff0c63b26210f7f8ab/c972b/hero.png 340w,\n/static/803406d105e34dff0c63b26210f7f8ab/27625/hero.png 680w,\n/static/803406d105e34dff0c63b26210f7f8ab/40a76/hero.png 1360w,\n/static/803406d105e34dff0c63b26210f7f8ab/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-22-llm-model-routing-cut-cost/index.md","relativeDirectory":"2026-09-22-llm-model-routing-cut-cost","ext":".md","sourceInstanceName":"blog"},{"id":"56ce1ff8-d1d4-5c6b-8de6-be79a4e1bb9f","children":[{"__typename":"MarkdownRemark","id":"3da62bf6-c69a-5c02-a50f-641022efb820","fields":{"slug":"/2026-09-23-fastapi-correlation-id-logging/"},"frontmatter":{"title":"Correlation IDs in FastAPI Logs","date":"2026-09-23T00:00:00.000Z","description":"One async request scatters a dozen log lines through concurrent traffic. Thread a correlation ID through FastAPI with contextvars and trace it in OpenSearch.","tags":["FastAPI","Observability","OpenSearch","Python","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACJklEQVQozyWPSU/bUBSFvSKTE89+o5+fx3hIXjzFMSFAIAwFytSq3SGx6C/othK/vUZIR2dx7v2kcyREdoh+CuBtkt8X1asonkX5kovHXqJ4WayessV3UbyK8jUXT3F6139+IdJYxSMFDWdwolEvqeLlJhFdWmyj5SbM1qI5T4uTPvSzKszX8XLtzlcDBQym1lAB0kRjKpgrIJxZngKiWS87nBi+bAWy4Y1VNlKoZi0w3WHaQdxhcszcHYCtYZXSRHWg18arl2X3Hizu3XjPoj1gG4s2Kkj7XmOFGPYyDG7z/CEIrqLoRognn19Z1qaHmUmaYvV2d/hIkh+E793g2vEOmJ2ZqFaMeKRAWfMNvNJwToIGeaVs9gXnCoz7zVTHgiftotmSsLbcGvC1xSoVpzoUBB1klU81H7DWdAQOGhzUyK8grzSUSxOFWrQVq7eri3/z9KfjXfLwlvILSE8sXCNwjtG5YQmbNbZb8OTYy7Zu0kG/1nAm9ZNMXCWL38e7v378iNxT4u0xO7VpZ6KSwIOqJ7IWAFIBmjO/csMau8KEiQnn0niGTFKm2fNp9yeIbiHbEn5GeA+3Bix1Iz+STV2jnZdueFRRv3XDHDopoBlgn7DtbKr6/eHbR7b4xfxrP7qn/BI7ZzpYDmVzNIXjKdRVTFHIacadzCFzAkNNxdJQtqeGp6PUdoQG54oVKnbU+8wMJprTX790NLGPZHswBQMZfHmf/Ac+i1te6gdHzAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/fd1d62f8a9974fed0f894db38d842403/40a76/hero.png","srcSet":"/static/fd1d62f8a9974fed0f894db38d842403/c972b/hero.png 340w,\n/static/fd1d62f8a9974fed0f894db38d842403/27625/hero.png 680w,\n/static/fd1d62f8a9974fed0f894db38d842403/40a76/hero.png 1360w,\n/static/fd1d62f8a9974fed0f894db38d842403/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-23-fastapi-correlation-id-logging/index.md","relativeDirectory":"2026-09-23-fastapi-correlation-id-logging","ext":".md","sourceInstanceName":"blog"},{"id":"7943181f-84fc-55dc-aa7d-2365f9022af4","children":[{"__typename":"MarkdownRemark","id":"96c186ac-4c99-5efa-bec5-957f637c1e2c","fields":{"slug":"/2026-09-24-roaring-bitmaps-fast-filters/"},"frontmatter":{"title":"How Roaring Bitmaps Make Filters Fast","date":"2026-09-24T00:00:00.000Z","description":"Roaring bitmaps store integer sets in three container types so filters stay small and fast. How they work, why OpenSearch leans on them, and the tradeoffs.","tags":["OpenSearch","Search","Data Structures","RAG","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACCUlEQVQozzWPS27bMBCGtWgi60VRFk1REvWwXpZly3EsJ7FsJxGahYPGTtCk6GPXAF22B+i6J+gBuu0BesKOohb4QXwznG9ACnmwGYfb1Kvrk7vm/O22ul+f7puLx8vqYT3fbxcH6NTzu+3iHsqz6W7kr0HpIhzrjoicI4050Swt63hyEU9XRXU1Otkk5Qp4NN9AczTfwi1P50eaLequCJbuCpoZIjKE8yUtqP1Qwp78PxLiks4BFMNXMMRTDf8lgaCTqM9SO5gN3HHfSvssG/ACWNY5TIMDt7CxlbGHzCEMdAwRBtYkDOosuqbunDonb06fm/LD7eLzofryfvXt5+Pvrzc/fn3883z5HbOxyUsanBp2gUgiI1eAZcYgs1mpkwSReOidBW6VeCuA1F9vxw/L9LYpnorhldr9i0QA7aPaP+vcwH5gl5YZY+zLGqMk5vZY0Zii2a8kg5iRqBJJs2BaRo6sOS28sGAYYWYtFsPrkteumftkuk52u/JpxjfUTK6T/aH8tMvfpfZSRAyZoUFjBXOQJWQLGAdFcD5LN2Vce7RwSV5lzVn+OudLgqMyWlejZpk3AStF1cI0Is5Iwa0paUxAOmdm5jtTl+bEiCAuG3vOhJGsr4cOzbk98diEmnErIAec9vGtbAk9lYoqPZaJqAzEjpVBV/Y6VggE+j3N6qnWvxNKlf4FaQlS6xVSP4EAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/64f59be93a1aa438e69ee401c93c2449/40a76/hero.png","srcSet":"/static/64f59be93a1aa438e69ee401c93c2449/c972b/hero.png 340w,\n/static/64f59be93a1aa438e69ee401c93c2449/27625/hero.png 680w,\n/static/64f59be93a1aa438e69ee401c93c2449/40a76/hero.png 1360w,\n/static/64f59be93a1aa438e69ee401c93c2449/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-24-roaring-bitmaps-fast-filters/index.md","relativeDirectory":"2026-09-24-roaring-bitmaps-fast-filters","ext":".md","sourceInstanceName":"blog"},{"id":"840cd18e-2b5a-54ee-88f4-c1e423fea152","children":[{"__typename":"MarkdownRemark","id":"bfb5012f-35ea-5f68-9ad7-06dc5a14f989","fields":{"slug":"/2026-09-19-minhash-lsh-near-duplicate-detection-rag/"},"frontmatter":{"title":"Dedupe a RAG Corpus with MinHash and LSH","date":"2026-09-19T00:00:00.000Z","description":"Exact md5 hashing misses near-duplicate documents; comparing every pair is O(n²). How MinHash and LSH find and cluster them across a RAG corpus.","tags":["RAG","LLM","Python","Search","Data Engineering"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACDUlEQVQoz02PW2+bMBiGuVhOgDEHGxswhnAMJKQkKLRJIUnTbqu0dZo0bVOlSpN2sV3tF+zPz+m0atJj6/2Ory2VGStSbz7zT/um3y537bzbVoeuPh2aw3UtwtentttV15eLY7/qrqoy94uMlc9IIy0cggCSYlbfpFUfz7t0sRe62rwp6lNUdvP1XTzvk0VfrE5ptddJOQBcTAkk1eQCYAWyzgR/Q8XwhVYMIbisc8UMZSMQWjUDgMJz/3ObJGoTTYz5qhGImuXkNpubNJMhkzVnrDnISVgQO35ikhS7M6AHE+CMIFN0X/KSTV7f2MHKdCud5JjXdriGJEPBJjv+rJuv3z9sH59+3z7+KHef+fEBtJfl7be3ix6argTtxKA5wImGE/E8RLNiegGsqYaiMS5cP46ikLI8jGPKogmOFDsEJDFQJENPcqMmXe6j8tpiS4BTxJZuuNZwavhNd3Gq63df7tv797/6j49V+7CqP4XlvmmfdkWr6Y4ESWo6M2EunCGOkJOLD5t2Au2M+wvCLqoi6bZXSdUgf0XZ2nBKyi8ZzRToSGOVvKDpLsKBafmWxRWNvpLxREU68jgnGNtAs6BhQh3phgF0PAFUEueFMSBDxR6pZ8aAyiKjkjz113VaFZ7j8ek05EGYxKHrehNAhLP9H0TM/7vPGbFFBhhA4WMPFTpQ6FAhA5kO5HPDH8eyT3LwxOXyAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/4aa6b11a00da437300ba4f3109b953d1/40a76/hero.png","srcSet":"/static/4aa6b11a00da437300ba4f3109b953d1/c972b/hero.png 340w,\n/static/4aa6b11a00da437300ba4f3109b953d1/27625/hero.png 680w,\n/static/4aa6b11a00da437300ba4f3109b953d1/40a76/hero.png 1360w,\n/static/4aa6b11a00da437300ba4f3109b953d1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-19-minhash-lsh-near-duplicate-detection-rag/index.md","relativeDirectory":"2026-09-19-minhash-lsh-near-duplicate-detection-rag","ext":".md","sourceInstanceName":"blog"},{"id":"338277c3-7454-559a-b41c-19b1aa00f2b6","children":[{"__typename":"MarkdownRemark","id":"c2138c41-dd09-5194-ba8b-65db2d390778","fields":{"slug":"/2026-09-20-mixture-of-experts-explained/"},"frontmatter":{"title":"Mixture of Experts: Sparse Compute, Dense VRAM","date":"2026-09-20T00:00:00.000Z","description":"Mixture of Experts routes each token to a couple of expert layers, so the model runs cheaper per token yet still needs every expert sitting in GPU memory.","tags":["AI","LLM","GPU","Inference","Machine Learning"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4ElEQVQoz0WQ227TQBCGjYDE9q69u453fVh7N7ZzdtLEdYmiqDmgVAIJlbY3CHGBhAQS4im4g2t4H654MCZxaaVPvzwz/z+2x5ioKVCqGehQjs/79WF52FTby/lmNV3vzvf7+iUolFfLq6pfg+fBb7RI2iZpy00wL1g8Fno2qffDapuX66xcDRfbUbUbzDfZZDVabIWauUEf+Tn4IWVgphrQEW3TtIVj0FOpbJLaVEEJmK6EjuN10f+IgcAHM5L6Qa/fq7JsVuRzx9OIJs2oATpeUHiiYKKgPAc/NA2bJA0s6As58o46dv3soQ9YroSAHl1EvcVgspTdmenE0IewRCR57oRa5H/eff37/tuP3Y1hcUwhJhsQkW2alvrsslc/9TLiw5shLA3bjQHTifLu2ffXH36+/fRlf2f7XQuHlhO1ndByIxuHLS+7vnj1+83HzfzA1dx2QkgZMGuAZU+QeOZpWxRcjvx4CAzUlPEcszTOqrDc36yvf91+ZlmNThHDgt0nIOxQid0IBsfPcSLEklhXTPTgSHCOWJVhWppU0o5CbgwRCAcNpKOJrwnvUp5hevxVFo19/YIEQ0Tijpd0OqnvK8E155owaTqBYWLxCHrU5iQ2idBxUdzG4h50/wCef14NSLeaKCNzAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/af4d473859fb3f274c785c8efe369f46/40a76/hero.png","srcSet":"/static/af4d473859fb3f274c785c8efe369f46/c972b/hero.png 340w,\n/static/af4d473859fb3f274c785c8efe369f46/27625/hero.png 680w,\n/static/af4d473859fb3f274c785c8efe369f46/40a76/hero.png 1360w,\n/static/af4d473859fb3f274c785c8efe369f46/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-20-mixture-of-experts-explained/index.md","relativeDirectory":"2026-09-20-mixture-of-experts-explained","ext":".md","sourceInstanceName":"blog"},{"id":"c871fa37-e84f-56e3-9db7-041621f6e7f8","children":[{"__typename":"MarkdownRemark","id":"305c428c-f298-5714-805c-1a6ab9e6af51","fields":{"slug":"/2026-09-21-binary-quantization-vector-search/"},"frontmatter":{"title":"Binary Quantization for Vector Search","date":"2026-09-21T00:00:00.000Z","description":"Float32 embeddings make a vector index expensive to keep in RAM. Binary quantization cuts them 32x; Hamming search plus rescoring keeps recall high.","tags":["RAG","VectorSearch","Embeddings","OpenSearch","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3ElEQVQozz2QW3ObMBSEeQugGwiEAAHCgLkZ2xg3ZuzUtdtkmsn//0M92J3MfA/L2V1JB4PUBwDXI6p26Xyvfn3ml3cgm3+vLh/V9TM/v5fXv839K3m92eWW1OMjv7QMRBObKMZzXzbrdt5N93ZzGfbXbrh0w1u//dlv3w7HP7vDbd2ePFkzN4c8tAADc424xl5O/RXmOWIZdnMQVJRMlFQU4JpUWU6KXE15vuTdbIFrwySxRRVyUpsq4uUk63Da8m6icU3DisG5WYvXe4QjxBJb1YhnyNOQBwxdjTLtTBzhpHabiRzO7PbhzXd8upL+SIZXMl3Y+xcpBhB0f6bnO9me4Di4zHCDwgkKi0bEX4XFkcctFrnUI096ofc82QBu2MjVxLPBizsnbrnqnbC2SGRwVbthiZjCLHFEZZPIQtLCEsNk2SWGuYkC2JY4KcwBRGNEFViGnzSuLC0S2kwhb9kH+/D/FuDzoTPi66f1f2Evsx0FjzWCrHNk8WILHORye/KHH14/ifXo9UexWbTfTovujmKcw2YKdie5m1law3MMEwdwrUUkYGLJgzyIKhGVUq0dLxNx5YdFEFeu0OA+kt9IKEMnePKCBJSjtIGm0h0XOnxomPjhCtzv5JN/DidGDyZRRRAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3c2717ac11b2d145c93f39416ca41a5a/40a76/hero.png","srcSet":"/static/3c2717ac11b2d145c93f39416ca41a5a/c972b/hero.png 340w,\n/static/3c2717ac11b2d145c93f39416ca41a5a/27625/hero.png 680w,\n/static/3c2717ac11b2d145c93f39416ca41a5a/40a76/hero.png 1360w,\n/static/3c2717ac11b2d145c93f39416ca41a5a/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-21-binary-quantization-vector-search/index.md","relativeDirectory":"2026-09-21-binary-quantization-vector-search","ext":".md","sourceInstanceName":"blog"},{"id":"dbaadd8a-12a5-5606-ab85-0caea7791ca4","children":[{"__typename":"MarkdownRemark","id":"6f4f493c-56f7-58b0-87ae-575a3407763f","fields":{"slug":"/2026-09-17-kubernetes-native-sidecar-containers/"},"frontmatter":{"title":"Kubernetes Native Sidecars: Fix Startup Order","date":"2026-09-17T00:00:00.000Z","description":"Kubernetes native sidecars are init containers that keep running. They start before your app, restart on their own, and get shut down last. Here is how.","tags":["Kubernetes","DevOps","Sidecar","Reliability","ArgoCD"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACA0lEQVQozz2Qa2/aMBiFo3YCX2Lj3O2EJBQSCLcB41YILQyiUrZCR/dl09Am1v3/3zAD3aRHR5bfc+TXR9GTVKLVpkZ9Fqe7arprLF5uxptq+hxPt+XJ5/p8X5k8JfN9NN2enel/VTD1EHWlalY5Sob19rTTn9dat9XmpN6ZNbp37d590rptdmZJc6LblYv5ogrWQ6wHUolRkoq0AGAHqg5ENkDWGRuqHGoB+uc5+08RBTP/DS2QAUwEqwyM/idneeDZT2f5w+hvCuU+UjnCjvScnW8RBRWKJ5gPoaXVJuLhKFaHOPvudz+K9l3Yzyqrb3x5EOsji8cQmSenXPuckmEPsSKAhjl6Eo+vhNcgMCjzKtVenAzi+kClHEGTuInY/DFHW+pEVtAgRgipewoDoOutBc9+wTzLAd3yavNsN55mveFilGaL7NngUQ4YIM/E+lVvzTG2MSvKzhRIOGIefzjKAoDqEM1frb+IIMlh2ys130HTCxurxz0quHKKjRJf/5YHSIVEkQvTmw9W+gJy7AqY1eaoO7hXrohml00eMaukXNN2b1Z/P7nOm/LPZvqVBG2k2qcwxBbzm2bcR0SWWSxFXTdsYOZByk8vyL2o8MJWGPfkGVNhVoea31CZC4mjANUmepFZsgBOjUDVihKq+/L+jCV9RPclmLmoIOQuBTO4TP8CyY1NprMB3wIAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/40a76/hero.png","srcSet":"/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/c972b/hero.png 340w,\n/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/27625/hero.png 680w,\n/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/40a76/hero.png 1360w,\n/static/3ee5aa23c0d9f96fa0a3f6f3949a00ed/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-17-kubernetes-native-sidecar-containers/index.md","relativeDirectory":"2026-09-17-kubernetes-native-sidecar-containers","ext":".md","sourceInstanceName":"blog"},{"id":"e8c812a1-4061-5f17-bf23-35ef7b35d6a7","children":[{"__typename":"MarkdownRemark","id":"cc58229d-f8cb-52bc-ae43-a8747a98b34c","fields":{"slug":"/2026-09-18-fix-react-rerenders-streaming-chat/"},"frontmatter":{"title":"Fix Unnecessary React Re-Renders in a Chat UI","date":"2026-09-18T00:00:00.000Z","description":"An LLM streams tokens and React repaints your whole chat history on every one. How to keep the message list still while a single reply streams in.","tags":["React","Frontend","LLM","Performance","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACPElEQVQoz02Qy27TUBRFrYrGbzu242tf29ev+hE7cdLYTuIkTh8iaUC0pEWCUgnBLzBAQswYMWCKKG1VOkWAmPJ93GaEtLQmZ28daROuU7vO3HPnjj0Ldg6mk+ej4dk95VmRPx2Png12j8tiveF0WJ763h5Oblo1QYlGQ4BbnLYtmrIZh71JmE38zijqT4KsindnO1nld8dhb4pp92cqShgJkQIkRYNgmkiHke90DbPdBKGkx7IeSXooaSE+MZLDyh42JSK6iVjJFhSPk2yMIDsEwcGLrPq9fnlztL5enNyuzq72H3+rjy4xs+XX8ezLsLicHfx4ePxpfOABZ+iG0yAtnSiBLkGw8CIpfy5PrqaLu/nRTb28nS2vp4vv9eqymt+tP/568+dt/eo8HTwJdj0VFX573i3GcS+BNkEKhqe6lREVRjg0o9IMxygurahCSQ7daf/1av+zZtVEQ8BvLNWOdadthbHhhppNMLzBSBbTspkWohWLlky8HyXe+wFekVW26SbNAVaALA9pQSc50GBbDValeJ0gWaA53SCfo2SI4sIMct3uQW+g2VnLSPFygubLMFatrgwjRYlcc+RZIx9VUO0RFAtkPUZBBb1Cd3LdHUAPOzf8Erj9YnC+2nsXJQtgZ4qRanLa8Q8HyaM8WTmgICgOiKoPULdlpqrVaZmdjVOAMh64J/WH9y/+ZuHxFsnTvAbkxFD6+C3Scyhn92WK0zD0Bup/8xrJqZhNBqOygiE2XUG0RdHhm/Y/TbhmN17DKOUAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/5137398b75e04b7554db72bb2d3bcbd7/40a76/hero.png","srcSet":"/static/5137398b75e04b7554db72bb2d3bcbd7/c972b/hero.png 340w,\n/static/5137398b75e04b7554db72bb2d3bcbd7/27625/hero.png 680w,\n/static/5137398b75e04b7554db72bb2d3bcbd7/40a76/hero.png 1360w,\n/static/5137398b75e04b7554db72bb2d3bcbd7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-18-fix-react-rerenders-streaming-chat/index.md","relativeDirectory":"2026-09-18-fix-react-rerenders-streaming-chat","ext":".md","sourceInstanceName":"blog"},{"id":"837ae7b3-a036-58d2-85c3-6a32dfe055d4","children":[{"__typename":"MarkdownRemark","id":"5185e4e1-d463-52a2-b411-39b13e3d3e76","fields":{"slug":"/2026-09-14-opensearch-vector-store-rag/"},"frontmatter":{"title":"OpenSearch as a Vector Store for RAG","date":"2026-09-14T00:00:00.000Z","description":"Run RAG retrieval inside the OpenSearch cluster you already operate. Set up a knn_vector index, pick faiss vs lucene, and avoid the memory traps.","tags":["OpenSearch","RAG","VectorSearch","AI","DevOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB7UlEQVQozzWP246bMBRFeWkA24BNANtgMLckJJCrkqFJpiiVpqp6mYvatz71pf//Cz1Mp9LS1tbR2pJtNPoKzNPzYflpOL5c948fjs/D8fl6eIR+3n0b+/77rf8xnF6284+L7PJvAhimlwDvXMnzbrY5zzcXyMX2WnV91fbl8q7Z3dfr993ptjwMYbYE83USQxqEaeK/gWmGWQYJ3eOVG41gNt6RlyKaOdP8TWYZDA0MV5LYgKMITTFNbU9hloa6AYJ0AR15CmwwbTyayBk1wCChDtqlaJqgrLE/SozPfD5zpwVhueMXXljRsIYlEXnUrnjTUK3BRK4y0FSxsp7mlae0TaUX1Xp1rdZDMuu9uJXlKS77qd6RaY6DlBUVmG6cIpYg+DNypGnyicUtLG0iWDQr6otI9iLeyWSfFn1Z338+/ZayM1FkWdy0uI1j5I4YNkuornxVOJEyXR6L9sv250P3dMyGu/x2a74+tE+/+j+KdyYTNCuZKlypkSdtVxooSMJ1wxdzN1XYjyc4xrQktMAekJOxl6abmVhgngXtQjRzvywQFfBMwybctMOJHSJHTLCoM7mpeVPwVcnbSkCuCr7MwzAILSzABCwc2Q4HDMuJLIePkGiCI8F5roROpFYjWSzy1/RoYJL/JkzIyF9mDEg/kt3NYwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/5b138803918816bc6564009524360289/40a76/hero.png","srcSet":"/static/5b138803918816bc6564009524360289/c972b/hero.png 340w,\n/static/5b138803918816bc6564009524360289/27625/hero.png 680w,\n/static/5b138803918816bc6564009524360289/40a76/hero.png 1360w,\n/static/5b138803918816bc6564009524360289/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-14-opensearch-vector-store-rag/index.md","relativeDirectory":"2026-09-14-opensearch-vector-store-rag","ext":".md","sourceInstanceName":"blog"},{"id":"379bdda0-678d-5e37-acbc-9e8417704f45","children":[{"__typename":"MarkdownRemark","id":"f92a4916-d3a7-5658-bae1-babd493fb8d8","fields":{"slug":"/2026-09-15-grounded-citations-rag/"},"frontmatter":{"title":"RAG Citations: Make the LLM Cite Its Sources","date":"2026-09-15T00:00:00.000Z","description":"How to make a RAG system cite its sources: force the model to reference chunks by ID, then verify each citation against the source text before trusting it.","tags":["RAG","LLM","AI","FastAPI","Citations"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB6UlEQVQozzWR7ZKaMBSG+edKwAABCSQBFMKHCooiorW62467s1tvodPW+7+IHth25pl3Ts5n5hzFFMeBDrOWhCdZ3+P1R7z5CJevsv7xz9jewQ85Bj+A/i85KggzdeJjEhGaOH6Wrbq8OmZllxR7sBfrL3LRruqveXWCKKFStwIVMzSgIDNQDYHMcGLPdTJTjUDtPQGywt74xBCATiIAmQIZHA0lChE7Grd0tsVuMXFzUMAAvIVBC0jSzAiRRLUAqdmZ7uQ9dgohZRpuuTyweE/nOzfaQhc625Fka7LK9FYq9mEXov4dFd95+mx4G0w3oIa/Q9ZMoWEd5h2Xe5F2LNkH6YGlBzvdWryE4Sr2INvP30Vx4/nNky+AHZ0N3iEzUtywFukhyKC+FbL15UkeHzZvLN6YvG+PWRfVv5L2AcT7R9z88cufdnLvv+0EayZbL268eQMaxE2YtAYrTR8mL+EQOi3dxYWVV391ZeWzm59JcjDDFpaqiLgpNy+L8rKsrovqKmXLeIW9leVXUDzWXN0v3eNNnN7Y8ZWf3tzdN7K+WPlZnQjFnKaEFsTNba8gNNccqU9TPM2wm02mcqy7KoarzFUMV+wBG1kx6Finygg5I83pdeBJm/agAe3zCX77CdAGRfZoAEJ/AcmbURXYoUZ7AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/dea034eb79a4b0ee218da87ab715cee7/40a76/hero.png","srcSet":"/static/dea034eb79a4b0ee218da87ab715cee7/c972b/hero.png 340w,\n/static/dea034eb79a4b0ee218da87ab715cee7/27625/hero.png 680w,\n/static/dea034eb79a4b0ee218da87ab715cee7/40a76/hero.png 1360w,\n/static/dea034eb79a4b0ee218da87ab715cee7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-15-grounded-citations-rag/index.md","relativeDirectory":"2026-09-15-grounded-citations-rag","ext":".md","sourceInstanceName":"blog"},{"id":"e8300e22-85cb-5ca3-b300-a1b460ee3476","children":[{"__typename":"MarkdownRemark","id":"82ef316a-8136-5ed6-9669-3204545dd028","fields":{"slug":"/2026-09-16-fastapi-pydantic-v2-request-validation/"},"frontmatter":{"title":"FastAPI Request Validation with Pydantic v2","date":"2026-09-16T00:00:00.000Z","description":"FastAPI validates request bodies with Pydantic v2 before your handler runs. Models, Field constraints, custom validators, the 422 response, and failure modes.","tags":["FastAPI","Pydantic","Python","API","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB1UlEQVQoz1WQa2+bMBSG+ZQABttgbCAYsLkXwiXptClpk3btqlb7/z9oh0SqNOnRq1c+57ElG7QbAa8bcd2L6dj//qifX6unF8jidGkvb9ChlOdr9/Lev/5h/UTawbtZho0lwing8SpO9/v52o/P3XB+GJ+q7tcwX6H306UZztCH+cLjB8LKu2UgP7vjBtplyg1KzCuHaSIqImqXaSpKwkscaLpmQXjhBsrxM8BANEVEIrKmTaTIpkgvVDSRmoWa/bBN8jFORzCTfIrk3vXVFssNliZJDRAQS+0VibwUBRmKtE0Sm+dOqCySeCwPhWJhEQkthMJelvNsSSstcpATtvTl11l/nPy5p8PoHQ+kG+g4e/OMu4ENo5wO6XJM54NcDkLWS6z+dsNRaviwnSuVXzcAFGen3bxCPCO6YeOeZR3NWjtUdphbIodi0gTDe56kVBoWji03Mp0VC0WgOUlhotDmKUq06cRbHG/dCNZsmqyQ2MSx6a4YYFq3GSTMfD352SSKx/bxrfvxXh9fx9PndP7aNT/hnOWzG5emE94tkMNv4FacNGTXMrUXegJ4MYflAgRqorLDuxZ+1HLEfd8wHfE/HNiiYGMHm3vabAUF29vIRPx7+R/odUZAaloa9wAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/8007290a8ca1a8e6e05f5955fe127fe7/40a76/hero.png","srcSet":"/static/8007290a8ca1a8e6e05f5955fe127fe7/c972b/hero.png 340w,\n/static/8007290a8ca1a8e6e05f5955fe127fe7/27625/hero.png 680w,\n/static/8007290a8ca1a8e6e05f5955fe127fe7/40a76/hero.png 1360w,\n/static/8007290a8ca1a8e6e05f5955fe127fe7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-16-fastapi-pydantic-v2-request-validation/index.md","relativeDirectory":"2026-09-16-fastapi-pydantic-v2-request-validation","ext":".md","sourceInstanceName":"blog"},{"id":"a2909770-d3d0-5775-8fa7-b3c5711e66eb","children":[{"__typename":"MarkdownRemark","id":"b31d0de0-b10e-58dc-8998-d7a497a25e1f","fields":{"slug":"/2026-09-12-fastapi-websockets-streaming-llm-chat/"},"frontmatter":{"title":"FastAPI WebSockets for Streaming LLM Chat","date":"2026-09-12T00:00:00.000Z","description":"SSE streams one direction only. When an LLM chat needs the browser to interrupt a running response, FastAPI WebSockets give you a full-duplex channel.","tags":["FastAPI","WebSockets","LLM","Python","React"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABtUlEQVQoz03Oa3OiMBQGYD5VRQlBJORiEiCRq9KlRVtvrd3tzn7Y//9/9ljcjjPPnAnhfZM4jTagkumubn+9HD62r5f+5eduD/Ptafv5ejx3/fvzDha/D6e+XNcqGyrAGfkKPCBJ0x95ewamOazas92czfpUdh9ZvTebo92cqu7C7TMkr/mvljMLFPDmGsdFyOto2fgkd4Nk4i9dLCdIzMJsIRoiNzBxnENyqABniuVVoKCjVn39+KZXWyLqkGR+qK8iq2xvm4PMd4isbvkvjgs33Iixx3CoGbdcFJznghnJQQaLVFjJ0gU1KNTfFSiLwcwX8FTDlKUiISKJhY5FQiXsSKb/dE/7skLEBlH6XXFcxEGn2DFXWUxbW3ZFUyizTm2TWMuVoUtNxKVZ10I6Y+J6dKgAZ4IYnLHKqtKUUuWQLpZJlRVlWhRpUWZlbSuTln9P721mH5DAC+X6HFrAmXgUjBEfefDNg4CHAfM94iMCc47pYs5BYjtlHpluFsxMfTa0oBzfmyHqY0aJojHQMVFRJDFm8NopFihU15tmZAg7sLo3mhIX0Zhq+l9EFOyMbn+j+/A/YwZGwBp7r5QAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/f592754569a19a404a61ee0fa9a91ca8/40a76/hero.png","srcSet":"/static/f592754569a19a404a61ee0fa9a91ca8/c972b/hero.png 340w,\n/static/f592754569a19a404a61ee0fa9a91ca8/27625/hero.png 680w,\n/static/f592754569a19a404a61ee0fa9a91ca8/40a76/hero.png 1360w,\n/static/f592754569a19a404a61ee0fa9a91ca8/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-12-fastapi-websockets-streaming-llm-chat/index.md","relativeDirectory":"2026-09-12-fastapi-websockets-streaming-llm-chat","ext":".md","sourceInstanceName":"blog"},{"id":"ba416a22-8dd4-5d55-bd7d-78220ac347bf","children":[{"__typename":"MarkdownRemark","id":"c337c28d-a9b9-5749-82a0-071a6c36a5a2","fields":{"slug":"/2026-09-13-agentic-rag-when-to-retrieve/"},"frontmatter":{"title":"Agentic RAG: When Should It Retrieve?","date":"2026-09-13T00:00:00.000Z","description":"Naive RAG retrieves on every turn, even when it shouldn't. How agentic RAG lets the model route, grade its own context, and re-retrieve, plus the tradeoffs.","tags":["RAG","LLM","AI","Agents","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACBklEQVQoz22Ry27TQBSGvSmN7fHM+DYXX8Z2bCe+x46b0KSWQIKyaWkLC8SOd2DNU7DlZTnphg3Sp6Ojf+bXf+aMJsJFRhdEeDeMz+P8dRhf+vF5t//S9J/b4WmYXrrhqekf6/ZhBLF7ZPIUxIsMF02noU6CFZbYS8ruthrP7bTUu3Mz3W2H07Y/NdNSDaeiPZbdsR7P0JhOrBNp0FAzbUX83HIzg4IUrXCk48ggsUGTK8tdUf8K2aCYdkJZYVAF1ywnJV4OjWaSyA0akUxcDV7YUVHZsiF+ucJsU37/+O73PP5ETmp5GWEFVOQkftyF+Wzzjabj0JFVsN7HxcxUT/jWeTVfW15d/Xi4/3N7+IVohqgyaYIAO5Fql5ZHV1RgDi7mdBLJLsgmcNqiwV4OOoxqsw0MaXoKZ5VTtCTdmq7CSUnyGgVrTbekTKduvu8Pn9r5nqnJV5PNK90STB6r9jlW75EscDOw/YE2O5NnbrcXb88kbyAZ9rx2ZQ1QtiGstPkW9gdm7OS+GKlXURrFfK1EEbE1pmEYKBUlPou1FeLw+v35YX9+XDeLG40subFFtUKMybe7/lucfuBedluMS32Yi1EwNQ/13c1QlwWMzXUsDPg3/A+IBd0kQrox92LhJ9xTjhMZWEDYG4NdGezaZJDM/ss1YohI6kSA81oBiwaXU4tfQOwvRmRODAajbqYAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/c912980bcf337b4612f77538821ce496/40a76/hero.png","srcSet":"/static/c912980bcf337b4612f77538821ce496/c972b/hero.png 340w,\n/static/c912980bcf337b4612f77538821ce496/27625/hero.png 680w,\n/static/c912980bcf337b4612f77538821ce496/40a76/hero.png 1360w,\n/static/c912980bcf337b4612f77538821ce496/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-13-agentic-rag-when-to-retrieve/index.md","relativeDirectory":"2026-09-13-agentic-rag-when-to-retrieve","ext":".md","sourceInstanceName":"blog"},{"id":"32ffb60a-1fe7-5c98-ba28-ad7ae8181bec","children":[{"__typename":"MarkdownRemark","id":"9d76bfa5-6fd9-5fdd-9240-9069d7a08f7b","fields":{"slug":"/2026-09-09-parent-document-retrieval-rag/"},"frontmatter":{"title":"Parent Document Retrieval: Search Small, Answer Big","date":"2026-09-09T00:00:00.000Z","description":"Small chunks search precisely but read like fragments. Parent document retrieval matches on child chunks, then feeds the whole parent to the model.","tags":["RAG","LLM","Retrieval","Embeddings","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACE0lEQVQozy3R2W6jMBQGYK7SLBgIYDYvmMVgwEmhkzYkhaTppKmq6eRmpF5W8/5PMW410qff25Fl+Wh1iZWqQMehez7cbTfV09Adh1blYy9Phx/7h+Z0uBv3a7W538oyD+tC1WOV2gTQiU4BLHI5FqsjEzvRnvjq8O3I109JNRTrJy6P9d2Zif3C4RMQTwC7MZhmwszyctPLdSdRDJjpdrxYkrmF1WTpp3aQLb0E2AjY2HSpBRmwKXCIblMN0jbKege3LulstLYiaXrlwsJzk5gOlu397WaU3Q4ltY8LD5dxmssmpyxTNZodVVHSobSL0hbi2kW15fEpiKYAGQ6Oiw0qRlQ8BtnOT3slyvsouw9IqVtIK3giKoFjQVjFsjLJCkwT20sMVz0VM7GlzSVuzkxemHyNm5+oOLjxvY+5bkXatqPXc/Z+ys8j/3hLP9+RrLNS7op6gwm9PtO/V/z5+7+PV/xxQX9eyK1kMxBqufrmVVPVZSmqbp1fn+O2IX6I/ABREg4P6tL858C/jHzYlmNfHvpClGxmBJqNVpBtzahdog4E6zmUps8DIkyYzg01Dqj5heo3JSwvkXgJ+MkivYv4wvA0KxCQdjDuVNpIKgbMbxbwZuGZdhBnFc5byr+gpAnjKoxFQEVEkhnwtLkZ6UuiGqt/9Rap5cwIp7o3Bb7KBXCNpe945Bt1/VglsLw5gOr0H3xmWlqUGuSYAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/73688f50ebb030dd3cc9f68a43db401a/40a76/hero.png","srcSet":"/static/73688f50ebb030dd3cc9f68a43db401a/c972b/hero.png 340w,\n/static/73688f50ebb030dd3cc9f68a43db401a/27625/hero.png 680w,\n/static/73688f50ebb030dd3cc9f68a43db401a/40a76/hero.png 1360w,\n/static/73688f50ebb030dd3cc9f68a43db401a/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-09-parent-document-retrieval-rag/index.md","relativeDirectory":"2026-09-09-parent-document-retrieval-rag","ext":".md","sourceInstanceName":"blog"},{"id":"08800f8e-655b-5824-a65e-225f24654959","children":[{"__typename":"MarkdownRemark","id":"bd303029-a6e7-5ac7-b7cc-6726c8ae4510","fields":{"slug":"/2026-09-10-maximal-marginal-relevance-rag/"},"frontmatter":{"title":"Maximal Marginal Relevance for RAG","date":"2026-09-10T00:00:00.000Z","description":"Top-k vector search keeps returning near-duplicate chunks that fill the context window. How Maximal Marginal Relevance reranks for relevant, diverse results.","tags":["AI","LLM","RAG","Retrieval","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB8klEQVQozz1RaXObMBDlS2NjCQmQEIcQhzgNBhIfLT5qO8nkS///D+qSznTmzc7uap/eHkaX7AB9MoDdxt1j//w4fd6m38/jO/jX8fY8vD8OT8i8Hz8uw7WV3f9644WqFY1fiERcE78udpft/qn783b/qKdbNV7btztY3c+700c5XGjYIF68kHhFlYGdxGKZxXLCtS1K5GQbO8VujpwUuUseuxkAOYlJJbIVWTIJsmPkKANiixUWLwGYlW7Ui2SifgO+xStIgr+8upkX91x21Cu+ZSr4xdjQGP8js8IJWi8eg+TVVxMRNfEqKiobyFDgZlIfgvQ1SCcuez+d3LAFssRMLwqiBqYddMzf/tl/5fUcZFPezlANr9AkZqnlwThqTUKASSJjQyKLabzIdm7Yx/o47T8jOQj1aouGejU0j3lBHJX5hRJasJTYMcCi0jBJCMqEl16w5dFOpm95M4toJ+LBZAViMGGFmGYsvXeXc3U8N7/m+nRt5z4dDNMKkJuzoP0a71ofnKiHFqB/IpqD3jfJuHY1zExduOzPcTeXehQ89XnOXAVkH5TtoFX6LUhg5tYJOyoa0By250gNaFl7CbfxZMtlw2W9puEP5K2wMNZYwOiw8xWGNSwOrBAsnHBtx6Ydb2wF4Rr7KyB8A3yQNLH/FwJLSj8v5LHiAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/42035b5990649c4308fa5035902519cc/40a76/hero.png","srcSet":"/static/42035b5990649c4308fa5035902519cc/c972b/hero.png 340w,\n/static/42035b5990649c4308fa5035902519cc/27625/hero.png 680w,\n/static/42035b5990649c4308fa5035902519cc/40a76/hero.png 1360w,\n/static/42035b5990649c4308fa5035902519cc/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-10-maximal-marginal-relevance-rag/index.md","relativeDirectory":"2026-09-10-maximal-marginal-relevance-rag","ext":".md","sourceInstanceName":"blog"},{"id":"e7314fa2-bbef-5c1d-8e11-75b4acae108e","children":[{"__typename":"MarkdownRemark","id":"f283d1b6-cb95-5855-a273-a2b67a3c9b2e","fields":{"slug":"/2026-09-11-cosine-dot-product-euclidean-vector-search/"},"frontmatter":{"title":"Cosine, Dot Product, or Euclidean for Embeddings?","date":"2026-09-11T00:00:00.000Z","description":"Cosine, dot product, and Euclidean rank vector search results the same on normalized embeddings, differently otherwise. How to pick and configure one.","tags":["RAG","Embeddings","VectorSearch","OpenSearch","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAByElEQVQozz2R3XKbMBCFuQsgrYQACRAIgUAY/+DYvohjJ+1Fmk7f/426Np3OfLNzNNpztAsBnc7whPoT1vHHH/v+5T5/u4/v7vbd37+7+68Hty+8wiPfXtZONAaENf/gTVb4ze42bt6W08/98dPPb6i3hzuyWz7mw93P11xN/y0BSVuS2li0CM06mlrjTpDaEGqStHW/2PEMeR/yRjbbYXu1/gJ5t7oCkhiEZR2XLmY1l305vEI5EtkT5WS/6OnMEhODFnlfmYPUMxXt6gpi3iBEtIkaUfBikMd3cAv0B+j2dHwVy5W6PTFzJLtYuTh59j/MDZprJGL6mddEUBXmyFILiYGk4WmfyJFKB3qi3Y7Pl0R77AlpiTWImV4BXAODmFZmD4/lW4xjueNyoLiXeMQJOcasSrVv5kvWTEHEKiSEkgicR6NOK9zqMRUCmWWyx1wUGCcKjz2QtVnlWW6DCHCAknDNMrvqVHmKHwKqiJaUG3w2JAUeMQsHec5cvBCFFc1FSBUVNWQGRZxoIlsiDdOO10NSD8J4BAVVLRT4k2q0rM8EaEBeiERCoiKhadkhotvkwy7r59zv1XTI3ExLSytL8ibEzqfrL2TMQD9kW0U8AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/253f7d1c56e9e7b3fd4601ef40351ea0/40a76/hero.png","srcSet":"/static/253f7d1c56e9e7b3fd4601ef40351ea0/c972b/hero.png 340w,\n/static/253f7d1c56e9e7b3fd4601ef40351ea0/27625/hero.png 680w,\n/static/253f7d1c56e9e7b3fd4601ef40351ea0/40a76/hero.png 1360w,\n/static/253f7d1c56e9e7b3fd4601ef40351ea0/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-11-cosine-dot-product-euclidean-vector-search/index.md","relativeDirectory":"2026-09-11-cosine-dot-product-euclidean-vector-search","ext":".md","sourceInstanceName":"blog"},{"id":"bb61d485-c290-54c2-b045-46a83bafcab2","children":[{"__typename":"MarkdownRemark","id":"0cff266b-27bb-5932-b32a-4cd29e512c76","fields":{"slug":"/2026-09-07-parsing-pdfs-for-rag/"},"frontmatter":{"title":"Parsing PDFs for RAG: Text, Tables, and OCR","date":"2026-09-07T00:00:00.000Z","description":"How to parse PDFs for a RAG pipeline: detect born-digital vs scanned files, pull out tables without flattening them, and reach for OCR only when you must.","tags":["RAG","LLM","Python","FastAPI","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACAklEQVQoz0WQWVPbMBSF81JI7HiT5D22LG+yvMUEShzbIQkM9KGFKXT6QP//D+kNzLQz35w5vjpndK2ZwUejGFExGnzQst5pT+L4lg7P+fgCmo3Pye57Nr4kux/l8c1p79Wsh+RHfpxJqiervqR4OmbYTm1frK+PdbcX9a5eT931kVe9aHZF1Zft6IU1tjOdMMhDayajUDbOLBFVCFuiaKGtFloAOgdUf6GfvaSHcy1Y4ugzIxkhMJP1QEGRiiIFMwX6OFI/DHIyyxfEL0yXY5crKNQIHAEUFDwkYW1fj2+s7hvKelKdMB9IfSLijhR7a/1Eyr07/LLSr4wVIc1plEdxSWkaJ6XtxVB2UTF5+3dSHuztT7N5cO/e3cMfs3tyx9+4PDj7d7ucymqTZnWeN1xs4jiv2q23Ss4PptMrzCcjuUVpD5jrRwBWwNmA0i1pHkh6w5iIYs4Yj5MqDNM4rV24ea44qpVi2mqeQKtKdbjuCc0tlnaOglrzChQ2qpOFQeT71LRXlDJs+nEUY3M1WygO/DOpjrC81ZyS6TWdXs+6f7Pbexga4uBVQyt4U9bT9vo43NxedbUosziBsrV0CzXq1LA12MbKt1Z+C9i8N+INDBXaobCiQcRYniY8+SCiiesGs/nSmsvmJ5cSuVjgf8Dn/7lkXkjkC7AATy5l80I2/wIPgFRej56GUAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2cd1baef737ff704c51e7dc49d568c7e/40a76/hero.png","srcSet":"/static/2cd1baef737ff704c51e7dc49d568c7e/c972b/hero.png 340w,\n/static/2cd1baef737ff704c51e7dc49d568c7e/27625/hero.png 680w,\n/static/2cd1baef737ff704c51e7dc49d568c7e/40a76/hero.png 1360w,\n/static/2cd1baef737ff704c51e7dc49d568c7e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-07-parsing-pdfs-for-rag/index.md","relativeDirectory":"2026-09-07-parsing-pdfs-for-rag","ext":".md","sourceInstanceName":"blog"},{"id":"97299977-049c-5277-94c0-0dbf98003167","children":[{"__typename":"MarkdownRemark","id":"35ad08c2-61c9-5116-bead-bcf514543cda","fields":{"slug":"/2026-09-08-ivf-index-vector-search/"},"frontmatter":{"title":"IVF Vector Search: Search Fewer Vectors","date":"2026-09-08T00:00:00.000Z","description":"Brute-force vector search compares every embedding. How an IVF index partitions vectors into cells, probes only the nearest, and where the nprobe knob bites.","tags":["AI","RAG","VectorSearch","Embeddings","FAISS"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABy0lEQVQoz12RS2+bQBCAudTBwO6yPHd5eNcstsFOTeIYg7ErK6pyaXpIeui59+QP9N93FjdSVenTaEbLp3lgSHGWUjMTw7p66tof7f5l//ACyf3d9659hRI4tK/N9vk0/Fwtv87yk7bE2TBJYmIOTJyYsmKz+6LWbVHv62YoN119d6qaYXHbr5pBrnafHy4eKyeIaYskhkNnOCzduHbjisQVjnQkEKOV482nJJ+6uUWF7QmbCpNklps7VIAFGBbJKN8wdYznXVz0QATJiONL4qu5Oubz+/nyIBdtKhovKkGx3RwwLJxSvtaOPIxOryl6VvQoKJAnQl5jX7qBoqECE3sS5CsgJyAzLXeB3F+G92+Pv5kauDriQGF/FiTljcNuEB9hJk4skl4xLMQpq6FbJNpAtn376+n8BjJTPQ4VohljirMyZipNFpyXXiCniENLwDARc7XcgQyTw8LXqHeGCTEnvnDc1CYJRCh1PgK5YToxyOPYh49T/U3gJIjm+eIYZk2YbYNsy+VOVme1uZS3j26oQI5G+fhxMM1Vhr+Cae6FJUwHG04x9yIVsmXEV3FSITfVsu7gK+QX/wFfw+u/TOxgYgWfLH9i+VD+AUBdTY02lx04AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/ce304b9c360b6d8df5372e94a8ea8897/40a76/hero.png","srcSet":"/static/ce304b9c360b6d8df5372e94a8ea8897/c972b/hero.png 340w,\n/static/ce304b9c360b6d8df5372e94a8ea8897/27625/hero.png 680w,\n/static/ce304b9c360b6d8df5372e94a8ea8897/40a76/hero.png 1360w,\n/static/ce304b9c360b6d8df5372e94a8ea8897/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-08-ivf-index-vector-search/index.md","relativeDirectory":"2026-09-08-ivf-index-vector-search","ext":".md","sourceInstanceName":"blog"},{"id":"a8258a50-621c-5da5-88ae-ca77efffee88","children":[{"__typename":"MarkdownRemark","id":"c99c50ef-9ee9-50ae-b0fd-acff1649e1b8","fields":{"slug":"/2026-09-05-parse-partial-json-llm-streaming/"},"frontmatter":{"title":"Parsing Partial JSON While an LLM Streams","date":"2026-09-05T00:00:00.000Z","description":"LLM structured output isn't valid JSON until the last token. Here's how to complete and parse a streaming buffer so you can render fields as they arrive.","tags":["AI","LLM","JSON","React","Streaming"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABz0lEQVQozzWQW4+bMBSEeeoWG2zAYGNj7pcEQwikmzSbVH2s1O1W+97//0N6IIr0aTT28RxGWH769uRaHX93p7/N/Gf/+pmPv8C0y0e3fDxMM7/vvsH0nSaXR8RCNME0QUTRsGjNeVx+9tPNHO9Nf94frsPyYzjeh/lu5ls3XOC4n26EFYgqSFnYz7CfgzpBAQZ5KfJy5BcOaxzW4qDBbCOoYGpTjf3UZcWWyizspU80ptoJKoi5rHb8dZfz2AuwmsQTAA/WslsEausnCQ5K4OGRt+kGbCFiXJdGe6pOTtghAvfaer5QyIP1DSbJWsFLbQI3YDT8DhIf1hF8DTTsqf5ubykLZiuuhHpxcYqzUWRD3i678SqzgWsjUhOlrzKbmOzT6lj1t+78j0lju8KyicRUuVQRqiJeRaIOeSlkw+LG46UXV4hp21eYaRQkmCU8N6I6BEn3lcTWF0cophddznU/Fe1UdkZXbSRDKCZTr8/TxcjDTs99ZKp4bMO+xLlwa+XIFMJcs+Re7W6teWvNvRuOWb3nSrHMzQqxNPps8rcRVC4dqL6YeGn9PsMqtV4c7hLBfcU9ueLLyF8VO/yFCiwSmyskEvTQDRxrUJvG/wHFjUdA3AcjkAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/6075141fc24c832e20f8bc8a74a39ebe/40a76/hero.png","srcSet":"/static/6075141fc24c832e20f8bc8a74a39ebe/c972b/hero.png 340w,\n/static/6075141fc24c832e20f8bc8a74a39ebe/27625/hero.png 680w,\n/static/6075141fc24c832e20f8bc8a74a39ebe/40a76/hero.png 1360w,\n/static/6075141fc24c832e20f8bc8a74a39ebe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-05-parse-partial-json-llm-streaming/index.md","relativeDirectory":"2026-09-05-parse-partial-json-llm-streaming","ext":".md","sourceInstanceName":"blog"},{"id":"a9bee792-e878-5699-848f-b822beeb22e4","children":[{"__typename":"MarkdownRemark","id":"fb1611c9-fd09-5d77-bf8c-b014c900e4b2","fields":{"slug":"/2026-09-06-kubernetes-poddisruptionbudget-node-drains/"},"frontmatter":{"title":"PodDisruptionBudgets: Survive a Node Drain","date":"2026-09-06T00:00:00.000Z","description":"A cluster upgrade drains a node and evicts every replica of your service at once. How a PodDisruptionBudget caps voluntary disruptions and keeps you online.","tags":["Kubernetes","DevOps","Reliability","ArgoCD","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB8ElEQVQozzVSaW/qMBDMR0oOJ3Z827nIhRMngZaGUkoP9f//pmeKnjQaj7Q72tmVvaS3DnE36tPb/uu3/fjeXW7N9dOJ5vpVnq/d7eehzfdvvl5AOzwsDt42VBufB5Eum5fp8NWPl9Zc2uHamPe9vdX79268menWmrf9+F53q+vfhtIPlR9pL0yrVJqYtSGug7Ty0ypCWmUlFRmmIs8yJVUINWBdwroQ7wCpHQeo9GHmJbyv7Y3oJaYGSgv4yJgyjc45Kjn4mOlqEMJS1mvRXwIyAG6hmgBpfaC8CDfA2aoF9S+JHAEfKBFQ4Lbvr2WRplByhKkOqUFybFqryjEWFuBmG8m7GSqb2ld8usBiBmygmNJxIOsnl1RJl5xRlidyLrrX89EOxqWzgDiz8NwD5USaZz6cXexYjJRyXbK8LzgOcsUqjTAWbh1X7cxRVUsipvvkkHsBzAPkDlABXEdpHSa7BGqGOSMiJYpSyRiPoHQ9oavej1pHjmH+FDEvJjtz/DHHb6Itqga0WDRMybzQ0fY7zXSD9SJyh1nk03/MIK02AXXmWrfnrH2l2YLbGa8HvCzpeizWw6GXKm9k+Vw2J4eifrmL+lQ0JzdyExBvC8Q2Vlsgg0QHsXa/5cEx3T3FhZ9kvqvG6ukBcOe/fuHM/wCVkE+S52BpGwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/6f73cc52999ecdead939a70ceb07cead/40a76/hero.png","srcSet":"/static/6f73cc52999ecdead939a70ceb07cead/c972b/hero.png 340w,\n/static/6f73cc52999ecdead939a70ceb07cead/27625/hero.png 680w,\n/static/6f73cc52999ecdead939a70ceb07cead/40a76/hero.png 1360w,\n/static/6f73cc52999ecdead939a70ceb07cead/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-06-kubernetes-poddisruptionbudget-node-drains/index.md","relativeDirectory":"2026-09-06-kubernetes-poddisruptionbudget-node-drains","ext":".md","sourceInstanceName":"blog"},{"id":"1884a72e-ef13-517c-b205-2561e5635d39","children":[{"__typename":"MarkdownRemark","id":"09c22b50-9382-5b6f-bc0f-83c0ecc02e8f","fields":{"slug":"/2026-09-02-reciprocal-rank-fusion-hybrid-search/"},"frontmatter":{"title":"Reciprocal Rank Fusion for Hybrid Search","date":"2026-09-02T00:00:00.000Z","description":"Reciprocal Rank Fusion merges two ranked lists without tuning score weights. The RRF formula, why the k constant matters, and how to run it in OpenSearch.","tags":["AI","RAG","OpenSearch","Search","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACI0lEQVQoz02QvW/TQBiHvcSfZ9+d7xyffbZjOx9N4qSkSRqSNp+tUJUSqYpECUPUAgKpYUPdWNjYmJDYmBnKwsDEwMIfxqWFCumZfvo9d+/7SlmheE8tTJpJebbfn3R6o73uUW8waLamnYezbn/Y6ozb+424JDr3fUmGkSBnBjpJLXcHsmqpOSzvjuNaf6c1SeoHaXZYeTDehs0R9uuiI5qyFSowkgCOTBILIE1RvgidFNiFW2IDhf8R6XZk0QTRVJSFJZB0GLCkXWs/KjYnSTaq7B2Xdmcs6WK+i1ndQMGdLGqk1KFhnfpV6teEKUIhc+iUKM94mPlhxqOGHzZsVrNo0SSJcP7BEasjt4ycVEx399xWVgFTDdsjeUZcFzsEUlm3NcvTof/3WxwIRKJBT0NcKGILA4eSZjLTjodPvxy9/EGiQdp9frL51Zhcq8DRTFfWoKIjVSEW4AhFCIVAZ4pq5xRTVi1JBXngpL3N19H1T1qbpcdvJu9+V5fvcyp0Cv3Zi5vB2Sd2cha83eRPH3vPVt7VZWG4ml3ctBcfJA24wObukzm7XNppmfY63utzZzpUFOTEhwfrb53F5/x8Sa7W9umcnC/Jq1U4vRiuv7cWHyXVdA2LxW5Y8UKKPY/yKo8Y8XWLyQalLMY0UDQaFTJVd2xSYKycU7DLixb2tmNvfSwOw2XgatAHt7fZ5oYDxHkspgIXkkgkBvJNO1AMx8Tb/A8dqVfhOKMvqAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/03c69b7b1f3f10ef17416f7f382600ae/40a76/hero.png","srcSet":"/static/03c69b7b1f3f10ef17416f7f382600ae/c972b/hero.png 340w,\n/static/03c69b7b1f3f10ef17416f7f382600ae/27625/hero.png 680w,\n/static/03c69b7b1f3f10ef17416f7f382600ae/40a76/hero.png 1360w,\n/static/03c69b7b1f3f10ef17416f7f382600ae/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-02-reciprocal-rank-fusion-hybrid-search/index.md","relativeDirectory":"2026-09-02-reciprocal-rank-fusion-hybrid-search","ext":".md","sourceInstanceName":"blog"},{"id":"573c69b7-2da2-533a-8f71-9df921c91777","children":[{"__typename":"MarkdownRemark","id":"497a162a-2256-5037-bff9-faf0d26e093f","fields":{"slug":"/2026-09-03-opensearch-ism-index-lifecycle/"},"frontmatter":{"title":"OpenSearch ISM: Automate Index Rollover","date":"2026-09-03T00:00:00.000Z","description":"Log indexes grow until a data node runs out of disk. How OpenSearch ISM rolls indexes over by size, ages them through hot and warm, then deletes on schedule.","tags":["OpenSearch","Observability","DevOps","Kubernetes","Reliability"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB80lEQVQoz02RW4/aMBCF80ZCnItzsePEsXMn5AYhYaEUVNFu0Wpb2lV3H6qV+tj/1J9bA9Wq0qejM2MfzViWvGBPgr1QPzx0y6em+9b1T1Xzdbn6UXXndvm9H5/r7jxvvjTduR+eRYfQwy0lKWagGL6se8AO8+auaDfNah+XQ7nYzdpt0YjyMOu2WbUu2q3w8+V7zWYiMjUDSYUMWLHhFJqVAgFMVTPWnUQwNbkK+VUj1YqAUMhV6wpkAkkxAtfritnngG4wWTtoZTkLXoxlt0e0xqy1/RLi3PJyoQITZaoZ3pAU3YdOPS9/ZtkjZRvLbS23gbgwUXoJeLnhii3iNww3nRp0agRCRZiI8HH3pyp/U3oMw5MffLDJjEQLzBqPtSTq8EUXHm8J7wwnVk0KIBN5SdE8aNd59iuJXhL+kievjD7SdKjHh/nqVA2nengo+083X/b3AIa2m7Bs1K1QkjUEnSZLXzk/e96e+vfY22G+wHwZpGsBiYcgW3tRH2R3JFqJybqbYH820Yg0UV2bVCw5+uwdYRvCtoRv/Hgk8egnozB+PJArt9IO6hhHO5pmiEkyQLr4Nx1NgCu2kIGrGkSDdKIiWcMTgAAUL6TCyADLKgI2D3H0MckjN7yE5dvBm9HQP69dmopQDf9/R9UwMgnQ8F/xRFB8eplDiQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/0e6d058ccf250e8146224cb217027f5b/40a76/hero.png","srcSet":"/static/0e6d058ccf250e8146224cb217027f5b/c972b/hero.png 340w,\n/static/0e6d058ccf250e8146224cb217027f5b/27625/hero.png 680w,\n/static/0e6d058ccf250e8146224cb217027f5b/40a76/hero.png 1360w,\n/static/0e6d058ccf250e8146224cb217027f5b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-03-opensearch-ism-index-lifecycle/index.md","relativeDirectory":"2026-09-03-opensearch-ism-index-lifecycle","ext":".md","sourceInstanceName":"blog"},{"id":"73831753-11f5-5577-b773-da60341f9f34","children":[{"__typename":"MarkdownRemark","id":"7350b3d1-3f0a-518b-b0f4-a13039e927bb","fields":{"slug":"/2026-09-04-idempotency-keys-fastapi-safe-retries/"},"frontmatter":{"title":"Idempotency Keys: Safe API Retries in FastAPI","date":"2026-09-04T00:00:00.000Z","description":"A network retry can submit the same request twice. How idempotency keys in FastAPI make POST endpoints safe to retry without duplicate side effects.","tags":["FastAPI","Backend","Reliability","API","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACBElEQVQozyWQSW/bMBCFdUmT2BIXkZS4aCO1UJvlJXEqK3Z7CZqgKBrk0FP///8onQIPgzcDfngz9Nr82clmi1OdzMfx9fvx43z4vex/zdPPy8P75fH9ZflzaF+a9OTetNnzf8TJu4XyCxBrWiBeu8r1pp6WcvjqatE9VtNcTadmt8R69CPtx2ZFshvIb6C4hcoDxATEAFriuI6SHkW1H+qriAahjomluOasy+U2V7tcbZ2PiGXM+jj3AK0wb1HsZHU7s2SEkcWiA1EdkiqnY8IGmx531WWqzl32ZMQ+pYOivY8zL6AlURuWToi3zmDeEzVG2dbBKDQpHbUD5LHgDzY/p2yqslnxSYR2jVIHG+hCeOu7zV0gq1yLuPWpwaSUoWVAR9BMyfIx/R3EPIinQRxd+BolnjvYLUzUAFkZpRscN0S0VA1XODQOplATUAhq++bs4Ev59q181Wy7gtJzH6PKp7Q7i8i8maYT+pBUP3RDmYahVp8wCwzpO3zZctVleMjIIEl7hQOi3cGxPpi0v5T9Ju/H1O5VRZiBuJC4IUERoVKOkzjuRd67LUKQx7haA+kBZgJWhdw23cnY2faLLHYrWrshxkVGhxhWJt2P/aWrT2N/TqNBIqtItwLcuwdyjdQKqjsg74C4BeIeqjV0E7kCgqAi/BQKMgQyV50nSCOU3fnRPyWKUHOhjkAHAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/2f02f9ab751572adeacc0c1abc490f53/40a76/hero.png","srcSet":"/static/2f02f9ab751572adeacc0c1abc490f53/c972b/hero.png 340w,\n/static/2f02f9ab751572adeacc0c1abc490f53/27625/hero.png 680w,\n/static/2f02f9ab751572adeacc0c1abc490f53/40a76/hero.png 1360w,\n/static/2f02f9ab751572adeacc0c1abc490f53/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-04-idempotency-keys-fastapi-safe-retries/index.md","relativeDirectory":"2026-09-04-idempotency-keys-fastapi-safe-retries","ext":".md","sourceInstanceName":"blog"},{"id":"81688d77-a7eb-5237-b8f5-d227792dc856","children":[{"__typename":"MarkdownRemark","id":"4eb7370e-f70d-59d2-8466-2debeb48fdcb","fields":{"slug":"/2026-08-31-continuous-batching-llm-serving/"},"frontmatter":{"title":"How Continuous Batching Speeds Up LLM Serving","date":"2026-08-31T00:00:00.000Z","description":"A naive LLM server holds finished slots idle until the slowest request in the batch drains. Continuous batching refills them every step. How it works.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB80lEQVQozz2QWW+jMBSFeZnOJBAWgzEYzGawzRoITZu0TZqlM9K8jDTz2v//P+Y2lSp9ujqWfHyPj9YkXZv0QB23x+l4ub/AfFkfrg/X8/ZyWB8v2+v5/nKaT6+b02k+77snFTdwH4zancXurPibGRmY581OTce83fFuX29eQfP2SY3HangW6wPManjh/ZOOC7AAmuEkKze3cYkCYXnc9LiFSx1l3y22sNKlcwNlSyf7nDrKV5jrbm6gTNNtZuHKizov7hBtbqIngUrjPmV9wvrAl4EvKJFARBTwKRxcaUsrNtzCcDk8qaMPAQjazMVmKqYh6Qsn5y6P7CxyCmpnofUBQwUlAsyR6ZWWL5ywdmlr+sIN6iHur6H8zcf33dsfOZ+pmmgTp2Mz/+y3v5r5jcZDiEttaVL4pAXZ8k1UPthEWkTyQF0j9U/dv0+Hv2o+hUL60qVdUD4wuafVzqcdBfPCDFduYROF2YDZGvZDitQXPS47XL6y7jFUI5ElrmKvyoliWGDIjHjoV9piFRgoBwMKGygMIkAQ5lXULSMsGJYZqauwHbOppm1BVOZLIPGqj9iLFYHCVl51q6oETCwSIjv+OMrn9Y1e7FW+FWxUyQTU2aaKBgLmH4YPnelO8sXSYSZKkZs6KAEQ6BuOk3wBR92O/wOC1lN8rolhEwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/3113e5e31d17506d62c29098723d1894/40a76/hero.png","srcSet":"/static/3113e5e31d17506d62c29098723d1894/c972b/hero.png 340w,\n/static/3113e5e31d17506d62c29098723d1894/27625/hero.png 680w,\n/static/3113e5e31d17506d62c29098723d1894/40a76/hero.png 1360w,\n/static/3113e5e31d17506d62c29098723d1894/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-31-continuous-batching-llm-serving/index.md","relativeDirectory":"2026-08-31-continuous-batching-llm-serving","ext":".md","sourceInstanceName":"blog"},{"id":"1e8e8717-95fc-533c-a108-9cfbbfe3f1e0","children":[{"__typename":"MarkdownRemark","id":"6d99677f-e8e4-5f96-8abd-559f92d363f6","fields":{"slug":"/2026-09-01-metadata-filtering-rag-vector-search/"},"frontmatter":{"title":"Metadata Filtering in RAG Vector Search","date":"2026-09-01T00:00:00.000Z","description":"Post-filtering vector search silently drops good results. Here is pre-filter vs filtered ANN for RAG, why filtered HNSW is hard, and how to choose.","tags":["AI","RAG","VectorSearch","Postgres","OpenSearch"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB30lEQVQoz02O666iMBRG+XMUW0oLlEuh5X4TFQV1xOPxGOPMZN7/iWaryWSSRfPt9lu0mlEPBGgGVPb+cKluf4qv38l0B2LgdE/Pj/q1CQFWsb/iagsKiBo2JYBIaFpJVozb4dZ2U92eVuvLcv3ZdFOznNbb66r/grHtzkm6o1aKydPSsB0TJ3OiJVcrJ1lZoiW8QHaC3Aw7GYaek8G4YDG2EygE7Z6JGiwYNUQl5bnIDkFxdI4XkR9lcQrzozNMbnMM4jHIDlxuqF9bfsPLHe9/ML+mXoWZesqIScOKMZOIJxDsoLb9ing5thQ0CFzCFNQwi007M1j8VF6AHGErhqcyr3LiFQ1q5leWX9mqs0QDGY4IzzBXBo9pWNAgx84zg6ghU8BtxC1d2cly5FEn0q1IelEMnloDpluZQUmLJuj3+fWeTle7WZO4fMoLUwCYiAUL55tRN8UMe3Pk6t1W9xIdefB3bEX0/El/Psj3t3m7sV8PUncLEmjwoRfYluk4RWEViSoMynA1hllHaQQFw5Fmt2G70T2d+OFI+x1J67fsv8E0VKIOo0apZSRbKSolW+rEOnYRCw1PmUHq5i1Pa8jYVaBouuH9Y4Zd4APxGXI/8JP5f6c69mYLDrwzrH8BI7BHFvWFfcIAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/1547a1eef22b6c181246160d46518c3d/40a76/hero.png","srcSet":"/static/1547a1eef22b6c181246160d46518c3d/c972b/hero.png 340w,\n/static/1547a1eef22b6c181246160d46518c3d/27625/hero.png 680w,\n/static/1547a1eef22b6c181246160d46518c3d/40a76/hero.png 1360w,\n/static/1547a1eef22b6c181246160d46518c3d/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-09-01-metadata-filtering-rag-vector-search/index.md","relativeDirectory":"2026-09-01-metadata-filtering-rag-vector-search","ext":".md","sourceInstanceName":"blog"},{"id":"83b4db9e-ea32-5c2e-8b73-4d8f0d291dbd","children":[{"__typename":"MarkdownRemark","id":"e799f4e1-c88c-58fc-90d3-aa3a9d528733","fields":{"slug":"/2026-08-29-circuit-breaker-llm-api-calls/"},"frontmatter":{"title":"Circuit Breakers for LLM API Calls","date":"2026-08-29T00:00:00.000Z","description":"When an LLM provider degrades, retries make it worse. A practical guide to adding a circuit breaker in Python: the three states, tuning, and failure modes.","tags":["LLM","FastAPI","Python","Reliability","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABwklEQVQoz12Qa2+bMBSG+VA1gDE2NxuMsWkIxJARwnKBNd32odqXqept+/+/ZYYom1bpkXWO/T7Hso1cPmikOJ+Ob+Pw67B/Oeyfh9Pb8fDa756G03u3/TlvvtyPv3WtkxdFY5iIXSg2g+ofyk/juruvd+eyHXO1r/vzajM0/df19kt7+L6sjwuX/VUMx5OOJxxfAk/YKLOxuBRBVHO+R345tTizULaATJ9Cf85PSAPg7ArXIRMLE3GARc7Hdv2DRBsb85Cobf2Uys4jpTWd6jsmxZin8guUFDJZ0UAAnN6AkNKuXT87WPhRVeTfAloGZAlgAlEKtY+4geN1Vg3LzTnItllSNrIuM4WDvFw+9vW71qCXW4jdOAS5iWL5rmp3RSNDLadaVrwaZX0Os86LK5I1IVdx2qrVo4Vi22VBpNxAwuDOx1zL/WrT3VUiTIGbzm+ev0SvFkwWgNyCyIacUAX9zHRiE1I9Ql/uoCT0Uh+zEDPPY5abGBaklkMtOIV0j0iJk4YXp0I9YKr8pNHTpwyMNYsr5twal90rFEdVJHZx/pkt91T0AWsBSi1IZv8jhumQ/4kWILq1Q40uTM3HwD/+AE3HRJtRV0csAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/0df538f83ed1b79f46a4c41b7c7bb925/40a76/hero.png","srcSet":"/static/0df538f83ed1b79f46a4c41b7c7bb925/c972b/hero.png 340w,\n/static/0df538f83ed1b79f46a4c41b7c7bb925/27625/hero.png 680w,\n/static/0df538f83ed1b79f46a4c41b7c7bb925/40a76/hero.png 1360w,\n/static/0df538f83ed1b79f46a4c41b7c7bb925/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-29-circuit-breaker-llm-api-calls/index.md","relativeDirectory":"2026-08-29-circuit-breaker-llm-api-calls","ext":".md","sourceInstanceName":"blog"},{"id":"189c736f-8066-5933-a0ef-59428d0e118b","children":[{"__typename":"MarkdownRemark","id":"9f12d0f7-13dc-557e-8a4c-b51c0ba975ce","fields":{"slug":"/2026-08-30-prompt-caching-claude-api/"},"frontmatter":{"title":"Prompt Caching with the Claude API","date":"2026-08-30T00:00:00.000Z","description":"Prompt caching reuses a stable prompt prefix to cut Claude API cost and latency. How breakpoints, TTLs, and cache reads work, and what quietly breaks a hit.","tags":["AI","LLM","Claude","FastAPI","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABw0lEQVQoz1WP6XKjMBCE+RMbEBK3bonLgMGOTRInqayvXb//Q+1gJ1u11FeqVk83U3KGTo+dHlq1Hezt8vb1sbn82v8+Teev3eW4Px9Bv4ADVxCnuwnJoZ1bzoIUS1I+BRbnfb+71sNxPf1Zbc/1eOq219X20j1fWxCb8zDdms0JBKHrJ2yh5QSJAfzIkLzx49INjRcaOFEMpgYfxF1/mwBOiyCeWw6axwVTtSo6U7Y513FmmNAusTB+pFFkSWrSXIW0r4Z3075ldgqS0vFDyBkuzeeO3j7z6zvdDfx6YEmuXKJRrO/7Z/ZrLnUR8U0qh5j1sBXKyiMqzvSm59PIxo4dnikwDZQk0Ff3gITTGn7YZiRiCyQ8wsFxfCJdLDOqqoJbywvLq4KVlvc1fRlzFAoIRan1Q2nUbL6OOY7l/DsiHY8IF4so1VoJJX9QQgjZNbI2kmVVo/ssMYJL+NpKFlbAi/xQOB7my0AUmsfcBnaFZY15FajaC4QfzQtRKBeYS1qqvPRCeIWBfbAWilBmKORK24SZUFSJbjKzwpl2EYUR4GLmE6FEA+BIusG3DzhwARaILhF1UQ7cBX34/1g+Av+bfwHdJ0MNNm91MgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/ee39d6bd9f6285aa6710ac73b9b54026/40a76/hero.png","srcSet":"/static/ee39d6bd9f6285aa6710ac73b9b54026/c972b/hero.png 340w,\n/static/ee39d6bd9f6285aa6710ac73b9b54026/27625/hero.png 680w,\n/static/ee39d6bd9f6285aa6710ac73b9b54026/40a76/hero.png 1360w,\n/static/ee39d6bd9f6285aa6710ac73b9b54026/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-30-prompt-caching-claude-api/index.md","relativeDirectory":"2026-08-30-prompt-caching-claude-api","ext":".md","sourceInstanceName":"blog"},{"id":"3cc9aa54-7823-52f4-9969-9d8b3c7cf22d","children":[{"__typename":"MarkdownRemark","id":"d4433ab1-072d-5165-a119-cb01ae7969fa","fields":{"slug":"/2026-08-26-scheduling-gpu-pods-kubernetes/"},"frontmatter":{"title":"Scheduling GPU Pods on Kubernetes","date":"2026-08-26T00:00:00.000Z","description":"A GPU node won't run your Pods until a device plugin advertises it. How Kubernetes discovers GPUs, how to share one across Pods, and where scheduling breaks.","tags":["Kubernetes","GPU","DevOps","MLOps","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/ElEQVQoz1WRW2/TMBiGc8O6tIkTO/EhB9s5nxdtpOvUNkVsaLTbaNguEHAD//9f4G5wgfTo1SPre2V9tgbFWmEFKy//WC2npH8o3h/bmxcl2eVTc/MSdftyOIr2vhwmmn5Qk5Cv39DmwNdNz0TCl23dr4t2pbIfdkWzzOqhaK/zZtldjWl1rdKXnY2TuRUsXtEMJ0F+RXkLWbVAieHEhpNatLFZa3udRWrodYZbLGwxt7npRMCNDSQWUCE1ixZRsy37OxJ24DR6oQry8me8/B1dfg/7H9HwC0ebuRXqlpgBcWZyJXNLLGyuATex/SuUfTGdGIk1Lp6AEyG5c9K92sVJ7lB8azoJdLlH1W445sSjjusyHagyKXF2wOlnN1Hcq3T+F5w9WP5ACA3J2ZAvbnszxO9ChnQQagCXXvUi22ecf2WletVnN5v8alLipEdeT0H7jcpVzFlA5tedvxtkygHDUAfBqRw2k6wPtDgG9aNsDqRQnUdRn0SlaCcUrgjGuQB16rYZrmIYUDQzfbVzFuZjXG1YsuXFmDQjTUZZjVGlZCvLjSx3tndhQ5pyFIcoCmAhHUbwzGDq5hyKEQQbkt761YGV+6C698o9Kz6z4pPFtxbf2azXTaamZwZ9y3OT6ibV1I8bUBpQnBIp3kSc/N+5+pVzg5wwXzH+8gfzwVSyekC+RgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/c0c1e4720da2467daade0fe540bb7ba0/40a76/hero.png","srcSet":"/static/c0c1e4720da2467daade0fe540bb7ba0/c972b/hero.png 340w,\n/static/c0c1e4720da2467daade0fe540bb7ba0/27625/hero.png 680w,\n/static/c0c1e4720da2467daade0fe540bb7ba0/40a76/hero.png 1360w,\n/static/c0c1e4720da2467daade0fe540bb7ba0/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-26-scheduling-gpu-pods-kubernetes/index.md","relativeDirectory":"2026-08-26-scheduling-gpu-pods-kubernetes","ext":".md","sourceInstanceName":"blog"},{"id":"978f8492-6e33-5715-a205-cf7862632e48","children":[{"__typename":"MarkdownRemark","id":"b135385e-51f1-5bf9-8f8c-93f7662184f9","fields":{"slug":"/2026-08-27-kubernetes-hpa-autoscaling-pods/"},"frontmatter":{"title":"Autoscaling a FastAPI Service with the Kubernetes HPA","date":"2026-08-27T00:00:00.000Z","description":"The Kubernetes HPA scales pods from a metric, but its defaults thrash and lag under real load. How the control loop works, how to tune it, and where it breaks.","tags":["Kubernetes","DevOps","FastAPI","Autoscaling","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3klEQVQoz12R25KiMBCGvVxPEA6aEMI5kICIs4oiBAWdqtld3/+Bthn3aqu+6urq/v9O0pkhuTe+QaLUxQ5Asky6e9aPXA2JusvhmfZj0g1atvsnEOXbMltobLFm8yVFVmxjYdgcYpo3xV7lpRJFK4sWcll05ia1sLCJ1M1ovnLBNVuavrZJdJwZTm5QabHCpPnaTlY2X01xYr3hACISEWEQAWINKnY8WyLPcAoc1Tg8GX5FxNnyK0RLRHcmqwxaAsiZeOff7KGFnHy20BnCEjk7ABo6zrF/9DPlxpcgUzQ8Y35iVcf2reVViEwyRIppIpFgduHCtn+YGmRnuGXUf6WPFx+AP3x84XOPa+V0903VmKTcBj8pv5CohiNhYVTH0vY/gqoPSuVWij9eUXGP9mO0H+LqsU1q06ss/0CaW/j55eUtSU6W9zGZ55qjw5JJicPj1j04BxV/vgLehXkfSAVTSFhrONdJodvSPjSbq4KnIVzok3lN9K1gxxtrn6wZo+FXdHyGog9lH+Y3APwsvXpZ50tFg7PfPKPnb68eYfNgxjDD4Q0THeBmLY0voPZFz9KWJg3lVxdI2zfQnTRZi0g++7HaLhCDD4O1TyAP8rUVGphrdjTV/8Pw3jJw/QUWP1bhWSFUPAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2b103420edc752bcbc021aafeeffcf81/40a76/hero.png","srcSet":"/static/2b103420edc752bcbc021aafeeffcf81/c972b/hero.png 340w,\n/static/2b103420edc752bcbc021aafeeffcf81/27625/hero.png 680w,\n/static/2b103420edc752bcbc021aafeeffcf81/40a76/hero.png 1360w,\n/static/2b103420edc752bcbc021aafeeffcf81/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-27-kubernetes-hpa-autoscaling-pods/index.md","relativeDirectory":"2026-08-27-kubernetes-hpa-autoscaling-pods","ext":".md","sourceInstanceName":"blog"},{"id":"e7281158-bb3e-53b7-8aff-8a3ea4be3fbe","children":[{"__typename":"MarkdownRemark","id":"0b710961-fda2-5921-ab59-0508a83f2760","fields":{"slug":"/2026-08-28-contextual-retrieval-rag/"},"frontmatter":{"title":"Contextual Retrieval for RAG, Step by Step","date":"2026-08-28T00:00:00.000Z","description":"Vector search misses chunks that lost their document context. Contextual Retrieval prepends a short LLM-written summary to each chunk before you embed it.","tags":["AI","LLM","RAG","Embeddings","Search"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+0lEQVQoz02Q24+aQBTGeXOBAWaAAYbhIvdRUawXUNHV7ibNZhvttunFl762//9/0KP70uSXLyeT75vz5Uim6EnVW6N9ub8U+0t1+JJ0r+Lxa9Ff8t0ZKHrgApR3ffeDApKqc0XzdTMuxLqeH+r5PquW5agtxaoU62K0LsdtLpblpBPT7Wi2M6wY/JACJNWMVTNCVqySSMahgiPiCRo3zvADYPGahlPChEIiADzIHIL/TiypOPyPAJEoyDfTjz+mz9f6+ZrVj2L9EtZHBVa9e+5f3MChpOBAvaMYNxC0INFA57Kdyk6h0Ow2QzsrgV4PmicjV9GYrDEwS4ruy7oPqhgcgPBt0BiiGZ0ceXcO999Y+9mdnrzm2W9frfGB5J0xXEBEMmhC3EK3E/meN2gKlRSdIa+qnn41L7/Xb39Xb3/GT9e4O2eH76y9eP1POv8ECyQ7qCPRB8WGFx3PN0G5MfnUcCvVTrnYB9WOl9ug3Iaid9KVwSaEz6x4gaO5bPgSjWbJ5BiPD36xcYYLN1laYYNdodpJVJ+SyWlYn7ys89LWSVYkaEwADGEj60wiZmQ7GXUzi6a2k5o0UQlclcsG03llxmMSjnAgQGHW3BxugZxctYcyciSkuQZmOvYx8QnhBvYHKn1AgCPrjmb6CDNEGDJ9mOF9oNg3bh7nHzaWUIthr2VSAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/4ec5f89f4346f411a76181b4e06109fe/40a76/hero.png","srcSet":"/static/4ec5f89f4346f411a76181b4e06109fe/c972b/hero.png 340w,\n/static/4ec5f89f4346f411a76181b4e06109fe/27625/hero.png 680w,\n/static/4ec5f89f4346f411a76181b4e06109fe/40a76/hero.png 1360w,\n/static/4ec5f89f4346f411a76181b4e06109fe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-28-contextual-retrieval-rag/index.md","relativeDirectory":"2026-08-28-contextual-retrieval-rag","ext":".md","sourceInstanceName":"blog"},{"id":"c56ccf89-e00a-5a6d-a30e-0498bb5bd62b","children":[{"__typename":"MarkdownRemark","id":"598c7a08-cfca-5d83-8f47-5328a549f524","fields":{"slug":"/2026-08-25-speculative-decoding-faster-llm-inference/"},"frontmatter":{"title":"Speculative Decoding: Faster LLM Inference","date":"2026-08-25T00:00:00.000Z","description":"Speculative decoding uses a small draft model to guess tokens a big model verifies in one parallel pass, cutting LLM latency with no change to output.","tags":["AI","LLM","GPU","Inference","Performance"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACO0lEQVQoz02QS2sTURiGx6TJZDJzbjOTyZxL5pqZXG1unaTmWopFi8HeEKFgXZSC4mXjQlBw47ZLf4Au/QEuRFy5EsSlO/+Lp7oRnsX7fbzP4eMoTX8maXjTdriYj+6uxkfLrcMbvTtXOTv6Ox5MB+udyfG0v5bjYuugEy1lX1qKipiKeBFSTOuNwbwzWjX7s7CVJde35djozeLupN7dlksZ2sNla7iweFoAVFqKQTzD9CXACnTsGdiHdgytEFoRtP8RGkQWApmBFepX2b/aEF/RcU2DvASYjoXM13SiWrxk8pIlYDUynAC7dRVR000IrZs0QXaoIS7vLWOhlJGwWcqDrjRVSB/OXtwfP1m2T/b7Z81gMW6sGevH4ZTY9ePe+SxZF4CDzVC4m4gEUuYs6MbNDNnBhuF8ufj58ezrh9NPny9+XB6+//b418tbl9+f/a57k9e7l6fZ0zysCL7ZjVeWkyplyFSjWtQd+YoGaddfpGKSiHHHm0ds1AtXPu1n8R7EHnPatpVokOlEfnBVx1yRArA8VAk1QGXOGWYO2HnM8sgtEVHAXDO9AhGAePNk3fFmRcPREYeWryGmaMCtiKaI+lj6iD3aeXO+fJVGq15jX9RGUTR3eJ/6me2kb/fePcie53TTpmnUmkhfytWSIXHKkKqgerNzb9U+zBq3dzonvhi0o0XFbdVqA2wHw3A3pkMVONDyJAbhitT+RylqeQ1uADsHTA3RIqzomGnINYjI6SRfJrKj6pV//AHvI13EQ+DzCAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/d9b4468e96fefd425a311dd41e3dc69b/40a76/hero.png","srcSet":"/static/d9b4468e96fefd425a311dd41e3dc69b/c972b/hero.png 340w,\n/static/d9b4468e96fefd425a311dd41e3dc69b/27625/hero.png 680w,\n/static/d9b4468e96fefd425a311dd41e3dc69b/40a76/hero.png 1360w,\n/static/d9b4468e96fefd425a311dd41e3dc69b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-25-speculative-decoding-faster-llm-inference/index.md","relativeDirectory":"2026-08-25-speculative-decoding-faster-llm-inference","ext":".md","sourceInstanceName":"blog"},{"id":"d9593dd5-35f9-59a3-8570-d0c95b9ad902","children":[{"__typename":"MarkdownRemark","id":"56bf8cc2-1a85-516d-90e4-0e4420034e09","fields":{"slug":"/2026-08-23-opentelemetry-tracing-rag-pipeline/"},"frontmatter":{"title":"Tracing a RAG Pipeline with OpenTelemetry","date":"2026-08-23T00:00:00.000Z","description":"Trace a RAG pipeline with OpenTelemetry: instrument FastAPI, put each retrieval and model step in its own span, and read the latency waterfall in OpenSearch.","tags":["OpenTelemetry","Observability","RAG","FastAPI","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB7ElEQVQoz22Qu47TQBSGvUGbxI49Hl8ytrOJPZ5x7NhOsL1xks1lQ3DYikueYBugWdHR0dHwGhR0iIfgTRASoqDmBTgOiAWB9Onon3/m1zlzhNTjQOyyTTbdFuVlMdvPV6tJvi1mQDVf7srFZV5Ws+X92cU6O09c9jMCCE3VPUUDSWdutODjdVTskmnlJ6tgsgmzLUDjCz9djYodaG+0aGu0iQYt1QUERfcAZPiKQWXd62guIOu0FrdHT8IDRXd1wgzCVNMHR9ZcAZkMk1AlwZGhah0ht+C6BqjL72DeMGPBGCEnUbtMUvuCDD27/DfoH8BUCW/p/Ply/LqavLm6O2ZhU6OdY5j+Gf4vmHABs4/X0y83+feX5aFIBUQVfFaHERmierC/gIGPgsMVJkFD4+8O6bcX+debfJ9EJ4jKqFeHYfIOVJMhAk+H0Aq0BNsy/aP24YcNjb19GH5+Fn16GlXx8ESlHWQLsNh+uKTJFvrQ5F5ZXTus1HtpPHt0FizAtLzcdictI3i15h+eBO8fByUPTjGVFEuQcJ+Pt6NiDyvt82l8/oAMJioJw3xvezmsOsp2PN0gbZCx8DCfXmVZ33JbMqnDomKJyBFVR0S2qDgSctqKXTu/sCXUE1GvLVsatk3dMTRHRhaE2zL5ASInVm+4pGA3AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/b6acffc732f92430e93409753d062d6e/40a76/hero.png","srcSet":"/static/b6acffc732f92430e93409753d062d6e/c972b/hero.png 340w,\n/static/b6acffc732f92430e93409753d062d6e/27625/hero.png 680w,\n/static/b6acffc732f92430e93409753d062d6e/40a76/hero.png 1360w,\n/static/b6acffc732f92430e93409753d062d6e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-23-opentelemetry-tracing-rag-pipeline/index.md","relativeDirectory":"2026-08-23-opentelemetry-tracing-rag-pipeline","ext":".md","sourceInstanceName":"blog"},{"id":"93435464-9574-5e92-8589-c2025c6ad518","children":[{"__typename":"MarkdownRemark","id":"83ffe5cb-d954-5205-a36e-71976d964dea","fields":{"slug":"/2026-08-24-prefill-vs-decode-llm-inference/"},"frontmatter":{"title":"Prefill vs Decode: Two Phases of LLM Inference","date":"2026-08-24T00:00:00.000Z","description":"The first token is slow, the rest stream fast. Why LLM inference splits into a compute-bound prefill and a memory-bound decode, and what it costs you.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB5ElEQVQozz2RSY/TQBBGfUq8b+3eu+0sozi24yX2BMwkGTEoQsxhGAbBAXHl//8GyglCerK+qurncssGkycuT1Qcs+XTcPjZ9d+r5qU//Gj7t7J+afbfoGz3b3X3+j/I9JGJI1iGFQo7lFYgiN5u24e8+ZDX464/F90RMjw39VgN5ym3Ryir/oxVbgYcLMOJ0iuZhxYQ7HAqrVBDuGEFygyk6Qtg5tGZx5xYO5GCY4YTasAFP9Rzl9/KK+n1i7gf3wVow2TP9SCzUabvwySHJpwx7EABkJgu0nXjRqBNHdOnbrTg8qz0Raqn5epZpZe2/T2OfxiHO5/sYJIlCCFZqWW33Z3Vsmd6B52EDuu7VyYe4mQHhKikYtiUH5v+CyyPcQmiYfvCCWRE116UzV1m+RSRZrF4zrLPhO0RrhPSIdyipJFqFHLkYlR6eiOIhuVzOxARWZke4apPFxchP1F2T0XHxD2X75gY4qQGgqgI4zJCVRRXISpANCyPAbbPiThU5a9t/hU2aH1S+oRJBxvQ1cS41ek5zR4pGxBuoqS0vEmmlkdAjnHh+MKL0jBZE1kxtcO8uJHwgsoK0TxAKz9ewgVd+IUeNUyX3JjZaO6SuYNnTjJ3MfBv5GG4kTmNkmnk4Inr9C98Qksg9Y7QMwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/40a76/hero.png","srcSet":"/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/c972b/hero.png 340w,\n/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/27625/hero.png 680w,\n/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/40a76/hero.png 1360w,\n/static/56d22ee8a29b5bcb2d0a497a6c2abc7e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-24-prefill-vs-decode-llm-inference/index.md","relativeDirectory":"2026-08-24-prefill-vs-decode-llm-inference","ext":".md","sourceInstanceName":"blog"},{"id":"26da22e0-7836-5892-8853-ac4d9a228c3b","children":[{"__typename":"MarkdownRemark","id":"10f7249b-435c-594b-8e67-c004b1f1808e","fields":{"slug":"/2026-08-20-llm-as-a-judge-rag-answers/"},"frontmatter":{"title":"LLM-as-a-Judge: Scoring RAG Answer Quality","date":"2026-08-20T00:00:00.000Z","description":"Retrieval metrics say the right docs came back, not that the answer is right. Build an LLM-as-a-judge to score RAG answers for faithfulness and quality.","tags":["AI","LLM","RAG","Evaluation","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACD0lEQVQozy2P2Y7TQBBF/QCTjNf20m67N6+dOF46sZNJHGfxMEiARgLxwDMS//8T9DBIR6Vbt+qqVNq6xNOpna/9862/T9tP90G190nOl91tktexu53l87W/jN3l1CoxX3eDLCtB6hXVPpjMi2sujnX/uWhum/6laK4r+bySs+jmfHMp21vVv6gqunvdv+TV2cf1g8UXdqpZfqK7TAfUcLnpJTpQmhlvzhumyw01cqiqj4AtHbawyNKmOlDLXENJT8sxzp5c3Hqks4JcJSFt4nQXp1uUdHaQWzAz/MSHNMIEohjFBEbMBEzzs120PSN5hpsnl3U2KnWXhlxScVQETAJUB3lv43WW0GLd7E+XYrPNyxQEVPPzXbifwuGs8IqtHRa6S0LW8dWRFHuFFzde2tlYcM5fZ/7rS/L7OxGr1PGJ5vEOisM7SltBpgPskybK9ijto2xwcQNSacWCMfbjW/r6Nfnzk3ab1Hax5qvH5Ii6EbZHN5EWzFUYs6YQh7wcSnEgpKWZ9OIy4YSPJzJf+sPUitLyIs2L2wBLhR936j3HSwOA94W81cdr9XQSQ5u0U9lXsSCcVJVYr1eiWheluhxphs/xMNLDOdgenLTSTbS0UBBwHpc0Knhc+B51ADbsyALI9UPgKaDjokcLaUsrNCAzIddD/giipQGXZvhgwI8GfPiPakNlLt589M7in/MXpRdTQrGmqsQAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/7084089adaa1a7af370ff3e404bd44b4/40a76/hero.png","srcSet":"/static/7084089adaa1a7af370ff3e404bd44b4/c972b/hero.png 340w,\n/static/7084089adaa1a7af370ff3e404bd44b4/27625/hero.png 680w,\n/static/7084089adaa1a7af370ff3e404bd44b4/40a76/hero.png 1360w,\n/static/7084089adaa1a7af370ff3e404bd44b4/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-20-llm-as-a-judge-rag-answers/index.md","relativeDirectory":"2026-08-20-llm-as-a-judge-rag-answers","ext":".md","sourceInstanceName":"blog"},{"id":"2ff98729-dc36-5972-96db-4bec8cb04ae4","children":[{"__typename":"MarkdownRemark","id":"0dc5a4ff-341a-538c-a18a-51a728109d4b","fields":{"slug":"/2026-08-21-prompt-injection-defense-rag/"},"frontmatter":{"title":"Prompt Injection Defense for RAG Systems","date":"2026-08-21T00:00:00.000Z","description":"Retrieved documents are untrusted input. A practical guide to defending a RAG copilot against direct and indirect prompt injection, and why filters alone fail.","tags":["AI","LLM","RAG","Security","Prompt Injection"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQoz02P+26bMBSHkaYtTUhCAhgCvmBsYwjYXAxJ2oY0S/vH3mDv/yhzN02b9NOnc9Gno+M0RNdYDcI8xsetf3tM72/D/eP8YYu7uVt+Hx/Xbrb8M7kP399PHy3rreUsPPxlA58CmutX3s20ec7Vq+hulbnz9iraWXQz01fZ32Q3l/2b7G6yn92Aft0ix90TABiOOAoZjAU8SJTINBbAp1GQh2EehCwEbL0nqx1eemi1Q8stdHfYThy7vsnzSPspNzUzXXnuy5OpLjXRXT4YMY1iepbniSrXzzzAtkG+CbKNT90dcaIw7/gYJHWZ9z0fENZpchRZ15aXSowINRipDKsLVftYAqT9Q+lFwgP8UwYh7fmYQPVDvfyc7r0wGe0x6SDWEDY26WdUQ9Q+KgCsrRwk5RYwd4ccEGRWjmBTF6ORE+VdISdRTExMELfJX3mg7erz4cwetA8v1slymzhhQAY+xskxJdreh0ilRCFUE1RT3NBMZaQhRMusQBAzyvOMYUQtPR86oY81MyHSkA0RUQCrGKmEmwhrkOkY1of0CHFTUlEJduqbqa0rWdAs9/zUyuhavZTlS1vPsryUx/ORn3Q9V8VF1M8VMyXtj7kxtF240XITL9ex5bdV9LSOndUm5gfBYp7H3JLb/G7/1QdRJEXk44ULntbR//kFE0FZNhTam00AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/4ee9029b7de0dd2bab142f433a952db9/40a76/hero.png","srcSet":"/static/4ee9029b7de0dd2bab142f433a952db9/c972b/hero.png 340w,\n/static/4ee9029b7de0dd2bab142f433a952db9/27625/hero.png 680w,\n/static/4ee9029b7de0dd2bab142f433a952db9/40a76/hero.png 1360w,\n/static/4ee9029b7de0dd2bab142f433a952db9/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-21-prompt-injection-defense-rag/index.md","relativeDirectory":"2026-08-21-prompt-injection-defense-rag","ext":".md","sourceInstanceName":"blog"},{"id":"eda9c2e9-3228-575a-ac00-5bbaa6893814","children":[{"__typename":"MarkdownRemark","id":"1a790ab4-db00-5bb5-a948-8972ec88add2","fields":{"slug":"/2026-08-22-hyde-hypothetical-document-embeddings-rag/"},"frontmatter":{"title":"HyDE: Hypothetical Document Embeddings for RAG","date":"2026-08-22T00:00:00.000Z","description":"Vector search fails when a short question looks nothing like its answer. HyDE has an LLM draft a fake answer, embeds that, and retrieves against it instead.","tags":["AI","LLM","RAG","Retrieval","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB80lEQVQoz0XRy3KbMBQGYFZtjNAFhAwIjG0wBoQwl0lwsOM4jttML4usOln0/d+jB2fRmW80kn6dAR0ZOO+sbUuLPj29rY/f0qe39eGaPH1fPr4mh2+rcZpnzz8W+xdIl48XUvTWtsM3BsKhaUlHpHV7LutjoUdVH3VzUrtj3Z0LNZZqVPqQF4OqDrDkYgPnEYmAQUXKvAxgsZmxBTDt+P/oZ2aUm0GGomIms5kdW+4a8RVyYmB4yy7bXYr2teyu0WbgUSMWrYg72y9NGmL9QMYr2b/gxwt9ONNqT6qB1CPOOkQjg7ipE5Rclo5fcKl4oG5LRcXmjoSiP3Xvf6uff+rfH82vj+313enPrHsmejSheIaDr2gOviBB3RUTa8xj6i6xE8+IpCsdtk+yPsjdIehP9ra3ksZKWxSXJpHw5YR5+Sc31ERsAHZTy16aOCBpwevWVQ1XO9EPbtWwvGJlTdMCUmOqidrpnovWjXZOqCdSw3Vm2Lezejm8pPtLMlzS4RLfn4S65/qBbTSkn8UNv3HCHQsq4MjqVuxRN3P82vY08ypABPxgaXuKOAmkBrJjeC0/yP1I+WExD3LuZZazRiyCGN6DzbN5pMWi4iH0sgBEJMieUgNadYcEJh5lcmJLTKGF4s6ag88JosGE3DA57VvT/j+Q/U9do1Ac+wAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/90f3785213ffc1873444a0b510a7d3fb/40a76/hero.png","srcSet":"/static/90f3785213ffc1873444a0b510a7d3fb/c972b/hero.png 340w,\n/static/90f3785213ffc1873444a0b510a7d3fb/27625/hero.png 680w,\n/static/90f3785213ffc1873444a0b510a7d3fb/40a76/hero.png 1360w,\n/static/90f3785213ffc1873444a0b510a7d3fb/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-22-hyde-hypothetical-document-embeddings-rag/index.md","relativeDirectory":"2026-08-22-hyde-hypothetical-document-embeddings-rag","ext":".md","sourceInstanceName":"blog"},{"id":"98c87997-da49-5411-9898-d99811801a63","children":[{"__typename":"MarkdownRemark","id":"2700db83-5625-52c5-9c8e-a3d808b301f2","fields":{"slug":"/2026-08-18-product-quantization-vector-search/"},"frontmatter":{"title":"Product Quantization for Vector Search","date":"2026-08-18T00:00:00.000Z","description":"HNSW makes vector search fast, but the embeddings still fill your RAM. Product quantization compresses them ~32x with a small recall hit. Here is how it works.","tags":["AI","RAG","VectorSearch","Embeddings","FAISS"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB9klEQVQozz1Q2W7bMBDUmy1KlERRsg7qMnVbR2w39SH5StLEboIANdrH9lP6713ZQIHBYriYmeWuoOc9KXq92Knphm/e66dfxeHKNx/F/ke8/Ziu36vTT76G5zV4fFPTrV70JB8AREDYRdgBYM2Pkvms6au2T8vVrO3yap2WX8tmm83W9XwfxguVRqCXFBcpUJkg6aFsTLGVWVFr+JXOSmUSSyQQSYBIIJEQaQMRtUCmETamoP8PQXcqVr642cHLjizdqSaXSaAYsWIm+FaBS6qHKVcMjkk4EDOBdEnzBeq2QfPdK569/IllRxlGqQwbXJ2kxM6hQgRSPZlEmteQZK35rWLG4IQmmBu/vrD8aTCne1kfzLI+Nf120X3qzkymMdI8WWHGwyv//Ze9/MF0ejMzgTq1X59ZdvKykwtm2FBxZX1YT3cL+ALw4ZxwFxobfq1aGb4tAjLYGcyX+7fd9CARX1RsM1y6+cFNOpb2wMfYglEOXwTFKixW2iQRFQcgELv0ymeLd07cO3EHkSK2/OKYPF6j5pwsP4GPkKEED/byYs+/2YtXo9wjjYmyJcAcYDz/YrF8jG1xgAWp1EnzZkvtRMSOiCfI5FbVBauzVe/UsAEXyISxPAFoRogJG0nm/QkEYYuYESjuzRGiY0QlGkL6SNTvsn9m7U0QrDp1ngAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/4cc29e9488098aed49e7246f0af47f78/40a76/hero.png","srcSet":"/static/4cc29e9488098aed49e7246f0af47f78/c972b/hero.png 340w,\n/static/4cc29e9488098aed49e7246f0af47f78/27625/hero.png 680w,\n/static/4cc29e9488098aed49e7246f0af47f78/40a76/hero.png 1360w,\n/static/4cc29e9488098aed49e7246f0af47f78/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-18-product-quantization-vector-search/index.md","relativeDirectory":"2026-08-18-product-quantization-vector-search","ext":".md","sourceInstanceName":"blog"},{"id":"7471ff09-34bb-5a52-9174-c0d18c44c479","children":[{"__typename":"MarkdownRemark","id":"a37228c9-b46e-5bd9-ba71-1b923a94d004","fields":{"slug":"/2026-08-19-concurrent-llm-calls-asyncio-gather/"},"frontmatter":{"title":"Fan Out Concurrent LLM Calls with asyncio.gather","date":"2026-08-19T00:00:00.000Z","description":"Awaiting retrieval and LLM calls one by one wastes seconds per request. Here's how to fan them out with asyncio.gather, bound it, and handle partial failures.","tags":["Python","AsyncIO","FastAPI","LLM","RAG"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3UlEQVQozyWR6Y6bMBSF+dVJ2IzNDsY2S8gEJguEkDSTqIumI02lblP1/V+lh0T6ZB0f+9x7DZqSF5Cr67D/dTy+H4bfffdjPPzZ9z+xwgQQx/H9dPyLIyme7xGgzUgCSFDU69Oquyx3z1V7bPpr1Y5tf11uz/X6Y9NdALZlO9p+/mDH95RmUgkspgwnY35BvUJ3sjnJdEdAYDWovGkB03DEdJMKc0JqyABsiF9VRafUFsJ0pcGEecNgqJXqDp8c+Lf7dzSdcN1OLa8gUZMtT1l9grDcXCep4fApQwVvuqhsUYJVDYSXLacU4Qinup1YrmLphlfHtBwhTKZg6iTBRDRpfbnxxYbGjeVh5tSgfEqRVMOluRVRt5LpuRCXUlwVPzushKlbMV7I+LZ6+qRWZyduUUu346nuDW2OT2eFrlsL7/BUvjT5VxGMqDWzIhwZNLOjJU2aMBtCvrdZ/sHw70dAQ4eZGTB3UfPPrXpt5AsEZSVMFLWIWOCXJqdd/X1TvfK0T0TrePnMDBFEOJyZPsJZMHSrt3X9LQsP9Db23I6Ik593/7b126P6UstrEm+9sKJejhTQpg5Tk8iPHmOxjrI1CxbTg6fnRDYTqhjycpB5L1VvOvzBDB7uETP4Dyi0SscBzjsMAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/8562546a0ec941aaf484051b6f70cfca/40a76/hero.png","srcSet":"/static/8562546a0ec941aaf484051b6f70cfca/c972b/hero.png 340w,\n/static/8562546a0ec941aaf484051b6f70cfca/27625/hero.png 680w,\n/static/8562546a0ec941aaf484051b6f70cfca/40a76/hero.png 1360w,\n/static/8562546a0ec941aaf484051b6f70cfca/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-19-concurrent-llm-calls-asyncio-gather/index.md","relativeDirectory":"2026-08-19-concurrent-llm-calls-asyncio-gather","ext":".md","sourceInstanceName":"blog"},{"id":"273c2501-fdde-5107-b1c4-560b89840b19","children":[{"__typename":"MarkdownRemark","id":"620934ee-c307-5bb1-81c5-8f0f20e23850","fields":{"slug":"/2026-08-15-grouped-query-attention-kv-cache/"},"frontmatter":{"title":"How Grouped-Query Attention Shrinks the KV Cache","date":"2026-08-15T00:00:00.000Z","description":"Grouped-query attention shares key/value heads across query heads to cut the KV cache. How GQA sits between MHA and MQA, with the memory math and code.","tags":["AI","LLM","GPU","Inference","Transformers"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2klEQVQoz22PWY+bMBSFeWjDjlltMBizJSEkEALJdLKRh1E1UqfJTF9aqf//h/RmaCtVqvTp6Pj6nGtZKPlx5Njd3rledt+Om+uh/Trs3s7bt3P/Cma/fjn1t337MmP7vxVBROHEoKrD89Wnqhumzb5sT+XmVNSPQFL2s/Vx0Z2z5QPMs+pBsWMRUWgBgmZz3eaGk4JRzFg1Y1DJCDU7MfEUVNJD1brPZcQUxDSLgwcFBEmnE9UfUU0GyEYYxHVc9CResbwDDxnVYibOEE5NkukOH5NCNu/rbqjWx2V7grOkB5DGUUXxkuHadWZRum6qi4pYvRj61VO3euJxK8I6xATHn/qsItECR6VsUOSmvNgGbtXE5yLcXeavnxffn4cfxC8nClGNSNFDBf1GEDXyUXE/yI6oYknzLS936bwgmyTcTsLiUF6H6Y0nbcwb/f5nKhsBoBgUEJJwU/L9MjkZNpd03/RSGtccNwt2oFFbskfqlCSu4OUvzU/qVxK6N8cVAnK44+W2l5tuoiIqaZilLXIS7tUzvwe1vCxK1rLuk6gK4pUTTMGPCJAWVe+OhmWdyBpWUMCyNoiWyE1AwcsGRIkEt/8C5fv0j+L3XVjUPJvkHp1bOB33Sv/jF5dTSoR2B0eaAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/737643482065a12c3b04d10612fdd8ce/40a76/hero.png","srcSet":"/static/737643482065a12c3b04d10612fdd8ce/c972b/hero.png 340w,\n/static/737643482065a12c3b04d10612fdd8ce/27625/hero.png 680w,\n/static/737643482065a12c3b04d10612fdd8ce/40a76/hero.png 1360w,\n/static/737643482065a12c3b04d10612fdd8ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-15-grouped-query-attention-kv-cache/index.md","relativeDirectory":"2026-08-15-grouped-query-attention-kv-cache","ext":".md","sourceInstanceName":"blog"},{"id":"1ab01e9a-039d-5db3-b529-821b2545f64a","children":[{"__typename":"MarkdownRemark","id":"fe96d32d-ba38-5767-a5cf-128756298b6f","fields":{"slug":"/2026-08-16-pagedattention-vllm-kv-cache/"},"frontmatter":{"title":"How PagedAttention Powers vLLM's KV Cache","date":"2026-08-16T00:00:00.000Z","description":"A self-hosted LLM server wastes most of its GPU memory to KV cache fragmentation. Here is how PagedAttention in vLLM pages the cache like an OS.","tags":["AI","LLM","GPU","Inference","vLLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACGElEQVQozy2RXW/TMBSGewVN7Dh2bKf5dJLmo02aLF3TtM26rptg0wQb7IKJCyRuds0Nd/wRkPi1nALSK+uRdd5zXvuMWDj8lxqK1QNo1j0W3WO2fA8CSJr7sn9Kz+7j+u4E7TvT3/6zjHTT101PI57Bo/nZMGuGst0Xi21W9gDVcp9Xm/Vwu1hepvN1fX4AIDwCFzL9EWLK4AmmLmYOkSm2IpAhEmCdRRq0ZkozQ52eNCYBnFCAWAjGEaKh8OZp/yXdvNj+3E+3XrZzk5VlJxqymLvATCEzwFZiiNSUKTQlIgXGPIHYAXOr7PA9O/6A8E5xI+MdlNJgo9YvPGipnSEaEFlMknVYHlR5iBZXwMSejTTiiqiTqjXllDkVnWTUmROZhe3n+sPPMRLp/pucXo2ZKvPN8/rm7mz/dftmOu2wLEaa4cioF6ojdiGi3quf7ezo5NeT9II6M+bWzcdfzvwBMX/it8prVDzEfiPc+u9kw6FOCcMhPHWb5um3TK/hbcyrqbPg4Yr7DbYU4aloNuJ45NsrfnmQ3QUR+cmMWWhYMZG5iNZCncuos9SO+iuIg3lM7BwWY4jMqYZk91atjmp5dKsB6kdjbHPVe/mlCFsM2aY73bDt6pOd32Lq2UlvxxvYJSzGchfSa6Rfy6DhsAX4bTAjKzNgOAsMKzCYpxmTMeIAxAp14rxGYowl6DWSr5A4SRfAcPMHPTVTeXIlg6QAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/40a76/hero.png","srcSet":"/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/c972b/hero.png 340w,\n/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/27625/hero.png 680w,\n/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/40a76/hero.png 1360w,\n/static/d3acee5dffc0d4f12d52d2a5d8ed1fef/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-16-pagedattention-vllm-kv-cache/index.md","relativeDirectory":"2026-08-16-pagedattention-vllm-kv-cache","ext":".md","sourceInstanceName":"blog"},{"id":"34c1f520-de56-5bd4-a749-8acc2d2f9a2d","children":[{"__typename":"MarkdownRemark","id":"f9b827c1-d760-5a1a-803f-295eace538ac","fields":{"slug":"/2026-08-17-semantic-caching-llm-apps/"},"frontmatter":{"title":"Build a Semantic Cache for LLM Apps","date":"2026-08-17T00:00:00.000Z","description":"Semantic caching for LLM apps: cache answers by embedding similarity in FastAPI, tune the cutoff, and avoid false cache hits. Working code and failure modes.","tags":["AI","LLM","RAG","FastAPI","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABwElEQVQoz1WN6ZKiQBCE+SdXNyAj2gdnQ3MrA4LgzBhqzPs/05ZjjLsb8UVGVnZWl2Lljdf25e1bfFyyz6s4X+TlniwXMPH8WV6/5dcNctB4/opOn2De6s7OG6doFR1xZId5tchqyeulqM9td83rMwDJ/v3WdNd9fyuajzgbEzllxQk7kYa4gX3FXAe6zVWLGY6v277uPNBsX7U46Aqzp/nJA2MdQFOzfMP2wStRehDFlORDlPWinPyk27FsqOV9bq5Tc5/b26md9vnQZMdGDnW2dOX91HbnDsEyiVs/63n6DoBhotuEFREySiT3BWMxQEhEWQIQmoCHxGOxYXPFjfYkOwJUAiPNRlccUFLgrdDsYGWyFWIq5qYbm+vYcCIYHwliusWUrehYduRyJOmASWGR0gorOy1cmiI3gAZcMGyo0ifgn+iYKm7YeMnBSzpQN2wdXllBicMUb0LD4dDQofda+OcXDRPFiw9wmYqeioGI3iHV47Is11Sgta+h3f+Qx3ewjCmMimaRF6pFdBsedqrhqeYWFIeSjjOfFj7ObFpwXKimp6HtEwWGn+ovL4/Ab3SXmbvowTYE1d/436bp/QEKhUqevXKzkQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/9d14570bff46c536f588658086d0da12/40a76/hero.png","srcSet":"/static/9d14570bff46c536f588658086d0da12/c972b/hero.png 340w,\n/static/9d14570bff46c536f588658086d0da12/27625/hero.png 680w,\n/static/9d14570bff46c536f588658086d0da12/40a76/hero.png 1360w,\n/static/9d14570bff46c536f588658086d0da12/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-17-semantic-caching-llm-apps/index.md","relativeDirectory":"2026-08-17-semantic-caching-llm-apps","ext":".md","sourceInstanceName":"blog"},{"id":"4c93c2c3-fb2c-53b0-81b6-6a2d2ffd773e","children":[{"__typename":"MarkdownRemark","id":"4c3b6c41-28b2-5a2c-a3eb-f416cc17970b","fields":{"slug":"/2026-08-13-zero-downtime-reindexing-opensearch/"},"frontmatter":{"title":"Zero-Downtime Reindexing in OpenSearch","date":"2026-08-13T00:00:00.000Z","description":"Change an OpenSearch mapping without dropping writes or serving stale data. A step-by-step reindex with aliases, the Reindex API, and the failure modes.","tags":["OpenSearch","DevOps","Observability","Search","Elasticsearch"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB9UlEQVQoz03RWYvbMBAHcL80yUa2ZEuyDluWLB+Jc2dzbZLd5uim2y196lMLhX7/j1E5hVL4MQzD/IVgvIkp/2lSc17trtv9x8fNp+3hvN4d56vrZu8m++lilNmxKf7f97pIOx2Y+XEN+VA3+3pxspNjPT9VsxfTPA2XFzcxzT5gQ59WHZS1+/eU50f6LvOxAcQirCNiEDUB1g7mFaQW0TzABhJX75utNnUP49zHNiS5iLWVlouKisoFQJSnxZIkDZGNW2gRG7QKEGkQZh5itRocud0Wg833t28/bu+Hp9dm+2W2e5/u3pv154nrn77moyMSE6IWOJ1jNYdx1Yep5x5AcQlpgVgZpePMjN8WMyqbOBnyZJCbMU+GVNSzzZWpUQ8qEBn3BRBlfZR6D1A+BKLnC4SVtSOuhuuqzllKw2hRqENTNFowFCJeT9fXOBul5RJg0wtkHyYeQBIi5qCQo1AAxBWT10G+1PJ5oA+1fq6zpZG5ULeXy8hWA22tVD4UPSi9GMerKlkUiYmRptBQmJDgMcOvFTsV9FzG55JeXG/J21j9vu1/Xbc/z6uEyQ7gHoCcRBxjHoYxJoLGKaUJwjKIBGxJiGXbYOkj7oe8nUTSpR4C7nV91gGtD4D1wzQg7QGDKIP3OzuQaNhW44eqC9hfPb/1B023S6Sztnk7AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/b78a3a6b876e8bd49503a2378a13233e/40a76/hero.png","srcSet":"/static/b78a3a6b876e8bd49503a2378a13233e/c972b/hero.png 340w,\n/static/b78a3a6b876e8bd49503a2378a13233e/27625/hero.png 680w,\n/static/b78a3a6b876e8bd49503a2378a13233e/40a76/hero.png 1360w,\n/static/b78a3a6b876e8bd49503a2378a13233e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-13-zero-downtime-reindexing-opensearch/index.md","relativeDirectory":"2026-08-13-zero-downtime-reindexing-opensearch","ext":".md","sourceInstanceName":"blog"},{"id":"c3d05c0b-0226-550f-a6b6-8c914a6f0919","children":[{"__typename":"MarkdownRemark","id":"5ce0839d-0e24-5d40-aa41-f3a3b56c2974","fields":{"slug":"/2026-08-14-fastapi-token-bucket-rate-limiting/"},"frontmatter":{"title":"Rate Limiting a FastAPI Service with a Token Bucket","date":"2026-08-14T00:00:00.000Z","description":"Add per-user rate limiting to a FastAPI backend with the token bucket algorithm: an in-process version, an atomic Redis script, 429s, and the failure modes.","tags":["FastAPI","Python","Redis","Backend","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACEElEQVQozzWQ2W7UMBSGI3WZ7IkTO7FjZ0+afWmmdDrT0lbttIhFhUIFXCKehEseg0VccQGPiKct0nfx+0j/8WcLmJ4QeuKSVV48G6a33fimG1+Pcx5uhum2HW7q9tX+wbt+fzPvhg1JfuV6x7wlSKYnAzrTMEv7/aPLalhV43EzPc3bBQ/1eJI3h0W/LIdVOSz3ukU7PyVRI+pENqmggIAjm75kMNFgkuErgEomEQ13pqNdDXJ2VFvUPRXEupUoRqiCUDEDjqCYvmpFAO9xdCfT7Lhu7obxc1l9zIv3cXqbpLdpdsclTZKxZo6yxkpKg6WKFQiSTnWUsnyBo8lmveFkhwdfrs9+rU+/XZ//vDr7fnX+4/nF77L8pDDmTB0aGrstzSpXnFCQDSqbTN4Is3t5yq00K1ZBpFkJf9gDXJBfw+U50mOFCpJGdJiE5TGOD1A4AVysjr6+WP95uf6bVx9QMLnRkRsvIZ2bUeYtBjLvUF+BOleRz7UJ36HBWLVCGYR8JfGWQXDBAU7Nv8OECcewIhFQ0fEfQdzRE0TVVUGAw8HxOxr0AKWYVHBDUbKy8ivX61w6OKSmNiucIEd+Bv3UpqZBeNlRrQCy1iZVnj+Bbk5IjdmIaV+FbR22mHaYbcoeZA1NCxLt4SiGzHgoiyraVeBMQVuidR+geM+2grZlJP4/7ijOlryZ8DnPM9X5B06KUziMKam8AAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/71976257c3eef0cc9cb8c8710a4c6c3c/40a76/hero.png","srcSet":"/static/71976257c3eef0cc9cb8c8710a4c6c3c/c972b/hero.png 340w,\n/static/71976257c3eef0cc9cb8c8710a4c6c3c/27625/hero.png 680w,\n/static/71976257c3eef0cc9cb8c8710a4c6c3c/40a76/hero.png 1360w,\n/static/71976257c3eef0cc9cb8c8710a4c6c3c/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-14-fastapi-token-bucket-rate-limiting/index.md","relativeDirectory":"2026-08-14-fastapi-token-bucket-rate-limiting","ext":".md","sourceInstanceName":"blog"},{"id":"e49e7127-4cf0-5c49-91e7-1653575ab280","children":[{"__typename":"MarkdownRemark","id":"71eff3b6-d7de-5e08-8de6-c2538e5512e7","fields":{"slug":"/2026-08-11-how-flashattention-speeds-up-attention/"},"frontmatter":{"title":"How FlashAttention Speeds Up the Attention Layer","date":"2026-08-11T00:00:00.000Z","description":"Attention is memory-bound, not compute-bound. Here's how FlashAttention uses tiling and online softmax to skip the N×N matrix and run exact attention faster.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB0klEQVQoz0XQa6+aQBAGYNK0gsIuiwJ7X64iyE2PtrX1cjym3/p/+vs7FpMmTybDsu/sgrU1HeiS4bq7fRwfj6+P++EO9f3tDs79GRbPw+W2v13G623/PplS1szXtq+hsnzc7G7VeCm6n3n3oxqv0Gfb02Z3zdpTvX8v+jNsWPcXsznOsIKU5QVmgsOMxIUf5UFcLmkJjy7RbmBsJGwkHSznvpo4WCx8uSDaeu4gGi0TU+51Psi0U9lgijHk1QzxMCoS06fJIGUbszrmNWU1FQ2XLaWVtXgOk3OiHF/ZWH5B4pPLfGLCVQoy3dWb07g95/kx5i0THRW91KPJDkr1EJYeUctVItla8srw6lf9XYktWmUk0IY3KqqyeMNWZUI3QETrkjcla+AK1hwLQpSKiyEb+rT/Vuz+nH9rPbhhYSPKWZWbXZ7stGhTPQDFt6kZ82QPB0CYO4g7UDH8FWFj8RnxBVFwI3iFiYLzg2UCojgXqqG8AqtV6gfamiMGFli4RE284Fkh7HgxDnORv6Fo7YUlYTXhjU+flYgWRQWE6T9s4YsnLF6NLxw3CmhV9neWHUCc7CEW6gFAH8A3w/gXRCfTOMej07rtxnPMXhD9v9+L/wIza0l/29XgfQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/2d6b9a4a8b053eec65ba5b226b112ebe/40a76/hero.png","srcSet":"/static/2d6b9a4a8b053eec65ba5b226b112ebe/c972b/hero.png 340w,\n/static/2d6b9a4a8b053eec65ba5b226b112ebe/27625/hero.png 680w,\n/static/2d6b9a4a8b053eec65ba5b226b112ebe/40a76/hero.png 1360w,\n/static/2d6b9a4a8b053eec65ba5b226b112ebe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-11-how-flashattention-speeds-up-attention/index.md","relativeDirectory":"2026-08-11-how-flashattention-speeds-up-attention","ext":".md","sourceInstanceName":"blog"},{"id":"2d39033d-57fc-5398-b629-fdcbd7f61433","children":[{"__typename":"MarkdownRemark","id":"f23dfcf7-7500-502d-b664-5c063870ce8e","fields":{"slug":"/2026-08-12-matryoshka-embeddings-rag/"},"frontmatter":{"title":"Matryoshka Embeddings: Smaller Vectors for RAG","date":"2026-08-12T00:00:00.000Z","description":"Matryoshka embeddings front-load meaning into a vector's first dimensions, so you can truncate them for cheaper, faster RAG search without losing much recall.","tags":["AI","RAG","Embeddings","Vector Search","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQozz2R346TQBSHuZOZMzPlf6EwDIVCKW1pWW0DW9vaXeN2d9PEx9B7TfQhjFfGd/DGW298Nw+6MflyQs6Z7/Bj0FjRcGR6RSd1uDmku9equ8mP52hzRIrjvWpvku42P5xVe5rs33irDvIVKihqIKInBjItNtVyt2yO89W+qNpycV03h3J+jWATR/PlTo3XwCPgIaKBFYOlsDJLIdRKqCF7TEWNmBhSuCl3EjKIqKWIO2bDCRtm4KXgjjUw5BPoy5Ilc6z9sxGDGRteNqm2vpxREYKbsKSCuISkYukCwkKjuBLB2SjHL/9Lw6KSmTG+XzjjrHyBMuEjcBLUetNJ/q1GOaRGRFkAsuTrjtdbvm5ZPANcZ0puK5U3TpATHlBbgZ/1KzCXGWNYjYoRxYElWVbz7sRvz6I7iXyNJ3AkLJUWV7af4RlwFPNSbkTsv0xEQLgPcspnz8X9xXj/Tlze8sUW0jkxI+oqqkrdls+Iq7sxdROK+QcRM/DvhBqa6IOa8VVrfvrg/fphfv7IFxu8EhxhomHROOOFKUuslqpsVYmw6PO7CcpDwjwYTXj3yv72Zfj7p/39K98c8DIJOOCnSXeX7x+ylw/T4yXfP+aHR2+9F1XL80bTmaczVxc+CVIoa2i2tKxJkGFHh77fZ7aiHjPU+xphh7iKWNEfjoNO/UjSMDQAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/9564d1641bc95b0cb470629a8c950a45/40a76/hero.png","srcSet":"/static/9564d1641bc95b0cb470629a8c950a45/c972b/hero.png 340w,\n/static/9564d1641bc95b0cb470629a8c950a45/27625/hero.png 680w,\n/static/9564d1641bc95b0cb470629a8c950a45/40a76/hero.png 1360w,\n/static/9564d1641bc95b0cb470629a8c950a45/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-12-matryoshka-embeddings-rag/index.md","relativeDirectory":"2026-08-12-matryoshka-embeddings-rag","ext":".md","sourceInstanceName":"blog"},{"id":"947464fe-2627-5396-b00f-5682a6135eee","children":[{"__typename":"MarkdownRemark","id":"ad3f2662-0583-52a3-b8fb-a6d92630e63c","fields":{"slug":"/2026-08-08-kubernetes-jobs-cronjobs-batch-workflows/"},"frontmatter":{"title":"Kubernetes Jobs and CronJobs for Batch Work","date":"2026-08-08T00:00:00.000Z","description":"Run finite and scheduled work on Kubernetes with Jobs and CronJobs: completions, parallelism, backoffLimit, cleanup, and the failure modes that bite.","tags":["Kubernetes","DevOps","Jobs","CronJobs","Batch"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4ElEQVQozy1Q2W7bMBAUUCCVRJEUD1HUQer0IVmyXbh24gtBgT61TZAez+3//0VXjoHBYrgzyx3S4cszW5xkf+2ffzXHH7Pz6/zy2k38e/X4bXF9g2b3/LM9TRWkm/8MFeAgknk4CUU5bq+L1VM3nvr1uR9Pi/6pXe7hOOsOw/Y67w6AbjhSXoIfpgAO4hbxAuAz64d2qsx6oYGKWOHfiEcNGHDUvJPbyDTlIJBp7pMsYBbzEo4u1ojmQN4BKkhR3hfLA5EVcJ9m/s3geCTFso7yUeajyIak3pXLY8ALD4LBZJgTbokoiCipLHlcY26pKDEkpbkTqkZXOyzKgMEeWGJiu1Z2C9fDEZ5HWCplZpOsMkZr6/ri7c+/l99/P7jSifKBRjWi6WpzHj5dinbz4EmedqFqXaSInrN6L4o+6fbMDsx0ftr3m4upRjfQDlWtSFewJIxKACSESEm1m5IHsai26fYrbfZs/BLOHmnzma+f42Z4wMojieMGcajmyqxF2pOoYXoRmRGLCtYimrG4DljuIfnRZa7LXSQ9FgdJgaSBqx0Pa/gSoVtdrJVZyaxjcTMN4BikKTk3oarha0JVAZiqA5JBHwywWflEQ3VRNCGIoOsCoBNMxLtD3wmY76r6Dy2ARUHKEGsOAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/cc4e4f17fbc960d6928d553d8582c8ce/40a76/hero.png","srcSet":"/static/cc4e4f17fbc960d6928d553d8582c8ce/c972b/hero.png 340w,\n/static/cc4e4f17fbc960d6928d553d8582c8ce/27625/hero.png 680w,\n/static/cc4e4f17fbc960d6928d553d8582c8ce/40a76/hero.png 1360w,\n/static/cc4e4f17fbc960d6928d553d8582c8ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-08-kubernetes-jobs-cronjobs-batch-workflows/index.md","relativeDirectory":"2026-08-08-kubernetes-jobs-cronjobs-batch-workflows","ext":".md","sourceInstanceName":"blog"},{"id":"69f3a290-77a2-5508-81a0-5cb521a17d28","children":[{"__typename":"MarkdownRemark","id":"9be3254f-ef57-59d4-a536-5bc2738d2cb4","fields":{"slug":"/2026-08-09-byte-pair-encoding-llm-tokenization/"},"frontmatter":{"title":"How Byte-Pair Encoding Tokenizes Text for LLMs","date":"2026-08-09T00:00:00.000Z","description":"Byte-pair encoding turns text into the tokens an LLM bills and reasons over. How BPE merges are learned, why token counts drive cost, and where it breaks.","tags":["AI","LLM","Tokenization","NLP","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2klEQVQoz21PyXKbQBTkJNZZQMyMEAwQNm0gAVoItmxXkoovsRPH5UMOueXk/P8H5I10TVVXV0/P67doaXK+om2fuvZp338/7H8cDy+n48/d7htowHB67btncA77F9Cb9WMS30JEM8gcoOMgrrqqGRfbG+BNf7dqb9PlPlsdwVm157L+uO4Ub/p7WewmKDBIqDlu7LiJRSPI6ygwaWSrp7w8VVOThDaNwTFJBGyRyKbygliFDRgrxy/jOyAKB3haNKwXz1/Pfz8P7zIadDTDfk54ifwcgFmBWQVCs4mEai62Q/tr7H4z3hh4buJ58eHTw/Cnr9/4bKsjQcUqLMeoGuXixgsbN9rS2UqzSAib6A4nXm4ROUEMHDiExzvY31DLc3AIr9ywZknP070Kzxs6W2qWmhN4fkn9YsoWNo2gFE8zKiq46OqYaOaKZZw/iKS/JGsPJoulBkkDCT+ssZ8hEiOa2K7kcgst4Au7KXFT2AtKZXaXre/DYvDjHeRV2HCE4yWUlwDCCk8sgWEsYbmCX1BWGjbDvHSjOshPcLmsRj/piFhAmCMvUQFekAtAYIhdtVBNTcSdaQpHsqhhsgEGjaaZCus2g976/2DhwCZzEwnDUTUTy78CNDj/AACtStyDvHSlAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/57c3759a1c497be2a52be92e9f658072/40a76/hero.png","srcSet":"/static/57c3759a1c497be2a52be92e9f658072/c972b/hero.png 340w,\n/static/57c3759a1c497be2a52be92e9f658072/27625/hero.png 680w,\n/static/57c3759a1c497be2a52be92e9f658072/40a76/hero.png 1360w,\n/static/57c3759a1c497be2a52be92e9f658072/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-09-byte-pair-encoding-llm-tokenization/index.md","relativeDirectory":"2026-08-09-byte-pair-encoding-llm-tokenization","ext":".md","sourceInstanceName":"blog"},{"id":"35343dd0-6b50-5ce6-80d7-5edbbddeb287","children":[{"__typename":"MarkdownRemark","id":"11ede45d-5c6f-52a5-9d56-37d99accd26e","fields":{"slug":"/2026-08-10-async-connection-pooling-fastapi/"},"frontmatter":{"title":"Async Connection Pooling in FastAPI","date":"2026-08-10T00:00:00.000Z","description":"Your async FastAPI app stalls under load, then times out. Here is how SQLAlchemy pool_size and max_overflow really work, and how to size them for Postgres.","tags":["FastAPI","Python","PostgreSQL","SQLAlchemy","Backend"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACMElEQVQozz3Oy2/TMAAG8BzG2jiJEzupY8dxXk2yvh9sbKxdu62HCTgg9hLlgDhMGgN1PAYnEEzaJAQIBOIA/wESiAP8h7grQvopspTvsz+lmvu1C/KQl+nKUmXYb6+tNkfri4Nea3PQHfbaa1eba6utYb+z1M0WUvY/r8zDsAAj+VVRAknFT5ezxiCp9fPmMMxXFtobWXOQNoZ5a73SGXnJEiRV1YpnLUXHQsfBFBKGHalmoNlpKbiMWKMkOpi35Y2qJTQkgDVNysy/PBaKJn9cMJ0YkxCX/O0RPT0oHe24k33y4p5zeIt4ngdwGXt1N+yyqFsSbYtWdRwqwPQlFXJMU+aXCeUnY/T7rPBpon19An6+Ln58qEcBU3GG/WaSr97Y3JbjEW/qaFrmM3K25QSm7Y+3nDeHxvGe9WxsnR3AyR7iHlOtyOYNniyK9IoTdBCrybEKgJ6kGgy7ZS4S12WP99GvU/XDA+3Lsfb9JXh3ZESCXtI8YDLPTVbieubGBZ1q0FNUyKYMJl9Gjm9ifmfLfntff7RvPh+b5wfG8a7JPTqnMQf7vSC/nlR7Ip83KIBMUQ0qFXUXlWLPjyh1T26bf84Lnyfg21Pw41Xx/ZEWCqKolGC+ndV383pfZHOaCwwqy65U1AkiMRcxY2S0bB/eNHc2rLvXzMYCA1Zo2z5GPHKjBi+3/DRn8aylyNqMCuUSuYIAg2iQgAsGEtAOoR3IqGlx3fJ0i0PENcMt6OQvpL1eAoequOIAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/6be4c650659d2ce67014e656d7abb978/40a76/hero.png","srcSet":"/static/6be4c650659d2ce67014e656d7abb978/c972b/hero.png 340w,\n/static/6be4c650659d2ce67014e656d7abb978/27625/hero.png 680w,\n/static/6be4c650659d2ce67014e656d7abb978/40a76/hero.png 1360w,\n/static/6be4c650659d2ce67014e656d7abb978/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-10-async-connection-pooling-fastapi/index.md","relativeDirectory":"2026-08-10-async-connection-pooling-fastapi","ext":".md","sourceInstanceName":"blog"},{"id":"ab5633cf-d917-5852-9454-a8867d667fd2","children":[{"__typename":"MarkdownRemark","id":"9799f54d-383c-5c54-91d3-7fd06672e250","fields":{"slug":"/2026-08-06-fastapi-dependency-injection-explained/"},"frontmatter":{"title":"How FastAPI Dependency Injection Actually Works","date":"2026-08-06T00:00:00.000Z","description":"A practical guide to FastAPI dependency injection: how Depends resolves a graph, yield setup and teardown, per-request caching, and where it leaks.","tags":["FastAPI","Python","Backend","AI","API"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB30lEQVQozy2Q6Y6bMBSF+TFqAtgGbLAxO4Q1kJUsk0VKmnamo7bTef+36SWJ9Onq2NfnLlas8EDDI/F3UftWrv9W/b9m+1WtP9PZRzr7Vaz+TBa/s/kHUPWfXvnd8PdgeaDohq8ZPqZRUq6bxbFdnheby3RxLtt91e2b+XG6PEGsutfF5ppVPTIDeK/fUXQr0mmEWYxorJmRChiQDkA/sZ6oRoRogmkyWAZixeC56ZZU1pZbAoQliKaI5boZ3Am1+2gq8YAxlo8jVIeU4pW3sv8S+c2MzqJ4N4Mt5h0WHXaqYTwzNEUJMFk7/tT2GmxnxJkAUFohvLHkDPMpchrCW51mKpEqFohlyC4NXrnZTk62k+5Sr37ks4tINna4tLxOt0JFRa6KhEZcADyDMDwANBRi2dXNXuPmWCzfJ/OffnEIigNPelNO751ZTGz4gxDT0HBSiCqW8GfD2iwnooY+PFnJbCvSnvozuDHd1pQNLKXY8SGob155ddITi09EdIi3yIHCsYq4bniwJ5WVJXJb1lSWVBS2V1s814insLAPq0tUX5x4bwY75NQqHuYHJwiNSOaCraBiwmTBZG7xDATMC2+Ubxp7GVsvYwpipA+MEb8jHmKk87F+F8gZoad4pP4DMNpGYwqfMVAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/df58b502e7deb0a3d25d6eacd0c715a6/40a76/hero.png","srcSet":"/static/df58b502e7deb0a3d25d6eacd0c715a6/c972b/hero.png 340w,\n/static/df58b502e7deb0a3d25d6eacd0c715a6/27625/hero.png 680w,\n/static/df58b502e7deb0a3d25d6eacd0c715a6/40a76/hero.png 1360w,\n/static/df58b502e7deb0a3d25d6eacd0c715a6/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-06-fastapi-dependency-injection-explained/index.md","relativeDirectory":"2026-08-06-fastapi-dependency-injection-explained","ext":".md","sourceInstanceName":"blog"},{"id":"1a517d2a-d901-5378-906f-94fb35cfef80","children":[{"__typename":"MarkdownRemark","id":"bc50fb41-9c0c-5daf-9241-6785f1518aa4","fields":{"slug":"/2026-08-07-argocd-applicationsets-many-clusters/"},"frontmatter":{"title":"ArgoCD ApplicationSets: One Template, Many Clusters","date":"2026-08-07T00:00:00.000Z","description":"ArgoCD ApplicationSets generate one Application per cluster or environment from a single template. How the generators work, a Git example, and where they bite.","tags":["Kubernetes","ArgoCD","GitOps","DevOps","ApplicationSets"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3ElEQVQoz1WP2XKjMBBFeQsIJDYh9k0SSAZjwHbGqdhJJpn8/zdNQ+Zlqm7d6mqd2602PD35uzx9dPsRJO8f6v1LvL5BIV7fwQ+f38Pnd/vyIP3gqhHInZ8MRAqblODEb2iiQWq8D6e3Xr9M82/wYXws569p+ZD65lNJE0WCFuEtZdhBtcmvnKDGtAUhv0J+iZIWl5LUnVNKi9WWW0Cf7ACQAEDEsL3S8SvwrfBK5OW2m8O4cND87db/eTT352DQCMJubuEUCuBJWIMbFsn9RKX8nItLLq60mHAoHFp5Xef1wtO7q94JqiDV8Jo0ayGucXv2UwU3ZySS0Mr4GUTLyWW9G3Msuc0r3HNb1KSTHhOsnDJ+ydpz0ixhOWEmDPiJy2TcrLm8JO2aiYsX905YYcEdiPXckTXuBA4qWowAwJoU4O66hU2cECrias3bS1qvUTbhQOD/w6TjJKhpNgLwo21zxA3TjkkhouMSjyc2nKLT7HGNwgLz1mkrrIXDaxhkB0Wgxnhe49PCpiU4TqSWhmUzOC98PtBVh7Nij9lfBxTmsBN3jTsrrDnuBYpKfz1Et4H+GsPrwbsqoqRhOsy02ROKdrEnKzLR1kFhhuLcohliOaKZ+Q/YZQMQA/MX3W1J0TzsEjEAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/a6a16269b53c8cca9bd20782d15167ce/40a76/hero.png","srcSet":"/static/a6a16269b53c8cca9bd20782d15167ce/c972b/hero.png 340w,\n/static/a6a16269b53c8cca9bd20782d15167ce/27625/hero.png 680w,\n/static/a6a16269b53c8cca9bd20782d15167ce/40a76/hero.png 1360w,\n/static/a6a16269b53c8cca9bd20782d15167ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-07-argocd-applicationsets-many-clusters/index.md","relativeDirectory":"2026-08-07-argocd-applicationsets-many-clusters","ext":".md","sourceInstanceName":"blog"},{"id":"c7b6b8e5-90a1-5743-af8a-41b6a34eca37","children":[{"__typename":"MarkdownRemark","id":"5e10ccb3-9f3e-54f2-bed6-38b9b0617a1a","fields":{"slug":"/2026-08-04-fastapi-background-tasks-vs-task-queue/"},"frontmatter":{"title":"FastAPI BackgroundTasks vs a Task Queue","date":"2026-08-04T00:00:00.000Z","description":"FastAPI BackgroundTasks run inside your web process and disappear on restart. When that is fine, when you need a real task queue, and how to move over.","tags":["FastAPI","Python","Backend","Redis","Architecture"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACBklEQVQoz2WRy27aUBCGXVUFbOO7fW62zzHY+AbYmEAugEJCqEqV0CbqqtuqfYJK3XdTVepDlF1eswPdtdKn0SzmP/PPfyTirygQQF165HKQvambp2G1hzqq3kEznryvmkegmX2I+htEr4i/BAkIJcX0ZYO1ulhzhUViPmjKZpWU58NmlVVXwGB4UdTLcrqq5msiSoskBuqBBIQgDi2c0HDIRImCTHNE1+ZdR8gma+sUhmQjhBmoshF0baE5PdUWqsVVS0iK4ds0jcerwXgTpWsaLVhvCWB+iYI5YhPklw6DhdlfPJojv4BGcyJJ0X3Ni51JNVt8e3x43t//fn17uFsftjeH7eb58uI7Ckc4OmP9ORJTwusmm2XDlZ/Mda8vyToDqx7LbTwwUQwYXmJ4sWKJiGUXyWiRjjHqKTbXwfPRtgDbuhupZiDJXWKTQX52I7IrImY0mgOYNyYqPDoUYR3xqUsrAxUmzk1cHEG5jlI4W5I1Ai85eRUkm7R4irM90E8fePw27O9EvIviHY/vCV8qLldhoRdpXt/EJYQndeCTbAHHuMcY0iM0s09AA+dgvzBJEvTWdfN5Mv1UT77ko4/h5FyzOYhR1wohT5vm/2DR3GUFpG3ihInF5vrn9vbH5vpXM/2KylqzwqP4BAbkU/0fyKWtulKrI73qvGi1X3YUVWOyhv8AdlFXAfSvsIkAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3e4ce285c6ea6a6c3330336b6ea44ef3/40a76/hero.png","srcSet":"/static/3e4ce285c6ea6a6c3330336b6ea44ef3/c972b/hero.png 340w,\n/static/3e4ce285c6ea6a6c3330336b6ea44ef3/27625/hero.png 680w,\n/static/3e4ce285c6ea6a6c3330336b6ea44ef3/40a76/hero.png 1360w,\n/static/3e4ce285c6ea6a6c3330336b6ea44ef3/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-04-fastapi-background-tasks-vs-task-queue/index.md","relativeDirectory":"2026-08-04-fastapi-background-tasks-vs-task-queue","ext":".md","sourceInstanceName":"blog"},{"id":"fe13381d-7b41-5cf5-a49c-5c93843eeb5a","children":[{"__typename":"MarkdownRemark","id":"999305a3-5610-5cb5-aa02-c67d693cd50d","fields":{"slug":"/2026-08-05-late-interaction-retrieval-colbert-rag/"},"frontmatter":{"title":"Late Interaction Retrieval for RAG with ColBERT","date":"2026-08-05T00:00:00.000Z","description":"A bi-encoder averages token detail away; a cross-encoder is too slow to rank a corpus. Late interaction with ColBERT sits between them. Here is how it works.","tags":["AI","LLM","RAG","VectorSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB6UlEQVQozz1R2W7bMBDUk62LpERKPERKsiWLVmXLVxwfsVMD7UtROHHz0P//la6QIsCA2B3O7nCXTlteAI05Hfpfl+3b69Pjsnu77t5vh4+X7f20+v19/3jdP14299vzn2370+bnzxKAM0JqhFWYTHK7a/pz059mA451f4Sg/LYf0uUJrubri2m2KK3GJBsTDXConDPVkrRCbBrEhU+MHxdCLIzacN5ptQbejcwIZR7JA1p4kfEjE8YlwEl0J4q1MisIImERnYRxkch5pntbn0XWAdrmOpseCZ1GrKonB5Za8Aii3CG8oVk3yQ9JtqR6EfEGLlysApL39kdIS8pmx9X9uvuIWc1ld9v/VWrhoswnueMTHcQ5oRNESwh8AqweyMgw1mCYhZYsnSdp69EiSuqYVmOsPjWOjwc1sJhVQyWkWHtYxqxKUgvtYBFctFJ2bqxTbmlS+5EGDSjBORsFqch72Nw44JB6sHxWSrWs8wPmM1hvpvrKPAfJxOanRLZAkrT2kHRcJMHH1DtR9hAABYAWMEiSNtAITGTWTqsNkOCMhh/RATFDsR9yXbS13dr2SRk7DlIfSzfkHhZUTHk247oR2kpjU1ULY4VuoGwQIOEgGC/WUawpNXAC+wUfnoAHDG/BwsP/0y/BP/HiRoxjo5RKAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/40eca43c663841ba2316288ccfdce514/40a76/hero.png","srcSet":"/static/40eca43c663841ba2316288ccfdce514/c972b/hero.png 340w,\n/static/40eca43c663841ba2316288ccfdce514/27625/hero.png 680w,\n/static/40eca43c663841ba2316288ccfdce514/40a76/hero.png 1360w,\n/static/40eca43c663841ba2316288ccfdce514/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-05-late-interaction-retrieval-colbert-rag/index.md","relativeDirectory":"2026-08-05-late-interaction-retrieval-colbert-rag","ext":".md","sourceInstanceName":"blog"},{"id":"92bfb7d3-408b-5a38-8358-3e2bfa17508a","children":[{"__typename":"MarkdownRemark","id":"22340aee-80d4-550b-9098-2bf45c1755f5","fields":{"slug":"/2026-08-01-metadata-filtering-vector-search/"},"frontmatter":{"title":"Metadata Filtering in Vector Search for RAG","date":"2026-08-01T00:00:00.000Z","description":"Adding a metadata filter to a vector search can silently return fewer results or wreck recall. How post-filter, pre-filter, and filterable HNSW actually differ.","tags":["AI","LLM","RAG","VectorSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB20lEQVQoz12Ny07bQBRAvSCMnzOe+DGesT2xY2MnOO/ESRMBIUmholIfQqJLpKpSxa5qt/2nLtuf4KN6IYKiSkcjz/ice5VK9oFuVM2PF9t6e/HqYtVfberttt6dTzfryfmes/F6t3g9K+fduAL/WPbgVBCJgYYVerJ/NDgpR2etzrwYneaDk854DS9ptcz6q7y3Gi4vRT4+MAWy5eFjpZhUPtEybKmR2GW54+eGkyAq4YQrdVPdjnUSGf/kBxTDjgENh8DDN4kdlom4+7befdl8vJxs/LBjuakBJWjkSXtEgXkA9dtNloOBiGjJwa/rr/e3P35/uru//f7n5m7RHh5iATb1MzD3CQBxaNI4LWdpOdUwx34xWd5cjzaMZYTnhh39PH337eoz8nKTiKSctjtT4qYaFhAqOowkQrW4agaaFWTDK5bWSoMgzKO0hyyuHGAnrbPBG9VkoGkWN0gIFaDANkCH3mTEy8rZB/gHS0BqZUOTRgbmFpXF9D32MnCg2SeAAtv2qKYPK4JkgqygYTBksbK/UDFvGL5qBfCOnQScZx+AmD0DSzTChZtUsluI4ijsJLzIRMkcqROu4+ClDCgw7CXI9AnhXjNyaejQqEnDph1izJHh/WcCfwHoaksAlH9PDQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/7968701b169fe845aa0823b8b0577839/40a76/hero.png","srcSet":"/static/7968701b169fe845aa0823b8b0577839/c972b/hero.png 340w,\n/static/7968701b169fe845aa0823b8b0577839/27625/hero.png 680w,\n/static/7968701b169fe845aa0823b8b0577839/40a76/hero.png 1360w,\n/static/7968701b169fe845aa0823b8b0577839/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-01-metadata-filtering-vector-search/index.md","relativeDirectory":"2026-08-01-metadata-filtering-vector-search","ext":".md","sourceInstanceName":"blog"},{"id":"e88e8e0e-af5c-5660-9bfc-4ab32975e767","children":[{"__typename":"MarkdownRemark","id":"a6ed8d4f-c0d9-5d40-a026-66b29d1ebd40","fields":{"slug":"/2026-08-02-contextual-retrieval-for-rag/"},"frontmatter":{"title":"Contextual Retrieval for RAG Pipelines","date":"2026-08-02T00:00:00.000Z","description":"Chunking a document for RAG strips each piece of its context. Contextual retrieval adds an LLM-written note to every chunk before you index it.","tags":["AI","LLM","RAG","Retrieval","Search"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+klEQVQoz02QW2/aQBCF/Wh7ba9vu/Z6fb9hsIEQAhgbl9ICSRQ1VRu1qqrk//+NDvBS6dPRmbMz2p0V1NHiRtR+yT+dk+4Ytoe0P2X9KemPcfc1Gx6z3QlyCKP2gPKZWi6UcgEqIJXLimeYSVY+VHU3mfZVva1nO/BgRvUWktGkra5mPO2xlSDNvyGoJFNprtECVCU5MmPZCCUzgtxileWNTVYZrFJJodgpHKl2jMzwSiSQYpUPL+XwEm9O9rQ3orlix5Id0WQxXz3Xy9Ns9TyaHWh4T/hU1jxZ4wjAPtIDwQxnbLLjk4GWrZ1vDOjAHOm+TFJEc0QyFNUSKL0g2bFMEkRTBAb7gsWnLO3cpGXp1k02ptfIioOCUfH9T/P2Uf98b359NG/v4x9/s2+/2fHVGB7x+VVb72WVCbpT6k5huCNAI7nBxgrmml/Fq2O2OSfrE2jePqXro3+3DxZ7Wvd20+vlUtKYgK/DJnyMN8a0uAybIeaVV7S83PKrkvjeDOaY1did2MEdjZd62IgwbPHGKzqWtTcMVosKFTUXkRg5iRJWsIJsR4DipkoyQW4KXjIDSXUFWNLNWjfd0OgBgGFIAVEmOB/zbR/2g+YlIiJWM4+Gz37byRaXZCKpjnD92+A//MvNFxwJM2RxaIWHXEr9WpqeqDpQQs8/LHlTj3KqFbsAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/ab292b7169b3a72f3ade4c490cddf89c/40a76/hero.png","srcSet":"/static/ab292b7169b3a72f3ade4c490cddf89c/c972b/hero.png 340w,\n/static/ab292b7169b3a72f3ade4c490cddf89c/27625/hero.png 680w,\n/static/ab292b7169b3a72f3ade4c490cddf89c/40a76/hero.png 1360w,\n/static/ab292b7169b3a72f3ade4c490cddf89c/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-02-contextual-retrieval-for-rag/index.md","relativeDirectory":"2026-08-02-contextual-retrieval-for-rag","ext":".md","sourceInstanceName":"blog"},{"id":"9bd8ee8b-1cd8-5a82-a7d2-e56674ac5cee","children":[{"__typename":"MarkdownRemark","id":"db6e6998-df8f-5abb-9920-5537638f1d93","fields":{"slug":"/2026-08-03-pgvector-rag-postgres/"},"frontmatter":{"title":"RAG Vector Search in Postgres with pgvector","date":"2026-08-03T00:00:00.000Z","description":"Store and query RAG embeddings inside Postgres with pgvector: HNSW indexing, distance operators, metadata filtering, hybrid search, and the tradeoffs I hit.","tags":["AI","RAG","pgvector","Postgres","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4klEQVQoz02QaW+bQBCG+dAkro25Dy/HLhgMC+wB2AkGx457qZH6oe3//zMdnKaq9AjNDPvwzqI0JGuSrMZbGpGnWrzsh+thOHeH6+Nwkv2lf3xu99B+Gaa+qKs4nc+/o9xp0b0W6z7VUeURkbFTIS9vT0IH2r5AvROXqvvkJq3qlcAHLb7T8IOOFWtTOEFpeJnubtcWWRrxysCqOReqhW9tvDJhEhs2Md10xiFQqyZWPNxFxQnTsxW2m+0AtYv3gEcOTtyHu4nQ8yY7cgqbX8ZunPrTUY51xpZ6pMDCdixRNhioceM2KiaUHQE/PZiI2ZF0cWtFkmb8s2ivXJ4ZqDLBdDXLXmEF3E8frZDboQhmcwDgQ7pfmUFjBcxArN4214Z95fx3L8aKJ3G50kNILu1IgAxHnUjcYgdoXdyZqIHwWQ447Pldsitjr5I/1zwFWUOQXFohOMOcHMkwn4J8BPz0CS5iweYhB5nl7JsQl4ZD+LEWOCqXs+zu7IDNF5tl7hP4Vf0NSK5MVFuo1jxKk+KHqH611U9ZvfKqwPlC3SgOKsO0RYQ7AY3zPkxlnHUIN4gIHzPNzXU3X6wRsv2xJMcyGQoylWQXbO5VX1moHvBx7f8r3liofyf/4S/e3z7cJn8A4m1V7m1z4lwAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/74e573a27101a4894857b92b08201f6b/40a76/hero.png","srcSet":"/static/74e573a27101a4894857b92b08201f6b/c972b/hero.png 340w,\n/static/74e573a27101a4894857b92b08201f6b/27625/hero.png 680w,\n/static/74e573a27101a4894857b92b08201f6b/40a76/hero.png 1360w,\n/static/74e573a27101a4894857b92b08201f6b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-08-03-pgvector-rag-postgres/index.md","relativeDirectory":"2026-08-03-pgvector-rag-postgres","ext":".md","sourceInstanceName":"blog"},{"id":"3766888e-8d44-55ee-b5db-652646f16d09","children":[{"__typename":"MarkdownRemark","id":"3fd28694-5c1c-50ee-8265-37fcdd8cd144","fields":{"slug":"/2026-07-30-managing-context-window-llm-agents/"},"frontmatter":{"title":"Managing the Context Window in Long Agent Runs","date":"2026-07-30T00:00:00.000Z","description":"An LLM agent that runs long enough fills its context window and starts to slow or fail. How to prune, compact, and offload context so agents keep going.","tags":["AI","LLM","Agents","Python","RAG"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACDElEQVQoz03QSW/TQBgGYBcKcWJ7vLtOvIwd23EW21lsZ+2iJrQJBJJUZb0hlKpCICROHBESiBM3zkic+CtcOPJ/+NxEEdKjT9a8885YQ1j4EJjGMAxm3fQiTZZJvGo150m8TJNV3Fn0e5ed9qMsiiFaDvqP67UzbI6gRZBsCdxlVNVq+NGw2hwBL+jDrLeOnEa3Eg7cRrfeOYK0EvaD5KRUDmE/tAiaN29gmCSr51ljn1ZuUcIeJe4VBNhR4Iw8q5NIzzEapAXOpPgMVAiKMzagbOhVTas0/ekwejEInw7DZ9iIGR6rZqp7g0Zyr1hOBC0Q9Qgg2SMKrL7DcAaJlJfz79+u/35+9fvr+k8nuIRDTXukOT1oqlas4HbGbCPJhbK2wQjYsNuKUX1w+OHN6tfVwx/Xi5++d3aHlmjBZkRHLFY5xYPvjGhnv11ApQ1WsiTV52T7OF4/Of2yOv54cfLJKR9zomO7Y682DbozNzpVy2nJ7QFOqRB5VNxi1Byl5GgljZ6fD96Pe28nvXeWNSCRSgkmJeA8h+FOJDtIcpDsUrxBQGcLFQXV5RW7Hi+G569743V/cqWXU8RbBh55/sQNR7LZzB5MC0U9ZCQbygdbSGVFzAi64Q+9ztxtTr32falUg3Mr/qxeX8g4OrBuXgu3YDJSmSBpZSdHyeD/lWyRVvbz3O08u0l3IPoHh8lcRU/a7vMAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/2aaa682982a02a1e294ea1c41dfe55ce/40a76/hero.png","srcSet":"/static/2aaa682982a02a1e294ea1c41dfe55ce/c972b/hero.png 340w,\n/static/2aaa682982a02a1e294ea1c41dfe55ce/27625/hero.png 680w,\n/static/2aaa682982a02a1e294ea1c41dfe55ce/40a76/hero.png 1360w,\n/static/2aaa682982a02a1e294ea1c41dfe55ce/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-30-managing-context-window-llm-agents/index.md","relativeDirectory":"2026-07-30-managing-context-window-llm-agents","ext":".md","sourceInstanceName":"blog"},{"id":"82353eb8-5369-5d1e-8491-92bccb319a77","children":[{"__typename":"MarkdownRemark","id":"5e20654d-788f-5d13-ac34-605690744acc","fields":{"slug":"/2026-07-31-graceful-shutdown-fastapi-kubernetes/"},"frontmatter":{"title":"Graceful Shutdown for FastAPI on Kubernetes","date":"2026-07-31T00:00:00.000Z","description":"A rolling deploy sends SIGTERM and kills your FastAPI pod mid-request, dropping live SSE streams. How to catch it, drain connections, and shut down cleanly.","tags":["FastAPI","Kubernetes","Python","DevOps","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQoz02P3W7aMBzFLbWFOP4KBIjtOHEgxIS0fGltByEB+jG6Vdplpe1iL7LH2NXu9yy73ivNYdVU6ae/jo/P+VsGU6OKE9MsrMv5oV5Vm9nD4Xq3XT4erqvNvLy9rDezfbWsN/NdudjcFHkmm7xRoE21pUVi7GfZ1W66uh8VlZ1pUeWrezPbW9POyeJufFlPFgedl8gfn1oJwN3IYVbFrpdYC7IIMgWZxJ0IktC1MOV6Eeo0WI1ohL0Ye80ENqSjIIkDrQbDOOgNBI8K1p9euIqGIzY0RI5c3GxBTBGesCSleoSVJmECSEcet+rTPn3cJtuVb4Ye8ounOitf1t2PFf+w5s9V8FRSnTlEDmb51XE9O5ZymVETAuxJk4a50ROjTSo8P7i/6f75eX67Hp8hhQiHVHaKIny5o8OMBlpMpyIvelmGoxi4VLaxhTtYXCDZ8eXvH+3Dux4AAlHRtn+moXPRZ6kRn2vXOog3YSLsRwCkwlp2PfYEOA+/Hr1f36EVDglGqdnv3g9E0rbvw2Bw3FAzcWDgMgmbigDQXpxAjIMz/u2Zf3ni4JxTP4oSs1zOw9iQrm45fb2cxcVl2+lD+lqx5eA/LuWkP+7wnPqxLSMvamGJPEW6EfPjUGRaTdym+ZoHDh68hXQV68Wncsx6mp22/DuSk4Bvwn8B/DZLUAfiRtMAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/0ed827f19ec7b4a87eeef897fe2b7026/40a76/hero.png","srcSet":"/static/0ed827f19ec7b4a87eeef897fe2b7026/c972b/hero.png 340w,\n/static/0ed827f19ec7b4a87eeef897fe2b7026/27625/hero.png 680w,\n/static/0ed827f19ec7b4a87eeef897fe2b7026/40a76/hero.png 1360w,\n/static/0ed827f19ec7b4a87eeef897fe2b7026/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-31-graceful-shutdown-fastapi-kubernetes/index.md","relativeDirectory":"2026-07-31-graceful-shutdown-fastapi-kubernetes","ext":".md","sourceInstanceName":"blog"},{"id":"9b378d63-2ad1-5f5c-b875-d9ef5f41ea29","children":[{"__typename":"MarkdownRemark","id":"f789e1ef-1deb-500e-bb0e-e60e79786149","fields":{"slug":"/2026-07-27-prompt-caching-cut-llm-cost/"},"frontmatter":{"title":"Prompt Caching: Cut LLM Cost and Latency","date":"2026-07-27T00:00:00.000Z","description":"Prompt caching reuses a request's prefix to cut LLM cost and latency. How the prefix match works, where to put the breakpoint, and the silent cache misses.","tags":["AI","LLM","Prompt Caching","FastAPI","Agents"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+UlEQVQozz2RW4+TQBiGuWo5zQDDucAApeVMW6i0drs96Ga72u662XhhTIw3mpi4Vyb+//hBE5M33zyTmWeOjOJt+txIzspN79L2eVo/xs3TZHHO2uegfIjmHYxnH9Llp2L94iTvJXd9tRhecgTJgYqIH8TLstmn1aZY7IrFbb16N8lX0K2afZyvquWh3Z7oZI5V/2oxgkIFxYcqkoCXXQ6PYAwq28WW9LBnm4PVVX8oWt184vNyZzGC7F2D1UBxWlo+ecWF0FtCt7S8QIi/I/TGK87AWnhEeiJrgaSFoMCxXWigg1VqJR+b09/y8OpUX+zic33/pzy+urOvdn7l3179XfXeTPPWogWLRt2dRcXT3FI2YiO6qw6/4vU3Iz6byWO1/9lxcjHjc7X/AWznL8goOGzBliAyPB5xyObkgCcR0qfyqMJmjs0MQtyFbFfYyCQz02gDAENw1YFgDEUTRIZFFiIeMSOkuIqVhOXBDBpspqpbJPXJz3ZSz+nyYVweiVPBE9Jo5k8WkuYzHLIgouyJsiObsTPdGH6tjErFSp3pW9WbS3ZO7IymW2vcgiwSqhhjeDMe2yCbHDLAxIoLX627he6VWI+QGmhujvWJqIZIC4md9jAGZ8jrQ8EAkWFFAzIU9GsGvDbg1P/cgaizPbM9dPORyYoQ4x+ZEFCYwqVGlgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/f3de8aa2c7ecc91722c578140feaab86/40a76/hero.png","srcSet":"/static/f3de8aa2c7ecc91722c578140feaab86/c972b/hero.png 340w,\n/static/f3de8aa2c7ecc91722c578140feaab86/27625/hero.png 680w,\n/static/f3de8aa2c7ecc91722c578140feaab86/40a76/hero.png 1360w,\n/static/f3de8aa2c7ecc91722c578140feaab86/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-27-prompt-caching-cut-llm-cost/index.md","relativeDirectory":"2026-07-27-prompt-caching-cut-llm-cost","ext":".md","sourceInstanceName":"blog"},{"id":"3627a711-73b6-5a97-a7f6-8d72a97d35ec","children":[{"__typename":"MarkdownRemark","id":"2c592198-7b64-5c5b-8857-56b385f97ff4","fields":{"slug":"/2026-07-28-choosing-embedding-model-rag/"},"frontmatter":{"title":"How to Choose an Embedding Model for RAG","date":"2026-07-28T00:00:00.000Z","description":"The embedding model sets the ceiling on RAG retrieval quality. How to choose one by task fit, sequence length, dimensions, and domain, plus the silent bugs.","tags":["AI","LLM","RAG","Embeddings","Search"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2klEQVQoz02RW2+jMBBGedsYjMFgsI3BXBIDuRC6aao0V0qqtqvt//8/O0mkaqWj0cz4fPaDLb/tANp2XrMM5p05vU0Pl+YyQlOfR8AcB9jcl1cYSb3wmxW9pyybpA7JEFZeUEWyNfPXeXdqV0eo9WK/6M7N4rC4b1ZPA8BEC6btKkhZTqBvhLnLSi+u7mNuU/0/yNeIahzkDtVeVIEJDpiWQzMbK1I00qxT0yvT6/aZqQbB3V4KIKIiXpqmr1enpjua5SFOl4RV2M8sG4xAQ9hThogZERURUxwVNtMPENNuXNBk5quapk2Qzb2kJnKKw9xCWAbr3+LzGr9d+HVg+60adtX3VX+cyz+X8u84/R6LryH/HNTbLtw/8/EMpvgYaddbtisdprGssChZ2bHZS2w2NDUkqUS94c2Om42nKj810ETmhVUdFoUrS4dlFiISuRJhMXF4KJeZOYhia7sJckWYdOnsFerEiW2iZLGF00DMYQQfUhZItzyRE5fzvDf9e97sbQJhHmX9bH2N9NMEx4gkuj3W/TtLVxPMYYQIhKG75W0i4SdIZPzYkDAHqKg9XlNek1B7rIS9FxlwHjK8asGtP/xyIseXLlXYV/hR/QRwaQpgeuvB+fH/ATL8SrjG2RNCAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/77b826ceb3b55af1c5bbd4bbb78df257/40a76/hero.png","srcSet":"/static/77b826ceb3b55af1c5bbd4bbb78df257/c972b/hero.png 340w,\n/static/77b826ceb3b55af1c5bbd4bbb78df257/27625/hero.png 680w,\n/static/77b826ceb3b55af1c5bbd4bbb78df257/40a76/hero.png 1360w,\n/static/77b826ceb3b55af1c5bbd4bbb78df257/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-28-choosing-embedding-model-rag/index.md","relativeDirectory":"2026-07-28-choosing-embedding-model-rag","ext":".md","sourceInstanceName":"blog"},{"id":"4e2625a1-92f9-55e4-84f7-429cffcc4e68","children":[{"__typename":"MarkdownRemark","id":"8df25a11-b866-5893-bcaa-49ba9200f5cd","fields":{"slug":"/2026-07-29-llm-sampling-temperature-top-p-top-k/"},"frontmatter":{"title":"LLM Sampling: Temperature, Top-p, and Top-k","date":"2026-07-29T00:00:00.000Z","description":"Temperature, top-p, and top-k are the three knobs that shape how an LLM picks each token. How each one works, when to reach for it, and how they interact.","tags":["AI","LLM","Sampling","RAG"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABzklEQVQoz21QyY6bQBTkaKChVxbTzTbYbrMZMs4otsGeUXKKMusll/xA/v8L8tqWIkWKVGq9qq63WlRPAF7P2/P79vKhz+/V8Xl1egG6Oj3r89tmfl1PLyDWjx/r6XUzvwEVzZnqk+X4ietLx1tWej/un7phboZp2x0B7TD346XZTe1u0u2hNfoB9Gpzj7CERMtl2RW5jdUCpzbJXJo7Bpl5r9QmKdDra/SFryCAFMsFCSsSlLLoSihJUxcrgIMlYlmU1h41BrCBiILKW9Y47b2kcWlmOcan/GDNZM/lzmOFy0sUrqE2i3SQdCSuEcmcWzleEtnRbPSDFVCzsycqKkeqRiIHmvSuGTgN0kFUR7Y6iuIzi2sbToMlK/Z8deTVAQLECgtO5YeaLLv49FO0X0nceLx0cELjhuuL+v6bryeS9NAD0ZyqXfjpx/LxFy0ecKSthRcjfkflwIoHlt0bH1GOH4ukY9mebebg7gt0BhvMybJR1E9B+43n0Dm3bC8GwA7QE8c1zIyp4gKWTCBHyB6H2sXJ1RbBOUnSmp1FZaMIkiMAFjkN7wAeVTcFUcXCkkUVDcu/IgQkKACY50CtBQoBtz/AAvCv8j/RDAv0D2etR5Bw7PryAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/c7670afd8e01157c75428c788f6b297f/40a76/hero.png","srcSet":"/static/c7670afd8e01157c75428c788f6b297f/c972b/hero.png 340w,\n/static/c7670afd8e01157c75428c788f6b297f/27625/hero.png 680w,\n/static/c7670afd8e01157c75428c788f6b297f/40a76/hero.png 1360w,\n/static/c7670afd8e01157c75428c788f6b297f/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-29-llm-sampling-temperature-top-p-top-k/index.md","relativeDirectory":"2026-07-29-llm-sampling-temperature-top-p-top-k","ext":".md","sourceInstanceName":"blog"},{"id":"3f1ac6f7-de94-5394-a681-da963c228a45","children":[{"__typename":"MarkdownRemark","id":"4109c72d-779c-570b-9258-2054394578e1","fields":{"slug":"/2026-07-24-speculative-decoding-llm-inference/"},"frontmatter":{"title":"How Speculative Decoding Speeds Up LLM Inference","date":"2026-07-24T00:00:00.000Z","description":"Speculative decoding uses a small draft model to guess tokens a big model verifies in one pass, cutting LLM latency 2-3x without changing the output.","tags":["AI","LLM","GPU","Inference","Performance"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACEElEQVQozz1Ry5KTQBRllRc0NDTvNA0ECCQ8Qgh5TDJJsFLzyEpLXY8Lp/wGLVf6B27nP/QDpvS/vBi16tSt2+f06dt1Lpe6ASCh3nKSNfX6uFjdbHb7eQ3Ni3pzqJZAwrGpW34RpxPHS73g4uI6EutiDxmxGVRRsU/mTbo4Bdl1VBzgGM+buDwG2S7M98nipPsVr4872O2CS2Icjx0eD0Xi8TLrS3Qg0bbiFsAgxRNkJiiuqDCN2Lrm2AbDCkgO8JyoBsSeIjUAiFrYQoUaCbKLiEusxPLnOptpduzYo5gF1BppZoDICKZyxCm97K5nlu+uynpaIbvQnBmQ8FZXMKDSyUlyN2U0fXq7/fZq8/Tm6vVq2dMSAVOO0JmbngZ0/fF2tc/nvAXmgtAC6xGxImzETtLg0b6Z1c+Pu+8P21+P2w+HZUcF85BTaDHKTqK//3y/PeTlxawMC9mM6WgmmwlLjmrU3Cx3z++3Px62P/+aY0GyYXLpZueBVb6s8nxcIitXaTsZEb8n6BCBk97K/vXUn3w5rz/dLL+eV3fzRV+NB6LFgSzbmaSPkR5jK2kbCEwfQ9Q9wYDYZDvF5gRroaCGPAn7JBioIQTWRyYHz/eRIRLmBkWQVAYd85INzH/0kEFUGlMvHLpj6jOTwWovUmuGD0iqi+Sh0C6ciYoD5D9oA6lVRZn+UV24gBQKPKi/AWwMWbQilyDRAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/b795063cc4996b8cbc2c4e853c552d50/40a76/hero.png","srcSet":"/static/b795063cc4996b8cbc2c4e853c552d50/c972b/hero.png 340w,\n/static/b795063cc4996b8cbc2c4e853c552d50/27625/hero.png 680w,\n/static/b795063cc4996b8cbc2c4e853c552d50/40a76/hero.png 1360w,\n/static/b795063cc4996b8cbc2c4e853c552d50/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-24-speculative-decoding-llm-inference/index.md","relativeDirectory":"2026-07-24-speculative-decoding-llm-inference","ext":".md","sourceInstanceName":"blog"},{"id":"97513486-cec7-5d61-a521-f43ad240c465","children":[{"__typename":"MarkdownRemark","id":"8393e977-7768-556b-9aef-153b2b7900d9","fields":{"slug":"/2026-07-25-keda-autoscale-kubernetes-queue-depth/"},"frontmatter":{"title":"Scale Kubernetes Workers on Queue Depth with KEDA","date":"2026-07-25T00:00:00.000Z","description":"A CPU-based HPA can't see a backed-up queue, so workers fall behind. How KEDA autoscales Kubernetes workers on queue depth, and where it breaks.","tags":["Kubernetes","KEDA","Autoscaling","DevOps","HPA"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACAUlEQVQoz02R6YvTQBiH86HadpOZzGQyyeRqmrSbzdl021xt0rIriKAoon73qJ9FVvBf8NjFA/9hJ7sihYeX37w87xyMwKyOY/S1pawJ48fL9YsofbI4f57lz1bFqyR7ykl5Ll/yPne4eet3whiZnBE0IPWQPvfDYlFcBOkmyDbx+S4vL5PVLlxseSfMWzdYcQeQ6RCysWwKInYlxREVHagm0pwTrA8kfB+Qe5LCGYh4ICp3y4GkDKEKVRsQC1EfEE8YAd31L9rt56b+sN1c1eXH8Ox1Eh6i8A0njt5H4ds4OsTRu74fH+ryU1NdzcMHin4qDAF1Jo/2zZ+m+LItr/fN767+vt/8aqvrturDrr7pa/Ozrb519U1X/9iWXzWrEpEjjKEBsG/Zl5StdaNhRkv1ghkbnlV9bZgd1UuNVczsiLY0zB3PlJW285BPCSfQkJBLtTUmiUIzRV0AFMo4kZUEkVjGKSIJUmJMMoACQpeKmmA1VbWVJE/6k8eQjYDGHz+UNAmbjpe482wySyGxvSCXVUdlc2oElpuJyOQON7nPp4QxYLfwLYyRpMtkcpbUp3HFK3PiOG8tL7O9pR/UQbSTkDO6k3v6Yf0IDVLf9As37LCRUiendub42XSe8es4Xoz12UjS/vsCXxwjIpv/IdJmkEwBcaHqQvIPRKciso7lv5mmWZvH4n2kAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/087e118db1fb141ff439e029fa956a73/40a76/hero.png","srcSet":"/static/087e118db1fb141ff439e029fa956a73/c972b/hero.png 340w,\n/static/087e118db1fb141ff439e029fa956a73/27625/hero.png 680w,\n/static/087e118db1fb141ff439e029fa956a73/40a76/hero.png 1360w,\n/static/087e118db1fb141ff439e029fa956a73/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-25-keda-autoscale-kubernetes-queue-depth/index.md","relativeDirectory":"2026-07-25-keda-autoscale-kubernetes-queue-depth","ext":".md","sourceInstanceName":"blog"},{"id":"b0b072bf-4d29-550b-af46-cfdc47549f90","children":[{"__typename":"MarkdownRemark","id":"a7b06f79-4095-5133-809a-fc1cb19ca6cf","fields":{"slug":"/2026-07-26-llm-quantization-int8-gptq-awq/"},"frontmatter":{"title":"LLM Quantization: INT8, GPTQ, and AWQ Explained","date":"2026-07-26T00:00:00.000Z","description":"The weights don't fit on the GPU you have. How LLM quantization shrinks them to INT8 or INT4, why GPTQ and AWQ beat naive rounding, and where it breaks.","tags":["AI","LLM","GPU","Quantization","Inference"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQozz2Q2W7bMBBF9dLYWiiStihRC62N8ibLm+RFdhAnNZygm+EUeShQIO1HFP2Ioh/dcZwGOBgQ93LukKP0wy3Q62w2s883i9Nu8bhbPt4uv9bTT9v5l339dD0/gg51tzitxh+6or60AMqV6b1Drt4O4+GyO9kkOdTtsNzJYp2N66yo03zVm27laJ2O1lG/gpsN7DWwDygmi7EdUy6xkxhnw9ewAHQaaqSj047aCrCdUEe2eIbaEWDQzguhIpNqOb4viz3U2eAu5NO2nRlUGEQ0kBuH5XH9XBQ7kU7i7pxYsYYDnYgLSsvKXGfs8BHjue1CHRos0dsReCr2aCtNvQqR8MrgDcNtmh6IgHZ+YKBg3ieikN3b6/m3zeypzI/L/JSlNxoJVNOFCNxOqCU1KjQiYJLFegCiIUQoppVCvwiqsTwU6X6cHcrex6izYqybiy138iCoonhzWP0ERLIm7sgKJrY9UJGrYCapP+JRGWYbL1owb2LyPoJvE0FoaNv9IChzuf/98PfX/Z+BvLP8whMVRDeRoxC7S4KiL98/zH/sJ98P0+coqhHv6ThoGLaKuGZ6VzqDg458nfiUpWYrVA0OiqKaHHZLnZT8BzNYqa8i50LTsBEVzMnatiQsRi3xZinNc7yjmVzDrmZe4E2Dgf7Gy/xXVz27r/o/W0VRIRtUeRcAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/f903aeb9cbb35378dc7a29620092b56f/40a76/hero.png","srcSet":"/static/f903aeb9cbb35378dc7a29620092b56f/c972b/hero.png 340w,\n/static/f903aeb9cbb35378dc7a29620092b56f/27625/hero.png 680w,\n/static/f903aeb9cbb35378dc7a29620092b56f/40a76/hero.png 1360w,\n/static/f903aeb9cbb35378dc7a29620092b56f/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-26-llm-quantization-int8-gptq-awq/index.md","relativeDirectory":"2026-07-26-llm-quantization-int8-gptq-awq","ext":".md","sourceInstanceName":"blog"},{"id":"b6435206-d113-5412-8136-54e38eff25e7","children":[{"__typename":"MarkdownRemark","id":"aec18548-96ec-59a0-b5b9-cd27583414c3","fields":{"slug":"/2026-07-22-tracing-llm-agent-opentelemetry/"},"frontmatter":{"title":"Tracing an LLM Agent with OpenTelemetry","date":"2026-07-22T00:00:00.000Z","description":"An LLM agent request hides where the time and tokens went behind one flat log. Trace it with OpenTelemetry spans, the GenAI conventions, and where it breaks.","tags":["AI","LLM","Agents","Observability","OpenTelemetry"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+UlEQVQoz22Ry4/SQBzHq2KhtJ1OS6H0MTNQXlv6CktAHgVEWMjGBwuHXbJx4yMbPa1XEz168Kon75486d2/zh/LrhdNPjPznfl9v/ObZLgmDXwaNkkQluPlYDluTfrh4FFnBmIYDSeHD4Fpe5rEyaw722/DUgx+SHG8QtIKuY8cUXcPDse1aOj6/bh3VPZ77KBTiwb1OGnEo2owCLrzWpTU4xE4wQ8pTlLpX7KKI2IqqlQAoTgpTLEdCsgGncUEDkHvSpjs/Ryo/yKYzWnrqN95Wus8E51IyVdRrmSQoMgig/h7DwfdbsDX7HrayI4+P375a/26Hc8263fv51vsRBImSHcljQH7CITtPQKyYBaRdRfTF8nmx8mre2qJxwwe/HNzeTZYwTlWbFUl8m2EyyJLkE1No1XHY1bDMiqpQv3b+s2Jn+iV1nx5KhJ/FYy+bt6m9Aqz6i71i2Zt1wlZnIBMAJSSoyjHFI3c0cqfji+uesdcvhJEY7jrw3j1cfGcQ0SQjbRsZuQiAClOgOWajGQAgmTwshl649/nV+fxBFGvQhpfFtvQn/DIQhpFGsP5sqxRMEPYuOXmlqxc4FX2IJ5/f3I5vdi254tqqSvkXRlbzPVY2bOYB/mMVOBg/Isg5lOyyRcaBmtjK4C/zYj6riTqaVHnsztg+wel/VV3RVrUeAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/e5f3c00f4b4662e82b0b40efb94e8ed3/40a76/hero.png","srcSet":"/static/e5f3c00f4b4662e82b0b40efb94e8ed3/c972b/hero.png 340w,\n/static/e5f3c00f4b4662e82b0b40efb94e8ed3/27625/hero.png 680w,\n/static/e5f3c00f4b4662e82b0b40efb94e8ed3/40a76/hero.png 1360w,\n/static/e5f3c00f4b4662e82b0b40efb94e8ed3/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-22-tracing-llm-agent-opentelemetry/index.md","relativeDirectory":"2026-07-22-tracing-llm-agent-opentelemetry","ext":".md","sourceInstanceName":"blog"},{"id":"0713cdd1-bfc4-551f-aaf9-0d17ac90cbc0","children":[{"__typename":"MarkdownRemark","id":"fa22fec1-7895-5c1c-89f7-f1169b41089f","fields":{"slug":"/2026-07-23-query-rewriting-rag-retrieval/"},"frontmatter":{"title":"Query Rewriting for Better RAG Retrieval","date":"2026-07-23T00:00:00.000Z","description":"Short, vague, follow-up questions don't match how your docs are written. How query rewriting, multi-query expansion, and HyDE fix retrieval before it runs.","tags":["AI","LLM","RAG","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB+0lEQVQoz1WPa2+bMBSG+dCu2GAbjAHbmFsgkAuEpMqaNE2bLU2rrtKmTdq0af//h+ykUj9MenR0dPxeZMttVqQ94zZLp16wyXW1f8q2x/HDi7k5VPvncnfKb4+wFLtH0i6d8QBK0oB+ZTnUODTBrma8ELKN1KQbHtrZbb86NNPtYvVpvrif9XtYJt1OxE0oW8ZLTBIwWg7PSDhiUU2CkoYlTORl2M9sL0VeajPzNhPbMw4HQUVE4fIcXIDleMaTbZB0LGpIWHtRQ8MxRDCeeUHhi9L1Uz+sAt3xdOBm8OXM8TNwOV5qYZYI02fjrak+ZvVG5te+mlJRRqqRuo0lBBVZtRZmycWUyy5Il+AHF2bGQlQLNS1nu7Lfj/p9mC+ZqDBRiGmb6SsiHT/3VM91z5+++evPQdxBP5RjpqFZ21RdJDUu5ihtr9TI5gaLHO7nCFeSqBLtlnd3/o/ffHvy4zlPFi6YibIgW22Ow/e/sy8/h69/utdf2eGVrg9uM+C0wcUEZy2v1tAWxPNA9QF8W88RVYBlu3HQ3RR3z/nuNLp/Mdsj6za022AzRmqEdYUCg2niqbmn+zNyhliC3BgRaSESXznhJRKXWFwg8QEL+/wQo/dpu1Go62K8HE1ugLxe+CKHI7xCc2STN90bsJ8v/4OppEHKRAYTQO+af1+0SGyi03LaAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/16e70e892c537421cf56a7d2f5b2a2c6/40a76/hero.png","srcSet":"/static/16e70e892c537421cf56a7d2f5b2a2c6/c972b/hero.png 340w,\n/static/16e70e892c537421cf56a7d2f5b2a2c6/27625/hero.png 680w,\n/static/16e70e892c537421cf56a7d2f5b2a2c6/40a76/hero.png 1360w,\n/static/16e70e892c537421cf56a7d2f5b2a2c6/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-23-query-rewriting-rag-retrieval/index.md","relativeDirectory":"2026-07-23-query-rewriting-rag-retrieval","ext":".md","sourceInstanceName":"blog"},{"id":"1f67cf05-e75d-5407-b15e-f2ad2fdabc1f","children":[{"__typename":"MarkdownRemark","id":"60600e66-047f-5e6e-b249-94962f0e9774","fields":{"slug":"/2026-07-20-llm-as-a-judge-evaluating-outputs/"},"frontmatter":{"title":"LLM-as-a-Judge: Evaluating LLM Output Quality","date":"2026-07-20T00:00:00.000Z","description":"Human review does not scale for grading LLM answers. How to use an LLM as a judge: write a rubric, score with structured output, and control the biases.","tags":["AI","LLM","Evaluation","RAG","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABzUlEQVQoz22Qa2+bMBSGkbaFm23M1RiMuSxQQsOAXNo0ySZ16dRWUzd1lx+wP7D//3EHIuXTpEfW8TnPax1ZydIjkMpDmh7a5fP+7vd69W13+3Oz/r7dvN5sX4fhBWporoYXmexBO0cARbMilXDsZQ6v0qtVf/u56T/W/aFc7q66PRTvm5uq3dXd2KFsDib4kAIUZKfIltjNiFcQt5hhPsPhZQyFTmPkZKadgQkOmOBPpIpJkxFLwFnknxblU10+VsWpyI/L5iFJ1tQtdcJVwjTCz9oFxbDEGdNJYSU7qKhXOn6dJLu6eiqL+4lTVXxJ5Z1uxSYVl4hiUKHj0JF10R8deU0Xne4JDbMZ8pGfv0M+1G644MngR0uDJhrmhhWfUQwSmTgKymG+O8n24FdbGlfGuGHshjW2pYYYy7p6/cjz/vnY/rjv3PH1yCSRok8eDedO0gB2XBMvh+dniOGgVEmkosATrWxOcTH8+dr9/bVmLJ6h0LC4AjsDqhmohj9i+ipiDo2auNyWq0ZUthU50YIXG571H9p+aFvLjWEdSEGYnfMjZAQGFhVSXOf5IMWSUKGhwJi0t0b4RmdTckSBwX+AGXzkBNSXvo5HLtd/ha5G1wz7qLEAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/d98f85980960ee55fdf7a04ec405b51b/40a76/hero.png","srcSet":"/static/d98f85980960ee55fdf7a04ec405b51b/c972b/hero.png 340w,\n/static/d98f85980960ee55fdf7a04ec405b51b/27625/hero.png 680w,\n/static/d98f85980960ee55fdf7a04ec405b51b/40a76/hero.png 1360w,\n/static/d98f85980960ee55fdf7a04ec405b51b/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-20-llm-as-a-judge-evaluating-outputs/index.md","relativeDirectory":"2026-07-20-llm-as-a-judge-evaluating-outputs","ext":".md","sourceInstanceName":"blog"},{"id":"a11bc781-6320-58e0-8f2a-89204f87931a","children":[{"__typename":"MarkdownRemark","id":"3c09f836-0c8d-5a65-b841-63cd8aec67f3","fields":{"slug":"/2026-07-21-continuous-batching-llm-inference/"},"frontmatter":{"title":"Continuous Batching for LLM Inference","date":"2026-07-21T00:00:00.000Z","description":"Static batching leaves the GPU idle when requests finish at different steps. How continuous batching schedules LLM inference per token to raise throughput.","tags":["AI","LLM","GPU","Inference","Serving"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACIUlEQVQoz02R24/SQBTGB9gtnU47baH0Rjud0nIrd0hBWOgCsm4kqw9qVHwyMSaazfpg5Nk3TTbxf/awGxOTX85MvnO+OSdnUNLwgFbdXc372cXg8mK4ycbZYgBxvRzN02S9Gq0WA1CePZ0tpp1m7EJ9+8GFipQLNJD0KEqWreGmM9kBcXdV72ZxJ6sly2S8a/bX7eG2l17Ve5dYj6AeXACSS0wu+dQIIAqKJ1Bf0jyiQ/SJzgC4yLonyE4eV7EWUIND5QMMkVPOL4iearbb3SEPayJ1QfwfTL1BN1pMWK9hSNQmGnvUkax5SPR3MyN70pyOwg/PPcVoYuqCQVKr0DMvsW2q3x+zd/vGr7tWtprlihb0k1QPnROvxu37L7LtuHnswpwVltJywHxHt+Jz2Y+4+fszKVccJLiuH//5+Z7x+jlxiFZFBez2Wu60b1t8mgzmYWvm+zzkYaPZdoKOoITLib+ZVuu9zeX2utFd7jfddNTMCZasukhULLkUlqojgXJRi5AUHQ90lBiiVivbESqak3H/ePsSYS6V4oIS/TgoSVyBGSXVQbCAArbTAbt9pQxb+rfX5NMNzRUdrJhF2XzIOl8Pvbs3Sr+hf39LPu7VnOgQamPFRlix4NDK7tXcepGZm6kNqwLlH5ZE4SH7emHeZOY6tUX4y5MCLguJsomprZRZXgqAM5nTMoOGoANFUiGqoxpBgfCzUzZQDQbKY/YvtmxSHW735VsAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/588d887e7adcb5259d4fec21c98da32d/40a76/hero.png","srcSet":"/static/588d887e7adcb5259d4fec21c98da32d/c972b/hero.png 340w,\n/static/588d887e7adcb5259d4fec21c98da32d/27625/hero.png 680w,\n/static/588d887e7adcb5259d4fec21c98da32d/40a76/hero.png 1360w,\n/static/588d887e7adcb5259d4fec21c98da32d/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-21-continuous-batching-llm-inference/index.md","relativeDirectory":"2026-07-21-continuous-batching-llm-inference","ext":".md","sourceInstanceName":"blog"},{"id":"59c2782d-178e-5553-a4f4-e10fa4ff330f","children":[{"__typename":"MarkdownRemark","id":"8acf9654-8ff2-552e-946d-69fc7a56f48d","fields":{"slug":"/2026-07-18-semantic-caching-llm-apps/"},"frontmatter":{"title":"How to Build a Semantic Cache for LLM Apps","date":"2026-07-18T00:00:00.000Z","description":"Exact-match caching misses paraphrases, so LLM bills stay high. Here is how to build a semantic cache with embeddings, a similarity threshold, and its traps.","tags":["AI","LLM","Caching","Embeddings","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAByElEQVQoz13R2Y6bMBQGYK4awBuQDWOWYUvMFhLI0hQG0Eymrfr+D9STaZSqlT4d2b98DLYVQ1amrNi2FM0l7afoOmTTrXj7CM7f0n6EJOnHpBshTPop7oZ8uon2AuuhS9Gpi5inYsfxy2o/yaKr2zewya5FPW7LTpZduR+resiKrqyH3X7iolB1rmNXQZb/h24+qERoWCDDu0+hGr5m+oTHlCfUASlzEpgSO1Zg0T+ooH7K0pzYISIuMn1ketTfRON7dvsp33/k33+l083MDlbVKjpznxBzaShZ1Rq7I8v3RCTIgu97muVrPNJ5pH2CAeIxVGgWD9QhImZFS/yShJVRHFnV4LkP+Wr+0iRNuz2Cozzt0ybhcuNIuDDnAXMaZySuqTywr50V127WGG6CiSNW4Wt+HqormHZdX1zKoNgFpaJR/oBt7CWL08m+nNbXs30+zZujNvc0wlXKkeEiA27x/o9QsQnHFIpG7CedOTSrWN4w2bCyoZFkVoAgnIcvWR8Vr3E5ABisgoPpFNC8/guvNcaxF5Ngg/iLTmzEOOT3TRchW4LIWEZsEcITYNNXVLz6n75UteW94vUznKHFTL/78llnaAl+A8eDSl9/u1OAAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/6d3beb8303d887f41eb6c64e89f41154/40a76/hero.png","srcSet":"/static/6d3beb8303d887f41eb6c64e89f41154/c972b/hero.png 340w,\n/static/6d3beb8303d887f41eb6c64e89f41154/27625/hero.png 680w,\n/static/6d3beb8303d887f41eb6c64e89f41154/40a76/hero.png 1360w,\n/static/6d3beb8303d887f41eb6c64e89f41154/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-18-semantic-caching-llm-apps/index.md","relativeDirectory":"2026-07-18-semantic-caching-llm-apps","ext":".md","sourceInstanceName":"blog"},{"id":"2103589c-548e-5c52-8350-1c3926ce50de","children":[{"__typename":"MarkdownRemark","id":"1413df97-2cce-5e2f-af70-a96a59ca4742","fields":{"slug":"/2026-07-19-indirect-prompt-injection-rag/"},"frontmatter":{"title":"Indirect Prompt Injection in RAG Systems","date":"2026-07-19T00:00:00.000Z","description":"A RAG copilot reads tickets and logs, so whoever writes them can plant instructions in the prompt. How indirect prompt injection works and how to contain it.","tags":["AI","LLM","RAG","Security","Agents"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/0lEQVQozz3Q227aQBAGYF8Fn7B37fX5BMZnbDC2sLGBAklDaJuQNE0v2vd/kI6DVOnTamZXv0Y7lJRuUdRNmkuyf4t212j3Gu/f0sPPoH+BIt6/htvrrPuRHt5n3fP89MuuzijqpWQLKHZs3LGqbiVZ0adFB+KsTfJNPG+zokvybr7YpUUPr1HWLuuj6c4ZXucEC1BIjbAeIW0gqiH4X3CSz+EJi1wWe6xoM4JJ8waHbE7yOMmFk1InlRk0ul9ZwVqfVoZfO1FjhUMt6pmgBBxyhjnYE6c1jjZjLWQFc7hEDmWf/kwf/mrtVWleVLB+lquLVJ7l1ZO6/cDpnhEMXgtJ+YjjjTir5NUj8muGN1gIG8W9V1+M/KSmey07qMlODjs52AA1/YLcJfwQ5UcctySoSbjGfokW97wWMWOD0t3SnjWqsyRmIRs51jOsJTeKvRBln5En1uLU5v22OoK+6JPVA+8ULKdS2rS2wg2xl8QpibOUrAIbc2wOFK+Ctd0Jhl+dr839x+7b++777/brunlizIzhlM9w0H4mS+KWkr3AZn6jeCsI04ws+BVeHAU3ByhqYR2wCGasU8QuVG8lmTlAeoqNTNQSUYuBbBUC8WlehSHjSYnyAxCijTRZjcmU5hVqxBFAcwo0I25A3wwtgRPCYMRItKDBwBFLABRw+Q9N5FYZ2kBO4gAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/20d9039dc8bd069316ddaa58c83980fa/40a76/hero.png","srcSet":"/static/20d9039dc8bd069316ddaa58c83980fa/c972b/hero.png 340w,\n/static/20d9039dc8bd069316ddaa58c83980fa/27625/hero.png 680w,\n/static/20d9039dc8bd069316ddaa58c83980fa/40a76/hero.png 1360w,\n/static/20d9039dc8bd069316ddaa58c83980fa/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-19-indirect-prompt-injection-rag/index.md","relativeDirectory":"2026-07-19-indirect-prompt-injection-rag","ext":".md","sourceInstanceName":"blog"},{"id":"45d445f0-ee13-5589-8e9b-ca91f3621ed2","children":[{"__typename":"MarkdownRemark","id":"2cbf563b-f059-5403-b205-cf7a8cb3f986","fields":{"slug":"/2026-07-15-kubernetes-oomkilled-requests-vs-limits/"},"frontmatter":{"title":"Kubernetes OOMKilled: Requests vs Limits","date":"2026-07-15T00:00:00.000Z","description":"Your pod died with OOMKilled and exit 137. What Kubernetes memory requests and limits actually do, what triggers the kill, and how to stop it happening.","tags":["Kubernetes","DevOps","Reliability","Observability","GitOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACJklEQVQozyVRy27TQBT1CvKo52mPZ8avafyIHduJ4zgpdVxaSlsEAipaBAiExJI9S36ADbsKVPGzjEG6ujq6M0fnnnsM4fW6mOh8ddZs366am3pzU9XX6/Z2qfvmdlG9rJs3dTMMpX/iyE64/f8yxkiOoQB26AR5lLdpdZSvuqTc6q7xoumjYpvX+/mqixZb288BOxwBMYZyglzDpDNgJ8iZQzYnIoMsndLItOIDGk1xCHGIcAhQYLGYOYllR9SaYaIACfWrAZ2UeEssSyyXZXulFidIlMStsFtCqjgJHRIyHCwXj453Tz2eaqyHFAcT5BuAJcRdQp5jN3VUi2Q2ZTGWFZYFIGpgEkWRI/mMWxEyLQo9hyqCgzH0NDlFsqDuet/9uDz/83h/v9l9scMSCU3WsopAVqUfnp/9Pj++uzj6HquKIp8STXaNwbDMz/pfTfMNiiovXnx89cmbVYAXUGtCu0zfX/X3oagxSV9vP989u7aQp5UnQBoT4sbZu777+YAIHpTzNGNeVhQt/KdsIX7R3Xl8jYAdsFlse183J3M5N6E7BsIwLcVVz8M9cRe7ts3LDeAlDwfPJhrsKbdjJFh52WWySpwYYyWsQ4zckcn12rE+LBD5LD/eHJ2ud6d2uEayQrIEyB8Oi0TqZk+Suo9WjSo5Ha5IkDcymTFFvk4V2JE2P9HZWjFkiWnNTHo4NTmGUv+zSYCwBzWgOiRPy5pAPDxgfwFwmlj+1mWLqQAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/6399392464251e994ff9f039b0376535/40a76/hero.png","srcSet":"/static/6399392464251e994ff9f039b0376535/c972b/hero.png 340w,\n/static/6399392464251e994ff9f039b0376535/27625/hero.png 680w,\n/static/6399392464251e994ff9f039b0376535/40a76/hero.png 1360w,\n/static/6399392464251e994ff9f039b0376535/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-15-kubernetes-oomkilled-requests-vs-limits/index.md","relativeDirectory":"2026-07-15-kubernetes-oomkilled-requests-vs-limits","ext":".md","sourceInstanceName":"blog"},{"id":"8234cce2-fc09-5fb7-94fc-47b0e2ee7c33","children":[{"__typename":"MarkdownRemark","id":"ba2c0916-a919-5097-aa00-3813a628ae9a","fields":{"slug":"/2026-07-16-cancel-llm-stream-react-abortcontroller/"},"frontmatter":{"title":"Cancelling an LLM Stream in React with AbortController","date":"2026-07-16T00:00:00.000Z","description":"A user hits stop or switches chats and the old LLM stream keeps writing tokens and running up cost. How to cancel a streaming fetch in React the right way.","tags":["React","LLM","Frontend","Streaming","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3klEQVQoz1WQaW+jMBCG+bINhw9uY8CYEBKuhABJkzQ0afu9rbrq//8vO7DaSis9HtnjeedSSjlW6fM4fN6PX7fHr2v//jx8vJ2/Xx5/A/fZMw4fYz/xdvl+6t434glUgLKg4YJGQdqU/VgNt3x3WbeX8nhb7k6b7lr1t1VzzurTur1mzbnoRl9Wv3AAEkBBlgR0KgwrMcxENwW1s0G8HtLX0G00E/wS/NhOTTejToptiQArARWIpw/DFMiagAu25DLYr4LOdda6+Tep8FguRB2LuszagOUajcGpGGaMbSgIj/ifjTQa6TQGCxEQBx1iSzA3zXm+FUXoZyqZApS5YKKR8AedRgiykBhm02ho2yJjy1282YuiitarYOU4yZw9UqibkWmShDgSQHaikgBDn7zIo6JPmqPctaJuRTMkTSfqOqp8J9Uw10mowIEdUG+JXUnc1OdlFGyXQS/SLhFN7Jfchz5L7hVVdhrK+6F6iXj1gJhOOIg5tIpw5Nl57G9Dr3LszCDhQmdaItyucNuN0268rmSH2lyvVMQ0GGdGUTHjfiX5nnkFdKviADwINkRj5MUklITLyc4gX+g4RLBRDCmYoiJfx1zF/gNy4a2T4Cexhphq/Ic2l0VWDJEg/APzg0crJbqYnAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/0ae2d35eba94c6cf5e371bebd166c7f2/40a76/hero.png","srcSet":"/static/0ae2d35eba94c6cf5e371bebd166c7f2/c972b/hero.png 340w,\n/static/0ae2d35eba94c6cf5e371bebd166c7f2/27625/hero.png 680w,\n/static/0ae2d35eba94c6cf5e371bebd166c7f2/40a76/hero.png 1360w,\n/static/0ae2d35eba94c6cf5e371bebd166c7f2/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-16-cancel-llm-stream-react-abortcontroller/index.md","relativeDirectory":"2026-07-16-cancel-llm-stream-react-abortcontroller","ext":".md","sourceInstanceName":"blog"},{"id":"9f96cee7-ad8f-5611-b45e-b924eec36638","children":[{"__typename":"MarkdownRemark","id":"00c9b306-432e-57e1-8b2f-6d317675c0f2","fields":{"slug":"/2026-07-17-build-mcp-server-llm-agent/"},"frontmatter":{"title":"Build an MCP Server for Your LLM Agent","date":"2026-07-17T00:00:00.000Z","description":"MCP standardizes how LLM agents reach your tools and data. A hands-on guide to building an MCP server in Python, picking a transport, and where it breaks.","tags":["AI","LLM","Agents","MCP","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB5UlEQVQoz1WRa5OaMBSG+Va5JQQI4Zpwk5sIrLq64mp17NZ22+5+aP//b+mhznTamYdDMjxvDgckEu3v4GBrJ4fl/mex+jFffYeaDa/J8lau37L+Ne++5sO3cvNuidEId4RPEUnBgYoDBfvIEtQv6n4sl7tqua+7fdnu8uaxW38s26eqG7v1qelHGhTI4gryISWphAOaGROvZrwzvVq3c8XgqpUgVtpBo9O5aiYKOFZmuCU4xK1UM4aUpBoRoJkCvKx9FsWjwQrVCJGdWcEiWxzssNWtVCMRdoqo2CbVEzQAH1Lw2iGgGnyme4ifVaedBiFwsFBJQtLbnybTehrNW2F+hAX4kJpmhhtiDQ17JztbfKvTUqeVZpeILazkhJwGOfUELY1gZYoRBPBhbAkugISbdPUrar/Q7OwWVza/eOWVZWcnO1rpyYyPd+AsJz3R/Ir9QdFdSUaejHzsPTj5NWpe7PjZLy5R/Um0N6hecaHp0YoPAPRk+TlqPvv1C/b6mc4kWXenMGvceKiGE1SH916yZvGDHS7hF5h+8xf4hEwMjhgwW8y0Kcwgj92Wik1UjGY4UL520x1sDb8jQf8v96c234Ava1SaaQ4g41A2+AcUKYZQMJdxJGOuEDFt/we0qeJwptHfhjlOGA/Sx+sAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/fb69a747f6e4288dc2aab7f5ef430139/40a76/hero.png","srcSet":"/static/fb69a747f6e4288dc2aab7f5ef430139/c972b/hero.png 340w,\n/static/fb69a747f6e4288dc2aab7f5ef430139/27625/hero.png 680w,\n/static/fb69a747f6e4288dc2aab7f5ef430139/40a76/hero.png 1360w,\n/static/fb69a747f6e4288dc2aab7f5ef430139/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-17-build-mcp-server-llm-agent/index.md","relativeDirectory":"2026-07-17-build-mcp-server-llm-agent","ext":".md","sourceInstanceName":"blog"},{"id":"82e57f30-7aff-5c41-ac7c-7ffd1d836a61","children":[{"__typename":"MarkdownRemark","id":"b5978d2e-ba20-59fe-b99c-c408050cd62e","fields":{"slug":"/2026-07-13-streaming-markdown-react-llm/"},"frontmatter":{"title":"Streaming LLM Markdown in React Without Flicker","date":"2026-07-13T00:00:00.000Z","description":"LLM tokens arrive one at a time, and re-parsing Markdown on every token flickers and drags. How to render streaming Markdown in React without the jank.","tags":["React","LLM","Frontend","Markdown","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4UlEQVQoz02R6W7iMBRG8zN4N3EScByHbA4hLAGGpYWyqHSqvv8L9TKVRpWOPl1dfedKTjzi1rRZE9fjejV5eS/Pf/PXR3H6qN4+i9PD7K/15RM2ze3LHu6oWlLXU7d+Wm7tYWYQ0VxmQezq6X6+epstTt3yDNnOX2HzM/w5fMBSxU4EOaIJWICHh5aogutWxA0OChJWNKwgiSqB56wqPMx8bpC0LMxJMAHlH5mHecJGTdKdTbWLJ/1Qd3I8+80wmfOoJjLFwiBhsEj/4w1YwlRl3aHoznn7GiTdUM/gxA9PWXcidlCFpk+1zzTi5nmIG5A1C6s43yf1OalPdnq17dW407jc6/IY2l7qGQ9rGkGnz9ze1jtlFqAgnngDOoZJmS6yczlyNCyfqJyonKoCko8aHlZCt5PFZbp5NOt3257EuEV07Pk0BlmOpirpAt3C83hUPTOuQYYr8CGhQKTFIkM8xdLS4QQLO2Agk4ipUuWbqDrE9XHkjuPmJSy3waQXpgNkuoACkgmJMxJlvtTAAKAjb4BDaqbp9T273O3lri831m/ZagPwfsv7jdgciJ2x5Sr/+rCPm9ptwpcdnc99Ens+DpE0zDYsdQBNHTH1b6hx8IdQbHnR8MLJshVVi3QO4jdXbk0MRLGiNgAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/7fde826b4ceb97a0223355de964fb9fe/40a76/hero.png","srcSet":"/static/7fde826b4ceb97a0223355de964fb9fe/c972b/hero.png 340w,\n/static/7fde826b4ceb97a0223355de964fb9fe/27625/hero.png 680w,\n/static/7fde826b4ceb97a0223355de964fb9fe/40a76/hero.png 1360w,\n/static/7fde826b4ceb97a0223355de964fb9fe/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-13-streaming-markdown-react-llm/index.md","relativeDirectory":"2026-07-13-streaming-markdown-react-llm","ext":".md","sourceInstanceName":"blog"},{"id":"ac69b43c-f042-5d75-81dc-dbf9e61360ea","children":[{"__typename":"MarkdownRemark","id":"a41767e3-70ee-5b7c-a2bc-ed563e723851","fields":{"slug":"/2026-07-14-reliable-json-from-llms/"},"frontmatter":{"title":"Getting Reliable JSON Out of an LLM","date":"2026-07-14T00:00:00.000Z","description":"Getting an LLM to return JSON is easy; getting valid JSON every time is not. How to use JSON Schema, constrained decoding, and validation to make it reliable.","tags":["AI","LLM","Structured Outputs","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAByElEQVQoz12RW4/aMBCFs2hhA7GdCyHO1XbiBAgJNIE0yyIQsCtVVaW+tE997p/pQ5/6izskq6220qcja3zOzFhWCi57jlVzbffXj/vn9um8a18eD8ClaY/V7tI8nqrm+GHX1091s2IJRJSRzh50BurFVb69LOvLojonxWFZnfP6AoekPEAxWZ9Evk/Xx3x7jebNkESQUpDJeiZ6CIz1EE1jgy4MJ9OdFNRy5ybNXDfF01glQYffRxTNiN7oS2CKsy1PaxqVNCpcVlBWsDDDVmw60pjFyOK9X+kH3maSgNixPkuQGXl+6riS2BJZorsN1G4pjxW2N0cm7yMQDl6BZSwYy4fwGMzvCLvD4QCzoc41k2ngxv5oQlXkTTCYbxEFMm9oRgBrp4HYJbJO0g3nteBbwbHho2mkRQkRqRYIYGJH0EsZE6+ny3uaxX+2iz9f1r8+lb8/g65/1HPLDBzK5KZcNVuRL/xMmh5TsauMsfvKLe9NjPBJiu8b+bWQ39byZREPxhSubDNYOaL05JLGiRXMDL8P0/+AP783+L3OBwQezMyZMGxBbIGmfKQ5I0QfsKt2TkVFzjuwoxEX6S66KYXzu9YI9J/5LxqzRjEZv3uyAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/c4ceb8e65853708427d78040856e38b7/40a76/hero.png","srcSet":"/static/c4ceb8e65853708427d78040856e38b7/c972b/hero.png 340w,\n/static/c4ceb8e65853708427d78040856e38b7/27625/hero.png 680w,\n/static/c4ceb8e65853708427d78040856e38b7/40a76/hero.png 1360w,\n/static/c4ceb8e65853708427d78040856e38b7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-14-reliable-json-from-llms/index.md","relativeDirectory":"2026-07-14-reliable-json-from-llms","ext":".md","sourceInstanceName":"blog"},{"id":"9fb66a37-9a54-5e90-94cf-ecbd40e4c189","children":[{"__typename":"MarkdownRemark","id":"32ce6b7d-30eb-52d4-aba7-70e05e325d44","fields":{"slug":"/2026-07-11-llm-api-rate-limits-retries-backoff/"},"frontmatter":{"title":"Handling LLM API Rate Limits: Retries and Backoff","date":"2026-07-11T00:00:00.000Z","description":"Your LLM backend returns 429s the moment traffic bursts. How to retry with backoff and jitter, respect Retry-After, and pace fan-out to stay under the limit.","tags":["LLM","FastAPI","Python","Backend","AI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABvElEQVQoz22Q2XLbMAxF9WQt3EktpERSu+TYdVwvrSeebE7+/58K2X3MzCHmcoBLEAieJrsBZjf15nrZfn+er5dfry+7z7cD8Pby/NC3tyPE9+v+fJjWYwkWMAYrWoe0AUD48fJ0+Oq3r8D6921z/F7vb8P2fXP4Gncf0+5j3t9Md1qRGgBLgKUj0i+oGgkfMou4S4SLuY2ZTRbtE9Dc4qLDqlFZy/Oepg2WPoDSmJYhNhGtuPA266SsU9VI1UAKMUuEp3ekGXnaclmzfIBXEmYDOFW7Gzd/lZnytJ7tAA2pcEL6wY5zs9V5K6VTyj/ignTatFR5MFci7zI7c9WKesr3zwgbqhyipflzEkWLhQUQt0hYIi1llenmbJgRKYOEljExEdYAjIqzJqEVfAexCmVNDHHhfr0LqE+Ux2mdgDmmJsR6gWjJqiZzLNVcwQpKSP1IRHSINLQMoKFvBuuHiJS5bsZ+TEhW6pzxggqNmVng5r+4a55a51umqiAmBVOOZzWF2UxbHLf9rtuchvV5KnsfwyzMLNBH1FhaYbq0GmAv0DlfJRkQoixCeZjkLK2KyqfaRbiA7A9AGVrEPzB4P5h5opdNAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/30ff3f68b1dcfb1160e7300152411747/40a76/hero.png","srcSet":"/static/30ff3f68b1dcfb1160e7300152411747/c972b/hero.png 340w,\n/static/30ff3f68b1dcfb1160e7300152411747/27625/hero.png 680w,\n/static/30ff3f68b1dcfb1160e7300152411747/40a76/hero.png 1360w,\n/static/30ff3f68b1dcfb1160e7300152411747/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-11-llm-api-rate-limits-retries-backoff/index.md","relativeDirectory":"2026-07-11-llm-api-rate-limits-retries-backoff","ext":".md","sourceInstanceName":"blog"},{"id":"61939c80-9d8c-5373-848a-d0ccf18bdbc5","children":[{"__typename":"MarkdownRemark","id":"8a72594d-1c63-59d4-8297-7642f0c60106","fields":{"slug":"/2026-07-12-llm-kv-cache-gpu-memory/"},"frontmatter":{"title":"LLM KV Cache: Why GPU Memory Runs Out","date":"2026-07-12T00:00:00.000Z","description":"A long prompt or a long agent run can hit CUDA out of memory, and the KV cache is usually why. How it grows, the per-token math, and how to shrink it.","tags":["AI","LLM","GPU","Inference","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB2UlEQVQoz0WO63KbMBBG+dUA5qogkEASMverb6FxYgjGaTLt+z9R12Y6nTmjWe1+ZyWlEV0j+lb0VVSf6/NtuI27aRlu8/G6vCzT/gOuH4cZ+tfTchs+T8VQsQbyICo/bP70wAzyMDtl/Zh27/VpSbtLvpuy/gIFNPPdWB7mbvik6dHAGeRBVAxXrFjPWwPFG4dvXPFkRaoVwak7HEbQgQLQbLZBMcTWvnJPPyoTumvU4Zw3Iu622x4FGawwHhnAQTHzU+ZnAU7AV3Sb6XYEAynaRDQIbzUrIkEW8zaJ4btHGaSWK3wvDrDwPOFhiX0JJ/xCeZjM8qRqR8hmDS3GpPtdHOe0/y52X2XHCSMBIyH3I+6HMoxzJvNQZJoVKppJTZcjPyvLw9d0/TMt03B52Q+n/dC1Q1IcnLhGsrF5bbDaCguHpm6YWVjqJlU0i+p2aCLB8jfRz0E94nwkxUTyO7SYwnIKkjccD748O0GlGgG8BxYALxO461boxYMnXrH4ycpZtr9EfYWC14tobiS7ePLVT94dUt9lMME3CciwCWSKaIXCBnBI5dLGizqP9c9Ra5PSJRWiNYxsnGqGvyqAohr+ytMGr6gbb+NQEzELcdONVAP/H/0Lr/wFUNZLWBRwh3EAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/3532ef527ffd15a7acd37770357c598c/40a76/hero.png","srcSet":"/static/3532ef527ffd15a7acd37770357c598c/c972b/hero.png 340w,\n/static/3532ef527ffd15a7acd37770357c598c/27625/hero.png 680w,\n/static/3532ef527ffd15a7acd37770357c598c/40a76/hero.png 1360w,\n/static/3532ef527ffd15a7acd37770357c598c/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-12-llm-kv-cache-gpu-memory/index.md","relativeDirectory":"2026-07-12-llm-kv-cache-gpu-memory","ext":".md","sourceInstanceName":"blog"},{"id":"e38dca35-c77b-512a-805c-a96ed42690be","children":[{"__typename":"MarkdownRemark","id":"e0b07ce6-e8fc-5bd1-8029-6f8039c2ca11","fields":{"slug":"/2026-07-09-hnsw-vector-search-explained/"},"frontmatter":{"title":"How HNSW Vector Search Actually Works","date":"2026-07-09T00:00:00.000Z","description":"Every RAG stack leans on HNSW but treats it as a black box. Here is how the layered graph index finds nearest neighbors fast, and the knobs that matter.","tags":["AI","LLM","RAG","VectorSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB60lEQVQoz1WR2W6bQBSGuWlihlmYzWyGAduYMWCb2E4cF2ibSr1JojR5/5fpIbmq9OnXz4Gz4gjb86qX22EzvNnxvezfVtcX8MvrK/hqfAe/ur7aHx/bnx/V+FfVI7e9+MRBNEYk9lhid9f2MDT7vt5d6/Zx2z7a5gK6O/Rlddo2l3b3fWPPHokQmoN6NHE8YQDEU9dPkZ8hnlG9JFFN4wYgUfPlJwMatyw9CDvQyHo8c/LymC47qgrMU89PMc+C4k7VT2IziE0vyn4y1SCrSafI+irsSOZrjy0cKnPIZKpA/gKxBVVrokqi1kyXPKyZ3lC5+g9eYGGwLBCMzVRORDaDTVjySQzN/ahm4RaUx41snmT7G3pKO05Ug9r/YYsWkcjJVl263PMAqhqXRFBVxDs/rAERtz6QdgxWBaIGoFGD1colIVza+Yb0jRdAQ3hwKSTnMBILrB81MtlJc+Jp58+tH1geNRBkwZbqksglfAyd94mpPX8aGOq5OIB3KjvPi4s2Dyq/hHfPYfes7S9h7qd4ftH5A5a5SwLY2fg6Z9J4kIzncDBl7nV2VtlJGdCzNvfBZgyPL6Z90ulRpkf4STOsp+QbpIBbT99iPcPB182+jufSmOkiXnfJqsMULhoneYN5cuupGQlmeP4PTIRMIYsQN60AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/19f8cb970a43134f4a3f984c45f292f7/40a76/hero.png","srcSet":"/static/19f8cb970a43134f4a3f984c45f292f7/c972b/hero.png 340w,\n/static/19f8cb970a43134f4a3f984c45f292f7/27625/hero.png 680w,\n/static/19f8cb970a43134f4a3f984c45f292f7/40a76/hero.png 1360w,\n/static/19f8cb970a43134f4a3f984c45f292f7/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-09-hnsw-vector-search-explained/index.md","relativeDirectory":"2026-07-09-hnsw-vector-search-explained","ext":".md","sourceInstanceName":"blog"},{"id":"263161ad-a85c-50d1-99d1-ea84df4c3cad","children":[{"__typename":"MarkdownRemark","id":"4d38fdf2-a5e1-5a29-9e92-2a8df98b7b8b","fields":{"slug":"/2026-07-10-fastapi-blocking-event-loop/"},"frontmatter":{"title":"FastAPI Event Loop Blocking: Sync vs Async","date":"2026-07-10T00:00:00.000Z","description":"One blocking call in a FastAPI route stalls every other request, including live SSE streams. Here is how the event loop breaks, and how to keep it free.","tags":["FastAPI","Python","AsyncIO","Backend","LLM"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4klEQVQoz1WRa2+bMBSGkdYmBHzBGLAN2JhAWEISAgtJk3TT9mnStK3t1P//X3aSTtMmPRz58j6cI3Bs8fEvRl/63fdx/wzs90/97sfh8Gvcvwz9z8P4fHp4hVutL9b8yTsuTYEpUTi2gayb7XnZP1ab02J7brozbN9353r90GxP7fBYtcdAVCS2b5aDmEGsgIp5SaK5Fxgv0CSEQ42v1QI+ux7OaO6zAjI4tDfLOH6gAXTDpxnIqSovnR5WeWMVi2rK61isg2hBwrl/y7wpgOPRfEKyCc7ucYpDSDQoMCTMAY8ql6gpkTDFjJjS2MOm6FfG5JlL4DYHOatk2eb1Si925aZJS8I0jESCeSaGIj1moqdsPiOK8jQRqVKWx3ZGUhAdQrNPZfU09K/j+DJ++No0x3Jd5Usd9W3xZd9+a+3nLBr8IHNxeueriZ/yqPVAJqkDj4n0UtmNXnR6WcY5hmmxCliV8FbwTRKtobOLJWGKx2DqkBewhVmcGZb3SN4h8c5LEKsQg6+S4UB6JPapcLFwUTL146mvSq3PnWkrqVM5RRJEkIV3BdISFtBTJHps9aGbt7UJo4rxSog143NEtYuki8S1LRaAAy/+B3GrMeN5Ii1PCsIt4QXlBfx5Fyf/h5Pf8EtEs8CjTlAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/1e4adbb579bee59ab351a70e64eaa51f/40a76/hero.png","srcSet":"/static/1e4adbb579bee59ab351a70e64eaa51f/c972b/hero.png 340w,\n/static/1e4adbb579bee59ab351a70e64eaa51f/27625/hero.png 680w,\n/static/1e4adbb579bee59ab351a70e64eaa51f/40a76/hero.png 1360w,\n/static/1e4adbb579bee59ab351a70e64eaa51f/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-10-fastapi-blocking-event-loop/index.md","relativeDirectory":"2026-07-10-fastapi-blocking-event-loop","ext":".md","sourceInstanceName":"blog"},{"id":"eef1d96f-4352-566e-b281-21707f6b9596","children":[{"__typename":"MarkdownRemark","id":"8ec3862c-86da-53e4-97ff-f1494db5c70d","fields":{"slug":"/2026-07-08-cross-encoder-reranking-rag/"},"frontmatter":{"title":"Cross-Encoder Reranking for RAG Pipelines","date":"2026-07-08T00:00:00.000Z","description":"Retrieval puts the right chunk at rank 8, but the generator only reads the top few. How a cross-encoder reranker reorders RAG candidates, and where it fails.","tags":["AI","LLM","RAG","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABzElEQVQoz4WQ6Y6bMBSFUTWZCTvYgLGNzb4kEAgQMglJJn3/p+ptRqpU9UelT9bR9TnHi7IT6bLrvsblMZ7WYboN07U7Pqfz2k9rP8LwfpyB60sDz/lzqvZ7mbVxrmwsYQYly0dZLbI+18dntl+r4Rk3l7y718efxeFe9g9Y092F51NUzBYpIfVhS0V3IsMVuisMV1peAkJ3XrgSJiA0V25NrsMZKNFs2JKmG+v2b79iegXNTsnuxvOFZYvHDwZKoPG7QnOEZUcsK+g65etS3M/xdSZjZ/IU8orLOtncw3R2aYtYh6MB6lSLaXak2pGFBPejKG/E+Sa6mdS9V3aobG1ZqRZXHLoXzYMkJxwdPTECJs5eYW7YXBBpOEzDKc+vtLhgPkA7eODZ4FHcoIybG00mzFqPd4CJJGyE2D+lZE5DirEB4fLKy0/EO8RaFB0sL9NMqhh+FRZ3LCabHhzWA/BDGyMMMJOEOy41HQpdBoqdILf93A4K0JrNVIsqBY+/+nYoq1rKWohGSh9z5NLQ5+9G+GGEWzNUv7Go+ke/UBgmO8ELmcSUyZAyzw8Q8RD4yN+E/2rlTQ9+aORNIxs9hNu+6eRdDzZ6sDX+zy/csEbw2u67jwAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/8653045cf4c590d50d2952d56a05590d/40a76/hero.png","srcSet":"/static/8653045cf4c590d50d2952d56a05590d/c972b/hero.png 340w,\n/static/8653045cf4c590d50d2952d56a05590d/27625/hero.png 680w,\n/static/8653045cf4c590d50d2952d56a05590d/40a76/hero.png 1360w,\n/static/8653045cf4c590d50d2952d56a05590d/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-08-cross-encoder-reranking-rag/index.md","relativeDirectory":"2026-07-08-cross-encoder-reranking-rag","ext":".md","sourceInstanceName":"blog"},{"id":"5faa4a10-cfdd-5192-9ce7-b9bdea035306","children":[{"__typename":"MarkdownRemark","id":"c1b3b49a-40e4-5afa-b165-1c2860df69db","fields":{"slug":"/2026-07-07-kubernetes-liveness-readiness-startup-probes/"},"frontmatter":{"title":"Kubernetes Probes: Liveness, Readiness, Startup","date":"2026-07-07T00:00:00.000Z","description":"Kubernetes has three health probes and mixing them up causes outages. How liveness, readiness, and startup probes work, and the failure modes to avoid.","tags":["Kubernetes","DevOps","Observability","Reliability","GitOps"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABxElEQVQoz22Ra2+bMBSG+dQAvmBuNhgb43AJhGxJadIko+qSTfvSpZOW//9j5oQP06pJj458fJ7XlmzLl0cDEQdWvq4O12r9tnz+3Qzv9eNltb+221/l+s20zXDpD1fjGHOKGCzXywwO5iFvuvXYff7Sb8b207HfvCw342Z3qrpdvx6b/nm1eaHZwkEpuEdMtWBQwEC5RIJAAT93iXI8eYPkU3V9ZZN85okZFiAsQFAAX01YKkv3fXLe6m9bva4pZcLxFPRzMOEpXGu2bYrXQX8d6FBjXQByHxFpUcYbLVaLed9onXM/kq4ngS+nsfGQLOJukfRL1ndx2yCugBGI0YRlY/EAxVRnWNoux1Xn4gwwjVTtQo7nrdkEsrZhZhY2ymxPuDcyCwfCj0QQS3NnGItAlvHPM1muwv0u/j7iuqOXk1e18Y/Rf3oMeCmpppG6hTE3r83B/ekmzHlINyAqQFpCUYEgx+XCJQKJEvK5+RQa5qUZeZmNU8vB6T8ghuIu7c7103s1XJL2BMPGQYkD76CbM89qTDIbMhNOPobpIlA7Vh5ZdQjUFsbVLfzXSeypRcyyIf0IiGcgenBDwwzEpv2Pc+cP/rZDcQAr9q4AAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/cfd174a30e720a223f3e3720fedfbc48/40a76/hero.png","srcSet":"/static/cfd174a30e720a223f3e3720fedfbc48/c972b/hero.png 340w,\n/static/cfd174a30e720a223f3e3720fedfbc48/27625/hero.png 680w,\n/static/cfd174a30e720a223f3e3720fedfbc48/40a76/hero.png 1360w,\n/static/cfd174a30e720a223f3e3720fedfbc48/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-07-kubernetes-liveness-readiness-startup-probes/index.md","relativeDirectory":"2026-07-07-kubernetes-liveness-readiness-startup-probes","ext":".md","sourceInstanceName":"blog"},{"id":"06b2e044-2c4d-5f7c-9b71-d50a968a3401","children":[{"__typename":"MarkdownRemark","id":"b7c780b8-1b71-59d0-bfd4-8a159a78b751","fields":{"slug":"/2026-07-06-chunking-strategies-for-rag/"},"frontmatter":{"title":"Chunking Strategies for RAG Pipelines","date":"2026-07-06T00:00:00.000Z","description":"How to chunk documents for a RAG pipeline: why fixed-size splitting fails, structure-aware splitting, size and overlap tradeoffs, and the failure modes.","tags":["AI","LLM","RAG","Python","FastAPI"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4ElEQVQozzWRCW+jMBCFWa2UJtwYsPFNuEsMOVvlJDTq7v//SeuQrfTp6c0bjWckGyvRtVx16frP8e+4f5z7y3V9u+/HYXu/78ZxP2q9boZx/zVsh3N30eXj46Fk3wplzDyuWfiCl5uyOxfqXHSXan3N1Kla3zRFr/253g71ZtAtUR9Itp77YuYxww6EDcTM578s/Nsmpi4DaQVCY/rc9Lg2DpA6fGE9Q/ZKDO28uNgVh2P5+Vl+oKSx49KFpe2zimS9bHKU4gDTkLKQUkAIIGzyKOTGwqVeXO7VeOofx/4hyyNcHlzUwJDLJCNccdlhvopgDqIU4oYJFSW17uqH9GYSwpK/D2I1ytVY9t9ZcwOoDgGXIUsCliVZTascZTlaVrRqeU1CwQFlgBqmi72kEuqe9l9PupHUp4C0lkeoSFmacg0XhDLKuFZCKMIE68OhPttJ3Dhn0+bncvVFypMHayuioMqJUhqQFS4TrpCeTD0hfZE6jNiEGAsbuVFOqzOrL6y6xHLnJe9uVOphP80i0cZLRdsdaTa42XB1SIoeLrtALl2mhx1o+sxHFcANwHWAqiCp9ectHGRDYkH8H/RU80WcWIiYETbmNpzb8QR84sCfBM5NOLcmTPhm/ZSTvk36DwfTTb+Bu/4VAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/5ce2db2f91119d288617245a689490cb/40a76/hero.png","srcSet":"/static/5ce2db2f91119d288617245a689490cb/c972b/hero.png 340w,\n/static/5ce2db2f91119d288617245a689490cb/27625/hero.png 680w,\n/static/5ce2db2f91119d288617245a689490cb/40a76/hero.png 1360w,\n/static/5ce2db2f91119d288617245a689490cb/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-06-chunking-strategies-for-rag/index.md","relativeDirectory":"2026-07-06-chunking-strategies-for-rag","ext":".md","sourceInstanceName":"blog"},{"id":"d413f1ef-d24c-5286-8a81-e1fa8c327b10","children":[{"__typename":"MarkdownRemark","id":"5b2e4ab3-0a82-5ed9-9f56-50277f24b352","fields":{"slug":"/2026-07-04-measuring-rag-retrieval-quality/"},"frontmatter":{"title":"Measuring RAG Retrieval Quality: recall@k, MRR","date":"2026-07-04T00:00:00.000Z","description":"Changed your embeddings or added a reranker? Measure it. Build a golden set and score retrieval with recall@k, MRR, and nDCG before you trust the change.","tags":["AI","LLM","RAG","Evaluation","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB0ElEQVQoz22RyZKbMBRFWSSxjUGAmBGDGCSQ8YABt4fGbne7V51NKv//MXnY3iSVqlO3jl69u9GTFjwUPKzL6PK6eb+0w3EF+XpYvg3NddheThtIGI5ybs/HlWDkUYGUJohOUDLVKK1OfH3N66FuPxftjS0vYvtRNcB7Kk4wh2fEXr4r8aMCKc31UNbIPUNZH5khMqb2zCkK5PvO7C7PfSNScCwhOzeDSnMKxcwA1cphojlMNamCE+xX2C8VnOouwx4I1V1uEaGa6VyPJDvesOYjZHs7brysJ8U+KPYO7aCP7CIojm62R66wk85KdqotvGwX8AE5QkZEMoggZU/rgXDob61oY4ZrJ201l6kW86lgJfdjYUeLvs1pXiGvXtSMZsUPJZCsQMS8D6ujn/VGsNT9GoCyYnESpT+v+dcla5v8bV/8/qTNqjh0/Nct267Sb/JYLtPqJaqOQd5jsjSCGnCzDjnM8LLmzOsD1/3F8sDWFxAhOt7eSjNkE8WTjEB4vPeLHYDDNSYjTtppdgGfp6e9Tlsoa8nWyHoQPWn1fKd51Uxx4FTw6cm/mFQeT0UQpggncBgVJ+DKU2ASzlRHmszt/zJVnIkCYt15DP8SWPgD0OJOKSmqTUgAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/9561657ff6fc95d7f80513b82185e1c1/40a76/hero.png","srcSet":"/static/9561657ff6fc95d7f80513b82185e1c1/c972b/hero.png 340w,\n/static/9561657ff6fc95d7f80513b82185e1c1/27625/hero.png 680w,\n/static/9561657ff6fc95d7f80513b82185e1c1/40a76/hero.png 1360w,\n/static/9561657ff6fc95d7f80513b82185e1c1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-04-measuring-rag-retrieval-quality/index.md","relativeDirectory":"2026-07-04-measuring-rag-retrieval-quality","ext":".md","sourceInstanceName":"blog"},{"id":"29c7aa6e-ef3c-55cb-870d-5d2f49de468d","children":[{"__typename":"MarkdownRemark","id":"d6031681-282c-5d5f-8d8c-67462fea5b86","fields":{"slug":"/2026-07-05-sandboxing-llm-generated-code/"},"frontmatter":{"title":"Running LLM-Generated Code in a Sandbox","date":"2026-07-05T00:00:00.000Z","description":"An LLM that writes and runs code needs real isolation, not a try/except. How to sandbox AI-generated code with E2B microVMs, and the failure modes.","tags":["AI","LLM","Agents","Python","Security"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB4klEQVQoz12R627cIBCF/a+xvQzY+I4BAwbfN46aKNkoyW6q9v1fqWxWUaVKn0YHNGc4GgIybsm4kWFFdqr3J/f+OV5+69cPX9XLm3p516f38fxr+fyTrTu4mYzrtf/LFcTAI9QmeZ+VY83XYT6t+4ebTtt+9trNp2F5PT5cjvulYktSWKA6PLQR4t4YxIkIcXugHeQKZSokwte0HqDow4SHiYhSGRJ+53tyhXMFVEIqD6mMUxFkzaTH54KvlC2Q91cyg4g8UFnez+U6gO7yZWT7DKazwjyr8ciUzK8Tg6Qahv1ij+dc3Cf1QuoZKotFj5hKV0NGgSRLJkM3jTRTTL613QsTPGt93gAXttaPjXkq5ANlW9qsmA20H7CyYCUSDXYaegWGw9D1XH1wc+6syuUdsICUrlaPrH8s5E7qJW02SHUUVxFuUudSZ0FrYno6WDCmkEb2jitDSxmiJoDC0tY/OCX1RMqRVJNfmHdGlBWby0cNsqWzrTaHu9anyI8OWxE3PET1NXbOt8b8bPSVrF3Bm1EdJQ2eFZ47UD6wFxK6Bqwiq8K2RU0bHqoAUYUL58Pf8Np/Q4iqKKn9nkFy7AyoDkSLrQatQHBsOtSKMC6Cu0Ph+RHnN27Hb8ov/tP/Lv8CCRJIesEq3/EAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/276b514ff6dac30102034af9dd35cc27/40a76/hero.png","srcSet":"/static/276b514ff6dac30102034af9dd35cc27/c972b/hero.png 340w,\n/static/276b514ff6dac30102034af9dd35cc27/27625/hero.png 680w,\n/static/276b514ff6dac30102034af9dd35cc27/40a76/hero.png 1360w,\n/static/276b514ff6dac30102034af9dd35cc27/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-05-sandboxing-llm-generated-code/index.md","relativeDirectory":"2026-07-05-sandboxing-llm-generated-code","ext":".md","sourceInstanceName":"blog"},{"id":"126658ab-f991-54b1-905b-3c09ec430de0","children":[{"__typename":"MarkdownRemark","id":"78d1a54e-bbcf-587c-85db-82427cc13cbd","fields":{"slug":"/2026-07-01-opensearch-workflow-monitoring/"},"frontmatter":{"title":"OpenSearch Dashboards for Workflow Monitoring","date":"2026-07-01T00:00:00.000Z","description":"Build an OpenSearch dashboard that watches a job pipeline: structured logs, an index mapping, the queries behind each panel, and alerts that fire early.","tags":["OpenSearch","DevOps","Observability","Monitoring","Kubernetes"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACD0lEQVQozyWQx47bMBRFtfJYtkV1iU1dVqWaLTu25CJkCiabAMkmi+zT1lkHmK/Jf+TLQs8ABwcX7/GCBIVV0nGkpPOP78PhIbk8R6en6PTI7Q/3yfUD7s888Al3OD7S/RV242rd8oqwBPSGRByvKqpTvZnq7pqzoWov3GV9SotD2ZxZcy6qMa/GrDxSl4krzFvCUvOWqisCOpfpggfFWSjuGzzfAcLNV5zbSnX5+VffEBYyNQiLyguJd7KdarjUcGE4jU4rFWVBPnrZ4Oejnw0k2il2ztFgaZJGNhNBXGKz6IuXn1awhf5+BdnMqBTCJFSoMDdoc4PUptsafqf5jRZ11naEw2Q0O0EUobk5pH9/B/2X67d/fVt//9TbtImCDsBcTzZ6ujXY3mwP1m6E5yu8TnCa0MO90e35zVCPm+DrR5Lfl08vu7b+8bkvwv65Hpb2Wo9aLWjkN7waOBVHdirFqQFMBRFAyYhViykwlXRvZWYzJQYol3GpWAmwEl0PEitcwziG8RqtuV3T90wf6a4wW9p+xKbLCYdbg1Y6rSVrzdJDlh1lXKm0IWZ4oPEpZh2N3vnZPsgTywk1FOpUmK9sSJMiZ8hjFi01xPhDqNsit1X4n+HKMoJf5f5PP21InOKwIGFsOrFOgteyNZfQnYS5RQktALc955bxLQM+gaaMDRlrClZlxFEA1GQEAPwPi4NYmDI7eDAAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/9c33da952bb8f40f57c05eb37a28efb1/40a76/hero.png","srcSet":"/static/9c33da952bb8f40f57c05eb37a28efb1/c972b/hero.png 340w,\n/static/9c33da952bb8f40f57c05eb37a28efb1/27625/hero.png 680w,\n/static/9c33da952bb8f40f57c05eb37a28efb1/40a76/hero.png 1360w,\n/static/9c33da952bb8f40f57c05eb37a28efb1/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-01-opensearch-workflow-monitoring/index.md","relativeDirectory":"2026-07-01-opensearch-workflow-monitoring","ext":".md","sourceInstanceName":"blog"},{"id":"3ea41e2a-a0af-5382-8739-89376d4414cd","children":[{"__typename":"MarkdownRemark","id":"c9272a05-b97b-5fec-a63c-586853b48c38","fields":{"slug":"/2026-07-02-hybrid-search-rag-bm25-vectors/"},"frontmatter":{"title":"Hybrid Search for RAG: BM25 + Vectors","date":"2026-07-02T00:00:00.000Z","description":"Vector search alone misses exact IDs and error codes. Here's how to combine BM25 keyword search with dense retrieval, fuse the rankings with RRF, and rerank.","tags":["AI","LLM","RAG","OpenSearch","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB40lEQVQoz02PWY/aMBRG89LJQpwEKAnxTUycfSGELANMYKCqAKmsbacPfen//xs1g0pHOrqyfb/ja3MmrAy8pP52Wv8sqh/Z5DwuLvn0ytZ5cWHbsvk1Kb/fDosry2STS9m8jehXZnGSBoJqagalcZlM22S6TIo2mryk5Wpcr2+1emXnYb7I6/Wk2bhJ7caVplNmcZ0u6XRHkmbzCD8hS1DJE7J5xUY9Imnkk4xZS+5SQYEnhHkF2IJHwFrM4jqa/Q/SN5zuwAGgaeAF1PFGxHML21oQ+8WlSwNnPd3TPrsym/eucJJqMTqqJSDAtpdGUVsmdR6NwMqns/bIvroGs0njXTE++cGybwSiAneLyfBAQDiP/WkaWhgC6j/vzvX5NNvtXWdumlUW79N4z8vGI89JCr4jIqz2YFHE1TikFo6CbHa6bv78nh8PYbCwYZ7F2zTaqX0qouFd4UTFvCMgE2k49UehSxwLIj9ujufi7dwcvvneDPCz6yw957WjgqgM7wrHrnnAy8Pbg4nlAKaAy/ZLfTpU7cYyazBrAgtdH/PyQETmPc9k44GADEkxqG2z2Q5xAi+erbaetwBoiD0HXL07//OcIOsf4TsDSbU1PejjhNXuIOgN494w7BoB+yQb+zH8F4mGUab5x2CsAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/dd2bcaa9601c27b33c0e7510855e8462/40a76/hero.png","srcSet":"/static/dd2bcaa9601c27b33c0e7510855e8462/c972b/hero.png 340w,\n/static/dd2bcaa9601c27b33c0e7510855e8462/27625/hero.png 680w,\n/static/dd2bcaa9601c27b33c0e7510855e8462/40a76/hero.png 1360w,\n/static/dd2bcaa9601c27b33c0e7510855e8462/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-02-hybrid-search-rag-bm25-vectors/index.md","relativeDirectory":"2026-07-02-hybrid-search-rag-bm25-vectors","ext":".md","sourceInstanceName":"blog"},{"id":"b089bc47-bac0-5ba3-b209-972fb7b660e1","children":[{"__typename":"MarkdownRemark","id":"ef6bfe12-ca66-5892-9ebf-7f276bba0df5","fields":{"slug":"/2026-07-03-argocd-sync-waves-ordering-rollout/"},"frontmatter":{"title":"ArgoCD Sync Waves: Ordering a Kubernetes Rollout","date":"2026-07-03T00:00:00.000Z","description":"ArgoCD applies your whole app at once, so a migration races the pods that need it. How sync waves and hooks order a Kubernetes rollout, and where they stall.","tags":["Kubernetes","ArgoCD","GitOps","DevOps","Observability"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABvElEQVQoz4VRbW/TMBDON5bEr01iO05jJ06ctHlrt45uHUPakBAwBOL//xquRdM+IIT06HT33HN+znbAzemM8p7o92b47K+/N7tvENv9i1u+9oef3eFHNX0Zjr9y/0SLIyhfR05BRHVIFE3tSja1vx53H4b5oR/vttOpH+628wmYpr9dbj7qamKyxUn9DuuQFjEtApS2RGy5nlk+Yulj5ZBqYlHH0iHdIojyzETSceXyoilKJ1W1EjbiNsBiZMUhtScs96Qccd0i26KqxbWnmwGScwmou7x2rVkv3vS1WWsT0TLAaZOtJ2lmnm9iZrjqlF2gzMoJr2phZlFCdwE+5hVTG2EXUOLERbA2FX3p77vds6wPVHTC7v3y5MZH3dzyfGv6h3Z5roZHaXfQVfVNt/+UN0ci+ojoIGKGqQHOjrmhiUVsHXGH5YyynskOFCHJQ6xx1nG9oFUD7xSRHPjLMLc4dWmxjRMfr1oAVTNTU0iKGKSJhxchcoqYvcKapM5VjgsPBvBHQYjlFQCJEKuLj74kCuK5RXK4FywV/hFgmWQGzEMM65yH1SvkX7iQKHvLsbpCb8oAPP8H+a/Wb3tdQtPhRG8pAAAAAElFTkSuQmCC","aspectRatio":1.899441340782123,"src":"/static/072a9d5ad2239659e3f54544e74b3960/40a76/hero.png","srcSet":"/static/072a9d5ad2239659e3f54544e74b3960/c972b/hero.png 340w,\n/static/072a9d5ad2239659e3f54544e74b3960/27625/hero.png 680w,\n/static/072a9d5ad2239659e3f54544e74b3960/40a76/hero.png 1360w,\n/static/072a9d5ad2239659e3f54544e74b3960/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-07-03-argocd-sync-waves-ordering-rollout/index.md","relativeDirectory":"2026-07-03-argocd-sync-waves-ordering-rollout","ext":".md","sourceInstanceName":"blog"},{"id":"741287d1-dc98-5a96-839c-c33479982cc2","children":[{"__typename":"MarkdownRemark","id":"6f3170da-0e26-5a26-b6a7-6e4dc4d2d4ed","fields":{"slug":"/2026-06-29-incremental-rag-indexing/"},"frontmatter":{"title":"Incremental Indexing for RAG Pipelines","date":"2026-06-29T00:00:00.000Z","description":"How to keep a RAG index fresh without full rebuilds: detect changed files with checksums, re-embed only what changed, and handle deletions safely.","tags":["AI","LLM","RAG","FastAPI","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB/UlEQVQozy1S226jMBDlZVUcsAEDBuMLOMHcIaYt1bZJmjQr7cv+//+s013pyD5nZo5mxrITdnPUzagZxfbeft4t9OVm0Vxu3fVXc/mypD5dLa/PNvg13n/TdQua0bqcHeIeEjvIk6yp220y134+d/NpWM6WtMNHP53G4+e83qwczed0vGBSA/hwOR6Wu0iAgLsBe4LU9ZnrcwAFQNxF7B+ATaEChBwg9gPk307phdLZBTwkmsgZ5y1mXTx2pNeoLgOlUz5h2oVZExd9woaI6Ej06dzjWqG6gkw5ABaY9qzeEjYm1ZK9m2KbolXH4ygPGy2PhE9ZZfJqTeiQ1IZ+LMm8D80eqb0DEI3ylu+3lI0pN3L5Q/QZlj8HffqQuiHSZLKUc6ZW/Og/5uVK1ZqwKUgPDvDzkGqyXzBvsBhzfU3VGxIvVfXc032Zloe0LFif8BHT1m5hd0lYj/MOxpXzBAg+DvJusFHRq2aHV16/EbmkchHte6FeUrHkahX6ESTyaBfMK2OzAXl0zvxMQCa8jPk5R3EJsfQj4dvzm8CQIywhLv3ISgltQVxZ6QXMPlgGPOLuiOtlKe3KZqNyCkSTa8O6F8p0oxYhBkIOhTLi8BwkyvVS1yfW6NjLhf8BsUBxZfv4sfBj6SclwjzCMoxEEHE7kZ3LC+1HyFyYWeNfAPpNAmAAtIcAAAAASUVORK5CYII=","aspectRatio":1.899441340782123,"src":"/static/815c0a626e8039a1fb7e0aacb5827bf8/40a76/hero.png","srcSet":"/static/815c0a626e8039a1fb7e0aacb5827bf8/c972b/hero.png 340w,\n/static/815c0a626e8039a1fb7e0aacb5827bf8/27625/hero.png 680w,\n/static/815c0a626e8039a1fb7e0aacb5827bf8/40a76/hero.png 1360w,\n/static/815c0a626e8039a1fb7e0aacb5827bf8/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-06-29-incremental-rag-indexing/index.md","relativeDirectory":"2026-06-29-incremental-rag-indexing","ext":".md","sourceInstanceName":"blog"},{"id":"a46a1a17-982f-5c8e-9713-854958acfccf","children":[{"__typename":"MarkdownRemark","id":"81828bec-9bbf-5ba7-a2b6-7951f5b7175c","fields":{"slug":"/2026-06-30-fastapi-sse-streaming-llm/"},"frontmatter":{"title":"Streaming LLM Responses from FastAPI with SSE","date":"2026-06-30T00:00:00.000Z","description":"Stream LLM output token by token from a FastAPI backend with Server-Sent Events: working code, the EventSource client, proxy buffering, and failure modes.","tags":["AI","LLM","FastAPI","React","Python"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABk0lEQVQoz32P63KbMBCF+QnCuiJsg7gYHG4yJNgZ1zXGafwASZr2/d+lKxon7p/OfHNmdfastLJ4NUh91s+/q/NbcXqtn36W49vd8AJHKKrRmPr5V3l6bX68T4F3rxl5dRL1yUIknFFV1PuuPzftcfMwNt1Q6QMUuhvqzfdqc2h7Y97vnur2uK4eIQ9TLlGWK1IkEptGiCeAw+K/BWLJZwGmQ2OTYYlNlMsTg0gtRJWDA3MTi1wWT0RX4g/lMfcz4mfYA12DYrEC3yKhlvmjSHvXy+AiBI/A4zdAyCFREGuZaC9qRdhgvyB+YYZltq8PL2l3kastz3ue7+Z6YPlWNkdRfuPlXj5cvKRbZn2zvRTdyIIazwss17CUxVQrVMfje7wozE+8FQ1KurijyxL7uSuBDNaWSof5DpSolqoWNnepshwSOCScCODzDl4iEiAaouvRQAKXpwaRzrwVAAWY1kfbEHzW9pf5P2B4cWXuspDKFIuYeAn1UtAZj0CJSEChC5mb/MKyZ/MvJsu+ad86/yQn/gCzpkI6b86R9QAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/aa9d918b5ab39f1c4481960a11c4f9a9/40a76/hero.png","srcSet":"/static/aa9d918b5ab39f1c4481960a11c4f9a9/c972b/hero.png 340w,\n/static/aa9d918b5ab39f1c4481960a11c4f9a9/27625/hero.png 680w,\n/static/aa9d918b5ab39f1c4481960a11c4f9a9/40a76/hero.png 1360w,\n/static/aa9d918b5ab39f1c4481960a11c4f9a9/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-06-30-fastapi-sse-streaming-llm/index.md","relativeDirectory":"2026-06-30-fastapi-sse-streaming-llm","ext":".md","sourceInstanceName":"blog"},{"id":"4e4f1ac1-3da7-5588-9ac0-ea092e997cf1","children":[{"__typename":"MarkdownRemark","id":"3b4f72a0-8f23-5bd7-8a40-c769e8d9b0a9","fields":{"slug":"/2026-06-30-llm-agent-tool-loop/"},"frontmatter":{"title":"How an LLM Agent Tool-Calling Loop Works","date":"2026-06-30T00:00:00.000Z","description":"A practical look at the agent loop behind LLM tools: how the model asks to call a tool, your code runs it, and the result feeds back until the answer is done.","tags":["AI","LLM","Agents","Python","Claude"],"thumbnail":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAAB0klEQVQoz02QWY/aMBSF81QgXuPETkK8ZCFJSTIzUAgMDGol2gppXkrb//9fepl2UKVPlu1zju7i5e50x7kXa45Df9nvfo3b63bzY7u57rY/d+ONrvtu9OF/vzdl8ztMlUiaJO+LbrsYdlU/lsNYP+yXq1PzeEjznqmKx+Xd7+HA4sC9YVlU9c2rUg/Ojk190noThR0Xtc8tAgJHo4KEBRYOCwt4iJu/+FyTwC3zi0v2hXkGSn2w8RiGLUiI6ZuHaZ/+AzHj3d7vzOg8lC0LK8JzFtTgFvIj5s7nGQqtTzMUaJI6pkumC6xu4eydOeY2iBomykX2udXnWD4xWYXJ0peGFg2OC9rWYnD5l3X23JGF9nw6RyxDb2Ea5FTkMuyX7uu6fXXJgaWLYN4gCTNrKIsjg2ODlEaxxlJ7M5pOiJqSZILVjKRUFIQ7LXcm2smow9xgZj4gOcExMMUxeO54sAmlhkg2cbKUcQt3LkrMNQ0cSLCCNHmKVAsqEEYNdDojCZSE0wvDelVdF/a46i5DczZqLUQNeVgy1AxE9an5XbuXx/bb0J5LfaTMTbGcEWgh9qATTDWhFhNDqKHMTmEKrHySTnAEl7uKqSHM+iSBMPwDfwCNBEUA8WM2TAAAAABJRU5ErkJggg==","aspectRatio":1.899441340782123,"src":"/static/7250ff100f79cc48a94fdb61a4cb4e3e/40a76/hero.png","srcSet":"/static/7250ff100f79cc48a94fdb61a4cb4e3e/c972b/hero.png 340w,\n/static/7250ff100f79cc48a94fdb61a4cb4e3e/27625/hero.png 680w,\n/static/7250ff100f79cc48a94fdb61a4cb4e3e/40a76/hero.png 1360w,\n/static/7250ff100f79cc48a94fdb61a4cb4e3e/ed396/hero.png 2000w","sizes":"(max-width: 1360px) 100vw, 1360px"}}}}}],"relativePath":"2026-06-30-llm-agent-tool-loop/index.md","relativeDirectory":"2026-06-30-llm-agent-tool-loop","ext":".md","sourceInstanceName":"blog"}]}}}