mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-20 11:07:32 +08:00
fix model
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
"defaults": {
|
"defaults": {
|
||||||
"workspace": "~/.clawgo/workspace",
|
"workspace": "~/.clawgo/workspace",
|
||||||
"model": "glm-4.7",
|
"model": "glm-4.7",
|
||||||
|
"model_fallbacks": ["gpt-4o-mini", "deepseek-chat"],
|
||||||
"max_tokens": 8192,
|
"max_tokens": 8192,
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
"max_tool_iterations": 20
|
"max_tool_iterations": 20
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type AgentLoop struct {
|
|||||||
provider providers.LLMProvider
|
provider providers.LLMProvider
|
||||||
workspace string
|
workspace string
|
||||||
model string
|
model string
|
||||||
|
modelFallbacks []string
|
||||||
maxIterations int
|
maxIterations int
|
||||||
sessions *session.SessionManager
|
sessions *session.SessionManager
|
||||||
contextBuilder *ContextBuilder
|
contextBuilder *ContextBuilder
|
||||||
@@ -99,6 +100,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
|
|||||||
provider: provider,
|
provider: provider,
|
||||||
workspace: workspace,
|
workspace: workspace,
|
||||||
model: cfg.Agents.Defaults.Model,
|
model: cfg.Agents.Defaults.Model,
|
||||||
|
modelFallbacks: cfg.Agents.Defaults.ModelFallbacks,
|
||||||
maxIterations: cfg.Agents.Defaults.MaxToolIterations,
|
maxIterations: cfg.Agents.Defaults.MaxToolIterations,
|
||||||
sessions: sessionsManager,
|
sessions: sessionsManager,
|
||||||
contextBuilder: NewContextBuilder(workspace, func() []string { return toolsRegistry.GetSummaries() }),
|
contextBuilder: NewContextBuilder(workspace, func() []string { return toolsRegistry.GetSummaries() }),
|
||||||
@@ -247,7 +249,7 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
|
|||||||
"tools_json": formatToolsForLog(providerToolDefs),
|
"tools_json": formatToolsForLog(providerToolDefs),
|
||||||
})
|
})
|
||||||
|
|
||||||
response, err := al.provider.Chat(ctx, messages, providerToolDefs, al.model, map[string]interface{}{
|
response, err := al.callLLMWithModelFallback(ctx, messages, providerToolDefs, map[string]interface{}{
|
||||||
"max_tokens": 8192,
|
"max_tokens": 8192,
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
})
|
})
|
||||||
@@ -347,13 +349,13 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
|
|||||||
}
|
}
|
||||||
|
|
||||||
al.sessions.AddMessage(msg.SessionKey, "user", msg.Content)
|
al.sessions.AddMessage(msg.SessionKey, "user", msg.Content)
|
||||||
|
|
||||||
// 使用 AddMessageFull 存储包含思考过程或工具调用的完整助手消息
|
// 使用 AddMessageFull 存储包含思考过程或工具调用的完整助手消息
|
||||||
al.sessions.AddMessageFull(msg.SessionKey, providers.Message{
|
al.sessions.AddMessageFull(msg.SessionKey, providers.Message{
|
||||||
Role: "assistant",
|
Role: "assistant",
|
||||||
Content: userContent,
|
Content: userContent,
|
||||||
})
|
})
|
||||||
|
|
||||||
al.sessions.Save(al.sessions.GetOrCreate(msg.SessionKey))
|
al.sessions.Save(al.sessions.GetOrCreate(msg.SessionKey))
|
||||||
|
|
||||||
// Log response preview (original content)
|
// Log response preview (original content)
|
||||||
@@ -457,7 +459,7 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe
|
|||||||
"tools_json": formatToolsForLog(providerToolDefs),
|
"tools_json": formatToolsForLog(providerToolDefs),
|
||||||
})
|
})
|
||||||
|
|
||||||
response, err := al.provider.Chat(ctx, messages, providerToolDefs, al.model, map[string]interface{}{
|
response, err := al.callLLMWithModelFallback(ctx, messages, providerToolDefs, map[string]interface{}{
|
||||||
"max_tokens": 8192,
|
"max_tokens": 8192,
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
})
|
})
|
||||||
@@ -519,7 +521,7 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe
|
|||||||
|
|
||||||
// Save to session with system message marker
|
// Save to session with system message marker
|
||||||
al.sessions.AddMessage(sessionKey, "user", fmt.Sprintf("[System: %s] %s", msg.SenderID, msg.Content))
|
al.sessions.AddMessage(sessionKey, "user", fmt.Sprintf("[System: %s] %s", msg.SenderID, msg.Content))
|
||||||
|
|
||||||
// 如果 finalContent 中没有包含 tool calls (即最后一次 LLM 返回的结果)
|
// 如果 finalContent 中没有包含 tool calls (即最后一次 LLM 返回的结果)
|
||||||
// 我们已经通过循环内部的 AddMessageFull 存储了前面的步骤
|
// 我们已经通过循环内部的 AddMessageFull 存储了前面的步骤
|
||||||
// 这里的 AddMessageFull 会存储最终回复
|
// 这里的 AddMessageFull 会存储最终回复
|
||||||
@@ -527,7 +529,7 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe
|
|||||||
Role: "assistant",
|
Role: "assistant",
|
||||||
Content: finalContent,
|
Content: finalContent,
|
||||||
})
|
})
|
||||||
|
|
||||||
al.sessions.Save(al.sessions.GetOrCreate(sessionKey))
|
al.sessions.Save(al.sessions.GetOrCreate(sessionKey))
|
||||||
|
|
||||||
logger.InfoCF("agent", "System message processing completed",
|
logger.InfoCF("agent", "System message processing completed",
|
||||||
@@ -602,6 +604,92 @@ func formatMessagesForLog(messages []providers.Message) string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (al *AgentLoop) callLLMWithModelFallback(
|
||||||
|
ctx context.Context,
|
||||||
|
messages []providers.Message,
|
||||||
|
tools []providers.ToolDefinition,
|
||||||
|
options map[string]interface{},
|
||||||
|
) (*providers.LLMResponse, error) {
|
||||||
|
candidates := al.modelCandidates()
|
||||||
|
var lastErr error
|
||||||
|
|
||||||
|
for idx, model := range candidates {
|
||||||
|
response, err := al.provider.Chat(ctx, messages, tools, model, options)
|
||||||
|
if err == nil {
|
||||||
|
if al.model != model {
|
||||||
|
logger.WarnCF("agent", "Model switched after quota/rate-limit error", map[string]interface{}{
|
||||||
|
"from_model": al.model,
|
||||||
|
"to_model": model,
|
||||||
|
})
|
||||||
|
al.model = model
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lastErr = err
|
||||||
|
if !isQuotaOrRateLimitError(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx < len(candidates)-1 {
|
||||||
|
logger.WarnCF("agent", "Model quota/rate-limit reached, trying fallback model", map[string]interface{}{
|
||||||
|
"failed_model": model,
|
||||||
|
"next_model": candidates[idx+1],
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("all configured models failed; last error: %w", lastErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (al *AgentLoop) modelCandidates() []string {
|
||||||
|
candidates := []string{}
|
||||||
|
seen := map[string]bool{}
|
||||||
|
|
||||||
|
add := func(model string) {
|
||||||
|
m := strings.TrimSpace(model)
|
||||||
|
if m == "" || seen[m] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seen[m] = true
|
||||||
|
candidates = append(candidates, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(al.model)
|
||||||
|
for _, m := range al.modelFallbacks {
|
||||||
|
add(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidates
|
||||||
|
}
|
||||||
|
|
||||||
|
func isQuotaOrRateLimitError(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := strings.ToLower(err.Error())
|
||||||
|
keywords := []string{
|
||||||
|
"status 429",
|
||||||
|
"429",
|
||||||
|
"insufficient_quota",
|
||||||
|
"quota",
|
||||||
|
"rate limit",
|
||||||
|
"rate_limit",
|
||||||
|
"too many requests",
|
||||||
|
"billing",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, keyword := range keywords {
|
||||||
|
if strings.Contains(msg, keyword) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// formatToolsForLog formats tool definitions for logging
|
// formatToolsForLog formats tool definitions for logging
|
||||||
func formatToolsForLog(tools []providers.ToolDefinition) string {
|
func formatToolsForLog(tools []providers.ToolDefinition) string {
|
||||||
if len(tools) == 0 {
|
if len(tools) == 0 {
|
||||||
|
|||||||
@@ -24,11 +24,12 @@ type AgentsConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AgentDefaults struct {
|
type AgentDefaults struct {
|
||||||
Workspace string `json:"workspace" env:"CLAWGO_AGENTS_DEFAULTS_WORKSPACE"`
|
Workspace string `json:"workspace" env:"CLAWGO_AGENTS_DEFAULTS_WORKSPACE"`
|
||||||
Model string `json:"model" env:"CLAWGO_AGENTS_DEFAULTS_MODEL"`
|
Model string `json:"model" env:"CLAWGO_AGENTS_DEFAULTS_MODEL"`
|
||||||
MaxTokens int `json:"max_tokens" env:"CLAWGO_AGENTS_DEFAULTS_MAX_TOKENS"`
|
ModelFallbacks []string `json:"model_fallbacks" env:"CLAWGO_AGENTS_DEFAULTS_MODEL_FALLBACKS"`
|
||||||
Temperature float64 `json:"temperature" env:"CLAWGO_AGENTS_DEFAULTS_TEMPERATURE"`
|
MaxTokens int `json:"max_tokens" env:"CLAWGO_AGENTS_DEFAULTS_MAX_TOKENS"`
|
||||||
MaxToolIterations int `json:"max_tool_iterations" env:"CLAWGO_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"`
|
Temperature float64 `json:"temperature" env:"CLAWGO_AGENTS_DEFAULTS_TEMPERATURE"`
|
||||||
|
MaxToolIterations int `json:"max_tool_iterations" env:"CLAWGO_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelsConfig struct {
|
type ChannelsConfig struct {
|
||||||
@@ -83,10 +84,10 @@ type QQConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DingTalkConfig struct {
|
type DingTalkConfig struct {
|
||||||
Enabled bool `json:"enabled" env:"CLAWGO_CHANNELS_DINGTALK_ENABLED"`
|
Enabled bool `json:"enabled" env:"CLAWGO_CHANNELS_DINGTALK_ENABLED"`
|
||||||
ClientID string `json:"client_id" env:"CLAWGO_CHANNELS_DINGTALK_CLIENT_ID"`
|
ClientID string `json:"client_id" env:"CLAWGO_CHANNELS_DINGTALK_CLIENT_ID"`
|
||||||
ClientSecret string `json:"client_secret" env:"CLAWGO_CHANNELS_DINGTALK_CLIENT_SECRET"`
|
ClientSecret string `json:"client_secret" env:"CLAWGO_CHANNELS_DINGTALK_CLIENT_SECRET"`
|
||||||
AllowFrom []string `json:"allow_from" env:"CLAWGO_CHANNELS_DINGTALK_ALLOW_FROM"`
|
AllowFrom []string `json:"allow_from" env:"CLAWGO_CHANNELS_DINGTALK_ALLOW_FROM"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProvidersConfig struct {
|
type ProvidersConfig struct {
|
||||||
@@ -171,6 +172,7 @@ func DefaultConfig() *Config {
|
|||||||
Defaults: AgentDefaults{
|
Defaults: AgentDefaults{
|
||||||
Workspace: filepath.Join(configDir, "workspace"),
|
Workspace: filepath.Join(configDir, "workspace"),
|
||||||
Model: "glm-4.7",
|
Model: "glm-4.7",
|
||||||
|
ModelFallbacks: []string{},
|
||||||
MaxTokens: 8192,
|
MaxTokens: 8192,
|
||||||
Temperature: 0.7,
|
Temperature: 0.7,
|
||||||
MaxToolIterations: 20,
|
MaxToolIterations: 20,
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ func (p *HTTPProvider) Chat(ctx context.Context, messages []Message, tools []Too
|
|||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return nil, fmt.Errorf("API error: %s", string(body))
|
return nil, fmt.Errorf("API error (status %d): %s", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.parseResponse(body)
|
return p.parseResponse(body)
|
||||||
|
|||||||
Reference in New Issue
Block a user