Files
smartmate/backend/agent/schedulerefine/graph.go
Losita 525a8b32cb Version: 0.7.3.dev.260322
♻️ refactor(schedule-refine): [WIP] 重构 Plan-and-Execute ReAct 链路,并增强 JSON 解析兜底能力

- 🧩 重构 `schedulerefine` 主流程,引入 `Planner` / `Replan` 机制,以及执行预算与轮次状态管理
- 🧠 扩展状态与观察上下文,补充工具结果、失败签名、连续失败计数与后置反思策略等信息
- 🔧 增强工具层能力与参数兼容性,补齐 `Query` / `Move` / `Swap` / `BatchMove` / `Verify` 等行为及约束校验
- 🛡️ 提升解析鲁棒性,支持从代码块或混杂文本中提取首个 JSON 对象,并增加单次解析重试机制
- 👀 增强可观测性,补充 `debug raw` 阶段输出与分片透传能力
- ✍️ 优化提示词近端约束,将严格 JSON 输出协议追加到各节点 `userPrompt` 末尾

- 🚧 备注:当前链路仍处于持续调优阶段,稳定性与可用性仍需进一步验证
2026-03-22 22:38:51 +08:00

94 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package schedulerefine
import (
"context"
"fmt"
"github.com/cloudwego/eino-ext/components/model/ark"
"github.com/cloudwego/eino/compose"
)
const (
graphNodeContract = "schedule_refine_contract"
graphNodeReact = "schedule_refine_react"
graphNodeHardCheck = "schedule_refine_hard_check"
graphNodeSummary = "schedule_refine_summary"
)
// ScheduleRefineGraphRunInput 是“连续微调图”运行参数。
//
// 字段语义:
// 1. Model本轮图运行使用的聊天模型。
// 2. State预先注入的微调状态通常来自上一版预览快照
// 3. EmitStageSSE 阶段回调,允许服务层把阶段进度透传给前端。
type ScheduleRefineGraphRunInput struct {
Model *ark.ChatModel
State *ScheduleRefineState
EmitStage func(stage, detail string)
}
// RunScheduleRefineGraph 执行“连续微调”独立图链路。
//
// 链路顺序:
// START -> contract -> react -> hard_check -> summary -> END
//
// 设计说明:
// 1. 当前链路采用线性图,确保可读性优先;
// 2. “终审失败后单次修复”在 hard_check 节点内部闭环处理,避免图连线分叉过多;
// 3. 若后续需要引入多分支策略(例如大改动转重排),可在 contract 后追加 branch 节点。
func RunScheduleRefineGraph(ctx context.Context, input ScheduleRefineGraphRunInput) (*ScheduleRefineState, error) {
if input.Model == nil {
return nil, fmt.Errorf("schedule refine graph: model is nil")
}
if input.State == nil {
return nil, fmt.Errorf("schedule refine graph: state is nil")
}
emitStage := func(stage, detail string) {
if input.EmitStage != nil {
input.EmitStage(stage, detail)
}
}
runner := newScheduleRefineRunner(input.Model, emitStage)
graph := compose.NewGraph[*ScheduleRefineState, *ScheduleRefineState]()
if err := graph.AddLambdaNode(graphNodeContract, compose.InvokableLambda(runner.contractNode)); err != nil {
return nil, err
}
if err := graph.AddLambdaNode(graphNodeReact, compose.InvokableLambda(runner.reactNode)); err != nil {
return nil, err
}
if err := graph.AddLambdaNode(graphNodeHardCheck, compose.InvokableLambda(runner.hardCheckNode)); err != nil {
return nil, err
}
if err := graph.AddLambdaNode(graphNodeSummary, compose.InvokableLambda(runner.summaryNode)); err != nil {
return nil, err
}
if err := graph.AddEdge(compose.START, graphNodeContract); err != nil {
return nil, err
}
if err := graph.AddEdge(graphNodeContract, graphNodeReact); err != nil {
return nil, err
}
if err := graph.AddEdge(graphNodeReact, graphNodeHardCheck); err != nil {
return nil, err
}
if err := graph.AddEdge(graphNodeHardCheck, graphNodeSummary); err != nil {
return nil, err
}
if err := graph.AddEdge(graphNodeSummary, compose.END); err != nil {
return nil, err
}
runnable, err := graph.Compile(ctx,
compose.WithGraphName("ScheduleRefineGraph"),
compose.WithMaxRunSteps(12),
compose.WithNodeTriggerMode(compose.AnyPredecessor),
)
if err != nil {
return nil, err
}
return runnable.Invoke(ctx, input.State)
}