Skip to content

Commit 4be0575

Browse files
committed
Successful experiment by having the LLM return structured data instead
1 parent 4b9435d commit 4be0575

File tree

1 file changed

+37
-91
lines changed

1 file changed

+37
-91
lines changed

src/Return.Web/Components/NoteLaneBase.cs

Lines changed: 37 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -271,37 +271,10 @@ protected async Task AutoGroupNotes()
271271

272272
ChatOptions chatOptions = new()
273273
{
274-
Tools = [
275-
AIFunctionFactory.Create(
276-
this.MakeNoteGroup,
277-
new AIFunctionFactoryCreateOptions
278-
{
279-
Name = "Create group",
280-
Parameters = [
281-
new("title") { Description = "The name of the group to create", IsRequired = true, ParameterType = typeof(string)},
282-
]
283-
}
284-
),
285-
AIFunctionFactory.Create(
286-
this.AddNoteToGroup,
287-
new AIFunctionFactoryCreateOptions
288-
{
289-
Name = "Assign note to group",
290-
Parameters = [
291-
new("noteGroup") { Description = "Title of the group created with the \"Create note group\" tool", IsRequired = true, ParameterType = typeof(int)},
292-
new("noteId") { Description = "Integer ID of the note to move to the group", IsRequired = true, ParameterType = typeof(int)},
293-
],
294-
ReturnParameter = new() {
295-
Description = "Returns if the move was successful",
296-
ParameterType = typeof(string)
297-
}
298-
}
299-
),
300-
],
301-
ToolMode = ChatToolMode.RequireAny,
302274
TopP = 0.9f,
303275
Temperature = 0.2f,
304-
TopK = 10
276+
TopK = 10,
277+
ResponseFormat = ChatResponseFormat.Json
305278
};
306279

307280
List<ChatMessage> chatMessages =
@@ -315,11 +288,7 @@ protected async Task AutoGroupNotes()
315288
- Do not include the same note in more than one group.
316289
- Assign each group a concise title (maximum of 5 words) summarizing its content.
317290
318-
Workflow:
319-
1. Create group with a title
320-
2. For each note belonging to the group: invoke the ""add note to group"" tool
321-
322-
What now follows is a list of notes to divide into groups. Do not response with a summary, invoke the tool.
291+
What now follows is a list of notes to divide into groups.
323292
Each note is starts with [NOTE ID]. Each note ends with [END NOTE].
324293
325294
Example note with ID 123:
@@ -339,17 +308,45 @@ [NOTE 123] Some text here [END NOTE]"
339308
long startTime = Stopwatch.GetTimestamp();
340309

341310
IChatClient client = new ChatClientBuilder()
342-
.UseFunctionInvocation(f =>
343-
{
344-
f.RetryOnError = true;
345-
})
346311
.UseLogging(this.Logger)
347312
.Use(this.ChatClient);
348313

349314
Logger.LogDebug("Invoking AI with {Count} messages", chatMessages.Count);
350315
try
351316
{
352-
ChatCompletion response = await client.CompleteAsync(chatMessages, chatOptions);
317+
ChatCompletion<AIGroupedNote[]> response = await client.CompleteAsync<AIGroupedNote[]>(chatMessages, chatOptions);
318+
319+
if (response.TryGetResult(out AIGroupedNote[] result))
320+
{
321+
foreach (AIGroupedNote groupedNote in result)
322+
{
323+
RetrospectiveNoteGroup createdGroup = await this.Mediator.Send(new AddNoteGroupCommand(this.RetroId.StringId, this.Lane.Id));
324+
325+
this.Contents.Groups.Add(createdGroup);
326+
await this.Mediator.Send(new UpdateNoteGroupCommand(this.RetroId.StringId, createdGroup.Id, groupedNote.GroupTitle));
327+
328+
createdGroup = this.Contents.Groups.FirstOrDefault(x => x.Id == createdGroup.Id) ?? createdGroup;
329+
createdGroup.Title = groupedNote.GroupTitle;
330+
331+
foreach (int noteId in groupedNote.NoteIds)
332+
{
333+
if (this.ExecuteNoteMove(noteId, createdGroup.Id))
334+
{
335+
await this.Mediator.Send(new MoveNoteCommand(noteId, createdGroup.Id));
336+
}
337+
else
338+
{
339+
Logger.LogWarning("Invalid attempt to move note {NoteId} to group {Title}", noteId, createdGroup.Title);
340+
}
341+
}
342+
}
343+
344+
Logger.LogInformation("Resulting grouped notes: {@Results}", [result]);
345+
}
346+
else
347+
{
348+
Logger.LogWarning("Cannot decode response: {@Response}", response);
349+
}
353350

354351
Logger.LogTrace("AI response: {@RawResponse}", response);
355352
}
@@ -365,58 +362,7 @@ [NOTE 123] Some text here [END NOTE]"
365362
Logger.LogDebug("Completed AI invocation in {Elapsed}", Stopwatch.GetElapsedTime(startTime));
366363
}
367364

368-
369-
private async Task MakeNoteGroup(string title)
370-
{
371-
try
372-
{
373-
Logger.LogInformation("AI tool callback: Make note group with title {Title}", title);
374-
375-
RetrospectiveNoteGroup result = await this.Mediator.Send(new AddNoteGroupCommand(this.RetroId.StringId, this.Lane.Id));
376-
377-
this.Contents.Groups.Add(result);
378-
await this.Mediator.Send(new UpdateNoteGroupCommand(this.RetroId.StringId, result.Id, title));
379-
380-
result = this.Contents.Groups.FirstOrDefault(x => x.Id == result.Id) ?? result;
381-
result.Title = title;
382-
}
383-
catch (Exception ex)
384-
{
385-
Logger.LogError(ex, "Error processing AI invocation");
386-
throw;
387-
}
388-
}
389-
390-
private async Task<string> AddNoteToGroup(string noteGroup, int noteId)
391-
{
392-
try
393-
{
394-
Logger.LogInformation("AI tool callback: Move note {NoteId} to group {GroupTitle}",
395-
noteId,
396-
noteGroup);
397-
398-
RetrospectiveNoteGroup noteGroupInstance = this.Contents.Groups.FirstOrDefault(x => String.Equals(noteGroup.Trim(), x.Title.Trim(), StringComparison.OrdinalIgnoreCase));
399-
if (noteGroupInstance is null) return $"Note group \"{noteGroup}\" does not exist";
400-
401-
IEnumerable<string> notes = this.Contents.Notes.Where(x => x.Id == noteId).Select(x => x.Text);
402-
foreach (string note in notes) {
403-
Logger.LogDebug("Note selected for group {Title}: {NoteText}", noteGroupInstance.Title, note);
404-
}
405-
406-
if (this.ExecuteNoteMove(noteId, noteGroupInstance.Id))
407-
{
408-
await this.Mediator.Send(new MoveNoteCommand(noteId, noteGroupInstance.Id));
409-
return "Success";
410-
}
411-
}
412-
catch (Exception ex)
413-
{
414-
Logger.LogError(ex, "Error processing AI invocation");
415-
throw;
416-
}
417-
418-
return "Invalid move";
419-
}
365+
private sealed record AIGroupedNote(string GroupTitle, int[] NoteIds);
420366

421367
public Task OnNoteAdded(NoteAddedNotification notification) {
422368
if (notification.LaneId != this.Lane?.Id ||

0 commit comments

Comments
 (0)