|
| 1 | +# Sample file search with agent in Azure.AI.Agents.Persistent. |
| 2 | + |
| 3 | +In this example we will create the local file, upload it to the newly created `VectorStore`, which will be used in the file search. In this example we will stream the result. |
| 4 | + |
| 5 | +1. First we need to create agent client and read the environment variables that will be used in the next steps. |
| 6 | +```C# Snippet:AgentsFilesSearchStreamingExample_CreateClient |
| 7 | +var projectEndpoint = System.Environment.GetEnvironmentVariable("PROJECT_ENDPOINT"); |
| 8 | +var modelDeploymentName = System.Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME"); |
| 9 | +PersistentAgentsClient client = new(projectEndpoint, new DefaultAzureCredential()); |
| 10 | +``` |
| 11 | + |
| 12 | +2. Create a file and upload it to the data store. |
| 13 | + |
| 14 | +Synchronous sample: |
| 15 | +```C# Snippet:AgentsUploadAgentFilesToUseStreaming_Sync |
| 16 | +// Upload a file and wait for it to be processed |
| 17 | +System.IO.File.WriteAllText( |
| 18 | + path: "sample_file_for_upload.txt", |
| 19 | + contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); |
| 20 | +PersistentAgentFileInfo uploadedAgentFile = client.Files.UploadFile( |
| 21 | + filePath: "sample_file_for_upload.txt", |
| 22 | + purpose: PersistentAgentFilePurpose.Agents); |
| 23 | +Dictionary<string, string> fileIds = new() |
| 24 | +{ |
| 25 | + { uploadedAgentFile.Id, uploadedAgentFile.Filename } |
| 26 | +}; |
| 27 | +``` |
| 28 | + |
| 29 | +Asynchronous sample: |
| 30 | +```C# Snippet:AgentsUploadAgentFilesToUseStreaming |
| 31 | +// Upload a file and wait for it to be processed |
| 32 | +System.IO.File.WriteAllText( |
| 33 | + path: "sample_file_for_upload.txt", |
| 34 | + contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457."); |
| 35 | +PersistentAgentFileInfo uploadedAgentFile = await client.Files.UploadFileAsync( |
| 36 | + filePath: "sample_file_for_upload.txt", |
| 37 | + purpose: PersistentAgentFilePurpose.Agents); |
| 38 | +Dictionary<string, string> fileIds = new() |
| 39 | +{ |
| 40 | + { uploadedAgentFile.Id, uploadedAgentFile.Filename } |
| 41 | +}; |
| 42 | +``` |
| 43 | + |
| 44 | +3. To create agent capable of using file search, we will create `VectorStore`, with the ID of uploaded file. |
| 45 | + |
| 46 | +Synchronous sample: |
| 47 | +```C# Snippet:AgentsCreateVectorStoreStreaming_Sync |
| 48 | +// Create a vector store with the file and wait for it to be processed. |
| 49 | +// If you do not specify a vector store, create_message will create a vector store with a default expiration policy of seven days after they were last active |
| 50 | +PersistentAgentsVectorStore vectorStore = client.VectorStores.CreateVectorStore( |
| 51 | + fileIds: new List<string> { uploadedAgentFile.Id }, |
| 52 | + name: "my_vector_store"); |
| 53 | +``` |
| 54 | + |
| 55 | +Asynchronous sample: |
| 56 | +```C# Snippet:AgentsCreateVectorStoreStreaming |
| 57 | +// Create a vector store with the file and wait for it to be processed. |
| 58 | +// If you do not specify a vector store, create_message will create a vector store with a default expiration policy of seven days after they were last active |
| 59 | +PersistentAgentsVectorStore vectorStore = await client.VectorStores.CreateVectorStoreAsync( |
| 60 | + fileIds: new List<string> { uploadedAgentFile.Id }, |
| 61 | + name: "my_vector_store"); |
| 62 | +``` |
| 63 | + |
| 64 | + |
| 65 | +4 The ID of the created vector store will be used in the `FileSearchToolResource` needed for agent creation. |
| 66 | + |
| 67 | +Synchronous sample: |
| 68 | +```C# Snippet:AgentsCreateAgentWithFilesStreaming_Sync |
| 69 | +FileSearchToolResource fileSearchToolResource = new FileSearchToolResource(); |
| 70 | +fileSearchToolResource.VectorStoreIds.Add(vectorStore.Id); |
| 71 | + |
| 72 | +// Create an agent with toolResources and process agent run |
| 73 | +PersistentAgent agent = client.Administration.CreateAgent( |
| 74 | + model: modelDeploymentName, |
| 75 | + name: "SDK Test Agent - Retrieval", |
| 76 | + instructions: "You are a helpful agent that can help fetch data from files you know about.", |
| 77 | + tools: new List<ToolDefinition> { new FileSearchToolDefinition() }, |
| 78 | + toolResources: new ToolResources() { FileSearch = fileSearchToolResource }); |
| 79 | +``` |
| 80 | + |
| 81 | +Asynchronous sample: |
| 82 | +```C# Snippet:AgentsCreateAgentWithFilesStreaming |
| 83 | +FileSearchToolResource fileSearchToolResource = new FileSearchToolResource(); |
| 84 | +fileSearchToolResource.VectorStoreIds.Add(vectorStore.Id); |
| 85 | + |
| 86 | +// Create an agent with toolResources and process agent run |
| 87 | +PersistentAgent agent = await client.Administration.CreateAgentAsync( |
| 88 | + model: modelDeploymentName, |
| 89 | + name: "SDK Test Agent - Retrieval", |
| 90 | + instructions: "You are a helpful agent that can help fetch data from files you know about.", |
| 91 | + tools: new List<ToolDefinition> { new FileSearchToolDefinition() }, |
| 92 | + toolResources: new ToolResources() { FileSearch = fileSearchToolResource }); |
| 93 | +``` |
| 94 | + |
| 95 | +5. To parse and print stream output, we will use the `ParseStreamingUdate` method, which replaces reference placeholders by file IDs or by file names and also prints cited text. |
| 96 | +```C# Snippet:AgentsFilesSearchExampleStreaming_Print |
| 97 | +private static void ParseStreamingUdate(StreamingUpdate streamingUpdate, Dictionary<string, string> fileIds) |
| 98 | +{ |
| 99 | + if (streamingUpdate.UpdateKind == StreamingUpdateReason.RunCreated) |
| 100 | + { |
| 101 | + Console.WriteLine("--- Run started! ---"); |
| 102 | + } |
| 103 | + else if (streamingUpdate is MessageContentUpdate contentUpdate) |
| 104 | + { |
| 105 | + if (contentUpdate.TextAnnotation != null) |
| 106 | + { |
| 107 | + if (fileIds.TryGetValue(contentUpdate.TextAnnotation.InputFileId, out string annotation)) |
| 108 | + { |
| 109 | + Console.Write($" [see {annotation}]"); |
| 110 | + } |
| 111 | + else |
| 112 | + { |
| 113 | + Console.Write($" [see {contentUpdate.TextAnnotation.InputFileId}]"); |
| 114 | + } |
| 115 | + } |
| 116 | + else |
| 117 | + { |
| 118 | + //Detect the reference placeholder and skip it. Instead we will print the actual reference. |
| 119 | + if (contentUpdate.Text[0] != (char)12304 || contentUpdate.Text[contentUpdate.Text.Length - 1] != (char)12305) |
| 120 | + Console.Write(contentUpdate.Text); |
| 121 | + } |
| 122 | + } |
| 123 | + else if (streamingUpdate.UpdateKind == StreamingUpdateReason.RunStepCompleted) |
| 124 | + { |
| 125 | + if (streamingUpdate is RunStepUpdate runStep) |
| 126 | + { |
| 127 | + if (runStep.Value.StepDetails is RunStepToolCallDetails toolCallDetails) |
| 128 | + { |
| 129 | + foreach (RunStepToolCall toolCall in toolCallDetails.ToolCalls) |
| 130 | + { |
| 131 | + if (toolCall is RunStepFileSearchToolCall fileSearh) |
| 132 | + { |
| 133 | + Console.WriteLine($"The search tool has found the next relevant content in the file {fileSearh.FileSearch.Results[0].FileName}:"); |
| 134 | + Console.WriteLine(fileSearh.FileSearch.Results[0].Content[0].Text); |
| 135 | + Console.WriteLine("==============================================================="); |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | + else if (streamingUpdate.UpdateKind == StreamingUpdateReason.RunCompleted) |
| 142 | + { |
| 143 | + Console.WriteLine(); |
| 144 | + Console.WriteLine("--- Run completed! ---"); |
| 145 | + } |
| 146 | + else if (streamingUpdate.UpdateKind == StreamingUpdateReason.Error && streamingUpdate is RunUpdate errorStep) |
| 147 | + { |
| 148 | + throw new InvalidOperationException($"Error: {errorStep.Value.LastError}"); |
| 149 | + } |
| 150 | +} |
| 151 | +``` |
| 152 | + |
| 153 | +6. Now we will create thread and message used to ask a question to an Agent. |
| 154 | + |
| 155 | +Synchronous sample: |
| 156 | +```C# Snippet:AgentsFilesSearchExampleStreaming_CreateThreadMessage_Sync |
| 157 | +// Create thread for communication |
| 158 | +PersistentAgentThread thread = client.Threads.CreateThread(); |
| 159 | + |
| 160 | +// Create message to thread |
| 161 | +PersistentThreadMessage messageResponse = client.Messages.CreateMessage( |
| 162 | + thread.Id, |
| 163 | + MessageRole.User, |
| 164 | + "Can you give me the documented codes for 'banana' and 'orange'?"); |
| 165 | +``` |
| 166 | + |
| 167 | +Asynchronous sample: |
| 168 | +```C# Snippet:AgentsFilesSearchExampleStreaming_CreateThreadMessage |
| 169 | +// Create thread for communication |
| 170 | +PersistentAgentThread thread = await client.Threads.CreateThreadAsync(); |
| 171 | + |
| 172 | +// Create message to thread |
| 173 | +PersistentThreadMessage messageResponse = await client.Messages.CreateMessageAsync( |
| 174 | + thread.Id, |
| 175 | + MessageRole.User, |
| 176 | + "Can you give me the documented codes for 'banana' and 'orange'?"); |
| 177 | +``` |
| 178 | + |
| 179 | +7. Stream the results. |
| 180 | + |
| 181 | +Synchronous sample: |
| 182 | +```C# Snippet:AgentsFilesSearchExampleStreaming_StreamResults_Sync |
| 183 | +// Create the stream and parse output |
| 184 | +CollectionResult<StreamingUpdate> stream = client.Runs.CreateRunStreaming(thread.Id, agent.Id, include: [RunAdditionalFieldList.FileSearchContents]); |
| 185 | +foreach (StreamingUpdate streamingUpdate in stream) |
| 186 | +{ |
| 187 | + ParseStreamingUdate(streamingUpdate, fileIds); |
| 188 | +} |
| 189 | +``` |
| 190 | + |
| 191 | +Asynchronous sample: |
| 192 | +```C# Snippet:AgentsFilesSearchExampleStreaming_StreamResults |
| 193 | +// Create the stream and parse output. |
| 194 | +AsyncCollectionResult<StreamingUpdate> stream = client.Runs.CreateRunStreamingAsync(thread.Id, agent.Id, include: [RunAdditionalFieldList.FileSearchContents]); |
| 195 | +await foreach (StreamingUpdate streamingUpdate in stream) |
| 196 | +{ |
| 197 | + ParseStreamingUdate(streamingUpdate, fileIds); |
| 198 | +} |
| 199 | +``` |
| 200 | + |
| 201 | +8. Finally, we delete all the resources, we have created in this sample. |
| 202 | + |
| 203 | +Synchronous sample: |
| 204 | +```C# Snippet:AgentsFilesSearchExampleSteaming_Cleanup_Sync |
| 205 | +client.VectorStores.DeleteVectorStore(vectorStore.Id); |
| 206 | +client.Files.DeleteFile(uploadedAgentFile.Id); |
| 207 | +client.Threads.DeleteThread(thread.Id); |
| 208 | +client.Administration.DeleteAgent(agent.Id); |
| 209 | +``` |
| 210 | + |
| 211 | +Asynchronous sample: |
| 212 | +```C# Snippet:AgentsFilesSearchExampleSteaming_Cleanup |
| 213 | +await client.VectorStores.DeleteVectorStoreAsync(vectorStore.Id); |
| 214 | +await client.Files.DeleteFileAsync(uploadedAgentFile.Id); |
| 215 | +await client.Threads.DeleteThreadAsync(thread.Id); |
| 216 | +await client.Administration.DeleteAgentAsync(agent.Id); |
| 217 | +``` |
0 commit comments