Skip to content

Commit 28a3376

Browse files
authored
Clean up samples and add individual readme files for them. (Azure#49047)
* First draft * Add files * Add more samples * Fix * Fix URI and add one more sample * Fix snippets * Fix * Fix formatting * Fix typoes
1 parent 6ee166f commit 28a3376

39 files changed

+6077
-483
lines changed

sdk/ai/Azure.AI.Projects/README.md

Lines changed: 137 additions & 94 deletions
Large diffs are not rendered by default.
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# Sample file search with agent in Azure.AI.Projects.
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.
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:FilesSearchExample_CreateClient
7+
var connectionString = System.Environment.GetEnvironmentVariable("PROJECT_CONNECTION_STRING");
8+
var modelDeploymentName = System.Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME");
9+
AgentsClient client = new(connectionString, new DefaultAzureCredential());
10+
```
11+
12+
2. Now we will create a file and upload it to the data store.
13+
14+
Synchronous sample:
15+
```C# Snippet:UploadAgentFilesToUse_Sync
16+
// Upload a file and wait for it to be processed
17+
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+
AgentFile uploadedAgentFile = client.UploadFile(
21+
filePath: "sample_file_for_upload.txt",
22+
purpose: AgentFilePurpose.Agents);
23+
Dictionary<string, string> fileIds = new()
24+
{
25+
{ uploadedAgentFile.Id, uploadedAgentFile.Filename }
26+
};
27+
```
28+
29+
Asynchronous sample:
30+
```C# Snippet:UploadAgentFilesToUse
31+
// Upload a file and wait for it to be processed
32+
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+
AgentFile uploadedAgentFile = await client.UploadFileAsync(
36+
filePath: "sample_file_for_upload.txt",
37+
purpose: AgentFilePurpose.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:CreateVectorStore_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+
VectorStore vectorStore = client.CreateVectorStore(
51+
fileIds: new List<string> { uploadedAgentFile.Id },
52+
name: "my_vector_store");
53+
```
54+
55+
Asynchronous sample:
56+
```C# Snippet:CreateVectorStore
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+
VectorStore vectorStore = await client.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` used for agent creation.
66+
67+
Synchronous sample:
68+
```C# Snippet:CreateAgentWithFiles_Sync
69+
FileSearchToolResource fileSearchToolResource = new FileSearchToolResource();
70+
fileSearchToolResource.VectorStoreIds.Add(vectorStore.Id);
71+
72+
// Create an agent with toolResources and process assistant run
73+
Agent agent = client.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:CreateAgentWithFiles
83+
FileSearchToolResource fileSearchToolResource = new FileSearchToolResource();
84+
fileSearchToolResource.VectorStoreIds.Add(vectorStore.Id);
85+
86+
// Create an agent with toolResources and process assistant run
87+
Agent agent = await client.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 properly render the links to the file name we use the `WriteMessages` method, which internally calls `replaceReferences` method to replace reference placeholders by file IDs or by file names.
96+
```C# Snippet:FilesSearchExample_Print
97+
private static void WriteMessages(IEnumerable<ThreadMessage> messages, Dictionary<string, string> fileIds)
98+
{
99+
foreach (ThreadMessage threadMessage in messages)
100+
{
101+
Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
102+
foreach (MessageContent contentItem in threadMessage.ContentItems)
103+
{
104+
if (contentItem is MessageTextContent textItem)
105+
{
106+
if (threadMessage.Role == MessageRole.Agent && textItem.Annotations.Count > 0)
107+
{
108+
string strMessage = textItem.Text;
109+
foreach (MessageTextAnnotation annotation in textItem.Annotations)
110+
{
111+
if (annotation is MessageTextFilePathAnnotation pathAnnotation)
112+
{
113+
strMessage = replaceReferences(fileIds, pathAnnotation.FileId, pathAnnotation.Text, strMessage);
114+
}
115+
else if (annotation is MessageTextFileCitationAnnotation citationAnnotation)
116+
{
117+
strMessage = replaceReferences(fileIds, citationAnnotation.FileId, citationAnnotation.Text, strMessage);
118+
}
119+
}
120+
Console.Write(strMessage);
121+
}
122+
else
123+
{
124+
Console.Write(textItem.Text);
125+
}
126+
}
127+
else if (contentItem is MessageImageFileContent imageFileItem)
128+
{
129+
Console.Write($"<image from ID: {imageFileItem.FileId}");
130+
}
131+
Console.WriteLine();
132+
}
133+
}
134+
}
135+
136+
private static string replaceReferences(Dictionary<string, string> fileIds, string fileID, string placeholder, string text)
137+
{
138+
if (fileIds.TryGetValue(fileID, out string replacement))
139+
return text.Replace(placeholder, $" [{replacement}]");
140+
else
141+
return text.Replace(placeholder, $" [{fileID}]");
142+
}
143+
```
144+
145+
6. We will ask a question to the file contents and add it to the thread, create run and wait while it will terminate. If the run was successful, we will render the response and provide the reference to the uploaded file.
146+
147+
Synchronous sample:
148+
```C# Snippet:FilesSearchExample_CreateThreadAndRun_Sync
149+
// Create thread for communication
150+
AgentThread thread = client.CreateThread();
151+
152+
// Create message to thread
153+
ThreadMessage messageResponse = client.CreateMessage(
154+
thread.Id,
155+
MessageRole.User,
156+
"Can you give me the documented codes for 'banana' and 'orange'?");
157+
158+
// Run the agent
159+
ThreadRun run = client.CreateRun(thread, agent);
160+
161+
do
162+
{
163+
Thread.Sleep(TimeSpan.FromMilliseconds(500));
164+
run = client.GetRun(thread.Id, run.Id);
165+
}
166+
while (run.Status == RunStatus.Queued
167+
|| run.Status == RunStatus.InProgress);
168+
Assert.AreEqual(
169+
RunStatus.Completed,
170+
run.Status,
171+
run.LastError?.Message);
172+
PageableList<ThreadMessage> messages = client.GetMessages(
173+
threadId: thread.Id,
174+
order: ListSortOrder.Ascending
175+
);
176+
WriteMessages(messages, fileIds);
177+
```
178+
179+
Asynchronous sample:
180+
```C# Snippet:FilesSearchExample_CreateThreadAndRun
181+
// Create thread for communication
182+
AgentThread thread = await client.CreateThreadAsync();
183+
184+
// Create message to thread
185+
ThreadMessage messageResponse = await client.CreateMessageAsync(
186+
thread.Id,
187+
MessageRole.User,
188+
"Can you give me the documented codes for 'banana' and 'orange'?");
189+
190+
// Run the agent
191+
ThreadRun run = await client.CreateRunAsync(thread, agent);
192+
193+
do
194+
{
195+
await Task.Delay(TimeSpan.FromMilliseconds(500));
196+
run = await client.GetRunAsync(thread.Id, run.Id);
197+
}
198+
while (run.Status == RunStatus.Queued
199+
|| run.Status == RunStatus.InProgress);
200+
Assert.AreEqual(
201+
RunStatus.Completed,
202+
run.Status,
203+
run.LastError?.Message);
204+
PageableList<ThreadMessage> messages = await client.GetMessagesAsync(
205+
threadId: thread.Id,
206+
order: ListSortOrder.Ascending
207+
);
208+
WriteMessages(messages, fileIds);
209+
```
210+
211+
7. Finally, we delete all the resources, we have created in this sample.
212+
213+
Synchronous sample:
214+
```C# Snippet:FilesSearchExample_Cleanup_Sync
215+
client.DeleteVectorStore(vectorStore.Id);
216+
client.DeleteFile(uploadedAgentFile.Id);
217+
client.DeleteThread(thread.Id);
218+
client.DeleteAgent(agent.Id);
219+
```
220+
221+
Asynchronous sample:
222+
```C# Snippet:FilesSearchExample_Cleanup
223+
await client.DeleteVectorStoreAsync(vectorStore.Id);
224+
await client.DeleteFileAsync(uploadedAgentFile.Id);
225+
await client.DeleteThreadAsync(thread.Id);
226+
await client.DeleteAgentAsync(agent.Id);
227+
```

0 commit comments

Comments
 (0)