起因:只有一台 Win7 老机器
手头只有一台 Windows 7 机器,想玩 AI Agent。
结果发现现代 AI 栈在老系统上全是坑:
- pydantic_core 是 Rust 编译的,Win7 加载 DLL 直接崩
- openai SDK 依赖 jiter(也是 Rust),同样挂
- duckduckgo-search 依赖 primp(还是 Rust),装都装不上
- typer 和现代 click 版本冲突
我当时心态崩了。
但这反而激发了一个想法:如果把所有现代依赖全部砍掉,用纯 Python 标准库重写,能跑吗?
于是开始了一个跨越 30 年操作系统史的项目。
系列全景
从 Win3.1 到 Win11,一共做了 6 个仓库:
| 仓库 | 平台 | 行数 | 核心突破 |
|---|---|---|---|
| open-research-agent | Win7 | 500 | pydantic 1.x + httpx 抓 Bing |
| xp-agent | XP | 29 | 纯标准库,零依赖 |
| win2000-agent | Win2000 | 50 | Py2.7/3.x 双兼容 |
| win31-agent | Win 3.1 | 80 | 视觉复古(蓝底 + ASCII 窗口框) |
| win98-agent | Win98 | 80 | 视觉复古(DOS 提示符) |
| legacy-agents | 汇总 | — | 索引仓库 |
技术核心:三步砍掉所有依赖
1. pydantic 2.x → 1.10.13
pip install "pydantic==1.10.13"
pydantic_core 是 Rust 编译的,Win7 上 DLL 加载失败。降级到 1.10.13(纯 Python 实现)即可。代码里把所有 .model_dump() 改成 .dict()。
2. 抛弃 openai SDK,改用 httpx 直调
openai>=1.x 依赖 jiter,Win7 同样挂。直接用 httpx 调 OpenAI 兼容接口:
import httpx, json
def chat(messages, model, api_key, base_url):
payload = {"model": model, "messages": messages, "temperature": 0.2}
headers = {
"Authorization": "Bearer " + api_key,
"Content-Type": "application/json",
}
with httpx.Client(timeout=300) as client:
r = client.post(base_url + "/chat/completions",
headers=headers, json=payload)
return r.json()["choices"][0]["message"]["content"]
零 SDK 依赖,Win7 能跑。
3. 抛弃 duckduckgo-search,改用百度 + Bing
duckduckgo-search 依赖 primp(Rust),Win7 装不上。直接用 httpx + BeautifulSoup 抓百度:
import httpx
from bs4 import BeautifulSoup
from urllib.parse import quote
def web_search(query, top_k=5):
url = "www.baidu.com/s?wd=" + quote(query)
r = httpx.get(url, headers={"User-Agent": "Mozilla/5.0"})
soup = BeautifulSoup(r.text, "html.parser")
results = []
for h3 in soup.find_all("h3")[:top_k]:
a = h3.find("a")
if a:
results.append(a.get_text(strip=True))
return results
踩过的 5 个真 Bug
Bug 1:搜索无限循环
LLM(GLM-4-Flash)每一步都生成完全相同的 query,导致 agent 死循环 8 次以上。
修复:加 query 去重 + 搜索次数上限。
Bug 2:LLM 复读同一 query
去重挡住了循环,但模型还是只会复读。
修复:把候选 query 生成从 LLM 移到代码——从初始搜索结果里抠关键词,按列表依次使用。
Bug 3:Bing 中文泛化
搜索"固态电池最新进展",Bing 返回一堆"固态硬盘"——因为都含"固态"两个字。
修复:改用百度优先(中文分词好),Bing 只做严格过滤的 fallback。
Bug 4:报告生成超时
GLM-4-Flash 写 2000+ 字报告要 3-8 分钟,经常超时。
修复:限制报告 800-1200 字,加超时重试,换更快的模型。
Bug 5:Bing fallback 泄漏
百度结果不足时 fallback 到 Bing,Bing 又泛化到固态硬盘。
修复:严格过滤——必须同时包含核心词前 3 字和技术关键词。
v0.13 现状
主项目 open-research-agent 迭代到 v0.13:
- 流式 Web UI:SSE 实时日志,每步搜索都能看到
- BYOK:用户自己填 API Key,只存浏览器 localStorage
- 6 个 LLM 后端:智谱 / Intern InkStone / DeepSeek / 硅基流动 / Kimi / OpenAI
- 百度 + Bing 双引擎:严格相关性过滤
- PDF 导出:浏览器直接打印
- PWA:可安装到手机主屏
- Docker:docker compose up 一键部署
- Windows 无窗口启动:双击 VBS 后台跑
实测效果
用 Intern InkStone 的 DeepSeek-V4-Flash 跑"固态电池最新进展":
- 5 步搜索,全是固态电池相关
- 报告 5 小节,900 字
- 8 条真实来源
- 零编造文献
两个待解的挑战
挑战 1:Win2000 的 TLS 1.2
Win2000 最高只能装 Python 2.7.8,自带 OpenSSL 0.9.8,只支持 TLS 1.0。现代 API 都要求 TLS 1.2。
方案:stunnel 做本地 TLS 代理——Python 走 HTTP 到本地,stunnel 升级到 TLS 1.2 转发出去。
issue:github.com/doujiaozh/w…
挑战 2:Win3.1 装 Python 1.5
有个小红书用户指出:Win3.1 可以装 Win32s + Python 1.5,PuTTY 有 Win32s 的反向移植。
理论上:Win3.1 + Win32s + Python 1.5 → 手写 socket → PuTTY 做 TLS 代理。
issue:github.com/doujiaozh/w…
开源地址
- 主项目:github.com/doujiaozh/o…
- XP 版:github.com/doujiaozh/x…
- Win2000 版:github.com/doujiaozh/w…
- Win31 版:github.com/doujiaozh/w…
- Win98 版:github.com/doujiaozh/w…
- 索引:github.com/doujiaozh/l…
MIT 协议,随便用。
如果你有真 Win3.1 / Win2000 机器,欢迎来挑战 issue。