- 新增计费模块:执行开始建单、终态结算/取消/失败处理,支持按条/按秒/按token计费 - 新增执行生命周期跟踪:优雅关停时取消运行中执行并等待落库 - 新增异步任务等待/通知机制(Wait/Notify) - 重构执行记录落库与进度上报,统一失败分类与重试语义 - 重命名文件:async_task.go→async.go、flow_checkpoint_store.go→exec_checkpoint.go、flow_graph_util.go→exec_record.go - 更新 .gitignore 与数据库密码配置
91 lines
3.4 KiB
Go
91 lines
3.4 KiB
Go
package flow
|
|
|
|
import (
|
|
"ai-agent/gateway"
|
|
"ai-agent/workflow/consts/model"
|
|
"ai-agent/workflow/service/flow/processor"
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
)
|
|
|
|
// isVideoModel 判断模型是否为视频模型(模型类型 TypeVideo=600),用于视频节点多视频自动合成判断
|
|
func isVideoModel(ctx context.Context, modelId int64) bool {
|
|
modelInfo, err := gateway.GetModelInfoById(ctx, &gateway.GetModelInfoByIdReq{ModelId: modelId})
|
|
if err != nil {
|
|
g.Log().Warningf(ctx, "查询模型配置失败,跳过自动视频合成 modelId=%d err=%v", modelId, err)
|
|
return false
|
|
}
|
|
return modelInfo.ModelManage.ModelType != nil && *modelInfo.ModelManage.ModelType == model.TypeVideo
|
|
}
|
|
|
|
// invokePreTool 执行前置处理器,把模型请求参数转换为模型调用入参列表。
|
|
// 前置处理器契约:入参即模型请求参数本体;返回值:
|
|
// - map[string]any 一次模型调用,入参为返回值
|
|
// - []map[string]any 多次模型调用,逐个入参请求
|
|
// - nil 视为异常,节点失败(不允许静默跳过模型调用)
|
|
func invokePreTool(ctx context.Context, processorName string, modelParams map[string]any) (paramsList []map[string]any, err error) {
|
|
if processorName == "" {
|
|
return []map[string]any{stripInternalKeys(modelParams)}, nil
|
|
}
|
|
data, err := processor.Call(ctx, processorName, modelParams)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("执行前置处理器[%s]失败: %v", processorName, err)
|
|
}
|
|
switch v := data.(type) {
|
|
case nil:
|
|
return nil, fmt.Errorf("前置处理器[%s]返回空", processorName)
|
|
case map[string]any:
|
|
return []map[string]any{stripInternalKeys(v)}, nil
|
|
case []map[string]any:
|
|
list := make([]map[string]any, 0, len(v))
|
|
for _, m := range v {
|
|
list = append(list, stripInternalKeys(m))
|
|
}
|
|
return list, nil
|
|
default:
|
|
return nil, fmt.Errorf("前置处理器[%s]返回类型不支持: %T", processorName, data)
|
|
}
|
|
}
|
|
|
|
// stripInternalKeys 剥离 __ 前缀的内部键(如 __segment_fields/__produced),
|
|
// 模型网关做参数严格校验(CheckParams strictUnknown)会拒绝未知字段,内部标记不得随请求体下发。
|
|
func stripInternalKeys(params map[string]any) map[string]any {
|
|
if params == nil {
|
|
return params
|
|
}
|
|
for k := range params {
|
|
if strings.HasPrefix(k, "__") {
|
|
delete(params, k)
|
|
}
|
|
}
|
|
return params
|
|
}
|
|
|
|
// invokePostTool 执行后置处理器,加工模型调用结果。
|
|
// 后置处理器契约:入参 {"output": 模型输出结果列表, "request": 原始模型请求参数}(列表须包成对象传入);返回值:
|
|
// - []map[string]any 替换模型输出
|
|
// - map[string]any 替换为单条输出
|
|
// - nil 保留原输出
|
|
func invokePostTool(ctx context.Context, processorName string, outputRes []map[string]any, requestParams map[string]any) ([]map[string]any, error) {
|
|
if processorName == "" {
|
|
return outputRes, nil
|
|
}
|
|
data, err := processor.Call(ctx, processorName, map[string]any{"output": outputRes, "request": requestParams})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("执行后置处理器[%s]失败: %v", processorName, err)
|
|
}
|
|
switch v := data.(type) {
|
|
case nil:
|
|
return outputRes, nil
|
|
case []map[string]any:
|
|
return v, nil
|
|
case map[string]any:
|
|
return []map[string]any{v}, nil
|
|
default:
|
|
return nil, fmt.Errorf("后置处理器[%s]返回类型不支持: %T", processorName, data)
|
|
}
|
|
}
|