Files
sundynix-agentix/sundynix-dispatcher/internal/eino/graph.go
T
Blizzard aa574a8cb2 feat: DSL→对话编译 — Eino 图用节点字段而非整段 JSON 喂模型
dispatcher 真正解析 DSL 图:input 节点文本=用户消息,agent 节点 system=系统提示词,
不再把整段 DSL JSON 当 prompt 丢给模型。

- dispatcher/internal/dsl: Compile(graph)→Plan{System,Query,Tools}
  (input.text/agent.prompt→query, agent.system→system, tool.tool→tools, 兜底默认)
- eino/graph: recall 调 dsl.Compile,模板加 {system}(Agent 系统提示词+画像注入)
- eino/orchestrator: 写回历史落真实 query 而非 DSL 原文
- frontend nodeCatalog: input 节点改 text 字段(用户输入,必填),检查器可编辑
- 验证: 全模块+前端 build✓; 真实 DeepSeek——curl DSL(input '中国首都?')→'北京';
  真实浏览器——加 input 节点输入'NATS是什么'→运行→DeepSeek 简洁正确作答

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 16:34:38 +08:00

86 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 eino
import (
"context"
"github.com/cloudwego/eino/components/prompt"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
"github.com/sundynix/sundynix-dispatcher/internal/dsl"
"github.com/sundynix/sundynix-dispatcher/internal/llm"
"github.com/sundynix/sundynix-shared/contract"
)
// memoryFetcher 召回某用户与本次输入相关的偏好记忆(经 MCP memory_get 工具)。
type memoryFetcher func(ctx context.Context, userID, query string) string
// historyFetcher 召回某会话的短期多轮历史(经 MCP history_get 工具)。
type historyFetcher func(ctx context.Context, sessionID string) []*schema.Message
// buildGraph 编译这套"记忆增强"图:
//
// START → recall(召回画像+历史→写State) → prompt(注入system+history) → model(流式) → END
//
// 返回可流式执行的 Runnable。
func buildGraph(ctx context.Context, pool *llm.Pool, fetch memoryFetcher, fetchHist historyFetcher) (compose.Runnable[*contract.Task, *schema.Message], error) {
g := compose.NewGraph[*contract.Task, *schema.Message](
compose.WithGenLocalState(func(context.Context) *AgentState { return &AgentState{} }),
)
// 1) recall:编译 DSL → 取系统提示词/用户输入 → 召回画像+历史 → 写 State,输出模板变量。
if err := g.AddLambdaNode("recall", compose.InvokableLambda(
func(ctx context.Context, t *contract.Task) (map[string]any, error) {
uid, _ := t.Meta[contract.MetaUserID].(string)
sid, _ := t.Meta[contract.MetaSessionID].(string)
plan := dsl.Compile(t.Graph) // DSL→对话编译:抽取 system / query / tools
profile := fetch(ctx, uid, plan.Query)
hist := fetchHist(ctx, sid)
_ = compose.ProcessState(ctx, func(_ context.Context, s *AgentState) error {
s.UserID, s.SessionID, s.Profile, s.Input = uid, sid, profile, plan.Query
return nil
})
if profile == "" {
profile = "(暂无该用户的偏好记忆)"
}
return map[string]any{
"system": plan.System,
"profile": profile,
"query": plan.Query,
"history": hist,
}, nil
})); err != nil {
return nil, err
}
// 2) promptAgent 节点系统提示词 + 画像注入 system,历史用占位符,用户输入作为 user message。
tpl := prompt.FromMessages(schema.FString,
schema.SystemMessage("{system}\n\n关于当前用户的已知信息:\n{profile}\n请据此个性化作答并保持其偏好。"),
schema.MessagesPlaceholder("history", true),
schema.UserMessage("{query}"),
)
if err := g.AddChatTemplateNode("prompt", tpl); err != nil {
return nil, err
}
// 3) modelLLM Pool 适配为 ChatModel 节点,流式产出。
if err := g.AddChatModelNode("model", newPoolModel(pool)); err != nil {
return nil, err
}
if err := g.AddEdge(compose.START, "recall"); err != nil {
return nil, err
}
if err := g.AddEdge("recall", "prompt"); err != nil {
return nil, err
}
if err := g.AddEdge("prompt", "model"); err != nil {
return nil, err
}
if err := g.AddEdge("model", compose.END); err != nil {
return nil, err
}
return g.Compile(ctx)
}