feat: 调用链接入引用解析,计价按系统模型 id

- ModelCall/ModelCallStream:GetNotTenantId 后 resolveModelConfig,modelBillable 改 modelInfo.Id
- 异步 task_end:轮询/计价用解析后系统模型配置,calcModelCost 改 modelInfo.Id

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-29 14:37:15 +08:00
co-authored by Claude
parent bc78ad2b2f
commit b99f43b31f
2 changed files with 33 additions and 8 deletions
+22 -6
View File
@@ -30,7 +30,15 @@ func (s *modelCallService) ModelCall(ctx context.Context, req *dto.ModelCallReq)
if err != nil {
return nil, fmt.Errorf("获取模型配置失败: %v", err)
}
if modelInfo == nil || (modelInfo.Enabled != nil && !*modelInfo.Enabled) {
if modelInfo == nil {
return nil, fmt.Errorf("模型不存在")
}
// 引用行 → 解析为系统模型配置+本人 apiKey;系统模型已删除等解析失败 → 阻塞调用
modelInfo, err = resolveModelConfig(ctx, modelInfo)
if err != nil {
return nil, err
}
if modelInfo.Enabled != nil && !*modelInfo.Enabled {
return nil, fmt.Errorf("模型不存在或未启用")
}
@@ -39,8 +47,8 @@ func (s *modelCallService) ModelCall(ctx context.Context, req *dto.ModelCallReq)
if err != nil {
return
}
// 调用前检查模型计价配置(shop-user-trade):未配置/未启用 → 阻塞调用
if err = modelBillable(ctx, req.ModelId); err != nil {
// 调用前检查模型计价配置(shop-user-trade):未配置/未启用 → 阻塞调用subject=解析后的系统模型 id)
if err = modelBillable(ctx, modelInfo.Id); err != nil {
return nil, err
}
err = queue(ctx, modelInfo.ModelName, userInfo.TenantId, gconv.Int64(modelInfo.MaxConcurrency), func(ctx context.Context) (err error) {
@@ -101,7 +109,15 @@ func (s *modelCallService) ModelCallStream(ctx context.Context, w http.ResponseW
if err != nil {
return fmt.Errorf("获取模型配置失败: %v", err)
}
if modelInfo == nil || (modelInfo.Enabled != nil && !*modelInfo.Enabled) {
if modelInfo == nil {
return fmt.Errorf("模型不存在")
}
// 引用行 → 解析为系统模型配置+本人 apiKey;系统模型已删除等解析失败 → 阻塞调用
modelInfo, err = resolveModelConfig(ctx, modelInfo)
if err != nil {
return err
}
if modelInfo.Enabled != nil && !*modelInfo.Enabled {
return fmt.Errorf("模型不存在或未启用")
}
if *modelInfo.ResponseType == *model.ResponseTypeStream.Code() {
@@ -110,8 +126,8 @@ func (s *modelCallService) ModelCallStream(ctx context.Context, w http.ResponseW
if err != nil {
return err
}
// 调用前检查模型计价配置(shop-user-trade):未配置/未启用 → 阻塞调用
if err = modelBillable(ctx, req.ModelId); err != nil {
// 调用前检查模型计价配置(shop-user-trade):未配置/未启用 → 阻塞调用subject=解析后的系统模型 id)
if err = modelBillable(ctx, modelInfo.Id); err != nil {
return err
}
err = queue(ctx, modelInfo.ModelName, userInfo.TenantId, gconv.Int64(modelInfo.MaxConcurrency), func(ctx context.Context) (err error) {
+11 -2
View File
@@ -198,6 +198,15 @@ func (s *modelTaskEndService) processClaimedTask(asyncCtx context.Context, item
return nil
}
// 引用行 → 解析为系统模型配置+本人 apiKey(轮询/计价均用系统模型)
modelInfo, err = resolveModelConfig(asyncCtx, modelInfo)
if err != nil {
g.Log().Errorf(asyncCtx, "模型配置解析失败: modelId=%d err=%v", item.ModelId, err)
docMsg.ErrorMsg = fmt.Sprintf("模型配置解析失败: %v", err)
finalize()
return nil
}
// 连续轮询失败上限:瞬时抖动(HTTP 错/空响应/解析失败)先有限重试,超限按终态错误落库
const maxPollErrRetries = 3
pollErrCnt := 0
@@ -281,8 +290,8 @@ LOOP:
docMsg.PromptTokens = gconv.Int64(modelUtils.GetByPathValue(respObj, promptTokPath))
docMsg.CompletionTokens = gconv.Int64(modelUtils.GetByPathValue(respObj, compTokPath))
// 调 shop-user-trade 按用量算费(媒体类型取任务创建时的快照)
docMsg.Cost = calcModelCost(asyncCtx, item.ModelId,
// 调 shop-user-trade 按用量算费(媒体类型取任务创建时的快照subject=解析后的系统模型 id
docMsg.Cost = calcModelCost(asyncCtx, modelInfo.Id,
buildModelUsage(docMsg.PromptTokens, docMsg.CompletionTokens, 0, item.MediaType, time.Since(startTime).Seconds()))
// 判断任务状态,轮询等待