首先你需要找到一个蛇头,在本论坛就有,他/她负责接单,你负责搬砖,如果找不到可以去留学生论坛去以“作业辅导”的名义发帖,然后小红书是一个非常重要的宣传口,里面巨多富哥富姐
作业的内容千奇百怪,不过最好你只接本专业的,比如我是数学系,我接了很多统计学的,然后我本人是程序员,也接了很多开发任务,有时甚至有回头客

薪资方面,基本上 3-500 一小时,遇到土豪老板 700 一小时也是有的

需要注意的是,很多作业是不让用 AI 的,所以不要用 AI 去糊弄然后翻车,你可以遇到不会的用 AI 自学,然后手写
另外富哥们一般都是 deadline 前几天才出来找枪手,所以你的时间会非常紧张,不要浪费时间

最近站里各位佬的公益站 / 转发站越来越多,屯屯鼠本鼠余额也攒了不少。公益站稳定性不可预测,经常写着写着代码就得停下来换站点。

所以让 Claude 搓了这个:Claude Code Proxy

用了 N 周还算稳定,就一个 py 脚本,核心功能:

  • Web UI 切换供应商,自动拉取模型列表
  • 一键复制 URL/Key/Model、打开签到 / 福利站链接、保持账号活跃
  • 多终端统一出口 IP,避免多设备访问同一公益站被封号

快速开始

仓库地址: GitHub - QAA-Tools/ccproxy: 轻量级 Claude API 反向代理,Web UI 即时切换供应商,自动发现模型,批量测试保持账号活跃。Lightweight Claude API reverse proxy with Web UI for instant provider switching, auto model discovery, batch testing to keep accounts active.

使用文档: Claude Code Proxy - 轻量级 Claude 代理切换工具

  1. 复制配置文件:
copy config.in.json config.json
  1. 编辑 config.json,填入你的公益站信息:
{ "HOST": "0.0.0.0", "PORT": 3456, "APIKEY": "sk-your-local-ui-key", "Providers": [ { "name": "站点1", "api_base_url": "https://api.example.com/v1/messages", "api_key": "sk-provider-key-1", "models": [], "checkin": "https://example.com/console/personal" } ] } 
  1. 启动代理:
python ccproxy.py --config config.json
  1. 修改 Claude Code 配置(~/.claude/settings.json%USERPROFILE%\.claude\settings.json):
{ "env": { "ANTHROPIC_AUTH_TOKEN": "sk-your-local-ui-key", "ANTHROPIC_BASE_URL": "http://127.0.0.1:3456" } } 

注意: ANTHROPIC_AUTH_TOKEN 要和上面的 APIKEY 一致。改完重启 CC CC 支持热重载,不用重启。

  1. WebUI 地址 http://127.0.0.1:3456,用 APIKEY 作为密码登录(用户名随便填)

WebUI 使用

基础操作:

  • 下拉选择 provider,立即生效
  • Refresh 按钮自动拉取上游模型列表
  • 选模型后点 Copy,粘贴 /model xxx 命令到 CC 切换模型
  • 上游挂了就回网页换一个
  • 改了 config.jsonReload Config 重新载入,不用重启代理

保活操作:

  • Refresh & Test 按钮,屯屯鼠保活,测试结果显示为颜色:绿色(成功)/ 黑色(失败)
  • 若失败可查看输出日志排查原因
  • 签到 按钮快速跳转到站点签到页面领额度

进阶技巧:

  • 点击 settings.json 按钮,将剪贴板粘贴到 ~/.claude/settings.json 文件中,也可以不重启 Claude Code 立即切换供应商


本脚本的配置格式兼容 ccr,但不包含模型转换功能(只支持原生 Claude 格式的 API)。

(对比) 之前采用的 公益站 切换方案:

  • NewAPI:能自动拉模型列表,兼容 CC/Chat 等调用方式,适合佬们开公益站。但个人用来管理公益站 URL 的话,出问题排查太费事
  • ccr:功能很全,路由能力强(能把不同模型转换)。但模型列表要自己填,Web 界面改配置经常不生效,路由功能用不到
  • cc-switch:热重启切换,单机体验很好。但配置只能图形界面或 SQLite 改,我更习惯直接编辑 JSON

因为经常要在 Linux 服务器上跑,就想要个更简单的方案:JSON 配置 + 不重启 CC 就能切换 + 自动拉模型列表 + 定期保活避免被清号。

类似项目推荐


📌 转载信息
转载时间:
2026/1/12 11:38:58

分享一个自用的 Certimate docker compose file 配置,一个支持 SSL 证书从申请到部署完全自动化的开源软件。

文档 | Certimate

https://docs.certimate.me/zh-CN/docs/introduction/

services: certimate:  certimate/certimate:latest container_name: certimate restart: always ports: - "127.0.0.1:8090:8090" volumes: - /etc/localtime:/etc/localtime:ro - ./data:/app/pb_data environment: - TZ=Asia/Shanghai deploy: resources: limits: memory: 512M reservations: memory: 128M security_opt: - no-new-privileges:true read_only: true tmpfs: - /tmp:size=64M,mode=1777 healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://localhost:8090/api/health"]
      interval: 30s timeout: 10s retries: 3 start_period: 10s logging: driver: json-file options: max-size: "10m" max-file: "3" compress: "true" networks: default: driver: bridge 

📌 转载信息
原作者:
puppetdevz
转载时间:
2026/1/12 11:38:43

用佬友的方案部署的,不知道啥时候失效,用完为止
url:https://etsotlncsvnk.ap-southeast-1.clawcloudrun.com
key:sk-qVGqv9cfMz2T8zhVbKDoRem4M7UhynLbPH46YgrHfZqVCEnJ
可用模型:gemini-3-pro-preview(包含生图)、gemini-3-flash-preview、gemini-2.5-pro、gemini-2.5-flash


📌 转载信息
原作者:
cjdem
转载时间:
2026/1/12 11:38:21

前期回顾
https://linux.do/t/topic/776482
https://linux.do/t/topic/777708

封号时间:2025 年 8 月 8 日
封号原因:不断的绑卡,试卡,想白嫖谷歌云 300 刀,后面直接被谷歌封禁。

补救措施:被封控之后,我不断的尝试申诉登录,结果风控系统升级,之前绑定的二次验证,恢复邮箱和手机号码,备用码,包括 2fa 都用不了,必须要注册时的号码。

因为是接码平台注册,不能二次接码,进入死循环无法完成验证和申诉。

得出的结论:当被账号封控之后,我们不要做过多的尝试,尝试次数过多,封控会越来越强,最有效的方法就是晾着不管,等待一周,一个月,三个月或半年多,再尝试登陆谷歌会让你重新填一个号码。

gemini 告诉我,封控的账号有冷却时间,试过一次不成功就不要尝试了,得过 24 小时,要不然会加重封控。

这时要找长期稳定能接码的号码,家人或朋友的号码都可以,86 的也行的,说来也奇怪,我这个号码都绑定了很多账号的恢复号码和验证号码,那天可能是 ip 质量好,一填上去就能顺利接码,我猜测用于安全存储的安全验证号码,可能 2~3 个月才能接一次。

我还有两个谷歌靓号账号也是只要找稳定能接码的号码就能救回,在删号前救回就行了,如下图所示。

救号流程:我们输入邮箱和密码,过人机验证,验证 2fa,重新填一个新的接码号码,验证号码,这时候会提示你账号已经被封禁,“看起来这个账户的使用方式违反了谷歌的政策。
该账户已于 202x 年 x 月 x 日失效。自 202x 年 x 月 x 日起,该账户将被考虑删除。” 点击开始上述,申诉理由可以让 ai 写,内容大概是我是美国人,在中国工作,需要使用 vpn, ip 变动大,或者我是真实用户,机器审核的。然后填写一个通知邮箱,等待邮件通知,一般第 2 天就会收到。如果审核通过了,恢复了最好也要晾个一两天,找一个干净的 ip 登录。申诉不过的话,隔几天再重新申请。

这个时候你再登录,会让你重新接码验证,收到验证号码,填入就能登录,登录再修改一下密码和头像之类的,活跃一下账号。

保号养号措施:经常使用谷歌生态应用就行,尽可能的像真人使用,例如收发邮件,使用谷歌搜索,观看油管,使用谷歌硬盘之类的。

2026 年注册谷歌账号流程:
用没有注册过的安卓手机,平板或者苹果手机,在谷歌邮箱 app 或者谷歌商店里面添加账号注册就行,尽可能的模拟真实环境,提前几天修改手机的国家,时区还有语言,注册时要关掉手机定位,因为现在注册谷歌账号要求很高,有设备环境验证,ip 网络验证等,提前想好要注册的账号内容(名称,名字,生日,密码)准备好手机号码,为什么要提前准备?在账号注册过程中,如果反复尝试某个环节,谷歌就会将设备标记为不可靠。
账号注册成功之后可能会遇到立刻封号验证手机号码或者强制退出封控,现在这些都是正常的真人验证,按照相应的流程申诉就行,最好也要晾几天再申诉。

账号注册一点都不难,难的是没有那么多号码接码。


📌 转载信息
转载时间:
2026/1/12 11:26:26

方法是旧的,但是在最近一个月严格风控情况是简易又简便。

就是注册谷歌账户时候,选择使用现有邮箱,比如我刚使用 outlook 邮箱注册了一个全新的谷歌账户。3 分钟丝滑搞定。大善人非常友好,让我用 GV 号码就完成了短信验证(感动居然不要实体号码。然后又加入自己的 Google One 家庭组,又一个 PRO 账户瞬间搞定

管用就点赞呗


📌 转载信息
原作者:
pijiu
转载时间:
2026/1/12 11:25:49

25 年写的中行预约的填充信息的脚本,26 年应该还能用,可惜湖北今年不是在中行约了,发出来给大家参考,自行修改关键信息,主要是一键填充信息,预约还是要自己提交的,我记得预约界面还有短信验证码和图片验证码

中行的纪念币预约地址: 中国银行纪念币销售

脚本里还有填充预约查询的,可以试试看。记得修改脚本里要填写的内容

javascript: (function() {
	var t = 0,
	e = 0;
	try {
		document.getElementById("txt_name_1956714") && (document.getElementById("txt_name_1956714").value = "姓名") ? t++:e++
	} catch(t) {
		e++
	}
	try {
		document.getElementById("txt_mobile_1956715") && (document.getElementById("txt_mobile_1956715").value = "手机号") ? t++:e++
	} catch(t) {
		e++
	}
	try {
		document.getElementById("txt_phonenumber_1956668") && (document.getElementById("txt_phonenumber_1956668").value = "手机号") ? t++:e++
	} catch(t) {
		e++
	}
	try {
		document.getElementById("txt_identitynumber_1956717") && (document.getElementById("txt_identitynumber_1956717").value = "身份证号") ? t++:e++
	} catch(t) {
		e++
	}
	try {
		document.getElementById("txt_identitynumber_1956669") && (document.getElementById("txt_identitynumber_1956669").value = "身份证号") ? t++:e++
	} catch(t) {
		e++
	}
	try {
		document.getElementById("date-picker") && (document.getElementById("date-picker").value = "预约的日期如2025/05/10") ? t++:e++
	} catch(t) {
		e++
	}
	try {
		document.getElementById("sel_93844_1956719") && (document.getElementById("sel_93844_1956719").value = "数量") ? t++:e++
	} catch(t) {
		e++
	}
	console.log("完成!成功:" + t + "个,失败:" + e + "个")
})();

📌 转载信息
原作者:
nssiwi
转载时间:
2026/1/12 11:06:58


如图,每次一轮对话完成进行 toast 提示 + 系统提示音

{ "alwaysThinkingEnabled": true, "env": { "ANTHROPIC_MODEL": "claude-sonnet-4-5-20250929", }, "hooks": { "Stop": [ { "hooks": [ { "command": "powershell -NoProfile -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null; $t=[Windows.UI.Notifications.ToastTemplateType]::ToastText02; $x=[Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($t); $x.GetElementsByTagName('text')[0].AppendChild($x.CreateTextNode('Claude'))|Out-Null; $x.GetElementsByTagName('text')[1].AppendChild($x.CreateTextNode('Stop'))|Out-Null; $toast=[Windows.UI.Notifications.ToastNotification]::new($x); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('Windows PowerShell').Show($toast)\"", "type": "command" }, { "command": "powershell -NoProfile -Command \"[console]::Beep(1000,200)\"", "type": "command" } ] } ] } } 

📌 转载信息
转载时间:
2026/1/12 10:55:11

之前分享了一个自用的 docx-format skill, 发现能帮到不少佬友。在此分享一个自己更常用的 SKILL:code-style-review. 原理是把我平常的代码风格沉淀下来作为 SKILL:绝对避免防御性编程、绝对避免复杂性编程。感兴趣的佬友们可以二次开发反馈~

code-style-review.zip

贴一下 SKILL.md 文档:

---
name: code-style-review
description: Python code style guide for clean, maintainable code. Use when writing or reviewing Python code.
---

# Python Code Style Guide

## 必须 (Must)

### Naming
- Classes: `PascalCase` (e.g., `DataLoader`, `ConfigManager`)
- Functions/methods: `snake_case` with verb-first (e.g., `load_data`, `process_batch`)
- Constants: `UPPER_CASE` (e.g., `MAX_RETRIES`, `DEFAULT_TIMEOUT`)
- Math operations: single-letter variables allowed (N, D, x, y)

### Exception Handling
- Fail-fast: no defensive try/except, let errors crash early
- Use `logger.warning()` for recoverable issues, not exceptions

### Code Philosophy
- No over-engineering; keep it simple
- Comments in English only
- Follow Occam's Razor: no unnecessary complexity

## 尽量 (Should)

### Comments & Docs
- Minimal docstrings; only for complex logic
- Explain "why", not "what"
- Self-explanatory code needs no comments

### Imports
- Order: stdlib → third-party → local (blank lines between)
- Prefer absolute imports
- Explicit names, avoid `import *`

### Function Design
- Explicit parameters; avoid `**kwargs`
- Multiple returns: use tuple
- Avoid hidden global state

### Code Organization
- Layered architecture: low-level → high-level
- OOP for core logic
- Separation of concerns

### Aesthetics
- Clean alignment and simple naming
- Colorful output / progress bars for UX
- Use `logging` module

## 可选 (Optional)

### Type Annotations
- Python 3.10+ syntax: `list[int]`, `X | None`
- Annotate public methods and return types

### Assert
- Use sparingly for invariants; don't overuse

### Logging
- Optionally write logs to file (ask user first)

## 加分项 (Nice to Have)

### Data Structures
- Use `@dataclass` for configs
- Prefer simple containers (list, dict)

---

## Code Review (Codex)

All code review is delegated to Codex. Claude should NOT run scripts directly.

When invoking, Claude MUST replace placeholders with absolute paths:
- `{SKILL_DIR}` → absolute path to this skill directory (e.g., `/Users/xxx/.claude/skills/code-style-review`)
- `{TARGET}` → absolute path to file(s) or directory to review (supports multiple files or recursive directory scan)

```bash
codex exec -m gpt-5.2 \
  -c model_reasoning_effort="xhigh" \
  --dangerously-bypass-approvals-and-sandbox \
  --skip-git-repo-check \
  "You are a code style reviewer. Review the Python code for style compliance.

## Paths (absolute)
- Skill directory: {SKILL_DIR}
- Target to review: {TARGET}

## Setup (run once if tools missing)
bash {SKILL_DIR}/setup.sh

## Your Tasks
1. Read the style guide: cat {SKILL_DIR}/skill.md
2. Run automated linter: ruff check --config {SKILL_DIR}/ruff.toml {TARGET}
3. Run custom checker: python3 {SKILL_DIR}/style_check.py {TARGET}
4. Read and analyze the target code
5. Combine automated results with your own analysis

## Output Format
Provide a structured review:
- **Summary**: Overall assessment (pass/needs work/fail)
- **Automated Issues**: List violations from ruff and style_check.py
- **Manual Review**: Issues requiring human judgment (over-engineering, naming clarity, code aesthetics)
- **Suggestions**: Specific, actionable improvements with code examples

## Priority Levels
- 必须 (Must): Violations are errors, must fix
- 尽量 (Should): Violations are warnings, should fix
- 可选 (Optional): Suggestions for improvement
- 加分项 (Nice to Have): Optional enhancements" 2>/dev/null

📌 转载信息
转载时间:
2026/1/12 10:55:07

和前女友分手后,无心他事,自己学习炒股,本金 5000,半个月小赚 400

常用炒股助手

  1. Google AI stuido 相较于网页,幻觉会减少,且会实时搜索,但是它会乱说!!!如果你上文了说了非农,下文分析其他股票它会强行关联到非农的影响,除非新开一个话题。
  2. Chatgpt 用的 k12 版本,不太行,但是 GPT 一点好就是不会瞎说,它会根据新闻资讯来判断,但是很少做出前瞻性建议和判断。
  3. Grok 我常用来进行新闻真伪判断,结合新闻询问 AI

总得来说 AI 作为助手,比我自己瞎炒股靠谱点,是一个很好的帮手。下面有我自己的写的 propmt。一半自己资讯分析一半运气,AI 也是能扩大你了解到的资讯,它会抓取到你没注意到的一些信息。

块引用 1. 你是一位拥有实时联网能力的资深金融分析师。
1. 【核心指令】:
2. 强制联网 (Must Search):对于我询问的任何股票、指数、汇率或新闻,你必须第一时间调用搜索工具查询此时此刻的最新价格、涨跌幅和相关新闻。
1. 我要求联网搜索,enable websearch tool,抓取当前尽可能多的信息,搜索中国(政府网站、东方财富网、雪球网、同花顺、金十财经、微信公众号、网络文章、抖音、小红书等等)、国际上的内外的消息进行分析,不限制数量,可以结合外媒权威的报道进行交叉判断信息的真实性,越详细越权威越好,不要自己乱推理,有数据支撑,不要有太多的感情因素。
3. 数据校验 (Verify):不要依赖你的训练数据,也不要盲目相信我上传文件中的过时 / 未来日期。一切以 Google/Bing 搜索到的最新实时数据为准。
1. enable websearch tool,联网搜索当前日期,并以实时获取的日期当作最新的锚点,实时获取我问的股票、黄金、白银的价格,要多次从不同渠道和资讯验证获取其正确的盘面价格。
1. 如果我给出股票价格以及当前时间以我给出的为准进行分析,可能包含涨停等词语,也需要进行分析。
5. 时间锚定 (Time Anchor):在回答开头,请务必标注你搜索到的 **“当前北京时间” “最新价格”**,并附上来源链接。请忽略所有非实时的预设背景,直接搜索最新数据并分析
6. 并对适合抄底的时机做出判断和建议,以及对我所询问的,给出前瞻性的建议,包括抄底、逃离等,持仓观望、空仓观望等等。
1. 给出是否建议抄底,如不建议给出理由,如建议也要给出理由
2. 给出利空和利好的消息,如果没有相应的消息,可以说没有
4. 如果问的是 A 股市场中的股票,需要结合资讯,给出当前热门的板块和行业,以及这些行业的利好或者利空消息。
7. 在返回最终答复之前,请根据用户的原始约束条件审查您生成的输出。我是否回答了用户的意图,而不仅仅是字面意思?
8. 中英文对照生成 prompt,让 Gemini 更好的理解进而来减少幻觉。以及最后要求中文回答 优化一下上述的 prompt


📌 转载信息
转载时间:
2026/1/12 10:54:52

作者 | 华卫

 

本文为《2025 年度盘点与趋势洞察》系列内容之一,由 InfoQ 技术编辑组策划。本系列覆盖大模型、Agent、具身智能、AI Native 开发范式、AI 工具链与开发、AI+ 传统行业等方向,通过长期跟踪、与业内专家深度访谈等方式,对重点领域进行关键技术进展、核心事件和产业趋势的洞察盘点。内容将在 InfoQ 媒体矩阵陆续放出,欢迎大家持续关注。

 

我们采访了真机智能董事长兼首席科学家刘智勇,听他讲述了视觉语言导航(VLN)技术的当前难题、具身智能领域在 2025 年的各类进展以及今年在能力边界上的两个突破方向和技术决胜点。他表示,一旦世界模型的因果推理能力取得突破,无论是机器人的安全性还是行为和推理的安全性问题,都能得到很好的解决。

 

“2026 年本体厂商肯定会收缩,估计中国最终只会剩下 5 到 8 家本体机器人公司。”他指出,核心是在某个单一场景实现盈利,不是毛利而是不依赖大量售后成本的净利。但单纯的整机销售并非很好的商业模式,如果只卖硬件,后续的售后压力会非常大,用户一次性付太多钱也承受不了。

 

下面是详细对话内容,以飨读者。

VLN 和世界模型上“大分”

 

Q:2025 年具身智能领域有哪些突破性进展让您印象深刻,包括技术、产业化和生态建设上?这些进展是否已经为具身智能从实验室走向特定场景的“初步普及”奠定了基础?

 

刘智勇:我印象比较深刻的是 VLN 方向的相关进展。过去我们主要是以 SLAM 为核心的技术路线,但从去年到现在,涌现出了大量基于视觉语言作为多模态输入的导航模型。这种视觉语言模型能解决零样本泛化的问题,我们不再需要预先构建地图了。把一个机器人放到任何全新的固定场景里,它都能实现零样本泛化,自主完成导航任务。另外,像 UniNavid、ETPNav、FSR - VLN 这些代表性工作,也让机器人门到门配送的实现出现了曙光和可能性。这就是从几何测量的导航范式,转变到学习增强的导航范式。当前的瓶颈在于未达极高的导航成功率。

 

从场景普及的角度来说,核心是我们不再需要预先建图了。这就意味着,把机器人放在任何新的位置上,它都能立刻开始工作,直接解锁了很多之前无法覆盖的场景。最关键的一点是,零样本能力等同于部署成本的大幅降低。部署成本降下来之后,整个成本结构就能适配场景化的盈利模式,这正是为场景普及奠定的核心基础。技术成熟后,前期的准备和部署工作会大幅减少,这也为未来的产业发展打下了很好的基础。

 

Q:具身智能的核心技术栈正在如何演变?2025 年这一年有哪些值得关注的新范式或共识?

 

刘智勇:从算法角度来看,核心变化是从之前感知、决策、执行分离的多模块化范式,逐渐转向 VLN 或 VLA 的端到端统一范式。从数据角度来说,发展方向是从单纯的真实数据采集,逐步转向合成数据、离线轨迹挖掘以及世界模型这些领域。训练范式也发生了改变,从强化学习调参慢慢转向世界模型驱动。现在世界模型算是行业内解决数据问题的一个共识,原因很简单,不管是在长程层面模拟预测未来状态、在底层层面预测动态物体轨迹,还是弥补数据的 corner case,世界模型都起到了不可或缺的作用。

 

Q:世界模型被寄予厚望,被认为是实现高级推理和规划的关键。现阶段来看,它对机器人实际能力的提升体现在何处?之后还有哪些方面的潜力?

 

刘智勇:现阶段来看,主要体现在三个方面。第一,机器人执行长程任务时容易陷入短视困境,而世界模型可以模拟未来的长程状态,对全局规划能力有非常重要的提升;第二,动态环境下静态地图容易失效,无法准确指引路径轨迹,世界模型能够预测动态物体的轨迹,让机器人的本地行动更安全;第三,世界模型能较好地生成相关数据,减少数据泛化鸿沟。我们认为,世界模型是 VLN 突破长程规划和动态适应瓶颈的充分非必要条件。但现在世界模型的主要问题是黑盒,而非白盒可微。

 

Q:大模型的快速发展,为具身智能的“智能”部分带来了哪些质变?

 

刘智勇:从我们的实践来看,最核心的变化是导航和路径规划的技术范式发生了转变。过去我们采用的是 SLAM 方案,现在则转向了 VLN 范式。过去的 SLAM 方案存在几个明显的局限,一是方案本身不具备语义理解能力,二是依赖静态地图,必须预先建图才能使用,三是需要对特定的传感器做专门标定。而 VLN 范式完全不同,它可以结合语言和视觉实现语义层面的理解,同时能应对非静态环境,实现动态适配。更关键的是,这个方案不再依赖高规格的激光雷达,也不需要预先部署地图,成本和效率都实现了大幅优化。大模型的快速发展,推动技术范式从几何测量的 SLAM 转向学习增强的 VLN,这正是带来质变的核心原因。行动、观测和语言本来属于三个空间,现在要把三个空间统一起来,这也是目前的核心难点。

大规模落地现在卡在哪儿?

Q:几乎所有专家都指出,高质量、大规模的物理交互数据稀缺是当前最大瓶颈。面对真实数据采集成本高昂的困境,仿真合成数据、人类视频数据等替代方案能走多远?“数据工厂”是可行的解决方案吗?

 

刘智勇:我们面临的主要数据瓶颈有两个,一是数据的场景覆盖不足,比如现在常用的数据集大多基于 Mate Port 3D、Habitat、AI2THOR 等 构建,只包含 固定的训练环境,场景覆盖肯定不够;二是做 VLN 的数据采集成本很高,有时需要 3D 数据采集,标注成本也比 2D 图像高出一个量级。对 VLN 来说,现在数据是完全不足的,既存在场景覆盖问题,又有成本高昂的问题。

 

目前,我们在采用多种数据解决方案。第一是采集真实数据,采集 RGBD 视频流,以及数字手套等,再结合人工标注指令,像 Atomic 和一些基准数据集的主要来源就是真机数据。第二是比较常见的用仿真器生成,比如借助模拟器搭载 3D 场景库,批量生成视觉语言轨迹三元组。第三是采用 新范式,不用额外改动 3D 环境,通过改写人类标注数据的方式生成新样本,这是一种静态片段生成的新范式。另外,未来还有一种发展方向是离线数据、离线轨迹挖掘的方式,有点类似实行微克隆。

 

Q:当前的硬件如灵巧手、关节驱动、传感器等,在哪些方面最能满足机器人的技术需求?又在哪些方面构成了发展的主要制约?

 

刘智勇:要讲满足技术需求的地方,我们可以和轮式机器人做个比较。之前的轮式机器人只能移动到楼下,没办法开单元门、摁电梯,只能在楼下送货或者在室内移动。而现在的灵巧手、一体化关节,再加上一些触觉传感器,能让机器人具备开门、按电梯的能力,这是轮式机器人到人形机器人的一个巨大转变。

 

不过目前硬件也存在几方面的制约。第一,我们还需要高分辨率的柔性触觉皮肤。因为机器人需要用机械灵巧手摁电梯,如果触觉不够灵敏,盲按的波动率大,成功率就会比较低。第二,门把手的种类太多了,如果机器人没有触觉反馈,根本没办法应对成千上万种门的情况,也很难实现场景泛化。再就是机器人要进行成千上万次的反复操作,电机、执行器、丝杠这些部件的脆弱性,可能在我们的应用场景中被放大 100 倍。所以从硬件角度来讲,目前主要的制约就是开门要做得好、触觉要做得好这两点。

 

Q:目前为止,制约具身智能大规模落地应用难题还有哪些?

 

刘智勇:对于我们的 VLN 技术来说,主要有两方面的难题。第一是感知决策的延迟问题,这甚至可能是致命的。简单来说,长程规划和行动频率的匹配很关键,如果感知和决策环节出现延迟,机器人在开放环境中运作就会遇到很多麻烦,这就要求必须在端侧做好部署。第二是硬件性能短板,既要让硬件能灵敏地感知外部世界,又要保证它能反复进行操作,而目前这类硬件的耐疲劳性、反脆弱性能还不够强。对于世界模型来说,核心瓶颈是隐式神经表征,而非显式 3D 高斯,可能在开门和按键上缺少精准几何信息。

具身智能该告别 “一锤子买卖”?

Q:面对这样的机遇与挑战,您们在接下来一年的战略重点和核心发力方向是什么?

 

刘智勇:真机智能其实分成了北京真机和苏州真机两个公司。北京真机关注的还是比较传统的 SLAM 加轮式机器人的技术栈和方案,苏州真机则聚焦于 VLN 加人形机器人的技术栈及方案。

 

苏州真机接下来有两个关注重点,第一是通过视觉语言导航的方式,实现无需额外提前部署的门到门配送。过去部署成本太高了,大概占了整个机器人售价成本的 38% 左右。我们希望能实现零样本泛化,换句话说,就是让机器人能够直接理解环境,直接完成导航任务。第二是全身运动控制,要解决的核心问题是开门。之前的控制是基于机器人静态的假设来实现的,哪怕是协作机器人也是保持自身不动去拉开门,这种方式需要的扭矩非常大。我们希望通过全身控制打破静态平衡的限制,依靠动态平衡的方法更泛化地解决开门的问题。

 

把这两个点结合起来,我们既能实现无需预先建图的门到门配送任务,同时又能解决开门和按电梯的任务。这两个方案结合之后,就可以实现最后五公里的门到门配送,既能开门、操作电梯,又能以无建图、无 GPS 的方式完成导航。室内本身没有 GPS 信号,但又需要实现导航,这时候视觉和语言理解的作用就非常关键了。

 

Q:除了直接销售机器人整机,具身智能未来的商业模式可能有哪些创新?

 

刘智勇:整机销售和租赁这两种方式都会存在。但我个人觉得,单纯的整机销售并不是很好的商业模式,更好的方式是 “整机销售 + 每年服务费” 的组合模式。如果只卖硬件,一次性卖完其实很亏,后续的售后压力会非常大。“整机销售 + 每年服务费” 就比较合理,既能保证长期的最大收益,又能解决售后问题,还能让设备商一次性回本。通过这种组合模式,能把原本不赚钱的 “卖铁生意”,变成能持续盈利的长期现金流生意。另一方面,用户一次性付太多钱确实承受不了。

 

除此之外,未来还可能出现按单收费的商业模式。比如人形配送机器人测算下来每单成本能控制在两到三元人民币,和达达这类上游公司合作,机器人完成一单就赚一笔费用。

本体厂商大收缩,要拼什么?

Q:到 2026 年,我们有望看到具身智能在能力边界上实现怎样的突破?整个具身智能领域的技术决胜点可能会是什么方面?

 

刘智勇:2026 年可能会有两个关键突破方向。第一是机器人在非结构化场景中实现稳定作业。要做到这一点,需要机器人具备一定的社交行为表现和自主导航能力。解决了之后,一些之前没想到的非结构化环境下的任务机器人也可能完成了。目前行业内大多还聚焦在结构化环境,所以这会是一个重要突破。第二是突破莫拉维克悖论(Moravec's Paradox)。以往大家觉得,机器能完成人类觉得难的事,但难以完成人类觉得简单的事,而 2026 年可能机器人也能胜任这类任务,会在人类觉得简单的事情上取得突破。

 

至于技术决胜点,我认为有几个关键因素,其中最重要的是世界模型的因果推理能力。一旦这项能力取得突破,无论是机器人的安全性还是行为和推理的安全性问题,都能得到很好的解决。

 

Q:2026 年,全球具身智能公司的竞争情况将如何变化?中国公司与国际巨头各自的优势和赛点分别会在哪里?

 

刘智勇:2026 年本体厂商肯定会收缩,马太效应会非常明显,估计中国最终只会剩下 5 到 8 家本体机器人公司。不过应用场景相关的公司和上游企业会多一些。

 

中国和国际企业的优势不一样,国际公司的大模型技术更先进,基础模型能力更强,国内企业还处在追赶状态,但中国企业拥有供应链成本优势。另外竞争维度也在升级,现在大家可能还在追求单点技术的先进性,到了 2026 年,整体系统的效率会变得更重要。

 

至于赛点,我觉得核心是在某个单一场景实现盈利,不是毛利而是不依赖大量售后成本的净利。谁能做到这一点,谁就能形成数据飞轮,有了数据之后,模型和方法能力会进一步提升,之后再推进跨场景复制。

国务院开展外卖市场竞争调查评估

1 月 9 日,国务院反垄断反不正当竞争委员会办公室宣布,对外卖平台服务行业市场竞争状况开展调查、评估。

该部门负责人表示,近段时间以来,外卖平台服务行业拼补贴、拼价格、控流量等问题突出,挤压实体经济,加剧行业「内卷式」竞争,社会各方面反映强烈。本次调查评估将通过现场核实、当面访谈、问卷调查等方式,深入了解外卖平台竞争行为,广泛听取平台内经营者、新就业群体、消费者等各方意见,全面调查市场竞争状况,组织开展分析论证,传导监管压力,提出处置措施。

随后,美团、淘宝闪购均发文表示将积极配合。

此前在 2025 年 2 月,京东进军外卖业务,成为外卖补贴战的起点。阿里在 4 月底宣布入局参战,并将淘宝天猫旗下即时零售业务「小时达」升级为「淘宝闪购」,高调补贴外卖,并在 7 月 2 日进一步宣布 500 亿元补贴计划。面对竞争,美团也随之跟进,加入补贴。

对此,2025 年 5 月和 7 月,市场监管总局会等部门两次约谈饿了么、美团、京东三家企业。9 月,市场监管总局组织起草《外卖平台服务管理基本要求(征求意见稿)》,并在 12 月作为推荐性国家标准实施,对商户管理、收费与促销行为、用工管理及争议处理等作出规定。


Claude Code 封禁第三方兼容工具接入

1 月 9 日,Anthropic 确认已部署技术措施,禁止以流行终端 AI 编程工具 OpenCode 为代表的第三方应用伪装成其官方工具 Claude Code 接入模型,打击规避商业 API 费用的行为。

对此,Anthropic 解释称,第三方非授权接入引发了难以诊断的技术故障,导致平台稳定性下降。此外,有 xAI 员工利用 Cursor IDE 大规模调用 Claude 辅助自家模型研发,违反了 Claude 服务条款中关于禁止使用其服务构建竞品的排他规定。

然而,社区讨论普遍认为,经济考虑才是此次封禁的主要动机。Claude Max 订阅计划定价为 200 美元,订阅者可获高额用量。相比之下,如果通过按量计费的 API 调用同等规模算力,月成本极易超过 1000 美元。

面对封锁,OpenCode 迅速推出了每月 200 美元的 OpenCode Black 服务,转而通过企业级 API 接入 Claude。


知名开源框架 Tailwind CSS 受 AI 影响大幅裁员

知名开源 CSS 框架 Tailwind CSS 的开发商 Tailwind Labs 本周证实,受 AI 的「残酷冲击」,公司被迫裁减四名开发团队成员中的三名,即整个团队的 75%。CEO Adam Wathan 透露,虽然 Tailwind CSS 的使用量正以创纪录的速度增长,但公司营收却暴跌近 80%,若不重组,公司资金预计将在六个月内耗尽。

Wathan 指出,AI 编程工具的普及改变了开发者的工作习惯,导致官网文档页面的访问量在两年内下降了 40%。Tailwind Labs 的主要商业模式是向访问文档的开发者销售「终身买断制」的 Tailwind UI 组件库和模板。由于开发者现在直接通过 AI 获取代码,不再需要访问官网,也不需要购买付费组件库,上述商业模式难以为继。

Tailwind CSS 发布于 2019 年,是最受欢迎的 CSS 框架之一,许多 AI 模型擅长编写其代码,并且倾向于主动使用该框架。

Wathan 是在近期的一起 GitHub 社区争议中公开该情况的。此前,有贡献者提议优化文档格式,以便于大语言模型抓取和学习,但被 Wathan 拒绝。他解释称,让 AI 更容易免费获取内容会使业务「更加不可持续」,并可能导致项目因无人维护而成为「废弃软件」,并说明了上述背景。

该裁员消息引发技术社区广泛讨论,并引起了对行业巨头使用开源项目、用开源代码训练 AI,却不给予回报的批评。Vercel 和谷歌 AI Studio 随后宣布成为 Tailwind CSS 的赞助商。


伊朗发生大规模断网

据新华社报道,当地时间 1 月 8 日晚 8 时左右,伊朗首都德黑兰互联网服务出现中断。监控全球上网情况的国际非政府组织 NetBlock ,伊朗正在实施全国性网络管制,这与多地持续的抗议活动相关。Cloudflare 的路由信息显示,伊朗的 IPv4 链接在 8 日到 9 日期间大幅下降,此后略有恢复;IPv6 链接则完全归零。(IPv6 流量在技术上较 IPv4 更难审查。)

据《卫报》援引专家分析,此次断网在覆盖范围和技术手段上均创下新高,导致该国约 90% 的网络流量瞬间消失。此次断网实施了白名单机制,例如伊朗最高领袖哈梅内伊仍能在 X 发帖。

除断网之外,伊朗境内国际长途通话被阻断,移动通信服务全面瘫痪,大部分地区处于无信号、无服务的数字真空状态。曾在 2022 年抗议期间维持通讯的星链(Starlink)卫星互联网系统,此次也受到针对性信号干扰。


Cloudflare 遭意大利罚款,威胁停止冬奥会网络安保服务

近日,意大利通信管理局(AGCOM)因 Cloudflare 未能配合该国「反盗版盾牌」(Piracy Shield)系统屏蔽盗版内容,对其处以 1400 万欧元(约合 1.14 亿元)罚款。对此,Cloudflare 威胁将停止为即将到来的 2026 米兰—科尔蒂纳冬奥会提供网络安全服务,并考虑全面撤出意大利市场。

意大利实施的反盗版盾牌法案要求,互联网服务商在收到版权方举报后,必须在 30 分钟内无条件封锁涉嫌侵权的 IP 地址和域名。该系统自 2024 年启用以来在技术界备受争议,批评者指出其自动化封锁机制缺乏透明度,要求 DNS 解析器在极短时间内进行封锁,极易导致误伤合法网站。例如,其此前曾因误封 Google Drive 等合法服务,造成大范围网络中断。

Cloudflare CEO Matthew Prince 在 X 上激烈抨击该机制是「缺乏司法监督的审查计划」,指责其试图迫使 Cloudflare 的公共 DNS 服务(1.1.1.1)在全球范围内执行封锁,而非仅限于意大利。Prince 表示将坚决上诉,并计划下周前往华盛顿和洛桑,分别与美国政府及国际奥委会(IOC)商讨此事。

作为反制措施,Prince 列出了四项潜在行动:终止为冬奥会提供的数百万美元公益网络安全支持、停止向所有意大利用户提供免费服务、移除在意大利境内的所有服务器,以及取消在当地设立办事处的投资计划。鉴于冬奥会将于 2 月 6 日开幕,若 Cloudflare 此时撤出,可能导致赛事面临严重的网络攻击风险。


iOS 26 升级率低于过往版本同期水平

据网络流量分析机构 StatCounter 发布的数据,在 2026 年 1 月,全球范围内仅有约 15% 至 16% 的活跃 iPhone 运行 iOS 26‌,仍有超过 60% 的设备停留在 iOS 18。

基于这些数据,‌iOS 26 ‌的使用率似乎不到前几代系统在相同时间后的四分之一。例如,StatCounter 2025 年 1 月的数据显示,在 iOS 18 发布约四个月后,约有 63% 的 iPhone 运行着该系统的某个版本。2024 年 1 月,iOS 17 在类似时间段内达到了约 54% 的使用率,而 iOS 16 在 2023 年 1 月前已有超过 60% 的使用率。

StatCounter 的估算源自网络流量分析,通过全球参与其统计的网站页面追踪操作系统版本。采用不同统计方法的网站给出了不同数据。例如,TelemetryDeck 显示 iOS 26 有 60% 的使用率,而 iOS 18 仍有 37% 的使用率。

知名苹果资讯网站 MacRumors 表示,去年一月的第一周,89.3% 的访客使用 iOS 18 版本。而今年同期,只有 25.7% 的读者在使用 iOS 26 版本。由于苹果官方尚未公布数据,真实的 iOS 26 普及率尚不得而知,但这些数据表明,用户对 iOS 26 的犹豫程度是近年来前所未有的。


看看就行的小道消息

  • 据社交媒体消息,国产 Linux 发行版统信 UOS 的董事长因着装原因解雇了一名内核工程师。该公司最近临时通知员工年会必须自备西装参加,而一位负责 Linux 内核开发的骨干工程师在群里问了句「没西装怎么办」,董事长随后将其解雇。
  • 据网友近日咨询招商银行客服获得的说法,招行旗下 Visa 信用卡 1 月 15 日起可绑定至苹果 Apple Pay。此前在中国内地,Apple Pay 只能绑定银联借记卡、信用卡。此前,苹果已修改 Apple Pay 支持卡列表文案,从原本的表述「银联信用卡和借记卡」改为「银行卡」。
  • Wccftech 声称,从几家捷克电商的网站数据发现,Steam Machine 的 512GB 版本售价约为 19,826 捷克克朗(约 6,622 元),2TB 版本的售价约为 22,305 捷克克朗(约 7,450 元)。不过,欧洲地区的电子产品零售价通常包含约 20% 的增值税,且第三方零售商往往会添加额外的渠道溢价。
  • 1 月 11 日,近日受到关注的独居安全应用「死了么」团队就应用名称和开始收费的决定回应称,感谢网友对于新名称的积极建议,团队都会认真研究和考虑;为了让项目能够健康、持续地发展,并覆盖日益增长的短信、服务器等成本,将基于成本推出 8 元的收费方案。同时,团队也欢迎更多资本方关注和联系,会选择最能助力项目成长的机构或个人进行合作;最后,想呼吁更多人关注独居群体,给予他们更多关怀与理解。在「死了么」app 中,用户需要设置紧急联系人并签到,若连续多日没在应用内签到,系统将于次日自动发送邮件告知紧急联系人。


少数派的近期动态

  • 年末「夯」一下!少数派 2025 年度盘点正式上线
  • 少数派会员年终福利来袭,引荐比例限时上调至 15%,邀请好友享 85 折入会优惠。参与活动
  • 好玩又实用,还有迪士尼授权配件可选,少数派「扭扭宝」充电宝火爆开售。来一个试试
  • GAMEBABY for iPhone 17 Pro & 17 Pro Max 系列现已上市。进一步了解
  • 《蓝皮书》系列新版上架,一起探索全新 iOS 和 macOS 的精彩。试读并选购


你可能错过的好文章


    西班牙当局逮捕了34名个人,据称他们是一个涉及网络欺诈的犯罪网络的一部分,并被认为与在欧洲各地从事非法活动的Black Axe团伙有关。

    此次行动是在巴伐利亚州刑事警察局的协助和欧洲刑警组织的支持下进行的。

    在对塞维利亚、马德里、马拉加和巴塞罗那的搜查中,警方查获了66,400欧元现金、电子设备、车辆,并冻结了银行账户中的119,350欧元。

    这个西班牙网络犯罪团伙由尼日利亚裔的个人领导,他们是Black Axe帮派的成员,专门从事所谓的中间人诈骗,例如商业电子邮件入侵(BEC)。

    西班牙国家警察表示:“该组织专门从事被称为‘中间人’(MITM)的诈骗,这是一种犯罪分子介入合法通信以拦截、修改或重定向信息和支付,而受害者毫无察觉的技术。”

    “检测到的最常见形式是商业电子邮件入侵(BEC),即企业电子邮件账户被入侵或冒充,使得犯罪分子能够拦截公司之间的真实通信、更改银行信息,并将大额支付转移到该组织控制的账户。”

    据调查人员称,这些网络犯罪分子在过去15年中造成的损失超过600万美元,其中350万美元与此行动有关。

    该团伙利用了一个遍布欧洲多国的庞大钱骡和前台人员网络,帮助转移非法所得并掩盖踪迹。

    被捕人员中有四名主要嫌疑人已被采取审前拘留措施。他们现在面临严重持续性欺诈、参与犯罪组织、洗钱、文件伪造和妨碍司法公正等指控。

    西班牙当局强调,调查仍在进行中,可能很快会有更多逮捕行动。

    Black Axe于1977年在尼日利亚成立,是世界上影响最广、最危险的网络犯罪集团之一,据信拥有30,000名注册成员以及一个庞大的钱骡和协助者网络。

    该团伙从事毒品贩运、人口贩运、卖淫、绑架、武装抢劫、精神诈骗,以及最近的网络犯罪。

    两年前,美国判处其一名成员奥卢本加·拉瓦尔十年监禁,因其为Black Axe操作员在该国诈骗所得的数百万美元进行洗钱。

    2022年,国际刑警组织在南非开展了一次大规模行动,逮捕了70名Black Axe团伙的疑似成员。

    BreachForums黑客论坛数据库泄露,暴露32.4万个账户

                            By
    

    01:17 PM

    更新:文末已补充新信息。

    臭名昭著的BreachForums黑客论坛最新版本遭遇数据泄露,其用户数据库表已在网上曝光。

    BreachForums是一系列黑客论坛的名称,这些论坛被用于交易、出售和泄露被盗数据,以及出售企业网络访问权限和其他非法网络犯罪服务。

    该网站在首个同类论坛RaidForums被执法部门查封、其所有者"Omnipotent"被捕后成立。

    尽管BreachForums过去曾遭遇数据泄露和警方行动,但它已多次通过新域名重新上线,有人指控其现已成为执法部门的蜜罐。

    昨日,一个以ShinyHunters勒索团伙命名的网站发布了一个名为breachedforum.7z的7Zip压缩包。

    该压缩包包含三个文件:

    shinyhunte.rs-the-story-of-james.txt
    databoose.sql
    breachedforum-pgp-key.txt.asc

    ShinyHunters勒索团伙的代表向BleepingComputer声称,他们与分发此压缩包的网站无关。

    压缩包中的"breachedforum-pgp-key.txt.asc"文件是创建于2023年7月25日的PGP私钥,BreachForums曾用其签署管理员的官方消息。虽然该密钥已泄露,但受密码保护,没有密码便无法滥用其签署消息。

    受密码保护的BreachForums PGP私钥
    来源:BleepingComputer

    "databoose.sql"文件是一个MyBB用户数据库表(mybb_users),包含323,988条成员记录,涵盖成员显示名称、注册日期、IP地址及其他内部信息。

    BleepingComputer对该表的分析显示,大部分IP地址映射到本地回环IP地址(0x7F000009/127.0.0.9),因此实用价值有限。

    然而,有70,296条记录未包含127.0.0.9 IP地址,我们测试的这些记录映射到了公共IP地址。这些公共IP地址可能对相关人士构成操作安全风险,对执法部门和网络安全研究人员则具有价值。

    新泄露用户数据库中的最后注册日期为2025年8月11日,这正是前一个BreachForums论坛(breachforums[.]hn)关闭的日期。此次关闭发生在该论坛部分涉嫌运营者被捕之后。

    同日,ShinyHunters勒索团伙的一名成员在"Scattered Lapsus$ Hunters" Telegram频道发布消息,声称该论坛是执法部门的蜜罐。BreachForums管理员随后否认了这些指控。

    breachforums[.]hn域名后来于2025年10月被执法部门查封,此前该域名被重新用于勒索受ShinyHunters勒索团伙发起的大规模Salesforce数据盗窃攻击影响的企业。

    "我们希望就近期关于所谓数据库泄露的讨论进行说明,并清晰解释事件经过,"N/A在BreachForums上写道。

    "首先,这不是近期事件。相关数据源自2025年8月的一次旧用户表泄露,当时BreachForums正从.hn域名进行恢复/重建。"

    尽管管理员表示BreachForums成员应使用一次性邮箱以降低风险,且多数IP地址映射到本地IP,但该数据库仍包含可能引起执法部门关注的信息。

    更新 2026年1月10日 下午04:02(美国东部时间):
    本文发布后,网络安全公司Resecurity告知BleepingComputer,该网站现已更新并包含了BreachForums PGP私钥的密码。

    另一位安全研究人员向BleepingComputer确认,该密码与此密钥匹配。

    微软正在停用一项允许您直接从Microsoft Word将文档发送至Kindle的功能。

    在更新支持文档时,微软确认将从Microsoft Word中移除“发送文档至Kindle”的选项。

    此项变更将于2026年2月后逐步推行,但具体日期尚未确定,因此可能会分阶段实施。

    功能停用后,您将无法再通过导出菜单访问该功能。

    微软指出:“我们建议直接通过此发送至Kindle网站发送doc和docx文件。”

    对于不了解的用户,“发送至Kindle”功能允许您在几分钟内将Microsoft Word文档直接发送至您的Kindle图书馆。

    微软解释道:“传输的文件可以显示为可调整字体大小的Kindle电子书,也可以显示为固定版式的打印文档,以保留您的页面设计格式。”

    当您使用“发送至Kindle”时,Word会保留格式样式和页面布局,类似于打印时的显示效果。

    使用“发送至Kindle”时仅会丢失批注和修订记录。

    遗憾的是,2026年2月后将无法继续使用“发送至Kindle”功能。

    加州隐私保护局(CalPrivacy)已对营销公司Datamasters采取行动,该公司在未注册为数据中介的情况下出售了数百万用户的健康和个人数据。

    根据《加州删除法案》,买卖消费者信息的企业必须在每年1月31日前注册其数据中介活动。

    从2026年开始,消费者将能够访问一个名为“删除请求与退出平台”(DROP)的在线平台,在该平台上他们可以向所有注册的数据中介提交删除个人信息的请求。

    对于以Datamasters名义运营的Rickenbacher Data LLC,CalPrivacy因其未能及时注册而处以45,000美元的罚款。

    由于持续存在严重违规行为,这家总部位于德克萨斯州的公司还被禁止出售属于加州居民的个人信息。

    根据该机构的最终命令,Datamasters购买并转售了数百万患有各种疾病(如阿尔茨海默病、药物成瘾、膀胱失禁)用户的个人信息,用于定向广告。

    收集的数据包含数亿条记录,其中包括姓名、电子邮件地址、实际地址和电话号码。

    一个加重处罚的因素是该公司对州监管工作的态度,其声称未在加州开展业务或管理加州居民数据,后在证据面前承认了相反事实,并辩称其正在手动筛查数据。

    尽管监管机构多次试图强制该公司合规,但据报道Datamasters予以抵制,同时继续以未注册数据中介的身份运营。

    根据12月12日签署的决定,该公司还被命令在12月底前删除所有先前购买的加州居民个人信息。

    如果Datamasters未来在更大的数据集中收到属于加州居民的信息,该公司必须在收到后24小时内将其删除。

    Datamasters还必须在未来五年内保持合规措施,并在一年后提交其相关隐私实践报告。

    CalPrivacy还对S&P Global Inc.处以62,600美元的罚款,因其未能在2025年1月31日的截止日期前注册为2024年度的数据中介。然而,此次违规是由于行政错误所致。

    该机构在对S&P Global的罚款决定中指出:“尽管S&P Global迅速采取行动注册为数据中介并实施了纠正措施,但该公司仍有313天处于未注册状态。”

    Instagram否认数据泄露,尽管声称有1700万账户数据遭窃

                            By
    

    02:13 PM

    Instagram表示已修复一个允许威胁行为者批量请求密码重置邮件的漏洞,此前有声称称超过1700万个Instagram账户的数据被爬取并泄露到网上。

    Meta发言人告诉BleepingComputer:"我们修复了一个允许外部方为部分Instagram用户请求密码重置邮件的问题。"

    "我们希望向所有人保证,我们的系统没有遭到入侵,用户的Instagram账户仍然安全。人们可以忽略这些邮件,对于可能造成的任何困惑,我们深表歉意。"

    在Malwarebytes警告其客户网络犯罪分子已窃取1750万个账户的数据后,媒体开始对所谓的Instagram数据泄露事件大肆报道。

    据称这些Instagram数据已在多个黑客论坛上免费发布,发帖者声称这些数据是通过未经证实的2024年Instagram API泄露事件收集的。

    论坛帖子泄露据称的Instagram数据

    共享的数据总共包含17,017,213个Instagram账户资料,包括电话号码、用户名、姓名、实际地址、电子邮件地址和Instagram ID。

    该数据集包含以下唯一值的数量:

    ID: 17,015,503
    Username: 16,553,662
    Email: 6,233,162
    Phone number: 3,494,383
    Name: 12,418,006
    Address: 1,335,727

    并非每条记录都包含所有这些信息,有些记录仅包含Instagram ID和用户名。

    X平台上的网络安全研究人员声称[1, 2],这些被爬取的数据来自2022年的一次API爬取事件,但尚未提供任何明确证据来证实这一点。

    此外,Meta告诉BleepingComputer,他们不知道2022年或2024年有任何API事件。

    然而,Instagram此前曾遭受API爬取事件,例如2017年一个被利用来爬取并出售据称600万个账户个人信息的漏洞。

    目前尚不清楚新泄露的Instagram数据是否是2017年泄露数据与过去几年额外信息的汇编。

    BleepingComputer联系了泄露Instagram信息的人以确认数据被盗时间,但未收到回复。

    Instagram否认数据泄露

    目前没有证据表明该事件代表一次新的Instagram数据泄露。Meta表示他们不知道2022年或2024年有任何API被入侵的情况,也没有发生新的泄露。

    此外,研究人员尚未提供证据证明泄露的数据集是通过最近的漏洞获得的。

    相反,信息表明这些数据可能是多年来从多个来源爬取的信息汇编。

    好消息是,这些泄露的数据不包含密码,因此无需更改密码。

    然而,人们确实需要警惕利用这些信息进行的针对性网络钓鱼、短信钓鱼和社会工程攻击。

    威胁行为者通常使用泄露的数据来尝试窃取额外信息,例如用户密码。

    如果您收到Instagram密码重置邮件或发送到您手机号码的验证码,但您并未发起账户恢复,请直接忽略并删除它们。

    如果您的账户未启用双因素身份验证,强烈建议您开启此功能以增强安全性。

    更新于26年1月11日:添加了唯一数据值。

    基于 Pydantic-Resolve 和 FastAPI-Voyager 的 Clean Architecture 实践

    篇幅较长无法粘贴全文,原文链接:
    https://github.com/allmonday/A-Python-web-development-methodology-for-complex-business-scenarios/blob/main/README.zh.md

    一套面向复杂业务场景的 Python Web 开发方法论

    目录


    1. 背景与问题

    1.1 当前主流做法及其痛点

    在 Python Web 开发中,处理复杂业务场景时,开发者通常采用以下几种模式:

    模式一:直接使用 ORM (如 SQLAlchemy )

    @router.get("/teams/{team_id}", response_model=TeamDetail)
    async def get_team(team_id: int, session: AsyncSession = Depends(get_session)):
        # 获取团队基本信息
        team = await session.get(Team, team_id)
    
        # 获取 Sprint 列表
        sprints = await session.execute(
            select(Sprint).where(Sprint.team_id == team_id)
        )
        team.sprints = sprints.scalars().all()
    
        # 获取每个 Sprint 的 Story
        for sprint in team.sprints:
            stories = await session.execute(
                select(Story).where(Story.sprint_id == sprint.id)
            )
            sprint.stories = stories.scalars().all()
    
            # 获取每个 Story 的 Task
            for story in sprint.stories:
                tasks = await session.execute(
                    select(Task).where(Task.story_id == story.id)
                )
                story.tasks = tasks.scalars().all()
    
                # 获取每个 Task 的负责人
                for task in story.tasks:
                    task.owner = await session.get(User, task.owner_id)
    
        return team
    

    这种做法在简单场景下确实很直观,能够快速上手。ORM 的类型安全特性也能在编译时发现一些错误,而且与数据库表结构的一一对应关系让代码容易理解。但当我们面对真正的业务场景时,这种方式的缺陷很快就暴露出来了。

    最致命的问题是 N+1 查询。虽然代码看起来很清晰,但执行时会产生大量的数据库查询。每当我们访问一个关联关系时,ORM 就会发起一次新的查询。在深层嵌套的情况下,查询数量会呈指数级增长。更糟糕的是,这种性能问题在开发阶段不容易发现,只有当数据量积累到一定程度后才会显现出来,那时候往往已经太晚了。

    代码的组织方式也是个问题。数据获取的逻辑散落在各个嵌套的循环中,业务逻辑和数据获取逻辑混在一起,难以阅读和维护。当需要修改业务规则时,开发者不得不在复杂的嵌套结构中寻找修改点,很容易引入新的 bug 。性能更是不可控,随着数据量的增长,查询效率会急剧下降,而这些性能瓶颈很难在代码层面直接观察到。

    此外,相似的数据获取逻辑会在多个 API 中重复出现,导致大量代码冗余。当一个 API 需要获取"团队及其 Sprint",另一个 API 需要"团队及其成员"时,即使它们的查询逻辑非常相似,也不得不重复编写。这违反了 DRY ( Don't Repeat Yourself )原则,增加了维护成本。

    模式二:使用 ORM 的 Eager Loading

    @router.get("/teams/{team_id}", response_model=TeamDetail)
    async def get_team(team_id: int, session: AsyncSession = Depends(get_session)):
        # 使用 joinedload 预加载关联数据
        result = await session.execute(
            select(Team)
            .options(
                joinedload(Team.sprints)
                .joinedload(Sprint.stories)
                .joinedload(Story.tasks)
                .joinedload(Task.owner)
            )
            .where(Team.id == team_id)
        )
        return result.scalar_one()
    

    为了解决 N+1 查询问题,ORM 提供了 Eager Loading 机制,让我们可以通过 joinedloadselectinload 等方式预先加载关联数据。代码变得更简洁了,性能问题也得到了缓解。但这种方案也带来了新的挑战。

    最明显的问题是笛卡尔积。当我们使用多层 JOIN 预加载关联数据时,数据库返回的数据量会急剧膨胀。比如一个团队有 10 个 Sprint ,每个 Sprint 有 10 个 Story ,每个 Story 有 10 个 Task ,那么 JOIN 的结果集会包含 1000 行数据,即使每行的数据量不大,也会给网络传输和内存占用带来压力。

    更严重的问题是灵活性差。Eager Loading 的策略是在代码中硬编码的,所有使用同一个 Model 的 API 都会执行相同的预加载逻辑。但不同的 API 往往需要不同的数据。比如一个 API 只需要团队的基本信息,另一个 API 需要团队的 Sprint ,还有一个 API 需要团队的成员。如果统一使用 Eager Loading 加载所有关联数据,就会出现过度获取的问题,前端不需要的数据也被查询和传输了,浪费了资源。

    配置 Eager Loading 本身就很复杂。开发者需要理解 lazyjoinedloadselectinloadsubquery 等多种加载策略的区别,知道什么时候用哪一种,以及它们各自会有什么副作用。这种配置错误很容易导致性能问题或意外的数据加载行为。而且,这种"一刀切"的配置方式意味着所有 API 都使用相同的加载策略,无法针对特定场景进行优化。

    模式三:手动组装数据

    @router.get("/teams/{team_id}", response_model=TeamDetail)
    async def get_team(team_id: int, session: AsyncSession = Depends(get_session)):
        # 1. 批量获取所有需要的数据
        team = await session.get(Team, team_id)
    
        sprints_result = await session.execute(
            select(Sprint).where(Sprint.team_id == team_id)
        )
        sprint_ids = [s.id for s in sprints_result.scalars().all()]
    
        stories_result = await session.execute(
            select(Story).where(Story.sprint_id.in_(sprint_ids))
        )
        story_ids = [s.id for s in stories_result.scalars().all()]
    
        tasks_result = await session.execute(
            select(Task).where(Story.id.in_(story_ids))
        )
        tasks = tasks_result.scalars().all()
    
        owner_ids = list(set(t.owner_id for t in tasks))
        owners_result = await session.execute(
            select(User).where(User.id.in_(owner_ids))
        )
        owners = {u.id: u for u in owners_result.scalars().all()}
    
        # 2. 手动组装数据结构
        sprint_dict = {s.id: s for s in sprints_result.scalars().all()}
        story_dict = {s.id: s for s in stories_result.scalars().all()}
    
        for story in story_dict.values():
            story.tasks = [t for t in tasks if t.story_id == story.id]
            for task in story.tasks:
                task.owner = owners.get(task.owner_id)
    
        for sprint in sprint_dict.values():
            sprint.stories = [s for s in story_dict.values() if s.sprint_id == sprint.id]
    
        team.sprints = list(sprint_dict.values())
    
        return team
    

    为了获得最优的性能和精确的数据控制,有经验的开发者会选择手动组装数据。这种方式完全掌控查询逻辑,可以精确控制每个查询的 SQL 语句,避免不必要的数据库访问。通过批量查询和智能的数据组装,可以获得最佳的性能,而且没有冗余数据。

    但这种方式的代价是代码变得非常冗长。如上面的例子所示,为了获取一个团队的完整信息,我们需要编写多个查询,手动构建数据字典,然后通过嵌套循环组装数据。代码的长度和复杂度都大幅增加,而真正表达业务逻辑的代码反而被淹没在数据组装的细节中。

    更容易出错也是个大问题。手动组装数据涉及到大量的索引操作和循环嵌套,很容易出现索引错误、空指针引用等 bug 。而且这些错误往往只有在运行时、特定数据条件下才会暴露,难以在开发阶段发现。

    维护成本更是高昂。当业务规则发生变化时(比如需要添加一个新的关联关系),开发者需要在所有相关的 API 中修改数据组装逻辑。如果遗漏了某个地方,就会导致数据不一致。而且,相似的数据组装逻辑会在多个 API 中重复出现,违反了 DRY 原则。

    最根本的问题是,这种代码已经变成了纯粹的数据搬运工,看不出任何业务意图。代码中充满了字典操作、循环嵌套、索引查找,而这些都是技术细节,与业务需求毫无关系。新加入的团队成员很难从这些代码中理解业务逻辑,业务知识的传递变得异常困难。

    模式四:使用 GraphQL

    type Query {
        team(id: ID!): Team
    }
    
    type Team {
        id: ID!
        name: String!
        sprints: [Sprint!]!
    }
    
    type Sprint {
        id: ID!
        name: String!
        stories: [Story!]!
    }
    
    type Story {
        id: ID!
        name: String!
        tasks: [Task!]!
    }
    
    type Task {
        id: ID!
        name: String!
        owner: User!
    }
    

    GraphQL 确实是一个很有吸引力的方案。前端可以按需获取数据,需要什么字段就查什么字段,不会有过度获取的问题。它提供了类型安全的查询接口,而且通过 DataLoader 可以自动解决 N+1 查询问题。这些特性让 GraphQL 在前端开发中广受欢迎。

    但 GraphQL 的学习曲线非常陡峭。开发者需要学习全新的查询语言、Schema 定义、Resolver 编写、DataLoader 配置等一堆概念,这与 REST API 的直观性形成了鲜明对比。更麻烦的是,GraphQL 的过度灵活性给后端带来了巨大的挑战。前端可以构造任意复杂的查询,有些查询甚至可能是开发者没有想到过的,这导致后端很难进行针对性的优化。当一个查询嵌套了 10 层,返回了数百万条数据时,数据库和服务器都会面临巨大的压力。

    调试 GraphQL API 也比调试 REST API 复杂得多。当一个 GraphQL 查询出错时,错误信息往往很难定位到具体的问题源头。而且 GraphQL 需要额外的服务器和工具链支持,无法直接利用现有的 FastAPI 生态系统。比如 FastAPI 的依赖注入、中间件、自动文档生成等特性,在 GraphQL 中都无法直接使用。

    还有一个更深层次的问题是 ERD 和用例的界限模糊。GraphQL 的 Schema 同时扮演了实体模型和查询接口两个角色。当我们设计一个 GraphQL Schema 时,很难确定应该按照实体来组织(一个 Type 对应一个数据库表),还是按照用例来组织(不同的业务场景需要不同的字段)。这导致最佳实践不清晰,不同的项目、不同的开发者可能有完全不同的组织方式。

    而且随着业务增长,所有的用例都会堆砌在同一个 Schema 中,导致 Schema 膨胀,难以维护。权限控制也变得异常复杂。不同的 API 端点可能有不同的权限要求,但它们可能都查询同一个实体(比如 User ),在 GraphQL 中很难针对不同的查询场景应用不同的权限规则。

    1.2 问题根源分析

    上面我们探讨的所有模式,虽然表面上的问题各不相同,但它们的核心困境其实是一致的。

    问题 1:业务模型与数据模型混淆

    # SQLAlchemy ORM 同时扮演两个角色:
    # 1. 数据模型(如何存储)
    # 2. 业务模型(业务概念)
    
    class Team(Base):
        __tablename__ = 'teams'
    
        id = Column(Integer, primary_key=True)
        name = Column(String)
    
        # 这是数据库的外键关系,还是业务关系?
        sprints = relationship("Sprint", back_populates="team")
    

    在传统的 ORM 开发中,业务模型和数据模型是混在一起的。看看这个例子,Team 类既表达了业务概念(团队是什么),又承载了数据模型的细节(如何在数据库中存储)。当我们在 sprints 字段上定义 relationship 时,这到底是在描述一个业务关系(团队有多个 Sprint ),还是在声明一个数据库外键约束?这种模糊性会导致很多问题。

    数据库的设计约束会直接影响我们的业务建模。比如,如果数据库中的 teams 表没有直接到 users 的外键,而是通过中间表 team_members 关联,那么在 ORM 中我们也必须通过这个中间表来定义关系。这意味着业务模型被迫适应数据库的实现细节,而不是反过来。

    更严重的是,这种方式无法表达跨库、跨服务的业务关系。现代系统中,数据可能分布在不同的数据库中,甚至存储在外部服务里。比如用户的基本信息在 PostgreSQL ,而用户的偏好设置在 MongoDB ,用户的实时状态在 Redis 中。ORM 的 relationship 无法跨越这些边界,业务模型因此被限制在了单一数据库的范围内。

    问题 2:依赖方向错误

    传统架构的依赖方向:
    ┌─────────────┐
    │   API Layer │  ← 依赖于
    └──────┬──────┘
           │
           ↓
    ┌─────────────┐
    │ ORM Models  │  ← 依赖于
    └──────┬──────┘
           │
           ↓
    ┌─────────────┐
    │  Database   │
    └─────────────┘
    
    问题:业务规则依赖于数据库实现!
    

    这违反了 Clean Architecture 的依赖规则。正确的依赖关系应该是:业务规则最稳定,不依赖任何外层;数据库是实现细节,应该依赖业务规则;当数据库变化时,业务规则不应该受影响。但传统架构的依赖方向恰恰相反,业务规则被数据库的实现细节所绑架。

    问题 3:缺少业务关系的显式声明

    # 传统方式:业务关系隐藏在查询中
    async def get_team_tasks(team_id: int):
        # "团队的任务"这个业务概念隐藏在 SQL WHERE 中
        result = await session.execute(
            select(Task)
            .join(Sprint, Sprint.id == Task.sprint_id)
            .where(Sprint.team_id == team_id)
        )
        return result.scalars().all()
    

    业务关系没有被显式声明出来,这是个很隐蔽但危害很大的问题。看看这个例子,"团队的任务"是一个清晰的业务概念,但这个概念被隐藏在 SQL 的 JOIN 和 WHERE 子句中。新加入团队的成员需要阅读大量代码才能理解系统中有哪些业务关系,这些关系是如何定义的。更糟糕的是,没有自动化的方式来检查业务关系的一致性。当需求变化需要修改某个关系时,开发者很难找到所有相关的代码,很容易遗漏某个地方,导致业务逻辑的不一致。

    问题 4:中间表的技术暴露

    在 SQLAlchemy ORM 中,多对多关系需要显式定义中间表,这导致技术细节泄漏到业务层。

    # SQLAlchemy ORM:必须定义中间表
    class Team(Base):
        __tablename__ = 'teams'
        id = Column(Integer, primary_key=True)
        name = Column(String)
    
        # ORM relationship 需要指定中间表
        members = relationship("User",
                              secondary="team_members",  # 必须指定中间表
                              back_populates="teams")
    
    class User(Base):
        __tablename__ = 'users'
        id = Column(Integer, primary_key=True)
        name = Column(String)
    
        teams = relationship("Team",
                            secondary="team_members",  # 必须指定中间表
                            back_populates="members")
    
    # 中间表(技术实现细节)
    class TeamMember(Base):
        __tablename__ = 'team_members'
        team_id = Column(Integer, ForeignKey('teams.id'), primary_key=True)
        user_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
        role = Column(String)  # 可能还有额外字段
    
    # 查询时需要关心中间表的存在
    @router.get("/teams/{team_id}")
    async def get_team_members(team_id: int, session: AsyncSession):
        # 必须通过中间表查询
        result = await session.execute(
            select(User)
            .join(TeamMember, TeamMember.user_id == User.id)  # 中间表暴露
            .where(TeamMember.team_id == team_id)
        )
        return result.scalars().all()
    

    这个问题的根源在于,ORM 的多对多关系需要显式定义中间表,这导致技术细节直接泄漏到业务层代码中。业务代码必须知道 team_members 中间表的存在,查询时也需要显式地 join 这个中间表。这增加了代码复杂度,更重要的是,业务逻辑被数据库的实现细节所绑架。

    更深层的问题是业务语义变得模糊。TeamMember 到底是一个有意义的业务概念,还是纯粹的技术实现?如果中间表还有额外的字段(比如 role 表示用户在团队中的角色,joined_at 表示加入时间),这些字段应该被建模为独立的实体吗?不同的开发者可能给出不同的答案,缺乏统一的指导原则。

    数据组装也因此变得复杂。查询"团队的所有成员"需要 join 中间表,查询"用户所属的团队"也需要 join 中间表。所有涉及多对多关系的查询都变得冗长和难以理解。当业务规则要求"获取用户在所有团队中的角色"时,情况就更加复杂了。这些技术细节让业务逻辑的实现变得异常沉重。

    对比:Pydantic-Resolve ERD 的方式

    # ERD:业务概念清晰,无需关心中间表
    class TeamEntity(BaseModel, BaseEntity):
        """团队实体 - 业务概念"""
        __relationships__ = [
            # 直接表达"团队有多个成员"的业务关系
            Relationship(
                field='id',
                target_kls=list[UserEntity],
                loader=team_to_users_loader  # loader 内部处理中间表
            ),
        ]
        id: int
        name: str
    
    class UserEntity(BaseModel, BaseEntity):
        """用户实体 - 业务概念"""
        __relationships__ = [
            # 直接表达"用户属于多个团队"的业务关系
            Relationship(
                field='id',
                target_kls=list[TeamEntity],
                loader=user_to_teams_loader
            ),
        ]
        id: int
        name: str
    
    # Loader 实现细节:中间表只在这里出现
    async def team_to_users_loader(team_ids: list[int]):
        """加载团队成员 - 内部处理中间表"""
        async with get_session() as session:
            # 只有这里需要知道中间表的存在
            result = await session.execute(
                select(User)
                .join(TeamMember, TeamMember.user_id == User.id)
                .where(TeamMember.team_id.in_(team_ids))
            )
            users = result.scalars().all()
    
            # 构建映射
            users_by_team = {}
            for user in users:
                for tm in user.team_memberships:
                    if tm.team_id not in users_by_team:
                        users_by_team[tm.team_id] = []
                    users_by_team[tm.team_id].append(user)
    
            return [users_by_team.get(tid, []) for tid in team_ids]
    

    关键差异

    维度 SQLAlchemy ORM Pydantic-Resolve ERD
    中间表位置 暴露在业务层 隐藏在 loader 实现中
    业务语义 技术关系 (secondary) 业务关系 (团队包含成员)
    查询代码 需要 join 中间表 loader.load(team_id)
    代码位置 分散在多处 集中在 loader
    测试 依赖数据库表结构 可 mock loader

    架构优势

    传统方式:
    Team → TeamMember (中间表) → User
    业务层需要知道中间表的存在
    
    Pydantic-Resolve 方式:
    Team → User (业务关系)
    中间表是数据层的实现细节,业务层不关心
    

    这意味着:

    1. 业务模型纯净:Team 和 User 的关系直接表达业务语义

    2. 技术细节封装:中间表的存在被封装在 loader 中

    3. 灵活的存储策略


      • 数据库可以用中间表实现
      • 也可以用 JSON 字段存储
      • 甚至可以是外部服务(如 LDAP )
      • 业务层代码无需修改
    4. 易于理解:新人看到 ERD 就能理解业务关系,不需要先学习数据库设计


    2. Clean Architecture 思想

    2.1 核心原则

    Clean Architecture 由 Robert C. Martin (Uncle Bob) 提出,核心思想是:

    "Software architecture is the art of drawing lines that I call boundaries."
    软件架构的艺术在于画界线。

    原则 1:依赖规则

    外层依赖内层,内层不依赖外层。
    
                    ↓ 依赖方向
        ┌─────────────────────┐
        │   Frameworks &      │  外层
        │   Drivers           │  (实现细节)
        ├─────────────────────┤
        │   Interface         │
        │   Adapters          │
        ├─────────────────────┤
        │   Use Cases         │
        │   (Application)     │
        ├─────────────────────┤
        │   Entities          │  内层
        │   (Business Rules)  │  (核心)
        └─────────────────────┘
    

    遵循依赖规则有几个关键点需要注意。首先,内层不知道外层的存在,这意味着核心业务逻辑不依赖于任何框架、数据库或 UI 的细节。其次,内层不包含外层的信息,比如业务规则不应该知道数据是用 PostgreSQL 还是 MongoDB 存储的。最后,外层的实现可以随时替换而不影响内层,这意味着我们可以从 SQLAlchemy 切换到 MongoDB ,或者从 FastAPI 切换到 Django ,而业务逻辑代码无需修改。

    原则 2:业务规则独立

    # ❌ 错误:业务规则依赖数据库
    class Task:
        def calculate_priority(self, session):
            # 业务逻辑被数据库实现细节污染
            if self.assignee_id in session.query(TeamMember).filter_by(role='lead'):
                return 'high'
    
    # ✅ 正确:业务规则独立
    class Task:
        def calculate_priority(self, assignee_roles):
            # 业务逻辑只依赖业务概念
            if 'lead' in assignee_roles:
                return 'high'
    

    原则 3:跨边界的数据传递

    # 内层定义数据结构
    class TaskEntity(BaseModel):
        id: int
        name: str
        assignee_id: int
    
    # 外层负责转换
    def task_entity_to_orm(entity: TaskEntity) -> Task:
        return Task(
            id=entity.id,
            name=entity.name,
            assignee_id=entity.assignee_id
        )
    

    2.2 依赖规则

    在 Web 开发中,依赖规则可以这样理解:

    ┌────────────────────────────────────────────────────┐
    │         Presentation Layer (外层)                   │
    │  - FastAPI Routes                                   │
    │  - Request/Response Models                          │
    │  - 依赖: Application Layer                          │
    └────────────────────────────────────────────────────┘
                        ↓
    ┌────────────────────────────────────────────────────┐
    │      Application Layer (Use Cases)                 │
    │  - 业务用例(获取用户、创建订单)                    │
    │  - 依赖: Domain Layer                               │
    └────────────────────────────────────────────────────┘
                        ↓
    ┌────────────────────────────────────────────────────┐
    │           Domain Layer (内层)                      │
    │  - Entities (业务实体)                              │
    │  - Business Rules (业务规则)                        │
    │  - Value Objects (值对象)                           │
    │  - 不依赖任何外层                                    │
    └────────────────────────────────────────────────────┘
                        ↓
    ┌────────────────────────────────────────────────────┐
    │    Infrastructure Layer (最外层)                   │
    │  - Database (SQLAlchemy)                           │
    │  - External Services                               │
    │  - File System                                     │
    └────────────────────────────────────────────────────┘
    

    关键洞察

    • Entities 不应该知道 SQLAlchemy 的存在
    • Business Rules 不应该知道数据库表结构
    • Use Cases 不应该知道 HTTP 协议的细节

    2.3 在 Web 开发中的应用

    传统架构的问题

    # 传统方式:所有层次耦合
    
    # Domain Layer (应该独立,但实际上依赖了 ORM)
    class User(Base):  # ← SQLAlchemy Base
        __tablename__ = 'users'
        id = Column(Integer, primary_key=True)
    
    # Application Layer (应该只依赖 Domain ,但直接使用了 ORM)
    async def create_user(data: dict, session: AsyncSession):
        user = User(**data)  # ← 直接使用 ORM Model
        session.add(user)
        await session.commit()
    
    # Presentation Layer
    @router.post("/users")
    async def api_create_user(data: dict, session=Depends(get_session)):
        return await create_user(data, session)  # ← 暴露了数据库细节
    

    这段代码暴露了传统架构的核心问题。SQLAlchemy 虽然建立了对象关系映射( ORM ),让数据库表可以通过 Python 对象来操作,但这种映射关系过于紧密。ORM Model 既承担了数据持久化的职责,又要表达业务概念,导致对象无法自由地代表业务模型。业务实体被数据库的实现细节所绑架,每个字段、每个关系都必须与数据库表结构一一对应,完全失去了作为独立业务概念存在的自由。

    更深层次的问题包括:

    1. Domain Layer 被 SQLAlchemy 绑定:业务实体继承了 SQLAlchemy 的 Base ,无法独立于数据库存在
    2. 业务逻辑无法脱离数据库测试:编写单元测试时必须启动完整的数据库环境,大大降低了测试效率
    3. 切换数据库需要修改所有层:当从 PostgreSQL 迁移到 MongoDB 时,所有使用 ORM Model 的代码都需要重写


    。。。

    之前喜欢刷手机,后来感觉可以利用这段时间,索性 Vibe 了一个学英语的 ide 插件,支持 Cursor 、Antigravity 。

    主要是内嵌了一个播放器,利用 yt-dl ,贴上油管地址,练习听力挺好用的,没啥特别的。

    当然你想用来摸鱼看油管也不是不行。

    如果你有喜欢的英文频道,可以拿来学习。

    大家有什么推荐的英语学习频道可以分享下。

    https://github.com/kylesean/lingo-tube

    折腾了一圈衬线字体看书用,口味上偏楷书,目前最喜欢这两个。



    霞鹜文楷规整清晰,偏旁部首倾泻而出;方正楷书则更顿挫,字字浑然一体。

    V 友有没有推荐?