From 73e48ce6d653f61c938dbb8e4b60268f120356a8 Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 12 Dec 2025 19:09:32 +0800 Subject: [PATCH] Enhance DESIGN.md to document new search modes and configuration options - Introduced a new `Uses` struct to encapsulate configuration for search modes, including `builtin`, `agent`, and `mcp`. - Updated the `Searcher` initialization to utilize the new `Uses` struct for improved clarity and flexibility in search handling. - Expanded documentation to detail the three web search modes, their functionalities, and the corresponding configuration options. - Added examples illustrating the AI-powered search flow when using the agent mode, enhancing understanding of intent-aware search capabilities. - Clarified the roles of built-in providers and the MCP server in the search process, ensuring comprehensive guidance for developers. --- agent/search/DESIGN.md | 213 ++++++++++++++++++++++++++++++++++------- 1 file changed, 179 insertions(+), 34 deletions(-) diff --git a/agent/search/DESIGN.md b/agent/search/DESIGN.md index fd6409e0..442a731f 100644 --- a/agent/search/DESIGN.md +++ b/agent/search/DESIGN.md @@ -157,9 +157,11 @@ agent/search/ │ ├── handlers/ # Search handler implementations │ ├── web/ # Web search -│ │ ├── handler.go # Web search handler -│ │ ├── tavily.go # Tavily provider -│ │ └── serper.go # Serper provider +│ │ ├── handler.go # Web search handler (mode dispatch) +│ │ ├── tavily.go # Tavily provider (builtin) +│ │ ├── serper.go # Serper provider (builtin) +│ │ ├── agent.go # Agent mode (AI Search) +│ │ └── mcp.go # MCP mode (external service) │ │ │ ├── kb/ # Knowledge base search │ │ ├── handler.go # KB search handler @@ -242,18 +244,26 @@ type Searcher struct { citation *CitationGenerator } +// Uses contains the uses.* configuration for search +type Uses struct { + Web string // "builtin", "", "mcp:" + Keyword string // "builtin", "", "mcp:" + QueryDSL string // "builtin", "", "mcp:" + Rerank string // "builtin", "", "mcp:" +} + // New creates a new Searcher instance // cfg: merged config from agent/load.go + assistant config -// usesRerank: reranker type from uses.rerank -func New(cfg *types.Config, usesRerank string) *Searcher { +// uses: uses.* configuration from agent.yml + assistant config +func New(cfg *types.Config, uses *Uses) *Searcher { return &Searcher{ config: cfg, handlers: map[types.SearchType]interfaces.Handler{ - types.SearchTypeWeb: web.NewHandler(cfg.Web), - types.SearchTypeKB: kb.NewHandler(cfg.KB), - types.SearchTypeDB: db.NewHandler(cfg.DB), + types.SearchTypeWeb: web.NewHandler(uses.Web, cfg.Web), + types.SearchTypeKB: kb.NewHandler(cfg.KB), // KB always builtin + types.SearchTypeDB: db.NewHandler(uses.QueryDSL, cfg.DB), }, - reranker: rerank.NewReranker(usesRerank), + reranker: rerank.NewReranker(uses.Rerank), citation: NewCitationGenerator(), } } @@ -671,8 +681,10 @@ type Config struct { } // WebConfig for web search settings +// Note: uses.web determines the mode (builtin/agent/mcp) +// Provider is only used when uses.web = "builtin" type WebConfig struct { - Provider string `json:"provider,omitempty"` // "tavily", "serper", "mcp:server-id" + Provider string `json:"provider,omitempty"` // "tavily" or "serper" (for builtin mode) APIKeyEnv string `json:"api_key_env,omitempty"` // Environment variable for API key MaxResults int `json:"max_results,omitempty"` // Max results (default: 10) } @@ -1085,15 +1097,50 @@ uses: vision: "workers.system.vision" fetch: "workers.system.fetch" - # Search processing tools + # Search processing tools (NLP) keyword: "builtin" # "builtin", "workers.nlp.keyword", "mcp:nlp-server" querydsl: "builtin" # "builtin", "workers.nlp.querydsl", "mcp:querydsl-server" rerank: "builtin" # "builtin", "workers.rerank", "mcp:rerank-server" + + # Search handlers + web: "builtin" # "builtin", "workers.search.web", "mcp:search-server" + # Note: kb & db always use builtin (access internal data) # Note: embedding & entity follow KB collection config ``` Tool format: `"builtin"`, `""` (Agent), `"mcp:"` (MCP) +**Web Search Modes:** + +| Mode | Example | Description | +| --------- | ---------------------- | -------------------------------------------------------------------------- | +| `builtin` | `"builtin"` | Use built-in providers (Tavily, Serper) | +| Agent | `"workers.search.web"` | AI-powered search: understand intent → optimize query → search → summarize | +| MCP | `"mcp:search-server"` | External search service via MCP protocol | + +**Why Agent for Web Search (AI Search)?** + +When `uses.web` is set to an assistant ID, the search flow becomes: + +``` +User Query: "What's the best laptop for programming in 2024?" + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Agent (workers.search.web) │ +│ 1. Understand intent: laptop recommendations for coding │ +│ 2. Generate optimized queries: │ +│ - "best programming laptop 2024 review" │ +│ - "developer laptop comparison 2024" │ +│ 3. Execute multiple searches │ +│ 4. Analyze & deduplicate results │ +│ 5. Return structured, relevant results │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +High-quality, intent-aware search results +``` + ### System Built-in Defaults (`defaults/defaults.go`) These are the hardcoded defaults, used by `agent/load.go` when loading configuration: @@ -1613,48 +1660,146 @@ All handler implementations are in `search/handlers/` directory. ### Web Search (`handlers/web/`) +Web search supports three modes via `uses.web`: + +| Mode | Value | Description | +| ------- | ---------------------- | ------------------------------------------- | +| Builtin | `"builtin"` | Direct API calls to Tavily/Serper | +| Agent | `"workers.search.web"` | AI-powered search with intent understanding | +| MCP | `"mcp:search-server"` | External search service | + ```go // handlers/web/handler.go package web import ( + "strings" + "github.com/yaoapp/yao/agent/context" - "github.com/yaoapp/yao/agent/search/interfaces" "github.com/yaoapp/yao/agent/search/types" ) // Handler implements web search type Handler struct { - provider Provider - config *types.WebConfig -} - -// Provider interface for web search providers -type Provider interface { - Search(ctx *context.Context, query string, opts *SearchOptions) ([]*types.ResultItem, error) + usesWeb string // "builtin", "", "mcp:" + config *types.WebConfig } // NewHandler creates a new web search handler -func NewHandler(cfg *types.WebConfig) *Handler { - var provider Provider - switch cfg.Provider { - case "tavily": - provider = NewTavilyProvider(cfg) - case "serper": - provider = NewSerperProvider(cfg) +func NewHandler(usesWeb string, cfg *types.WebConfig) *Handler { + return &Handler{usesWeb: usesWeb, config: cfg} +} + +// Search executes web search based on uses.web mode +func (h *Handler) Search(ctx *context.Context, req *types.Request) (*types.Result, error) { + switch { + case h.usesWeb == "builtin" || h.usesWeb == "": + return h.builtinSearch(ctx, req) + case strings.HasPrefix(h.usesWeb, "mcp:"): + return h.mcpSearch(ctx, req) default: - // MCP provider - provider = NewMCPProvider(cfg) + // Agent mode: delegate to assistant for AI-powered search + return h.agentSearch(ctx, req) } - return &Handler{provider: provider, config: cfg} +} + +// builtinSearch uses Tavily/Serper directly +func (h *Handler) builtinSearch(ctx *context.Context, req *types.Request) (*types.Result, error) { + var provider Provider + switch h.config.Provider { + case "tavily": + provider = NewTavilyProvider(h.config) + case "serper": + provider = NewSerperProvider(h.config) + } + return provider.Search(ctx, req) +} + +// agentSearch delegates to an assistant for AI-powered search +func (h *Handler) agentSearch(ctx *context.Context, req *types.Request) (*types.Result, error) { + // 1. Call assistant with search request + // 2. Assistant understands intent, generates optimized queries + // 3. Assistant executes searches (may call builtin internally) + // 4. Assistant analyzes and returns structured results + return nil, nil +} + +// mcpSearch calls external MCP server +func (h *Handler) mcpSearch(ctx *context.Context, req *types.Request) (*types.Result, error) { + serverID := strings.TrimPrefix(h.usesWeb, "mcp:") + // Call MCP server's search tool + return nil, nil } ``` -| Provider | File | Notes | -| -------- | ------------ | ------------------------------- | -| Tavily | `tavily.go` | Recommended for AI applications | -| Serper | `serper.go` | Google search API | -| MCP | (via config) | Any MCP server with search tool | +**Built-in Providers (when `uses.web = "builtin"`):** + +| Provider | File | Notes | +| -------- | ----------- | ------------------------------- | +| Tavily | `tavily.go` | Recommended for AI applications | +| Serper | `serper.go` | Google search API | + +**Agent Mode (AI Search):** + +When `uses.web` is set to an assistant ID (e.g., `"workers.search.web"`), the assistant can: + +1. **Understand user intent** - Parse complex queries, identify what user really wants +2. **Generate multiple queries** - Create optimized search terms for better coverage +3. **Multi-source search** - Search multiple providers or sources +4. **Result analysis** - Deduplicate, rank, and summarize results +5. **Context-aware** - Use conversation context to improve search relevance + +``` +User Query: "What's the best laptop for programming in 2024?" + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Agent (workers.search.web) │ +│ 1. Understand intent: laptop recommendations for coding │ +│ 2. Generate optimized queries: │ +│ - "best programming laptop 2024 review" │ +│ - "developer laptop comparison 2024" │ +│ 3. Execute multiple searches via builtin providers │ +│ 4. Analyze & deduplicate results │ +│ 5. Return structured, relevant results │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +High-quality, intent-aware search results +``` + +**Example AI Search Assistant:** + +```typescript +// assistants/workers/search/web/src/index.ts +function Create(ctx, messages, options) { + const userQuery = messages[messages.length - 1].content; + + // 1. Analyze intent (this assistant has access to LLM) + const intent = analyzeIntent(ctx, userQuery); + + // 2. Generate optimized queries + const queries = generateQueries(intent); + + // 3. Execute searches using builtin provider + const allResults = []; + for (const q of queries) { + const result = ctx.search.Web(q, { + provider: "tavily", // Use builtin provider + limit: 5, + }); + allResults.push(...result.items); + } + + // 4. Merge, deduplicate, and rank results + const merged = mergeAndRank(allResults, intent); + + return { + type: "search_result", + items: merged, + }; +} +``` ### Knowledge Base (`handlers/kb/`)