2025-03-01 21:27 - 21:55 (28 分钟)
ai_search/proxy_pool.py ✅文件:/srv/projects/agent-reach/ai_search/proxy_pool.py (200 行)
核心类:
- ProxyStat:记录单个 (proxy, domain) 的成功/失败/延迟统计
- SmartProxyPool:智能代理池,评分公式:
python
score = success_rate × speed_factor × recency_bonus
# speed_factor = min(1000 / avg_latency_ms, 2.0)
# recency_bonus = 1.2 (30分钟内成功) | 0.8 (30分钟内失败) | 1.0 (其他)
# 未测试代理: exploration_score = 0.4
持久化:~/.ai-search/proxy-stats.json,30秒防抖写入
单例:init_pool() / get_pool()
ai_search/channels/base.py ✅新增:
- PROXY_MODE 类属性:"fallback" | "always" | "never"
- async def fetch() 方法:统一 HTTP 请求,自动使用代理池
- 最多尝试 4 个候选代理
- 记录每次请求的成功/失败和延迟
- 403/429/503 视为失败,继续下一个代理
导入:添加 import httpx, time, urlparse
self.fetch() ✅| Channel | PROXY_MODE | HTTP 调用替换 |
|---|---|---|
| searxng | never |
无 HTTP 调用(requests 用于 localhost) |
| exa_search | never |
无需改(MCP) |
| xiaohongshu | never |
无需改(MCP) |
| bosszhipin | never |
requests.get → self.fetch() |
always |
完全重写,删除旧 reddit_proxy 逻辑 |
|
| bilibili | always |
更新 check(),保留 yt-dlp subprocess proxy(legacy) |
| web | fallback |
requests.get → self.fetch() |
| github | fallback |
无 HTTP 调用(gh CLI subprocess) |
| youtube | fallback |
无 HTTP 调用(yt-dlp subprocess) |
fallback |
Jina fallback: requests.get → self.fetch() |
|
fallback |
Jina fallback: requests.get → self.fetch() |
|
fallback |
Jina fallback: requests.get → self.fetch() |
|
| rss | fallback |
无 HTTP 调用(feedparser) |
重点改造:
- reddit.py:完全重写,删除 config.get("reddit_proxy"),改用 self.fetch(),PROXY_MODE=always
- bilibili.py:更新 check() 显示代理池状态,保留 yt-dlp 的 --proxy 参数(subprocess)
- web.py:requests.get → self.fetch()
- twitter.py:_read_jina() 中 requests.get → self.fetch()
- linkedin.py:_read_jina() 中 requests.get → self.fetch()
- instagram.py:_read_jina() 中 requests.get → self.fetch()
- bosszhipin.py:_read_jina() 中 requests.get → self.fetch()
config.py ✅新增:
PROXY_POOL_DEFAULT = [
"socks5h://127.0.0.1:50002",
"socks5h://127.0.0.1:50004",
"socks5h://127.0.0.1:50005",
"socks5h://127.0.0.1:50006",
"socks5h://127.0.0.1:50007",
"socks5h://127.0.0.1:50008",
"socks5h://127.0.0.1:50009",
"socks5h://127.0.0.1:50010",
"socks5h://127.0.0.1:50013",
]
def get_proxy_pool(self) -> list:
return self.get("proxy_pool", self.PROXY_POOL_DEFAULT)
删除:FEATURE_REQUIREMENTS 中的 "reddit_proxy": ["reddit_proxy"]
core.py ✅修改:AISearch.__init__() 中添加:
from ai_search.proxy_pool import init_pool
proxies = self.config.get_proxy_pool()
if proxies:
init_pool(proxies)
proxy-status 和 proxy-reset ✅新增命令:
- ai-search proxy-status:展示每个域名的最优代理和统计
- ai-search proxy-reset [--domain <domain>]:重置学习数据
实现:
- _cmd_proxy_status():调用 pool.summary(),格式化输出
- _cmd_proxy_reset():调用 pool.reset_domain() 或 pool.stats.clear()
修改:_cmd_doctor() 也初始化代理池(确保 doctor 能正确显示代理池状态)
新增:
"httpx[socks]>=0.24",
"socksio>=1.0.0",
安装:pip install -e . --break-system-packages
core.py 搜索路由 ✅改造方法:
- search_github():优先 self.find(query, engines="github"),fallback 到 channel.search()
- search_youtube():优先 self.find(query, engines="youtube"),fallback 到 channel.search()
- search_bilibili():优先 self.find(query, engines="bilibili"),fallback 到 channel.search()
- search_reddit():使用 self.find(query + " site:reddit.com", engines="google"),fallback 到 Exa
原理:SearXNG 的 github/youtube/bilibili/google 引擎作为主搜索,Channel 的 search() 作为 fallback
# GitHub — 走 SearXNG
ai-search search-github "machine learning" -n 3
# 结果:tensorflow/tensorflow, huggingface/transformers, microsoft/ML-For-Beginners
# Reddit — 走 SearXNG google + site:reddit.com
ai-search search-reddit "python" -n 3
# 结果:r/Python, 日文帖子, "What are the real downsides of python?"
ai-search version
# AI Search v2.0.0
ai-search proxy-status
# 暂无统计(首次运行)
ai-search read "https://www.reddit.com/r/Python/top/.json?limit=2"
# 成功返回 r/Python — top,3 个帖子
ai-search proxy-status
# 域名 最优代理 成功率 延迟
# www.reddit.com ocks5h://127.0.0.1:50004 100% 1990ms
学习数据:~/.ai-search/proxy-stats.json
{
"www.reddit.com": {
"socks5h://127.0.0.1:50002": {
"success": 0, "fail": 1, ...
},
"socks5h://127.0.0.1:50004": {
"success": 1, "fail": 0, "total_latency_ms": 1990.04, ...
}
}
}
ai-search search-github "machine learning" -n 3
# 走 SearXNG github 引擎,返回 3 个结果
ai-search search-reddit "python" -n 3
# 走 SearXNG google + site:reddit.com,返回 3 个结果
ai-search web "test" -n 3
# Speedtest, Test - Wikipedia, Merriam-Webster
ai-search find "diabetes" --engine clinicaltrials -n 3
# 3 个临床试验结果
ai-search doctor
# ✅ B站视频信息和字幕 — 代理池已就绪(9 个节点),yt-dlp + 代理池
# ✅ Reddit 帖子和评论 — 代理池已就绪(9 个节点)
pytest tests/test_searxng.py -v --tb=short
# ================== 31 passed, 3 warnings in 110.26s ==================
| 文件 | 行数 | 说明 |
|---|---|---|
proxy_pool.py |
200 | 新增 |
base.py |
+60 | 新增 fetch() 方法 |
config.py |
+15 | 新增 get_proxy_pool() |
core.py |
+10 | 初始化代理池 + 重叠路由重构 |
cli.py |
+50 | 新增 proxy-status/proxy-reset 命令 |
reddit.py |
重写 | 删除旧代理逻辑,改用 self.fetch() |
bilibili.py |
+5 | 更新 check() |
web.py |
+2 | requests → self.fetch() |
twitter.py |
+2 | requests → self.fetch() |
linkedin.py |
+2 | requests → self.fetch() |
instagram.py |
+2 | requests → self.fetch() |
bosszhipin.py |
+2 | requests → self.fetch() |
| 其他 7 个 channel | +7 | 添加 PROXY_MODE |
pyproject.toml |
+2 | 添加 httpx[socks], socksio |
总计:~360 行新增/修改
never:localhost 服务(SearXNG)、MCP 服务器always:必须走代理(Reddit、Bilibili)fallback:优先最优选项(可能是直连)--proxy 参数保留(legacy),因为 yt-dlp 是 subprocess 调用,不走 httpx这些限制是合理的,因为 subprocess 调用的工具有自己的代理配置机制。
交接给 reviewer(agent:reviewer:main)进行代码审查。