Beyond RAG: Build a Relational Context Engine from Scratch — Peter Werry, Unblocked
AI Engineer · 38 min · 403 sentences · from YouTube's caption track
Each timecode opens YouTube at the start of that sentence. Line anchors (#s42) are the cue ids in the WebVTT, and every line carries its start and end seconds. All transcripts has every talk, and the whole corpus as one file.
- 00:12Okay.
- 00:13So, I'm I'm Peter.
- 00:14I'm from Unblocked.
- 00:15Um, over here is my colleague Brandon.
- 00:18And today, uh, well, first of all, I just want to talk a little bit about what we do.
- 00:22So, uh, we build a context engine.
- 00:25Our company's name is Unblocked.
- 00:27And uh we deliver organizational context to humans and increasingly of course agents.
- 00:33Um so the session was originally a couple hours.
- 00:35It's it's now one hour so it's quite condensed.
- 00:38U which means that I'm going to step through the workshop pretty quickly.
- 00:42If you don't get uh you know all the steps nailed down as we go don't worry about it because the repos up online um and you can run through it at your leisure um afterwards.
- 00:53Um, so the thesis here is that rag and I'm just going to say that rag in our parlance today is going to be semantic similarity search or vector retrieval.
- 01:04Okay, rag is only half of retrieval and today we're going to build the other half which is turning na natural language into real database queries.
- 01:14So here's the again the QR code for setup um if people haven't already done so.
- 01:19I'm gonna now skip um on to the next thing and I'm just going to briefly bring up hopefully that renders.
- 01:25No, it won't.
- 01:26Of course.
- 01:27Give me one second to switch.
- 01:32Whoops.
- 01:37And hopefully people can see this.
- 01:39Uh this is the repo here.
- 01:40So setup steps are pretty simple.
- 01:42Um there are a few sort of uh dependencies up here, prerexs that that uh you'll need to run through.
- 01:50Um and the the course throughout the course of the workshop, we're going to be running through a series of pull requests uh and the network is basically gone or at least isn't running properly.
- 02:05Let's try this one instead.
- 02:16Well, the good thing is we don't need network for this talk.
- 02:19Um, so hopefully you got everything before we started.
- 02:23Um, because this one's obviously not going to work.
- 02:26But at any rate, uh, we're going to be following a series of six pull requests and they stack on top of each other.
- 02:32So, I'll be There we go.
- 02:34I'll be referencing these as we go.
- 02:36Um, and I'll just go back to here so that everyone can see that.
- 02:41And back to the keynote.
- 02:43Now I'm gonna have to extend it again.
- 02:47Sorry.
- 02:58There we go.
- 03:01All right.
- 03:02Hopefully people can see that.
- 03:03Great.
- 03:04So um our agents need context and context is scattered across every tool that engineering teams live in.
- 03:12So you're going to find it in PRs, review comments, um issues and tickets like in linear and jura docs [clears throat] and wikis, notion confluence, and of course in conversations and places like Slack and Teams.
- 03:26And all of that is semantically queryable, but it's it also has structure.
- 03:30It has authors, dates, uh, states, labels, relationships, etc. And you know, the the instinct I I love to say this like even two years ago is ancient history in the realm of AI, but the instinct even two years ago was let's just dump this all in a vector store and retrieve it and rerank it and hopefully we
- 03:50get the right thing.
- 03:52Um, but that's that's not going to work.
- 03:54So I'm just going to step back and and kind of relate this to the larger discussion about context.
- 03:59um in in the context of a context engine that serves organizational context um this is this is made up of more than just code as I said we're connecting everything together
- 04:11so the scattered context uh on the left in all your code and PRs docs etc goes in and the idea is to get you know grounded context that relates to each other out the other side that's specifically tailored to the task at hand
- 04:26um and in that model uh we have to care not just about the semantic relationships, but of course the structural relationships that connect all the data.
- 04:35So again, rag is about embedding the query, finding docs with similar meaning, and then we take that stuff and we stuff it into the prompt, right?
- 04:43Well, um, that shines for content questions like find the code, find the PR that changed it, find the Slack thread that debated it, but um, and if you wrap it in an agent loop, you can get pretty far with that.
- 04:59And you can also wire this thing up to like um, you know, tools that can recurse files and it acts as a good jump off point.
- 05:06you get a good semantic head start and then from there your agent can recurse over the actual file system in GitHub um and you can get pretty far with that.
- 05:17But in our experience um our this is not really the way things go in practice.
- 05:22engineers often ask questions like this PRs that I merged last week or my team merged last week.
- 05:29Um they're they're basically, you know, hunting for something in particular and they know where the starting point is, but they don't know where the destination is, but they do know the relationships.
- 05:42So, as an example, PRs I merged last week, let's think about this in a rag context.
- 05:46you'd you'd you know embed that sentence, you'd find the nearest vectors, you'd rerank it top K. Uh you get PRs that mention merging about a talk last week, but
- 05:58uh you wouldn't get the actual relationships like the author, the merge state, um and whether it was merged last week actually.
- 06:08So what you could end up with is the wrong answer where you pull up PR that's semantically related but it was merged three years ago.
- 06:17Um and so that doesn't actually answer the question because there's a structural there's a temporal aspect to that question.
- 06:24And so retrieval has two halves here semantic and again today we're going to be talking about this structured queries.
- 06:34And here's the key.
- 06:35We're going to take uh the model doesn't actually answer the question in this paradigm.
- 06:38It writes the query that accesses the database.
- 06:45Okay.
- 06:46So, um it would be naive to say that generating the query is the only thing that we have to do.
- 06:52Um in order to generate the query and to do it reliably um and and to take care of maybe even some security concerns, we need to look at all four of these points here.
- 07:04So that first of all the LM needs to be aware of what the schema is before uh creating the query.
- 07:10It needs to understand uh some of the relationships in the data.
- 07:13So for example, if you pass a natural language query that says show me Peter's open PRs, um then it's not going to know what to do because it'll synthesize a query that says Peter when really the GitHub login name might be different.
- 07:28So it needs to be able to map that across.
- 07:30Um, and of course you're going to have some uh untrusted queries coming out the other end.
- 07:36Um, maybe using the function operator in the in parlance which might execute JavaScript directly on the server and we probably don't want that.
- 07:45Um, and then finally, if there are errors the first time around, we want to be able to self-correct those things.
- 07:52So here's here's what this looks like in one single shot.
- 07:56What we want is something that looks like this.
- 07:58Um it it maps uh my colleagueu's name is Rashine.
- 08:02His user login name is is Rashab.
- 08:05Um and then we want to be able to map things like the state and get maybe uh operators like limit and sort.
- 08:16So uh this is what we're going to build.
- 08:18We're going to start with a full UX, a stubbed engine, um, that is not capable to start with, and we're going to gradually build this up.
- 08:28And then at step three, the thing will come alive.
- 08:31And so we'll actually be able to issue queries to it and see what it does.
- 08:36And uh, if you hadn't seen that before, now is another good time to scan that and get it in.
- 08:46I'm here to help you.
- 09:00Yeah.
- 09:03Yes.
- 09:03Any repo is fine.
- 09:04Doesn't matter which one.
- 09:07Um and if if you want to take a shortcut, you can just point an agent at the thing and let it set everything up for you.
- 09:13That works.
- 09:16Okay, let's move.
- 09:19So, this is what we're going to do to start with.
- 09:21Um, by now you you probably should have run this ingestion thing.
- 09:25Don't worry if you haven't.
- 09:26Um, again, like you can revisit this at the end.
- 09:29I'm just going to quickly show what the the kind of barebones interface looks like for this thing.
- 09:36So, now this thing is running.
- 09:37Now, if I type anything in here, this is obviously not going to work.
- 09:41Um, and what you should see is something like that.
- 09:43Um, there's also a tab for chat.
- 09:46This is a fully implemented agent uh that can uh do work for you.
- 09:51So, we'll come back to that in a sec.
- 09:58And so, this this is the contract in the code if you wanted to read.
- 10:01Um, we're going to don't worry about this.
- 10:03We're going to skip through this.
- 10:05Um, but basically like that's the entry point and we're going to be building around that.
- 10:10So the first thing we want to talk about is schema discovery.
- 10:14Um during ingestion, if you if you look at the way that the ingestion script worked, it it actually had to build out a schema in order to download the content and store it.
- 10:24Um but you can imagine that you may not know the schema.
- 10:27So the ingestion may be happening in a service elsewhere and you want to build like a fully dynamic schema discovery engine.
- 10:34Um schemalis.
- 10:36So there's no schema to read.
- 10:38um unlike you know PG or something where we could read the table definitions.
- 10:42Um so what we'll do is we'll sample the documents to infer the schema and that's the whole trick.
- 10:52So the we're just going to reconstruct it.
- 10:54We're going to take um all the nodes and merge them down.
- 10:58So this is going to sample 300 documents, collapse it into a single tree.
- 11:03uh nulls are skipped because missing fields won't be able to constrain the type.
- 11:08And then uh we're going to do something kind of interesting here with enum types.
- 11:17And so now uh with with enum types, we can do an interesting sort of procedural trick.
- 11:23This is just one thing.
- 11:25I would suggest using procedural tricks to to do this type of thing because you could pass it through an LLM and do extraction and that works u but it's fairly non-deterministic.
- 11:36So you always need some kind of structural um harness around it that is running procedural code to either validate the things that you pull out or to actually do the extraction itself.
- 11:48And in this sample project um it's the procedural code that's doing the extraction.
- 11:55And let's go and show that.
- 12:00So we'll do and then run it again.
- 12:09And now what we get is this thing here.
- 12:12So the schema ran uh the the discovery process ran and it created a schema for us that outlines what the pull request schema looks like in GitHub.
- 12:22It even created some indexes for us.
- 12:25Now, this is like marked down on purpose because we're going to take this schema and pass it to the LLM when we synthesize the actual uh query.
- 12:40Now, the second step is the thing that I referred to a few slides ago about identity resolution.
- 12:45And this is because like my lo GitHub login um is similar but it's not quite the same.
- 12:51And so if I were to ask a question like um hey find all the PRs by Peter um it if without doing some sort of identity mapping it would just say
- 13:03you know it would just match across Peter and it's not going to find anything.
- 13:07So we have to be able to solve that.
- 13:09[snorts]
- 13:11And again, um, we're going to do this.
- 13:14At first blush, this seems like we're coupling to the schema a little bit here.
- 13:19Um, but you know, it is absolutely possible to determine this dynamically.
- 13:24And you can have uh your LLM essentially synthesize the mappings for you.
- 13:32So, but in in our case, we're just going to do these simple little tricks.
- 13:35Um very simple sort of fuzzy matching.
- 13:38Um Levenstein distance is fine.
- 13:40You can just like match across the names and uh there you go.
- 13:50Oh, actually I want to show you one thing before we get on to that one.
- 13:54So let's do the same thing again.
- 13:57We can pop up
- 14:01Oh yeah, I'm sorry.
- 14:03Absolutely.
- 14:05Tell me when it's big.
- 14:07Good.
- 14:08Thanks.
- 14:08Good call out.
- 14:11Okay.
- 14:12So, let's run our thing again.
- 14:15And now, um Oh, actually, I have to I have to wait till the next step.
- 14:20I apologize.
- 14:21That's not going to be wired up just yet.
- 14:24So, we'll go on to the thing that will really give us the payoff here, which is step three.
- 14:36So this is the actual query plan step and it's it's it's arguably sort of the simplest part.
- 14:42It's the LM part.
- 14:44Um and what we do here is we pass the schema give it a tool and force it to call that tool for name extraction and synthesis.
- 14:54Um and then it will execute the plan.
- 14:56There's one other thing which is the temporal aspect.
- 15:00uh LLMs are actually pretty good about generating temporal queries if you pass them the current date and time.
- 15:08So that's another important thing to do in the in the prompt.
- 15:18And so here this is the name extraction part.
- 15:21We're going to force that tool call to happen in this case.
- 15:28And at this point I am going to show you the the payoff for this.
- 15:33So there we go.
- 15:47So now I can do things like this.
- 15:52open PRS by Peter and bam.
- 15:59So what we'll see here is that it uh generated this um this match clause and uh you can't see it from here but it it mapped Peter to my GitHub user login puery
- 16:13and generated the query and that's the outcome.
- 16:22So that's cool, but um we need to get on to the next step because even though we are able now to query the data, we have some safety concerns.
- 16:31Um it could be the case that it produces untrusted output and so you know it could use the wear or function clauses and literally run JavaScript on the server which means that this is now a prompt injection point.
- 16:48Um, you could also have hidden fields in your schema like ID or metadata fields that leak internals.
- 16:56So, we need to sanitize um, and we don't deny list these things.
- 17:01We allow list them.
- 17:03So, it's deny by default.
- 17:05You want to create basically an allow list of allowed operators and uh, you know, potentially an allow list of allowed fields.
- 17:12In our case, this is dynamic schema discovery, so we're not going to do that.
- 17:16Um, but we could have some fields that we know about like metadata fields.
- 17:21And this is a a useful thing for like tenant uh tenant isolation.
- 17:27So if you have a a uh collection that houses multiple tenants, I don't recommend that.
- 17:32you should probably separate your collections by tenant, but if you did, then you could have a metadata field that contains the tenant ID and you would want to hide that
- 17:43no that um information from the LLM, but also validate the output.
- 17:49So if it outputs that metadata field, you need to wipe it out and then you need to inject your own metadata field underneath.
- 18:05And again, like technically this is it's not actually that difficult to do.
- 18:08You just have to write the code.
- 18:10It's all procedural.
- 18:11Um I I wouldn't recommend using LLMs for this part.
- 18:19And so again, allow list, don't deny or deny everything, I should say.
- 18:33Now the last part is um we're going to this kind of dovetales into the next step.
- 18:38At the end of validation we're obviously going to return an error and it's going to get dumped out.
- 18:43And right now that error is just it's just there.
- 18:46We're not going to do anything with it just yet.
- 18:49But I will show you now what this looks like.
- 18:52Um, oops.
- 19:04Stay on that one and run our service.
- 19:10So now I'm going to write run another query that checks for authentication in the title and we've disallowed regular expressions.
- 19:20So now what we can see is that it rejects the query.
- 19:35And finally, this is the thing that kind of ties it all together is the retry loop.
- 19:47The plan can fail in a couple of different ways, right?
- 19:50Um, it can fail validation.
- 19:52So maybe the uh the LM actually outputs things that are illegal according to our validator.
- 19:59Or it could actually fail during execution.
- 20:02Um, so for example, let's imagine that it it mixed an inclusion exclusion project.
- 20:09Um, then that's obviously going to fail.
- 20:13And then but we can self-correct.
- 20:15We can take that error and pass it back into the LLM and say hey that was wrong.
- 20:20Um maybe you can do better up to some number of max attempts of course.
- 20:30So I'm going to show now what this looks like back over to our project so we can punch up a level.
- 20:41Whoops.
- 20:41Sorry.
- 20:45You have to forgive me.
- 20:46I actually have to read this off of the screen out here.
- 20:56Okay.
- 20:57So now if we run that same query.
- 21:09Perfect.
- 21:10So, what we can see is that it took several attempts to get it right.
- 21:14Um, by the third attempt though, there's a bit of a problem here because we said no regular expressions, no FTS.
- 21:22Um, so now it said we're going to just use match, but now it's an exact match.
- 21:29So it tries to find authentication fails which means there's one more thing that we can do which is this.
- 21:42We'll add full text search.
- 21:49It's pretty basic.
- 21:50Um we need to create an index obviously and we'll combine it with author and state filters uh in the same match.
- 21:59And so now we should be able to answer a question like this.
- 22:07And let's see what happens.
- 22:09And see if it is actually going to do what I said it's going to do.
- 22:29Bam.
- 22:30There we go.
- 22:36And so now the the final payoff here is if we go into the chat tab, we can ask some sophistic more sophisticated questions that um you know an agent can actually reason about behind the scenes.
- 22:48So you can say things like um did we work on anything authentication related last week.
- 23:10So here we can see that it generated the query.
- 23:14Now it's pulling the data and kind of reasoning about it.
- 23:18There we go.
- 23:22That's it.
- 23:35So, just a quick summary of what we built.
- 23:38We're basically like reaching the end.
- 23:41There's going to leave lots of time for questions.
- 23:44So just to recap here, um there are questions that that rag can't touch.
- 23:49All those structural questions around things like state or temporality.
- 23:54Um you don't get the right data out when you ask those types of questions with rag, traditional rag.
- 24:02So the same engine behind the query playground and the chat agent, uh they're they're the same.
- 24:06So if you guys want to play with that after, go ahead.
- 24:09Um it's it's the same backing thing.
- 24:11The only difference is of course that uh the chat agent actually does reasoning whereas the query interface is just for queries.
- 24:20So just to to recount on this here are the reusable ideas here.
- 24:25Schema aware prompting dynamic schema discovery identity resolution validation and error retries.
- 24:36The error loop is actually one of the most important things.
- 24:45And so we built something that's capable of filtering, providing aggregations, it's time scoped, has full text search.
- 24:55Um, it's validated, it self-corrects, and it powers a full-blown chat agent.
- 25:00So you could take this into your organization and just deploy.
- 25:03I I would recommend maybe working a little bit more on the validation harnesses before deploying this internally, but um yeah, it'll it'll answer all your questions about your PRs.
- 25:14And that's it.
- 25:16So, we've left lots of time for questions now.
- 25:18[laughter]
- 25:19Did Did everyone uh was everyone able to actually set it up?
- 25:22Just curious.
- 25:24No. Okay.
- 25:26If if you want uh you can come and fetch Brandon and I afterwards, we'll just kind of linger outside here.
- 25:33Oh, at the and at the P16 booth as well.
- 25:35Yeah, but that that starts later today at around four o'clock and we'll be there all week.
- 25:42Cool.
- 25:42Any questions?
- 25:44Yes,
- 25:45I have a question.
- 25:46I think you did a great job breaking down like basics.
- 25:49Yeah,
- 25:50a lot of my mind goes like okay so at scale how does for example you you generate the schema and you put it into the system prompt how does that work at scale?
- 25:58It's like also depending on the size of your company, how are you fitting all this data?
- 26:02How do you choose what data and like how long does it take to process all this?
- 26:06What's the cost?
- 26:07That's where my mind is.
- 26:08Yeah, it's a good question.
- 26:09So, you know, um I'm just going to repeat the question so everyone can can hear it.
- 26:13The demo showed obviously a fairly contrived example where you're just focusing on pull requests.
- 26:19Um and so the question is how do you scale this?
- 26:21Like how do you do this across multiple different collections, multiple different tables, etc. Um, so you you can add uh another LM step on top where uh this the schema collections have tiny little summaries and descriptions
- 26:36and then uh depending on what the query is, you can load the right schema for that query.
- 26:43LMS are surprisingly good at this.
- 26:44They weren't a year ago, but now they're very good at it.
- 26:47Um, so that's kind of the way to shave the context thing down.
- 26:51And that's to your question about scaling things out.
- 26:53Um, was there another aspect of scaling that you were interested in?
- 26:57Getting all the data in and I guess like part of that is like cost.
- 27:01Yeah, it's livveness and stuff too.
- 27:03How long does it take to do like what is what data should I pick to put into this?
- 27:08Yeah, it's it's a good question.
- 27:10So unblocked um at unblocked like we're continuously ingesting content.
- 27:14Uh we get web hook callbacks for all the events for example in in PRs.
- 27:19And so every time there's a change, we get that web hbook event, we ingest the content, we rem um and store it in the database.
- 27:27Um that that's just really just like a distributed systems question about how you scale that out from an ingestion level.
- 27:34Um you know, storage, same thing.
- 27:36So yeah,
- 27:38so maybe this will make it more concrete.
- 27:40So what if you would say like these are the top three data sources like someone seems like GitHub maybe like something
- 27:49um so Slack for sure a lot of the like why questions and and decision- making happens in Slack um people uh in the context of this sort of like structural query
- 28:01um people usually think about conversations that they've had in the past um and they'll be able to query unblocked and say Oh yeah, you know, roughly three weeks ago, I was having a conversation with so- and so.
- 28:14And so that that's a perfect thing for structural query.
- 28:17Um yeah, like I would say that um Slack is the most important for why questions.
- 28:23Um a lot of the why decision-m is also embedded in PRs.
- 28:28PRs uh have all of that like organizational history in the comments and that's just basically black hole, right?
- 28:36So uh you can basically run over that data before you serve it and and kind of mine it for interesting insights.
- 28:44So for example at unblocked we we create these things called best practice memories which are distilled from PR comments in the past.
- 28:53Does that make sense?
- 28:54Yeah.
- 28:54Yep.
- 28:55Any else?
- 28:56Yeah.
- 28:57Question.
- 29:02directly into how this building.
- 29:25[snorts]
- 29:26Yeah, I mean you you can definitely do that.
- 29:28So if you have a structured if you have a structured query table, you could express that through MCP.
- 29:34You can even do that dynamically by updating the tool every time the schema changes behind the scenes.
- 29:39Um this this type of thing is showing like what happens on the other end of that MCP call.
- 29:44So you you could you know have an MCP interface that just takes natural language queries for example and then translate that all on the back end or you could provide a direct interface to the database.
- 29:55It depends on like what the customer interface looks like, but yeah.
- 29:59Yeah.
- 30:02Yeah.
- 30:21Yep.
- 30:22Second part is better.
- 30:32Thoughts around
- 30:40uh how to mean how to combine it or let me just make sure I understand your last question.
- 30:50Yeah.
- 30:51feel like this is like
- 30:54No, not at all.
- 30:54No, no, they're absolutely complimentary.
- 30:56Yeah.
- 30:57Yeah.
- 30:57I mean, you can have a full text search that does this kind of um you know, like that's full text search, right?
- 31:04So, it'll identify keywords.
- 31:06You still need some kind of mechanism to to do like the actual semantic similarity search because there you all have ideas and sentences that are encoded that aren't not ne necessarily textual matches.
- 31:19So you want you want that like conceptual matching, right?
- 31:24So as I said um at the beginning like there's similarity search is actually really powerful for jump off points.
- 31:31So you can for example start with a vector search and then from there give it access to tools like this because then it'll actually have like some interesting starting data
- 31:43and help it form queries to go and and fetch the data.
- 31:46So yeah that that's that's something that we do and so sorry the first part of your question was
- 32:03so you take um you take you know in in anyways like these are all documents and they're they kind of like form into JSON so you can merge those things down and look for certain tokens
- 32:15and then you you know, extract the tokens and then that's how you distill the types.
- 32:20So you you can look through the source code and you'll see that at least like this iteration of that algorithm is pretty hacky, right?
- 32:26It'll do things like look to make sure that the character count is between two and eight for uh for type information and then for enumerations it's it's looking for particular patterns as well.
- 32:38Yeah.
- 32:54Yes.
- 33:05Now, that that's a very overloaded term, so I'll just make sure I understand exactly what you're talking about.
- 33:09Do you mean hybrid search in terms of um a provider that does semantic similarity and then also does a lexical search and then does rank fusion?
- 33:34Yeah.
- 33:35Oh, yeah.
- 33:35Yeah.
- 33:35No. So, so we we do that.
- 33:37Yes.
- 33:37The answer is yes.
- 33:38Yeah.
- 33:38Yeah.
- 33:53Uh just empiric empirical trial and error.
- 33:57And so I mean there's there's no easy solution to this.
- 34:01Um be behind the scenes like at unblocks we're we're using a lot of static schemas because we want to get the correctness absolutely nailed down.
- 34:09This this was like a just a technique that I wanted to show because um you know for exploration of data or experimental um uh for experiments or either to wire up like arbitrary
- 34:22databases this is a good technique.
- 34:24So we we got this through some trial and iteration with customers and you know we we'd ingest a whole bunch of contents from the document store and we'd get
- 34:36responses back from customers that said oh you missed the thing that I was searching for and we'd dig into it and we'd figure out why and we kind of got to the sample size that made the most sense.
- 34:56Yeah,
- 34:58it's absolutely true.
- 34:59Yeah, definitely.
- 35:01You're always actually gonna you're going to miss something.
- 35:03There's always going to be some document that has a little edgy thing.
- 35:06Yeah.
- 35:09Anyone else?
- 35:12I thought I saw a question over there.
- 35:13Oh, yep.
- 35:21Sorry, can you say that first part again?
- 35:22There's mention that you understand the schema.
- 35:30Uh yeah, what we do is we force a tool to be called for not for schema discovery because that happens at the start.
- 35:37It's for name extraction.
- 35:48we so we have a validator that watches what the agent's doing.
- 35:52So like if it doesn't call the the first part which is name extraction.
- 35:57Um so there's there's actually two techniques for this.
- 35:59One is you create a tool that does the the query and as an argument to the tool you accept a username.
- 36:06So you can fail right there if the username is not correct or malformed.
- 36:11Um, if you want to do name extraction uh via tool call, then you have to watch what the agent does.
- 36:20And then if it doesn't call it, you just basically insert a user message that says you forgot to call the extraction tool.
- 36:26Do so now.
- 36:28Yeah.
- 36:32Yeah.
- 36:40How do you handle the changes?
- 37:04Yeah.
- 37:05So remember like for this particular example the schema is is completely unknown and so as documents get added um that schema could update.
- 37:14So you your your choice is either you know on a sampling interval you you rerun the schema generation um in our case at unblock the schema is is static and it's tied to our codebase
- 37:26and we control the schema actually.
- 37:28So if the schema of if GitHub decides to change the schema um that of course rarely happens because that would have serious implications for their customers but if they did then we would just adopt whatever changes are made
- 37:41statically and then obviously deploy that through CI.
- 37:44Yeah.
- 37:50Anyone else?
- 37:55Awesome.
- 37:55I think we can uh reclaim some time in that case.
- 37:59Thanks.
- 38:00[applause]
- 38:16[music]