تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Switching to Vector Stores0:00

If your AI can only answer from hand-picked files, then it's nothing more than a demo. When it can answer from a file that a customer just uploaded, well, that's a product. In the previous episode, we talked about essentially self-managed embeddings. They are embeddings that we stored inside of our database. In this episode, we're going to switch that to provider-managed vector stores so that we can scale our search, and it's primarily for files. So, we are going to build a feature that allows users to upload and in-depth documents.

So, we are going to build a feature that allows users to upload and in-depth documents. Then they can ask questions about that document. And then we can also have a simple cleanup to remove files. So, instead of using our database and our cosign method that we wrote in the previous episode, we are going to pretty much hand the heavy lifting off to our provider. But that doesn't mean we won't need to store something in our database. So, we are going to make a model called uploaded document. The idea is that any document that we upload, we are also going to provide to

UploadedDocument Migration1:08

So, we are going to make a model called uploaded document. The idea is that any document that we upload, we are also going to provide to the provider, and we need to store some information about that document so that we can access it from the provider. So, let's start off with the create uploaded documents table migration. And I'm going to do something a little bit different in this episode, instead of typing all of this out, because a lot of it is just normal stuff. I'm just going to paste it in. Think of me as your less efficient AI.

I'm just going to paste it in. Think of me as your less efficient AI. So, our table called uploaded documents, we will have a foreign ID to the team, as well as the user. And we are going to store the file name, because obviously. But these two fields are very important, provider file ID and provider store ID . Essentially, we are storing the provider file ID so that we can find that file and delete it later. We are storing the provider store ID so that we can search the file again if we

and delete it later. We are storing the provider store ID so that we can search the file again if we need to. And then the metadata field is going to hold whatever filters that we need for strict scoping. So, when it comes to something like this, we always want to save the provider IDs, because the provider is the system of record. And we need those IDs to access the things that are stored by our provider. So, with that in place, we can just go ahead and migrate our database.

Creating the Model2:31

And we need those IDs to access the things that are stored by our provider. So, with that in place, we can just go ahead and migrate our database. But, of course, we need to go to the uploaded documents model. And once again, I'm just going to paste in that code, because once again, it's just plain, ordinary, Laravel stuff. So, we have our fillable array so that we can fill the model with our data. We are casting the metadata as an array. Then we have the relationships for team and user. Next, we need to use artisan to make an agent, because this agent is what is

Building the QA Agent3:02

Then we have the relationships for team and user. Next, we need to use artisan to make an agent, because this agent is what is going to, well, search our document. So, let's call this document QA assistant, and we don't need structured data or anything like that. Let's open up the document QA assistant file. And let's start with our attributes. So, first, we had the provider attribute, which once again, I'm going to use lab open AI.

So, first, we had the provider attribute, which once again, I'm going to use lab open AI. And let's do something a little bit different. We've been using the cheapest model. When it comes to something like this, we might want something that's a little smarter. So, let's use the smartest model. Of course, that's going to cost more. But whenever we are talking about indexing and searching documents, we want something

But whenever we are talking about indexing and searching documents, we want something that's a little bit smarter. And max tokens. Let's not be too conservative here. Let's say 1600, we might need more than that, but we're going to start there. And then this is going to be a tool, or at least we are going to provide tools here. So, we'll have the max steps, and I don't know, let's set that to three. Okay, so there's nothing new as far as these attributes are concerned.

So, we'll have the max steps, and I don't know, let's set that to three. Okay, so there's nothing new as far as these attributes are concerned. But, you know, this is going to be a tool that is going to work with our documents. So, therefore, it's going to need quite a few pieces of information. So, we will have our constructor, which is, first of all, going to need the team ID. So, we will have read only int team ID. We will need the user ID. Then we will also need the store ID. This is going to be a string called store

We will need the user ID. Then we will also need the store ID. This is going to be a string called store ID. Then we want public string. This will be the provider file. We will initialize that as null, or not initialize, but give it a default value of null. And that is going to be our constructor. So, that when it comes time for our instructions, well, this is going to be an assistant that works with support documentation, or any document that comes up.

assistant that works with support documentation, or any document that comes up. So, let's have our prompt, and we will end our prompt. And, first of all, we want to tell the agent that you are a support documentation assistant. And we want to constrain its answers. We don't want it to be, you know, going off on engines or anything like that. So, I will say only answer using the uploaded document available through the... We're going to create a tool called file search tool. Now, it's entirely possible that the user is going to ask a question that the

We're going to create a tool called file search tool. Now, it's entirely possible that the user is going to ask a question that the AI can't find an answer for. So, we'll say if the answer is not in the document or documents, say you do not know. And then, after the answer, include a short sources list with file names. That way, the user knows where our agent got the answers that I got, because I know I want that. And so, then we don't need messages, which also means we will need to get rid of the conversational

And so, then we don't need messages, which also means we will need to get rid of the conversational here, because all we need is agent and has tools. So, then we get to define our file search tool. So, we will return new file search. This is a class provided by the SDK. And we're going to pass in the store ID. Then we will have a callback function that accepts a file search query object, which we'll just call query. And the first thing that we want to do with this query is essentially scope it

which we'll just call query. And the first thing that we want to do with this query is essentially scope it to the current team and the user. So, we'll say where the team ID is this team ID, and also where the user ID is the user ID property. Next, we want to check the provider file, because if we have just one file that we are currently querying over, then we need to filter by the provider file ID with this provider file ID. And that's going to be that provider file undefined property.

provider file ID. And that's going to be that provider file undefined property. Oh, it's the lowercase ID there. Thank goodness for code editors that point that out, because it would take me forever to find that. It almost took me forever just to find it. And I knew that there was a problem there. Sorry. So, that's our agent. It's very simple and straightforward.

So, that's our agent. It's very simple and straightforward. We are using the file search tool to search our documents using the query. Now, the beautiful thing about this file search tool is that it essentially lets the model retrieve file chunks without running any kind of embeddings. So, this is going to allow that search to happen, which is great. And we don't have to write anything extra. I like it. So, we're done with our agent.

Controller for Upload/Q&A/Delete8:16

I like it. So, we're done with our agent. And now we need a controller. And this isn't just any controller. This will be a controller for uploading and all of that stuff. So, AI document QA controller. And this is one of those places where I'm going to be pasting some code. Because, you know, we are going to be doing some very normal things as far as Laravel is concerned. Like, for example, let me paste in the index method.

Laravel is concerned. Like, for example, let me paste in the index method. So, what do we do? We get the user. We are going to ensure that the user has team access. That's a method that we will define here in a few moments. Then we get our uploaded document where the team ID is, of course, our team ID. The user ID is the user ID. And then we are going to display that inside of our view. So, all we are doing is fetching the documents based upon the team and the user

And then we are going to display that inside of our view. So, all we are doing is fetching the documents based upon the team and the user . That way, the signed in user is only viewing the documents that they should be able to see, basically. Nothing out of the ordinary, just normal, basic stuff. But, of course, we are going to need to upload files. In much case, we're going to need a store method. So, here's our store method.

In much case, we're going to need a store method. So, here's our store method. Once again, we ensure team access to make sure that the user has a team. We validate the incoming document. It needs to be a PDF text or markdown. We resolve the team store, which is a method that we will talk about here in a few moments. And then, our AI document. Now, just so that we don't confuse ourselves with other kinds of documents, this is actually going to be part of the Laravel SDK.

Now, just so that we don't confuse ourselves with other kinds of documents, this is actually going to be part of the Laravel SDK. So, let's go ahead and let's add a use statement there. We want Laravel AI files document as AI document. Now, this is a class that is very important when it comes to working with documents that we are going to upload to the provider. Because it is going to essentially wrap around our uploaded file. Because the SDK knows how to serialize the file using the provider's file API. So, that's a pretty important thing there.

Because the SDK knows how to serialize the file using the provider's file API. So, that's a pretty important thing there. But then, we want to store the file with the provider. And we use the files class to do that. We are simply calling the put method to put that document. And it is therefore going to be uploaded to the provider's storage. That's going to give us both the stored file and the document that we want to work with. But here is that stored file ID. That is that very important value that we are going to store in our database.

But here is that stored file ID. That is that very important value that we are going to store in our database. So, then, we add the file to the vector store in our provider. And then, we store all of that information in our uploaded document database table. So, not only are we getting that uploaded file like we normally would, but this is where we are essentially taking it and uploading that to our provider. So, our AI document has this very handy from upload method. So, that we can just provide the uploaded file and that creates the document.

So, our AI document has this very handy from upload method. So, that we can just provide the uploaded file and that creates the document. So, that then we can put that document in our provider's store to store it. So, very straightforward is just another step in the process as far as uploading documents are concerned. But storing the document is just part of the solution. The next thing that we need to do is provide the ability to answer questions that the user might ask. So, we are going to have a method called ask. Once again, we get the user, we get the team, which we will implement this

might ask. So, we are going to have a method called ask. Once again, we get the user, we get the team, which we will implement this method here pretty soon. Then we validate the incoming information from the request. So, that once again, we will get the documents for this user and then we get the store ID. And if we are searching for a single document or searching within a single document, then we will fetch that document and get the store ID for that document. If we don't have a store ID, then we just return a view telling the user to

then we will fetch that document and get the store ID for that document. If we don't have a store ID, then we just return a view telling the user to please upload a document before asking a question. Otherwise, we log our run. And in this case, our feature key is document QA. Then the fun part, we will use our agent passing in the necessary information for the team, the user, the store ID, and the provider file ID. Then we will prompt using the question coming from the form. If we have a problem, we update our run. But if not, we update our run again

Then we will prompt using the question coming from the form. If we have a problem, we update our run. But if not, we update our run again with success. If we have a usage, then we create our usage based upon that run ID, we normal ize our sources, which we'll talk about here in a moment, and then we return our view. So, as far as asking the question here, it's really nothing new. It's the same kind of process that we've been doing so far. We are taking whatever information from the user and then essentially passing that on to our agent,

We are taking whatever information from the user and then essentially passing that on to our agent, except that in our case, the agent needs some pieces of information, such as the team, the user, the store, and the provider file ID. So, we have to get all of that in order for the agent to do its thing. And then next, we need to provide the ability to delete an uploaded file. So, we have our destroy method. We're going to start off the same way, getting the user, getting the team. And we need to be sure that the uploaded document has the same team ID and the user ID.

And we need to be sure that the uploaded document has the same team ID and the user ID. Otherwise, we don't want to delete that document because that person doesn't have authority to do so. But here, we need to get the file from our data store, from our provider's data store. We use the store's class from the SDK to get the store, we get the document ID, and then we remove that document from the store. Using the files class once again, instead of putting the file into our provider ,

Using the files class once again, instead of putting the file into our provider , we are deleting that file from the provider. We delete our uploaded document record and then we redirect. Again, nothing really out of the ordinary here, except that right here, we are including the AI stuff from the SDK. But the SDK is doing what a good SDK does. It doesn't matter what provider we are using, the SDK is going to handle all that for us. So all we need to do is get the store, get the document ID so that we can

that for us. So all we need to do is get the store, get the document ID so that we can remove the document based upon the ID from the store, then we delete it. And so then we just need those helper methods. So first of all, we have the resolve team store. All we are doing is essentially getting the team from the user so that we can get the stores and return it. If it's there, otherwise we create the store for that given team.

and return it. If it's there, otherwise we create the store for that given team. As far as normalizing sources, it's just normalizing sources. Let's pull in the string class here. And so this method just receives the tool results. Here we essentially filter the results because we only want results from file search. We want no other tools. Then we get the raw results from that tool. We build our sources array and then we return our sources.

Wiring Views and Routes15:33

Then we get the raw results from that tool. We build our sources array and then we return our sources. And then we need our view. Let's put this inside of our AI folder. We'll call it document qa.blade.php and I'll paste in the markup. It's just a set of normal forms. There's nothing really special about this view. And then we need our routes. So let's open up our route file. We've added quite a few routes, but we're going to add quite a few more because

So let's open up our route file. We've added quite a few routes, but we're going to add quite a few more because we need to handle the index method, the store method, the ask and the delete. Let's open up the sidebar because we want to add another item to the menu. So we have the AI search there. We are going to add another flux sidebar item. So let's open up the menu here. Let's ask document and we want to upload an index, a document. So let's just pick one.

Let's ask document and we want to upload an index, a document. So let's just pick one. It doesn't matter. I have a refund policy that we will upload and index. And once it is uploaded, we can ask questions about it. Now here we can select what document that we want to search or not necessarily search, but ask questions about all uploaded documents or we could pick an individual. Since we only have one, let's ask how many days and we will ask that document also that we can get an error.

Since we only have one, let's ask how many days and we will ask that document also that we can get an error. Integrity constraint violation, not null constraint failed. AI ticket ID. Yeah, makes sense. So let's open up the create AI runs because ticket ID is constrained and null on delete. PHP artisan migrate. We're just going to run fresh seed. Okay, so we're good there.

We're just going to run fresh seed. Okay, so we're good there. But unfortunately, that means that we need to, first of all, sign in. My user is Sarah@acme.test. Password is super secrets password. We will need to upload the document again. But this should get us past that particular problem because now that we are doing something more than just working with tickets, it makes sense for that to be null. So how many days?

more than just working with tickets, it makes sense for that to be null. So how many days? I think that's what our question was. I want to be vague there so that whenever we ask and we get a response, we'll see what kind of response that we get. And we have an answer. So we will, first of all, see our uploaded documents. We can see that it is stored in this vector store. But here we have the answer. It depends on days.

But here we have the answer. It depends on days. You mean in the refund policy, new subscriptions for refund within 14 days of initial purchase. So it at least kind of answered. I'm not going to read everything there. Since we were very vague in how many days, we're going to get a lot of things there. But you know, there is that option as to if the model doesn't know the answer. So we can say, who is John?

But you know, there is that option as to if the model doesn't know the answer. So we can say, who is John? Because there shouldn't be anything about John inside of the refund policy. Unless if it says to contact John, which I have no idea. I had AI generate that for me. And let's see what the answer is. I did not know. The provided documentation does not mention or identify anyone named John sources the refund policy. So there we go.

sources the refund policy. So there we go. It's doing exactly what we had told it to. And I like that. So we should be able to delete our refund policy. And sure enough, we can. It's no longer listed. And that's great. So we can use AI to search and index information from our own data sources. But we can also allow it to index and search really any information that a user

So we can use AI to search and index information from our own data sources. But we can also allow it to index and search really any information that a user provides. We of course need to store at least some metadata about those documents so that we can easily find them and work with them. But the really great thing is that all of the heavy lifting is done by the provider. We don't have to have any kind of a special database or a special column type or a special

We don't have to have any kind of a special database or a special column type or a special class to search and find similar data.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟