Playwright Fixture机制:模拟数据库与API,根治测试数据污染

做Web自动化测试这几年,我在实际项目里总结出三怕:一怕测试环境数据库连不上,二怕第三方接口突然限流,三怕测试数据互相污染。前两个问题会让你辛辛苦苦维护的用例在一夜之间全部标红,第三个问题则更隐蔽——明明昨天还能跑的用例,今天换了台机器或者换了个执行顺序就挂,而且报错信息看起来和代码毫无关系。后来我在某个跨平台系统的测试项目中彻底转向了Playwright的Fixture机制,把数据库、API客户端和测试数据这三类外部依赖全部“模拟化”,才算是真正把测试从环境手里解放出来。

这篇文章就围绕这个思路展开,核心内容是用Playwright(我用的是Python版,TypeScript版的概念完全一致)配合Pytest的Fixture机制,搭建一套不依赖真实数据库、不依赖真实后端服务、可以任意构造业务的测试数据层。如果你正在做Web应用或前后端分离项目的端到端自动化,被环境不稳定、数据串场、接口不可用搞得焦头烂额,那这套方案可以直接抄作业。

1. 先理清:为什么要把数据库、API客户端、测试数据全部模拟掉

1.1 不稳定的根子在外部依赖

先聊一个观点:端到端测试的稳定性,往往不是由测试代码本身决定的,而是由被测系统外部依赖决定的。一个管理后台页面要展示订单列表,前端会调用订单查询接口,接口从数据库里读数据,数据库背后可能还有缓存、消息队列。这条链路里的任何一个环节出问题,你的测试用例都会失败。

这就带来一个非常现实的问题:你在本机写用例的时候数据库是好的,接口是通的,用例跑得飞快;等提交到CI流水线,调度并发跑起来,数据库连接数打满,接口响应超时,测试就开始大面积地失败。你花在排查“为什么测试失败”上的时间,可能比写测试逻辑的时间还要多。

模拟(Mock)解决的就是这个问题。把数据库、API客户端、测试数据这三层外部依赖全部替换成可控的假实现,测试用例就不需要依赖任何外部环境,用例的输入输出完全由测试代码本身决定,自然也就不会因为环境问题而出现随机性失败。

1.2 Fixture不是“准备数据”那么简单

很多刚开始接触Pytest或者Playwright Fixture的人,容易把它理解成一个“返回数据的东西”。比如:

@pytest.fixture def user_data(): return {"id": 1, "name": "张三"}

这没有错,但只发挥了Fixture很小一部分能力。Fixture体系真正的价值在于依赖管理、作用域隔离和自动清理。

从工程角度看,Fixture可以理解为一套依赖注入机制。一个用例声明自己需要哪些Fixture,框架就会自动创建这些Fixture,并处理好创建顺序、作用域、复用和销毁。比如一个用例同时需要“数据库连接”和“登录态”,你不需要在用例里手动初始化这两样东西,只需要在参数列表里声明,框架就会先把它们创建好再交给用例。

正是这种“声明式”的用法,让模拟数据库、模拟API客户端和构造测试数据这三件事可以被组合成一个清晰的测试基础设施层。在下面的实战代码里,你会看到这几个Fixture是如何分层设计、互相引用的。

2. 第一层模拟:数据库与数据仓库

2.1 选择内存数据仓库而不是真库

在测试代码里模拟数据库,我经历过几个阶段:一开始是连测试环境的真实数据库,用例跑完自己清理;后来为了并行执行,改成每个用例创建一个临时库,跑完删掉;再后来发现并发量大了以后临时库的创建和销毁本身就变成了不稳定因素,于是彻底转向了内存数据仓库。

内存数据仓库的做法很简单:不用真实的数据库引擎,而是用Python对象来模拟表、行和查询逻辑。用什么数据结构?字典就够了。每一个业务实体对应一个字典或者一个dataclass列表,增删改查全部用Python语法直接操作。

这种做法的好处是显而易见的:

  • 没有外部连接,不会出现连接数打满的问题;
  • 数据是内存级的,读写速度极快;
  • 每个测试用例拿到的都是独立的仓库实例,天然隔离;
  • 不需要启动、停掉任何数据库进程,也不依赖容器环境。

当然,这个方案也有代价:它只模拟了数据存取行为,不模拟像事务回滚、并发读写冲突这类数据库高级特性。对我们做Web UI自动化而言,这基本不是问题,因为前端页面通常只关心数据是否存在、内容是否正确,不会去验证数据库的事务隔离级别。

2.2 用一个dataclass实现最小可用Mock数据库

以一个电商管理后台为例,我们需要模拟的核心业务实体是:用户(user)、商品(product)、订单(order)。下面是一个精简但完整可运行的内存数据仓库实现:

# mock_db.py from dataclasses import dataclass, field from typing import Dict, List, Optional @dataclass class MockDB: users: Dict[int, dict] = field(default_factory=dict) products: Dict[int, dict] = field(default_factory=dict) orders: Dict[int, dict] = field(default_factory=dict) _user_seq: int = 0 _product_seq: int = 0 _order_seq: int = 0 # ---------- 用户 ---------- def add_user(self, **kwargs) -> dict: self._user_seq += 1 record = {"id": self._user_seq, **kwargs} self.users[record["id"]] = record return record def get_user(self, user_id: int) -> Optional[dict]: return self.users.get(user_id) def update_user(self, user_id: int, **kwargs) -> Optional[dict]: if user_id in self.users: self.users[user_id].update(kwargs) return self.users.get(user_id) # ---------- 商品 ---------- def add_product(self, **kwargs) -> dict: self._product_seq += 1 record = {"id": self._product_seq, **kwargs} self.products[record["id"]] = record return record def list_products(self) -> List[dict]: return list(self.products.values()) # ---------- 订单 ---------- def add_order(self, **kwargs) -> dict: self._order_seq += 1 record = {"id": self._order_seq, **kwargs} self.orders[record["id"]] = record return record def get_order(self, order_id: int) -> Optional[dict]: return self.orders.get(order_id) def list_orders_by_user(self, user_id: int) -> List[dict]: return [o for o in self.orders.values() if o["user_id"] == user_id]

这段代码本质上就是用内存对象实现了表的基本操作。让每个Fixture函数或每个测试用例都持有一个自己独立的MockDB实例,就能保证用例之间的数据完全不互通。

2.3 数据工厂:默认值优先,参数覆盖兜底

只有一个空仓库还不够,页面上的用例往往需要一些预设好的业务数据。比如要测“订单详情页”,你就得先有用户、商品、订单这三层数据。我习惯把这部分逻辑独立成数据工厂,专门用来生成“看起来真实且合法”的测试数据。

# data_factory.py from mock_db import MockDB def seed_order_scenario(db: MockDB, *, username="default_user", product_name="默认商品", price=99.0) -> dict: user = db.add_user(name=username, role="customer", status="active") product = db.add_product(name=product_name, price=price, stock=100, status="on_sale") order = db.add_order( user_id=user["id"], product_id=product["id"], amount=price, status="pending", ) return {"user": user, "product": product, "order": order}

这里有一个比较反直觉的取舍:我没有一开始就引入Faker这类随机数据生成库,而是让所有字段都有默认值。原因是测试数据要优先保证可预测性——用例通过的前提是页面显示的内容和断言里写死的内容一致,如果数据是随机生成的,断言就不能写死,得跟着变化,那代码复杂度反而上升了。默认值优先的好处是,你的断言可以放心地写“张三”“默认商品”“99.0”这样的字面量。

等到你对某个字段确实需要多值覆盖时,再通过参数传进去,默认值仍然兜底。这种“默认值优先、参数覆盖兜底”的策略,是我在多个项目里验证过最省心、最不容易出错的数据构造方式。

3. 第二层模拟:API客户端与路由拦截

3.1 两种模拟API的路线选择

数据库搞定了,下一步是让前端页面拿到这些数据。这里有两种路线,我在不同项目里都用过:

路线A:绕过前端接口调用,直接把Mock数据注入到应用内部。这种方式要求被测应用具备可注入的数据访问层,对应用代码侵入性强,一般只适用于单元测试或组件测试。

路线B:保留前端真实的API调用行为,但在网络层拦截请求,然后返回Mock数据。Playwright的page.route就是干这个的,它可以在浏览器发出请求前就介入,让请求干脆到不了后端,直接把Mock数据返回给前端。

作为端到端测试的默认选择,路线B明显更合理。因为页面上的按钮点击、表格渲染、路由跳转全部保留了真实行为,只有后端依赖被替换掉了。这样从测试用例的视角看,整个应用“看起来”是完整的,测出来的结果也最接近真实用户感知。

3.2 用page.route拦截真实请求并返回Mock数据

先看一个最小实现。假设前端会向后端发起一个GET /api/me的请求,用来获取当前登录用户信息,我们在测试里拦截这个请求,并返回一个用户对象:

from playwright.sync_api import Page def intercept_user_api(page: Page, user: dict) -> None: def handler(route): response = { "code": 0, "message": "ok", "data": user, } route.fulfill( status=200, content_type="application/json", body=__import__("json").dumps(response, ensure_ascii=False), ) page.route("**/api/me", handler)

这里有两个容易被忽略的点。第一,route.fulfill里面传的body一定是字符串,不能直接传字典,我每次都要json.dumps一下。第二,URL匹配用的是**/api/me这种带通配符的写法,它的好处是不用关心前端页面究竟在哪个域名下访问接口,只要路径对得上就行,这能避免本地开发环境和CI环境域名不一致导致的匹配失败。

3.3 将Mock逻辑封装成可复用Fixture

上面这个函数只是基础能力,真正要落地到测试项目里,建议把拦截逻辑封装成一个Fixture。为了方便统一管理,我习惯把所有Mock路由注册到一个方法里,用例只需要调用一次就能把整个后端“虚拟化”。

# conftest.py import json import pytest from playwright.sync_api import Page, Route from mock_db import MockDB from data_factory import seed_order_scenario @pytest.fixture def mock_api(page: Page, mock_db: MockDB): def _register_order_routes() -> None: def order_list_handler(route: Route) -> None: orders = mock_db.list_orders() route.fulfill( status=200, content_type="application/json", body=json.dumps({"code": 0, "data": orders}, ensure_ascii=False), ) def order_detail_handler(route: Route) -> None: order_id = int(route.request.url.rstrip("/").split("/")[-1]) order = mock_db.get_order(order_id) if order: route.fulfill( status=200, content_type="application/json", body=json.dumps({"code": 0, "data": order}, ensure_ascii=False), ) else: route.fulfill( status=404, content_type="application/json", body=json.dumps({"code": 404, "message": "order not found"}), ) page.route("**/api/orders", order_list_handler) page.route("**/api/orders/*", order_detail_handler) return _register_order_routes

这段代码已经具备了一个基本Mock层的完整形态:列表接口、详情接口都有对应的Handler,Handler从MockDB取数据,然后以JSON格式返回给浏览器。注意order_detail_handler的URL解析逻辑,我是直接从请求URL末尾拿到订单ID的,这里有个隐含约定,就是要保证后端路由确实是/api/orders/{id}这种RESTful风格,如果你的项目不是这个风格,要改成从query参数取ID。

这里想特别强调一下返回结构。我在设计Mock接口时专门加了一个统一的包装结构{"code": 0, "message": "ok", "data": ...},这个结构不是一个随意的选择,而是为了对齐公司后端网关的通用响应对齐方案。如果你的Mock接口返回结构和真实后端不一致,前端代码里做响应解包的时候就会报错,直接导致页面白屏或者数据取不到。实战里最好的做法是:拿一份真实后端的响应样例,照抄它的结构。

4. 第三层模拟:测试数据的组装与生命周期

4.1 分清Fixture作用域,避免垃圾数据串场

现在数据库和API层面都完成了模拟,最后一块拼图是如何让测试用例拿到一组完整且互相不干扰的数据。

这里最关键的概念是Fixture的scope。在Pytest里,Fixture有四种作用域:function、class、module、session。它们的区别再直白不过:function作用域的Fixture,每个测试用例执行前都会重新创建;session作用域则整个测试会话只创建一次。

和我上面的设计对应起来:

  • 数据库仓库MockDB必须用function作用域,因为每个用例都需要一个干干净净、没有任何前朝遗留数据的仓库;
  • 浏览器实例用session或class作用域(Playwright插件通常默认管理),因为启动浏览器开销很大,没有必要每个用例都重新启动;
  • 登录态这类重量级数据可以用session作用域复用,但前提是你确认用例之间不会互相修改这个数据。

我用一张表来对比不同作用域的选择理由:

Fixture作用域选择理由
MockDBfunction保证每个用例拥有独立数据空间,彻底避免串场
mock_apifunction依赖page对象,且每个用例可能需要不同的路由行为,重新注册最稳妥
browsersession浏览器启动成本高,会话内复用可大幅缩短整体执行时间
pagefunction每个用例使用独立的标签页/上下文档,隔离性好;即使用例挂了也不影响后续用例

4.2 组装一套完整的“业务场景数据”

如果只是单个接口的Mock,前面几节的代码已经够用。但真实业务用例很少只依赖一个接口,比如“创建订单”这个动作就得同时有用户、商品、收货地址、库存等多个数据的支撑。针对这种情况,我会额外提供一个组合Fixture,把数据工厂、数据库仓库和路由注册串起来:

@pytest.fixture def order_scenario(mock_db: MockDB, mock_api): def _make_user_and_order(**kwargs): data = seed_order_scenario(mock_db, **kwargs) mock_api() return data return _make_user_and_order

这个Fixture返回的不是一个固定的数据对象,而是一个工厂函数。每个用例调用它的时候都可以传入自定义参数,比如想测“价格为零的订单页面”:

def test_zero_price_order(order_scenario, page: Page): scenario = order_scenario(price=0) page.goto("/orders/" + str(scenario["order"]["id"])) # 接下来就可以断言页面显示

这样我就能用同一个Fixture覆盖大量不同的业务分支,而不需要为每个分支单独写一套数据准备逻辑。如果对Pytest的Fixture不太熟悉,这里稍微补一句:Fixture里的返回值是惰性求值的,用例在调用order_scenario(...)之后才真正触发MockDB造数、注册路由这些操作,所以即便项目里有很多Fixture没有在用例里用到,也不会产生多余的开销。

4.3 配合参数化覆盖更多分支

数据、接口都模拟好之后,最后一个常用操作是Pytest的参数化。它让我们用一份用例逻辑验证多种数据分支。比如要测订单列表页在不同订单状态下的渲染情况:

import pytest @pytest.mark.parametrize("order_status", ["pending", "paid", "shipped", "cancelled"]) def test_order_list_status_rendering(order_status, mock_db, mock_api, page: Page): seed_order_scenario(mock_db, order_status=order_status) mock_api() page.goto("/orders") status_text = page.locator(".order-status").first.inner_text() assert order_status in status_text

这一招很实用,状态列表几乎是所有后台管理系统的标配功能,而状态又是典型的高频变化业务字段。如果没有Mock,想覆盖这四种状态就得在数据库里来回修改记录,费时费力还容易把别的用例搞脏;有了参数化加Mock数据库,一行参数就把四个分支全跑完了,执行效率和维护成本都是数量级的改善。

5. 踩坑实录:常见问题与排查方法

5.1 问题对照表

写这类测试时最容易踩的坑,我心里有一张不短的清单,挑几个最高频的列出来:

问题现象可能原因解决办法
页面数据没渲染出来,浏览器控制台报错Mock接口返回的数据结构和真实接口不一致对比真实后端响应样例,逐字段对齐结构
使用page.route后请求没有被拦截URL匹配模式写错,或者路由注册发生在请求之后确认路由模式,比如用**/api/orders;确保在page.goto之前注册路由
多个用例并发执行时数据串场MockDB被设计成了session作用域把MockDB改成function作用域,每个用例独立实例
点击导航后接口请求发出,但返回了上一次用例的数据route handler里引用了全局变量或旧的数据库引用检查是否在用例结束后清理了handler,或重新创建了page
Mock接口返回404,但页面没有进入错误展示404时返回了完整页面结构,没有走前端错误处理逻辑返回一个符合前端错误处理结构的数据,而不是随便一个状态码

5.2 三个最容易翻车的地方

第一个是路由注册的时机。很多新手把page.route写在某个页面动作发生之后,比如先在浏览器里点了按钮,再想起要Mock一个接口,那这个请求自然就跑到真实后端去了。记住:路由注册必须在触发请求前完成,最保险的做法是在page.goto之前把所有Mock注册好。

第二个是fixture之间的依赖顺序。MockDB和mock_api两个Fixture的关系是:mock_api依赖mock_db。如果反过来写,就会出现route handler已经注册,但它从数据库取值的时候数据库还没创建好的情况。在本文的设计里,product、order这些数据都来自mock_db,所以严格保证mock_db先于mock_api被创建。这个依赖关系Pytest会自己处理好,前提是你把Fixture的声明顺序写对。

第三个是测试数据挂在真实接口上的残留问题。有时候团队里还有一批历史用例是直接调真实后端的,一旦它们和Mock用例混跑,真实接口的数据会在库里制造出Mock用例完全不知道的记录。这种问题的排查极其折磨人,因为Mock用例本身看起来没有任何问题,但页面显示的数据就是多出了几条。我的建议是:要么彻底转向Mock方案,要么至少按照业务模块做物理隔离,不要在同一批执行环境里混用真实接口和Mock接口。

5.3 一个关于调试的硬经验

Mock数据拿不到或者数据结构不对的时候,我最常用的调试手段不是加print,而是让页面自己把接口响应打到日志里。Playwright的page.on("response")可以监听所有响应事件,我经常临时挂一个监听,把响应体直接打印出来:

def debug_responses(page: Page): def on_response(response): if response.url.startswith("**/api/orders**"): try: print(response.json()) except Exception: pass page.on("response", on_response)

不过这个方法有个前提,就是这个接口确实被浏览器发起了请求。如果请求压根没发出去,那么问题在前端逻辑而非Mock层,得去查前端代码或者控制台报错。我的经验是,控制台报错永远是最好的第一个线索,先看控制台,再看网络请求,最后才去核对Mock代码。

6. 一点个人经验与后续方向

整套方案跑通之后,我最大的感受是测试用例终于从“看环境脸色”变成了“受自己掌控”。不用再为了等测试环境数据库重置而加班,也不怕同事往测试库里塞一堆脏数据导致用例莫名失败。用例的失败率降下来,团队对自动化测试的信心也会明显提升。

如果你打算真的把这套方案用到自己的项目里,有两点我想单独拿出来说。第一,Mock接口的返回结构必须请熟悉后端响应格式的同事确认一遍,尤其是分页结构、时间格式化、状态码枚举这类细节。Mock数据的结构一旦和真实后端有偏差,前端在解包阶段就可能报错,这类问题比业务断言失败更隐蔽,因为它在任何一个用例里都可能会发生,排查起来没有规律可循。第二,Mock并不意味着把后端完全抛到一边,我建议给每个Mock接口都留一个开关,必要时可以切换成“透传模式”,也就是访问真实后端。这样在联调环境可用的时候,你仍然能跑一些真正端到端的验证,而不是被Mock封死。

后续可以扩展的方向也很多。比如可以在MockDB上做一个简单的“故障注入”接口,让测试用例可以模拟数据库超时、接口异常等服务不可用场景,用来验证前端页面的异常提示是否友好。再比如可以维护一个数据工厂的模板库,把公司里各种常用业务的造数逻辑沉淀成公共模块,团队的测试开发同学直接复用,不用重头写。总的来说,把数据库、API客户端和测试数据这三个模拟层做扎实,等于给测试项目打地基,地基稳了,后面盖什么楼都安心。

相关新闻

Qt 5.15.12 Windows 10下编译32位动态库完整指南

Qt 5.15.12 Windows 10下编译32位动态库完整指南

简介:面向Windows 10 32位应用开发的Qt 5.15.12动态库编译包,基于MSVC2019编译器构建,专为需要维护32位兼容性、或希望避开复杂编译配置的C开发者准备。压缩包内共2000个文件,以Qt头文件(.h)为主&#xff0…

2026/10/22 10:42:55 阅读更多 →
机械臂正运动学入门:从旋转矩阵到DH参数解析

机械臂正运动学入门:从旋转矩阵到DH参数解析

机械臂这个东西,入门时最容易迷惑的不是电机怎么转,而是“我要它去的点”和“它实际到的点”之间到底隔着什么。我刚开始折腾机械臂时,以为把每个舵机角度调到某个值就行,结果想让它末端走一条直线,它硬是在空中画了个…

2026/10/22 11:02:10 阅读更多 →
Java设计模式速通:场景+实战,快速掌握核心模式

Java设计模式速通:场景+实战,快速掌握核心模式

不是每一行代码都值得背下来,但设计模式是少数值得花时间想清楚的东西。尤其是Java生态里,框架源码、中间件、业务系统到处都嵌着这些模式,看不懂它们,读源码就像看天书;看懂了,重构和扩展的底气完全不一样…

2026/10/22 11:53:21 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/22 10:18:38 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/22 11:01:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/22 9:44:47 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/22 10:42:00 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/22 10:40:08 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/22 10:56:37 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/22 1:47:45 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/21 21:32:28 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/22 5:12:39 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 21:50:56 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 21:51:55 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/21 16:24:48 阅读更多 →