Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions decision/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"nofx/mcp"
"nofx/pool"
"regexp"
"strconv"
"strings"
"time"
)
Expand Down Expand Up @@ -109,6 +110,8 @@ type FullDecision struct {
CoTTrace string `json:"cot_trace"` // 思维链分析(AI输出)
Decisions []Decision `json:"decisions"` // 具体决策列表
Timestamp time.Time `json:"timestamp"`
// AIRequestDurationMs 记录 AI API 调用耗时(毫秒)方便排查延迟问题
AIRequestDurationMs int64 `json:"ai_request_duration_ms,omitempty"`
}

// GetFullDecision 获取AI的完整交易决策(批量分析所有币种和持仓)
Expand All @@ -128,13 +131,24 @@ func GetFullDecisionWithCustomPrompt(ctx *Context, mcpClient *mcp.Client, custom
userPrompt := buildUserPrompt(ctx)

// 3. 调用AI API(使用 system + user prompt)
aiCallStart := time.Now()
aiResponse, err := mcpClient.CallWithMessages(systemPrompt, userPrompt)
aiCallDuration := time.Since(aiCallStart)
if err != nil {
return nil, fmt.Errorf("调用AI API失败: %w", err)
}

// 4. 解析AI响应
decision, err := parseFullDecisionResponse(aiResponse, ctx.Account.TotalEquity, ctx.BTCETHLeverage, ctx.AltcoinLeverage)

// 无论是否有错误,都要保存 SystemPrompt 和 UserPrompt(用于调试和决策未执行后的问题定位)
if decision != nil {
decision.Timestamp = time.Now()
decision.SystemPrompt = systemPrompt // 保存系统prompt
decision.UserPrompt = userPrompt // 保存输入prompt
decision.AIRequestDurationMs = aiCallDuration.Milliseconds()
}

if err != nil {
return decision, fmt.Errorf("解析AI响应失败: %w", err)
}
Expand Down
2 changes: 2 additions & 0 deletions logger/decision_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type DecisionRecord struct {
ExecutionLog []string `json:"execution_log"` // 执行日志
Success bool `json:"success"` // 是否成功
ErrorMessage string `json:"error_message"` // 错误信息(如果有)
// AIRequestDurationMs 记录 AI API 调用耗时(毫秒),方便评估调用性能
AIRequestDurationMs int64 `json:"ai_request_duration_ms,omitempty"`
}

// AccountSnapshot 账户状态快照
Expand Down
7 changes: 7 additions & 0 deletions trader/auto_trader.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,13 @@ func (at *AutoTrader) runCycle() error {
log.Printf("🤖 正在请求AI分析并决策... [模板: %s]", at.systemPromptTemplate)
decision, err := decision.GetFullDecisionWithCustomPrompt(ctx, at.mcpClient, at.customPrompt, at.overrideBasePrompt, at.systemPromptTemplate)

if decision != nil && decision.AIRequestDurationMs > 0 {
record.AIRequestDurationMs = decision.AIRequestDurationMs
log.Printf("⏱️ AI调用耗时: %.2f 秒", float64(record.AIRequestDurationMs)/1000)
record.ExecutionLog = append(record.ExecutionLog,
fmt.Sprintf("AI调用耗时: %d ms", record.AIRequestDurationMs))
}

// 即使有错误,也保存思维链、决策和输入prompt(用于debug)
if decision != nil {
record.SystemPrompt = decision.SystemPrompt // 保存系统提示词
Expand Down