feat(orchestration): Phase2 —— map 真并行 fan-out + branch 真/假边标签精确选路
Phase1 让引擎按图执行后,本轮补上两块:
1) map 并行 fan-out(dispatcher)
- map 节点:planItems 把主题拆成 3–6 子项 → 复用 report 的 writeSections
有界并发(4)逐项撰写 → 结构化 sections 存黑板 + 拼进 answer + 流式呈现。
- 检索节点记下 owner 作用域库名(b.kb),供 map 各项并行检索复用。
- render 节点优先用 map 产出的多章 sections 渲染,否则整段成稿当单章。
2) branch 真/假边标签(前端 + DSL + dispatcher)
- TypedNode:分支节点渲染两个出口手柄 真(绿)/假(红),连线各带 sourceHandle。
- exportDsl / TaskDsl:边导出携带 sourceHandle。
- dispatcher dsl.Edge 增 SourceHandle;branchNode 优先按 true/false 标签精确
选路,无标签的旧图退回"出边顺序"约定,向后兼容。
实测(gateway+dispatcher+DeepSeek 真跑):
- map:input→map→render,DeepSeek 拆出 5 章并行撰写(347–512字),trace 见
section:0..4 并发 + 有界并发(section3 等槽);render 因 mcp-go 不在优雅降级 ✓
- branch 标签:把 true 边故意列第二位,条件真仍走 true 标签的分支A、假走分支B,
证明按标签而非边序选路 ✓
- 桌面端:分支节点正确渲染 真/假 两手柄,无 console 报错 ✓
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -122,6 +122,35 @@ func (o *Orchestrator) planOutline(ctx context.Context, topic string) reportOutl
|
||||
return out
|
||||
}
|
||||
|
||||
// planItems 为 map 节点把主题拆成一组并行子项(splitBy 为拆分依据提示)。
|
||||
// 模型不可用/解析失败则用通用兜底分项。
|
||||
func (o *Orchestrator) planItems(ctx context.Context, topic, splitBy string) []string {
|
||||
fallback := []string{"背景与现状", "核心分析", "结论与建议"}
|
||||
if !o.pool.Ready() {
|
||||
return fallback
|
||||
}
|
||||
hint := splitBy
|
||||
if hint == "" {
|
||||
hint = "合理的章节"
|
||||
}
|
||||
user := fmt.Sprintf("请把主题《%s》拆分为一组「%s」,用于并行撰写。"+
|
||||
"只输出 JSON 数组:[\"子项1\",\"子项2\", ...],3 到 6 项,不要任何多余文字。", topic, hint)
|
||||
txt, err := o.pool.Chat(ctx, []llm.ChatMessage{
|
||||
{Role: "system", Content: "你擅长把一个任务拆解为可并行处理的若干子项。"},
|
||||
{Role: "user", Content: user},
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("[map] 拆分子项失败,用兜底: %v", err)
|
||||
return fallback
|
||||
}
|
||||
var items []string
|
||||
if json.Unmarshal([]byte(stripFence(txt)), &items) != nil || len(items) == 0 {
|
||||
log.Printf("[map] 子项 JSON 解析失败,用兜底。原文: %s", truncate(txt, 200))
|
||||
return fallback
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// writeSections 各章节并行撰写(有界并发),结果按原顺序返回。
|
||||
func (o *Orchestrator) writeSections(ctx context.Context, topic, kb string, headings []string, tr *execTracer) []reportSection {
|
||||
out := make([]reportSection, len(headings))
|
||||
|
||||
Reference in New Issue
Block a user