Nonchalant Guidance

About Me·RSS·My Projects·LinkedIn


Added on: Monday, 21 October, 2024 | Updated on: Monday, 21 October, 2024

AI All The Way Down

Disclaimer: I did not write this using an LLM. I enjoy writing, why would I automate that?

For the past year or two, the world has been lit on fire, partly thanks to the introduction of large language models to the general public. Debates have raged on, jobs may have been cut or downsized, lawsuits have been filed detailing the dubious methods used to collect training data from the Internet without prior permission from website hosts and users alike, but one thing is certain: current AI models, as they are, are transformative.

Personally, I don’t really take much stock in the fact that AI will replace humans in creative endeavours. I’d like to believe that art is only really made by people, and generative AI will just be a tool people use to make it. AI “art” is mostly a misnomer, and that also goes to AI-generated books and the like. They’re amusing, but not really a replacement for one or more people trying to convey a message through a story, a painting etc.

There is a discussion to be had about how training data has been gathered and how, in a post-ChatGPT world, the Internet as we know it is falling apart both thanks to even more convincing bot comments and how websites are becoming warier of web scraping and automation, but that is not what I am discussing today.

Background

My number one use of LLMs, from the beginning, has been to get them to write code. When I first got access to the original GPT-3 powered ChatGPT in late 2022, some of my first interactions with it involved me feeding in a schema of database tables and having it try and solve some of my college’s DBMS class questions (I already solved these by hand, so no, I did not cheat).

It was extremely impressive: ChatGPT would give me a SQL query similar to the one I wrote myself, and in another context, when presented with a schema and a query I wrote myself, it was able to reason its way into telling me what the query did and what the result represents.

I also used it to learn more and prepare for tests. While factually it was not as accurate as reading books or articles on the Internet from reputable sources, when it came to unfamiliar material, it was able to give me enough keywords and a vague “gist” of the topic to be able to search more on the Internet about the topic in question.

I did try it out for creative writing, but I was never very impressed by the results in this regard, and ended up never really exploring those aspects.

Of course, that did not last. When I repeated the same experiment with ChatGPT 3.5 last year, it pretty much bombed. I’m sure GPT-4 (or 4o, or o1) would probably still work fine for this, but the free offerings from OpenAI have steadily decreased in quality as they try and get the operational costs down for free users.

As the free models steadily took a nosedive, and also to avoid hallucinations, I shifted to Brave Search and Kagi with their AI features, which worked well enough to optimize queries like “how do I do X in Y language”. In case these don’t work, only then do I end up “falling back” to a chat interface.

In parallel though, some smart people were building stuff like GitHub Copilot, which would live in your editor/IDE of choice and suggest completions based on your codebase and what you were currently typing. Reviews online seemed to land around the lines of “it basically replaces searching online for ways to do X in Y language” and “it is like LSP autocomplete turned up to 11”, so I decided I should start looking into how well this works.

Tool of choice: Aider

aider is a CLI tool which allows you to add your codebase as context and have the LLM modify your code, and create a git commit of the requested changes to boot.

There’s a lot more to it (asking questions about the codebase comes to mind for one, along with voice support, tool calling/running CLI commands, and even scraping the web for additional context using Chromium and a browser automation library!), but the core feature set is what I’m here for.

An aside: when I first started using aider, I noted how slow it was, especially compared to zed calling the same LLM and with similarly complicated query and context. I ended up putting up with it but using aider noticeably less, until for an unrelated reason I disabled IPv6 on my machine. Lo and behold, aider starts being extremely responsive to my prompts, and my Time to First Token becomes far more reasonable than before. Maybe there’s an IPv6 bug somewhere in the Python-based stack aider uses?

The Test

I decided to kick the tires on LLM-based development by creating a somewhat small project: a video game backlog tracker that would use HowLongToBeat and DoesItPlay to both help keep track of how long a game in the backlog is and if games in a wishlist are playable offline with just the disk.

I wanted something private, offline and open-source, and everything else was online-only and needed some account to access. It also doesn’t have DoesItPlay integration, which I thought would be a nice differentiating factor.

Initial Progress

In a few hours (read: maybe 2.5-3) I had a database with games I could add from the HowLongToBeat database, and a “platforms” table which I could use to store the platforms in a standard format.

Most of this time was initial setup: I had mistakenly forgot to enable the “derive” feature in the clap crate, and was repeatedly trying to “fix” the code (which was perfectly fine).

During my experience getting aider to write the code for me, it was not flawless. I had to step in:

There was also one time the code the LLM wrote was mangled for some reason (as in, it wrote the code properly but it had a bunch of whitespace and a newline in between which turned the word “sort” into “so rt”). This I also fixed myself.

Adding tests

Adding tests was interesting. The first attempt, it seemingly ended up creating its own test runner, with an initialization step unlike anything I’ve seen in Rust-land. The second time around, aided with my instructions to use standard cargo test tooling, it fared much better, but not perfect. It still wanted to do weird one-time initializations, so I stepped in and cleaned up its mess.

There were also other problems, like it using a database saved to disk for tests, and the codebase at the time having hardcoded the database creation, so I split those steps into creating the database and then setting it up with tables. This way I could use an in-memory database for tests and a real database file in production.

Another problem was a bit more logical. The LLM intended to insert one record for a game called “Test Game” and try inserting it again to make sure we can prevent that from happening. However, it would end up inserting “Game Test” (or something named similarly, ie, NOT “Test Game”) instead, and the test would be completely useless.

After some of these hiccups, however, it was fairly smooth sailing. It would get 80% of the way in writing the test, and I’d have to come in and fix the last 20%. Sometimes breaking API changes would mean the tests would end up failing to compile, and having the LLM fix these had a 50-50 chance of succeeding.

I definitely think having it write tests for my code was very good, and one of the best things I’ve seen people use LLMs for is to use them to add more tests to their code. This is something I’m willing to try out in more projects going forward.

Final Review

What I really liked about aider during this stage was just how easily it got me over the initial “I don’t want to write this setup code” stage. This small program is eventually going to be pretty useful for me, serving as a replacement for the Markdown doc I use and becoming an Android app (which would use the Rust code being written now as a backend).

It was not without its flaws, some of which are documented above. I initially amended aider’s own commits with my fixes, but later, any fixes I would do, I made in my own commits under my own name, so the human-LLM work split should be much clearer to see.

Running git shortlog --summary --numbered --all --no-merges on the repo as of the writing of this article, aider has 26 commits whereas I have 25.

This is pretty consistent with my experience, no aider-made commit was 100% correct, and would have required a corresponding correction from me. Also there’s some work I did on an aider-authored commit which is attributed to it as well, and some of my commits are documentation and licensing stuff.

As for this project, if this sounds interesting to you, stay tuned, because I do plan on developing this much further and using aider to skip to the novel part: using this core inside an Android app. This small experience has convinced me that trying out new stuff I’m more unfamiliar with is a lot easier than it used to be.


This website was made using Markdown, Pandoc, and a custom program to automatically add headers and footers (including this one) to any document that’s published here.

Copyright © 2024 Saksham Mittal. All rights reserved. Unless otherwise stated, all content on this website is licensed under the CC BY-SA 4.0 International License