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:
@@ -25,10 +25,11 @@ var ErrModelNotRequired = fmt.Errorf("model not required, caller should degrade
|
||||
|
||||
// ModelSelector routes requests to the best available LLMProvider based on purpose.
|
||||
type ModelSelector struct {
|
||||
loader *config.Loader
|
||||
envCfg OpenAIConfig
|
||||
mu sync.RWMutex
|
||||
cache map[string]LLMProvider
|
||||
loader *config.Loader
|
||||
envCfg OpenAIConfig
|
||||
mu sync.RWMutex
|
||||
cache map[string]LLMProvider
|
||||
cachedEnv LLMProvider // cached env fallback, created once
|
||||
}
|
||||
|
||||
// NewModelSelector creates a ModelSelector. If loader is nil or has no config,
|
||||
@@ -81,7 +82,12 @@ func (s *ModelSelector) DefaultAdapter() *Adapter {
|
||||
}
|
||||
|
||||
func (s *ModelSelector) envProvider() LLMProvider {
|
||||
return NewOpenAIProvider(s.envCfg)
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.cachedEnv == nil {
|
||||
s.cachedEnv = NewOpenAIProvider(s.envCfg)
|
||||
}
|
||||
return s.cachedEnv
|
||||
}
|
||||
|
||||
func (s *ModelSelector) getOrCreateProvider(modelID string, cfg *config.ModelsConfigData) (LLMProvider, error) {
|
||||
|
||||
Reference in New Issue
Block a user