Reduce batch size to 10 and tighten AI price check prompt
Still seeing stubs despite MaxTokens=8192 — smaller batches and explicit word limits in the prompt eliminate any remaining truncation risk. - BatchSize: 15 → 10 (~1200 output tokens per batch vs. potential 3000+) - Prompt: added 20-word cap on assumptions, 25-word cap on reasoning - Prompt: strengthened "nothing before or after the '['" instruction - Error log: now includes item IDs and first 300 chars of raw response so the next failure tells us exactly what Claude returned - JS timing: updated batch divisor from 25 → 10 to match actual batch size Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ public class AiCatalogPriceCheckService : IAiCatalogPriceCheckService
|
|||||||
private readonly ILogger<AiCatalogPriceCheckService> _logger;
|
private readonly ILogger<AiCatalogPriceCheckService> _logger;
|
||||||
|
|
||||||
private const string Model = "claude-sonnet-4-6";
|
private const string Model = "claude-sonnet-4-6";
|
||||||
private const int BatchSize = 15; // 25 items at ~250 tokens each exceeds 4096 output tokens
|
private const int BatchSize = 10; // keep responses predictably short; 10 items × ~120 tokens ≈ 1200 output tokens
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions JsonOpts = new() { PropertyNameCaseInsensitive = true };
|
private static readonly JsonSerializerOptions JsonOpts = new() { PropertyNameCaseInsensitive = true };
|
||||||
|
|
||||||
@@ -132,10 +132,11 @@ public class AiCatalogPriceCheckService : IAiCatalogPriceCheckService
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var raw = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await SendAsync(client, parameters);
|
var response = await SendAsync(client, parameters);
|
||||||
var raw = response.Content.OfType<TextContent>().FirstOrDefault()?.Text ?? "[]";
|
raw = response.Content.OfType<TextContent>().FirstOrDefault()?.Text ?? "[]";
|
||||||
var json = ExtractJsonArray(raw);
|
var json = ExtractJsonArray(raw);
|
||||||
|
|
||||||
var claudeItems = JsonSerializer.Deserialize<List<ClaudePriceCheckItem>>(json, JsonOpts) ?? new();
|
var claudeItems = JsonSerializer.Deserialize<List<ClaudePriceCheckItem>>(json, JsonOpts) ?? new();
|
||||||
@@ -164,8 +165,10 @@ public class AiCatalogPriceCheckService : IAiCatalogPriceCheckService
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "AI catalog price check batch failed");
|
var preview = raw.Length > 300 ? raw[..300] + "…" : raw;
|
||||||
// Return stub verdicts so the rest of the report still renders
|
_logger.LogError(ex,
|
||||||
|
"AI price check batch failed for items [{ItemIds}]. Raw response preview: {RawPreview}",
|
||||||
|
string.Join(", ", batch.Select(b => b.Id)), preview);
|
||||||
return batch.Select(item => new CatalogItemPriceVerdict
|
return batch.Select(item => new CatalogItemPriceVerdict
|
||||||
{
|
{
|
||||||
CatalogItemId = item.Id,
|
CatalogItemId = item.Id,
|
||||||
@@ -220,10 +223,12 @@ public class AiCatalogPriceCheckService : IAiCatalogPriceCheckService
|
|||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
sb.AppendLine("If the item already has an ApproximateArea or EstimatedMinutes, use those instead of guessing.");
|
sb.AppendLine("If the item already has an ApproximateArea or EstimatedMinutes, use those instead of guessing.");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
sb.AppendLine("Return ONLY a JSON array, no prose, no markdown fences. Use this exact schema for each element:");
|
sb.AppendLine("IMPORTANT: Keep responses concise to avoid truncation. Limit assumptions to 20 words max. Limit reasoning to 25 words max.");
|
||||||
|
sb.AppendLine();
|
||||||
|
sb.AppendLine("Return ONLY a JSON array — no prose, no markdown fences, nothing before or after the '['. Use this exact schema for each element:");
|
||||||
sb.AppendLine(@"{
|
sb.AppendLine(@"{
|
||||||
""catalogItemId"": <int>,
|
""catalogItemId"": <int>,
|
||||||
""assumptions"": ""<what you assumed about size/complexity>"",
|
""assumptions"": ""<≤20 words>"",
|
||||||
""estimatedSqFtMin"": <decimal>,
|
""estimatedSqFtMin"": <decimal>,
|
||||||
""estimatedSqFtMax"": <decimal>,
|
""estimatedSqFtMax"": <decimal>,
|
||||||
""estimatedMinutesMin"": <int>,
|
""estimatedMinutesMin"": <int>,
|
||||||
@@ -233,7 +238,7 @@ public class AiCatalogPriceCheckService : IAiCatalogPriceCheckService
|
|||||||
""suggestedPriceMin"": <decimal>,
|
""suggestedPriceMin"": <decimal>,
|
||||||
""suggestedPriceMax"": <decimal>,
|
""suggestedPriceMax"": <decimal>,
|
||||||
""confidence"": ""high|medium|low"",
|
""confidence"": ""high|medium|low"",
|
||||||
""reasoning"": ""<1-2 sentence explanation>""
|
""reasoning"": ""<≤25 words>""
|
||||||
}");
|
}");
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
|
|
||||||
// Estimate total seconds based on item count (roughly 12s per batch of 25, min 15s).
|
// Estimate total seconds based on item count (roughly 12s per batch of 25, min 15s).
|
||||||
function estimateDuration(itemCount) {
|
function estimateDuration(itemCount) {
|
||||||
var batches = Math.max(1, Math.ceil(itemCount / 25));
|
var batches = Math.max(1, Math.ceil(itemCount / 10));
|
||||||
return Math.max(15, batches * 12);
|
return Math.max(15, batches * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Messages keyed to approximate progress milestones (0–100).
|
// Messages keyed to approximate progress milestones (0–100).
|
||||||
function messageAt(pct, batchCount) {
|
function messageAt(pct, batchCount) {
|
||||||
if (pct < 10) return 'Loading catalog items…';
|
if (pct < 10) return 'Loading catalog items…';
|
||||||
if (pct < 20) return 'Sending items to Claude…';
|
if (pct < 20) return 'Sending items for analysis…';
|
||||||
if (batchCount <= 1) {
|
if (batchCount <= 1) {
|
||||||
if (pct < 75) return 'Analyzing your catalog with AI…';
|
if (pct < 75) return 'Analyzing your catalog with AI…';
|
||||||
if (pct < 92) return 'Reviewing pricing data…';
|
if (pct < 92) return 'Reviewing pricing data…';
|
||||||
|
|||||||
Reference in New Issue
Block a user