feat: LLM 调用日志 + ModelSelector 优化 + devtools.bat 编码修复

- 新增 call_log.go: 全局环形缓冲区记录每次 LLM 调用(模型/Token/耗时/错误)
- OpenAIProvider.doChat/ChatStreamWithTools 自动记录调用日志
- ai-core 暴露 GET /api/v1/llm-calls 端点, DevTools 代理 + UI 面板
- ModelSelector.envProvider 改为单例缓存, 避免重复创建 HTTP Client
- 新增 PurposeToolCalling 适配器, 后台思考工具调用走专用路由
- envFallback 超时 120s→180s, 显式设置 MaxRetries
- devtools.bat 全英文, 解决 Windows CMD GBK 编码乱码问题

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 15:44:53 +08:00
parent 7eb5e984c2
commit 47f9de2409
8 changed files with 266 additions and 22 deletions
@@ -43,6 +43,7 @@ type Thinker struct {
personaLoader *persona.Loader
memRetriever *memory.Retriever
llmAdapter *llm.Adapter
toolAdapter *llm.Adapter // 工具调用专用适配器
iotClient *tools.IoTClient
// 记忆管理
@@ -224,6 +225,7 @@ func NewThinker(
personaLoader *persona.Loader,
memRetriever *memory.Retriever,
llmAdapter *llm.Adapter,
toolAdapter *llm.Adapter,
iotClient *tools.IoTClient,
memoryStore *memory.Store,
toolRegistry *tools.Registry,
@@ -237,6 +239,7 @@ func NewThinker(
personaLoader: personaLoader,
memRetriever: memRetriever,
llmAdapter: llmAdapter,
toolAdapter: toolAdapter,
iotClient: iotClient,
thinkInterval: cfg.ThinkInterval,
silenceTimeout: cfg.SilenceTimeout,
@@ -598,7 +601,7 @@ func (t *Thinker) performThink(triggerReason string) {
var toolCallRecords []map[string]interface{}
for round := 0; round <= maxToolRounds; round++ {
resp, err := t.llmAdapter.ChatWithTools(ctx, messages, openAITools)
resp, err := t.toolAdapter.ChatWithTools(ctx, messages, openAITools)
if err != nil {
log.Printf("[后台思考] LLM调用失败 (round=%d): %v", round, err)
return