任务 ID: task-t038p2-95e3c0  |  文件: task.md  |  最后修改: 2026-03-01 19:40:33

Task task-t038p2-95e3c0 — ai-search 核心重构(T038-P2)

文件路径

原始需求

将 agent-reach 重构为 ai-search:包目录重命名、新增 SearXNG channel、扩展核心搜索方法。
这是 T038 搜索工具整合的第二阶段(核心代码重构)。

详细方案文档/root/.openclaw/workspace/memory/docs/todo/T038-R-refactor-plan.md(必读,包含完整架构、代码盘点、目录结构)

关键约束


执行链

coder → reviewer → 爱衣质检


各 Agent 职责


Ai.Dev 💻(session key: agent:coder:main

任务:执行 ai-search 核心重构,共 9 个子步骤。

执行前必读
1. /root/.openclaw/workspace/memory/docs/todo/T038-R-refactor-plan.md — 完整方案
2. /srv/projects/agent-reach/pyproject.toml — 当前项目配置
3. /srv/projects/agent-reach/agent_reach/core.py — 当前核心类
4. /srv/projects/agent-reach/agent_reach/channels/__init__.py — 当前 channel 注册

Step 2.1:包目录重命名

cd /srv/projects/agent-reach
# 复制而非 mv,保留 agent_reach/ 做兼容层
cp -r agent_reach ai_search

Step 2.2:全局 import 替换

cd /srv/projects/agent-reach/ai_search
# 替换所有 import/from 引用
grep -rl "agent_reach" . | xargs sed -i 's/agent_reach/ai_search/g'

⚠️ 仅替换 ai_search/ 目录内文件!不要动 agent_reach/(兼容层)

Step 2.3:pyproject.toml 改名 + entry point

[project]
name = "ai-search"
version = "2.0.0"
description = "统一搜索引擎:SearXNG + 平台搜索 + 语义搜索 + URL 读取"

[project.scripts]
ai-search = "ai_search.cli:main"
agent-reach = "ai_search.cli:main"   # 向后兼容别名

Step 2.4:兼容层 agent_reach/__init__.py
清空原 agent_reach/ 目录下除 init.py 外的所有文件(或保留整个目录只改 init.py),写入:

"""Backward compatibility — 'agent_reach' is now 'ai_search'."""
from ai_search import *  # noqa: F401,F403

注意:agent_reach/ 目录下其他 .py 文件可以删除(因为 ai_search/ 已经是新的主包),但 init.py 必须保留上面的转发。如果有外部代码 from agent_reach.channels.twitter import ... 这种深层 import,需要在 agent_reach/ 保留目录结构做转发。评估后决定最简方案。

Step 2.5:新增 ai_search/channels/searxng.py(~150 行)

核心类 SearXNGChannel(Channel),实现:
- name = "searxng"
- search(query, config, categories=None, engines=None, time_range=None, language=None, limit=20)List[SearchResult]
- list_categories(config) → 从 SearXNG /config API 动态获取
- list_engines(config, category=None) → 从 SearXNG /config API 动态获取,可按分类过滤
- check(config) → 健康检查
- can_handle(url) → return False(SearXNG 不处理 URL 读取)

分类别名映射:

CATEGORY_ALIASES = {
    "academic": "science",
    "qa": "q&a",
    "code": "repos",
    "pkg": "packages",
    "social": "social media",
    "wiki": "wikimedia",
}

搜索 API 调用:

GET http://127.0.0.1:8889/search?q={query}&format=json&categories={cat}&engines={eng}&time_range={tr}&language={lang}

Step 2.6:修改 ai_search/channels/__init__.py
在 channel 注册表中添加 SearXNGChannel。查看现有注册方式并遵循。

Step 2.7:扩展 ai_search/core.py
在主类中添加方法(保留原有所有方法不变):
- async web(query, time_range=None, language=None, limit=20) — 通用搜索(categories="general")
- async find(query, category=None, engines=None, time_range=None, language=None, limit=20) — 分类/引擎搜索
- async list_categories() — 列出 SearXNG 分类
- async list_engines(category=None) — 列出引擎

如果原来的类名是 AgentReach,保留别名:AgentReach = AISearch

Step 2.8:扩展 ai_search/config.py
添加 searxng_url 配置项,默认值 http://127.0.0.1:8889

Step 2.9:扩展 ai_search/doctor.py
添加 SearXNG 容器状态检查(调用 SearXNGChannel.check())

安装验证

cd /srv/projects/agent-reach
pip install -e . 2>&1 | tail -5
# 验证两个命令都能用
ai-search version
agent-reach version
# 验证 import
python3 -c "from ai_search.core import AISearch; print('ai_search OK')"
python3 -c "from agent_reach import *; print('agent_reach compat OK')"

开始时:

/root/.openclaw/workspace/scripts/log-to-channel.sh coder receive "T038-P2 核心重构" task-t038p2-95e3c0

完成后:
1. 在 task 目录创建 T038-P2-RESULT.md,记录每步执行结果、验证输出
2. 将执行日志追加到 session.md
3. 发工作日志:
bash /root/.openclaw/workspace/scripts/log-to-channel.sh coder handoff "T038-P2 核心重构" reviewer task-t038p2-95e3c0
4. sessions_send 通知 reviewer(agent:reviewer:main必须传 timeoutSeconds=0):
task_id=task-t038p2-95e3c0 task=/root/.openclaw/workspace/tasks/task-t038p2-95e3c0/task.md


Ai.Rev 📋(session key: agent:reviewer:main

任务:审查核心重构,验证功能完整性和兼容性。

审查要点:

  1. 代码质量
  2. 检查 searxng.py 是否遵循 base.py Channel 接口
  3. 检查 core.py 新方法命名与现有方法风格一致
  4. 检查 import 替换是否完整(grep -r "agent_reach" /srv/projects/agent-reach/ai_search/
  5. 检查是否有遗漏的硬编码路径

  6. 功能验证
    ```bash
    # SearXNG channel 搜索
    cd /srv/projects/agent-reach
    python3 -c "
    import asyncio
    from ai_search.channels.searxng import SearXNGChannel
    ch = SearXNGChannel()
    # check
    status, msg = ch.check()
    print(f'Health: {status} - {msg}')
    # search
    results = asyncio.run(ch.search('artificial intelligence', categories='general'))
    print(f'Search: {len(results)} results')
    if results:
    print(f' First: {results[0].title[:50]}')
    # list
    cats = asyncio.run(ch.list_categories())
    print(f'Categories: {len(cats)}')
    engines = asyncio.run(ch.list_engines(category='science'))
    print(f'Science engines: {len(engines)}')
    "

# core.py 新方法
python3 -c "
import asyncio
from ai_search.core import AISearch
s = AISearch()
r = asyncio.run(s.web('test'))
print(f'web(): {len(r)} results')
r = asyncio.run(s.find('test', category='science'))
print(f'find(science): {len(r)} results')
cats = asyncio.run(s.list_categories())
print(f'list_categories(): {len(cats)}')
"
```

  1. 兼容性验证
    ```bash
    # CLI 别名
    ai-search version && echo "ai-search OK"
    agent-reach version && echo "agent-reach OK"

# import 兼容
python3 -c "from agent_reach import *; print('compat import OK')"

# 现有 channel 未被破坏(doctor 检查)
ai-search doctor
```

  1. 零修改文件检查
    bash # 确认 12 个 channel 文件没被改过 cd /srv/projects/agent-reach for f in twitter youtube github reddit bilibili xiaohongshu instagram linkedin bosszhipin exa_search web rss; do diff agent_reach/channels/${f}.py ai_search/channels/${f}.py > /dev/null 2>&1 \ && echo "$f: ✅ 未修改" \ || echo "$f: ❌ 被修改了!" done # base.py 也不能改 diff agent_reach/channels/base.py ai_search/channels/base.py > /dev/null 2>&1 \ && echo "base.py: ✅" || echo "base.py: ❌"
    注意:ai_search/ 内的文件里 import 从 agent_reach 改为 ai_search 是正常的,这里只检查业务逻辑是否变了。正确的检查方式是看除 import 行外的内容是否一致:
    bash for f in twitter youtube github reddit bilibili xiaohongshu instagram linkedin bosszhipin exa_search web rss base; do diff <(grep -v "agent_reach\|ai_search" agent_reach/channels/${f}.py) \ <(grep -v "agent_reach\|ai_search" ai_search/channels/${f}.py) > /dev/null 2>&1 \ && echo "$f: ✅ 逻辑未变" \ || echo "$f: ❌ 逻辑被改了!" done

开始时:

/root/.openclaw/workspace/scripts/log-to-channel.sh reviewer receive "T038-P2 核心重构" task-t038p2-95e3c0

完成后:
1. 审查报告追加到 session.md(通过/不通过 + 问题列表)
2. 发工作日志:
bash /root/.openclaw/workspace/scripts/log-to-channel.sh reviewer handoff "T038-P2 核心重构" main task-t038p2-95e3c0
3. sessions_send 通知爱衣(agent:main:main必须传 timeoutSeconds=0):
task_id=task-t038p2-95e3c0 task=/root/.openclaw/workspace/tasks/task-t038p2-95e3c0/task.md


⚠️ 爱衣质检 SOP(收到最终通知后执行)

Step 1:评估工作区大小

du -sb /root/.openclaw/workspace/tasks/task-t038p2-95e3c0/

Step 2:读取 session.md

Step 3:质检要点

通用检查:
- 产出是否符合原始需求?
- 执行过程是否有明显问题?
- Agent 间是否有未解决的分歧?

任务特定检查:
- ai-search web "test" 是否返回 SearXNG 结果?
- ai-search find "test" --cat science 是否正确走分类搜索?
- agent-reach version 是否仍可用?
- from agent_reach import * 是否正常?
- 12 个 channel 文件的业务逻辑是否完全未变?
- searxng.py 是否有分类别名映射?
- core.py 新方法与旧方法风格是否一致?

Step 4:输出结论

通过 → log done + message 主人
不通过(rejectCount == 0) → 创建 retry task,log retry
rejectCount >= 1 → log fail + message 主人请裁决

超限处理

读 task.md + session.md 末尾 200 行,message 主人建议人工审计