From 463a092a6415c34dfbec1417e3099b8b17ecab58 Mon Sep 17 00:00:00 2001 From: darkedge <39146020@qq.com> Date: Tue, 11 Nov 2025 09:18:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0AI=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E8=80=97=E6=97=B6=E8=AE=B0=E5=BD=95=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E8=AF=84=E4=BC=B0=20(#587)=20#=20Conflicts:?= =?UTF-8?q?=20#=09decision/engine.go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- decision/engine.go | 14 ++++++++++++++ logger/decision_logger.go | 2 ++ trader/auto_trader.go | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/decision/engine.go b/decision/engine.go index a4d9132c..56633b58 100644 --- a/decision/engine.go +++ b/decision/engine.go @@ -8,6 +8,7 @@ import ( "nofx/mcp" "nofx/pool" "regexp" + "strconv" "strings" "time" ) @@ -114,6 +115,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的完整交易决策(批量分析所有币种和持仓) @@ -133,13 +136,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) } diff --git a/logger/decision_logger.go b/logger/decision_logger.go index e0be8d05..81ae52ef 100644 --- a/logger/decision_logger.go +++ b/logger/decision_logger.go @@ -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 账户状态快照 diff --git a/trader/auto_trader.go b/trader/auto_trader.go index e118fd7e..a059c377 100644 --- a/trader/auto_trader.go +++ b/trader/auto_trader.go @@ -459,6 +459,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 // 保存系统提示词