/root/.openclaw/workspace/tasks/task-t038p2-95e3c0/task.md/root/.openclaw/workspace/tasks/task-t038p2-95e3c0/session.md将 agent-reach 重构为 ai-search:包目录重命名、新增 SearXNG channel、扩展核心搜索方法。
这是 T038 搜索工具整合的第二阶段(核心代码重构)。
详细方案文档:/root/.openclaw/workspace/memory/docs/todo/T038-R-refactor-plan.md(必读,包含完整架构、代码盘点、目录结构)
agent-reach CLI 别名必须保留可用http://127.0.0.1:8889(host 网络模式,已可用)coder → reviewer → 爱衣质检
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
agent:reviewer:main)任务:审查核心重构,验证功能完整性和兼容性。
审查要点:
grep -r "agent_reach" /srv/projects/agent-reach/ai_search/)检查是否有遗漏的硬编码路径
功能验证
```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)}')
"
```
# import 兼容
python3 -c "from agent_reach import *; print('compat import OK')"
# 现有 channel 未被破坏(doctor 检查)
ai-search doctor
```
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: ❌"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
du -sb /root/.openclaw/workspace/tasks/task-t038p2-95e3c0/
通用检查:
- 产出是否符合原始需求?
- 执行过程是否有明显问题?
- 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 新方法与旧方法风格是否一致?
通过 → log done + message 主人
不通过(rejectCount == 0) → 创建 retry task,log retry
rejectCount >= 1 → log fail + message 主人请裁决
读 task.md + session.md 末尾 200 行,message 主人建议人工审计