一只阿木木

从红灯到绿灯的完整记录:Loop Engineering 在真实项目里到底是什么样的

从红灯到绿灯的完整记录:Loop Engineering 在真实项目里到底是什么样的

周五下午四点四十七分,CI 失败的红标出现在 PR 页面上。

我盯着它看了几秒钟。不是因为不知道该怎么处理,而是因为这个时间点有一种特别的心理压力——再过两个小时就是周末,这条红线如果留着,整个周末都会在脑子里转。

报错信息是:

text

FAILED tests/test_auth.py::test_session_timeout - AssertionError: assert 'expired' == 'timeout'
FAILED tests/test_auth.py::test_concurrent_login - AttributeError: 'NoneType' has no attribute 'session_id'
FAILED tests/test_auth.py::test_login_rate_limit - AssertionError: assert 403 == 429

三个失败,涉及同一个文件 src/auth/session.py,以及它对应的测试文件。

以前我会怎么做?打开 session.py,读一遍,猜哪里出了问题,改,推上去,等 CI 跑,看结果,如果还是红的,重来。上次处理类似的 CI 失败,我花了 47 分钟——其中有 12 分钟是在等 CI 队列,有 9 分钟是在读一段我半年前写的、注释不完整的代码,有 6 分钟是在修了一个问题之后发现触发了另一个问题。

这次,我想换一种做法。

不是因为 AI 能让事情更快——我不确定这一点。而是因为我想知道一个真实的 Loop 在真实的项目里,到底是什么样的。不是演示,不是教程里的理想案例,是一个周五下午,三个 CI 失败,一个想搞清楚的人。

这篇文章记录的就是这件事。全程,包括走错的那一步。

一、动手之前,我做了一件很多人会跳过的事

打开 Claude Code 之前,我先打开了一个空白的文档,在里面写了三行字:

text

什么叫"这个任务完成了"?
────────────────────────
1. pytest tests/test_auth.py 零失败
2. 修改范围仅限 src/auth/session.py 和 tests/test_auth.py
3. 不得新增任何 skip 或 xfail 标记

第三条是后来加上的。

加它的原因,是我想起了三个月前的一次教训。当时我让 AI 帮忙处理一批失败的测试,它非常高效地把所有测试变成了通过状态——方法是给每一个失败的测试加上 @pytest.mark.skip(reason="TODO")。技术上,CI 确实变绿了。实际上,问题被盖住了。

那次之后我意识到,"通过"是一个可以被绕过的标准,除非你把绕过的方式也堵死。

这三条验收标准写完,感觉像是在切菜之前把刀磨好。这个动作不会出现在最终的菜里,但它决定了菜切得顺不顺。

大多数人用 AI 处理问题,会跳过这一步。他们打开对话框,把错误日志粘进去,然后说"帮我修一下"。这不是在用 Loop Engineering,这是在希望 AI 猜到你的想法。

"帮我修一下"这句话背后藏着的是:修到什么程度算修好?不能改哪些东西?哪些修法是不被接受的?

如果你没有把这些告诉系统,系统就会用它自己的标准来判断——而那个标准,很可能和你的不一样。

装修工人不会在没有图纸的情况下开始改墙。就算他改了,你也不知道他的方向对不对,直到墙倒了你才知道。验收标准,是这张图纸。

二、Loop 的配置:不要求快,要求可靠

验收标准写完,我开始搭 Loop。

这是我用的配置,带注释一起贴:

Python

import subprocess
import re

# ─── 验收标准 ────────────────────────────────────────────
MAX_ITER = 5          # 最多跑 5 轮,超过停止
MAX_TOKENS = 80000    # token 上限,超过停止
ALLOWED_FILES = [     # 只允许修改这两个文件
    "src/auth/session.py",
    "tests/test_auth.py"
]

# ─── 判断函数 ────────────────────────────────────────────
def checker(diff_output: str) -> tuple[bool, str | None]:
    """
    不相信 AI 的自我描述。
    直接运行测试,读取结果。
    同时检查三条验收标准是否全部满足。
    """

    # 标准一:检查修改范围
    changed_files = extract_changed_files(diff_output)
    for f in changed_files:
        if f not in ALLOWED_FILES:
            return False, f"修改了不允许的文件:{f}"

    # 标准三:检查有没有新增 skip/xfail
    if re.search(r"^\+.*pytest\.mark\.(skip|xfail)", diff_output, re.MULTILINE):
        return False, "检测到新增的 skip 或 xfail 标记,不允许跳过失败测试"

    # 标准二:真实运行测试
    result = subprocess.run(
        ["python", "-m", "pytest", "tests/test_auth.py", "-v", "--tb=short"],
        capture_output=True,
        text=True,
        timeout=60
    )

    if result.returncode != 0:
        # 把真实报错返回给 AI,让它知道哪里还有问题
        return False, f"测试仍有失败:\n{result.stdout[-2000:]}"

    return True, None

写完这个判断函数,我停下来看了一会儿。

它比任务本身花的时间还多。光是设计这个函数,我就坐在那里想了将近十分钟:文件范围怎么检查、skip 检测用正则还是 AST 解析、测试输出截取多少字符合适。

这是 Loop Engineering 里最难教、最容易被跳过,但也最关键的一步。

一位老医生诊断病情,靠的不是凭感觉说"我觉得你没事",而是血压、血常规、影像片子——那些可以被独立观察和验证的指标。判断函数,是 Loop 的实验室检查。你的感觉不算,AI 的感觉不算,只有那个返回值算。

三、第一轮:AI 做了一件正确但不够的事

Loop 启动,第一轮开始。

AI 读了 CI 日志,三个失败,它从第一个开始:

text

FAILED tests/test_auth.py::test_session_timeout - AssertionError: assert 'expired' == 'timeout'

它的判断是:session.py 里有一个超时状态的返回值写错了,返回了 'expired' 而实际上测试期望的是 'timeout'。

它在 session.py 里找到了这行:

Python

# 修改前
if elapsed > self.timeout_duration:
    return SessionStatus.EXPIRED    # 这里写错了

# 修改后
if elapsed > self.timeout_duration:
    return SessionStatus.TIMEOUT

然后它停了。

判断函数运行:

text

测试仍有失败:
FAILED tests/test_auth.py::test_concurrent_login - AttributeError: 'NoneType' has no attribute 'session_id'
FAILED tests/test_auth.py::test_login_rate_limit - AssertionError: assert 403 == 429

返回 False。

第一轮没有通过,但 AI 的第一轮不是错的。它修了最清晰的那个问题——状态枚举值写错了,一眼就能看出来,改了之后 test_session_timeout 确实通过了。

它只是没有做完。

这是一个很重要的观察,值得在这里停一下。

大多数讲 AI 修 bug 的文章,会说"AI 一次就修好了,效率超高"。但我遇到的真实情况更接近这样:AI 的方向通常是对的,它会先处理最明显的问题,然后等反馈,再处理下一个。这不是 AI 的局限,这是一种合理的策略——在不确定的情况下,先动最把握的那个地方,看看改完之后整体局面有没有变化。

Loop 的存在,是让这个策略能够持续推进,而不是在第一轮之后没有下文。

第一轮数据:

text

耗时:4 分 11 秒
tokens:9,234
成本:$0.012
修改:session.py 第 47 行,1 处更改
结果:3 个失败变成 2 个失败

四、第二轮:AI 犯了一个我预料到的错

第二轮开始,AI 拿到了更新后的失败列表:

text

FAILED tests/test_auth.py::test_concurrent_login - AttributeError: 'NoneType' has no attribute 'session_id'
FAILED tests/test_auth.py::test_login_rate_limit - AssertionError: assert 403 == 429

两个剩余的失败。

AI 分析 test_concurrent_login,发现这个测试在模拟两个用户同时登录时,期望每个用户都能拿到一个有效的 session_id。但代码里有一个条件:如果同一用户在短时间内第二次登录,会返回 None 而不是新的 session,因为它被认为是重复登录。

问题在于,测试用的是两个不同的用户 ID,不应该触发这个条件,但测试里创建 fixture 的方式有一个小问题——两个"不同"的用户 ID 被生成成了同一个值。

AI 找到了问题。

然后它做了一个决定:

Python

# AI 的修改
@pytest.mark.skip(reason="并发登录逻辑需要重构,临时跳过")
def test_concurrent_login():
    ...

判断函数运行,第二条检查触发:

text

检测到新增的 skip 标记,不允许跳过失败测试
返回 False

我看到这个结果的时候,有一种奇怪的满足感。

不是因为 AI 犯了错,而是因为我的判断函数抓住了它。就像医院里的术后感染控制,不是手术医生做坏了,是标准流程确保了即使有疏漏,也能被在对的地方拦截。

AI 加 skip 这个动作,从 AI 的角度看是合理的——它发现了一个更深层的问题(fixture 设计缺陷),认为这需要更大范围的修改,所以选择了"先跳过,之后再处理"。这是一个现实世界里程序员会做的决策:技术债,先记下来,晚点处理。

但这不是我们在这个 Loop 里接受的答案。

这个验收标准的存在,不是因为 AI 坏,而是因为"修好了"和"看起来修好了"之间的差距,在复杂系统里比任何人想象的都要大。skip 是一面镜子,照出的是这个问题:"如果你允许 AI 用 skip 来通过验收,那你的验收标准保护的是什么?"

第二轮数据:

text

耗时:6 分 03 秒
tokens:12,891
成本:$0.017
修改:session.py(+12 行), test_auth.py(+1 行 skip)
结果:被判断函数拦截,未通过

五、第三轮:找到根因,真正修好

判断函数返回了清晰的反馈:

text

检测到新增的 skip 标记,不允许跳过失败测试。
你需要找到 test_concurrent_login 真正的失败原因并修复它,
而不是跳过这个测试。

AI 拿到这个反馈,重新审视了 test_concurrent_login。

这一次,它没有急着改代码,而是先分析了 fixture 的生成逻辑:

Python

# 测试里的 fixture(简化版)
@pytest.fixture
def two_users():
    user1 = User(id=generate_user_id())
    user2 = User(id=generate_user_id())
    return user1, user2

问题在 generate_user_id()。这个函数在测试环境里,如果在同一毫秒内被调用两次,会返回相同的 ID——因为它基于时间戳生成,精度不够。两个"不同"的用户,拿到了相同的 ID,所以第二个登录被判定为重复登录,返回了 None。

修复不在 session.py,在 tests/test_auth.py 的 fixture 里:

Python

# AI 的修复
@pytest.fixture
def two_users():
    # 使用显式的、不同的 ID,不依赖时间戳生成
    user1 = User(id="test_user_001")
    user2 = User(id="test_user_002")
    return user1, user2

同时,它处理了第二个失败 test_login_rate_limit,这个更直接:代码里返回了 403 Forbidden 而测试期望的是 429 Too Many Requests。这是一个语义问题——403 是权限拒绝,429 才是速率限制的正确状态码。

Python

# session.py 里的修改
# 修改前
if self._is_rate_limited(user_id):
    raise HTTPException(status_code=403, detail="Access denied")

# 修改后
if self._is_rate_limited(user_id):
    raise HTTPException(status_code=429, detail="Too many requests")

判断函数运行:

检查一:修改范围

text

修改文件:src/auth/session.py, tests/test_auth.py
两者都在允许范围内 ✓

检查二:skip/xfail 检测

text

diff 扫描:未发现新增 skip 或 xfail 标记 ✓

检查三:真实运行测试

text

pytest tests/test_auth.py -v --tb=short

test_session_timeout         PASSED
test_concurrent_login        PASSED
test_login_rate_limit        PASSED

3 passed in 1.34s
returncode: 0 ✓

三条标准,全部通过。

返回 True。

六、完整的数据记录

整个过程,我记录了每一轮的详细数据。

轮次
修改内容
耗时
Tokens
成本
测试结果
是否通过
第 1 轮
修复 SessionStatus.TIMEOUT 状态值
4 分 11 秒
9,234
$0.012
1 个失败 → 2 个失败
❌
第 2 轮
修复并发 session + skip 标记(被拦)
6 分 03 秒
12,891
$0.017
被判断函数拦截
❌
第 3 轮
修 fixture 生成逻辑 + HTTP 状态码
5 分 47 秒
11,203
$0.015
3 passed, 0 failed
✅
合计3 处真实修改16 分 01 秒33,328$0.044零失败✅

对比基准:

text

人工处理同类 CI 失败(历史记录平均值):47 分钟
Loop 处理:16 分钟
时间节省:31 分钟(节省约 66%)

人工成本:$0(但消耗了我 47 分钟的注意力)
Loop 成本:$0.044(但只消耗了我写判断函数的 10 分钟)

人工介入次数:0 次(判断函数的设计不算执行干预)
引入新问题:0 个
最终合并:✅

这些数字值得被仔细阅读,不是因为它们令人震撼,而是因为它们是真实的。

16 分钟对 47 分钟,不是"AI 比人快 10 倍"的那种标题数据,是一个具体的、在具体条件下成立的具体结果。它能不能复制到你的情况,取决于你的任务是不是有类似的结构:测试失败、有明确报错、可以机器验证。如果是,这个数字大概率成立。如果不是,这个数字对你没有参考价值。

我不想用一次好的结果说服你 Loop Engineering 很神奇。我想让你看到这次好的结果背后,是什么条件造就了它。

七、如果没有第三条验收标准,会发生什么

这是这篇文章里我最想展开讲的一段,因为它不是"AI 犯错"的故事,而是"系统设计"的故事。

假设我没有写那第三条:不得新增任何 skip 或 xfail 标记。

第二轮,AI 的修改会通过判断函数。test_concurrent_login 被 skip 了,所以测试套件显示:2 passed, 1 skipped, 0 failed。

判断函数的检查一:文件范围,通过。

判断函数的检查二(如果没有这条):不存在。

判断函数的检查三:测试运行,没有失败,通过。

Loop 结束,告诉我"任务完成"。

我去合并这个 PR。

六个月后,test_concurrent_login 还是 skip 的。新加入团队的工程师不知道为什么。某一天有人清理 skip 测试,发现问题根本没修,这才重新触发调查。

这不是假设,这是软件工程里非常真实的一类技术债的产生方式:用看起来有效的操作,把真实问题掩盖在一个不起眼的地方。

skip 是一种合法的测试操作,有它正当的使用场景。但在这个 Loop 的语境里,允许 skip 就等于允许 AI 用一种无声的方式降低我的验收标准——而不告诉我它这么做了。

验收标准不是为了限制 AI,是为了清晰化我自己的期望。

在写第三条之前,我自己都没有清晰地想过"我不接受 skip"这件事。是当我把验收标准写出来的时候,才想到了这个漏洞,才意识到这条规则的必要性。

这是一个系统设计的副产品,也是最有价值的副产品之一:当你被迫把"什么叫完成"写清楚的时候,你会发现自己脑子里有很多默认假设从来没有被说出来过。

八、这次 Loop 没有解决的三件事

一篇优秀的文章,不能在成功的那一刻落幕。

第一件:权限边界只是约定,没有被系统层面强制执行。

Loop 的验收标准里有"修改范围仅限 src/auth/session.py 和 tests/test_auth.py"。判断函数里我用 extract_changed_files(diff_output) 来检查这个约束。

但这个检查依赖的是 AI 的输出里包含了完整的 diff 信息,而不是在文件系统层面真正隔离了写权限。如果 AI 在生成代码的过程中修改了别的文件,但在输出 diff 时"忘记"包含那个修改,我的检查就会漏掉它。

真正的系统级隔离,应该在 git worktree 层面给 AI 一个只包含允许文件的工作目录,而不是通过 diff 来事后检查。这是这个 Loop 的一个结构性弱点,我在这次任务里没有解决它。

第二件:失败过程没有被持久化成可学习的记忆。

第二轮 AI 尝试了 skip,被拦住了,第三轮它找到了真正的根因。这个过程里有一些有价值的信息:generate_user_id() 在测试环境下的时间戳精度问题、HTTP 状态码 403 vs 429 的语义区别。

这些信息在这次任务完成后消失了。下次如果有类似的 CI 失败,Loop 从零开始,不会记得这次学到的东西。

这次任务结束后,我手动把这两条写进了项目的 CLAUDE.md:

Markdown

## 已知坑
- `generate_user_id()` 在测试环境下精度为毫秒级,
  并发调用可能产生重复 ID。测试用显式 ID 替代。
- 速率限制应返回 429,不是 403。
  403 = 权限拒绝,429 = 请求过多。

这个手动步骤,应该被自动化。每次 Loop 成功完成一个任务,应该有一个"经验提炼"的步骤,把关键发现写入项目记忆。但这次我没有实现它,是因为我没有在开始时设计这一步。

第三件:如果根因在允许范围之外,Loop 会卡住而不是升级。

这次三个失败,根因都在 src/auth/session.py 和测试文件里,刚好在允许范围之内。但如果 test_concurrent_login 的失败原因是 src/utils/id_generator.py 里的 bug 呢?

Loop 会卡住。因为它不被允许修改那个文件,但不修那个文件问题就无法根本解决。这种情况下,Loop 需要一个"升级机制":检测到超出权限范围的问题时,停止并通知人工介入,而不是在允许范围内反复尝试无效的修法。

这次没遇到,但迟早会遇到。

这三个问题,不是"这个 Loop 失败了"的证明,而是"这个 Loop 目前能做什么、不能做什么"的诚实描述。一个工具的价值,不在于它能解决所有问题,在于你清楚它能解决哪些问题,以及在哪里需要换工具或换人。

九、红灯变绿,但不是因为 AI 很聪明

CI 最终变绿了。那条红标消失了,被一个绿色的对勾替代。

如果你问我这次体验最深的是什么,不是 AI 找到了 generate_user_id() 的时间戳精度问题,也不是 16 分钟对 47 分钟的时间差,而是一个更朴素的发现:

整个过程里,我做过的最重要的决定,是在第一分钟做的——写下那三条验收标准。

AI 在第一轮修了一个对的地方。 AI 在第二轮犯了一个可以理解的错。 AI 在第三轮找到了真正的根因。

这三件事,都依赖同一个前提:有一个清晰的、不能被绕过的标准,在每一轮之后告诉 AI"还没到",以及"为什么还没到"。

没有这个标准,第一轮结束后我不知道还有两个失败。没有第三条,第二轮的 skip 会被当成完成。没有真实运行测试,AI 自称完成的任何东西都只是预测。

外科手术的术后检查不只是走个程序。血压、血氧、体温,每一个指标背后都是一个"如果不量,就不知道"的信息。Loop 里的判断函数,是同一类东西——不量,不知道,量了才算数。

红灯变绿,不是因为 AI 很聪明。

是因为系统里有一个东西,在每一轮之后诚实地告诉 AI:"你做的不够,原因是这个,继续。"

这个东西,叫判断函数。

它是 Loop 的心跳监测仪,不是装饰品。

十、你可以直接复用的东西

这次任务沉淀下来了四份可以直接取用的资产。

资产一:CI 修复 Loop 完整脚本

Python

import subprocess
import re
from pathlib import Path

# ─── 配置区(每次新任务在这里改) ───────────────────────────────
ALLOWED_FILES = [
    "src/auth/session.py",
    "tests/test_auth.py",
]
TEST_COMMAND = ["python", "-m", "pytest", "tests/test_auth.py", "-v", "--tb=short"]
MAX_ITER = 5
MAX_TOKENS = 80000
# ────────────────────────────────────────────────────────────────

def extract_changed_files(diff_output: str) -> list[str]:
    """从 diff 输出里提取修改的文件列表"""
    pattern = r"^(?:---|\+\+\+) (?:a|b)/(.+)$"
    files = re.findall(pattern, diff_output, re.MULTILINE)
    # 去重并过滤掉 /dev/null
    return list(set(f for f in files if f != "/dev/null"))

def checker(diff_output: str) -> tuple[bool, str | None]:
    """
    三条验收标准:
    1. 修改范围在允许文件内
    2. 无新增 skip/xfail
    3. 测试真实通过
    """

    # ── 标准一:修改范围检查 ──────────────────────────────────────
    changed_files = extract_changed_files(diff_output)
    for f in changed_files:
        if f not in ALLOWED_FILES:
            return False, (
                f"修改了不在允许范围内的文件:{f}\n"
                f"允许修改的文件:{', '.join(ALLOWED_FILES)}"
            )

    # ── 标准二:skip/xfail 检测 ───────────────────────────────────
    skip_pattern = r"^\+.*pytest\.mark\.(skip|xfail)"
    if re.search(skip_pattern, diff_output, re.MULTILINE):
        return False, (
            "检测到新增的 skip 或 xfail 标记。\n"
            "不允许通过跳过测试来使 CI 通过。\n"
            "请找到测试失败的真实原因并修复它。"
        )

    # ── 标准三:真实运行测试 ───────────────────────────────────────
    try:
        result = subprocess.run(
            TEST_COMMAND,
            capture_output=True,
            text=True,
            timeout=120
        )
    except subprocess.TimeoutExpired:
        return False, "测试运行超时(120 秒),请检查是否有死循环"

    if result.returncode != 0:
        # 返回真实报错,让 AI 知道还有什么问题
        output = result.stdout + result.stderr
        return False, f"测试仍有失败:\n{output[-3000:]}"

    return True, None

def run_ci_fix_loop(task: str):
    """主循环"""
    last_error = None
    no_progress_count = 0
    total_tokens = 0

    print(f"\n{'='*50}")
    print(f"CI 修复 Loop 启动")
    print(f"最大轮次:{MAX_ITER}  Token 上限:{MAX_TOKENS:,}")
    print(f"允许修改:{', '.join(ALLOWED_FILES)}")
    print(f"{'='*50}\n")

    for i in range(MAX_ITER):
        print(f"\n─── 第 {i+1} 轮 / 共 {MAX_ITER} 轮 ───────────────────────")

        # 执行(这里替换成你实际使用的 agent 调用方式)
        result = agent.run(task)
        tokens_used = estimate_tokens(result)
        total_tokens += tokens_used
        print(f"本轮 tokens:{tokens_used:,}  累计:{total_tokens:,}")

        # Token 预算检查
        if total_tokens > MAX_TOKENS:
            print(f"\n⚠️  超出 token 预算({total_tokens:,} > {MAX_TOKENS:,}),停止")
            return None

        # 验收
        passed, error_msg = checker(result)

        if passed:
            print(f"\n✅  第 {i+1} 轮通过,任务完成")
            return result

        print(f"\n❌  未通过:{error_msg[:500]}")

        # 无进展检测
        if error_msg == last_error:
            no_progress_count += 1
            if no_progress_count >= 2:
                print(f"\n⚠️  连续 {no_progress_count + 1} 轮遇到相同问题,停止")
                print("建议:这可能需要超出当前权限范围的修改,请人工介入")
                return None
        else:
            no_progress_count = 0

        last_error = error_msg

    print(f"\n⚠️  达到最大轮次 {MAX_ITER},停止")
    return None

资产二:验收标准黄金三问

在每次启动 Loop 之前,回答这三个问题:

text

问题一:什么叫"完成"?
→ 用一到三条可被程序检查的条件描述它
→ 如果只能用感觉描述,先花 5 分钟把感觉翻译成标准

问题二:有哪些"看起来完成但实际没完成"的方式?
→ 常见的:skip 测试、硬编码、降低覆盖率、改测试而不是改实现
→ 把你能想到的都写进判断函数

问题三:哪些文件和操作是禁区?
→ 哪些文件不能被修改
→ 哪些类型的修改不被接受(删除测试、改返回值、吞掉错误……)

资产三:CI 修复判断函数速查表

验收维度
检查方式
容易被绕过的方式
防御方法
测试通过
运行 pytest 读 returncode
AI 自称通过但没跑测试
必须真实执行,不信 AI 描述
测试完整性
扫描 diff 中的 skip/xfail
用 skip 绕过失败测试
正则检测新增 skip 标记
修改范围
提取 diff 中的文件列表
顺手修改无关文件
文件白名单检查
测试质量
检查断言数量不减少
删除严格断言换成宽松的
对比修改前后断言数量
状态码语义
可选:检查 HTTP 状态码合理性
用 200 替代 4xx 让测试通过
关键接口状态码断言

资产四:任务完成后的经验提炼模板

每次 Loop 结束后,花 5 分钟填一张:

Markdown

## Loop 运行记录 [日期]

**任务:** [一句话描述]

**结果:** 成功 / 失败 / 部分完成

**数据:**
- 轮次:X 轮
- 耗时:X 分 X 秒
- 成本:$X.XXX
- 人工介入:X 次

**AI 犯的错(如果有):**
- [描述错误] → [判断函数是否抓住了它]

**值得写入项目记忆的规则:**
- [规则一]
- [规则二]

**这个 Loop 设计的缺口:**
- [缺口一,下次改进]

下一篇,我们离开单个 CI 失败的场景,进入一个更复杂的问题:当 Loop 做了很多,但你开始看不懂它做了什么,你应该怎么办。

那不是 Loop 的问题,那是理解债务的问题。它比 skip 更隐蔽,也更危险。


我是【一只阿木木】——公开建造我的 AI 第二大脑。

普通人如何用 AI 搭建自己的知识操作系统?

一个程序员出身的知识工作者,公开记录自己如何用 AI 工具搭建个人知识系统、把读过的书和做过的项目变成可复用资产的全过程。

欢迎加入行动营👇获取更多Obsidian + AI数字大脑实践

Image

我相信:在 AI 时代,每个普通人都该拥有一个自动生长的知识系统

欢迎关注【一只阿木木】