Version: 0.8.3.dev.260328
后端: 1.彻底删除原agent文件夹,并将现agent2文件夹全量重命名为agent(包括全部涉及到的文件以及文档、注释),迁移工作完美结束 2.修复了重试消息的相关逻辑问题 前端: 1.改善了一些交互体验,修复了一些bug,现在只剩少的功能了,现存的bug基本都修复完毕 全仓库: 1.更新了决策记录和README文档
This commit is contained in:
122
backend/agent/graph/quicknote.go
Normal file
122
backend/agent/graph/quicknote.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package agentgraph
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
agentmodel "github.com/LoveLosita/smartflow/backend/agent/model"
|
||||
agentnode "github.com/LoveLosita/smartflow/backend/agent/node"
|
||||
agentshared "github.com/LoveLosita/smartflow/backend/agent/shared"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
)
|
||||
|
||||
const (
|
||||
// QuickNoteGraphName 是随口记图编排的稳定标识。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 仅用于 graph 编译和链路标识,方便日志与排障统一定位。
|
||||
// 2. 不参与意图判断,也不承载任务写库的业务语义。
|
||||
QuickNoteGraphName = "quick_note"
|
||||
)
|
||||
|
||||
// RunQuickNoteGraph 负责执行“随口记 -> 判断 -> 提取 -> 落库 -> 收口”的整条图链路。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 负责输入兜底、工具装配、节点注册与 graph 运行。
|
||||
// 2. 不负责每个节点的具体业务决策,节点内部逻辑由 node 层实现。
|
||||
// 3. 返回的 state 表示整条链路的最终状态,供上层继续拼接响应或写日志。
|
||||
func RunQuickNoteGraph(ctx context.Context, input agentnode.QuickNoteGraphRunInput) (*agentmodel.QuickNoteState, error) {
|
||||
// 1. 先校验最基础依赖,避免图已经启动后才发现模型或状态为空。
|
||||
if input.Model == nil {
|
||||
return nil, errors.New("quick note graph: model is nil")
|
||||
}
|
||||
if input.State == nil {
|
||||
return nil, errors.New("quick note graph: state is nil")
|
||||
}
|
||||
if err := input.Deps.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. 补齐当前请求时间,保证后续提示词、时间解析和落库字段都基于同一时刻。
|
||||
if input.State.RequestNow.IsZero() {
|
||||
input.State.RequestNow = agentshared.NowToMinute()
|
||||
}
|
||||
if strings.TrimSpace(input.State.RequestNowText) == "" {
|
||||
input.State.RequestNowText = agentshared.FormatMinute(input.State.RequestNow)
|
||||
}
|
||||
|
||||
// 3. 图运行前统一准备工具与节点容器,避免节点内部重复做依赖解析。
|
||||
toolBundle, err := agentnode.BuildQuickNoteToolBundle(ctx, input.Deps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createTaskTool, err := agentnode.GetInvokableToolByName(toolBundle, agentnode.ToolNameQuickNoteCreateTask)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodes, err := agentnode.NewQuickNoteNodes(input, createTaskTool)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 4. 主链路保持“意图识别 -> 优先级评估 -> 持久化 -> 退出”,中间通过 branch 决定是否提前结束或重试写库。
|
||||
graph := compose.NewGraph[*agentmodel.QuickNoteState, *agentmodel.QuickNoteState]()
|
||||
if err = graph.AddLambdaNode(agentnode.QuickNoteGraphNodeIntent, compose.InvokableLambda(nodes.Intent)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.QuickNoteGraphNodeRank, compose.InvokableLambda(nodes.Priority)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.QuickNoteGraphNodePersist, compose.InvokableLambda(nodes.Persist)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.QuickNoteGraphNodeExit, compose.InvokableLambda(nodes.Exit)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = graph.AddEdge(compose.START, agentnode.QuickNoteGraphNodeIntent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddBranch(agentnode.QuickNoteGraphNodeIntent, compose.NewGraphBranch(
|
||||
nodes.NextAfterIntent,
|
||||
map[string]bool{
|
||||
agentnode.QuickNoteGraphNodeRank: true,
|
||||
agentnode.QuickNoteGraphNodeExit: true,
|
||||
},
|
||||
)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.QuickNoteGraphNodeExit, compose.END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.QuickNoteGraphNodeRank, agentnode.QuickNoteGraphNodePersist); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddBranch(agentnode.QuickNoteGraphNodePersist, compose.NewGraphBranch(
|
||||
nodes.NextAfterPersist,
|
||||
map[string]bool{
|
||||
agentnode.QuickNoteGraphNodePersist: true,
|
||||
compose.END: true,
|
||||
},
|
||||
)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5. persist 节点允许有限次重试,因此最大步数要覆盖首次执行与重试回路。
|
||||
maxSteps := input.State.MaxToolRetry + 10
|
||||
if maxSteps < 12 {
|
||||
maxSteps = 12
|
||||
}
|
||||
|
||||
runnable, err := graph.Compile(ctx,
|
||||
compose.WithGraphName(QuickNoteGraphName),
|
||||
compose.WithMaxRunSteps(maxSteps),
|
||||
compose.WithNodeTriggerMode(compose.AnyPredecessor),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return runnable.Invoke(ctx, input.State)
|
||||
}
|
||||
202
backend/agent/graph/schedule.go
Normal file
202
backend/agent/graph/schedule.go
Normal file
@@ -0,0 +1,202 @@
|
||||
package agentgraph
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
agentmodel "github.com/LoveLosita/smartflow/backend/agent/model"
|
||||
agentnode "github.com/LoveLosita/smartflow/backend/agent/node"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
)
|
||||
|
||||
const (
|
||||
SchedulePlanGraphName = "schedule_plan"
|
||||
ScheduleRefineGraphName = "schedule_refine"
|
||||
)
|
||||
|
||||
func RunSchedulePlanGraph(ctx context.Context, input agentnode.SchedulePlanGraphRunInput) (*agentmodel.SchedulePlanState, error) {
|
||||
if input.Model == nil {
|
||||
return nil, errors.New("schedule plan graph: model is nil")
|
||||
}
|
||||
if input.State == nil {
|
||||
return nil, errors.New("schedule plan graph: state is nil")
|
||||
}
|
||||
if err := input.Deps.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if input.DailyRefineConcurrency > 0 {
|
||||
input.State.DailyRefineConcurrency = input.DailyRefineConcurrency
|
||||
}
|
||||
if input.WeeklyAdjustBudget > 0 {
|
||||
input.State.WeeklyAdjustBudget = input.WeeklyAdjustBudget
|
||||
}
|
||||
|
||||
nodes, err := agentnode.NewSchedulePlanNodes(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
graph := compose.NewGraph[*agentmodel.SchedulePlanState, *agentmodel.SchedulePlanState]()
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodePlan, compose.InvokableLambda(nodes.Plan)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeRoughBuild, compose.InvokableLambda(nodes.RoughBuild)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeExit, compose.InvokableLambda(nodes.Exit)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeDailySplit, compose.InvokableLambda(nodes.DailySplit)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeQuickRefine, compose.InvokableLambda(nodes.QuickRefine)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeDailyRefine, compose.InvokableLambda(nodes.DailyRefine)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeMerge, compose.InvokableLambda(nodes.Merge)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeWeeklyRefine, compose.InvokableLambda(nodes.WeeklyRefine)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeFinalCheck, compose.InvokableLambda(nodes.FinalCheck)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.SchedulePlanGraphNodeReturnPreview, compose.InvokableLambda(nodes.ReturnPreview)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = graph.AddEdge(compose.START, agentnode.SchedulePlanGraphNodePlan); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddBranch(agentnode.SchedulePlanGraphNodePlan, compose.NewGraphBranch(
|
||||
nodes.NextAfterPlan,
|
||||
map[string]bool{
|
||||
agentnode.SchedulePlanGraphNodeRoughBuild: true,
|
||||
agentnode.SchedulePlanGraphNodeExit: true,
|
||||
},
|
||||
)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddBranch(agentnode.SchedulePlanGraphNodeRoughBuild, compose.NewGraphBranch(
|
||||
nodes.NextAfterRoughBuild,
|
||||
map[string]bool{
|
||||
agentnode.SchedulePlanGraphNodeDailySplit: true,
|
||||
agentnode.SchedulePlanGraphNodeQuickRefine: true,
|
||||
agentnode.SchedulePlanGraphNodeWeeklyRefine: true,
|
||||
agentnode.SchedulePlanGraphNodeExit: true,
|
||||
},
|
||||
)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeQuickRefine, agentnode.SchedulePlanGraphNodeWeeklyRefine); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeDailySplit, agentnode.SchedulePlanGraphNodeDailyRefine); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeDailyRefine, agentnode.SchedulePlanGraphNodeMerge); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeMerge, agentnode.SchedulePlanGraphNodeWeeklyRefine); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeWeeklyRefine, agentnode.SchedulePlanGraphNodeFinalCheck); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeFinalCheck, agentnode.SchedulePlanGraphNodeReturnPreview); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeReturnPreview, compose.END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.SchedulePlanGraphNodeExit, compose.END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runnable, err := graph.Compile(ctx,
|
||||
compose.WithGraphName(SchedulePlanGraphName),
|
||||
compose.WithMaxRunSteps(20),
|
||||
compose.WithNodeTriggerMode(compose.AnyPredecessor),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return runnable.Invoke(ctx, input.State)
|
||||
}
|
||||
|
||||
func RunScheduleRefineGraph(ctx context.Context, input agentnode.ScheduleRefineGraphRunInput) (*agentnode.ScheduleRefineState, error) {
|
||||
if input.Model == nil {
|
||||
return nil, errors.New("schedule refine graph: model is nil")
|
||||
}
|
||||
if input.State == nil {
|
||||
return nil, errors.New("schedule refine graph: state is nil")
|
||||
}
|
||||
|
||||
nodes, err := agentnode.NewScheduleRefineNodes(input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
graph := compose.NewGraph[*agentmodel.ScheduleRefineState, *agentmodel.ScheduleRefineState]()
|
||||
if err = graph.AddLambdaNode(agentnode.ScheduleRefineGraphNodeContract, compose.InvokableLambda(nodes.Contract)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.ScheduleRefineGraphNodePlan, compose.InvokableLambda(nodes.Plan)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.ScheduleRefineGraphNodeSlice, compose.InvokableLambda(nodes.Slice)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.ScheduleRefineGraphNodeRoute, compose.InvokableLambda(nodes.Route)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.ScheduleRefineGraphNodeReact, compose.InvokableLambda(nodes.React)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.ScheduleRefineGraphNodeHardCheck, compose.InvokableLambda(nodes.HardCheck)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.ScheduleRefineGraphNodeSummary, compose.InvokableLambda(nodes.Summary)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = graph.AddEdge(compose.START, agentnode.ScheduleRefineGraphNodeContract); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.ScheduleRefineGraphNodeContract, agentnode.ScheduleRefineGraphNodePlan); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.ScheduleRefineGraphNodePlan, agentnode.ScheduleRefineGraphNodeSlice); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.ScheduleRefineGraphNodeSlice, agentnode.ScheduleRefineGraphNodeRoute); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.ScheduleRefineGraphNodeRoute, agentnode.ScheduleRefineGraphNodeReact); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.ScheduleRefineGraphNodeReact, agentnode.ScheduleRefineGraphNodeHardCheck); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.ScheduleRefineGraphNodeHardCheck, agentnode.ScheduleRefineGraphNodeSummary); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.ScheduleRefineGraphNodeSummary, compose.END); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runnable, err := graph.Compile(ctx,
|
||||
compose.WithGraphName(ScheduleRefineGraphName),
|
||||
compose.WithMaxRunSteps(20),
|
||||
compose.WithNodeTriggerMode(compose.AnyPredecessor),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return runnable.Invoke(ctx, input.State)
|
||||
}
|
||||
126
backend/agent/graph/taskquery.go
Normal file
126
backend/agent/graph/taskquery.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package agentgraph
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
agentmodel "github.com/LoveLosita/smartflow/backend/agent/model"
|
||||
agentnode "github.com/LoveLosita/smartflow/backend/agent/node"
|
||||
"github.com/cloudwego/eino/compose"
|
||||
)
|
||||
|
||||
const (
|
||||
// TaskQueryGraphName 是任务查询图编排的稳定标识。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 仅用于 graph 编译、日志和排障时标识当前链路。
|
||||
// 2. 不承载路由判断,也不负责描述具体业务含义。
|
||||
TaskQueryGraphName = "task_query"
|
||||
)
|
||||
|
||||
// RunTaskQueryGraph 负责串起任务查询图,并返回最终给用户的回复文本。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 负责做图运行前的依赖校验、默认值补齐、节点装配与 graph 编译执行。
|
||||
// 2. 不负责实现单个节点的业务细节,这些逻辑由 node 层承接。
|
||||
// 3. 返回值中的 string 是最终可直接透传给上层的回复;error 仅表示链路级失败。
|
||||
func RunTaskQueryGraph(ctx context.Context, input agentnode.TaskQueryGraphRunInput) (string, error) {
|
||||
// 1. 先拦住空模型、空状态和依赖缺失,避免 graph 运行到一半才出现不可恢复错误。
|
||||
if input.Model == nil {
|
||||
return "", errors.New("task query graph: model is nil")
|
||||
}
|
||||
if input.State == nil {
|
||||
return "", errors.New("task query graph: state is nil")
|
||||
}
|
||||
if err := input.Deps.Validate(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 2. 请求时间缺失时补齐当前时间,保证后续时间锚定与提示词上下文稳定。
|
||||
if strings.TrimSpace(input.State.RequestNowText) == "" {
|
||||
input.State.RequestNowText = time.Now().In(time.Local).Format("2006-01-02 15:04")
|
||||
}
|
||||
|
||||
// 3. 先准备工具,再构造节点容器;这样 graph 中每个节点都能拿到已校验好的依赖。
|
||||
toolBundle, err := agentnode.BuildTaskQueryToolBundle(ctx, input.Deps)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
queryTool, err := agentnode.GetTaskQueryInvokableToolByName(toolBundle, agentnode.ToolNameTaskQueryTasks)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
nodes, err := agentnode.NewTaskQueryNodes(input, queryTool)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 4. 注册节点与边,保持“计划 -> 归一化 -> 时间锚定 -> 查询 -> 反思”的单向主链。
|
||||
graph := compose.NewGraph[*agentmodel.TaskQueryState, *agentmodel.TaskQueryState]()
|
||||
if err = graph.AddLambdaNode(agentnode.TaskQueryGraphNodePlan, compose.InvokableLambda(nodes.Plan)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.TaskQueryGraphNodeQuadrant, compose.InvokableLambda(nodes.NormalizeQuadrant)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.TaskQueryGraphNodeTimeAnchor, compose.InvokableLambda(nodes.AnchorTime)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.TaskQueryGraphNodeQuery, compose.InvokableLambda(nodes.Query)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddLambdaNode(agentnode.TaskQueryGraphNodeReflect, compose.InvokableLambda(nodes.Reflect)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddEdge(compose.START, agentnode.TaskQueryGraphNodePlan); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.TaskQueryGraphNodePlan, agentnode.TaskQueryGraphNodeQuadrant); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.TaskQueryGraphNodeQuadrant, agentnode.TaskQueryGraphNodeTimeAnchor); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.TaskQueryGraphNodeTimeAnchor, agentnode.TaskQueryGraphNodeQuery); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddEdge(agentnode.TaskQueryGraphNodeQuery, agentnode.TaskQueryGraphNodeReflect); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = graph.AddBranch(agentnode.TaskQueryGraphNodeReflect, compose.NewGraphBranch(nodes.NextAfterReflect, map[string]bool{
|
||||
agentnode.TaskQueryGraphNodeQuery: true,
|
||||
compose.END: true,
|
||||
})); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 5. 反思节点支持按配置重试,因此最大步数需要覆盖“首次查询 + 多轮回看”的上限。
|
||||
maxSteps := 24 + input.State.MaxReflectRetry*4
|
||||
if maxSteps < 24 {
|
||||
maxSteps = 24
|
||||
}
|
||||
runnable, err := graph.Compile(ctx,
|
||||
compose.WithGraphName(TaskQueryGraphName),
|
||||
compose.WithMaxRunSteps(maxSteps),
|
||||
compose.WithNodeTriggerMode(compose.AnyPredecessor),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
finalState, err := runnable.Invoke(ctx, input.State)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if finalState == nil {
|
||||
return "", errors.New("task query graph: final state is nil")
|
||||
}
|
||||
|
||||
// 6. 最终回复为空时给一个稳定兜底,避免上层拿到空字符串后再次拼接出异常文案。
|
||||
reply := strings.TrimSpace(finalState.FinalReply)
|
||||
if reply == "" {
|
||||
reply = "我这边暂时没整理出稳定结果,你可以换一个更具体的筛选条件再试一次。"
|
||||
}
|
||||
return reply, nil
|
||||
}
|
||||
Reference in New Issue
Block a user