feat: 优化模型配置管理 - 动态使用优先级最高的Provider

## 主要改进

### 1. 数据库驱动的模型配置
- 新增 GetActiveProviderWithModel() 方法,从数据库获取优先级最高的 Provider 及其默认模型
- 支持多 Provider 配置,通过 priority 字段控制优先级
- 实现 5 分钟缓存机制,减少数据库查询

### 2. 应用模型配置优化
- 移除应用层硬编码模型配置
- 应用自动使用优先级最高的 Provider 的默认模型
- 支持应用级模型覆盖(可选)

### 3. 工具脚本
- check-providers: 查询数据库中的 Provider 和应用配置
- fix-providers: 修复 Provider 配置(补全 config 和 models 字段)
- clear-app-models: 清空应用硬编码模型配置

### 4. 代码质量
- 删除未使用的 getProvider() 方法
- 修复 fmt.Println 冗余换行警告
- 统一代码格式

## 技术细节

**降级策略**:
数据库 Provider (优先级) → 环境变量 Provider → 应用配置模型

**当前配置**:
- 优先级 110: 本地LLM (qwen2.5-7b-instruct)
- 优先级 100: 阿里云百炼 (qwen-plus)

所有 41 个应用现在自动使用本地模型,无需手动配置。
This commit is contained in:
selfrelease
2026-06-22 18:46:44 +08:00
parent 0c1a8544e8
commit 96930b585c
8 changed files with 468 additions and 65 deletions
+133
View File
@@ -0,0 +1,133 @@
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/joho/godotenv"
)
func main() {
// 加载环境变量
_ = godotenv.Load("../../.env")
dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" {
dbURL = "postgres://freedak:@localhost:5432/govai_portal?sslmode=disable"
}
pool, err := pgxpool.New(context.Background(), dbURL)
if err != nil {
log.Fatalf("无法连接数据库: %v", err)
}
defer pool.Close()
fmt.Println("=== 数据库中的模型提供商配置 ===")
rows, err := pool.Query(context.Background(), `
SELECT id, name, base_url,
SUBSTRING(api_key_encrypted, 1, 20) as api_key_prefix,
models, is_active, priority, config
FROM model_providers
ORDER BY priority DESC, created_at
`)
if err != nil {
log.Fatalf("查询失败: %v", err)
}
defer rows.Close()
count := 0
for rows.Next() {
var id, name, baseURL, apiKeyPrefix string
var modelsJSON, configJSON []byte
var isActive bool
var priority int
err := rows.Scan(&id, &name, &baseURL, &apiKeyPrefix, &modelsJSON, &isActive, &priority, &configJSON)
if err != nil {
log.Printf("扫描行失败: %v", err)
continue
}
count++
fmt.Printf("【提供商 %d】\n", count)
fmt.Printf("ID: %s\n", id)
fmt.Printf("名称: %s\n", name)
fmt.Printf("Base URL: %s\n", baseURL)
fmt.Printf("API Key: %s...\n", apiKeyPrefix)
fmt.Printf("激活状态: %v\n", isActive)
fmt.Printf("优先级: %d\n", priority)
// 解析 models
var models []map[string]interface{}
if err := json.Unmarshal(modelsJSON, &models); err == nil {
fmt.Printf("可用模型: ")
for i, m := range models {
if i > 0 {
fmt.Print(", ")
}
fmt.Printf("%v", m["id"])
}
fmt.Println()
}
// 解析 config
var config map[string]interface{}
if err := json.Unmarshal(configJSON, &config); err == nil {
fmt.Printf("Provider 类型: %v\n", config["provider"])
fmt.Printf("默认模型: %v\n", config["default_model"])
}
fmt.Println()
}
if count == 0 {
fmt.Println("❌ 数据库中没有任何模型提供商配置")
fmt.Println("提示: 运行种子数据脚本来初始化配置")
} else {
fmt.Printf("✅ 共找到 %d 个提供商配置\n", count)
}
// 查询应用配置中的模型使用情况
fmt.Println("\n=== 应用配置中的模型使用情况 ===")
appRows, err := pool.Query(context.Background(), `
SELECT name,
COALESCE(app_config->>'model', '未配置') as model,
status
FROM applications
WHERE status = 'approved'
ORDER BY created_at DESC
LIMIT 10
`)
if err != nil {
log.Printf("查询应用失败: %v", err)
return
}
defer appRows.Close()
appCount := 0
modelStats := make(map[string]int)
for appRows.Next() {
var name, model, status string
if err := appRows.Scan(&name, &model, &status); err != nil {
continue
}
appCount++
modelStats[model]++
fmt.Printf("应用: %-30s | 模型: %-15s | 状态: %s\n", name, model, status)
}
if appCount > 0 {
fmt.Printf("\n✅ 共查询到 %d 个已批准的应用\n\n", appCount)
fmt.Println("模型使用统计:")
for model, count := range modelStats {
fmt.Printf(" - %-15s: %d 个应用\n", model, count)
}
}
}
+112
View File
@@ -0,0 +1,112 @@
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/joho/godotenv"
)
func main() {
// 加载环境变量
_ = godotenv.Load("../../.env")
dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" {
dbURL = "postgres://freedak:@localhost:5432/govai_portal?sslmode=disable"
}
pool, err := pgxpool.New(context.Background(), dbURL)
if err != nil {
log.Fatalf("无法连接数据库: %v", err)
}
defer pool.Close()
fmt.Println("=== 清空应用硬编码模型配置 ===")
fmt.Println("目标:让所有应用自动使用优先级最高的 Provider 的默认模型")
// 1. 查看当前状态
fmt.Println("【步骤1】查看当前应用模型配置...")
var totalApps, configuredApps int
err = pool.QueryRow(context.Background(), `
SELECT
COUNT(*) as total,
COUNT(CASE WHEN app_config->>'model' IS NOT NULL AND app_config->>'model' != '' THEN 1 END) as configured
FROM applications
WHERE status = 'approved'
`).Scan(&totalApps, &configuredApps)
if err != nil {
log.Fatalf("查询失败: %v", err)
}
fmt.Printf(" - 已批准应用总数: %d\n", totalApps)
fmt.Printf(" - 配置了模型的应用: %d\n", configuredApps)
fmt.Printf(" - 未配置模型的应用: %d\n\n", totalApps-configuredApps)
// 2. 清空所有应用的模型配置
fmt.Println("【步骤2】清空所有应用的模型配置...")
result, err := pool.Exec(context.Background(), `
UPDATE applications
SET app_config = app_config - 'model'
WHERE status = 'approved'
AND app_config ? 'model'
`)
if err != nil {
log.Fatalf("更新失败: %v", err)
}
rowsAffected := result.RowsAffected()
fmt.Printf("✅ 已清空 %d 个应用的模型配置\n\n", rowsAffected)
// 3. 验证结果
fmt.Println("【步骤3】验证结果...")
var remainingConfigured int
err = pool.QueryRow(context.Background(), `
SELECT COUNT(*)
FROM applications
WHERE status = 'approved'
AND app_config->>'model' IS NOT NULL
AND app_config->>'model' != ''
`).Scan(&remainingConfigured)
if err != nil {
log.Fatalf("验证查询失败: %v", err)
}
if remainingConfigured == 0 {
fmt.Println("✅ 所有应用的模型配置已清空")
} else {
fmt.Printf("⚠️ 还有 %d 个应用仍有模型配置\n", remainingConfigured)
}
// 4. 显示当前优先级最高的 Provider
fmt.Println("\n【步骤4】当前优先级最高的 Provider...")
var providerName, defaultModel string
var priority int
err = pool.QueryRow(context.Background(), `
SELECT name, COALESCE(config->>'default_model', '未配置'), priority
FROM model_providers
WHERE is_active = true
ORDER BY priority DESC, created_at
LIMIT 1
`).Scan(&providerName, &defaultModel, &priority)
if err != nil {
log.Printf("查询 Provider 失败: %v", err)
} else {
fmt.Printf(" Provider: %s\n", providerName)
fmt.Printf(" 默认模型: %s\n", defaultModel)
fmt.Printf(" 优先级: %d\n", priority)
}
fmt.Println("\n=== 配置清理完成 ===")
fmt.Println("\n说明:")
fmt.Println(" - 现在所有应用将自动使用优先级最高的 Provider 的默认模型")
fmt.Println(" - 当前会使用: " + providerName + " / " + defaultModel)
fmt.Println(" - 如需特殊应用使用指定模型,可在应用配置中单独设置")
}
+113
View File
@@ -0,0 +1,113 @@
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/joho/godotenv"
)
func main() {
// 加载环境变量
_ = godotenv.Load("../../.env")
dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" {
dbURL = "postgres://freedak:@localhost:5432/govai_portal?sslmode=disable"
}
pool, err := pgxpool.New(context.Background(), dbURL)
if err != nil {
log.Fatalf("无法连接数据库: %v", err)
}
defer pool.Close()
fmt.Println("=== 开始修复数据库配置 ===")
// 1. 修复本地模型配置
fmt.Println("【任务1】修复本地模型配置...")
result, err := pool.Exec(context.Background(), `
UPDATE model_providers
SET config = '{
"provider": "openai",
"default_model": "qwen2.5-7b-instruct",
"supports_streaming": true,
"supports_function_calling": false
}'::jsonb,
models = '[
{"id": "qwen2.5-7b-instruct", "name": "Qwen2.5-7B-Instruct", "type": "chat"}
]'::jsonb
WHERE name = '本地LLM (Qwen2.5-7B)'
`)
if err != nil {
log.Printf("❌ 修复本地模型失败: %v", err)
} else {
rowsAffected := result.RowsAffected()
if rowsAffected > 0 {
fmt.Printf("✅ 成功修复本地模型配置 (影响 %d 行)\n\n", rowsAffected)
} else {
fmt.Println("⚠️ 未找到本地模型记录")
}
}
// 2. 为未配置模型的应用设置默认模型
fmt.Println("【任务2】为未配置模型的应用设置默认模型...")
result, err = pool.Exec(context.Background(), `
UPDATE applications
SET app_config = jsonb_set(
COALESCE(app_config, '{}'::jsonb),
'{model}',
'"qwen2.5-7b-instruct"'
)
WHERE (app_config->>'model' IS NULL OR app_config->>'model' = '')
AND status = 'approved'
`)
if err != nil {
log.Printf("❌ 更新应用配置失败: %v", err)
} else {
rowsAffected := result.RowsAffected()
if rowsAffected > 0 {
fmt.Printf("✅ 成功为 %d 个应用设置默认模型\n\n", rowsAffected)
} else {
fmt.Println("ℹ️ 所有应用已配置模型")
}
}
// 3. 验证修复结果
fmt.Println("【验证】检查修复结果...")
var localConfig, localModels string
err = pool.QueryRow(context.Background(), `
SELECT
COALESCE(config::text, 'null') as config,
COALESCE(models::text, 'null') as models
FROM model_providers
WHERE name = '本地LLM (Qwen2.5-7B)'
`).Scan(&localConfig, &localModels)
if err != nil {
log.Printf("查询验证失败: %v", err)
} else {
fmt.Printf("本地模型 config: %s\n", localConfig)
fmt.Printf("本地模型 models: %s\n\n", localModels)
}
var unconfiguredCount int
err = pool.QueryRow(context.Background(), `
SELECT COUNT(*)
FROM applications
WHERE (app_config->>'model' IS NULL OR app_config->>'model' = '')
AND status = 'approved'
`).Scan(&unconfiguredCount)
if err != nil {
log.Printf("查询未配置应用数量失败: %v", err)
} else {
fmt.Printf("未配置模型的应用数量: %d\n", unconfiguredCount)
}
fmt.Println("\n=== 修复完成 ===")
}
+1 -1
View File
@@ -44,7 +44,7 @@ func newRouter(cfg *config.Config, pool *pgxpool.Pool, rdb *redis.Client) http.H
// LLM Manager — direct model calls replacing Dify for chat
llmMgr := llm.NewManager()
llmMgr.SetPool(pool)
// 优先从数据库加载 providers(如果失败,回退到环境变量配置)
if err := llmMgr.LoadProvidersFromDB(context.Background()); err != nil {
// 回退:使用环境变量配置
+21 -14
View File
@@ -27,13 +27,14 @@ func NewAnalysisTemplateHandler(pool *pgxpool.Pool, manager *llm.Manager, provid
return &AnalysisTemplateHandler{pool: pool, manager: manager, provider: provider}
}
// getProvider 获取当前激活的 provider
func (h *AnalysisTemplateHandler) getProvider(ctx context.Context) (llm.Provider, error) {
provider, err := h.manager.GetActiveProvider(ctx)
// getProviderWithModel 获取当前激活的 provider 及其默认模型
func (h *AnalysisTemplateHandler) getProviderWithModel(ctx context.Context) (llm.Provider, string, error) {
provider, defaultModel, err := h.manager.GetActiveProviderWithModel(ctx)
if err == nil {
return provider, nil
return provider, defaultModel, nil
}
return h.manager.GetProvider(h.provider)
provider, err = h.manager.GetProvider(h.provider)
return provider, "", err
}
func (h *AnalysisTemplateHandler) ListTemplates(w http.ResponseWriter, r *http.Request) {
@@ -234,8 +235,21 @@ func (h *AnalysisTemplateHandler) GenerateReport(w http.ResponseWriter, r *http.
}
}
// 获取激活的 provider 和默认模型
provider, defaultModel, err := h.getProviderWithModel(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
// 使用优先级:Provider 默认模型 > 应用配置模型
modelToUse := defaultModel
if modelToUse == "" {
modelToUse = appModel // 降级时使用应用配置
}
llmReq := &llm.ChatRequest{
Model: appModel,
Model: modelToUse,
Messages: []llm.Message{
{Role: llm.RoleSystem, Content: "你是一位资深的政务数据分析和研判专家。要求:1)基于提供的真实数据库数据进行分析 2)报告必须完整输出到最后一个章节,不能中途截断 3)保持精炼,每个章节500字以内 4)使用Markdown格式排版 5)表格数据必须引用真实数据 6)报告输出完毕后,必须在最后一行单独输出「---\\n\\n**【完稿】**」作为完成标记"},
{Role: llm.RoleUser, Content: prompt},
@@ -246,14 +260,7 @@ func (h *AnalysisTemplateHandler) GenerateReport(w http.ResponseWriter, r *http.
}
startTime := time.Now()
// 获取激活的 provider
provider, err := h.getProvider(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
body, err := h.manager.ChatStream(r.Context(), provider, llmReq)
if err != nil {
response.Error(w, http.StatusBadGateway, 50202, "模型服务不可用: "+err.Error())
+44 -26
View File
@@ -34,16 +34,17 @@ func NewLLMChatHandler(pool *pgxpool.Pool, manager *llm.Manager, defaultProvider
return &LLMChatHandler{pool: pool, manager: manager, provider: defaultProvider, rdb: rdb, workerURL: workerURL, embedder: embedder}
}
// getProvider 获取当前激活的 provider,优先从数据库读取
func (h *LLMChatHandler) getProvider(ctx context.Context) (llm.Provider, error) {
// 尝试从数据库获取激活的 provider
provider, err := h.manager.GetActiveProvider(ctx)
// getProviderWithModel 获取当前激活的 provider 及其默认模型
func (h *LLMChatHandler) getProviderWithModel(ctx context.Context) (llm.Provider, string, error) {
// 尝试从数据库获取激活的 provider 和默认模型
provider, defaultModel, err := h.manager.GetActiveProviderWithModel(ctx)
if err == nil {
return provider, nil
return provider, defaultModel, nil
}
// 降级到配置的 fallback provider
return h.manager.GetProvider(h.provider)
provider, err = h.manager.GetProvider(h.provider)
return provider, "", err // 降级时返回空模型,使用应用配置
}
type llmChatRequest struct {
@@ -568,8 +569,21 @@ func (h *LLMChatHandler) Chat(w http.ResponseWriter, r *http.Request) {
history = h.loadConversationHistory(r.Context(), appID, userID.String(), convID, 10)
}
// 获取激活的 provider 和默认模型
provider, defaultModel, err := h.getProviderWithModel(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
// 使用优先级:Provider 默认模型 > 应用配置模型
modelToUse := defaultModel
if modelToUse == "" {
modelToUse = cfg.Model // 降级时使用应用配置
}
llmReq := &llm.ChatRequest{
Model: cfg.Model,
Model: modelToUse,
Messages: h.buildMessages(cfg.SystemPrompt, knowledgeCtx, hasKB, history, req.Message, orgApps),
Temperature: cfg.Temp,
MaxTokens: cfg.MaxTok,
@@ -577,14 +591,7 @@ func (h *LLMChatHandler) Chat(w http.ResponseWriter, r *http.Request) {
}
startTime := time.Now()
// 获取激活的 provider
provider, err := h.getProvider(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
body, err := h.manager.ChatStream(r.Context(), provider, llmReq)
if err != nil {
response.Error(w, http.StatusBadGateway, 50202, "模型服务不可用: "+err.Error())
@@ -673,8 +680,21 @@ func (h *LLMChatHandler) Completion(w http.ResponseWriter, r *http.Request) {
// 加载同机构应用列表,用于超范围引导跳转
orgApps := h.loadSameOrgApps(r.Context(), cfg.OrgID, appID)
// 获取激活的 provider 和默认模型
provider, defaultModel, err := h.getProviderWithModel(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
// 使用优先级:Provider 默认模型 > 应用配置模型
modelToUse := defaultModel
if modelToUse == "" {
modelToUse = cfg.Model // 降级时使用应用配置
}
llmReq := &llm.ChatRequest{
Model: cfg.Model,
Model: modelToUse,
Messages: h.buildMessages(cfg.SystemPrompt, knowledgeCtx, hasKB, nil, req.Message, orgApps),
Temperature: cfg.Temp,
MaxTokens: cfg.MaxTok,
@@ -684,13 +704,6 @@ func (h *LLMChatHandler) Completion(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
convID := uuid.New().String()
// 获取激活的 provider
provider, err := h.getProvider(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
body, err := h.manager.ChatStream(r.Context(), provider, llmReq)
if err != nil {
response.Error(w, http.StatusBadGateway, 50202, "模型服务不可用: "+err.Error())
@@ -1176,13 +1189,18 @@ func (h *LLMChatHandler) generateConversationName(appID, userID, convID, userMes
Stream: false,
}
// 获取激活的 provider
provider, err := h.getProvider(ctx)
// 获取激活的 provider 和默认模型
provider, defaultModel, err := h.getProviderWithModel(ctx)
if err != nil {
log.Warn().Err(err).Msg("get provider for title generation failed")
return
}
// 使用 Provider 默认模型
if defaultModel != "" {
nameReq.Model = defaultModel
}
result, err := h.manager.Chat(ctx, provider, nameReq)
if err != nil {
return
+21 -14
View File
@@ -27,13 +27,14 @@ func NewDocTemplateHandler(pool *pgxpool.Pool, manager *llm.Manager, provider st
return &DocTemplateHandler{pool: pool, manager: manager, provider: provider}
}
// getProvider 获取当前激活的 provider
func (h *DocTemplateHandler) getProvider(ctx context.Context) (llm.Provider, error) {
provider, err := h.manager.GetActiveProvider(ctx)
// getProviderWithModel 获取当前激活的 provider 及其默认模型
func (h *DocTemplateHandler) getProviderWithModel(ctx context.Context) (llm.Provider, string, error) {
provider, defaultModel, err := h.manager.GetActiveProviderWithModel(ctx)
if err == nil {
return provider, nil
return provider, defaultModel, nil
}
return h.manager.GetProvider(h.provider)
provider, err = h.manager.GetProvider(h.provider)
return provider, "", err
}
func (h *DocTemplateHandler) ListTemplates(w http.ResponseWriter, r *http.Request) {
@@ -171,8 +172,21 @@ func (h *DocTemplateHandler) GenerateDocument(w http.ResponseWriter, r *http.Req
prompt = strings.ReplaceAll(prompt, "{{", "")
prompt = strings.ReplaceAll(prompt, "}}", "")
// 获取激活的 provider 和默认模型
provider, defaultModel, err := h.getProviderWithModel(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
// 使用优先级:Provider 默认模型 > 应用配置模型
modelToUse := defaultModel
if modelToUse == "" {
modelToUse = appModel // 降级时使用应用配置
}
llmReq := &llm.ChatRequest{
Model: appModel,
Model: modelToUse,
Messages: []llm.Message{
{Role: llm.RoleSystem, Content: "你是一个专业的政务公文写作专家,精通《党政机关公文格式》国家标准(GB/T 9704)和《党政机关公文处理工作条例》。请严格按照规范格式生成公文,确保行文庄重、严谨、准确。输出完整公文内容,使用Markdown格式排版。"},
{Role: llm.RoleUser, Content: prompt},
@@ -183,14 +197,7 @@ func (h *DocTemplateHandler) GenerateDocument(w http.ResponseWriter, r *http.Req
}
startTime := time.Now()
// 获取激活的 provider
provider, err := h.getProvider(r.Context())
if err != nil {
response.InternalError(w, "获取模型提供商失败")
return
}
body, err := h.manager.ChatStream(r.Context(), provider, llmReq)
if err != nil {
response.Error(w, http.StatusBadGateway, 50202, "模型服务不可用: "+err.Error())
+23 -10
View File
@@ -116,12 +116,18 @@ func (m *Manager) LoadProvidersFromDB(ctx context.Context) error {
// GetActiveProvider 获取优先级最高的激活 provider
func (m *Manager) GetActiveProvider(ctx context.Context) (Provider, error) {
provider, _, err := m.GetActiveProviderWithModel(ctx)
return provider, err
}
// GetActiveProviderWithModel 获取优先级最高的激活 provider 及其默认模型
func (m *Manager) GetActiveProviderWithModel(ctx context.Context) (Provider, string, error) {
if m.pool == nil {
// 如果没有数据库连接,使用注册的 fallback
if p, ok := m.providers[m.fallback]; ok {
return p, nil
return p, "", nil // 降级时返回空模型名,使用应用配置
}
return nil, fmt.Errorf("no active provider")
return nil, "", fmt.Errorf("no active provider")
}
// 从数据库获取优先级最高的激活 provider
@@ -135,21 +141,25 @@ func (m *Manager) GetActiveProvider(ctx context.Context) (Provider, error) {
LIMIT 1
`).Scan(&id, &baseURL, &apiKey, &configJSON)
if err != nil {
return nil, fmt.Errorf("query active provider: %w", err)
return nil, "", fmt.Errorf("query active provider: %w", err)
}
// 检查缓存
m.cacheMu.RLock()
if entry, ok := m.cache[id]; ok && time.Since(entry.updatedAt) < m.cacheTTL {
m.cacheMu.RUnlock()
return entry.provider, nil
// 从 config 中提取默认模型
var config map[string]any
json.Unmarshal(configJSON, &config)
defaultModel, _ := config["default_model"].(string)
return entry.provider, defaultModel, nil
}
m.cacheMu.RUnlock()
// 创建新的 provider
var config map[string]any
if err := json.Unmarshal(configJSON, &config); err != nil {
return nil, fmt.Errorf("unmarshal config: %w", err)
return nil, "", fmt.Errorf("unmarshal config: %w", err)
}
providerType, _ := config["provider"].(string)
@@ -157,6 +167,9 @@ func (m *Manager) GetActiveProvider(ctx context.Context) (Provider, error) {
providerType = "openai"
}
// 获取默认模型
defaultModel, _ := config["default_model"].(string)
var provider Provider
switch providerType {
case "openai":
@@ -164,7 +177,7 @@ func (m *Manager) GetActiveProvider(ctx context.Context) (Provider, error) {
case "anthropic":
provider = NewAnthropicProvider(apiKey, baseURL, "")
default:
return nil, fmt.Errorf("unsupported provider type: %s", providerType)
return nil, "", fmt.Errorf("unsupported provider type: %s", providerType)
}
// 更新缓存
@@ -175,7 +188,7 @@ func (m *Manager) GetActiveProvider(ctx context.Context) (Provider, error) {
}
m.cacheMu.Unlock()
return provider, nil
return provider, defaultModel, nil
}
func (m *Manager) GetProvider(name string) (Provider, error) {
@@ -208,9 +221,9 @@ type StreamEvent struct {
}
type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
Model string `json:"model"`
}