Private
Public Access
1
0

Add Ollama diagnostic logging and broaden tool-call retry

Log model name, tool count, raw response preview, and parsed
tool_call count at INFO level. Broaden the retry nudge to trigger
whenever no tools are called on the first attempt, not just when
code is detected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-02-10 20:32:48 -05:00
parent 9b81a8e37e
commit 04d21afc87
+42 -3
View File
@@ -227,8 +227,28 @@ public class ChatService : IChatService
} }
else else
{ {
var rawContent = response?.Message?.Content ?? "I'm sorry, I couldn't process that request.";
// If the model responded without calling any tools on the first attempt,
// it likely fabricated data or generated code. Nudge it to use tools.
if (toolResults.Count == 0 && i == 0)
{
_logger.LogWarning("Model responded without calling tools on first attempt, retrying with nudge");
ollamaMessages.Add(new OllamaToolMessage
{
Role = "assistant",
Content = rawContent
});
ollamaMessages.Add(new OllamaToolMessage
{
Role = "user",
Content = "You did not use any tools. You MUST call the provided function tools to look up or modify my financial data. Do not make up data. Try again."
});
continue;
}
// No tool calls - save final assistant message // No tool calls - save final assistant message
var content = StripCodeBlocks(response?.Message?.Content ?? "I'm sorry, I couldn't process that request."); var content = StripCodeBlocks(rawContent);
assistantDbMessage = new ChatMessage assistantDbMessage = new ChatMessage
{ {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
@@ -417,13 +437,22 @@ public class ChatService : IChatService
var json = JsonSerializer.Serialize(request, OllamaJsonOptions); var json = JsonSerializer.Serialize(request, OllamaJsonOptions);
var content = new StringContent(json, Encoding.UTF8, "application/json"); var content = new StringContent(json, Encoding.UTF8, "application/json");
_logger.LogDebug("Sending chat request to Ollama: {Url}", $"{ollamaUrl}/api/chat"); _logger.LogInformation("Ollama request — model: {Model}, tools: {ToolCount}, messages: {MessageCount}",
request.Model, request.Tools?.Count ?? 0, request.Messages.Count);
var response = await client.PostAsync($"{ollamaUrl}/api/chat", content); var response = await client.PostAsync($"{ollamaUrl}/api/chat", content);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync(); var responseBody = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<OllamaToolChatResponse>(responseBody, OllamaJsonOptions); _logger.LogInformation("Ollama response — length: {Length}, preview: {Preview}",
responseBody.Length, responseBody.Length > 500 ? responseBody[..500] : responseBody);
var parsed = JsonSerializer.Deserialize<OllamaToolChatResponse>(responseBody, OllamaJsonOptions);
_logger.LogInformation("Ollama parsed — tool_calls: {ToolCallCount}, content_length: {ContentLength}",
parsed?.Message?.ToolCalls?.Count ?? 0,
parsed?.Message?.Content?.Length ?? 0);
return parsed;
} }
private async Task<(string toolResultType, object data, string summaryForLlm)> ExecuteToolAsync(Guid userId, OllamaToolCall toolCall) private async Task<(string toolResultType, object data, string summaryForLlm)> ExecuteToolAsync(Guid userId, OllamaToolCall toolCall)
@@ -1108,6 +1137,16 @@ public class ChatService : IChatService
}; };
} }
// Detect responses that contain code blocks or common code patterns
private static bool LooksLikeCodeResponse(string content)
{
if (content.Contains("```")) return true;
if (content.Contains("import ") && content.Contains("(")) return true;
if (content.Contains("def ") && content.Contains("():")) return true;
if (content.Contains("print(") || content.Contains("console.log(")) return true;
return false;
}
// Strip fenced code blocks that smaller models sometimes generate instead of using tools // Strip fenced code blocks that smaller models sometimes generate instead of using tools
private static readonly Regex CodeBlockRegex = new(@"```[\s\S]*?```", RegexOptions.Compiled); private static readonly Regex CodeBlockRegex = new(@"```[\s\S]*?```", RegexOptions.Compiled);
private static string StripCodeBlocks(string content) private static string StripCodeBlocks(string content)