Transcript
0:00 This is basically like the thing we all learn. The very first thing we do when we learn to code is we write the hello world is like okay let me just do this thing and now I see by example this is how it works. >> It's also why print debugging has overtaken like GDB debugging and debugger based debugging. It's because like it's just a learning test. That's what you're doing. >> So yes. So what we're going to talk about today is like how to formalize it and some ways that we've used it and we have some code examples of like how you can apply these techniques.
0:28 >> Like these models have gotten better. So all of us have done less work to do learning tests for simpler problems. We just kind of assume that they work when you call an LM but for more complex problems you still want [music] learning tests. >> You can accidentally steer a model. You cannot accidentally steer a type checker. And so if you can give the model access to a tool that draws deterministic like there's no opinions, there's no non-determinism in it. It's either right or wrong and then give the model the feedback about why. It gives the model a way to check its own work without having to rely on its decisionm which is like we all know models make bad decisions sometimes. They ship slop code. They do things wrong. They >> just like humans by the way. It's not just a model problem. It's a code problem. Code humans created this for humans. We wanted back pressure.
1:13 >> Exactly. All right, everyone. Welcome back. This is our weekly episode with Dexter and Bibb for AI that works. Uh, I run a company called Boundary where we make a programming language called BAML. Dexter works on an awesome tool called Riptide at a company named Human Lair. We've both been in the AI space for a couple years now. And we've been doing some stuff and the main point of this podcast is just yap about AI things that actually work. Incredible. I couldn't have done it better myself. Um, today we are talk a couple quick announcements.
1:49 Um, so the other episodes we we've updated kind of the schedule. So every Monday you'll get an email with the YouTube from last week's episode. A little teaser for what's coming next. The other thing that I think is worth shouting out as well is we are uh locking down a time and place for the uh in celebration of the 50th episode of AI that works, we will be doing a little unconference uh live in San Francisco.
2:11 So, in person, um, mostly off the record, um, just talks from builders. Um, everyone who comes is going to help build the agenda together. No RFP, no speakers like, uh, applications, just show up with something to talk about. So, if you're in SF or you're thinking of want to hang out with other AI that works people, uh, that will be happening >> and you'll be welcome to apply and hopefully we'll get as many people in as we can.
2:35 >> I think that's it. Let's get into what we're talking about today. Um, >> let's do it. >> So, I have a question for you, Vibb. Um, we've talked a lot about your coding agent workflows and your stack. Um, and I wanted to ask you like have you ever had a situation where you got like, you know, we do our plans and then we we do our research and our planning and our design and all this discussion and like figure out what we're going to build.
2:57 And at that point, we haven't really written much code yet, right? It's just working with Markdown and understanding what's there. Have [clears throat] you ever gotten to the point where you're deep in an implementation and you realize like, [snorts] oh, I was wrong about something? Like, I had some assumption much higher up about how a thing worked and it leaked all the way in and actually now I have to throw out this entire plan because there was some base assumption that was wrong.
3:20 >> Last night at 2:45 a.m. So, one of the things that we do in BAML is when you write BAML code, we do some really interesting work to make streaming work really, really nicely. What we do in BAML is we say something like this, main.py py if you call a streaming function. Um, can you see? All right, Dexter. >> Uh, yeah, I can see. Maybe go one one bigger. Yeah, that's better. Cool. >> Uh, resume equals B. Extract extract resume.
3:54 Uh, let's say you put in some resume over there and then you do a stream and then you do for chunk and resume. you do chunk dot like email for example, email is going to be optional automatically. But then if you went here and typed in like streamdone or stream not this becomes a string. So we actually generate two different type systems here. And this is >> where you have the partial type and then the full type. Right.
4:19 >> Exactly. But it gets even more complicated. So like let's and I'll show you the example in a second. Let's say you have a foo string and you have a type bar equals string or string or int or fu or string. When you do this over here, this should still be a string type even though it's like mapped through like multiple aliases. So there's a lot of simplification and weird things that we have to do to make this work nicely.
4:46 >> Collapsing the tree into the types in whatever native language that you're generating the stubs for. >> Exactly. And like we have to do like we have to do it in the in the streaming type system and the non-streaming type system to make it work perfectly. And this gets even hairier once you have classes with nested classes with nested aliases and recursive types and everything there. >> Yep. >> So I had an assumption there was baked wrong in the new work that we've been doing how to make it nicer and more ergonomic for developers to be able to modify better >> and like I just had to completely throw that out in terms of our implementation detail. I can talk about the actual implementation that's interesting but this is like the core problem because we have three types we have a type system during streaming we have a type system that the compiler reads and then we have a type system during non-streaming modes and we have to build algorithms for all three and that's architecturally wrong that we have to implement the same almost the same algorithm three times >> and the by algorithm you mean the thing that reads in raw like token [clears throat] streaming out of the model and decides how to translate that into a like full or partial structured object It takes a type that the user wrote and generates an equivalent type in any language of your choice that's perfectly matched and ergonomic based on what the code that you wrote here. The type simplification algorithm in the compiler.
5:59 >> Um, cool. So, can you like would you be able to riff out kind of like code like I want to see two types of code basically? One of them is like here's my assumption. Like can you write code that like shows that your assumption is false? Basically like here's here's my assumption and here's an assert that would like you know you know what I mean? >> I don't know if I can do that for this problem because this is more of a design problem. The design problem here from like a whiteboard perspective is that I have to I I I end up having like a class called uh type then I end up having a class called non-streaming type. Then I end up having a class called streaming type. And if you know Rust code, they're not actually classes. It's like an enum.
6:40 >> Okay. This is pseudo code for Rust. >> Yeah, exactly. Like I have an enum called like string that has like a string type and they have all these. And like in non-streaming, we have almost exactly the same exact thing, but there's some slight differences that exist in streaming versus non-streaming. And then stream similarly over here. There's some slight differences. and I have basically the same thing implemented three times, but they all have totally different semantics. And that's what's crazy about this.
7:09 >> So, it's an certain places in certain places downstream, even though the field names are the same, they're they're different strus. And so, you have to have like a switch statement for every single one like have like tag unions for the thing. Okay. >> So, it's exactly a design philosophy that's kind of wrong in our current compiler. >> Cool. That's great. Yeah. I had a similar thing uh recently where we were building some stuff on top of the cloud agent SDK. So essentially um you know you have uh the way the cloud agent SDK works is you have this like TypeScript uh SDK and you have a method called query and this thing takes in a giant options blob for how you can configure cla >> and then what happens under the hood is it actually like invokes the claude CLI um and it translates all of these options into some types of like flags basically. So if you say like you know Like if you if you put in here, you know, uh let's do >> allow dangerous permissions and it just said it makes sense.
8:09 >> So yeah, so you have like permissions mode bypass permissions. >> Yeah, >> this changes into a flag which is dangerously skip permissions. >> Exactly. >> So I've kind of just like written a wrapper on the CLI that allows you to call it from your TypeScript code. Right. Um okay this is a very simple example and there was other there so so this is like the the basic example what we wanted to do is we wanted to basically like experiment we wanted to like run something where it's like cuz this also had allowed tools and uh disallowed tools. Um, and so like you can put in a list here of like, you know, write, bash, edit, whatever it is.
8:54 Or you can say, you know, we want to disable task is what the tool for sub aents is called. Or you might want to disallow like uh I don't know what's another thing uh notebook edit, which is the Jupyter notebook thing. If we're like, we know we're not touching Jupyter notebooks. Um the thing is is like the beha we had some assumptions about the behaviors of these things and we got deep into this implementation and we found out that actually like what allowed tools does is um and this is like we're talking about the cloud agent SDK that is just an example like we're going to go a little bit like zoom out a little bit more of like how you can use this for any API but the idea here is like most of the code here is a system we don't control and we can't read the code >> valid >> and so the standard workflow of like research um plan implement.
9:44 >> Yeah. >> Like this relies on like we can get all of the knowledge we need to correctly build this feature by reading the code understand how the system works. The thing is is like if you have your code repo right and then you have you know you have all your modules etc but then if you're using like an SDK like this where you have like external dependencies some of these things like in if it's in node modules right you can also go rip gp through the source code of those things and you can research that um but if those things reference a external API maybe a closed source API or a uh you know closed source binary basically anything where you can't read the source of it then your research actually is just going to assume how that thing works and like the what would okay so let's assume you're doing this what's your first step that you would take to like let's say you were working on the cloud agent SDK how how would you how would you try to get better understanding of how that thing works >> I would just run it with a bunch of parameters or like d-help or other things.
11:00 >> Yeah. Okay. So, you could go to the cloud docs and you could pull in the reference, right? >> Um, and these docs are pretty good. They're very comprehensive. They tell you every parameter, everything you can pass in all of these things. There's like >> Yeah, that's even better than what I was doing. >> Yeah. So, you could go read the docs, right? So, you can and I actually have done this in our in our episode folder.
11:21 And so, like I grabbed the docs and I just dropped them in here. You can also use web search. You can use context 7. There's lots of different ways. So like that's step number one is like pull in the docs, but that generally in my opinion is not good enough. Um because it's easy to read the docs and misread them. They're very long. It's a lot of context. Like like subtle things can be missed. >> Um and so what we do is exactly what you said, which is we'll actually build what I call a learning test. And this is kind of the core of the episode is basically like I want to understand how these fields actually work. The best way to do that is you would create a what what we call a learning test. And this was invented I forget who mentioned this first learning test software. The problem is that this phrase has terrible SEO >> because this is just test assessing students.
12:10 >> I'm sorry that I stole the thunder and I just said it up front. I was I didn't realize that's what you're getting at. I should let you build up to it. >> Yeah. Um learning tests. Um, >> yeah, but the premise is like >> Yeah, Michael Feathers. Here we go. Yes. So, it it was in this thing of like working effectively with legacy code. >> Um, he talks about this uh of just like systems that are hard to understand, maybe you just jump in and poke them from the outside.
12:42 >> Yeah. Most people I know that work in like really complex like algorithm design problems like the way that you explore an algorithm space that you like when you're updating algorithm that you don't know. example, this is the only way to go do it. If you're doing like for example like a really easy analogous system to this is like performance engineering. If you're ever trying to reduce the amount of like assembly code that you generate, you don't actually you don't model the assembly. You literally write the code, you look at the assembly that gets generated, you're like cool, this is the slot I want to reduce. Then you experiment, you see if you reduced it. And that's like the way that you do this. There's different techniques beyond just like reducing the amount of assembly code and that doesn't always make your code faster. like reducing like that's an easy like performance engineering is basically a learning test all the time.
13:25 >> Yeah. So you could read the compiler code or you could just write a program compile it. >> Exactly. >> Look at the output. This is basically like the thing we all learn the very first thing we do when we learn to code is we write the hello world is like okay let me just do this thing and now I see by example this is how it works. It's also why print debugging has overtaken like GDB debugging and debugger based debugging. It's because like it's just a learning test. That's what you're doing.
13:52 >> So yes, so what we're going to talk about today is like how to formalize it and some ways that we've used it and we have some code examples of like how you can apply these techniques to basically in your research pipeline. Um the first thing we add of course is like read the code. The second thing we add is also uh you know read external docs, blog posts etc. Like if someone else has figured out how to glue a bunch of systems together in a way that works then we should pull that into our research doc as well and into our planning. And then the last one is actually as part of research it's write learning tests. So we're not writing code to ship a feature. We're writing code to like some people also call this like proofbased development where it's like we're proving the system works in the way that we think it does rather than like instead if we if we didn't do this we would just carry some assumptions through.
14:45 So the assumption lands in the research based on either what we read in the docs or just what is baked into the model weights that makes it into the plan that makes it into our implementation and then like uh like you know we do phase one and everything's working and then we do phase two and then everything's working and then in phase three we actually hit this thing that like oh our assumption was actually wrong and then we literally have to go and redo all of the work, all of the implementation, all the planning, all the research because we learned something and our idea A with AI coding is always about like leverage, right? We have this thing that we've been posting if you go all the way back to um AI that works the like August 5th one, right? Advanced context engineering for coding agents.
15:31 >> This thing of like >> focus on the highest leverage parts of your pipeline. What you don't want to do is like be, you know, hundreds of thousands of or like, you know, thousands of lines into your implementation and suddenly find yourself in a spot where like, oh, something was wrong and it invalidates everything before and we have to go back. And so when we write these learning based proof tests, it lets us vet our assumptions before we proceed into what we're going to change about the system.
16:00 Does that make sense? >> I agree. I think like especially for like algorithm design stuff or like new feature stuff, this is like an easy way to do this. But I'm going to make I'm going to make one push back that I'm always curious about in these scenarios. This just sounds like it's like one of the tools because obviously if you're doing something super complex like for example the type system work that I was doing there's no learning test I can do there that just requires like design >> but it sounds like for implementations there's a lot of learning tests that you can do and before you implement you might benefit especially when you're implementing against a black box you might and I actually like you know what's funny the best learning test is actually like when you're calling an LLM >> when you call an LM the only are a form of learning tests. Actually, like the way the boundary playground works is it enables you to do learn like if I put this prompt in, how will the LLM behave and to riff back and forth before you actually go stitch all of that into your code?
16:58 Is that where you're getting at? >> Exactly. Like because you like that's how you kind of build the learning test around this. And as we've gotten um as we've gotten there, one thing that we found that's interesting I think is this idea of how do you like these models have gotten better. So all of us have done less work to do learning tests for simpler problems. We just kind of assume that they work when you call an LLM, but for more complex problems, you still want learning tests.
17:25 >> I really like the framing there. That's a that's a really nice um I I've done this a few times. Um whenever I've uh what's it called? I've like this is how I've modeled most systems I've worked in because of the algorithm work that I did >> but yeah exactly like that's a learning test when you go actually press play. I don't think you have your API you might not have your API key but >> yeah you get the idea. I I haven't this is a new laptop so I just had to install BAML for the first time on my VS Code.
17:53 Uh because I haven't used VS Code or Cursor in a while. >> Really? You've moved on to Zed? >> So I use Zed because I'm almost always just using an editor to read and write Markdown files and their markdown viewer is pretty nice and it's really fast. Like so I can quit this. If I open Zed, it's open instantly. It's so fast. >> Yeah, I know. I know. Okay. I >> And you're going to tell me that it's cuz it's built in Rust, right? Of course, >> all things [snorts] built in Rust are fantastic.
18:21 >> Yeah, >> I'm trying back to this. So, yeah. So, I guess what you're saying is that the the the the issue you hit, which was a design kind of misconception, was not actually a good example of what we're going to talk about today. >> Yeah. Exactly. Exactly. And there there's a class of problems there, but there's a large large large class of problems where learning tests are the best way to really iterate. >> Yep. So, I'm going to pop open to like going a little bit deeper on this specific example that um we were looking at. Um here's like a very basic learning test.
18:53 It's barely even a learning test, right? It's just a hello world script. Like hello world is the most generic version of uh of of a learning test, which is like I'm going to run this code and see how it works. And so I'm telling it like read the meta MD and tell me what's there and then console log all the messages. So this is letting me see the structure of the output and what are the messages that come out from the cloud SDK when I run it etc.
19:17 >> So I'm going to ask some interesting questions here Dexter >> um when I or at least question that I find interesting at the very least. >> Um so this sounds like a thing that I think a lot of developers probably do very naturally. How do I >> It's especially before AI, it was a very normal thing to be like, I'm using a system I don't understand, whether it's a new library or another or a new database or whatever it is. Like we used to do this all the time. And it was the idea like the idea of learning to Sorry, finish your thought. I I'm going to draw something.
19:47 >> While you could draw that like the real question I really have is like I think most developers do this intuitively like when you use the new API, you often curl it first just to be like what the heck does it return? >> Um Yep. And like that's a learning test. Um, so I I suspect that that concept is in you. Tell me how I amplify this and tell me why. Like I see cloud code doing this sometimes as well.
20:07 >> Like it often will actually happen. >> Cloud code ends up doing it like at the in in the end where it's like, oh that didn't work the way I think it did. I'm sitting in a pile of git diffs. Like how do I try to resteer out of this situation? You could ask it like hey go figure out how this thing works and write a doc about it. And that's kind of what we're going to get into is like how do you get claude code to help you do this stuff.
20:28 >> Okay. >> Um but the idea with learning test is like if you want to like the the biggest the like really basic example is like you you have a new logging library, right? And you want to see like how logger the logger works, right? >> Sure. Yeah. >> And so you write a little file and you test what does logger.info do, what does like logger set level do, etc. >> If you just wanted to like understand how this library works.
20:51 >> Yep. [snorts] Makes sense. >> And like You have your code which is like you know public main whatever and then you have your test which is like you know public test ABC and this is like what you're supposed to use test for is like you write app code and then you write unit tests and like as you change the code you make sure the tests don't still pass. >> What you're not supposed to do is actually test external code because like the library maintainers are testing that code for you. like you should not maintain a bunch of unit tests for external libraries.
21:24 >> Yeah, I agree. >> But unit test frameworks are kind of nice because you can say you know you can attach attach something to standard out and then you can assert like that a thing was a thing was printed >> okay >> to standard out or a file or whatever. You wouldn't run these all the time but you have a little bit of a demonstration. So when you want to write code with this library, the model can go read this really useful and you know before it was like humans would use this as a reference. So like okay now I know how to apply this in my app code. Um but it also means and we've actually hit this before is like we had this thing of like public and I'll show you that we actually have this test in the code but it's like test it was like how cloud SDK session continuation works.
22:09 Um and it was basically like if you res if you if you resume a session uh there was a a behavior where like the session would always get a new ID not equals pre session id um and then they change this behavior and so what you get with this with a set of learning tests you don't run all the time the same with your evals like you don't run your evals on every CI/CD loop right but you can go run them manually or you can run specific specific evals if you have a feeling about what's wrong. If you think the contract with your external library has changed, which is a thing from cloud SDK1 to cloud SDK 2, um they changed the default behavior where now you have to pass in this fork session equals true. And so you have a literally like a documented list. We have probably a hundred of these now that we have documented our contract with the external things that we don't control. And then when we pull in a new version, all we have to do is rerun the learning tests and we know if something broke. And like it's not 100% coverage, but every time a contract with our external system breaks, we had another learning test. Um, and so you wouldn't do this for every single library use, but if you have a library that likes to change APIs sometimes, then this can be a really valuable way of like let me verify like if I think it wasn't our code that broke as something changed over there, you have a documented thing.
23:34 And I'll get into like some of these are quite uh And and what's really interesting over here is actually a second thing. What you're really specifically doing is it's not just a library because it's a library. You get types, you get everything else around there that are kind of deterministic that help constrain a lot of this. In your case, you're copying you're calling a CLI command which has no >> CLI or or like I've I've used this with some teams who are trying to use the OpenAI responses API and like there's different ways you can call it that cause it to like preserve or remove the thinking tokens from previous conversations. So, it's really for like poking black boxes that you don't control or that it's very inconvenient for you to go actually look at the internals.
24:14 >> Makes sense. Yeah. It's like what you're treating something like a proistic system. it has some probability of producing something and consumes some various kinds of inputs. So you're trying to constrain the probabilities. >> Yeah. So we can go from this basic hello world to like a slightly more interesting one. This is still not in a test harness. Um but we can improve the like printing and writing. And so we can do, you know, bun run ob.
24:41 And this is going to give me a little bit nicer output of like me as an engineer trying to see, okay, how does this thing behave when I ask it to do certain things, right? Okay, so this one was just say hello. Um, and then we can start doing like checks and like evaluations about it, right? So we we tell it to say hello. We're still streaming out all the messages. And then we're actually like outputting some like boolean flags about like is this true?
25:07 Is that true? Like did we get a session ID out? Um and starting to like basically like articulate the behavior of this system for whom for which we cannot read the code. >> Yeah. I think I think what to summarize I think what I'm hearing is you're trying to write unitest for external fuzzy libraries. >> External fuzzy libraries. And so like this is where you go from like hello world to a little bit more sophisticated. And eventually what we would if if you do this for a while, you end up just putting this into the unit test framework of your language.
25:36 >> Exactly. >> So here's like what does query emit and in what order. And so now we have not just logs but we have assertions about this. And so if they change the ordering of messages or add a new message like this test will then start to fail. >> Yep. >> Sorry. Um what's really interesting here is I've seen tests like this before at a at a couple places that I've worked. So like for example, we had a large network dependency on like some external finance system at my previous employer.
26:05 >> And in that scenario, >> see I worked in fintech too, dude. We had like a SOAP API that ran like over a tnet server. It was crazy. >> Exactly. And when you run into this problem, uh really it's not that like I think the common place where people have already done this because I think there's a large place where people in their code bases do this today already is like database setup. If you're ever trying to hit a database, you don't want your data database tests are notoriously flaky, especially like large scale systems.
26:31 >> And because they're flaky, you'll often write a pre-check that says, "Hey, if the database setup failed, just skip all these tests to run or fail depending on what company you're at." Y >> and that's basically kind of something similar where you have an external dependency that's kind of fuzzy and you want to have some known constraints and known goodness behavior before you start running the rest of your test cases >> because if those fail then some assumptions that you made about the external system are just bad.
26:54 >> There's this really funny interview question I think that I remember >> from a really long time ago >> which is like you have a blackbox API that takes like 25 minutes to run. How do you make it faster? >> Yeah. And like it's very similar like you and they gave you no other information. They'll tell you what the API is, what it inputs, what it outputs. You just have an API that's undefined and you have to go explore it.
27:16 >> Um and like that's I think a very similar kind of problem like you have to apply like a penetration testing approach. >> Again security of like okay what protocols does it support? What are the inputs and outputs? Like how does it behave under certain we call Yeah. We can call this also like fuzz testing right where you just like test the full range of output of inputs to see what breaks. >> Yeah. Exactly. So, there's so many different ways to do this. It It sounds like a really useful technique. How Now, the question I have for you is I think the hardest part about the system isn't actually implementing this because once you come up with the design, I'm sure you can just have cloud code rip through test and it'll just write a bunch of tests for you.
27:51 >> But if you scroll down, >> yeah, >> uh to that error to the error diagram. The hardest part is making sure that you somehow do it earlier rather than later. >> But the tradeoff that I often run with this is if I do it earlier, then I'm wasting time. And if it could have oneshot it, I feel like I'm I I'm like I should have just one shot. >> Dude, it's it's so fast. So, I'm actually going to live demo something.
28:14 Um there's a new TypeScript SDK interface that is like a different way of sending and continuing messages. This is straight from their docs um that I just this is like pretty new. I just noticed this for the first time last night, but they have this new API for sending messages with this unstable thing. And I want to go try this in my product. And so what I'm going to do is I'm going to pop open Claude in this air that works repo. Actually, we'll do it in the episode. Uh like read the v2 docs and the existing learning tests and create a learning test that demonstrates how to use the new stream send API uh and document its behavior in various circumstances.
28:54 And so literally I just say this to Claude and Claude is going to read as long as you have a couple of these for it to read for examples and we'll push these up so you can use the I mean these are for the Claude agent SDK but I also have one for like how does the node child pro process API work because I think that's an interesting one. Um there was an HMAC verification one of like how does the node crypto library work when like the lengths don't match and stuff like this. Um, but you basically log out some stuff and then you have assertions about like how this thing behaves so that if it changes, you'll know. Um, but yeah, so what this is going to do is literally going to go read these V2 docs and generate for me a learning test and it's probably going to make a learning test where the some of the initial assumptions are wrong. Like here's another one that we had a while ago where it's like we think that allowed tools is a white list and this is the only tools that are allowed.
29:43 Um, and then when we run it, we actually see that like uh we actually are going to see that like this assertion fails. But what's nice is like Claude is giving this. We talked about in the Ralph Wigum episode. We talked about back pressure and I think it's in the I think it's actually there's a picture in the notes. Actually, this is an interesting one too. This is a post about like basically like um if you use human feedback for the whole thing um then like basically you can like get feedback from the compiler uh based on your task complexity and you can solve parts of it and then you can get feedback from the type system and then you can get feedback from like MCP servers or playright or unit tests and then you could get feedback from basically like you're reducing the amount of time you the human have to spend.
30:31 >> Oh yeah. Exactly. Yeah. Exactly. Yes. >> Yeah. So it's like how do you how do you automate different parts of the back pressure and then it's like how do you do it during the planning instead of during implementation basically >> but I think the hardest part still and I think this is probably still what distinguishes like the goats of software engineering from like the not as goats which is just like you just have really good intuition for what to apply when >> because if you apply everything everywhere you will just be the slowest engineer in the world >> that's what that's the hardest part right because like >> yeah the and the only way you learn that is through reps you learn Okay, I did too much. Like I I think of this there's this idea in like I think it was in like a a blog post about maybe like about executive coaching or something, but like let's say there's some like spectrum of behavior and like this could be like too much planning and this is like not enough planning. But this could just as easily be like too extroverted, too introverted. This is like true for anything that you want to learn as an engineer.
31:30 >> Exactly. It just vibes. Um, so the idea is like let's say let's say you're over here, right? And then you try to get better and you end up over here and you end you try to get better and you end up over here and like the ideal range is somewhere in here. Um, >> I don't know if there's >> whatever it is. >> Huh. >> I I don't know if there's an absolute range. I think it's very problem problem and scenario specific.
31:55 >> Sure. Uh, let's say this is relative ideal range relative to the problem. like how good are you at picking the right amount of planning to do based on a problem. >> Yeah. >> And the idea is like basically if you do this you it's it's it's like you rather than just like trying to make incremental progress, you'll get there way faster if you what we call like make the other mistake. So like go way far to the other side and then come way back way back over here and you basically like binary searching around. And so the the idea is like sometimes you should do what feels like too much and sometimes you should do what feels like way not enough and you'll bounce back and forth and you'll get to the ideal range a lot faster than just trying to increment toward whatever you want to be. And this is true of lots of things in life. It's about developing instinct, right?
32:36 >> Yeah. Exactly. And I think like most people honestly that's why >> there >> well to be honest though I think that's why most people suck at a AI coding. >> It's because like most people like don't it's not that they're over here. It's actually it's it's because they don't know how to select for the right slides for the right problem. >> Like they they they're they're too constant with their technique. >> The thing about agentic systems is you actually have to be really variatic with the way that you code. This problem I use this technique. This problem I use this technique. Whereas in software when you're human typing you can almost always be using the same technique and it doesn't hurt your productivity. But with agentic coding, you have to constantly evaluate and be like, "Oh, well, okay, well, would I be actually be faster if I threw away all my work and started from zero again because this assumption is wrong?"
33:24 >> Yep. >> And very very few >> depending on the problem or even like the day of the week, this range shifts around based on >> exactly >> like what what models, new models, new problems, new types of things. And so you're like you're not just developing one set of instincts. You're developing a set of instincts that are kind of like spread across many dimensions. It's not it's not actually two dimensional. It's like a 10 dimensional space.
33:50 >> This is why I think most people suck though because it's like given a given a problem space, you got to pick your thing. And and what you do in that scenario when most people suck is you actually give guidelines. You say, "Hey, for 80% of people, we should always do the same process in this workflow." That's why processes exist because when you when you give a specific process, you're much much happier and you end up in the good zone way better way more likely than if you're exploring yourself and exploration isn't your skill set. So like for people that are like managing people, my advice to them is like really and if your team is really not getting the gro of AI, >> that's probably because they don't have the brain cycles because they're so they're so stressed about finishing the workload. They're being asked to do their jobs and also learn a completely new thing.
34:37 >> It's too much. It's too much. And like, let's be real, jobs are jobs. And like, I get why people feel that way. I love my job and I understand why some people don't want to like learn with like 120% cognitive load every single day of the week until they're max performance. Again, on the other hand, like with the back pressure thing that you talked about, like that's another technique that gives you like if it's if you're one of those people that is down to learn and I suspect most people attending here are.
35:02 >> If you go back to that diagram, >> that's that the previous diagram in the whiteboard. >> Yeah, this one >> that that technique that you described is a thing that pulls you more into too much planning. And that's fine, especially when you identify it's like, hey, this is a type of problem that needs more planning. And if I do this planning up front, I'll actually move faster long term. >> Yeah. And so I I encourage people to like if something feels like too small, like skip all the planning and just see if you can vibe it out. And if it works, then like now you've developed instinct of like, okay, for a problem that looks like this, I can just vibe it. And then for another one, it's like, cool, try to vibe it again. And you're like, okay, that was a disaster and I wasted two hours shouting at Claude. I guess next time I see a problem that looks like that, I should probably like do a little more planning, do a little more research, and make sure we follow the pattern. Yeah, I think this is that that instinct though is fundamentally the >> the what I call like the the difference between goats and non-goats is they just the goats just have a way better instinct and then they what that also means is that they're exploring techniques like the one that you're talking about all the time.
36:04 >> Yeah. >> Like they're just >> This is Jeff Huntley picture by the way is basically like you have to generate back pressure. you have to generate this loop of like you have your specs and then you and then you go and build it, you test it and then you update the specs as as you go. Um, and I actually want to jump in. I know we're getting tight on time, so I want to see kind of what I asked it to read the docs and write a test and it looks like it wrote this test. What I'm curious is if it ran the tests and then saw things failed.
36:29 Um, >> it did run the test and all seven tests passed on the first GP because it obviously probably read the docs and the docs were pretty good. Well, so it wrote this and it actually wrote like key findings at the top about the behavior. Um, and then it ran them and it saw the output and then it updated the findings that explained how things work. >> Oh, did you see? Okay, they all they all passed but it's looking at the output and it came in here and it actually updated the >> um Yeah. So, so yeah, I was saying like unstable it's a different one. Event stream shape matches v1 system init assistant result success. Um, but it throws before the first stream. Uh, yeah. So, it found some things about how the errors behave. So, it did it basically like wrote the test, ran the code, and then updated its findings.
37:15 >> That's cool. And now >> say like cool, I have the docs. Sorry. Go ahead. >> This basically becomes like a really shortcut for research. Like now for research where you don't own the code and you can't get it. You can do something like this. You can just be like, "Cool, here's how I think it works or here's how you think it works. Go prove it." And then we won't proceed to implementation or planning or anything until we've verified that this thing behaves for the parts of it that we care about, the surface area that we care about. We're not going to proceed to implementation until we verify that it works the way we think it does.
37:46 >> Exactly. >> Uh Josh's got a question. How do you define back pressure? >> So back pressure is exactly this is you give the model a way to fix its own mistakes. So whether it's unit test like whether you have a hundred unit tests and then the model makes changes and then it runs the test and it's like oh I broke something over there. You basically want to like >> reduce >> it's it's a feedback loop for the AI. So it's like rather than you having to check and read every line of code or click around a web app. It's like cool if the compiler can find errors and tell the model then the model can fix it before you even look at it. It's going to sit there and run the test and it'll enter over and over again until the compiler passes and then you just check everything else. And then if you can give it a type system, then it can run the compiler and then it can run the type check. I probably would run the type checks first for most things. Uh but then it's like cool, I don't have to check that the types are wrong. The model can get feedback that it's done something wrong without you having to spend time doing it. And so the more layers of automated ways that the model can run a CLI and get feedback or run an MCP and look at it in a browser and take a screenshot and look at how it looks, the the less you have to be in the loop and the more you can have confidence that you're only reviewing the most important things.
38:58 >> Exactly. >> Good question. Um, so Vibb demoed a diagram that the BAML team uses. It's an it's an example of back pressure. And actually there was another thing I was going to talk about which I don't think we'll have time for, but is like how do you optimize for human back pressure? Um because there's another thing we do and maybe this will be its own episode but like one of the hard things for like planning with a AI is like front end like AI is not good at like I mean it can make good front end but you have to like vibe back and forth with it.
39:26 >> This is uh for context for everyone asking like this is a diagram we talked about and like what we do is we basically have a dependency matrix of every single part of our codebase that's gets autogenerated from the codebase uh that shows us exactly what's happening. Yeah. >> So then we can find bugs really really easily. And like it's not just for humans. >> This is this is human back pressure, but you don't have to read the code to see that a boundary was broken. You're creating a very a way that takes the load off of the human in terms of trying to figure out if the model has broken any of our kind of expectations or rules about how these systems should fit together.
39:58 >> Exactly. Like for example, the bridge CFFI takes a dependency on compiler emit and that is bad. It should not do that. Green arrow should not come into this arrow. So that's a bad dependency and we need to fix that. Uh and like we flagged that >> someone made some code and then you generated this diagram and then you looked at it. >> Yeah. And we're just like >> that's gonna help you prompt the model on like how to do this.
40:19 >> Well, actually I'm what I'm really going to do is that uh I'm going to add a restriction here into this file that says >> hey bridge CFFI cannot import from like it will ban imports from uh this. So like for example I have where is this um anyhow u I'll just tell cloud I'm basically gonna tell cloud code >> and this is really someone asked like have you guys experimented with LLM as judge for back pressure and I think it's like this is a really important nuance here is LLM as judge is useful in certain cases but I think it's often overapplied um where you have like the the the builder and the manager and they talk to each other and the manager gives feedback. It's like they're both using the same freaking model. Like, yeah, maybe they're using different prompts and stuff, but you could just put the instructions from the manager into the builder prompt. The idea with real good back pressure is it's deterministic.
41:16 >> Like a model can read code and say, "Hey, like this is good." You're like, "Hey, is this code great?" And the model will read the code and be like, "Yep, it's good. It's comprehensive. Got unit tests." You can ask the same model, same system prompt, but you ask like, "Hey, what's wrong with this code?" And it will go find 10 things that are wrong with the code. And so like you can accidentally steer a model, you cannot accidentally steer a type checker. And so if you can give the model access to a tool that draws deterministic like there's no opinions, there's no non-determinism in it. It's either right or wrong and then give the model the feedback about why. It gives the model a way to check its own work without having to rely on its decisionm which is like we all know models make bad decisions sometimes. They ship slop code. They do things wrong. And just like humans, by the way, it's not just a model problem.
42:02 It's a code problem. Code >> this way. Humans created this for humans. We wanted back pressure. >> Exactly. Like if you're writing code, you will sometimes make incorrect assumptions. Like in this case, like cloud code wrote the file and just allowed bridge CF5 to import from BAML compiler. It should not. This should be a this should be this should be >> Oh, the model changed the stoml. >> Exactly. And like this is >> put in a hook that makes it so that it can't edit that file. Uh sometimes it needs to. So it's not as tricky as that.
42:29 >> Really I should have done what we should have done is we should have a code review process that requires us to code review this file specifically. >> Yep. >> Right. And that that was how we actually solve this problem like or we put like a or we put a rule in like our AI coding checkers and our PR that say hey if this file changes like these are the this file should not really change unless it really really really really has to. But most things are probably bad changes.
42:55 Yep. This is this is the high leverage thing, right? It's like you don't generally want to automate the checking of this file. You don't generally want to automate the the review of this file because if something here is incorrect, you have now opened the floodgates for hundreds and hundreds of errors to leak or like incorrect decisions to leak. >> Exactly. So then what we do instead is we have this file. This is small. We look at this image. We we find this assumption. Well, and then we also realize the file is wrong. And literally what I would tell >> accounting, right? It's like you review the file, but if you might have missed this thing. I mean, I just saw you. You spent five minutes trying to find where this issue was, or a couple minutes trying to find where this issue was.
43:32 >> But you also make it visual. So, you're checking it in two different ways. >> So, like what I would really do here is I literally I'm just going to go tell cursor to just say remove this >> and that's like how I'm going to go do this. And it will figure out whatever it needs to do to make the dependencies not be true here. >> Cool. >> And then this will just work. >> RM wants to know how you're creating the architecture diagrams automatically. Um there's a tool in our codebase called cargo sto that we built that does this.
43:58 Uh and like this is another thing about these things like Dexter for example just did this back pressure episode where he built that tool to test the cloud code CLI. His team invested time to write unit test and a unit testing framework like the pretty renderer for example for cloud code. So he can just easily see that the model doesn't have to see the JSON. It sees like a prettyified response. our team spent time that says look at our codebase and produce that diagram. So you can use our cargo sto in our repo you can just like um get it or like you can just copy and paste it run your own stuff but invest time in tooling.
44:31 >> Another question from Verun are there certain steps we can add in agents MD for back pressure um yes you can always prompt the model well you can prompt the model and tell it how to run the things um but again you want the back pressure to be somewhat deterministic. So it's like if you directly tell the model, hey, when you're done, run the type check and here's how to run it. Great. If you tell it, hey, when you're done, run the type check, and your agents MD has here's how to run the type check for each package, great. Uh the even more deterministic thing you could do is just have a global like stop hook where it's like whenever the agent thinks it's done talking, you deterministically run the checks and if any of them fail, then you inject that gets injected back into the model's context window of like, hey, this hook failed with this error or warning. Um, so lots of different ways to approach this >> or a pre-commit hook. A shout out to PRE. If you don't use PR, PRE is awesome, but a pre-commit hook, PRK for those that don't know, but um, a pre-commit hook is like another way to add like deterministic back pressure.
45:30 The back pressure mechanism doesn't have to be binary. It just needs to be observable. That's the key. >> The model has to be able to get tokens in to tell it what was wrong. >> Exactly. And sometimes that's a CLI command. Sometimes that's standard output. it really varies uh based on what you're trying to do. >> So if you look at some of the part of the reason why like the RPI plans are structured the way they are is because we want to make sure that the model is instructed exactly what to run for its automated back pressure and then maybe there's also some manual back pressure.
45:59 One of the things I often steer the model to do when I'm re reviewing these plan this one's already been executed. You can see the boxes are checked, but I'll read the manual verification steps and I'll say like this is a UI thing, but like I'll sometimes see it's like, okay, cool. Then manually like run a curl command against the running service. It's like no, make that an figure out a way to run a test like write a test file that spins up the service on its own port in its own directory and then hit it with a web request because that can be automated.
46:25 And so like you're in this constant battle of like how do we help the model give itself back pressure? And again, I've said this before, the best AI engineers I know and people even like back in like May or June when Cloud Code first was starting to come out and become really popular, the people that I was most impressed by were the people who would spend 3 days designing the back pressure system. Not even writing the code, not building anything, just understanding like okay, for the problem I'm looking to solve, uh how will the model be able to check its own work? and like enumerating out the different test cases in plain text like not design not writing the code but designing the s the harness and they wouldn't even really talk about the implementation of the system they would say here are the checks we'll run to make sure it's working and they would feed that to opus run it in a loop for two days and they would get back out like 20,000 lines of working code because they had designed the back pressure mechanism so they didn't have to be in the loop >> we got one more question which is I'm not a big fan of albums as judge and like or on the LM judge. I'm not super interested in various levels of role prompting. Don't think that works. But something on like a gvel. Well, I think the only place where that works if you're doing LMS as judge is um if you're actually simulating the exact conversation in the way that you send it out to the model in your main loop.
47:44 >> But if you're not sending out if you're not using RO prompts in your main loop, don't use ROS just to be like, hey, LMS judge, do this thing. I do think the user token does have a strong bias compared to a system token in the model. So like treat treating those as different is useful. A system and user also seems to have a slight bias but not a not as strong as I think system and user system and user seems to be like super super to trained for right now because of like prompt injection threats that people are worried about and what the big big models are worried about.
48:16 Um, so yes, you can you can do a reviewer agent to like and we do this in our PR flow of like go review the plan and what was implemented and like highlight the deviations. It's almost always finding like oh here's a thing I added in between two phases to because I decided I wanted it and that's kind of the idea of the plans are a little flexible but you do want to document that stuff and so like yes you can have an agent kind of review the implementation and make sure all the things in the plan were done according to spec. The key thing to note there is again if you remember that diagram that I showed earlier of like too much planning too little planning like you're just making trade-offs on speed and like what you speed versus accuracy is like fundamentally that's always the trade-off that you're making and like I don't think there's a perfect I personally don't think there's a perfect answer there between like >> do you do you always do the perfect planning or do you always do like oneshot and anyone I think that tells you that they're oneshotting everything is lying or producing totally garbage code. there's just no way. or they're doing or they're doing totally uninteresting things like they're not writing any piece of software that is interesting because fundamentally if you're doing interesting things they are hard and that probably means you made some design decisions that are incorrect at some point and if you're not make if you're always making correct design decisions you're either a goat and we have a couple of those in the form of Linux uh creators git creators people that that have made things like um Typescript and C like Anders is a few of them. There are a few goats in the world, but most people are not goats and like and like you should just keep trying and like keep assuming you'll make mistakes and keep exploring different ideas.
49:51 >> For most of those people weren't born goats. They did it because they gr they were grinding for years to develop the instincts. >> Yeah. So like and the best part now is you have to spend zero time waiting for the code to be written. You literally just say I'm going to try this idea and do it away. Sometimes what I do is I'll implement something. I'll literally have two repos open at the same time and I'll be working on implementing the same thing in like two different strategies in one approach and like planning in the other and I will just go do that and like through the process of doing that I'm literally exploring both state spaces of bugs really fast >> and that is like super interesting. No, I mean people love codeex 5.3. It's like it's slow, but it's like I'll kick off a like opus based like planning design structure session. In the meantime, I'll be like codeex 5.3 go try to solve this like just based on the ticket. And like >> it's all about learning the solution space and like what's what's possible and like that changes every month.
50:48 And so like if you're not put I don't know, Uncle Bob used to have this thing of like what it means to be like a truly like professional software engineer. I don't know if I like that word, but his basic recipe was like if you're working a 9 to5, you give 45 hours a week to your employer and you spend 20 hours a week for you >> honing your craft, improving your skills. >> I agree. >> Um doctors and lawyers don't like clock off and then go home and watch t like they're reading journals, they're reading papers. It's all part of their profession is like there is an extra 20 hours a week where you're spending keeping up with what's important, what works, what new things are happening.
51:24 >> Well, yeah. if you if you want to grow in the domain and like there's no harm if you don't like to be fair like trade-off in life but like if you want to if you want to hone the craft you got to put those hours >> I assume you're here because you want to hone your craft >> that's true assumption >> we are talking to a special kind of a group of folks >> but regardless this was really fun to share thank you for sharing I love how you put a coin to term to stuff that I hope people are doing today and like maybe not doing more actively consciously next time they do it they can hopefully telling a model or a coding agency, do this more deliberately.
51:58 >> Yes. Do it deliberately. Steer the models to the things you want. You can do anything. They can do anything. Find the things that they're really freaking good at that's high leverage. And uh yeah, happy h happy hacking, folks. Enjoy. >> Next week, we're going to talk about how we actually run a lot of the AI behind the show, such as like uh all the content generation, some of the uh like clip selections, the highlight reel selection, the email generation, how we get tone perfectly right. We've got a fun little automation workshop that I think will be fun. And we'll have Kevin joining us, uh, who's been doing a lot of the stuff for us behind scenes.
52:31 >> Legendary producer Kevin, uh, has been doing incredible things behind the scenes. I'm really excited to see how some of it works. >> All right, goodbye everyone. >> Thanks, everybody.
Summary
- Learning tests help validate assumptions before proceeding with implementation, reducing the risk of significant rework.
- The podcast highlights the shift from traditional debugging methods to print debugging as a more intuitive learning tool.
- The hosts discuss the challenges of working with external APIs and the necessity of creating tests to understand their behavior.
- They emphasize the importance of back pressure in coding, allowing models to self-correct based on feedback from tests.
- The conversation touches on the balance between planning and implementation, advocating for a flexible approach to coding that adapts to the problem at hand.
- The hosts share practical examples of how they implement learning tests in their workflows, including using AI to generate tests based on documentation.
- They advocate for investing time in creating tools and frameworks that facilitate testing and validation of code behavior.
- The discussion concludes with a focus on continuous learning and adaptation in software engineering to improve instincts and decision-making.