{
  "description": "Browse aymeric's, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.",
  "feed_url": "https://aggr.aymericbeaumet.com/sources/antirez.com/feed.json",
  "home_page_url": "https://aggr.aymericbeaumet.com/sources/antirez.com/",
  "items": [
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 53 days ago. 62313 views.</p>\n<pre><code><span class=\"code-snippet\">Amodei in his latest blog post wrote a mix of agreeable things and things that I believe misrepresent where the real risk of AI is located. I want to focus my attention on why, among all the risks, open weight models constitute the mildest one. I write these words as a person who strongly believes AI may be very dangerous in the near future:\n\n1. Exactly like what happened during the OpenAI / HF incident (which was a joke, but focus on the modalities, not the outcomes), the first serious AI incident is very likely to happen *inside* the walls of frontier AI labs, while testing a new model, or while the AI lab employees, or the few externals who have access, do something wrong compared to the expected power of the model.\n\n2. Closed models that will never even be opened to the public will be just a few TBs of data. All you need to leak one is a single person with access and the wrong goals, and you are back in the situation of open models. Open models are released *after* testing, and after similarly capable models were already available for some time under an API. The real risk is leaks, not releases, and leaks happen inside frontier companies.\n\n3. As Amodei says, open models, once LLMs are dangerous enough in fields like biology, can be trained on a corpus ablated of certain branches of science, while still being useful for a number of other things. The limited context window of a model that lacks strong pre-training in certain domains is a strong protection even if the model is otherwise very capable. We are currently not in a place where open models can constitute that kind of danger.\n\n4. In the context of cyber security, *not* having widespread access to the defensive security and bug seeking provided by LLMs creates exactly the &quot;LLMs as a weapon&quot; problem. It is already happening: open source maintainers, if they are out of some cyber program, can&#39;t find all the security bugs they could, while people with the right interests will be able to access frontier cyber models, do significant RL training on open weight models, and so forth.\n\n5. Once LLMs are dangerous enough (and we are near this limit, if progress continues), the real security chain that we need in place is inside labs, can&#39;t be set up without strong common rules, and a single company should not be able to evaluate independently whether a model is safe enough. We need a joint AI safety organization that includes experts from all over the world and is recognized by the governments where frontier AI companies exist.\n\n6. Slowing down AI for safety must be counterbalanced by the fact that AI discoveries in medicine and other sciences may lower human suffering. Lack of checks may result in some catastrophic outcome (&quot;Good morning! Let&#39;s work on this enhanced smallpox&quot;). Lack of progress may result in people who could be saved dying, not just in the present, but among the many who will suffer from illnesses in the future. This may look like a bizarre point, but we always need to understand that stopping AI *also* has a security cost embedded inside, which is just a lot more hidden.\n\n7. The ideological position of Amodei against China is unfair. We Europeans killed each other until 80 years ago without any limit of decency (people now forget, but one of the reasons the US invested in the stability of Europe in the past is that we were deeply dangerous, and would probably end up doing it again, while decades of wealth would make us a good market and would prevent us from fighting again). The US has, even in present times, tragic inequalities, people suffering for lack of basic health care, a president who looks unstable and is apparently very prone to war. I wish China had the same level of individual rights we have here in the West, but at the same time China&#39;s history is a lot less warlike than Western culture. It is absolutely not clear that an AGI military lock-in could be enforced more easily by China than the US, in the current conditions. Also, the current American administration spits hate at Europe in all forms, which is very worrying in a world where the US dominates everything. On top of all that, China&#39;s AI progress is not going to stop, whatever the GPU export policy is, so either Amodei is arguing that once America has AGI it should stop China by force, or what is his argument?\n\n8. In the history of humanity there are many cases where technological supremacy was initially reached in a single place of the world. This, AFAIK, never resulted in *a single* country trying to create a permanent advantage. The non-proliferation of nuclear weapons, which is probably the case most similar to the GPU ban, was not used to achieve a permanent economic advantage by threatening to bomb everybody else not complying, nor did it prevent several actors from acquiring that technology at different times, without one bombing the other to stop their progress. Moreover, I don&#39;t believe AI poses the greatest dangers because of government-driven actions. I wish this were the most dangerous scenario! Governments do silly things, are often aggressive, and their actions have even resulted in genocides, but it requires a lot of people agreeing on doing something terrible, which is itself a limiting factor. The greatest problem is what happens in two other cases: A) a few individuals generate an apocalypse event (the virus case), B) AI itself escapes the control of the people building it.\n\nI believe we should not consider AI safe. A critical event that may result in the extinction of Homo sapiens is possible, but the danger is not in open models, or China making faster progress than the US. The danger is that a few CEOs (everywhere in the world) without the required background and legitimacy are in the position of making hard choices for humanity at large. They were not selected to do so; it was just the randomness of events that created this setup. They can&#39;t speak for everybody, given the stakes, just because they have GPUs and money. This is the first thing that should be fixed.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-07-28T09:00:11+00:00",
      "date_published": "2026-07-28T09:00:11+00:00",
      "external_url": "http://antirez.com/news/172",
      "id": "urn:aggr:item:2de9016d480e831648f07987b1e242d3f9ea88f6",
      "summary": "Amodei in his latest blog post wrote a mix of agreeable things and things that I believe misrepresent where the real risk of AI is located. I want to focus my attention on why, among all the risks, open weight models constitute the mildest…",
      "tags": [
        "programming"
      ],
      "title": "The real AI risk is inside the labs",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-07-28-the-real-ai-risk-is-inside-the-labs/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 56 days ago. 74089 views.</p>\n<pre><code><span class=\"code-snippet\">(This blog post was adapted from the transcription obtained from my YouTube video at https://www.youtube.com/watch?v=l6lxgYeVZqs)\n\nWhen Linus Torvalds developed the first Linux kernel, he had studied the Minix sources, he had studied computer architecture, he had the base knowledge needed, and he was obviously a very brilliant programmer. But that operation of writing a minimal yet working Unix kernel for the 386 (at the beginning Linux was, let&#39;s say, mono-architecture) was something within the reach of many other programmers and students. Many in the sense of, I don&#39;t know, 0.1%, one in a thousand, one in ten thousand. Obviously most people are not able to do this kind of feat, but a lot of people are. If you look at Hacker News in the latest years, you&#39;ll see how many projects of kernels written in C, microkernels implemented from scratch, kernels written in Rust, kernels made in all sauces and manners, small Unix systems created vertically for the Raspberry Pi, operating systems for the ESP32 and so forth. Writing a kernel is not something within everybody&#39;s reach, but it is something that many can complete, if they put enough effort into it. Then, of course, not everybody will do it well. He is a genius programmer, without any doubt, so he did it better.\n\nAnd yet, of Linus there is only one. This implementative capacity of his, in fact, would not tell us much about him: what we should focus on, instead, is what happened later.\n\n## He stopped writing code\n\nAmong the maintainers of the famous open source projects, he was one of the very few that, very early in the history of the development of Linux, almost completely stopped writing code in order to concentrate on the leading of the project. On being the leader, the coordinator, the single mind holding the clarity about what the goals of the project must be, and so on. And this is a rare thing. Many maintainers (myself included, for a long time) continue instead to implement things directly, to not delegate much, and so forth.\n\nThis also starts from a different idea of software. Linux, necessarily, had to grow immeasurably: it is in the quality itself of a kernel that wants to embrace many devices, platforms, subsystems, and to continuously adapt to the times, to the needs of the new software, to the hardware that comes out little by little. So this was not a mistake. Redis, on the contrary, could remain something self contained. The other day I received a pull request on linenoise from Dr. Richard Hipp of SQLite: he too aimed at stability, at minimalism, at performances, but always keeping the code base very small, and he continued to write code for a very long time. Linus, instead, no. He understood immediately that he had to donate his time to something that was more important, for a project destined to become very big compared to what is the implementative capacity of a single person.\n\nSo he became the project leader, the one that owns the ideas, the direction. And what is it that Linus does, then? He does not look at every patch line by line, every time. Of course it also happens to him to look deeply into a single implementation, in order to understand what is going on. It happened to him, over the years, to write some new subsystem, or even to rewrite one: I think he did it once with the USB layer, many years ago, and he did it with the virtual file system, that at some point I believe he reimplemented, changing the structure of the inodes and of the inode cache, and he did it for several other reasons. From time to time he continued to program, when he created Git, and so forth. But for the most part he does not look at the patches singularly, in detail, line after line: he communicates with the maintainers of the subsections, and understands if a given feature or a given direction is, or is not, a road to take.\n\nSo, to say it in Brooks&#39; terms, in Mythical Man Month terms, Linus holds the design concepts of the kernel, and continues to dialogue with everybody below him in the hierarchy of the kernel so that the kernel goes towards a certain direction. So that the developments go towards a certain direction, both from the implementative point of view (how these developments are implemented, what is the quality, what is the implementative idea in the very way the code is written), and from the design point of view: what is it that we want to do, what we don&#39;t want, what is the best strategy for the modules, for the scheduler, for the hardware support, for the integration of Rust or not. All this stuff here.\n\nNow, I believe that this was the real genius of Linus. He is not just a very brilliant programmer: there are others. He is also a maintainer, an incredible designer, and one capable of handling a huge project ideas and structure in a coherent way, dialoguing with many other people. This thing is not for everybody.\n\n## We are Linus, now\n\nNow, when we program with the artificial intelligences, we are exactly that same thing. We are Linus Torvalds, not always with the talent that he has, but the role we should assume, in the projects where we don&#39;t do the review of every line of the code, is exactly of that type. It is exactly the role that he has.\n\nOnly, the thing is simpler to dominate: unless we use a lot of agents in parallel, it is substantially simpler to dominate than a multitude of patches arriving from different ways. But it is much faster. It is as if, instead of interacting with a team composed of many people at human speed, we interacted with a team composed of one, two, three people, based on how many parallel branches of our project we are developing in that moment, but that are much faster, so they give us immediately a much faster feedback. This slightly changes the modality of the work, but in my opinion for the better: it is easier, less context switching, fewer people to deal with, many fewer problems due to the character, the attitude, and so forth.\n\nSo, if we think that this role is important, we must not think that automatic programming is &quot;I put the prompt, and the thing writes&quot;. Vibe coding is a wrong idea of what automatic programming is, and of what automatic programming will be for the majority of people. Vibe coding is a very interesting thing for who does not have technological abilities and wants anyway to have an impact on the construction of their own tools, and so forth: so, welcome, because it democratizes the possibilities. But it is not that.\n\nAutomatic programming, instead, in the hands of people that are expert technicians, or expert programmers, expert designers, expert software architects, is to assume the role of Linus, with the agents and the LLMs assuming the role of the different maintainers of the different subsystems. And since not everybody is able to do it so well, automatic programming as well has need of talents that talk with the agents, that check the ideas, that know which are the implementations to do and the ones not to do, the way of communicating with the agents in order to make them do the best work, putting there those design hints that a great programmer intuits, that a good programmer intuits and manages to precompute.\n\nSo automatic programming, when it is done well, means to assume the role of Linus. And this thing can be done well, it can be done badly, it can be understood, or it can instead be debased. And it is also something that needs training, that needs to be learned, exactly as Linus had to learn it: he surely had an innate talent for this, but he passed from &quot;I implement everything&quot; to that capability of handling a symphony, of being the orchestra director.\n\nThat, for me, is the lesson of Linus, and it is one that should immediately be used as an argument of contrast for those that say that, well, with the LLMs programming is easy for everybody.\n</span></code></pre>\n",
      "date_modified": "2026-07-25T11:20:55+00:00",
      "date_published": "2026-07-25T11:20:55+00:00",
      "external_url": "http://antirez.com/news/171",
      "id": "urn:aggr:item:7634bbbd7b43a7f20cfc17e392e9b054459c91f6",
      "summary": "(This blog post was adapted from the transcription obtained from my YouTube video at https://www.youtube.com/watch?v=l6lxgYeVZqs) When Linus Torvalds developed the first Linux kernel, he had studied the Minix sources, he had studied…",
      "tags": [
        "programming"
      ],
      "title": "Being Linux Torvalds",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-07-25-being-linux-torvalds/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 59 days ago. 47881 views.</p>\n<pre><code><span class=\"code-snippet\">Even if you are as averse to semver as I used to be in the course of my programming activity, you can still think of open source software distribution as something that used to follow a fixed number of steps. There is a branch where developments happen, and this branch oftentimes happens to be not really ready for reliable work. Then you freeze the developments for a certain amount of time (even if, in the meantime, the work can continue on some new unstable branch), fix bugs, ask people to test it. At some point the number of bug reports starts to drop, your team and your users start to believe there are no longer obvious critical flaws that are easy to discover in the next few weeks: then you call the branch 2.4 or whatever, and that&#39;s it.\n\nHowever now, with AI coding, it&#39;s not just development that has changed, but also the act itself of using software is affected: it is not just you that can ask an AI to do certain changes to the software, but also the recipient of the software itself. This is obvious in the domains where a piece of software has its main user base among programmers, but this is also true in general, as more and more technologically inclined users have AI access and coding agents.\n\nBecause of this change, the idea of just having a stable branch with everything polished, and an unstable branch where everything is a work in progress, may no longer be the right way to do things. A code repository can also be a finished product, but could be even more useful if it is a template for how to do things around a given problem. Maybe the user will modify the code in order to specialize it for a specific set of requirements, hardware, specific problems to solve. Also, what is too unstable or unproven for the general public may be the right thing for another set of users.\n\nTake the example of Redis. For weeks now I have been iterating on a PR that provides strong memory savings for sorted sets. This work, if accepted, will hit every user of Redis, from people that don&#39;t have any idea about how Redis works, to users that maybe even contributed code in the course of years. From use cases that are trivial to use cases where a 50% memory saving on sorted sets could mean cutting a big slice of the cloud bill every year. For this last kind of user, having the final product (after all the testing and changes of design I&#39;m doing to refine something that &quot;just works&quot;, with the risk that maybe it will not even enter the code base) may be less interesting than having a 95%-ready branch since day zero. It is code they can test, adapt, iterate on, even specialize more for the problem at hand.\n\nMaybe DwarfStar is an even more telling example of how code repositories should be good examples more than finished products covering every piece of the features matrix. With local inference you have, in the specific case of DwarfStar, many kinds of GPUs, models, server mode, agent mode, CLI, SSD streaming, tensor and pipeline distributed execution. To test everything everywhere is complicated. Yet, once you have two solid examples of tensor parallel graph execution, a strong coding agent can infer how to implement the same thing for other backend/model pairs. Similarly, once you have an engine that supports two models well enough, a third can be implemented in an almost automatic way, using the existing code base as a guardrail for coding agents in order to guide the implementation.\n\nThis does not mean that a project like DwarfStar should not work out of the box, but that it could focus on supporting very well a set of features that can be extrapolated to a larger amount of possible situations that the users can cover themselves. It also means another thing: that main and unstable are no longer enough. Many experimental branches could be an integral part of the project. For instance, yesterday the Laguna S.1 model was released. It looks interesting on paper, however: will it really be good enough? Will the new DeepSeek v4 Flash checkpoints make it not really relevant for DwarfStar? It is too early to say. However, to collectively form an idea, publishing a branch with this model implementation is a good middle ground: people will try it, will refine it with their coding agents, and the community can collectively form an idea about how merge-worthy it is. Moreover, today I noticed how, thanks to the rails formed by the corpus of the code inside DwarfStar, the implementation was written in about two hours by GPT 5.6 Sol automatically. Implementing DS4 and GLM5.2 cost me a lot of steering, reading the model card and the details of the implementation of the attention of those models. Now it just worked. GPT 5.6 is more powerful but it also found a lot of good examples inside the existing source code.\n\nSoftware today is more malleable than ever. In some way this means that it can be released in a more fluid way. Also, it means that the documentation itself should not be just good for humans, but also for coding agents to understand how to change the system. How this will evolve exactly, and what the right point of balance between the different dimensions of stability, usability, and features will be, is not clear to me, but I believe we developers need to keep our eyes open to see where all this is headed.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-07-22T14:52:39+00:00",
      "date_published": "2026-07-22T14:52:39+00:00",
      "external_url": "http://antirez.com/news/170",
      "id": "urn:aggr:item:cb06f9a409d7013754e42d6a316f1baa21516f81",
      "summary": "Even if you are as averse to semver as I used to be in the course of my programming activity, you can still think of open source software distribution as something that used to follow a fixed number of steps. There is a branch where…",
      "tags": [
        "programming"
      ],
      "title": "Not just development, distribution of software may change as well",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-07-22-not-just-development-distribution-of-software-may-change-as/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 68 days ago. 317116 views.</p>\n<pre><code><span class=\"code-snippet\">Look at the past history of this blog. There are many blog posts about programming with AI, a few of them date back to January 2024 (like this: https://antirez.com/news/140). I’m a relatively well regarded programmer, after all. I don’t have the need to still be in the “loop” as a old man that seeks for relevance, I recently rejoined Redis, and now I also am developing a new open source software for local LLM inference that received a good welcome in the community. Why I keep doing this, of saying what people don’t want to hear? Why I keep announcing how future programming will be by default? Because I feel the urge of lowering the impact for people less prepared to the change than me, often younger than me, and that, unlikely me, didn’t see many of those things coming (In 2022 I published, before ChatGPT existed, a book preannouncing many things that now happened and other things that I believe *will* happen, so I feel like I can say this without sounding egocentric).\n\nSo mine is a trick. People feel more and more programming is completely modified by AI and don’t know what they should do, if they can really start coding in a completely different way, without looking much at the code as their main output. They feel like they are betraying their own field. So my intention is to arrive and say “look at me, In can write code, you know, I’m not hiding behind AI: yet, things changed, it’s not your weakness, it’s not that you are AI-pilled. It is just that our field is evolving in an incredible *and* painful (but also joyful) direction”.\n\nThis is why yesterday, on X, I said that I believe many programmers at this point have less impact they could have because they look at the code. I truly believe into that. And note that this does not mean to vibe code something just asking for the final product. The point is: if you control the ideas of your software, looking at the code itself is suboptimal and often pointless. For the following reasons:\n\n1. You can now generate a lot of code, even *not* accounting for the LLM code verbosity (that is also effect of not being able to instruct them well, for most of the part). How are you supposed to review 5k lines of code every day?\n\n2. LLMs are very good at writing locally optimal code, and are worse (but improving) with big ideas. What’s the point of scanning function by function, line by line? Instead you should prompt the design you have in mind, sometimes ask “how is exactly the design of that part? How does it work?”, and evaluate if it is the right model. It is much faster.\n\n3. The working day is 8 hours. If you read the code, it is a tradeoff. You are doing less of what today is the most important part of your job, that is, asking yourself: what I’m doing with this software? What are the new directions I want to take? And also, think at new ideas, features, optimizations tricks. And doing a lot of QA.\n\nControlling the ideas. Do you remember this phrasing from the Mythical Man Month? Well, a book from the 70s tells us more things about the current software era than many of the things that were said from 2000 to 2020. Why people that now protest against AI were not horrified by the state of software in the last decade? The level of slop we touched during recent years, before AI, is unbelievable. I’ll say you another thing. What is slop? With DwarfStar I implemented an inference for two LLMs (DeepSeek v4 and GLM 5.2) in a completely automated way, but: try it yourself, you will discover you can’t just say “implement XYZ” and see it working. You have to understand how things work, what is the best design, how to reach a certain level of performance. Then I compared the implementation, for correctness, to other systems, finding that other implementations sometimes contained more errors. I researched more, and found that the local inference world is full of subtle errors that accumulate and damage the model output, issues in the attention implementation causing performance slopes after the context is over a certain limit because indexed attention implementations are broken (do more work than they should, for instance), and so forth. This is the result of a domain that is very complicated to handle, fast changing, with models that are slightly different one from the other in the inference graph being released every day. It’s an unfair game for developers. Well: AI helps a lot with that. There are many domains where rigorous engineering (in the design side) and testing is *far* better than writing a GPU kernel by hand (or reading it). So are we sure most of that resistance it is not ideological?\n\nMatteo Collina yesterday asked me, in reply to my tweet: but didn’t you say that you check all the AI generated code for Redis? And this is a good question indeed. Yes, I do, but this is, at this point, something I *need* to do but that I believe to be mostly pointless, partially once GPT 5.5 was released, but now with Fable and GPT 5.6 Sol even more. Yes: I identify things that I don’t like how they are coded, but if I open other Redis files written by other Redis contributors there is *far worse*, and not since they are not good coders, but because it is a matter of taste. I write very clean code since I want it to be readable, so during the implementation of Redis Arrays I operated changes. I’m doing it again for the 50% memory saving optimization of Redis sorted sets, a PR that I’ll submit soon. But I do not feel this is useful anymore. Nobody should anymore look at this code, but only at the ideas the code contains. I continued to do it out of respect for users. Redis is at this point a commonly useful thing, and many programmers will open files and modify stuff by hand. But if I had my hands free, you know what I would do, instead? Use all the time that the review is taking me to do more QA, to think at the next optimization idea and apply it, and to use LLMs to write a DESIGN.md file where each data structure is described in human language, with the ideas it contains, the implementation tricks, the design. That, in the future, is going to be much more useful. Do you want to modify sorted sets? You open the file, read the design, then you own the ideas. You can open your agent and ask it what to do with the right mental model. This is a lot more useful than reviewing the code.\n\nFable and GPT 5.6 reviews to the sorted sets memory saving are going to spot ways more errors and subtle race conditions that my review is going to uncover. Yet I’ll do it. But for the majority of software projects, all this does not make sense anymore. Focus on controlling the ideas, instead. Focus on quality, testing, and having an idea of the software you want to ship. The world changed and it is painful, but also full of opportunities to improve a software world that was already completely rotten.\n\nI have a doubt only regarding young programmers that don&#39;t have enough experience, and can&#39;t build a mental model. We don&#39;t know, yet, if they will require or not to understand very well how a given piece of code works, but I believe they should learn how to write programs. Yet, I&#39;m not sure checking the LLM output is the right thing they should do. It may be a lot more useful if they learn some programming language and implement a small interpreter, a small database, an hash table and so forth. Reviewing some Javascript stuff of some web site for a customer? Hell, no, don&#39;t lose time with that shit.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-07-13T11:39:52+00:00",
      "date_published": "2026-07-13T11:39:52+00:00",
      "external_url": "http://antirez.com/news/169",
      "id": "urn:aggr:item:a4a84cf9cda99013157444bcd352577f70baf6e1",
      "summary": "Look at the past history of this blog. There are many blog posts about programming with AI, a few of them date back to January 2024 (like this: https://antirez.com/news/140). I’m a relatively well regarded programmer, after all. I don’t…",
      "tags": [
        "programming"
      ],
      "title": "Control the ideas, not the code",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-07-13-control-the-ideas-not-the-code/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 104 days ago. 127654 views.</p>\n<pre><code><span class=\"code-snippet\" data-language=\"YAML\"><span class=\"syntax-source syntax-yaml\"><span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">Automatic programming dramatically speeds up writing software in certain use cases and in the right hands. In my experience the output does not reach the structural quality and economy of complexity of the best hand-written software. However, not all the software is stellar, and my feeling is that automatic programming surpasses most of the times (and if well managed) the quality of decently developed hand-written code.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">Yet, there is a tradeoff between quality and time, in the case of writing new software with AI. This tradeoff in certain projects I developed can be brutal, that is, completing projects that may take many months in a few weeks. However, there are domains where LLMs simply open new strictly more powerful ways to automate processes, without any compromise on quality. One of those domains is software QA and testing.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\"><span class=\"syntax-entity syntax-name syntax-tag syntax-yaml\">Traditionally software is tested using test suites that are composed of locally-scoped tests and integration tests (think of Redis</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-mapping syntax-yaml\">:</span> <span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\"><span class=\"syntax-entity syntax-name syntax-tag syntax-yaml\">one thing is testing if SET foo 10 will be matched by GET foo =&gt; 10, another thing is testing if replication works in this case). And then by QA passes that are usually manually executed, and that can capture holes in the runnable test suite. It is a known fact that covering all the lines of the code does not mean covering all the possible states. Moreover integration testing is structurally hard</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-mapping syntax-yaml\">:</span> <span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">there are a number of timing issues, setups, and certain quality outputs that can only be visually inspected and not automatically checked that leave a lot of testing opportunities not really exploited because of time or logistic constraints.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\"><span class=\"syntax-entity syntax-name syntax-tag syntax-yaml\">LLMs offer a new way to do QA on top of the existing testing methodologies. The idea is to create a markdown file where an AI agent is asked to work as a QA engineer, performing a number of manual testings on the new release. For instance, in the case of DwarfStar (an inference engine for open weights LLMs) I use the following approach. In the markdown file, the agent is asked to check what are the new commits on top of the already released version of the software project. Then the model is told a list of things that should be performed, like</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-mapping syntax-yaml\">:</span>\n\n<span class=\"syntax-punctuation syntax-definition syntax-block syntax-sequence syntax-item syntax-yaml\">-</span> <span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">Check that distributed inference works across MacBook A and MacBook B, making sure the output is coherent, the inference works with all the GGUF files we have in both the machines, ...</span>\n<span class=\"syntax-punctuation syntax-definition syntax-block syntax-sequence syntax-item syntax-yaml\">-</span> <span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">Make sure this release does not contain any speed regression.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">And so forth. Notably, in the speed regression part, I don&#39;t have to tell the agent what was the previous expected speed, as this is a moving target that changes with new releases and new optimizations. Similarly the integration test for distributed inference does not require many instructions, at the start of the file there are just SSH endpoints and the key to use, the paths, and so forth.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">The agent is asked to check the long list of QA activities *especially* in light of the added commits, starting with an inspection of the changes and with the identification of what could be affected, so that the QA pass specializes trying to find specific regressions.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">In the case of Redis Arrays, I used a similar methodology asking the agent to build a large array-based Redis application, to setup a production environment with replication and persistency, to simulate the usage of the application for days and with many users, checking if something was odd.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">Testing that uses these approaches may also move in the more psychological side of software quality, asking the agent to identify all the new features that may look surprising, not documented enough, or generally sloppy from the POV of the user. All things that needed to be executed manually before, and that most of the times were mostly skipped.</span>\n\n<span class=\"syntax-string syntax-unquoted syntax-plain syntax-out syntax-yaml\">I have the feeling that the introduction of automatic QA may raise the bar of quality for new releases of software, and maybe partially compensate for the lower quality of the code produced at high speed with the use of automatic programming.</span>\n</span></span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-06-07T09:46:06+00:00",
      "date_published": "2026-06-07T09:46:06+00:00",
      "external_url": "http://antirez.com/news/168",
      "id": "urn:aggr:item:ebd195ff3b6a463bcb0d8a7a92b2ae6ba5829ba6",
      "summary": "Automatic programming dramatically speeds up writing software in certain use cases and in the right hands. In my experience the output does not reach the structural quality and economy of complexity of the best hand-written software.…",
      "tags": [
        "programming"
      ],
      "title": "A new era for software testing",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-06-07-a-new-era-for-software-testing/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 117 days ago. 58373 views.</p>\n<pre><code><span class=\"code-snippet\">High end NVIDIA cards, and the server and power needed to run them, cost a lot of money, especially if you plan to reach enough VRAM to run massive models. The alternative, so far, has been Apple hardware, or the DGX Spark that, even if severely limited because of memory bandwidth, still allows to run LLMs prompt processing (prefill) fast enough. The Mac Studio provided up to 512GB unified memory, a solution with modest memory bandwidth (but much better than the Spark) and compute at a price that was, after all, given the current situation, relatively fair.\n\nFor instance, with DwarfStar the Mac Studio M3 Ultra 512GB can run DeepSeek v4 PRO at 150 t/s prefill and ~10-13 t/s decoding, not great but at a level that is usable for certain use cases. Even 2-bit quantized, DeepSeek v4 PRO resists very well, like Flash at the same quantization (today I made PRO write a C compiler, I&#39;ll publish the video soon). I would not consider a trivial fact to run a frontier model at home, with a ~12k total spending.\n\nOne could expect this to get better and better, but the situation at the horizon appears cloudy. There is almost zero hope that NVIDIA setups will get less expensive, and even a small company can’t afford to easily purchase and handle a small data center for local inference. At the same time the RAM shortage is making it not exactly likely that we will see a Mac Studio with an M5 Ultra, maybe 1.2T/s memory bandwidth and more compute (the M5 Max is already faster, compute wise, and has the Neural Accelerators inside each GPU core that help with certain models).\n\nSo the current situation for local inference is that the best machine is probably a laptop. The M5 Max 128GB can run DeepSeek v4 Flash and Mimo V2.5, 2-bit quantized, at very decent prefill and decoding speeds. We are talking of ~500 t/s prefill and ~35-40t/s decoding speed, with a performance slope as the context size increases which is very acceptable. At the cost of 6-7k depending on the configuration, this is currently one of the best deals.\n\nIf this is the situation, for local inference projects in general, and for DwarfStart in particular, looking at distributed inference starts to be interesting. What we can do if we have two, three, four MacBook M5 Max systems? Or two M3 Ultra with 512 GB of RAM?\n\nTraditionally there are two main systems to run distributed inference. One is to duplicate memory by loading 50% of the transformer layers in computer A, the remaining 50% on computer B, and running the inference in a sequential way. In this case there is to send just the activations around, that’s very simple conceptually, and with some micro-batching magic it is possible to not just duplicate the memory but even in theory to increase substantially the prompt processing speed (but not the decoding: for a single token generation you have to wait the first layers on machine A, the remaining layers on machine B, and so forth — but at least less heat will be produced so it is possible to use a sustained load), which is not bad at all. This means, for example, that the lucky ones that have two Mac Studio 512GB machines could run full size DeepSeek v4 PRO (even if even the 2-bit quants are running very, very well) and with micro-batching even enjoy a faster prefill.\n\nAnother approach is, using Apple RDMA, to parallelize the execution across the two machines, a vertical split basically. For instance one could try to load the same 2 bit quants on machine A and B, so that both fit, and each side has *all* the routed experts. Then for each layer we could try to do the coordination needed in order to execute half the experts in machine A, half in machine B, and so forth (note that both machines have all the experts, so whatever the router says, we can send 50% of the computation to the other machine, and the activations are tiny). This is more viable for the PRO that has much larger routed experts, so the communication penalty is less sensible. But if this could be made to work well, is all to be seen.\n\nThere is also tensor parallelism, you are thinking, right? But I bet this is not viable at all with the communication speed we have among two Apple computers, two DGX Spark and so forth (go read the speed of NVLink). The magic about the above two models is that you have to send very little data.\n\nOk, so far I bet you are thinking, this is the same shit everybody knows about running LLMs in a parallel fashion, and indeed this is true. But this post was conceived to reach this exact point. What about if we could, instead, parallelize two Mac or DGX in a completely different way? Open weights models are now in a golden age, we have plenty and many are very powerful. In the 128GB 2-bit quants classes there are many interesting: Minimax M2.7, Mimo V2.5, DeepSeek v4 Flash, and a few more. At the same time it was recently noted that LLMs ensemble (https://arxiv.org/abs/2502.18036) is an understudied possibility that allows two models to run in a completely shared-nothing way in two different machines, to only combine the logits or select the best continuation at the end. There are different ways to do that, and it works even if the two models have different vocabularies: you can pick the continuation where the perplexity is lower (that is, pick the model which is more sure: it’s like a two experts MoE where the routing is implicit), and it is even possible to combine the logits (with some complexities given by the different vocabularies) and sample from there. More recent papers suggest that mixing the two techniques is the best approach. Anyway: these techniques seem to really work, models appear to do better than alone. It’s like if their knowledge is improved because each one brings his POV on what to say next.\n\nMaybe this is one of the most logical third approach to try, other than the first two. I really hope to find the time to play more with all that, in the next months.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-05-25T14:54:59+00:00",
      "date_published": "2026-05-25T14:54:59+00:00",
      "external_url": "http://antirez.com/news/167",
      "id": "urn:aggr:item:ca163ae658c42b321079c313bc5fb83750a36f4b",
      "summary": "High end NVIDIA cards, and the server and power needed to run them, cost a lot of money, especially if you plan to reach enough VRAM to run massive models. The alternative, so far, has been Apple hardware, or the DGX Spark that, even if…",
      "tags": [
        "programming"
      ],
      "title": "Distributing LLM inference in DwarfStar",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-05-25-distributing-llm-inference-in-dwarfstar/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 123 days ago. 49578 views.</p>\n<pre><code><span class=\"code-snippet\">EDIT: of course this was already done in the past! I had little doubts but people just confirmed me about it on Twitter :) But, keep reading: the CRC32 compromise at the end is an interesting tradeoff, and this is a good discussion to have in general.\n\nRight now I&#39;m working to an agent for my DS4 project. Local inference is token-poor, it&#39;s a battlefield where optimizations count. I was quite surprised by the fact the EDIT tool everybody is using right now forces the LLM to emit the old version of the text verbatim. This CAS (check and set) mode of operation, where I say EDIT old=&quot;foo&quot; new=&quot;bar&quot;, is needed because there are often colliding edits (the user is editing as well, or checked out a different branch, and so forth) and because the LLM can just hallucinate that a given line had a given content.\n\nThis means, basically, that just using line numbers is very fragile: to say, change line 22 with new=&quot;foobar&quot; is not good. Yet I don&#39;t want my local LLM to throw away tokens rewriting the old text each time, also because certain times the old text has a lot of special chars and spaces that the model may get wrong; in this case the tool would fail, forcing the LLM to do the same edit again. So I (re)designed a tag-based EDIT tool that is still CAS style, but more tokens efficient.\n\nThe READ and SEARCH tools return something like that:\n\n  10:Q8fA int count = 10;\n  11:rA3_ if (count &gt; limit) {\n  12:Kq9z     count = limit;\n  13:PX0b }\n\nSo there are line numbers and tags. The tag is 4 chars, on average 2.5 LLM tokens, representing a checksum of the line. Now the LLM can edit like this:\n\n  {\n    &quot;tool&quot;: &quot;edit&quot;,\n    &quot;path&quot;: &quot;/tmp/example.c&quot;,\n    &quot;line&quot;: 10,\n    &quot;tag&quot;: &quot;Q8fA&quot;,\n    &quot;new&quot;: &quot;int count = 11;&quot;\n  }\n\nOr, multi line, like this:\n\n  {\n    &quot;tool&quot;: &quot;edit&quot;,\n    &quot;path&quot;: &quot;/tmp/example.c&quot;,\n    &quot;lines&quot;: &quot;11:rA3_\\n12:Kq9z\\n13:PX0b&quot;,\n    &quot;new&quot;: &quot;if (count &gt; limit)\\n    return limit;&quot;\n  }\n\nThe saving is significant especially when the agent is deleting big amounts of text, but also in the general case. However, there is some overhead due to the fact we have line numbers and tags. There are potential tradeoffs, maybe the tag should be 8 chars and include the line number in the hash, there is to check exactly collisions possibilities and tokenization to see how much this is a win, but I like the line:tag format as later the LLM is often able to exploit the line information in many ways, like to get ranges in successive tool calls. Maybe there are other ways to exploit the tag, too, like: is this line still dj4_?\n\nThe interesting thing is that DeepSeek v4 Flash is able to use this tool in a very effective way, so apparently it is natural for it. And while I did&#39;t measure the exact savings I saw in the field that edits are much faster and even more reliable.\n\nThe alternative to this is to return just the whole file CRC32 each time (basically the tag becomes a file tag, even for partial reads). So that we can only work with line numbers + CRC, the edit would just specify 11,12,13,14. Less tokens, of course. This forces, however, to recompute the CRC32 of the file each time, but for reasonably sized files this is cheap enough. But this approach has limits: we fail the edit even if *unrelated* changes happened, so there is a strong tradeoff at play. To be fair to the whole file method, there is to say that it allows to specify ranges as 10:23, which is a huge win.\n\nI have the feeling I can decide which is better only with enough practical evidence, by using ds4-agent over multiple sessions with the two systems. For now maybe a command line to switch the edit mode is the first right step to do.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-05-19T07:26:03+00:00",
      "date_published": "2026-05-19T07:26:03+00:00",
      "external_url": "http://antirez.com/news/166",
      "id": "urn:aggr:item:a05ba560a919de2e118ccc2e9cf4bdf61fccf6e2",
      "summary": "EDIT: of course this was already done in the past! I had little doubts but people just confirmed me about it on Twitter :) But, keep reading: the CRC32 compromise at the end is an interesting tradeoff, and this is a good discussion to have…",
      "tags": [
        "programming"
      ],
      "title": "Alternatives for the EDIT tool of LLM agents",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-05-19-alternatives-for-the-edit-tool-of-llm-agents/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 127 days ago. 241401 views.</p>\n<pre><code><span class=\"code-snippet\">I didn’t expect DwarfStar 4 (https://github.com/antirez/ds4) to become so popular so fast. It is clear that there was a need for single-model integration focused local AI experience, and that a few things happened together: the release of a quasi-frontier model that is large and fast enough to change the game of local inference, and the fact that it works extremely well with an extremely asymmetric quants recipe of 2/8 bit, so that 96 or 128GB of RAM are enough to run it. And, of course: all the experience produced by the local AI movement in the latest years, that can be leveraged more promptly because of GPT 5.5 (otherwise you can’t build DS4 in one week — and even with all this help you need to know how to gently talk to LLMs).\n\nThe last week was funny and also tiring, I worked 14 hours per day on average. My normal average is 4/6 since early Redis times, but the first few months of Redis were like that.\n\nSo, what’s next? Is this a project that starts and ends with DeepSeek v4 Flash? Nope, the model can change over time. The space will be occupied, in my vision, by the best current open weights model that is *practically fast* on a high end Mac or “GPU in a box” gear (like the DGX Spark and other similar setups). I bet that the next contender is DeepSeek v4 Flash itself, in the new checkpoint that will be released and, hopefully, a version specifically tuned for coding, and who knows, other expert-variants (not in the sense of MoE experts) maybe. For local inference, to have a ds4-coding, ds4-legal, ds4-medical models make a lot of sense, after all. You just load what you need depending on the question.\n\nIt is the first time since I play with local inference (I play with it since the start) that I find myself using a local model for serious stuff that I would normally ask to Claude / GPT. This, I think, is really a big thing. It is also the first time that using vector steering I can enjoy an experience where the LLM can be used with more freedom. DeepSeek v4 Flash is really an impressive model, no doubt about that. If you can imagine in your mind the small good local model experience as A, and the frontier model you use online as B, DS4 is a lot more B than A. I can’t wait for the new releases, honestly (btw, thank you DeepSeek).\n\nSo, after those chaotic first days, I hope the project will focus on: quality benchmarks, potentially adding a coding agent that is also part of the project, a hardware setup here in my home that can run the CI test in order to ensure long term quality, more ports, and finally but as a very important point: distributed inference (both serial and parallel).\n\nFor now, thank you for all the support: it was really appreciated :) AI is too critical to be just a provided service.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-05-14T22:22:45+00:00",
      "date_published": "2026-05-14T22:22:45+00:00",
      "external_url": "http://antirez.com/news/165",
      "id": "urn:aggr:item:c11fd9f6fe19dd01b0e3ba4cf9ad67039bd27588",
      "summary": "I didn’t expect DwarfStar 4 (https://github.com/antirez/ds4) to become so popular so fast. It is clear that there was a need for single-model integration focused local AI experience, and that a few things happened together: the release of…",
      "tags": [
        "programming"
      ],
      "title": "A few words on DS4",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-05-14-a-few-words-on-ds4/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 138 days ago. 189927 views.</p>\n<pre><code><span class=\"code-snippet\">I started working on the new Array data type for Redis in the first days of January. The PR landed the repository only now, so this code was cooked for four months. I worked at the implementation kinda part time (kinda because many weeks were actually full time, sometimes to detach yourself from the keyboard is complicated), and even before LLMs the implementation was likely something I could do in four months. What changed is that in the same time span, I was able to do a lot more. This is the short story of what happened.\n\nIn the first month I just wrote the specification document. The rationale for the new data type, the C structures, the sparse representation used, the exact semantics of the array cursor for ring buffer and ARINSERT. I started writing for days a long specification by hand, then I paired with Opus initially, then GPT 5.3 was released and I switched all the design and development with Codex. Since then I use only GPT 5.x for system programming tasks. Thanks to AI, the specification evolved a lot, via back and forth of feedback, intellectual challenges about what was the best design, what was the right compromise, what was too engineered and what not.\n\nStarting from the second month, I started the implementation using automatic programming (auto coding if you prefer), constantly reviewing the developed code. Then I realized that the level of indirection I picked was wrong. I really wanted people to be able to do ARSET myarray 293842948324 foo and everything to still work without huge allocations. The two levels of directory + slices (sparse and dense) I had were not enough. Because I had AI, I took no compromises, and I decided to go the extra mile. Once certain conditions are reached, the data structure internally changes shape, and becomes a super directory of sliced dense directories, that also point to the actual array slices (4096 elements per slice, by default). This design provided still the internal &quot;is actually an array&quot; representation I wanted, and the memory characteristics I seeked, while being able, for ARSCAN, and ARPOP, to scan the existing arrays taking a time proportional to the existing elements and not to the range span.\n\nThen, it was time to read all the code, line by line. Everything was working, and this type has massive testing, thanks, again to AI, but still things that superficially work do not mean they are optimal. I found many small inefficiencies or design errors that I didn&#39;t want, so I started a process of manual and AI-assisted rewrite of many modules. When this stage was done, I started, during the third month, to stress test the implementation in many different ways. I started to be confident that it was really solid, useful, well designed.\n\nThen… it happened. While modeling different use cases to see if the data structure was comfortable to use, I started to put markdown files into Redis arrays. Because files are a very good match for it. At this point, as I was working for other goals with agents, I realized that I could have the skills markdown files centralized knowledge base that I needed, so from a need of mine I decided to implement ARGREP. But I wanted regular expressions, too. What library to pick?\n\nI ended up picking TRE (thanks Ville Laurikari!), because when you have regexp in Redis, you want to be sure that there are no pathological patterns in time or space. But TRE was very inefficient in a specific and extremely useful case, that is matching foo|bar|zap. So with the help of GPT I optimized it, fixed a few potential security issues, and extended the test. I had everything in place.\n\nYou know what was the biggest realization of all that? For high quality system programming tasks you have to still be fully involved, but I ventured to a level of complexity that I would have otherwise skipped. AI provided the safety net for two things: certain massive tasks that are very tiring (like the 32 bit support that was added and tested later), and at the same time the virtual work force required to make sure there are no obvious bugs in complicated algorithms. To write the initial huge specification was the key to the successive work, as it was the key to review each single line of sparsearray.c and t_array.c and modifying everything was not a good fit.\n\nI didn&#39;t spend any word on the use cases as I tried to document the PR itself with a message where they are detailed:\n\nhttps://github.com/redis/redis/pull/15162\n\nSo it was not really useful to repeat myself here. Enough to say that I really believe it is about time for Redis to have a data type where the numerical index is part of the semantics.\n\nI hope the Array PR will be accepted soon, and that we can benefit from the new use cases it opens. Of course, feedback is welcomed. Thank you.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-05-04T14:21:45+00:00",
      "date_published": "2026-05-04T14:21:45+00:00",
      "external_url": "http://antirez.com/news/164",
      "id": "urn:aggr:item:ddef1381d8ba915875ab7315a9822f440da662db",
      "summary": "I started working on the new Array data type for Redis in the first days of January. The PR landed the repository only now, so this code was cooked for four months. I worked at the implementation kinda part time (kinda because many weeks…",
      "tags": [
        "programming"
      ],
      "title": "Redis array type: short story of a long development",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-05-04-redis-array-type-short-story-of-a-long-development/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 156 days ago. 130850 views.</p>\n<pre><code><span class=\"code-snippet\">The proof of work is the wrong analogy: finding hash collisions, while exponentially harder with N, is guaranteed to find, with enough work, some S so that H(S) satisfies N, so an asymmetry of resources used will see the side with more &quot;work ability&quot; eventually winning.\n\nBut bugs are different:\n\n1. Different LLMs executions take different branches, but eventually the possible branches based on the code possible states are saturated.\n\n2. If we imagine sampling the model for a bug in a given code M times, with M large, eventually the cap becomes not &quot;M&quot; (because of saturated state of the code AND the LLM sampler meaningful paths), but &quot;I&quot;, the model intelligence level.\n\nThe OpenBSD SACK bug easily shows that: you can run an inferior model for an infinite number of tokens, and it will never realize(*) that the lack of validation of the start window, if put together with the integer overflow, then put together with the fact the branch where the node should never be NULL is entered regardless, will produce the bug.\n\nSo, cyber security of tomorrow will not be like proof of work in the sense of &quot;more GPU wins&quot;; instead, better models, and faster access to such models, will win.\n\n* Don&#39;t trust who says that weak models can find the OpenBSD SACK bug. I tried it myself. What happens is that weak models hallucinate (sometimes causally hitting a real problem) that there is a lack of validation of the start of the window (which is in theory harmless because of the start &lt; end validation) and the integer overflow problem without understanding why they, if put together, create an issue. It&#39;s just pattern matching of bug classes on code that looks may have a problem, totally lacking the true ability to understand the issue and write an exploit. Test it yourself, GPT 120B OSS is cheap and available.\n\nBTW, this is why with this bug, the stronger the model you pick (but not enough to discover the true bug), the less likely it is it will claim there is a bug. Stronger models hallucinate less, so they can&#39;t see the problem in any side of the spectrum: the hallucination side of small models, and the real understanding side of Mythos.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-04-16T10:46:46+00:00",
      "date_published": "2026-04-16T10:46:46+00:00",
      "external_url": "http://antirez.com/news/163",
      "id": "urn:aggr:item:328b272ccfdbd3ff4634ccb7b4352a45899ed225",
      "summary": "The proof of work is the wrong analogy: finding hash collisions, while exponentially harder with N, is guaranteed to find, with enough work, some S so that H(S) satisfies N, so an asymmetry of resources used will see the side with more…",
      "tags": [
        "programming"
      ],
      "title": "AI cybersecurity is not proof of work",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-04-16-ai-cybersecurity-is-not-proof-of-work/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 195 days ago. 93373 views.</p>\n<pre><code><span class=\"code-snippet\">Those who cannot remember the past are condemned to repeat it. A sentence that I never really liked, and what is happening with AI, about software projects reimplementations, shows all the limits of such an idea. Many people are protesting the fairness of rewriting existing projects using AI. But, a good portion of such people, during the 90s, were already in the field: they followed the final part (started in the ‘80s) of the deeds of Richard Stallman, when he and his followers were reimplementing the UNIX userspace for the GNU project. The same people that now are against AI rewrites, back then, cheered for the GNU project actions (rightly, from my point of view – I cheered too).\n\nStallman is not just a programming genius, he is also the kind of person that has a broad vision across disciplines, and among other things he was well versed in the copyright nuances. He asked the other programmers to reimplement the UNIX userspace in a specific way. A way that would make each tool unique, recognizable, compared to the original copy. Either faster, or more feature rich, or scriptable; qualities that would serve two different goals: to make GNU Hurd better and, at the same time, to provide a protective layer against litigations. If somebody would claim that the GNU implementations were not limited to copying ideas and behaviours (which is legal), but “protected expressions” (that is, the source code verbatim), the added features and the deliberate push towards certain design directions would provide a counter argument that judges could understand.\n\nHe also asked to always reimplement the behavior itself, avoiding watching the actual implementation, using specifications and the real world mechanic of the tool, as tested manually by executing it. Still, it is fair to guess that many of the people working at the GNU project likely were exposed or had access to the UNIX source code.\n\nWhen Linus reimplemented UNIX, writing the Linux kernel, the situation was somewhat more complicated, with an additional layer of indirection. He was exposed to UNIX just as a user, but, apparently, had no access to the source code of UNIX. On the other hand, he was massively exposed to the Minix source code (an implementation of UNIX, but using a microkernel), and to the book describing such implementation as well. But, in turn, when Tanenbaum wrote Minix, he did so after being massively exposed to the UNIX source code. So, SCO (during the IBM litigation) had a hard time trying to claim that Linux contained any protected expressions. Yet, when Linus used Minix as an inspiration, not only was he very familiar with something (Minix) implemented with knowledge of the UNIX code, but (more interestingly) the license of Minix was restrictive, it became open source only in 2000. Still, even in such a setup, Tanenbaum protested about the architecture (in the famous exchange), not about copyright infringement. So, we could reasonably assume Tanenbaum considered rewrites fair, even if Linus was exposed to Minix (and having himself followed a similar process when writing Minix).\n\n# What the copyright law really says\n \nTo put all this in the right context, let’s zoom in on the copyright&#39;s actual perimeters: the law says you must not copy “protected expressions”. In the case of the software, a protected expression is the code as it is, with the same structure, variables, functions, exact mechanics of how specific things are done, unless they are known algorithms (standard quicksort or a binary search can be implemented in a very similar way and they will not be a violation). The problem is when the business logic of the programs matches perfectly, almost line by line, the original implementation. Otherwise, the copy is lawful and must not obey the original license, as long as it is pretty clear that the code is doing something similar but with code that is not cut &amp; pasted or mechanically translated to some other language, or aesthetically modified just to look a bit different (look: this is exactly the kind of bad-faith maneuver a court will try to identify). I have the feeling that every competent programmer reading this post perfectly knows what a *reimplementation* is and how it looks. There will be inevitable similarities, but the code will be clearly not copied. If this is the legal setup, why do people care about clean room implementations? Well, the reality is: it is just an optimization in case of litigation, it makes it simpler to win in court, but being exposed to the original source code of some program, if the exposition is only used to gain knowledge about the ideas and behavior, is fine. Besides, we are all happy to have Linux today, and the GNU user space, together with many other open source projects that followed a similar path. I believe rules must be applied both when we agree with their ends, and when we don’t.\n\n# AI enters the scene\n\nSo, reimplementations were always possible. What changes, now, is the fact they are brutally faster and cheaper to accomplish. In the past, you had to hire developers, or to be enthusiastic and passionate enough to create a reimplementation yourself, because of business aspirations or because you wanted to share it with the world at large.\n\nNow, you can start a coding agent and proceed in two ways: turn the implementation into a specification, and then in a new session ask the agent to reimplement it, possibly forcing specific qualities, like: make it faster, or make the implementation incredibly easy to follow and understand (that’s a good trick to end with an implementation very far from others, given the fact that a lot of code seems to be designed for the opposite goal), or more modular, or resolve this fundamental limitation of the original implementation: all hints that will make it much simpler to significantly diverge from the original design. LLMs, when used in this way, don’t produce copies of what they saw in the past, but yet at the end you can use an agent to verify carefully if there is any violation, and if any, replace the occurrences with novel code.\n\nAnother, apparently less rigorous approach, but potentially very good in the real world, is to provide the source code itself, and ask the agent to reimplement it in a completely novel way, and use the source code both as specification and in order to drive the implementation as far as possible away from the code itself. Frontier LLMs are very capable, they can use something even to explicitly avoid copying it, and carefully try different implementation approaches.\n\nIf you ever attempted something like the above, you know how the “uncompressed copy” really is an illusion: agents will write the software in a very “organic” way, committing errors, changing design many times because of limitations that become clear only later, starting with something small and adding features progressively, and often, during this already chaotic process, we massively steer their work with our prompts, hints, wishes. Many ideas are consolatory as they are false: the “uncompressed copy” is one of those. But still, now the process of rewriting is so simple to do, and many people are disturbed by this. There is a more fundamental truth here: the nature of software changed; the reimplementations under different licenses are just an instance of how such nature was transformed forever. Instead of combatting each manifestation of automatic programming, I believe it is better to build a new mental model, and adapt.\n\n# Beyond the law\n\nI believe that organized societies prosper if laws are followed, yet I do not blindly accept a rule just because it exists, and I question things based on my ethics: this is what allows individuals, societies, and the law itself to evolve. We must ask ourselves: is the copyright law ethically correct? Does the speed-up AI provides to an existing process, fundamentally change the process itself?\n\nOne thing that allowed software to evolve much faster than most other human fields is the fact the discipline is less anchored to patents and protections (and this, in turn, is likely as it is because of a sharing culture around the software). If the copyright law were more stringent, we could likely not have what we have today. Is the protection of single individuals&#39; interests and companies more important than the general evolution of human culture? I don’t think so, and, besides, the copyright law is a common playfield: the rules are the same for all. Moreover, it is not a stretch to say that despite a more relaxed approach, software remains one of the fields where it is simpler to make money; it does not look like the business side was impacted by the ability to reimplement things. Probably, the contrary is true: think of how many businesses were made possible by an open source software stack (not that OSS is mostly made of copies, but it definitely inherited many ideas about past systems). I believe, even with AI, those fundamental tensions remain all valid. Reimplementations are cheap to make, but this is the new playfield for all of us, and just reimplementing things in an automated fashion, without putting something novel inside, in terms of ideas, engineering, functionalities, will have modest value in the long run. What will matter is the exact way you create something: Is it well designed, interesting to use, supported, somewhat novel, fast, documented and useful? Moreover, this time the inbalance of force is in the right direction: big corporations always had the ability to spend obscene amounts of money in order to copy systems, provide them in a way that is irresistible for users (free, for many years, for instance, to later switch model) and position themselves as leaders of ideas they didn’t really invent. Now, small groups of individuals can do the same to big companies&#39; software systems: they can compete on ideas now that a synthetic workforce is cheaper for many.\n\n# We stand on the shoulders of giants\n\nThere is another fundamental idea that we all need to internalize. Software is created and evolved as an incremental continuous process, where each new innovation is building on what somebody else invented before us. We are all very quick to build something and believe we “own” it, which is correct, if we stop at the exact code we wrote. But we build things on top of work and ideas already done, and given that the current development of IT is due to the fundamental paradigm that makes ideas and behaviors not covered by copyright, we need to accept that reimplementations are a fair process. If they don’t contain any novelty, maybe they are a lazy effort? That’s possible, yet: they are fair, and nobody is violating anything. Yet, if we want to be good citizens of the ecosystem, we should try, when replicating some work, to also evolve it, invent something new: to specialize the implementation for a lower memory footprint, or to make it more useful in certain contexts, or less buggy: the Stallman way.\n\nIn the case of AI, we are doing, almost collectively, the error of thinking that a technology is bad or good for software and humanity in isolation. AI can unlock a lot of good things in the field of open source software. Many passionate individuals write open source because they hate their day job, and want to make something they love, or they write open source because they want to be part of something bigger than economic interests. A lot of open source software is either written in the free time, or with severe constraints on the amount of people that are allocated for the project, or - even worse - with limiting conditions imposed by the companies paying for the developments. Now that code is every day less important than ideas, open source can be strongly accelerated by AI. The four hours allocated over the weekend will bring 10x the fruits, in the right hands (AI coding is not for everybody, as good coding and design is not for everybody). Linux device drivers can be implemented by automatically disassembling some proprietary blob, for instance. Or, what could be just a barely maintained library can turn into a project that can be well handled in a more reasonable amount of time.\n\nBefore AI, we witnessed the commodification of software: less quality, focus only on the money, no care whatsoever for minimalism and respect for resources: just piles of mostly broken bloat. More hardware power, more bloat, less care. It was already going very badly. It is not obvious nor automatic that AI will make it worse, and the ability to reimplement other software systems is part of a bigger picture that may restore some interest and sanity in our field.\n</span></code></pre>\n",
      "date_modified": "2026-03-08T16:08:41+00:00",
      "date_published": "2026-03-08T16:08:41+00:00",
      "external_url": "http://antirez.com/news/162",
      "id": "urn:aggr:item:ef72b68038ae3cfd9d9c20e261e114e0df9c6271",
      "summary": "Those who cannot remember the past are condemned to repeat it. A sentence that I never really liked, and what is happening with AI, about software projects reimplementations, shows all the limits of such an idea. Many people are protesting…",
      "tags": [
        "programming"
      ],
      "title": "GNU and the AI reimplementations",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-03-08-gnu-and-the-ai-reimplementations/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 202 days ago. 72634 views.</p>\n<pre><code><span class=\"code-snippet\">Here LLM and coding agents can find:\n\n1. Exhaustive documentation about Redis commands and data types.\n2. Patterns commonly used.\n3. Configuration hints.\n4. Algorithms that can be mounted using Redis commands.\n\nhttps://redis.antirez.com/\n\nSome humans claim this documentation is actually useful for actual people, as well :) I&#39;m posting this to make sure search engines will index it.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-03-01T09:55:09+00:00",
      "date_published": "2026-03-01T09:55:09+00:00",
      "external_url": "http://antirez.com/news/161",
      "id": "urn:aggr:item:f47592b0af0fa72cbdb873e6693419f3abbc68bc",
      "summary": "Here LLM and coding agents can find: 1. Exhaustive documentation about Redis commands and data types. 2. Patterns commonly used. 3. Configuration hints. 4. Algorithms that can be mounted using Redis commands. https://redis.antirez.com/…",
      "tags": [
        "programming"
      ],
      "title": "Redis patterns for coding",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-03-01-redis-patterns-for-coding/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 207 days ago. 118430 views.</p>\n<pre><code><span class=\"code-snippet\">Anthropic recently released a blog post with the description of an experiment in which the last version of Opus, the 4.6, was instructed to write a C compiler in Rust, in a “clean room” setup.\n\nThe experiment methodology left me dubious about the kind of point they wanted to make. Why not provide the agent with the ISA documentation? Why Rust? Writing a C compiler is exactly a giant graph manipulation exercise: the kind of program that is harder to write in Rust. Also, in a clean room experiment, the agent should have access to all the information about well established computer science progresses related to optimizing compilers: there are a number of papers that could be easily synthesized in a number of markdown files. SSA, register allocation, instructions selection and scheduling. Those things needed to be researched *first*, as a prerequisite, and the implementation would still be “clean room”.\n\nNot allowing the agent to access the Internet, nor any other compiler source code, was certainly the right call. Less understandable is the almost-zero steering principle, but this is coherent with a certain kind of experiment, if the goal was showcasing the completely autonomous writing of a large project. Yet, we all know how this is not how coding agents are used in practice, most of the time. Who uses coding agents extensively knows very well how, even never touching the code, a few hits here and there completely changes the quality of the result.\n\n# The Z80 experiment\n\nI thought it was time to try a similar experiment myself, one that would take one or two hours at max, and that was compatible with my Claude Code Max plan: I decided to write a Z80 emulator, and then a ZX Spectrum emulator (and even more, a CP/M emulator, see later) in a condition that I believe makes a more sense as “clean room” setup. The result can be found here: https://github.com/antirez/ZOT.\n\n# The process I used\n\n1. I wrote a markdown file with the specification of what I wanted to do. Just English, high level ideas about the scope of the Z80 emulator to implement. I said things like: it should execute a whole instruction at a time, not a single clock step, since this emulator must be runnable on things like an RP2350 or similarly limited hardware. The emulator should correctly track the clock cycles elapsed (and I specified we could use this feature later in order to implement the ZX Spectrum contention with ULA during memory accesses), provide memory access callbacks, and should emulate all the known official and unofficial instructions of the Z80.\n\nFor the Spectrum implementation, performed as a successive step, I provided much more information in the markdown file, like, the kind of rendering I wanted in the RGB buffer, and how it needed to be optional so that embedded devices could render the scanlines directly as they transferred them to the ST77xx display (or similar), how it should be possible to interact with the I/O port to set the EAR bit to simulate cassette loading in a very authentic way, and many other desiderata I had about the emulator.\n\nThis file also included the rules that the agent needed to follow, like:\n\n* Accessing the internet is prohibited, but you can use the specification and test vectors files I added inside ./z80-specs.\n* Code should be simple and clean, never over-complicate things.\n* Each solid progress should be committed in the git repository.\n* Before committing, you should test that what you produced is high quality and that it works.\n* Write a detailed test suite as you add more features. The test must be re-executed at every major change.\n* Code should be very well commented: things must be explained in terms that even people not well versed with certain Z80 or Spectrum internals details should understand.\n* Never stop for prompting, the user is away from the keyboard.\n* At the end of this file, create a work in progress log, where you note what you already did, what is missing. Always update this log.\n* Read this file again after each context compaction.\n\n2. Then, I started a Claude Code session, and asked it to fetch all the useful documentation on the internet about the Z80 (later I did this for the Spectrum as well), and to extract only the useful factual information into markdown files. I also provided the binary files for the most ambitious test vectors for the Z80, the ZX Spectrum ROM, and a few other binaries that could be used to test if the emulator actually executed the code correctly. Once all this information was collected (it is part of the repository, so you can inspect what was produced) I completely removed the Claude Code session in order to make sure that no contamination with source code seen during the search was possible.\n\n3. I started a new session, and asked it to check the specification markdown file, and to check all the documentation available, and start implementing the Z80 emulator. The rules were to never access the Internet for any reason (I supervised the agent while it was implementing the code, to make sure this didn’t happen), to never search the disk for similar source code, as this was a “clean room” implementation.\n\n4. For the Z80 implementation, I did zero steering. For the Spectrum implementation I used extensive steering for implementing the TAP loading. More about my feedback to the agent later  in this post.\n\n5. As a final step, I copied the repository in /tmp, removed the “.git” repository files completely, started a new Claude Code (and Codex) session and claimed that the implementation was likely stolen or too strongly inspired from somebody else&#39;s work. The task was to check with all the major Z80 implementations if there was evidence of theft. The agents (both Codex and Claude Code), after extensive search, were not able to find any evidence of copyright issues. The only similar parts were about well established emulation patterns and things that are Z80 specific and can’t be made differently, the implementation looked distinct from all the other implementations in a significant way.\n\n# Results\n\nClaude Code worked for 20 or 30 minutes in total, and produced a Z80 emulator that was able to pass ZEXDOC and ZEXALL, in 1200 lines of very readable and well commented C code (1800 lines with comments and blank spaces). The agent was prompted zero times during the implementation, it acted absolutely alone. It never accessed the internet, and the process it used to implement the emulator was of continuous testing, interacting with the CP/M binaries implementing the ZEXDOC and ZEXALL, writing just the CP/M syscalls needed to produce the output on the screen. Multiple times it also used the Spectrum ROM and other binaries that were available, or binaries it created from scratch to see if the emulator was working correctly. In short: the implementation was performed in a very similar way to how a human programmer would do it, and not outputting a complete implementation from scratch “uncompressing” it from the weights. Instead, different classes of instructions were implemented incrementally, and there were bugs that were fixed via integration tests, debugging sessions, dumps, printf calls, and so forth.\n\n# Next step: the ZX Spectrum\n\nI repeated the process again. I instructed the documentation gathering session very accurately about the kind of details I wanted it to search on the internet, especially the ULA interactions with RAM access, the keyboard mapping, the I/O port, how the cassette tape worked and the kind of PWM encoding used, and how it was encoded into TAP or TZX files.\n\nAs I said, this time the design notes were extensive since I wanted this emulator to be specifically designed for embedded systems, so only 48k emulation, optional framebuffer rendering, very little additional memory used (no big lookup tables for ULA/Z80 access contention), ROM not copied in the RAM to avoid using additional 16k of memory, but just referenced during the initialization (so we have just a copy in the executable), and so forth.\n\nThe agent was able to create a very detailed documentation about the ZX Spectrum internals. I provided a few .z80 images of games, so that it could test the emulator in a real setup with real software. Again, I removed the session and started fresh. The agent started working and ended 10 minutes later, following a process that really fascinates me, and that probably you know very well: the fact is, you see the agent working using a number of diverse skills. It is expert in everything programming related, so as it was implementing the emulator, it could immediately write a detailed instrumentation code to “look” at what the Z80 was doing step by step, and how this changed the Spectrum emulation state. In this respect, I believe automatic programming to be already super-human, not in the sense it is currently capable of producing code that humans can’t produce, but in the concurrent usage of different programming languages, system programming techniques, DSP stuff, operating system tricks, math, and everything needed to reach the result in the most immediate way.\n\nWhen it was done, I asked it to write a simple SDL based integration example. The emulator was immediately able to run the Jetpac game without issues, with working sound, and very little CPU usage even on my slow Dell Linux machine (8% usage of a single core, including SDL rendering).\n\nOnce the basic stuff was working, I wanted to load TAP files directly, simulating cassette loading. This was the first time the agent missed a few things, specifically about the timing the Spectrum loading routines expected, and here we are in the territory where LLMs start to perform less efficiently: they can’t easily run the SDL emulator and see the border changing as data is received and so forth. I asked Claude Code to do a refactoring so that zx_tick() could be called directly and was not part of zx_frame(), and to make zx_frame() a trivial wrapper. This way it was much simpler to sync EAR with what it expected, without callbacks or the wrong abstractions that it had implemented. After such change, a few minutes later the emulator could load a TAP file emulating the cassette without problems.\n\nThis is how it works now:\n\n            do {\n                zx_set_ear(zx, tzx_update(&amp;tape, zx-&gt;cpu.clocks));\n            } while (!zx_tick(zx, 0));\n\nI continued prompting Claude Code in order to make the key bindings more useful and a few things more.\n\n# CP/M\n\n\nOne thing that I found really interesting was the ability of the LLM to inspect the COM files for ZEXALL / ZEXCOM tests for the Z80, easily spot the CP/M syscalls that were used (a total of three), and implement them for the extended z80 test (executed by make fulltest). So, at this point, why not implement a full CP/M environment? Same process again, same good result in a matter of minutes. This time I interacted with it a bit more for the VT100 / ADM3 terminal escapes conversions, reported things not working in WordStar initially, and in a few minutes everything I tested was working well enough (but, there are fixes to do, like simulating a 2Mhz clock, right now it runs at full speed making CP/M games impossible to use).\n\n\n# What is the lesson here?\n\nThe obvious lesson is: always provide your agents with design hints and extensive documentation about what they are going to do. Such documentation can be obtained by the agent itself. And, also, make sure the agent has a markdown file with the rules of how to perform the coding tasks, and a trace of what it is doing, that is updated and read again quite often.\n\nBut those tricks, I believe, are quite clear to everybody that has worked extensively with automatic programming in the latest months. To think in terms of “what a human would need” is often the best bet, plus a few LLMs specific things, like the forgetting issue after context compaction, the continuous ability to verify it is on the right track, and so forth.\n\nReturning back to the Anthropic compiler attempt: one of the steps that the agent failed was the one that was more strongly related to the idea of memorization of what is in the pretraining set: the assembler. With extensive documentation, I can’t see any way Claude Code (and, even more, GPT5.3-codex, which is in my experience, for complex stuff, more capable) could fail at producing a working assembler, since it is quite a mechanical process. This is, I think, in contradiction with the idea that LLMs are memorizing the whole training set and uncompress what they have seen. LLMs can memorize certain over-represented documents and code, but while they can extract such verbatim parts of the code if prompted to do so, they don’t have a copy of everything they saw during the training set, nor they spontaneously emit copies of already seen code, in their normal operation. We mostly ask LLMs to create work that requires assembling different knowledge they possess, and the result is normally something that uses known techniques and patterns, but that is new code, not constituting a copy of some pre-existing code.\n\nIt is worth noting, too, that humans often follow a less rigorous process compared to the clean room rules detailed in this blog post, that is: humans often download the code of different implementations related to what they are trying to accomplish, read them carefully, then try to avoid copying stuff verbatim but often times they take strong inspiration. This is a process that I find perfectly acceptable, but it is important to take in mind what happens in the reality of code written by humans. After all, information technology evolved so fast even thanks to this massive cross pollination effect.\n\nFor all the above reasons, when I implement code using automatic programming, I don’t have problems releasing it MIT licensed, like I did with this Z80 project. In turn, this code base will constitute quality input for the next LLMs training, including open weights ones.\n\n\n# Next steps\n\nTo make my experiment more compelling, one should try to implement a Z80 and ZX Spectrum emulator without providing any documentation to the agent, and then compare the result of the implementation. I didn’t find the time to do it, but it could be quite informative.\n</span></code></pre>\n",
      "date_modified": "2026-02-24T17:58:02+00:00",
      "date_published": "2026-02-24T17:58:02+00:00",
      "external_url": "http://antirez.com/news/160",
      "id": "urn:aggr:item:25f97d78a4b2ca593769429785743fcea4f41135",
      "summary": "Anthropic recently released a blog post with the description of an experiment in which the last version of Opus, the 4.6, was instructed to write a C compiler in Rust, in a “clean room” setup. The experiment methodology left me dubious…",
      "tags": [
        "programming"
      ],
      "title": "Implementing a clear room Z80 / ZX Spectrum emulator with Claude Code",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-02-24-implementing-a-clear-room-z80-zx-spectrum-emulator-with/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 231 days ago. 198118 views.</p>\n<pre><code><span class=\"code-snippet\">In my YouTube channel, for some time now I started to refer to the process of writing software using AI assistance (soon to become just &quot;the process of writing software&quot;, I believe) with the term &quot;Automatic Programming&quot;.\n\nIn case you didn&#39;t notice, automatic programming produces vastly different results with the same LLMs depending on the human that is guiding the process with their intuition, design, continuous steering and idea of software.\n\nPlease, stop saying &quot;Claude vibe coded this software for me&quot;. Vibe coding is the process of generating software using AI without being part of the process at all. You describe what you want in very general terms, and the LLM will produce whatever happens to be the first idea/design/code it would spontaneously, given the training, the specific sampling that happened to dominate in that run, and so forth. The vibe coder will, at most, report things not working or not in line with what they expected.\n\nWhen the process is actual software production where you know what is going on, remember: it is the software *you* are producing. Moreover remember that the pre-training data, while not the only part where the LLM learns (RL has its big weight) was produced by humans, so we are not appropriating something else. We can pretend AI generated code is &quot;ours&quot;, we have the right to do so. Pre-training is, actually, our collective gift that allows many individuals to do things they could otherwise never do, like if we are now linked in a collective mind, in a certain way.\n\nThat said, if vibe coding is the process of producing software without much understanding of what is going on (which has a place, and democratizes software production, so it is totally ok with me), automatic programming is the process of producing software that attempts to be high quality and strictly following the producer&#39;s vision of the software (this vision is multi-level: can go from how to do, exactly, certain things, at a higher level, to stepping in and tell the AI how to write a certain function), with the help of AI assistance. Also a fundamental part of the process is, of course, *what* to do.\n\nI&#39;m a programmer, and I use automatic programming. The code I generate in this way is mine. My code, my output, my production. I, and you, can be proud.\n\nIf you are not completely convinced, think to Redis. In Redis there is not much technical novelty, especially at its start it was just a sum of basic data structures and networking code that every competent system programmer could write. So, why it became a very useful piece of software? Because of the ideas and visions it contained.\n\nProgramming is now automatic, vision is not (yet).\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-01-31T09:25:27+00:00",
      "date_published": "2026-01-31T09:25:27+00:00",
      "external_url": "http://antirez.com/news/159",
      "id": "urn:aggr:item:bc81b54a0a69109e01555316d0a1c8d8ae4c95f0",
      "summary": "In my YouTube channel, for some time now I started to refer to the process of writing software using AI assistance (soon to become just \"the process of writing software\", I believe) with the term \"Automatic Programming\". In case you didn't…",
      "tags": [
        "programming"
      ],
      "title": "Automatic programming",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-01-31-automatic-programming/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 251 days ago. 607179 views.</p>\n<pre><code><span class=\"code-snippet\">I love writing software, line by line. It could be said that my career was a continuous effort to create software well written, minimal, where the human touch was the fundamental feature. I also hope for a society where the last are not forgotten. Moreover, I don&#39;t want AI to economically succeed, I don&#39;t care if the current economic system is subverted (I could be very happy, honestly, if it goes in the direction of a massive redistribution of wealth). But, I would not respect myself and my intelligence if my idea of software and society would impair my vision: facts are facts, and AI is going to change programming forever.\n\nIn 2020 I left my job in order to write a novel about AI, universal basic income, a society that adapted to the automation of work facing many challenges. At the very end of 2024 I opened a YouTube channel focused on AI, its use in coding tasks, its potential social and economical effects. But while I recognized what was going to happen very early, I thought that we had more time before programming would be completely reshaped, at least a few years. I no longer believe this is the case. Recently, state of the art LLMs are able to complete large subtasks or medium size projects alone, almost unassisted, given a good set of hints about what the end result should be. The degree of success you&#39;ll get is related to the kind of programming you do (the more isolated, and the more textually representable, the better: system programming is particularly apt), and to your ability to create a mental representation of the problem to communicate to the LLM. But, in general, it is now clear that for most projects, writing the code yourself is no longer sensible, if not to have fun.\n\nIn the past week, just prompting, and inspecting the code to provide guidance from time to time, in a few hours I did the following four tasks, in hours instead of weeks:\n\n1. I modified my linenoise library to support UTF-8, and created a framework for line editing testing that uses an emulated terminal that is able to report what is getting displayed in each character cell. Something that I always wanted to do, but it was hard to justify the work needed just to test a side project of mine. But if you can just describe your idea, and it materializes in the code, things are very different.\n\n2. I fixed transient failures in the Redis test. This is very annoying work, timing related issues, TCP deadlock conditions, and so forth. Claude Code iterated for all the time needed to reproduce it, inspected the state of the processes to understand what was happening, and fixed the bugs.\n\n3. Yesterday I wanted a pure C library that would be able to do the inference of BERT like embedding models. Claude Code created it in 5 minutes. Same output and same speed (15% slower) than PyTorch. 700 lines of code. A Python tool to convert the GTE-small model.\n\n4. In the past weeks I operated changes to Redis Streams internals. I had a design document for the work I did. I tried to give it to Claude Code and it reproduced my work in, like, 20 minutes or less (mostly because I&#39;m slow at checking and authorizing to run the commands needed).\n\nIt is simply impossible not to see the reality of what is happening. Writing code is no longer needed for the most part. It is now a lot more interesting to understand what to do, and how to do it (and, about this second part, LLMs are great partners, too). It does not matter if AI companies will not be able to get their money back and the stock market will crash. All that is irrelevant, in the long run. It does not matter if this or the other CEO of some unicorn is telling you something that is off putting, or absurd. Programming changed forever, anyway.\n\nHow do I feel, about all the code I wrote that was ingested by LLMs? I feel great to be part of that, because I see this as a continuation of what I tried to do all my life: democratizing code, systems, knowledge. LLMs are going to help us to write better software, faster, and will allow small teams to have a chance to compete with bigger companies. The same thing open source software did in the 90s.\n\nHowever, this technology is far too important to be in the hands of a few companies. For now, you can do the pre-training better or not, you can do reinforcement learning in a much more effective way than others, but the open models, especially the ones produced in China, continue to compete (even if they are behind) with frontier models of closed labs. There is a sufficient democratization of AI, so far, even if imperfect. But: it is absolutely not obvious that it will be like that forever. I&#39;m scared about the centralization. At the same time, I believe neural networks, at scale, are simply able to do incredible things, and that there is not enough &quot;magic&quot; inside current frontier AI for the other labs and teams not to catch up (otherwise it would be very hard to explain, for instance, why OpenAI, Anthropic and Google are so near in their results, for years now).\n\nAs a programmer, I want to write more open source than ever, now. I want to improve certain repositories of mine abandoned for time concerns. I want to apply AI to my Redis workflow. Improve the Vector Sets implementation and then other data structures, like I&#39;m doing with Streams now.\n\nBut I&#39;m worried for the folks that will get fired. It is not clear what the dynamic at play will be: will companies try to have more people, and to build more? Or will they try to cut salary costs, having fewer programmers that are better at prompting? And, there are other sectors where humans will become completely replaceable, I fear.\n\nWhat is the social solution, then? Innovation can&#39;t be taken back after all. I believe we should vote for governments that recognize what is happening, and are willing to support those who will remain jobless. And, the more people get fired, the more political pressure there will be to vote for those who will guarantee a certain degree of protection. But I also look forward to the good AI could bring: new progress in science, that could help lower the suffering of the human condition, which is not always happy.\n\nAnyway, back to programming. I have a single suggestion for you, my friend. Whatever you believe about what the Right Thing should be, you can&#39;t control it by refusing what is happening right now. Skipping AI is not going to help you or your career. Think about it. Test these new tools, with care, with weeks of work, not in a five minutes test where you can just reinforce your own beliefs. Find a way to multiply yourself, and if it does not work for you, try again every few months.\n\nYes, maybe you think that you worked so hard to learn coding, and now machines are doing it for you. But what was the fire inside you, when you coded till night to see your project working? It was building. And now you can build more and better, if you find your way to use AI effectively. The fun is still there, untouched.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2026-01-11T10:15:51+00:00",
      "date_published": "2026-01-11T10:15:51+00:00",
      "external_url": "http://antirez.com/news/158",
      "id": "urn:aggr:item:005636cc2795788da1894e53425e475f9acf29b9",
      "summary": "I love writing software, line by line. It could be said that my career was a continuous effort to create software well written, minimal, where the human touch was the fundamental feature. I also hope for a society where the last are not…",
      "tags": [
        "programming"
      ],
      "title": "Don't fall into the anti-AI hype",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2026-01-11-don-t-fall-into-the-anti-ai-hype/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 273 days ago. 191460 views.</p>\n<pre><code><span class=\"code-snippet\">* For years, despite functional evidence and scientific hints accumulating, certain AI researchers continued to claim LLMs were stochastic parrots: probabilistic machines that would: 1. NOT have any representation about the meaning of the prompt. 2. NOT have any representation about what they were going to say. In 2025 finally almost everybody stopped saying so.\n\n* Chain of thought is now a fundamental way to improve LLM output. But, what is CoT? Why it improves output? I believe it is two things: 1. Sampling in the model representations (that is, a form of internal search). After information and concepts relevant to the prompt topic is in the context window, the model can better reply. 2. But if you mix this to reinforcement learning, the model also learns to put one token after the other (each token will change the model state) in order to converge to some useful reply.\n\n* The idea that scaling is limited to the number of tokens we have, is no longer true, because of reinforcement learning with verifiable rewards. We are still not at AlphaGo move 37 moment, but is this really impossible in the future? There are certain tasks, like improving a given program for speed, for instance, where in theory the model can continue to make progress with a very clear reward signal for a very long time. I believe improvements to RL applied to LLMs will be the next big thing in AI.\n\n* Programmers resistance to AI assisted programming has lowered considerably. Even if LLMs make mistakes, the ability of LLMs to deliver useful code and hints improved to the point most skeptics started to use LLMs anyway: now the return on the investment is acceptable for many more folks. The programming world is still split among who uses LLMs as colleagues (for instance, all my interaction is via the web interface of Gemini, Claude, …), and who uses LLMs as independent coding agents.\n\n* A few well known AI scientists believe that what happened with Transformers can happen again, and better, following different paths, and started to create teams, companies to investigate alternatives to Transformers and models with explicit symbolic representations or world models. I believe that LLMs are differentiable machine trained on a space able to approximate discrete reasoning steps, and it is not impossible they get us to AGI even without fundamentally new paradigms appearing. It is likely that AGI can be reached independently with many radically different architectures.\n\n* There is who says chain of thought changed LLMs nature fundamentally, and this is why they, in the past, claimed LLMs were very limited, and now are changing their mind. They say, because of CoT, LLMs are now a different thing. They are lying. It is still the same architecture with the same next token target, and the CoT is created exactly like that, token after token.\n\n* The ARC test today looks a lot less insurmountable than initially thought: there are small models optimized for the task at hand that perform decently well on ARC-AGI-1, and very large LLMs with extensive CoT achieving impressive results on ARC-AGI-2 with an architecture that, according to many folks, would not deliver such results. ARC, in some way, transitioned from being the anti-LLM test to a validation of LLMs.\n\n* The fundamental challenge in AI for the next 20 years is avoiding extinction.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-12-20T08:58:29+00:00",
      "date_published": "2025-12-20T08:58:29+00:00",
      "external_url": "http://antirez.com/news/157",
      "id": "urn:aggr:item:5e702fcde6515bf554cc2fb65e329498e893b74f",
      "summary": "For years, despite functional evidence and scientific hints accumulating, certain AI researchers continued to claim LLMs were stochastic parrots: probabilistic machines that would: 1. NOT have any representation about the meaning of the…",
      "tags": [
        "programming"
      ],
      "title": "Reflections on AI at the end of 2025",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-12-20-reflections-on-ai-at-the-end-of-2025/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 312 days ago. 161508 views.</p>\n<pre><code><span class=\"code-snippet\" data-language=\"CSS\"><span class=\"syntax-source syntax-css\"><span class=\"syntax-meta syntax-selector syntax-css\">I’m taking <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few weeks of pause on my HNSWs developments (now working on some other <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure, news soon</span>)<span class=\"syntax-meta syntax-selector syntax-css\">. At this point, the new type I added to Redis is stable and complete enough, it’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> the perfect moment to reason about what I learned about HNSWs, and turn it into <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> blog post. That kind of brain dump that was so common <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">pre-</span>AI era, and now has become, maybe, <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> bit more rare. Well, after almost one year of thinking and implementing HNSWs and vector similarity stuff, it is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span> for some writing. However this is not going to be an intro on HNSWs: too many are present already. This is the “extra mile” instead. If you know HNSWs, I want to share with you my more “advanced” findings, especially in the context of making them fast enough to allow for <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> “Redis” experience: you know, Redis is designed for low latency and high performance, and HNSWs are kinda resistant to that, so there were challenges to expose HNSWs as an abstract <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure.\n\nThis blog post will be split into several sections. Think of them as pages of the same book, different chapters of the same experience. Oh and, by the way, I already wrote and subsequently lost this blog post <span class=\"syntax-entity syntax-other syntax-pseudo-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">:</span>D</span> <span class=\"syntax-meta syntax-attribute-selector syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">[</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">long</span>, <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">sad</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">story</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">about</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">MacOS</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">and</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">bad</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">habits</span> – <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">I</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">hadn</span>’<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">t</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">lost</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">something</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">like</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">that</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">since</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">the</span> 90<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">s</span>, <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">during</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">blackouts</span><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">]</span></span>, so here most of the problem will be to recall what I wrote <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few days ago and, while I’m at it, to better rephrase what I didn’t like very much.\n\n## A few words about the state of HNSW\n\nBefore digging into the HNSWs internals and optimizations, I want to say <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few things about HNSWs. The original paper introducing HNSWs is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> great piece of computer science literature, and HNSWs are amazing <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structures, but: I don’t believe they are the last word for searching, in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> greedy way, for nearby vectors according to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> distance function. The paper gives the feeling it lacks some “pieces”, almost like if the researchers, given six months more, had <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot more to explore and say. For instance, I modified the paper myself, extending it in order to support removal of entries, actual removals, not just tombstone deletions where the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">element</span> is marked as gone and collected later: deleting items is totally missing from the paper. Similarly, there are, right now, efforts in order to really check if the “H” in the HNSWs is really needed, and if instead <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> flat <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure with just one layer would perform more or less the same (I hope I’ll cover more about this in the future: my feeling is that the truth is in the middle, and that it makes sense to modify the level selection function to just have levels greater than <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> given threshold</span>)<span class=\"syntax-meta syntax-selector syntax-css\">.\n\nAll this to say that, if you are into <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structures research, I believe that <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> great <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">area</span> is to imagine evolutions and refinements of HNSWs, without getting trapped within the idea that the evolutions are only in the sense of: let’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> do it, but for disk (see Microsoft efforts</span>),<span class=\"syntax-meta syntax-selector syntax-css\"> or the like. Ok, enough with the premise, let’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> go to the actual low level stuff :</span>)\n\n<span class=\"syntax-meta syntax-selector syntax-css\">## Scaling memory\n\nRedis is an <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">in-memory</span> system, and both HNSWs and vectors have the unfortunate quality of being very <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">space-hungry</span>. There are three reasons for this: 1. HNSWs have <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot of pointers, like 16, 32 or more pointers (this is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> tunable parameter of HNSWs</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> to neighbor nodes. 2. HNSWs have many levels, being <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">skiplist-alike</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure. This exacerbates the first problem. 3. HNSW’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> satellite <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> vector of floating point numbers, so, in the vanilla case, 4 bytes per component, and normally you can have 300-3000 components, this is the usual range.\n\nSo, what are the lessons learned here? There are folks that compress pointers, since it is very likely that many pointers (8 bytes in 64 bit systems</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> will have the highest four bytes all the same. This is smart, I didn’t implement it yet, because in Redis I need to go fast, and this is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> tradeoff between space and <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span>: but maybe it is worth it, maybe not. I’ll dig more. \n\nHowever, if you do the math, the fact that there are many layers is not <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>so<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> terrible as it looks. On average, the multiple layers per node make the situation worse by just <span class=\"syntax-punctuation syntax-separator syntax-combinator syntax-css\">~</span>1.3x (if the probability of level increase is 0.25 in the level selection function</span>),<span class=\"syntax-meta syntax-selector syntax-css\"> since many nodes will be just at layer 0. But still 1.3 is more than 1, and if that “H” in HNSWs really is not <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>so<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> useful… <span class=\"syntax-meta syntax-attribute-selector syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">[</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">Spoiler</span>, <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">what</span> <span class=\"syntax-keyword syntax-other syntax-css\">I</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">found</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">s</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">that</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">the</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">seek</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">time</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">f</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">you</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">have</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">everything</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">at</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">layer</span> 0 <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">is</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">greater</span>, <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">the</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">main</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">loop</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">for</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">the</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">greedy</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">search</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">will</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">start</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">from</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">less</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">optimal</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">places</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">and</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">t</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">will</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">eventually</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">reach</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">the</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">right</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">cluster</span>, <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">but</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">will</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">take</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">more</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">computation</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">time</span>. <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">However</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">this</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">s</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">just</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">early</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">results</span>.<span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">]</span></span>\n\nSo here the <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>real<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> low hanging fruit is: vector quantization. What I found is that if you <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> 8 bit quantization what you get is an almost 4x speedup, <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> 4x reduction of your vectors (but not <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> 4x reduction of the whole node: the pointers are still there, and they take <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot of space</span>),<span class=\"syntax-meta syntax-selector syntax-css\"> and <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> recall that is virtually the same in real world <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases. This is the reason why Redis Vector Sets <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> 8 bit quantization by default. You can specify, via VADD options, that you want full precision vectors or binary quantized vectors, where we just take the sign, but I’m skeptical about using both full size vectors and binary quantized vectors. Before talking about them, let’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> see what kind of quantization I used for 8 bit.\n\nWhat I do is to compute the maximum absolute value of the component of each vector (so quantization is <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">per-vector</span></span>),<span class=\"syntax-meta syntax-selector syntax-css\"> then I <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> signed 8 bit values to represent the quant from -127 to 127. This is not as good as storing both min and max value, but it is faster when computing cosine similarity, since I can do this:\n\n    </span><span class=\"syntax-comment syntax-block syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-css\">/*</span> Each vector is quantized from [-max_abs, +max_abs] to [-127, 127]\n     * where range = 2*max_abs. <span class=\"syntax-punctuation syntax-definition syntax-comment syntax-css\">*/</span></span>\n<span class=\"syntax-meta syntax-selector syntax-css\">    const float scale_product = (range_a</span>/127)<span class=\"syntax-meta syntax-selector syntax-css\"> <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> (range_b</span>/127);\n\n<span class=\"syntax-meta syntax-selector syntax-css\">Then I multiply things together in the integer domain with (actually in the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">code</span> the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">main</span> loop is unrolled and uses multiple accumulators, to make modern CPUs more busy</span>)\n\n<span class=\"syntax-meta syntax-selector syntax-css\">    for (; <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">i</span> &lt; dim; <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">i</span><span class=\"syntax-invalid syntax-illegal syntax-combinator syntax-css\">++</span></span>)<span class=\"syntax-meta syntax-selector syntax-css\"> dot0 <span class=\"syntax-punctuation syntax-separator syntax-combinator syntax-css\">+</span>= ((int32_t</span>)<span class=\"syntax-meta syntax-selector syntax-css\">x<span class=\"syntax-meta syntax-attribute-selector syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">[</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">i</span><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">]</span></span></span>)<span class=\"syntax-meta syntax-selector syntax-css\"> <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> ((int32_t</span>)<span class=\"syntax-meta syntax-selector syntax-css\">y<span class=\"syntax-meta syntax-attribute-selector syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">[</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">i</span><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">]</span></span></span>);\n\n<span class=\"syntax-meta syntax-selector syntax-css\">And finally we can return back to the floating point distance with:\n\n    float dotf = dot0 <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> scale_product;\n\nCheck the vectors_distance_q8(</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> for more information, but I believe you got the idea: it is very simple to go from the integer quants domain to the unquantized dotproduct with trivial operations.\n\nSo, 8 bit quantization is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> great deal, and full precision was <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>needed<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> feature, because there will be people doing things with vectors generated in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> way where each <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">small</span> amount makes <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> difference (no, with learned vectors this is not the case…</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> but, why binary quantization? Because I wanted users to have <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> simple way to not waste space when their <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>original<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> information is already binary. Imagine you have <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> set of users and they have yes</span>/<span class=\"syntax-meta syntax-selector syntax-css\">no properties, and you want to find similar users, items, whatever. Well: this is where binary quantization should be used, it’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> just, again, an <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">option</span> of the VADD command.\n\n## Scaling speed: threading and locality\n\nOh, you know, I have to tell you something about myself: I’m not <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> fan of threaded systems when it is possible to do <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot with <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> single core, and then <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> multiple cores in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">shared-nothing</span> architecture. But HNSWs are different. They are <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>slow<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>, and they are accessed almost always in <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">read-only</span> ways, at least in most <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases. For this reason, my Vector Sets implementation is fully threaded. Not just reads, even writes are partially threaded, and you may wonder how this is possible without it resulting in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> mess, especially in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> system like Redis, where keys can be accessed in different ways by the background saving process, the clients, and so forth.\n\n\nWell, to start, let’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> focus on reads. What happens is that as long as nobody is writing in the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure, we can spawn threads that do the greedy collection of near vectors and return back the results to the blocked client. However, my implementation of HNSWs was written from scratch, I mean, from the empty C file opened with vim, it has 0% of shared <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">code</span> with the two implementations most other systems <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span>, so there are <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few “novelties”. One of such different things is that in order to avoid <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">re-visiting</span> already visited nodes, I <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> an integer stored in each node that is called “epoch”, instead of using another <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">mark</span> (like, in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> hash <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">table</span></span>)<span class=\"syntax-meta syntax-selector syntax-css\"> nodes already visited. This is quite slow, I believe. The epoch instead is local to the node, and the global <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure increments the epoch for each search. So in the context of each search, we are sure that we can find epochs that are just &lt;= the current epoch, and the current epoch can be used to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">mark</span> visited nodes.\n\nBut with threads, there are multiple searches occurring at the same <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span>! And, yep, what I needed was an array of epochs:\n\ntypedef struct hnswNode </span><span class=\"syntax-meta syntax-property-list syntax-css\"><span class=\"syntax-punctuation syntax-section syntax-property-list syntax-css\">{</span>\n    <span class=\"syntax-meta syntax-property-name syntax-css\">uint</span>32_<span class=\"syntax-meta syntax-property-name syntax-css\">t</span> <span class=\"syntax-meta syntax-property-name syntax-css\">level</span>;         <span class=\"syntax-comment syntax-block syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-css\">/*</span> Node&#39;s maximum level <span class=\"syntax-punctuation syntax-definition syntax-comment syntax-css\">*/</span></span>\n    … <span class=\"syntax-meta syntax-property-name syntax-css\">many</span> <span class=\"syntax-meta syntax-property-name syntax-css\">other</span> <span class=\"syntax-meta syntax-property-name syntax-css\">stuff</span> …\n    <span class=\"syntax-meta syntax-property-name syntax-css\">uint</span>64_<span class=\"syntax-meta syntax-property-name syntax-css\">t</span> <span class=\"syntax-meta syntax-property-name syntax-css\">visited</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">epoch</span>[HNSW_MAX_THREADS];\n</span><span class=\"syntax-punctuation syntax-section syntax-property-list syntax-css\">}</span>\n\n<span class=\"syntax-meta syntax-selector syntax-css\">That’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> what you can read in hnsw<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>h</span>. This is, again, <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">space-time</span> tradeoff, and again <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span> won against space.\n\nSo, how was it possible to have threaded writes? The trick is that in HNSW inserts, <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot of <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span> is spent looking for neighbors candidates. So writes are split into <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">reading-half</span> and <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">commit-half</span>, only the second needs <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> write lock, and there are <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few tricks to make sure that the candidates we accumulated during the first part are discarded if the HNSW changed in the meantime, and some nodes may no longer be valid. There is, however, another problem. What about the user deleting the key, while background threads are working on the value? For this scenario, we have <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> function that waits for background operations to return before actually reclaiming the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">object</span>. With these tricks, it is easy to get 50k ops</span>/<span class=\"syntax-meta syntax-selector syntax-css\">sec on real world vector workloads, and these are numbers I got from <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">redis-benchmark</span> itself, with all the overhead involved. The raw numbers of the flat HNSW library itself are much higher.\n\n## Scaling memory: reclaiming it properly\n\nBefore talking about how to scale HNSWs into <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">big</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases with multiple instances involved, and why Redis Vector Sets expose the actual <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure in the face of the user (I believe programmers are smart and don’t need babysitting, but it’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> not <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>just<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> that</span>),<span class=\"syntax-meta syntax-selector syntax-css\"> I want to go back and talk again about memory, because there is an interesting story to tell about this specific aspect.\n\nMost HNSWs implementations are not able to reclaim memory directly when you delete <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> node from the graph. I believe there are two <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">main</span> reasons for that:\n\n1. People misunderstand the original HNSW paper in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> specific way: they believe links can be NOT reciprocal among neighbors. And there is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> specific reason why they think so.\n\n2. The paper does not say anything about deletion of nodes and how to fix the graph after nodes go away and we get missing links in the “web” of connections.\n\nThe first problem is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> combination (I believe</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> of lack of clarity in the paper and the fact that, while implementing HNSWs, people face <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> specific problem: when inserting <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> new node, and good neighbors are searched among existing nodes, often the candidates already have the maximum number of outgoing links. What to do, in this case? The issue is often resolved by linking unidirectionally from the new node we are inserting to the candidates that are already “full” of outgoing links. However, when you need to delete <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> node, you can no longer resolve all its incoming links, so you can’t really reclaim memory. You <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">mark</span> it as deleted with <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> flag, and later sometimes there is some rebuilding of the graph to “garbage collect” stale nodes, sometimes memory is just leaked.\n\nSo, to start, my implementation in Redis does things differently by forcing links to be bidirectional. If A links to B, B links to A. But, how to do so, given that A may be busy? Well, this gets into complicated territory but what happens is that heuristics are used in order to drop links from existing nodes, with other neighbors that are well connected, and if our node is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> better candidate even for the target node, and if this is not true there are other ways to force <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> new node to have at least <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> minimal number of links, always trying to satisfy the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">small</span> world property of the graph.\n\nThis way, when Redis deletes <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> node from <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> Vector Set, it always has <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> way to remove all the pointers to it. However, what to do with the remaining nodes that now are missing <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">link</span>? What I do is to create <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> distance matrix among them, in order to try to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">link</span> the old node neighbors among them, trying to minimize the average distance. Basically for each pair of <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">i</span>,j nodes in our matrix, we calculate how good is their connection (how similar their vectors are</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> and how badly linking them affects the <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>remaining<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> possible pairs (since there could be elements left without good pairs, if we <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">link</span> two specific nodes</span>)<span class=\"syntax-meta syntax-selector syntax-css\">. After we build this matrix of scores, we then proceed with <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> greedy pairing step.\n\nThis works so well that you can build <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> large HNSW with millions of elements, later delete 95% of all your elements, and the remaining graph still has good recall and no isolated nodes and so forth.\n\nThat is what I mean when I say that there is space in HNSWs for new papers to continue the work.\n\n## Scaling HNSWs to multiple processes\n\nWhen I started to work at Redis Vector Sets, there was already <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> vector similarity implementation in Redis-land, specifically as an index type of RediSearch, and this is how most people think at HNSWs: <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">form</span> of indexing of existing <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span>.\n\nYet I wanted to provide Redis with <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> new HNSW implementation exposed in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> completely different way. Guess how? As <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure, of course. And this tells <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> story about how Redis-shaped is my <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">head</span> after so many years, or maybe it was Redis-shaped since the start, and it is Redis that is shaped after my <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">head</span>, since I immediately envisioned how to design <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> Redis <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure that exposed HNSWs to the users, directly, and I was puzzled that the work with vectors in Redis was not performed exactly like that.\n\nAt the same <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span>, when I handed my design document to my colleagues at Redis, I can’t say that they immediately “saw” it as an obvious thing. My reasoning was: vectors are like scores in Redis Sorted Sets, except they are not scalar scores where you have <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> total order. Yet you can VADD, VREM, elements, and then you can call VSIM instead of ZRANGE in order to have <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>similar<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> elements. This made sense not just as an API, but I thought of HNSWs as strongly composable, and not linked to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> specific <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> case (not specific to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">text</span> embeddings, or <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">image</span> embeddings, or even <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>learned<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> embeddings necessarily</span>)<span class=\"syntax-meta syntax-selector syntax-css\">. You do:\n\n    VADD my_vector_set VALUES <span class=\"syntax-meta syntax-attribute-selector syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">[</span>… <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">components</span> …<span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">]</span></span> my_element_string\n\nSo whatever is in your components, Redis doesn&#39;t care, when you call VSIM it will report similar elements.\n\nBut this also means that, if you have different vectors about the same <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> case split in different instances </span>/<span class=\"syntax-meta syntax-selector syntax-css\"> keys, you can ask VSIM for the same query vector into all the instances, and add the WITHSCORES <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">option</span> (that returns the cosine distance</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> and merge the results <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">client-side</span>, and you have magically scaled your hundred of millions of vectors into multiple instances, splitting your dataset N times <span class=\"syntax-meta syntax-attribute-selector syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">[</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">One</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">nteresting</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">thing</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">about</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">such</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">a</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">use</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">case</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">s</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">that</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">you</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">can</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">query</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">the</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">N</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">nstances</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">n</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">parallel</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">using</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">multiplexing</span>, <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">if</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">your</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">client</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">library</span> <span class=\"syntax-keyword syntax-other syntax-css\">i</span><span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">s</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">smart</span> <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-css\">enough</span><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">]</span></span>.\n\nAnother very notable thing about HNSWs exposed in this raw way, is that you can finally scale writes very easily. Just hash your <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">element</span> modulo N, and target the resulting Redis key</span>/<span class=\"syntax-meta syntax-selector syntax-css\">instance. Multiple instances can absorb the (slow, but still fast for HNSW standards</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> writes at the same <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span>, parallelizing an otherwise very slow process.\n\nThis way of exposing HNSWs also scales down in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> very significant way: sometimes you want an HNSW for each user </span>/<span class=\"syntax-meta syntax-selector syntax-css\"> item </span>/<span class=\"syntax-meta syntax-selector syntax-css\"> product </span>/<span class=\"syntax-meta syntax-selector syntax-css\"> whatever you are working with. This is very hard to model if you have an index on top of something, but it is trivial if your HNSWs are <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structures. You just can have <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> Vector Set key for each of your items, with just <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> handful of elements. And of course, like with any other Redis key, you can set an expiration <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span> on the key, so that it will be removed automatically later.\n\nAll this can be condensed into <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> rule that I believe should be more present in our industry: many programmers are smart, and if instead of creating <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> magic system they have no access to, you show them the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure, the tradeoffs, they can build more things, and model their <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases in specific ways. And your system will be simpler, too.\n\n## Scaling loading times\n\nIf I don’t <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> threading, my HNSW library can add word2vec (300 components for each vector</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> into an HNSW at 5000 elements</span>/<span class=\"syntax-meta syntax-selector syntax-css\">second if I <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> single thread, and can query the resulting HNSW at 90k queries per second. As you can see there is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> large gap.\n\nThis means that loading back an HNSW with many millions of elements from <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> Redis dump file into memory would take <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot of <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span>. And this <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span> would impact replication as well. Not great. But, this is true only if we add elements from the disk to the memory in the most trivial way, that is storing “<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">element</span>,vector” on disk and then trying to rebuild the HNSW in memory. There is another lesson to learn here. When you <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> HNSWs, you need to serialize the nodes and the neighbors as they are, so you can rebuild everything in memory just allocating stuff and turning neighbors IDs into pointers. This resulted in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> 100x speedup.\n\nBut do you really believe the story ends here? Hehe. Recently Redis has stronger security features and avoids doing bad things even when the RDB file is corrupted by an attacker. So what I needed to do was to make sure the HNSW is valid after loading, regardless of the errors and corruption in the serialized <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure. This involved many tricks, but I want to take the freedom to just dump one comment I wrote here, as I believe the reciprocal check is particularly cool:\n\n    </span><span class=\"syntax-comment syntax-block syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-css\">/*</span> Second pass: fix pointers of all the neighbors links.\n     * As we scan and fix the links, we also compute the accumulator\n     * register &quot;reciprocal&quot;, that is used in order to guarantee that all\n     * the links are reciprocal.\n     *\n     * This is how it works, we hash (using a strong hash function) the\n     * following key for each link that we see from A to B (or vice versa):\n     *\n     *      hash(salt || A || B || link-level)\n     *\n     * We always sort A and B, so the same link from A to B and from B to A\n     * will hash the same. Then we xor the result into the 128 bit accumulator.\n     * If each link has its own backlink, the accumulator is guaranteed to\n     * be zero at the end.\n     *\n     * Collisions are extremely unlikely to happen, and an external attacker\n     * can&#39;t easily control the hash function output, since the salt is\n     * unknown, and also there would be to control the pointers.\n     *\n     * This algorithm is O(1) for each node so it is basically free for\n     * us, as we scan the list of nodes, and runs on constant and very\n     * small memory. <span class=\"syntax-punctuation syntax-definition syntax-comment syntax-css\">*/</span></span>\n\n\n<span class=\"syntax-meta syntax-selector syntax-css\">## Scaling <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases: JSON filters\n\nI remember the day when the first working implementation of Vector Sets felt complete. Everything worked as expected and it was the starting point to start with the refinements and the extra features.\n\nHowever in the past weeks and months I internally received the feedback that most <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases need some <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">form</span> of mixed search: you want near vectors to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> given query vector (like most similar movies to something</span>)<span class=\"syntax-meta syntax-selector syntax-css\"> but also with some kind of filtering (only released between 2000 and 2010</span>)<span class=\"syntax-meta syntax-selector syntax-css\">. My feeling is that you need to query for different parameters less often than product people believe, and that most of the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span> you can obtain this more efficiently by adding, in this specific case, each year to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> different vector set key (this is another instance of the composability of HNSWs expressed as <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structures versus <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> kind of index</span>)<span class=\"syntax-meta syntax-selector syntax-css\">.\n\nHowever I was thinking about the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">main</span> loop of the HNSW greedy search, that is something like this:\n\n</span>//<span class=\"syntax-meta syntax-selector syntax-css\"> Simplified HNSW greedy search algorithm. Don’t trust it too much.\nwhile(candidates<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>len</span>(</span>) &gt; 0) <span class=\"syntax-meta syntax-property-list syntax-css\"><span class=\"syntax-punctuation syntax-section syntax-property-list syntax-css\">{</span>\n    <span class=\"syntax-meta syntax-property-name syntax-css\">c</span> = <span class=\"syntax-meta syntax-property-name syntax-css\">candidates</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">pop</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">nearest</span>(<span class=\"syntax-meta syntax-property-name syntax-css\">query</span>);\n    <span class=\"syntax-meta syntax-property-name syntax-css\">worst</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">distance</span> = <span class=\"syntax-meta syntax-property-name syntax-css\">results</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">get</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">worst</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">dist</span>(<span class=\"syntax-meta syntax-property-name syntax-css\">query</span>);\n    <span class=\"syntax-meta syntax-property-name syntax-css\">if</span> (<span class=\"syntax-meta syntax-property-name syntax-css\">distance</span>(<span class=\"syntax-meta syntax-property-name syntax-css\">query</span>,<span class=\"syntax-meta syntax-property-name syntax-css\">c</span>) &gt; <span class=\"syntax-meta syntax-property-name syntax-css\">worst</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">distance</span>) <span class=\"syntax-meta syntax-property-name syntax-css\">break</span>;\n    <span class=\"syntax-meta syntax-property-name syntax-css\">foreach</span> (<span class=\"syntax-meta syntax-property-name syntax-css\">neighbor</span> <span class=\"syntax-meta syntax-property-name syntax-css\">from</span> <span class=\"syntax-meta syntax-property-name syntax-css\">c</span>) {\n        <span class=\"syntax-meta syntax-property-name syntax-css\">if</span> (<span class=\"syntax-meta syntax-property-name syntax-css\">neighbor</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">already</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">visited</span>()) <span class=\"syntax-meta syntax-property-name syntax-css\">continue</span>;\n        <span class=\"syntax-meta syntax-property-name syntax-css\">neighbor</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">mark</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">as</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">visited</span>();\n        <span class=\"syntax-meta syntax-property-name syntax-css\">if</span> (<span class=\"syntax-meta syntax-property-name syntax-css\">results</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">has</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">space</span>() OR <span class=\"syntax-meta syntax-property-name syntax-css\">neighbor</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">distance</span>(<span class=\"syntax-meta syntax-property-name syntax-css\">query</span>) &lt; <span class=\"syntax-meta syntax-property-name syntax-css\">worst</span>_<span class=\"syntax-meta syntax-property-name syntax-css\">distance</span>) {\n            <span class=\"syntax-meta syntax-property-name syntax-css\">candidates</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">add</span>(<span class=\"syntax-meta syntax-property-name syntax-css\">neighbor</span>);\n            <span class=\"syntax-meta syntax-property-name syntax-css\">results</span>.<span class=\"syntax-meta syntax-property-name syntax-css\">add</span>(<span class=\"syntax-meta syntax-property-name syntax-css\">neighbor</span>);\n</span>        <span class=\"syntax-punctuation syntax-section syntax-property-list syntax-css\">}</span>\n    }\n}\n<span class=\"syntax-meta syntax-selector syntax-css\">return results;\n\nSo I started to play with the idea of adding <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> JSON set of metadata for each node. What if, once I have things like </span><span class=\"syntax-meta syntax-property-list syntax-css\"><span class=\"syntax-punctuation syntax-section syntax-property-list syntax-css\">{</span>“<span class=\"syntax-meta syntax-property-name syntax-css\">year</span>”<span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-css\">:</span><span class=\"syntax-meta syntax-property-value syntax-css\"> </span><span class=\"syntax-meta syntax-property-value syntax-css\"><span class=\"syntax-constant syntax-numeric syntax-css\">1999</span></span></span><span class=\"syntax-punctuation syntax-section syntax-property-list syntax-css\">}</span>,<span class=\"syntax-meta syntax-selector syntax-css\"> this was enough to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">filter</span> while I perform the greedy search? Sure, the search needed to be bound, but there is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> key insight here: I want, to start, elements that are <span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span>near<span class=\"syntax-entity syntax-name syntax-tag syntax-wildcard syntax-css\">*</span> to the query vector, so I don’t really need to explore the whole graph if the condition on the JSON attributes is not satisfied by many nodes. I’ll let the user specify the effort, and anyway very far away results that match the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">filter</span> are useless.\n\nSo that’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> yet another way how my HNSW differs: it supports filtering by expressions similar to the ones you could write inside an “if” statement of <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> programming language. And your elements in the Vector Set can be associated with JSON blobs, expressing their properties. Then you can do things like:\n\n\n    VSIM movies VALUES … your vector components here… FILTER &#39;<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>year</span> <span class=\"syntax-punctuation syntax-separator syntax-combinator syntax-css\">&gt;</span>= 1980 and <span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>year</span> &lt; 1990&#39;\n\n## A few words on memory usage\n\nHNSW’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> fatal issue is — in theory — that they are normally served from memory. Actually, you can implement HNSWs on disk, even if there are better <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structures from the point of view of disk access latencies. However, in the specific case of Redis and Vector Sets the idea is to provide something that is very fast, easy to work with: the flexibility of <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">in-memory</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structures help with that. So the question boils down to: is the memory usage really so bad?\n\nLoading the 3 million Word2Vec entries into Redis with the default int8 quantization takes 3GB of RAM, 1kb for each entry. Many <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases have just <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few tens of million of entries, or <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot less. And what you get back from HNSWs, if well implemented, and in memory, is very good performance, which is crucial in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structure and in <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> workload that is in itself slow by definition. In my MacBook I get 48k ops per second with <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">redis-benchmark</span> and VSIM against this key (holding the word2vec dataset</span>)<span class=\"syntax-meta syntax-selector syntax-css\">. My feeling is that the memory usage of <span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">in-memory</span> HNSWs is very acceptable for many <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases. And even in the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases where you want the bulk of your vectors on disk, even if there is to pay for slower performance, your hot set should likely be served from RAM.\n\nThis is one of the reasons why I believe that, to be active in HNSW research is <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> good idea: I don’t think they will be replaced anytime soon for most <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases. It seems more likely that we will continue to have different <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> structures that are ideal for RAM and for disk depending on the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases and <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">data</span> size. Moreover, what I saw recently, even just scanning the Hacker News front page, is people with <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few millions of items fighting with systems that are slower or more complicated than needed. HNSWs and carefully exposing them in the right way can avoid all that.\n\n## Conclusions\n\nI like HNSWs, and working and implementing them was <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> real pleasure. I believe vectors are <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> great fit for Redis, even in an AI-less world (for instance, <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> few months ago I used them in order to fingerprint Hacker News users, replicating an old work published on HN in the past</span>)<span class=\"syntax-meta syntax-selector syntax-css\">. HNSWs are simply too cool and powerful for <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> number of <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases, and with AI, and learned embeddings, all this escalates to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> myriad of potential <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> cases. However, like most features in Redis, I expect that <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> lot of <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">time</span> will pass before people realize they are useful and powerful and how to <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">use</span> them (no, it’<span class=\"syntax-entity syntax-name syntax-tag syntax-css\">s</span> not just <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> matter of RAG</span>)<span class=\"syntax-meta syntax-selector syntax-css\">. This happened also with Streams: finally there is mass adoption, after so many years.\n\nIf instead you are more interested in HNSW and the implementation I wrote, I believe the <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">code</span> is quite accessible, and heavily commented:\n\nhttps:</span>//<span class=\"syntax-meta syntax-selector syntax-css\">github<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>com</span></span>/<span class=\"syntax-meta syntax-selector syntax-css\">redis</span>/<span class=\"syntax-meta syntax-selector syntax-css\">redis</span>/<span class=\"syntax-meta syntax-selector syntax-css\">blob</span>/<span class=\"syntax-meta syntax-selector syntax-css\">unstable</span>/<span class=\"syntax-meta syntax-selector syntax-css\">modules</span>/<span class=\"syntax-meta syntax-selector syntax-css\"><span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">vector-sets</span></span>/<span class=\"syntax-meta syntax-selector syntax-css\">hnsw<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>c</span>\n\nIf you want to learn more about Redis Vector Sets, please feel free to read the README file I wrote myself. There is also the official Redis documentation, but I suggest you start from here:\n\nhttps:</span>//<span class=\"syntax-meta syntax-selector syntax-css\">github<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>com</span></span>/<span class=\"syntax-meta syntax-selector syntax-css\">redis</span>/<span class=\"syntax-meta syntax-selector syntax-css\">redis</span>/<span class=\"syntax-meta syntax-selector syntax-css\">tree</span>/<span class=\"syntax-meta syntax-selector syntax-css\">unstable</span>/<span class=\"syntax-meta syntax-selector syntax-css\">modules</span>/<span class=\"syntax-meta syntax-selector syntax-css\"><span class=\"syntax-entity syntax-name syntax-tag syntax-custom syntax-css\">vector-sets</span>\n\nThanks for reading such <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> long blog post! And have <span class=\"syntax-entity syntax-name syntax-tag syntax-css\">a</span> nice day.\n\nReferences. This is the paper about the &quot;H&quot; in HNSW and how useful it is -<span class=\"syntax-punctuation syntax-separator syntax-combinator syntax-css\">&gt;</span> https:</span>//<span class=\"syntax-meta syntax-selector syntax-css\">arxiv<span class=\"syntax-entity syntax-other syntax-attribute-name syntax-class syntax-css\"><span class=\"syntax-punctuation syntax-definition syntax-entity syntax-css\">.</span>org</span></span>/<span class=\"syntax-meta syntax-selector syntax-css\">abs</span>/2412<span class=\"syntax-meta syntax-selector syntax-css\">.01940\n</span></span></span></code></pre>\n",
      "date_modified": "2025-11-11T12:53:38+00:00",
      "date_published": "2025-11-11T12:53:38+00:00",
      "external_url": "http://antirez.com/news/156",
      "id": "urn:aggr:item:80a5c1ef8dcfa796a202b80ef0cbfd1e361bfcd8",
      "summary": "I’m taking a few weeks of pause on my HNSWs developments (now working on some other data structure, news soon). At this point, the new type I added to Redis is stable and complete enough, it’s the perfect moment to reason about what I…",
      "tags": [
        "programming"
      ],
      "title": "Scaling HNSWs",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-11-11-scaling-hnsws/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 402 days ago. 356453 views.</p>\n<pre><code><span class=\"code-snippet\">Regardless of their flaws, AI systems continue to impress with their ability to replicate certain human skills. Even if imperfect, such systems were a few years ago science fiction. It was not even clear that we were so near to create machines that could understand the human language, write programs, and find bugs in a complex code base: bugs that escaped the code review of a competent programmer.\n\nSince LLMs and in general deep models are poorly understood, and even the most prominent experts in the field failed miserably again and again to modulate the expectations (with incredible errors on both sides: of reducing or magnifying what was near to come), it is hard to tell what will come next. But even before the Transformer architecture, we were seeing incredible progress for many years, and so far there is no clear sign that the future will not hold more. After all, a plateau of the current systems is possible and very credible, but it would likely stimulate, at this point, massive research efforts in the next step of architectures.\n\nHowever, if AI avoids plateauing long enough to become significantly more useful and independent of humans, this revolution is going to be very unlike the past ones. Yet the economic markets are reacting as if they were governed by stochastic parrots. Their pattern matching wants that previous technologies booms created more business opportunities, so investors are polarized to think the same will happen with AI. But this is not the only possible outcome.\n\nWe are not there, yet, but if AI could replace a sizable amount of workers, the economic system will be put to a very hard test. Moreover, companies could be less willing to pay for services that their internal AIs can handle or build from scratch. Nor is it possible to imagine a system where a few mega companies are the only providers of intelligence: either AI will be eventually a commodity, or the governments would do something, in such an odd economic setup (a setup where a single industry completely dominates all the others).\n\nThe future may reduce the economic prosperity and push humanity to switch to some different economic system (maybe a better system). Markets don’t want to accept that, so far, and even if the economic forecasts are cloudy, wars are destabilizing the world, the AI timings are hard to guess, regardless of all that stocks continue to go up. But stocks are insignificant in the vast perspective of human history, and even systems that lasted a lot more than our current institutions eventually were eradicated by fundamental changes in the society and in the human knowledge. AI could be such a change.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-08-13T15:59:56+00:00",
      "date_published": "2025-08-13T15:59:56+00:00",
      "external_url": "http://antirez.com/news/155",
      "id": "urn:aggr:item:cb96b3b78137d4a746efe1af9ac6ed281d52b3fe",
      "summary": "Regardless of their flaws, AI systems continue to impress with their ability to replicate certain human skills. Even if imperfect, such systems were a few years ago science fiction. It was not even clear that we were so near to create…",
      "tags": [
        "programming"
      ],
      "title": "AI is different",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-08-13-ai-is-different/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 426 days ago. 468071 views.</p>\n<pre><code><span class=\"code-snippet\">Frontier LLMs such as Gemini 2.5 PRO, with their vast understanding of many topics and their ability to grasp thousands of lines of code in a few seconds, are able to extend and amplify the programmer capabilities. If you are able to describe problems in a clear way and, if you are able to accept the back and forth needed in order to work with LLMs, you can reach incredible results such as:\n\n1. Eliminating bugs you introduced in your code before it ever hits any user: I experienced this with Vector Sets implementation of Redis. I would end eliminating all the bugs eventually, but many were just removed immediately by Gemini / Claude code reviews.\n\n2. Explore faster how a given idea could work, by letting the LLM write the throw away code to test ASAP in order to see if a given solution is actually more performant, if it is good enough, and so forth.\n\n3. Engage in pair-design activities where your instinct, experience, design taste can be mixed with the PhD-level knowledge encoded inside the LLM. In this activity, the LLM will sometimes propose stupid paths, other times incredibly bright ideas: you, the human, are there in order to escape local minimal and mistakes, and exploit the fact your digital friend knows of certain and various things more than any human can.\n\n4. Accelerate your work by writing part of the code under your clear specifications.\n\n5. Work with technologies far from your expertise but contiguous with what you can do (for instance: coding in 68000 assembly for an Amiga demo?) using LLMs as an extension of specific parts of your mind, for the knowledge you don&#39;t have.\n\nOne and half years ago I wrote a blog post called “LLMs and programming in the first days of 2024”. There, I found LLMs to be already useful, but during these 1.5 years, the progresses they made completely changed the game. However, in order to leverage their capabilities, humans interacting with LLMs must have certain qualities and follow certain practices. Let’s explore them.\n\n## Refuse vibe coding most of the times\n\nIn this historical moment, LLMs are good amplifiers and bad one-man-band workers. There are still small throwaway projects where letting the LLM write all the code makes sense, like tests, small utilities of a few hundreds lines of codes. But while LLMs can write part of a code base with success (under your strict supervision, see later), and produce a very sensible speedup in development (or, the ability to develop more/better in the same time used in the past — which is what I do), when left alone with nontrivial goals they tend to produce fragile code bases that are larger than needed, complex, full of local minima choices, suboptimal in many ways. Moreover they just fail completely when the task at hand is more complex than a given level. Tomorrow all this may change, but right now after daily experience writing code with LLMs I strongly believe the maximum quality of work is reached using the human+LLM equation. I believe that humans and LLMs together are more productive than just humans, but this requires a big “if”, that is, if such humans have extensive communication capabilities and LLMs experiences: the ability to communicate efficiently is a key factor in using LLMs.\n\n## Provide large context\n\nWhen your goal is to reason with an LLM about implementing or fixing some code, you need to provide extensive information to the LLM: papers, big parts of the target code base (all the code base if possible, unless this is going to make the context window so large than the LLM performances will be impaired). And a brain dump of all your understanding of what should be done. Such braindump must contain especially the following:\n\n* Hints about bad solutions that may look good, and why they could be suboptimal.\n* Hints about very good potential solutions, even if not totally elaborated by the humans still: LLMs can often use them in order to find the right path.\n* Clear goals of what should be done, the invariants we require, and even the style the code should have. For instance, LLMs tend to write Python code that is full of unnecessary dependencies, but prompting may help reducing this problem. C code tends to be, in my experience, much better.\n\nWhen dealing with specific technologies that are not so widespread / obvious, it is often a good idea to also add the documentation in the context window. For example when writing tests for vector sets, a Redis data type so new that LLMs don’t yet know about, I add the README file in the context: with such trivial trick, the LLM can use vector sets at expert level immediately.\n\n## Use the right LLMs\n\nThe most famous LLMs are not the best. Coding activities should be performed mostly with:\n\n* Gemini 2.5 PRO\n* Claude Opus 4\n\nGemini 2.5 PRO is, in my experience, semantically more powerful. Can spot more complex bugs, reason about more complex problems. Claude Opus may be better at writing new code sometimes (sometimes not), the user interface is more pleasant, and in general you need at least two LLMs to do some back and forth for complex problems in order to enlarge your (human) understanding of the design space. If you can pick just one, go for Gemini 2.5 PRO.\n\nThe fundamental requirement for the LLM to be used is: don’t use agents or things like editor with integrated coding agents. You want to:\n\n* Always show things to the most able model, the frontier LLM itself.\n* Avoid any RAG that will show only part of the code / context to the LLM. This destroys LLMs performance. You must be in control of what the LLM can see when providing a reply.\n* Always be part of the loop by moving code by hand from your terminal to the LLM web interface: this guarantees that you follow every process. You are still the coder, but augmented.\n\n## Conclusions\n\nDespite the large interest in agents that can code alone, right now you can maximize your impact as a software developer by using LLMs in an explicit way, staying in the loop. This will inevitably change in the future, as AI will improve, and eventually many coding tasks will be better served by AI alone: in this future, the human will decide the what &amp; how, which is still crucial. But we are not yet there. In this exact moment taking control allows to use LLMs to produce the sharpest code possible: minimal when needed, using complex ideas when required.\n\nYou will be able to do things that are otherwise at the borders of your knowledge / expertise while learning much in the process (yes, you can learn from LLMs, as you can learn from books or colleagues: it is one of the forms of education possible, a new one). Yet, everything produced will follow your idea of code and product, and will be of high quality and will not random fail because of errors and shortcomings introduced by the LLM. You will also retain a strong understanding of all the code written and its design.\n\nFrom time to time, it is wise to test what agents can do. But each time you feel they can’t do as well as you can, return to your terminal, and code with the help of AI (when you feel it can improve your output; there are times where you just are better alone). When this will be true, that agents will perform superb work, I’ll be the first to switch, and I’ll keep coding by myself just for passion. But for now, let’s skip the hype, and use AI at its best, that is: retaining control. There is another risk, however: of avoiding LLMs for some ideological or psychological refusal, accumulating a disadvantages (and failing to develop a large set of skills - hard to describe - needed to work with LLMs). Maybe this is really a case of &quot;In medio stat virtus&quot;.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-07-20T10:58:54+00:00",
      "date_published": "2025-07-20T10:58:54+00:00",
      "external_url": "http://antirez.com/news/154",
      "id": "urn:aggr:item:81c69983eb39b8f0503eee3b75fe55c15b59c526",
      "summary": "Frontier LLMs such as Gemini 2.5 PRO, with their vast understanding of many topics and their ability to grasp thousands of lines of code in a few seconds, are able to extend and amplify the programmer capabilities. If you are able to…",
      "tags": [
        "programming"
      ],
      "title": "Coding with LLMs in the summer of 2025 (an update)",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-07-20-coding-with-llms-in-the-summer-of-2025-an-update/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 478 days ago. 268770 views.</p>\n<pre><code><span class=\"code-snippet\">This is a short story of how humans are still so much more capable of LLMs. Note that I&#39;m not anti-AI or alike, you know it if you know me / follow me somewhere. I use LLMs routinely, like I did today, when I want to test my ideas, for code reviews, to understand if there are better approaches than what I had in mind, to explore stuff at the limit of my expertise, and so forth (I wrote a blog post about coding with LLMs almost two years, when it was not exactly cool: I was already using LLMs for coding and never stopped, I&#39;ll have to write an update, but that&#39;s not the topic of this post).\n\nBut, still: the current level of AI is useful, great too, but so incredibly behind human intelligence, and I want to remark this as lately it is impossible to have balanced conversations.\n\nSo, today I was working to Vector Sets for Redis, to fix a complicated bug: during the time I stopped working at Redis my colleagues introduced resistance against corruption RDB and RESTORE payloads, even when the checksum of the data passes. This feature is disabled by default, but provides an enhanced layer of safety for people wanting it.\n\nBut… there is a but as big as an elephant: In order to make HNSWs fast to save into Redis RDBs and to load back, I serialized the *graph* representation, and not the element-vector pairs, otherwise I would have to re-insert back data into HNSWs, and that would be, like, 100 times slower (!). So I store all the links the nodes have with other nodes, as integers, and then I resolve them into pointers, it’s a nice trick and works great. But if you mix this and random corruptions of the representation, and the fact that my own twist on HNSWs enforce reciprocal links between nodes (I wrote my own implementation of HNSWs with many useful features, but reciprocal links are needed to enable many of them) then this could happen:\n\n1. We load corrupted data that says A links to B, but B no longer links to A (corrupted node IDs).\n2. We delete node B: since the reciprocity is violated, we don’t clear the link from A to B.\n3. Then we scan the graph and once we are at B we access A: use-after-free :-D :-) :-|\n\nSo after loading data, I need to check that every link is reciprocal, and in the vanilla case this is going to be O(N^2), for each node we need to scan all the levels, for each level all the neighbors of the node, and check that it also links to this node by scanning its links at that level. Not good.\n\n# Human vs LLM\n\nTo start, I implemented the vanilla approach, to see if the fuzzer could no longer find the bug, and it worked indeed, but loading times for a big vector set with 20 million vectors went from 45 seconds to 90 or something. WTF. So I opened a Gemini 2.5 PRO chat and told the LLM, hey, what we can do here? Is there a super fast way to do so?\n\nThe best solution that Gemini could find was to say: order the pointers of the neighbors links, so you can use binary search. Oh, well, sure, I know this, I’m not really sure if in arrays of 16/32 pointers this is going to be faster or slower. So I asked, anything else? Nope, no better solution.\n\nSo I told it: look, what about when we see A linking B at level X we store in a hash table A:B:X (but we sort A and B always so that A&gt;B, and links are the same whatever the direction), and when we see the link again we clean it, this time we just scan the whole thing as we are already doing when resolving IDs to pointers in the links, and if at the end the hash table is not empty, we know there is some link that must be non-reciprocal?\n\nGemini told me it was a nice idea, but there was the snprintf() to create the key and the hashing time and so forth, but yep, it was better than what my original approach (even sorting pointers). I made it notice that snprintf() was not needed. We could just memcpy() pointers in a fixed sized key. It recognized that it was possible to do so, then I realized something…\n\nHey, I told Gemini, what about using a fixed accumulator for A:B:X? No hash table at all. Each time we see a link (A:B:X, so 8+8+4 bytes) we xor it in the current accumulator of 12 bytes. If we store it twice, it cancels out, so at the end if the register is non-zero, we know something is odd! However I anticipated Gemini that this system was potentially subject to collisions, and to evaluate them. Even if this feature is normally turned off in Redis, when users enable such extra checks they also often expect some more protection against an attacker deliberately crafting bad payloads.\n\nGemini was quite impressed about the idea, but still told that pointers are… you know, similar in structure, change of a few bits, so if there were three spurious links L1, L2, L3 it could happen that the xor between L1 and L2 was the same as the L3 bits, and we could have a false negative (zero register). I also noticed that allocators tend to be very predictable and externally guessable.\n\nI asked Gemini for ways to improve upon this: it got no great ideas. Then I thought, wait, we can actually hash this with a good enough hash function that is still fast, murmur-128 or alike (we don’t need it to have cryptographic properties for this task), and proposed the following schema to Gemini:\n\n1. Take the link A:B:X, but use a seed obtained via /dev/urandom to prefix all the keys with it, so we actually have S:A:B:X.\n2. We just xor the output of murmur-128(S:A:B:X) into the 128 bit register.\n3. At the end, we check if the register is 0 (all links reciprocal).\n\nI asked Gemini to do an analysis of that, and it was finally happy, saying that this makes it a lot harder both to casually find orphaned links that happen to xor to 0 together, and even that an external attacker could ever use this in a useful way, since “S” is not known, there is to control the pointers too, and all that it is really hard to put together. Also, this feature is a best effort extra protection that you need to enable, it is normally off and to be practical it should not pose a too big performance penalty.\n\nWell, all this to say: I just finished the analysis and stopped to write this blog post, I’m not sure if I’m going to use this system (but likely yes), but, the creativity of humans still have an edge, we are capable of really thinking out of the box, envisioning strange and imprecise solutions that can work better than others. This is something that is extremely hard for LLMs. Still, to verify all my ideas, Gemini was very useful, and maybe I started to think at the problem in such terms because I had a “smart duck” to talk with.\n</span></code></pre>\n",
      "date_modified": "2025-05-29T16:34:51+00:00",
      "date_published": "2025-05-29T16:34:51+00:00",
      "external_url": "http://antirez.com/news/153",
      "id": "urn:aggr:item:17b8e2c08b7d2990007ff240827e3525c21f427c",
      "summary": "This is a short story of how humans are still so much more capable of LLMs. Note that I'm not anti-AI or alike, you know it if you know me / follow me somewhere. I use LLMs routinely, like I did today, when I want to test my ideas, for…",
      "tags": [
        "programming"
      ],
      "title": "Human coders are still better than LLMs",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-05-29-human-coders-are-still-better-than-llms/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 505 days ago. 85642 views.</p>\n<pre><code><span class=\"code-snippet\">Yesterday, it was a very intense day. In Italy it was 1st of May, the workers holiday, so in the morning I went for a 4h walk in the Etna with friends &lt;3, I love walking, and I often take pauses when coding just to walk, to return later at the keyboard with a few more kilometers on my legs, and walking in the Etna is amazing (Etna is the largest active volcano in Europe, and I happen to live in Catania, that is on its slopes).\n\nThen at 6PM I was at home to release my blog post about the AGPL license switch, and I started following the comments, feedbacks, private messages, and I learned a few things in the process.\n\n1. Regardless of the different few clauses, that IMHO make a difference, the AGPL vs SSPL main difference is that AGPL is &quot;understood&quot;. In general, yesterday for the first time I realized that in licensing there is not just what you can do and can&#39;t do, but the degree a given license is understood, tested, adopted, ...\n\n2. I was very touched by the words of Simon Willison on the matter (https://simonwillison.net/2025/May/1/redis-is-open-source-again/) because it is very peculiar that different persons, living in different parts of the world, but with a similar age and background in software, feel *so similar* about things. I, too, when was writing Vector Sets, was thinking: I would never use it if it wasn&#39;t going to be released under the AGPL (or other open source license I understand). This sentiment, multiplied by a non trivial fraction of the community, makes open source eventually win even in the complex software landscape that there is today.\n\n3. People still care a lot about software distributions. Not that I didn&#39;t care, but in the past I burned my fingers with it. I was a very initial Linux user, with SlackWare 3.1 or something like that. During the years I wrote my device drivers, contributed a few patches to the kernel, during the years Debian had maybe ~10 packages of stuff that I wrote, from hping, to the Visitors web log analyzer, dump1090, Redis, and a few more. But, eventually, I started to see all the fragmentation, the rigidity of certain processes (binary compatibility of modules for the Linux kernel), the lack of a consistent design, the lack of a binary format for software distribution with all the libs inside, and so forth. I switched to MacOS on the desktop and continued using Linux on the server in a very pragmatic way, often times more happy to &quot;tar xvzf software.tgz; make&quot; than relying on what distributions offered. And, maybe, my obsession with shipping software with zero dependencies has something to do with it. But people still care a lot, and probably it is important to have Redis as distribution packages in many situations where you want to make things as automatic and reproducible as possible? Well, now there are many folks asking if Redis will re-enter the distributions.\n\nMy take on that is simple: Redis and ValKey diverged already in a significant way, and will diverge a lot more in the future. I believe distributions should have both, so that users can have a choice, and sometimes this choice is forced by the features difference. Trivially: if you need to do vector similarity searches, you need to use Redis; if instead your company has a no-AGPL policy, you need to use ValKey, and so forth.\n\n4. People are kind to me. In the comments around there were a few harsh takes, and this is normal and even healthy (after all it is part of the reason many companies believe more and more they can&#39;t use SSPL or other licenses but an OSI approved one). Yet, when addressing me personally, I see a lot of good words. I just want to say: thank you for all that.\n\n5. We kinda live in a bubble. In one of the forums out there at some point somebody said: &quot;But did you ever switched from Redis to one of the forks?&quot;, and there was a chain of comments: &quot;never&quot;, &quot;who cares if I can use it&quot; and so forth. And this is true for ValKey too, that if people write apt-get install redis and ValKey is installed instead, and they use SET, GET, DEL, a few more, they don&#39;t care. What I mean is that software is no longer the one in 1998 (to use a very crucial and symbolic date for open source, the Internet, and myself) where we were all open source software license experts. Most people, especially the newer generations, have a different and more practical take. So all this is very important (vital, to me), but there is to understand that not every sensibility is alike. In the end, what is the most important aspect of all, is trying to ship good software.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-05-02T08:46:25+00:00",
      "date_published": "2025-05-02T08:46:25+00:00",
      "external_url": "http://antirez.com/news/152",
      "id": "urn:aggr:item:c5bb534e85cd465ef3f9f79e7b3c12ec9f931390",
      "summary": "Yesterday, it was a very intense day. In Italy it was 1st of May, the workers holiday, so in the morning I went for a 4h walk in the Etna with friends <3, I love walking, and I often take pauses when coding just to walk, to return later at…",
      "tags": [
        "programming"
      ],
      "title": "What I learned during the license switch",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-05-02-what-i-learned-during-the-license-switch/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 506 days ago. 422989 views.</p>\n<pre><code><span class=\"code-snippet\">Five months ago, I rejoined Redis and quickly started to talk with my colleagues about a possible switch to the AGPL license, only to discover that there was already an ongoing discussion, a very old one, too. Many people, within the company, had the feeling that the AGPL was a better pick than SSPL, and while eventually Redis switched to the SSPL license, the internal discussion continued.\n\nI tried to give more strength to the ongoing pro-AGPL license side. My feeling was that the SSPL, in practical terms, failed to be accepted by the community. The OSI wouldn’t accept it, nor would the software community regard the SSPL as an open license. In little time, I saw the hypothesis getting more and more traction, at all levels within the company hierarchy.\n\nI’ll be honest: I truly wanted the code I wrote for the new Vector Sets data type to be released under an open source license. Writing open source software is too rooted in me: I rarely wrote anything else in my career. I’m too old to start now. This may be childish, but I wrote Vector Sets with a huge amount of enthusiasm exactly because I knew Redis (and my new work) was going to be open source again.\n\nI understand that the core of our work is to improve Redis, to continue building a good system, useful, simple, able to change with the requirements of the software stack. Yet, returning back to an open source license is the basis for such efforts to be coherent with the Redis project, to be accepted by the user base, and to contribute to a human collective effort that is larger than any single company. So, honestly, while I can’t take credit for the license switch, I hope I contributed a little bit to it, because today I’m happy. I’m happy that Redis is open source software again, under the terms of the AGPLv3 license.\n\nNow, time to go back to the terminal, to show Redis users some respect by writing the best code I’m able to write, and make Vector Sets more useful and practical: I have a few more ideas for improvements, and I hope that more will be stimulated by your feedback (it is already happening). Good hacking!\n\nP.S. Redis 8, the first version of Redis with the new license, is also GA today, with a many new features and speed improvements of the core: https://redis.io/blog/redis-8-ga/\n\nYou can also find the Redis CEO blog post here: https://redis.io/blog/agplv3/\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-05-01T15:55:50+00:00",
      "date_published": "2025-05-01T15:55:50+00:00",
      "external_url": "http://antirez.com/news/151",
      "id": "urn:aggr:item:c28fd7e66f6a049e78750abbf78580e901d994ce",
      "summary": "Five months ago, I rejoined Redis and quickly started to talk with my colleagues about a possible switch to the AGPL license, only to discover that there was already an ongoing discussion, a very old one, too. Many people, within the…",
      "tags": [
        "programming"
      ],
      "title": "Redis is open source again",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-05-01-redis-is-open-source-again/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 521 days ago. 149254 views.</p>\n<pre><code><span class=\"code-snippet\">About three years ago I saw a quite curious and interesting post on Hacker News. A student, Christopher Tarry, was able to use cosine similarity against a vector of top words frequencies in comments, in order to detect similar HN accounts — and, sometimes, even accounts actually controlled by the same user, that is, fake accounts used to uncover the identity of the writer.\n\nThis is the original post: https://news.ycombinator.com/item?id=33755016\n\nI was not aware, back then, of Burrows-Delta method for style detection: it seemed kinda magical that you just needed to normalize a frequency vector of top words to reach such quite remarkable results. I read a few wikipedia pages and took mental note of it. Then, as I was working with Vectors for Redis I remembered about this post, searched the web only to discover that the original page was gone and that the author, in the original post and website, didn’t really explained very well how the data was processed, the top words extracted (and, especially, how many were used) and so forth. I thought I could reproduce the work with Vector Sets, once I was done with the main work. Now the new data type is in the release candidate, and I found some time to work on the problem. This is a report of what I did, but before to continue, the mandatory demo site: you can play with it at the following link:\n\nhttps://antirez.com/hnstyle?username=pg&amp;threshold=20&amp;action=search\n\nNOTE: since the dataset takes 700MB of RAM, in my tiny server, in the next months I may take this down. However, later in this post you will find the link and the Github repository with the code to reproduce everything from scratch.\n\nNOTE2: I hope the web site will survive, it&#39;s a very crude Python script. I benchmarked the VSIM command in such a small server and yet it can deliver 80k VSIM per second! The wonders of int8 quantization, together with a few more optimizations. But the Python script is terrible, creates a new Redis connection each time and so forth. Fingers crossed.\n\n# Raw data download and processing\n\nWell, the first problem I had, in order to do something like that, was to find an archive with Hacker News comments. Luckily there was one with apparently everything posted on HN from the start to 2023, for a huge 10GB of total data. You can find it here: https://huggingface.co/datasets/OpenPipe/hacker-news and, honestly, I’m not really sure how this was obtained, if using scarping or if HN makes this data public in some way.\n\nSince I’m not a big fan of binary files, in the specific case of public datasets at least, I used two Python scripts in order to convert the Parquet files into something smaller and simpler to handle. The first script, gen-top-words.py, takes the binary files and generates a txt file with the list of the top N words used in the dataset. It generates 10k words by default, but for the statistical analysis a lot less are needed (or, actually: if you use too many words you no longer capture the style, but the kind of content a user is talking about!). Then, another Python script, accumulates all the comments for each single user and generates a very big JSONL file where there are just two keys: the user name and the frequency table of all the words used by a given user in all the history from HN starts to 2023. Each entry is like that:\n\n{&quot;by&quot;: &quot;rtghrhtr&quot;, &quot;freqtab&quot;: {&quot;everyone&quot;: 1, &quot;hates&quot;: 1, &quot;nvidia&quot;: 1, &quot;but&quot;: 1, &quot;treats&quot;: 1, &quot;ati&quot;: 1, &quot;as&quot;: 1, &quot;an&quot;: 1, &quot;afterthought&quot;: 1, &quot;another&quot;: 1, &quot;completely&quot;: 1, &quot;useless&quot;: 1, &quot;tool&quot;: 1, &quot;to&quot;: 1, &quot;throw&quot;: 1, &quot;on&quot;: 1, &quot;the&quot;: 1, &quot;pile&quot;: 1}}\n\nAt this point, the final script, insert.py, could do all the real work: to apply the Borrows method for each user, create the user style vector, and insert it into Redis. The advantage of pre-processing the files (a slow operation) is that the insertion script could be called more easily with different parameters (especially the number of top words to use) in order to see the different results more promptly, without the need to re-process the Parquet files each time.\n\n# How the Burrow method works?\n\nIn the original post, Christopher wrote that you just need to normalize the frequency of the words usage and apply cosine similarity. Actually the process is a bit more involved. First, let’s ask ourselves, how this method actually works, in its essence? Well, it wants to capture words that each specific user over-uses or under-uses compared to the expected “average” language. To do so, we actually use the following steps (from the Python code).\n\nThat’s what we do for each of the top words:\n\n# Convert to relative frequency\nrel_freq = frequency / total_words\n\n# Standardize using z-score: z = (freq - mean) / stddev\nmean = word_means.get(word, 0.0)\nstddev = word_stddevs.get(word, 1.0)  # Default to 1.0 to avoid division\nby zero\n\nz_score = (rel_freq - mean) / stddev\n\n# Set the z-score directly in the vector at the word&#39;s index\nvector[word_to_index[word]] = z_score\n\nSo we start by “centering” the frequency the user used a given word, by subtracting the *global* usage frequency for that word. This way, we have a number that describes how much the user under (negative) or over (positive) used such word. But, if you think at it, words that have a much higher variance among usage of different writers are less important, when they change. We want to amplify the signal of words that are under of over used by this user in a much greater way compared to the normal variance of the word. This is why we divide the centered frequency by the global standard deviation of the word. Now we have what is called the “z score”, an adjusted measure of how much a given word is an outlier in one or the other direction.\n\nNow, we are ready to insert the word into a Redis vector set, with just:\n\nVADD key FP32 [blob with 350 floats] username\n\n(I’ll not cover the details of vector sets here since you can find the doc here -&gt; https://github.com/redis/redis/blob/unstable/modules/vector-sets/README.md)\n\nNote that Redis performs L2 normalization of the inserted vectors, but remembers the L2 value in order to return back the values when VEMB is used to retrieve the associated vector, so the z_score was set as it is.\n\nFinally, with VSIM, we can get similar users:\n\n127.0.0.1:6379&gt; vsim hn_fingerprint ele pg\n 1) &quot;pg&quot;\n 2) &quot;karaterobot&quot;\n 3) &quot;Natsu&quot;\n 4) &quot;mattmaroon&quot;\n 5) &quot;chc&quot;\n 6) &quot;montrose&quot;\n 7) &quot;jfengel&quot;\n 8) &quot;emodendroket&quot;\n 9) &quot;vintermann&quot;\n10) &quot;c3534l&quot;\n\nAll the code (but the webapp itself) can be found here: https://github.com/antirez/hnstyle\n\nThe README file explains how to reproduce every part.\n\n# Why 350 words?\n\nOne of the things missing in the original post that stimulated this blog post, is how many top words one should use. If you use too many words, you’ll see many comments of mine about Redis, since Redis is one of the top 10k words used. Guess what? I did exactly this error, initially, and VSIM continued to report users that talked about similar topics than myself, not with similar *style*. But fortunately the Internet Archive cached the Christopher results for the “pg” account, here:\n\nhttps://web.archive.org/web/20221126235433/https://stylometry.net/user?username=pg\n\nSo now I could tune my top-k words to get similar results. Also, reading the original papers, I discovered that, with my surprise, for the analysis to work well you need even as little as 150 words. And in general the range from 150 to 500 is considered to be optimal.\n\nWarning: don’t believe that when you search for a user you’ll find mostly fake accounts. For many fake accounts there is too little data, as often people create throw away accounts, write a few comments, and that’s it. So most of the accounts associated with a given user style will be just other people that have a similar writing style. This method I believe is quite powerful in distinguishing who is a native speaker and who is not. This is especially clear from the vectors visualization below.\n\n# Validate and visualize…\n\nAnother thing that I reproduced (also an idea from OP) was to try inserting the same users in two variants, like antirez_A and antirez_B, using two different set of comments. Then check if asking for similar users to antirez_A would report B. Indeed, for *most* of the users I tested this against, it worked very well, and often times it was the top result. So we know that actually our method works.\n\nBut since from the vectors it is so easy to “see” a style, what about our naked eyes? Recently I switched to Ghostty as my terminal, and it supports the Kitty graphics protocol, so you can display bitmaps directly in the terminal window. It is quite some time I want to play with it. Finally I had a good reason to test this feature.\n\n\n\nWhat’s happening above is that we call the VEMB command, that returns just a list of floats (the vector).\nThen the vshow utility, also part of the repository, will care to find the smallest square that can contain the vector and show positive values in red, negative in green.\n\nAs you can see, as a non native speaker I over-use very simple words and under-use more sophisticated words. Other authors stress certain specific words, others are much more “plain”, showing less artifacts. At some point I was curious about what was really happening there: what words I would use too much and too little? So in the demo website you can also press the button to analyze a given user, and see the top 10 words over-used and under-used. Well, a few of mine are definitely due to my issues with English grammar :D\n\nOk, enough with this investigation! Vector sets are now in Redis 8 RC1 and I have more work to do, but this was fun, and I believe it shows that vectors were definitely cool even before AI. Thanks for reading such a long post.\n\nEDIT: I forgot to say that the insert.py script also inserts the JSON metadata with the total words written by the user. So you can use FILTER in order to only show matches with a given number of words. This can be useful to detect duplicated accounts since often they are used only seldom, when the identity must be covered:\n\n127.0.0.1:6379&gt; vsim hn_fingerprint ele pg FILTER &quot;.wordcount &lt; 10000&quot;\n 1) &quot;montrose&quot;\n 2) &quot;kar5pt&quot;\n 3) &quot;ryusage&quot;\n 4) &quot;corwinstephen&quot;\n 5) &quot;ElfinTrousers&quot;\n 6) &quot;beaned&quot;\n 7) &quot;MichaelDickens&quot;\n 8) &quot;bananaface&quot;\n 9) &quot;area51org&quot;\n10) &quot;william42&quot;\n\nEDIT2: In case the matches look suspicious to you (meaningless), like tptacek noted in a comment in the HN submission of this blog post, here is a &quot;visual&quot; match that shows how, for instance, montrose and pg are really similar in the words usage patterns:\n\n</span></code></pre>\n",
      "date_modified": "2025-04-16T13:53:16+00:00",
      "date_published": "2025-04-16T13:53:16+00:00",
      "external_url": "http://antirez.com/news/150",
      "id": "urn:aggr:item:a6b4e8b68a55c6a6bc060a3209f5b247283ba616",
      "summary": "About three years ago I saw a quite curious and interesting post on Hacker News. A student, Christopher Tarry, was able to use cosine similarity against a vector of top words frequencies in comments, in order to detect similar HN accounts…",
      "tags": [
        "programming"
      ],
      "title": "Reproducing Hacker News writing style fingerprinting",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-04-16-reproducing-hacker-news-writing-style-fingerprinting/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 534 days ago. 93622 views.</p>\n<pre><code><span class=\"code-snippet\">Yesterday we finally merged vector sets into Redis, here you can find the README that explains in detail what you get:\n\nhttps://github.com/redis/redis/blob/unstable/modules/vector-sets/README.md\n\nThe goal of the new data structure is, in short, to create a new “Set alike” data type, similar to Sorted Sets, where instead of having a scalar as a score, you have a vector, and you can add and remove elements the Redis way, without caring about anything except the properties of the abstract data structure Redis implements, ask for elements similar to a given query vector (or a vector associated to some element already in the set), and so forth. But more about that later, a bit of background, first:\n\nFrom the path of the README itself, you can see the implementation is into “modules”, but actually, Vector Sets are not a module, it’s a part of the Redis core, the thing is that I started developing them as a module, and later I suggested that the implementation should still use the modules API, in order to promote modularity of the internals of Redis, in order to have both the advantages: every Redis instance starting from Redis 8 will have Vector Sets as a native data type, and there are clear boundaries between the core and the implementation\n\n## The first new main data type of Redis after… some time\n\nI think that the latest big data structure of Redis were Streams, also developed by me. I resigned, returned, forks happened in the meantime, and it still it looks like the burden to introduce a new data type in Redis is mine :D I must say: I’m ok with that, because as much as I like programming, I also like design, a lot, and I had a feeling, that vectors, and vector similarity, are conceptually very simple, so they deserved a very simple API. And that was what I tried to do. Vector Sets are still a beta feature but I can tell you something, I can guarantee you can learn the API in 3 minutes.\n\nI decided that a fundamental requirement for implementing vector similarity was to also reimplement from scratch HNSWs (you can see my implementation in hnsw.c), because that was going to be my core data structure, and I didn’t want to grab some random code from GitHub and be happy with it. However, as I started reading the papers, I started to understand that a few pieces were missing.\n\nSo, as I did in the past with HyperLogLog, where I had to fill a few gaps (here: https://antirez.com/news/75), there was already some new algorithmic challenges. Especially I wanted two things:\n\n1. To have true deletions of nodes. In Vector Sets you can add new elements with VADD, and you can remove elements with VREM. And I wanted the memory to be reclaimed ASAP.\n\n2. I wanted to be sure that as you delete elements, the connectivity properties of the HNSW graph were retained.\n\nSo this lead me to a few differences compared to other implementations of HNSW. I don’t use tombstone deletions, but effectively unlink the node in the moment it gets deleted, relinking it back with other potential good neighbors. To do so, in turn, my implementation is designed to enforce that links must be reciprocal, it’s no longer a best effort property: this in turn changes quite a bit what you need to do during insertions.\n\nAnother modification I did in the HNSW was to support the ability to scan the graph with a predicate function, so that you can ask for nodes matching a given expression. This requires to modify the greedy graph scanning algorithm in some way: to collect potential nodes to visit, and to collect the result set, but also to have some early stop condition in case there is too much selectivity in the query. We don’t want trigger a full graph scan, of course.\n\nOther than the HNSW modifications, I wanted a few more things that are more pragmatic and obvious:\n\n1. Threading of all the vector similarity requests. Yeah, that’s new in Redis land, but as much as I believe single thread and shared nothing was a good design in general, I think that vectors are special. They are slow, a lot slower than other data structures modeled by Redis. As a bonus point, as I was implementing threaded VSIM (the command that performs vector similarity queries) I also discovered that with a few tricks you can split the read half and the write half of writes in two parts, so that neighbors candidate collections happen in the background, and the actual insertion is performed in the foreground. This splitting however is not the default, and you need to force it with the CAS option of VADD.\n\n2. I wanted to support quantization and even make it the default. So Vector Sets ship with both 8 bit quantization and binary quantization. There is also support for random projection for dimensionality reduction. However as much as I like RP and having bin quants, the reality is that the “killer” for me is int8 quants. They are super fast, take 25% of the memory of FP32, and the results are nearly identical to those from full vectors for most vectors generated via embedding AI models.\n\nBtw the end result is, I believe, a very fast implementation. For instance in my machine, with a 3 million items vector set of 300 components each, I get 50/60k VSIM (top 10 items) per second on my laptop. But I encourage you to do your benchmarks.\n\nAlso note that Vector Sets are serialized on disk as a graph, so when they are loaded back in memory, after a Redis restart, you don’t pay back the insertion time: loading every million of elements take a few seconds and not the minutes needed otherwise to add back into the in-memory HNSW.\n\n## Data structures, not indexes\n\nWhat I’ve said so far is all about the low level stuff. But for me the most interesting part of Vector Sets is the data model and the API supporting it. Many databases propose vector similarity as a kind of index, but that’s Redis, and things in Redis are data structures: no exception this time. You add stuff like that:\n\n&gt; VADD mykey FP32 …blob of data… item1\n\nAnd so forth. So you can have many small vector sets if you want, one per key. And an important thing here is that if you split your vectors into N different keys (hashing the item you are inserting or alike to select which key to pick), then you can merge different VSIM calls against different keys into a single reply:\n\n&gt; VSIM word_embeddings_int8 ele &quot;banana&quot; WITHSCORES COUNT 4\n1) &quot;banana&quot;\n2) &quot;0.9997616112232208&quot;\n3) &quot;bananas&quot;\n4) &quot;0.8758847117424011&quot;\n5) &quot;pineapple&quot;\n6) &quot;0.8288004100322723&quot;\n7) &quot;mango&quot;\n8) &quot;0.8179697692394257&quot;\n\nIf I get a few of those results from different keys and instances, I can sort by the score (where 1 means identical, 0 opposite vector) and that’s it.\n\nSo, my feeling is that Vector Sets can be composed into different patterns to handle having many vectors (they consume quite a bit of RAM) into different instances and so forth. Also it is interesting that splitting linearly scale writes, since each subset will hit a given key, and multiple insertions are possible in parallel.\n\nAs usually, the Redis community will likely figure many usage patterns that are now not obvious.\n\n## How filtering works\n\nAbout filtering, if threading was not common in Redis, let’s imagine JSON! But for the first time, I found a good reason to expose JSON directly in the Redis API, user facing:\n\n&gt; VGETATTR word_embeddings_int8 banana\n{&quot;len&quot;: 6}\n\nSo basically with VSETATTR / VGETATTR (and equivalent option to set the JSON attribute directly when adding the item in VADD) you can associate a string to the items you want.\n\nThen you can do things like that:\n\n&gt; VSIM word_embeddings_int8 ele &quot;banana&quot; FILTER &quot;.len == 3&quot;\n 1) &quot;yam&quot;\n 2) &quot;pea&quot;\n 3) &quot;fig&quot;\n 4) &quot;rum&quot;\n 5) &quot;ube&quot;\n 6) &quot;oat&quot;\n 7) &quot;nut&quot;\n 8) &quot;gum&quot;\n 9) &quot;soy&quot;\n10) &quot;pua&quot;\n\nThe filter expression is not a programming language, is what you could write inside the if() statement of high level programming languages, with &amp;&amp;, ||, all the obvious operators and so forth (but I bet we will add a few more).\n\nWell, the details are into the doc, there are also memory usage examples, in depth discussions about specific features, and so forth. I will extend the documentation soon, I hope. For now I really (really!) hope you’ll enjoy Vector Sets. Please, ping me if you find bugs :)\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-04-03T18:01:20+00:00",
      "date_published": "2025-04-03T18:01:20+00:00",
      "external_url": "http://antirez.com/news/149",
      "id": "urn:aggr:item:b01e3d7ab2c56f106f4bf16361ca9853c860906b",
      "summary": "Yesterday we finally merged vector sets into Redis, here you can find the README that explains in detail what you get: https://github.com/redis/redis/blob/unstable/modules/vector-sets/README.md The goal of the new data structure is, in…",
      "tags": [
        "programming"
      ],
      "title": "Vector Sets are part of Redis",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-04-03-vector-sets-are-part-of-redis/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 545 days ago. 95667 views.</p>\n<pre><code><span class=\"code-snippet\">I used AI with success 5 minutes ago.\n\nJust five minutes ago, I was writing a piece of software and relied on AI for assistance. Yet, here I am, starting this blog post by telling you that artificial intelligence, so far, has proven somewhat useless. How can I make such a statement if AI was just so helpful a moment ago? Actually, there&#39;s no contradiction here if we clarify exactly what we mean.\n\nHere’s the thing: at this very moment, artificial intelligence can support me significantly. If I&#39;m struggling with complicated code or need to understand an advanced scientific paper on math, I can turn to AI for clarity. It can help me generate an image for a project, make a translation, clean my YouTube transcript. Clearly, it’s practical and beneficial in these everyday tasks.\n\nHowever, except for rare, groundbreaking examples like AlphaFold — Google&#39;s AI that significantly advanced our understanding of protein folding — AI has yet to genuinely push forward human knowledge in a fundamental way. Aside from these few exceptional results, AI hasn’t (obviously) yet matched the capabilities of the very best human minds. If an AI system were at the same level as the brightest humans (and not better than that:  it&#39;s not needed for a first humanity jump) we could deploy millions of such systems to accelerate research dramatically, transforming progress expected to take centuries into developments happening within decades, or decades into years.\n\nYet, if artificial intelligence remains stuck at its current level of development indefinitely (even if with small incremental improvements, enough to fire many translators, programmers, drivers, actors, ...), perhaps it might have been better not to have it at all. I mentioned this during a conference here in Sicily. The thought hadn&#39;t crossed my mind until I was asked on stage. While I was formulating my reply I asked myself: if we knew AI would only yield minor incremental improvements, would it be worth enduring the social upheaval caused by job losses and other stresses? Possibly not. Technologies should serve humanity by enabling greater cultural development, reducing suffering, and allowing us to achieve what otherwise would be impossible. The current level of AI, while helpful, doesn&#39;t fully achieve that.\n\nThat&#39;s why investing in AI is like making a bet. I advocate for further investment and continued progress — not necessarily because of what AI can currently do, but because of what it might become in the future. The advancements we see today often exceed our expectations, hinting at even greater unforeseen breakthroughs tomorrow.\n\nFor us proponents of AI, the argument shouldn&#39;t hinge solely on AI’s current abilities but rather on its potential. Five years from now, AI could offer revolutionary advancements in medicine, saving countless lives. In 10 to 20 years, it might significantly contribute to environmental solutions, clarifying complex issues or providing effective methods to mitigate climate change.\n\nEven a modest breakthrough might clarify that climate change dynamics, while serious, can be controlled more effectively than we currently believe, or don&#39;t need control as they are not as dramatic as we may think, or that decisive action can resolve the problem within a manageable timeframe. The real stakes are in the future, not the present. To focus exclusively on today&#39;s AI capabilities limits our perspective and makes it challenging to convince skeptics. But if future developments meet or exceed expectations, the temporary social problems arising today would be a small price to pay for the immense benefits.\n\nHowever, we must be cautious. Existential risks (AI potentially becoming a catastrophic threat) are real, though minimal. We must remain vigilant and prepared. Social challenges, too, require thoughtful attention from governments and societies.\n\nUltimately, I believe we must take the risk, persist, and explore what&#39;s beyond the frontier, because if AI fulfills even some of its enormous potential, it could redefine our capabilities, reshape society, and completely transform humanity’s future: for the better.\n\nNow, let me go back to my LLM for free and fast code review.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-03-23T08:13:53+00:00",
      "date_published": "2025-03-23T08:13:53+00:00",
      "external_url": "http://antirez.com/news/148",
      "id": "urn:aggr:item:44cf8649e343ab59bb4699565ba62c227f5136c2",
      "summary": "I used AI with success 5 minutes ago. Just five minutes ago, I was writing a piece of software and relied on AI for assistance. Yet, here I am, starting this blog post by telling you that artificial intelligence, so far, has proven…",
      "tags": [
        "programming"
      ],
      "title": "AI is useless, but it is our best bet for the future",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-03-23-ai-is-useless-but-it-is-our-best-bet-for-the-future/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 552 days ago. 155477 views.</p>\n<pre><code><span class=\"code-snippet\">By multiple accounts, the web is losing pieces: every year a fraction of old web pages disappear, lost forever. We should regard the Internet Archive as one of the most valuable pieces of modern history; instead, many companies and entities make the chances of the Archive to survive, and accumulate what otherwise will be lost, harder and harder. I understand that the Archive headquarters are located in what used to be a church: well, there is no better way to think of it than as a sacred place.\n\nImagine the long hours spent by old programmers hacking with the Z80 assembly on their Spectrums. All the discussions about the first generation of the Internet. The subcultures that appeared during the 90s. All things that are getting lost, piece by piece.\n\nAnd what about the personal blogs? Pieces of life of single individuals that dumped part of their consciousness on the Internet. Scientific papers and processes that are lost forever as publishers fail, their websites shut down. Early digital art, video games, climate data once published on the Internet and now lost, and many sources of news, as well.\n\nThis is a known issue and I believe that the obvious approach of trying to preserve everything is going to fail, for practical reasons: a lot of efforts for zero economic gains: the current version of the world is not exactly the best place to make efforts that cost a lot of money and don&#39;t pay money. This is why I believe that the LLMs&#39; ability to compress information, even if imprecise, hallucinated, lacking, is better than nothing. DeepSeek V3 is already an available, public lossy compressed view of the Internet, as other very large state of-art models are.\n\nThis will not bring back all the things we are losing, and we should try hard supporting The Internet Archive and other similar institutions and efforts. But, at the same time, we should focus on a much simpler effort: to make sure that the weights of LLMs publicly released do not get lost, and also to make sure that the Archive is part of the pre-training set as well.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-03-16T11:56:33+00:00",
      "date_published": "2025-03-16T11:56:33+00:00",
      "external_url": "http://antirez.com/news/147",
      "id": "urn:aggr:item:496720b508920c9ed458809cd239d1ee6abd0b16",
      "summary": "By multiple accounts, the web is losing pieces: every year a fraction of old web pages disappear, lost forever. We should regard the Internet Archive as one of the most valuable pieces of modern history; instead, many companies and…",
      "tags": [
        "programming"
      ],
      "title": "Big LLMs weights are a piece of history",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-03-16-big-llms-weights-are-a-piece-of-history/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 587 days ago. 108179 views.</p>\n<pre><code><span class=\"code-snippet\">It’s not new, but it’s accelerating. People that used to say that LLMs were a fundamentally flawed way to reach any useful reasoning and, in general, to develop any useful tool with some degree of generality, are starting to shuffle the deck, in the hope to look less wrong. They say: “the progresses we are seeing are due to the fact that models like OpenAI o1 or DeepSeek R1 are not just LLMs”. This is false, and it is important to show their mystification as soon as possible.\n\nFirst, DeepSeek R1 (don’t want to talk about o1 / o3, since it’s a private thing we don’t have access to, but it’s very likely the same) is a pure decoder only autoregressive model. It’s the same next token prediction that was so strongly criticized. There isn’t, in any place of the model, any explicit symbolic reasoning or representation.\n\nMoreover, R1 Zero has similar reasoning capabilities of R1 without requiring *any* supervised fine tuning, just generating chain of thoughts, and improving it with a reward function, using reinforcement learning, was enough to learn a stronger form of reasoning. Interestingly enough, part of these capabilities were easily distilled into smaller models via SFT, which brings me to the next point.\n\nThe other fundamental observation is that the S1 paper shows that you need very few examples (as little as 1000) in order for the model to start being able to build complex reasoning steps and solve non trivial mathematical problems. S1, and R1 Zero, hint that in some way in the pre-training step the models already learned the representations needed in order to perform reasoning, just with the unsupervised next word prediction training target.\n\nSo it’s not just that R1 is a vanilla LLM in its fundamental structure, but also the unsupervised pre-training creates enough representations and potential that, powerful enough LLMs, with RL (and/or some minor SFT), learn to reply to complex questions the users pose (I&#39;m referring to instruct models, an old but yet impressive capability) and to use chain of thoughts to reason about things and provide better answers.\n\nReasoning models are just LLMs, and who said LLMs were a dead end was just wrong. Now, to be wrong happens (even if the version of being wrong, in this instance, was particularly aggressive, particularly in denial of evidences). However, trying to change the history and the terminology in order to be in the right side is, for me, unacceptable.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-02-09T18:19:38+00:00",
      "date_published": "2025-02-09T18:19:38+00:00",
      "external_url": "http://antirez.com/news/146",
      "id": "urn:aggr:item:b5788540d37cc6c5c20b95df2a47c228f9d4ff61",
      "summary": "It’s not new, but it’s accelerating. People that used to say that LLMs were a fundamentally flawed way to reach any useful reasoning and, in general, to develop any useful tool with some degree of generality, are starting to shuffle the…",
      "tags": [
        "programming"
      ],
      "title": "Reasoning models are just LLMs",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-02-09-reasoning-models-are-just-llms/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 588 days ago. 369278 views.</p>\n<pre><code><span class=\"code-snippet\">We are destroying software by no longer taking complexity into account when adding features or optimizing some dimension.\n\nWe are destroying software with complex build systems.\n\nWe are destroying software with an absurd chain of dependencies, making everything bloated and fragile.\n\nWe are destroying software telling new programmers: “Don’t reinvent the wheel!”. But, reinventing the wheel is how you learn how things work, and is the first step to make new, different wheels.\n\nWe are destroying software by no longer caring about backward APIs compatibility.\n\nWe are destroying software pushing for rewrites of things that work.\n\nWe are destroying software by jumping on every new language, paradigm, and framework.\n\nWe are destroying software by always underestimating how hard it is to work with existing complex libraries VS creating our stuff.\n\nWe are destroying software by always thinking that the de-facto standard for XYZ is better than what we can do, tailored specifically for our use case.\n\nWe are destroying software claiming that code comments are useless.\n\nWe are destroying software mistaking it for a purely engineering discipline.\n\nWe are destroying software by making systems that no longer scale down: simple things should be simple to accomplish, in any system.\n\nWe are destroying software trying to produce code as fast as possible, not as well designed as possible.\n\nWe are destroying software, and what will be left will no longer give us the joy of hacking.\n</span></code></pre>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://disqus.com\">blog comments powered by Disqus</a></p>\n",
      "date_modified": "2025-02-08T14:47:49+00:00",
      "date_published": "2025-02-08T14:47:49+00:00",
      "external_url": "http://antirez.com/news/145",
      "id": "urn:aggr:item:254cecc82f7214a27178cb31bf9cc3c5dd59fb95",
      "summary": "We are destroying software by no longer taking complexity into account when adding features or optimizing some dimension. We are destroying software with complex build systems. We are destroying software with an absurd chain of…",
      "tags": [
        "programming"
      ],
      "title": "We are destroying software",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2025-02-08-we-are-destroying-software/"
    },
    {
      "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://antirez.com/user/antirez\">antirez</a> 648 days ago. 387332 views.</p>\n<pre><code><span class=\"code-snippet\">I’m not the kind of person that develops a strong attachment to their own work. When I decided to leave Redis, about 1620 days ago (~ 4.44 years), I never looked at the source code, commit messages, or anything related to Redis again. From time to time, when I needed Redis, I just downloaded it and compiled it. I just typed “make” and I was very happy to see that, after many years, building Redis was still so simple.\n\nMy detachment was not the result of me hating my past work. While in the long run my creative work was less and less important and the “handling the project” activities became more and more substantial — a shift that many programmers are able to do, but that’s not my bread and butter — well, I still enjoyed doing Redis stuff when I left. However, I don’t share the vision that most people at my age (I’m 47 now) have: that they are still young. I wanted to do new stuff, especially writing. I wanted to stay more with my family and help my relatives. I definitely needed a break.\n\nHowever, during the “writing years” (I’m still writing, by the way), I often returned to coding, as a way to take breaks from intense writing sessions (writing is the only mental activity I found to be a great deal more taxing than coding): I did a few embedded projects; played more with neural networks; built Telegram bots: a bit of everything. Hacking randomly was cool but, in the long run, my feeling was that I was lacking a real purpose, and every day I started to feel a bigger urgency to be part of the tech world again. At the same time, I saw the Redis community fragmenting, something that was a bit concerning to me, even as an outsider.\n\nSo I started to think that maybe, after all, I could have a role back in the Redis ecosystem. Perhaps I could be able to reshape the company&#39;s attitude towards the community. Maybe I could even help to take back the role of the Redis core as the primary focus of new developments. Basically I could be some kind of “evangelist” (I don’t love the name of this role, but… well, you get it), that is, on one side, a bridge between the company and the community, but also somebody that could produce programming demos, invent and describe new patterns, write documentation, videos and blog posts about new and old stuff. And, what about the design of new stuff? I could learn from the work of people in the wild, from their difficulties, distill it, and report back design ideas, in order for Redis to evolve.\n\n# Time in NY\n\nAt some point my daughter, who is now 12, and is a crucial person in my life, enlightening my days with her intelligence, creativity and love, wanted to visit NYC for her birthday. We decided that yes, this was a good idea after all, we had a couple very difficult years recently, so, why not? My daughter is now more of a girl than a child. So, in NYC, I thought: maybe this is the right time, I can do a part time job. I met the new Redis CEO, Rowan Trollope, very recently, in a video call. I had the feeling that I could work with him to tune the future of the company’s relationships with the community and the codebase direction. So I wrote him an email saying: do you think I could be back in some kind of capacity? Rowan showed interest in my proposal, and quickly we found some agreement.\n\n# About the license switch\n\nPeople will ask questions about why I *actually* did this, whether there is some back story other than what I just wrote above, if there is some agreement involved, or a big amount of money; something odd or unclear. But sometimes things are very boring: 1. I contacted the company, not the reverse. 2. I’m not getting crazy money to re-enter, it’s not about exploiting some situation — normal salary (but, disclaimer: yes, I have Redis stock options like I had before, no less, no more). 3. I don’t have huge issues with Redis changing its license; Specifically I don’t think the fracture with the community is *really* about this. But since people will ask me about that very important matter, it is better to tell you all the truth immediately.\n\n# The licensing dilemma\n\nI wrote open source software for almost my whole life. Yet, as I’m an atheist and still I’m happy when I see other people believing in God, if this helps them to survive life’s hardships, I also don’t believe that open source is the only way to write software. When I started to develop Redis in the context of a company where I was one of the two founders and where we kept the software code closed (Redis was opened as it was considered not part of the core product). We didn&#39;t want our services to be copied by others, as simple as that. So I’m not an extremist in this regard – I’m an extremist only about software design.\n\nMoreover, I don’t believe that openness and licensing are only what the OSI tells us they are. I see licensing as a spectrum of things you can and can’t do. At the same time, I’m truly concerned that big cloud providers have changed the incentives in the system software arena. Redis was not the only project to change license, it was actually the last one… of a big pile. And I have the feeling that in recent years many projects didn’t even start because of a lack of a clear potential business model. So, the Redis license switch was not my decision and perhaps I would have chosen a different license? I’m not sure, it’s too easy to relitigate right now, far from the scene for many years and without business pressures. But in general, I can understand the choice.\n\nMoreover, if you read the new Redis license, sure, it’s not BSD, but basically as long as you don’t sell Redis as a service, you can use it in very similar ways and with similar freedoms as before (what I mean is that you can still modify Redis, redistribute it, use Redis commercially, in your for-profit company, for free, and so forth). You can *even* still sell Redis as a service if you want, as long as you release all the orchestration systems under the same license (something that nobody would likely do, but this shows the copyleft approach of the license). The license language is almost the same as the AGPL, with changes regarding the SAAS stuff. So, not OSI approved? Yes, but I have issues calling the SSPL a closed license.\n\nYou will say (I can hear you): the real problem is that there are companies controlling OSS projects’ direction! So eventually the interests get more aligned with companies and less with the user base. I’m grateful there are many projects out there with zero direct companies involvement (if not external sponsorship), but well, you know what? Involvement of companies, in many large projects, actually slows down this process of skewing the right path. This surely happened in the case of Redis.\n\n# The Robin Hood of software\n\nLet&#39;s jump back into the past, to the first days of Redis.\n\nWhen Redis started to become popular, I wanted to find a way to continue working on it. This was before VMware offered me to sponsor my work. I started to play with the idea of a business model, and guess what? It was in the form of closed source products that would kinda help people running Redis, in some way or the other. (Amazingly, one of the repositories associated with this idea is still online, showing commits of *15* years ago: https://github.com/antirez/redis-tools)\n\nI was about to try some kind of open core approach; I also remember I was thinking about delaying the BSD license for new code for six months, in order to create some kind of advantage for paying users. Now I don’t believe I would be a jerk and do strange games with my users, but I would not be what I was able to be thanks to VMware and, later, more extensively thanks to Redis Labs later: a freaking Robin Hood of open source software, where I was well compensated by a company and no, not to do the interests of the company itself, but only to make the best interests of the Redis community. This is a better setup than having your own company, I’m sure about that.\n\nVMWare, and later Redis Labs, didn’t pay just for me. If you give a quick look at the repository contributions history, you’ll see the second all time contributor to be Oran Agra (Redis) then there is Pieter Noordhuis (VMWare) and so forth.\n\nSo basically I think that 12 years of BSD code written just focusing on the user base is a good deal, and it’s something to be happy about. And right now for me the most important part is that the fracture with the community is not about licensing, or at least it’s not mainly about licensing. Actually the new license can solve some part of it: now there is no longer an incentive to just leave the core in maintenance mode and put the new developments into modules. With the new license, cloud providers can’t just cut and paste the Redis code base and sell it without any revenue sharing (was this really asking for too much? This could have prevented all the license switches you saw lately, not just Redis). With the new license, the spotlight can be back on the Redis core, with new, exciting features in the hands of the developers around the world. With tens of people well compensated for their work pushing useful, well documented changes in the GitHub repository. This is also one of the things I would like to help the company with, and I’ll try hard. We need to make the license switch having good effects on the user base and features: that’s my idea.\n\n# About AI, LLMs and vector indexing\n\nBut there is more: Redis is getting interested in developing vector capabilities, and in general to support the kind of programming you can do with AI. Now, every day, I read Hacker News, and I see a huge amount of technical people who dislike AI and the new developments. I also see a lot of people who don&#39;t even care to really try the latest models available in depth (hint: Claude AI is in its own league) and still dismiss them as kinda useless. For me, it’s different. I always loved neural networks. I wrote my first NN library in 2003 and was totally shocked by how powerful and cool the whole concept was. And now, at the end of 2024, I’m finally seeing incredible results in the field, things that looked like sci-fi a few years ago are now possible: Claude AI is my reasoning / editor / coding partner lately. I’m able to accomplish a lot more than I was able to do in the past. I often do *more work* because of AI, but I do better work. Recently I wrote a sci-fi short story for an Italian publisher, and thanks to Claude criticizing parts of it I rewrote the ending and produced a much better work (I didn’t let Claude write a single line of the story or the plot: great use of AI is not making machines do what you can do better).\n\nYesterday I needed to evaluate how much faster dot product could be computed with 8 bit quantization of my vectors; I told Claude I needed a benchmark designed in a specific way, and two minutes later I could test it, modify it, and understand whether it was worthwhile or not. Basically, AI didn’t replace me, AI accelerated me or improved me with feedback about my work. And I believe that (regardless of the popularity of RAG, which is not necessarily the main application, nor the most future proof or useful, as models contexts are becoming larger and larger, and soon popular models attention may have linear complexity), sorry for the digression, I was saying that I believe that learned embeddings are here to stay, and vector search is something that belongs to Redis for several reasons: first because vector indexes are data structures, particularly slow data structures, and such data structures can work very well in memory. Also, because I think I found the perfect API to expose them.\n\nDuring my work in designing Redis, I always showed some contradictory tendencies. I was always ready to say “no” to certain things that looked like perfect fits for the project (named Lua scripts, hash fields expires, that are both part of Redis now, btw) but at the same time I added Lua scripting capabilities — when it looked like nuts, an interpreter inside Redis?! —, the Pub/Sub capability, that seemed out of context, then streams, and even synthetic data structures that don’t exist in computer science books, like sorted sets. Because, for me, the fitness of new features into Redis was about two things: use cases and internal design fit. Redis, for me, is lego for programmers, not a “product”.\n\n# Vector sets\n\nSo recently I started to think that sorted sets can inspire a new data type, where the score is actually a vector. And while I was in talks with Rowan, I started to write a design document, then I started to implement a proof of concept of the new data structure, reimplementing HNSWs from scratch (instead of using one of the available libraries, since I wanted to tune every little bit), the Redis way, and well, I’m not sure how this will end, I’m still in the early stages of coding, but perhaps I may end up contributing code again, if this proposal gets accepted. The module I implemented (that would be later merged into the core – for now it’s a module just for the sake of simplicity) implements new commands that manipulate embeddings directly. I’ll show you just that as a hint:\n\n\nVSIM top_1000_movies_imdb ELE &quot;The Matrix&quot;  WITHSCORES\n 1) &quot;The Matrix&quot;\n 2) &quot;0.9999999403953552&quot;\n 3) &quot;Ex Machina&quot;\n 4) &quot;0.8680362105369568&quot;\n 5) &quot;Akira&quot;\n 6) &quot;0.8635441958904266&quot;\n 7) &quot;District 9&quot;\n 8) &quot;0.8631418347358704&quot;\n 9) &quot;The Martian&quot;\n10) &quot;0.8608670234680176&quot;\n11) &quot;The Bourne Ultimatum&quot;\n12) &quot;0.8599717319011688&quot;\n13) &quot;The Bourne Supremacy&quot;\n14) &quot;0.8591427505016327&quot;\n15) &quot;Blade Runner&quot;\n16) &quot;0.8585404753684998&quot;\n17) &quot;Metropolis&quot;\n18) &quot;0.8572960793972015&quot;\n19) &quot;Inception&quot;\n20) &quot;0.8521313071250916&quot;\n\nSo you have VSIM, VADD, VCARD, all the obvious stuff. It’s exactly the idea of sorted sets, but with multi-dimensional scores (embeddings!) and K-NN matches. What do you think? And, of course, on top of that there are many implementation tricks to make stuff more efficient. But for now it’s proof of concept code, let me work a bit more on it. I’m implementing threading, dimensionality reduction, quantization, and many more things. Quite fun, to be honest.\n\nAs you can see, there is no mention of hybrid search, the recent buzzword about vector stores. Again, this is the Redis way: to let the developer have a role and decide on their tradeoffs: they know what they are modeling, after all. You have a vector index per key, and like what programmers were able to do with sorted sets, they will invent interesting splitting strategies, new schemas, Lua scripts, patterns and all that is required in order to model their use cases.\n\nStill, while normally the associated item will likely be a small string or a document ID, nothing prevents it from being something more complex, with metadata that can be filtered later (but I’ll resist). I just have the feeling that many use cases don’t really need complex server-side filtering, and can be modeled by pre-partitioning data.\n\nWhat I see with great interest is the addition of a potential STORE option, to store the result into a sorted set instead of returning it to the user, where the score is the similarity, of course. All this also has complex and interesting effects on efficiency, scalability, ability to use scripting, and so forth: I hope I’ll have the opportunity to talk more about it in the next weeks and months.\n\nOk, ok: back to the point of this blog post. But perhaps the above is the *real* point, having new ideas that can be exciting.\n\n# So, I’m back 🙂\n\nAll this to say that, I’m back. I think it’s the right moment for a big thank you to all the Redis community, for what it has done over the years. See you around, I hope there is something more to add to this journey.\n\nP.S. I’m active on BlueSky, if you want to follow the developments of all this. https://bsky.app/profile/antirez.bsky.social\n</span></code></pre>\n",
      "date_modified": "2024-12-10T16:38:55+00:00",
      "date_published": "2024-12-10T16:38:55+00:00",
      "external_url": "http://antirez.com/news/144",
      "id": "urn:aggr:item:ef8bc9ad4ac77199b0085e83c05ef5207936e6d1",
      "summary": "I’m not the kind of person that develops a strong attachment to their own work. When I decided to leave Redis, about 1620 days ago (~ 4.44 years), I never looked at the source code, commit messages, or anything related to Redis again. From…",
      "tags": [
        "programming"
      ],
      "title": "From where I left",
      "url": "https://aggr.aymericbeaumet.com/items/antirez-com/2024-12-10-from-where-i-left/"
    }
  ],
  "language": "en",
  "title": "antirez.com",
  "version": "https://jsonfeed.org/version/1.1"
}