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:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user