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/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:取 user_id/session_id → 召回画像(memory_get)+历史(history_get) → 写 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) profile := fetch(ctx, uid, string(t.Graph)) hist := fetchHist(ctx, sid) _ = compose.ProcessState(ctx, func(_ context.Context, s *AgentState) error { s.UserID, s.SessionID, s.Profile, s.Input = uid, sid, profile, string(t.Graph) return nil }) if profile == "" { profile = "(暂无该用户的偏好记忆)" } return map[string]any{"profile": profile, "query": string(t.Graph), "history": hist}, nil })); err != nil { return nil, err } // 2) prompt:画像注入 system,历史用占位符插入,用户输入作为 user message。 tpl := prompt.FromMessages(schema.FString, schema.SystemMessage("你在与特定用户对话。关于该用户的已知信息:\n{profile}\n请据此个性化作答并保持其偏好。"), schema.MessagesPlaceholder("history", true), schema.UserMessage("{query}"), ) if err := g.AddChatTemplateNode("prompt", tpl); err != nil { return nil, err } // 3) model:LLM 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) }