Skip to content

Feature Search

BlueSkyXN edited this page May 4, 2026 · 2 revisions

Feature: Search

事实来源:主仓 pr-88 @ a312645 的 src/souwen/facade/search.py、src/souwen/cli/search.py、src/souwen/server/routes/search.py。

SouWen 把"搜索"统一为按 (domain, capability) 的派发。门面层从 registry 挑默认源,业务层 Client 各自实现 search 方法,门面用 MethodSpec.param_map 把统一参数映射到各 Client 的实参。


1. 五类 search capability

Capability 中文 源数量 默认源
search 通用搜索 72 openalex+arxiv(paper)/ google_patents(patent)/ duckduckgo+bing(web)
search_news 新闻搜索 1 duckduckgo_news
search_images 图片搜索 1 duckduckgo_images
search_videos 视频搜索 1 duckduckgo_videos
search_users / search_articles 用户 / 专栏文章 1 / 1 bilibili

非标准命名空间能力(exa:find_similar / unpaywall:find_oa)需显式指定 sources=[...]。


2. 三种入口

CLI

souwen search paper "transformer" -s openalex,arxiv -n 5
souwen search patent "quantum" -s uspto_odp -n 5
souwen search web "python asyncio" -e duckduckgo,bing -n 10
souwen search images "diagram"
souwen search videos "AI agent"

HTTP API

curl "http://localhost:8000/api/v1/search/paper?q=transformer&sources=openalex,arxiv&per_page=5"
curl "http://localhost:8000/api/v1/search/web?q=python&engines=duckduckgo,bing&per_page=10"
curl "http://localhost:8000/api/v1/search/images?q=diagram&max_results=20&safesearch=off"

Python

from souwen.facade import search, search_all

# 单 domain
papers = await search("transformer", domain="paper", limit=5)

# 跨 domain
mixed = await search_all("quantum", domains=["paper", "web", "knowledge"])

# 指定 capability
news = await search("AI policy", domain="web", capability="search_news", limit=10)

# 命名空间能力(须显式源)
oa = await search("10.1038/nature12345", domain="paper",
                  capability="unpaywall:find_oa", sources=["unpaywall"])

3. 默认源逻辑

每个源在 SourceAdapter 上有 default_for: frozenset[str]。registry.defaults_for(domain, capability) 按声明顺序返回所有标了 <domain>:<capability> 的源。

  • paper:search 默认:openalex + arxiv(CLI 兼容旧版给 5 源)
  • patent:search 默认:google_patents
  • web:search 默认:duckduckgo + bing

高风险源(带 tags={"high_risk"})必须 default_for=frozenset(),不进默认集——tests/registry/test_consistency.py::test_high_risk_not_default 强制校验。


4. 限流与异常隔离

  • per-event-loop Semaphore:channel search 默认 10 个并发。
  • 每源独立限流:Token Bucket + 滑动窗口;触发 RateLimitError。
  • 异常隔离:单源失败 → meta.failed,不阻塞其他源。
  • HTTP 端点:所有源失败返 502 bad_gateway;超过 timeout 返 504。

5. 完整端到端示例

import asyncio
from souwen.facade import search

async def find_papers(query: str):
    resp = await search(query, domain="paper",
                        sources=["openalex", "semantic_scholar", "arxiv"], limit=5)
    seen = set()
    for sr in resp:
        for r in sr.results:
            if r.doi and r.doi not in seen:
                seen.add(r.doi)
                print(f"{r.year} | {r.title[:80]} | {r.doi}")

asyncio.run(find_papers("graph neural network"))

6. 接下来

Clone this wiki locally