diff --git a/go.mod b/go.mod index 49cdd1e..67f5c13 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,8 @@ require ( github.com/cloudwego/base64x v0.1.6 // indirect github.com/cloudwego/eino v0.8.13 // indirect github.com/cloudwego/eino-ext/components/embedding/openai v0.0.0-20260427010451-749e3706378b // indirect - github.com/cloudwego/eino-ext/libs/acl/openai v0.1.15 // indirect + github.com/cloudwego/eino-ext/components/model/openai v0.1.13 // indirect + github.com/cloudwego/eino-ext/libs/acl/openai v0.1.17 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/eino-contrib/jsonschema v1.0.3 // indirect github.com/evanphx/json-patch v0.5.2 // indirect diff --git a/go.sum b/go.sum index 469c0f6..1b3020f 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,12 @@ github.com/cloudwego/eino v0.8.13 h1:z5dhaZNN8TWZbP/lgKxGmF26Ii8fPeUlQCGV/NTtms0 github.com/cloudwego/eino v0.8.13/go.mod h1:+2N4nsMPxA6kGBHpH+75JuTfEcGprAMTdsZESrShKpU= github.com/cloudwego/eino-ext/components/embedding/openai v0.0.0-20260427010451-749e3706378b h1:pOqupZQyc46rw2Z0HeybtTmSMTwqfTrbRuGDuDsNf2A= github.com/cloudwego/eino-ext/components/embedding/openai v0.0.0-20260427010451-749e3706378b/go.mod h1:zyPrZT2bO6LyRJgVksQowR18jVgyLSvqK93hnO53/Lc= +github.com/cloudwego/eino-ext/components/model/openai v0.1.13 h1:5XHRTiTD5bt9KQrMHcfvuWNklEC3tpm3XHejdozt9vM= +github.com/cloudwego/eino-ext/components/model/openai v0.1.13/go.mod h1:mgIoqYYOc0eECCqvLbEYpOJrQNTNxkwXzSJzFU+v5sQ= github.com/cloudwego/eino-ext/libs/acl/openai v0.1.15 h1:LbdSG9+qWzzp9RFW6dSFkaUW171JvCoYn/K63zX6dQE= github.com/cloudwego/eino-ext/libs/acl/openai v0.1.15/go.mod h1:p+l0zBB0GjjX8HTlbTs3g3KfUFwZC11bsCGZOXW/3L0= +github.com/cloudwego/eino-ext/libs/acl/openai v0.1.17 h1:EeVcR1TslRA2IdNW1h/2LaGbPlffwGhQm99jM3zWZiI= +github.com/cloudwego/eino-ext/libs/acl/openai v0.1.17/go.mod h1:Zkcx6DPTR2NfWmtSXbhItswGw6hqUezNPhNcke0pOG8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= diff --git a/internal/agent/model.go b/internal/agent/model.go new file mode 100644 index 0000000..1a2e248 --- /dev/null +++ b/internal/agent/model.go @@ -0,0 +1,18 @@ +package agent + +import ( + "context" + + "eino-test/config" + + "github.com/cloudwego/eino-ext/components/model/openai" + "github.com/cloudwego/eino/components/model" +) + +func NewChatModel(ctx context.Context, cfg *config.Config) (model.ToolCallingChatModel, error) { + return openai.NewChatModel(ctx, &openai.ChatModelConfig{ + BaseURL: cfg.OpenAIBaseURL, + APIKey: cfg.OpenAIAPIKey, + Model: cfg.OpenAIModel, + }) +} diff --git a/internal/agent/organizer.go b/internal/agent/organizer.go new file mode 100644 index 0000000..91e8f50 --- /dev/null +++ b/internal/agent/organizer.go @@ -0,0 +1,37 @@ +package agent + +import ( + "context" + + "eino-test/internal/rag" + "eino-test/internal/tools" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/components/model" + "github.com/cloudwego/eino/components/tool" + "github.com/cloudwego/eino/compose" +) + +func NewOrganizerAgent(ctx context.Context, chatModel model.ToolCallingChatModel, pipeline *rag.RAGPipeline) adk.Agent { + agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ + Name: "OrganizerAgent", + Description: "Organizes notes with tags and discovers relationships between notes. Use for categorization and knowledge graph operations.", + Instruction: `You are a knowledge organization expert. Your job is to help users categorize their notes and discover hidden connections. + +Use suggest_tags when the user wants to categorize or label a note. +Use find_related when the user wants to discover notes related to a specific topic or note. + +Help users build a well-organized knowledge base with meaningful connections.`, + Model: chatModel, + ToolsConfig: adk.ToolsConfig{ + ToolsNodeConfig: compose.ToolsNodeConfig{ + Tools: []tool.BaseTool{ + tools.NewSuggestTagsTool(pipeline, chatModel), + tools.NewFindRelatedTool(pipeline), + }, + }, + }, + MaxIterations: 8, + }) + return agent +} diff --git a/internal/agent/retrieval.go b/internal/agent/retrieval.go new file mode 100644 index 0000000..a1bc802 --- /dev/null +++ b/internal/agent/retrieval.go @@ -0,0 +1,37 @@ +package agent + +import ( + "context" + + "eino-test/internal/rag" + "eino-test/internal/tools" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/components/model" + "github.com/cloudwego/eino/components/tool" + "github.com/cloudwego/eino/compose" +) + +func NewRetrievalAgent(ctx context.Context, chatModel model.ToolCallingChatModel, pipeline *rag.RAGPipeline) adk.Agent { + agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ + Name: "RetrievalAgent", + Description: "Searches the knowledge base to find relevant notes. Use for information retrieval and discovery.", + Instruction: `You are a knowledge retrieval expert. Your job is to find the most relevant notes from the user's knowledge base. + +Use semantic_search for conceptual or fuzzy queries where the user describes something by meaning. +Use keyword_search when the user provides specific terms, titles, or exact keywords. + +Always return the most relevant results with enough context for the user to understand what was found.`, + Model: chatModel, + ToolsConfig: adk.ToolsConfig{ + ToolsNodeConfig: compose.ToolsNodeConfig{ + Tools: []tool.BaseTool{ + tools.NewSemanticSearchTool(pipeline), + tools.NewKeywordSearchTool(pipeline), + }, + }, + }, + MaxIterations: 10, + }) + return agent +} diff --git a/internal/agent/supervisor.go b/internal/agent/supervisor.go new file mode 100644 index 0000000..3cd6ad9 --- /dev/null +++ b/internal/agent/supervisor.go @@ -0,0 +1,50 @@ +package agent + +import ( + "context" + + "eino-test/config" + "eino-test/internal/rag" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/adk/prebuilt/supervisor" +) + +func NewSupervisorAgent(ctx context.Context, cfg *config.Config, pipeline *rag.RAGPipeline) (adk.Agent, error) { + chatModel, err := NewChatModel(ctx, cfg) + if err != nil { + return nil, err + } + + retrievalAgent := NewRetrievalAgent(ctx, chatModel, pipeline) + writerAgent := NewWriterAgent(ctx, chatModel, pipeline) + organizerAgent := NewOrganizerAgent(ctx, chatModel, pipeline) + + supervisorAgent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ + Name: "KnowledgeSupervisor", + Description: "Personal knowledge assistant that routes tasks to specialized agents.", + Instruction: `You are a personal knowledge assistant supervisor. Your job is to understand the user's request and route it to the right specialist agent. + +Available agents: +- RetrievalAgent: For searching and finding information in the knowledge base. Use when the user asks to find, search, or look up notes. +- WriterAgent: For creating new notes or generating summaries. Use when the user wants to write, create, or summarize content. +- OrganizerAgent: For tagging notes and discovering related content. Use when the user wants to organize, categorize, or find connections. + +Workflow: +1. Analyze the user's request to determine which agent(s) should handle it. +2. Transfer the task to the appropriate agent. +3. If the task requires multiple agents (e.g., search then summarize), coordinate them in sequence. +4. After all sub-agents complete, synthesize their results into a clear final response for the user. + +If the request is simple conversation (greetings, general questions), respond directly without transferring.`, + Model: chatModel, + }) + if err != nil { + return nil, err + } + + return supervisor.New(ctx, &supervisor.Config{ + Supervisor: supervisorAgent, + SubAgents: []adk.Agent{retrievalAgent, writerAgent, organizerAgent}, + }) +} diff --git a/internal/agent/writer.go b/internal/agent/writer.go new file mode 100644 index 0000000..bd2caca --- /dev/null +++ b/internal/agent/writer.go @@ -0,0 +1,37 @@ +package agent + +import ( + "context" + + "eino-test/internal/rag" + "eino-test/internal/tools" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/components/model" + "github.com/cloudwego/eino/components/tool" + "github.com/cloudwego/eino/compose" +) + +func NewWriterAgent(ctx context.Context, chatModel model.ToolCallingChatModel, pipeline *rag.RAGPipeline) adk.Agent { + agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{ + Name: "WriterAgent", + Description: "Creates new notes and generates summaries. Use for content creation and processing.", + Instruction: `You are a writing assistant. Your job is to help users create, organize, and summarize notes. + +Use create_note when the user wants to save new content to their knowledge base. +Use generate_summary when the user wants a concise overview of an existing note. + +Always write in clear, well-structured Markdown format.`, + Model: chatModel, + ToolsConfig: adk.ToolsConfig{ + ToolsNodeConfig: compose.ToolsNodeConfig{ + Tools: []tool.BaseTool{ + tools.NewCreateNoteTool(pipeline), + tools.NewGenerateSummaryTool(pipeline, chatModel), + }, + }, + }, + MaxIterations: 8, + }) + return agent +}