fix: save raw AI response for debugging and require calculated numbers

- Add RawResponse field to FullDecision and DecisionRecord
- Save raw AI response to database for debugging parse failures
- Add IMPORTANT note in prompt: all numeric values must be calculated numbers, not formulas
This commit is contained in:
tinkle-community
2025-12-08 11:29:31 +08:00
parent 10047577e1
commit f39fc8af23
4 changed files with 16 additions and 8 deletions
+5 -4
View File
@@ -137,6 +137,7 @@ type FullDecision struct {
UserPrompt string `json:"user_prompt"` // Input prompt sent to AI
CoTTrace string `json:"cot_trace"` // Chain of thought analysis (AI output)
Decisions []Decision `json:"decisions"` // Specific decision list
RawResponse string `json:"raw_response"` // Raw AI response (for debugging when parsing fails)
Timestamp time.Time `json:"timestamp"`
// AIRequestDurationMs records AI API call duration (milliseconds) for troubleshooting latency issues
AIRequestDurationMs int64 `json:"ai_request_duration_ms,omitempty"`
@@ -212,6 +213,7 @@ func GetFullDecisionWithStrategy(ctx *Context, mcpClient mcp.AIClient, engine *S
decision.SystemPrompt = systemPrompt
decision.UserPrompt = userPrompt
decision.AIRequestDurationMs = aiCallDuration.Milliseconds()
decision.RawResponse = aiResponse // Save raw response for debugging
}
if err != nil {
@@ -350,15 +352,13 @@ func GetFullDecisionWithCustomPrompt(ctx *Context, mcpClient mcp.AIClient, custo
decision.SystemPrompt = systemPrompt // Save system prompt
decision.UserPrompt = userPrompt // Save input prompt
decision.AIRequestDurationMs = aiCallDuration.Milliseconds()
decision.RawResponse = aiResponse // Save raw response for debugging
}
if err != nil {
return decision, fmt.Errorf("failed to parse AI response: %w", err)
}
decision.Timestamp = time.Now()
decision.SystemPrompt = systemPrompt // Save system prompt
decision.UserPrompt = userPrompt // Save input prompt
return decision, nil
}
@@ -581,7 +581,8 @@ func buildSystemPrompt(accountEquity float64, btcEthLeverage, altcoinLeverage in
sb.WriteString("## Field Descriptions\n\n")
sb.WriteString("- `action`: open_long | open_short | close_long | close_short | hold | wait\n")
sb.WriteString("- `confidence`: 0-100 (opening recommended ≥75)\n")
sb.WriteString("- Required for opening: leverage, position_size_usd, stop_loss, take_profit, confidence, risk_usd\n\n")
sb.WriteString("- Required for opening: leverage, position_size_usd, stop_loss, take_profit, confidence, risk_usd\n")
sb.WriteString("- **IMPORTANT**: All numeric values must be calculated numbers, NOT formulas/expressions (e.g., use `27.76` not `3000 * 0.01`)\n\n")
return sb.String()
}
+2 -1
View File
@@ -839,7 +839,8 @@ func (e *StrategyEngine) BuildSystemPrompt(accountEquity float64, variant string
sb.WriteString("## Field Description\n\n")
sb.WriteString("- `action`: open_long | open_short | close_long | close_short | hold | wait\n")
sb.WriteString(fmt.Sprintf("- `confidence`: 0-100 (opening recommended ≥ %d)\n", riskControl.MinConfidence))
sb.WriteString("- Required when opening: leverage, position_size_usd, stop_loss, take_profit, confidence, risk_usd\n\n")
sb.WriteString("- Required when opening: leverage, position_size_usd, stop_loss, take_profit, confidence, risk_usd\n")
sb.WriteString("- **IMPORTANT**: All numeric values must be calculated numbers, NOT formulas/expressions (e.g., use `27.76` not `3000 * 0.01`)\n\n")
// 8. Custom Prompt
if e.config.CustomPrompt != "" {
+8 -3
View File
@@ -22,6 +22,7 @@ type DecisionRecord struct {
InputPrompt string `json:"input_prompt"`
CoTTrace string `json:"cot_trace"`
DecisionJSON string `json:"decision_json"`
RawResponse string `json:"raw_response"` // Raw AI response for debugging
CandidateCoins []string `json:"candidate_coins"`
ExecutionLog []string `json:"execution_log"`
Success bool `json:"success"`
@@ -90,6 +91,7 @@ func (s *DecisionStore) initTables() error {
input_prompt TEXT DEFAULT '',
cot_trace TEXT DEFAULT '',
decision_json TEXT DEFAULT '',
raw_response TEXT DEFAULT '',
candidate_coins TEXT DEFAULT '',
execution_log TEXT DEFAULT '',
success BOOLEAN DEFAULT 0,
@@ -108,6 +110,9 @@ func (s *DecisionStore) initTables() error {
}
}
// Migration: add raw_response column if not exists
s.db.Exec(`ALTER TABLE decision_records ADD COLUMN raw_response TEXT DEFAULT ''`)
return nil
}
@@ -127,13 +132,13 @@ func (s *DecisionStore) LogDecision(record *DecisionRecord) error {
result, err := s.db.Exec(`
INSERT INTO decision_records (
trader_id, cycle_number, timestamp, system_prompt, input_prompt,
cot_trace, decision_json, candidate_coins, execution_log,
cot_trace, decision_json, raw_response, candidate_coins, execution_log,
success, error_message, ai_request_duration_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`,
record.TraderID, record.CycleNumber, record.Timestamp.Format(time.RFC3339),
record.SystemPrompt, record.InputPrompt, record.CoTTrace, record.DecisionJSON,
string(candidateCoinsJSON), string(executionLogJSON),
record.RawResponse, string(candidateCoinsJSON), string(executionLogJSON),
record.Success, record.ErrorMessage, record.AIRequestDurationMs,
)
if err != nil {
+1
View File
@@ -402,6 +402,7 @@ func (at *AutoTrader) runCycle() error {
record.SystemPrompt = aiDecision.SystemPrompt // Save system prompt
record.InputPrompt = aiDecision.UserPrompt
record.CoTTrace = aiDecision.CoTTrace
record.RawResponse = aiDecision.RawResponse // Save raw AI response for debugging
if len(aiDecision.Decisions) > 0 {
decisionJSON, _ := json.MarshalIndent(aiDecision.Decisions, "", " ")
record.DecisionJSON = string(decisionJSON)