让 Agent 看仓库就能干活
基于代码仓库的 AI-native · 一份讲义

让新开的 Agent,看仓库就能干活

把干活要用的东西都放进仓库:要做什么、代码在哪、怎么跑、怎样算对、改了什么。新开一个 Agent,不用你再解释,也能做完、自己检查、交给你审。

讲义按一条主线走:为什么要这样做 → 要做到什么 → 需要哪几样东西 → 怎样做好 → 从哪开始。例子取自 Stanford CS146S 的作业和源码,但不按课程顺序讲。

开工前的六个问题新会话 · 没有聊天记录
要做什么?做到哪算完?
任务规格docs/TASKS.md
代码在哪?有什么规矩?
项目上下文AGENTS.md
用什么命令跑?
执行入口Makefile
写错了能发现吗?
质量反馈tests/
哪里不能碰?谁来拦?
操作边界运行环境的权限和沙箱
交什么给人看?
交付证据改动 · 测试结果 · PR 说明
适合谁
用过 Claude Code、Codex、Cursor 这类工具,看得懂一点 Python。
用时
约一小时。第五章是查阅用的,可以先跳过。
例子来源
CS146S 2025/2026 的作业和源码;页内小实验;teaching/lab/ 里的三个脚本。

学完你能

标签:实测这次跑过读码看代码得出,没跑推断根据代码和文档推出,没跑建议讲义的看法

一 · 问题

Agent 只认仓库,不记得聊天

新开的会话默认看不到上一次的聊天。它能依据的只有两样:仓库里的文件,和你这次说的话。

所以,靠口头讲、靠聊天传下去的规矩,每开一次新会话就丢一次。你会发现自己一遍遍解释同样的事:测试怎么跑、哪个目录别动、改完要交什么。漏讲一句,它就按自己的猜测来。

办法是把这些写进仓库,并让仓库自己能检查。这就是"基于代码仓库的 AI-native":

把仓库建成人和 Agent 共用的工作环境:要做什么、项目知识、怎么做、怎样算对、改了什么,都存在仓库里,能复用、能检查。
二 · 目标

只靠仓库,走完五步

检验标准只有一个:开一个新会话,不做口头补充,只给一张任务单。它能不能靠仓库走完这五步?

  1. 理解任务
  2. 修改
  3. 验证
  4. 修正
  5. 交付

这五步由三方分工完成:

仓库存规矩和依据

任务说明、AGENTS.md、Makefile、测试、Git 历史。

Agent 运行环境负责动手

读写文件、跑命令、把结果交回模型。权限、沙箱、次数上限也在这里。

你定目标、做取舍、验收

决定做什么、什么算完成,批准有风险的操作。

三 · 拆解

每一步卡在哪,就补什么

倒过来想:新会话在每一步会卡在哪里?把让它不卡的东西补上,就得到六样。它们不是一份清单,是从这五步里推出来的。

  1. 理解任务

    会卡在不知道要做什么、做到哪算完;不知道代码在哪、有什么规矩。

  2. 修改

    会卡在改到不该改的地方,也没有东西拦它。

  3. 验证

    会卡在不知道用什么命令跑;跑了也看不出对错。

  4. 修正

    会卡在错了没人告诉它,或者一出错程序就崩。

  5. 交付

    会卡在你看不懂它改了什么、凭什么说做完了。

四 · 原则

把六样做好,靠四条原则

有了这六样还不够,还得做对。下面四条原则贯穿六样东西,每条配一个课程里的真实例子。

  1. 写清楚:具体、能直接用,而且是真的。
  2. 查得出:检查要能抓住你担心的错。
  3. 拦得住:执行、拦截、报错靠运行环境,不靠文字。
  4. 交得明白:不看聊天,也能审、能撤回。
原则 ①

写清楚:具体、能直接用,而且是真的

  1. 理解
  2. 修改
  3. 验证
  4. 修正
  5. 交付

写进仓库的每一句话,都会被 Agent 当真。所以要过三关:

  • 具体:命令要能直接复制,写明在哪个目录跑。写 make test,别写"运行测试"。
  • 只写这个仓库特有的:"请写高质量代码"这种放哪都成立的话,模型本来就会做;照抄 README 也是浪费。说明文件每次都会读进上下文,越长越费。
  • 是真的:写之前验证过。一句没验证的"事实",比不写更糟。

好的例子:CS146S 2025 年第 4 周的 Makefile,把启动、测试、格式化、检查、灌数据都写成了固定命令。

2025/week04/assignments/MakefileL1–17 · 打开原文
.PHONY: run test format lint seedrun:    PYTHONPATH=. uvicorn backend.app.main:app --reload --host $${HOST:-127.0.0.1} --port $${PORT:-8000}test:    PYTHONPATH=. pytest -q backend/testsformat:    black .    ruff check . --fixlint:    ruff check .seed:    PYTHONPATH=. python -c "from backend.app.db import apply_seed_if_needed; apply_seed_if_needed()"

练习:留、删还是改

假设你要给这个示例应用(FastAPI + SQLite)写 AGENTS.md。下面六句,该留、删还是改?想好再点开。

  1. 跑测试:在 week4/ 目录下执行 make test(等于 PYTHONPATH=. pytest -q backend/tests)
    看答案

    留读码命令准确,能直接复制,还说了在哪个目录跑(Makefile L6–7;作业 L59、L71)。

  2. 请编写高质量、可维护、符合最佳实践的代码。
    看答案

    删放在哪个仓库都成立,模型本来就会这么做。作业 L56 管这叫凑字数:这个文件每次都会读进上下文,越长越费。

  3. 本项目基于 FastAPI,这是一个高性能的现代 Python Web 框架。
    看答案

    删重复 README 和常识。有用的是下一句那种"东西在哪"。

  4. 路由在 backend/app/routers/,测试在 backend/tests/;测试用 client 夹具,它把数据库换成临时 SQLite。
    看答案

    留读码说清了入口和测试的写法(conftest.py L14–34)。

  5. 测试和开发数据库完全隔离,可以放心反复跑。
    看答案

    改推断测试只把请求用的数据库换成了临时库。但 with TestClient(app) 会触发应用启动(FastAPI 文档),启动时会在真实库上建表;data/app.db 不存在时,还会新建它并灌入种子数据(db.py L43–56)。没跑过,就别写"完全隔离"。先跑一次 make test,看 data/app.db 有没有冒出来。

    2025/week04/assignments/backend/tests/conftest.pyL34–37 · 打开原文
        app.dependency_overrides[get_db] = override_get_db    with TestClient(app) as c:        yield c
    2025/week04/assignments/backend/app/main.pyL21–24 · 打开原文
    @app.on_event("startup")def startup_event() -> None:    Base.metadata.create_all(bind=engine)    apply_seed_if_needed()
  6. data/app.db 是运行时生成的本地库,别提交、别手改;要改初始数据,改 data/seed.sql。
    看答案

    留读码说清了哪里不能改、该改哪里(db.py L12、L43–56)。

原则 ②

查得出:测试过了不算数

  1. 理解
  2. 修改
  3. 验证
  4. 修正
  5. 交付

Agent 靠检查结果判断自己做没做对。检查太松,它就会带着错误报"完成"。

例子还是那个示例应用。任务单要求搜索不分大小写:

2025/week04/assignments/docs/TASKS.mdL8–11 · 打开原文
## 2) Add search endpoint for notes- Add/extend `GET /notes/search?q=...` (case-insensitive) using SQLAlchemy filters- Update `frontend/app.js` to use the search query- Add tests in `backend/tests/test_notes.py`

现有的搜索测试只查了请求成功、结果不为空:

2025/week04/assignments/backend/tests/test_notes.pyL13–19 · 打开原文
    r = client.get("/notes/search/")    assert r.status_code == 200    r = client.get("/notes/search/", params={"q": "Hello"})    assert r.status_code == 200    items = r.json()    assert len(items) >= 1

一个不管搜什么都返回全部笔记的实现,也能通过。

测试过了不算数,要看它能不能抓住你担心的那种错。下面的小实验可以亲手试。

课程现在的搜索代码如下。注意第 31–32 行:没给搜索词时,返回全部。

2025/week04/assignments/backend/app/routers/notes.pyL29–39 · 打开原文
@router.get("/search/", response_model=list[NoteRead])def search_notes(q: Optional[str] = None, db: Session = Depends(get_db)) -> list[NoteRead]:    if not q:        rows = db.execute(select(Note)).scalars().all()    else:        rows = (            db.execute(select(Note).where((Note.title.contains(q)) | (Note.content.contains(q))))            .scalars()            .all()        )    return [NoteRead.model_validate(row) for row in rows]
原则 ② · 小实验

故意写错,看测试抓不抓得住

这里有四版搜索:课程原版,加三种常见写错法。先看原来的测试结果,再点按钮加三条新测试。

选一版,看代码
版本 原测试只有 1 条笔记;搜 Hello,有结果就算过 ① 大小写都能搜到搜 hello,要有 #1 和 #3 ② 不混进无关的搜 hello,不能有 #2 ③ 搜不到就返回空搜 zzz,结果为空

试试 Hello、zzz、%、_,或者留空。

    新测试用的 3 条笔记
    #标题内容
    1TestHello world(和课程测试一样)
    2Groceriesmilk and eggs
    3HELLO titlecaps in title
    示例:加强后的测试(不是课程代码,没在课程应用上跑过)可以加进 backend/tests/test_notes.py
    def test_search_is_case_insensitive_and_filters(client):    for title, content in [("Test", "Hello world"), ("Groceries", "milk and eggs"), ("HELLO title", "caps in title")]:        client.post("/notes/", json={"title": title, "content": content})    titles = {n["title"] for n in client.get("/notes/search/", params={"q": "hello"}).json()}    assert titles == {"Test", "HELLO title"}                                  # ① 和 ②    assert client.get("/notes/search/", params={"q": "zzz"}).json() == []     # ③

    推断换个数据库,结果可能不同

    课程代码能过 ①,是因为 SQLite 的 LIKE 默认不分英文大小写(SQLite 文档)。PostgreSQL 的 LIKE 分大小写,要换成 ILIKE(PostgreSQL 文档)。代码不变、换到 PostgreSQL,就不满足任务单第 9 行了。另外 实测非英文字母不会忽略大小写:用 école 搜不到 École。

    实测% 和 _ 会被当成通配符

    SQLAlchemy 的 contains() 默认不处理 % 和 _(文档),所以搜 % 会返回全部,上面可以试。想按原样搜,写 contains(q, autoescape=True)。算不算 bug,要看需求怎么定。

    读码测试写不出来,先补需求

    不给搜索词时返回全部(notes.py L31–32),测试第 13–14 行只查了状态码。需求没说这时该返回什么,测试也就没法判断对错。

    建议带回你自己的仓库

    故意写几版"看着对、其实错"的代码,看测试能不能抓出来。抓不出来的那版,就告诉你测试缺了哪条。

    页面里的结果是浏览器现算的,按 SQLite 的搜索规则模拟。同样四版代码用 Python 自带的 sqlite3 跑过,结果一样:search_mutants.py,输出在 results.txt。课程原版的 FastAPI 应用和测试没跑:本机缺依赖,沙箱也挡住了下载。

    原则 ③

    拦得住:靠运行环境,不靠文字

    1. 理解
    2. 修改
    3. 验证
    4. 修正
    5. 交付

    AGENTS.md 里写"别改仓库外的文件",只是一句话。真正能跑测试、能拒绝越界、能把错误交回模型的,是 Agent 的运行环境。

    看一个最小的例子。CS146S 2026 年第一课用不到 200 行 Python 写了个 Agent,能读文件、列目录、改文件。它的循环是:模型回一行 tool: 名字(参数),程序照做,把结果塞回对话,直到模型不再调工具。

    2026/week01/materials/drive/2026-w01-s1-02__coding_agent_from_scratch.pyL161–188 · 打开原文
            while True:            assistant_resp = execute_llm_call(conversation)            tool_invocations = extract_tool_invocations(assistant_resp)            if not tool_invocations:                print(f"{ASSISTANT_COLOR}Assistant{RESET_COLOR}: {assistant_resp}")                conversation.append({                    "role": "assistant",                    "content": assistant_resp                })                break            print(f"{ASSISTANT_COLOR}Assistant{RESET_COLOR}: {assistant_resp}")            conversation.append({                "role": "assistant",                "content": assistant_resp            })            for name, args in tool_invocations:                tool = TOOL_REGISTRY[name]                resp = []                if name == "read_file":                    resp = tool(args.get("filename", "."))                elif name == "list_files":                    resp = tool(args.get("path", "."))                elif name == "edit_file":                    resp = tool(args.get("path", "."), args.get("old_str", ""), args.get("new_str", ""))                conversation.append({                    "role": "user",                    "content": f"tool_result({json.dumps(resp)})"                })

    讲原理够了。真拿来改仓库,运行环境还缺这些:

    缺什么依据影响哪步一般怎么补 建议
    没法跑命令和测试读码只有读、列、改三个工具(L96–100)验证给一个受控的跑命令工具,把测试结果交回模型
    不限制路径实测../、绝对路径、~、指向外面的链接都能用(见下表)修改检查路径还在仓库里,再加沙箱
    覆盖了文件,却说是"新建"实测文件已存在也会被整个覆盖,返回的还是 created_file(L77–82)交付分清新建和覆盖,如实报告
    一出错就整个崩掉实测调不存在的工具(KeyError)、读不存在的文件(FileNotFoundError),程序直接退出;L176–184 没处理错误修正把错误当结果交回模型,让它自己改
    没有次数和花费上限读码循环是 while True(L161),只限了单次输出长度(L143)全程限制轮数、花费、时间
    不经批准就写入读码写文件立刻生效(L78、L90)修改危险操作先让人批准

    路径实验

    2026/week01/materials/drive/2026-w01-s1-02__coding_agent_from_scratch.pyL28–32 · 打开原文
    def resolve_abs_path(path_str: str) -> Path:    path = Path(path_str).expanduser()    if not path.is_absolute():        path = (Path.cwd() / path).resolve()    return path

    实测把这个函数原样拿出来,和加了检查的版本比一比(path_boundary.py):

    Agent 给的路径课程函数解析到加检查后
    notes.md仓库里放行
    ../secret.txt仓库外拒绝
    /etc/hosts仓库外拒绝
    ~/.ssh/config仓库外拒绝
    link(仓库里的链接,指向外面)仓库外拒绝
    sub/../notes.md仓库里放行
    示例补丁(不是课程代码,跑过 path_boundary.py)Python 3.9+
    def resolve_in_repo(path_str: str, root: Path) -> Path:    root = root.resolve()    candidate = Path(path_str).expanduser()    if not candidate.is_absolute():        candidate = root / candidate    resolved = candidate.resolve()          # 展开 .. 并跟随链接    if not resolved.is_relative_to(root):        raise OutsideRepoError(f"{path_str!r} resolves outside {root}")    return resolved

    另外三条"实测"来自 agent_functions.py:从课程代码里取出这几个函数原样运行,用写死的回复代替模型,没调用真模型。

    原则 ④

    交得明白:不看聊天,也能审、能撤回

    1. 理解
    2. 修改
    3. 验证
    4. 修正
    5. 交付

    Agent 做完了,你要决定收不收。你手上应该有这些,而不是一句"已完成":

    • 一件事一份改动:一个分支、一个 PR,出了问题能单独撤回。
    • 改了什么、为什么:问题是什么,怎么解决的。
    • 跑了什么、结果如何:命令和输出原样贴上。
    • 还有什么没做:取舍、限制、之后要补的。
    • 怎么撤回:有什么风险,出事怎么回退。

    CS146S 2025 年第 7 周作业对每个 PR 就是这么要求的,还要人逐行看过改动,再拿 AI 审查的意见和自己的比。

    报告本身也得是真的。原则 ③ 里那个教学 Agent,覆盖了一个已有文件,返回的却是"新建"(created_file)。实测工具报错了动作,后面的人就会看错改动。

    五 · 规范

    六样东西,每样的规范

    前面讲的是道理,这一章是查阅用的清单。每样分三块:必须写清什么、怎么算合格、常见问题。括号里是出处。规范是讲义根据课程作业整理的,不是统一标准。

    任务规格要做什么?做到哪算完?管:理解放在:Issue、任务单(比如 docs/TASKS.md)、设计文档
    必须写清
    • 要的效果:写用户看得到的行为。写"搜索不分大小写",别写"优化搜索"。(TASKS L9)
    • 范围:会改哪些文件,哪些不碰。(设计文档模板 L58–60:只能改列出的文件)
    • 限制:性能、安全、兼容这类要求。(模板 L15–19)
    • 验收:用哪些测试或命令判断完成,包括"不该发生什么"。(模板 L79–89)
    • 边界情况:空输入、大小写、搜不到时怎么办。
    怎么算合格

    把任务单单独交给一个新会话。它不用问你,就能说出要改哪几个文件、跑哪条命令来证明完成。

    常见问题
    • 只有目标,没有验收标准。
    • 边界情况没写,测试就没法判对错(原则 ② 里的空查询)。
    项目上下文代码在哪?有什么规矩?管:理解放在:根目录的 AGENTS.md 或 CLAUDE.md。大仓库可以在子目录再放一份,离被改文件最近的那份优先(AGENTS.md 官方说明)
    必须写清(2026 W4 作业 L50–54 的五块)
    • 项目是什么:一两句,让 Agent 知道是哪个领域。
    • 结构:关键目录、入口、各部分怎么连起来。
    • 命令:构建、测试、检查、运行,能直接复制(细节归"执行入口")。
    • 规矩:这个仓库实际在用的测试写法、代码风格、命名。
    • 禁区:不能手改的文件,容易用错的命令或目录。
    怎么算合格
    • 每句都只对这个仓库成立,一页左右。(L56)
    • 拿两个真任务试过:Agent 确实用了里面的命令、守了里面的规矩。(L58–62)
    常见问题
    • "请写高质量代码"这类空话;照抄 README。
    • 写了没验证过的话(原则 ① 练习里"完全隔离"那句)。
    • 只写"不要做 X",却没有东西真拦。那属于操作边界。
    执行入口用什么命令跑?管:验证放在:Makefile、package.json 里的 scripts、scripts/ 目录、依赖文件
    必须写清
    • 安装、启动、测试、检查、格式化,各有一条命令。(2025 W4 Makefile L3–17)
    • 在哪个目录运行。(2025 W4 作业 L59、L71)
    • 需要的环境变量、数据和前置步骤,比如先灌初始数据。
    • 命令可以重复跑,不会把环境弄乱。(2025 W4 作业 L105:"prefer idempotent steps")
    怎么算合格

    在一台干净的机器上照抄就能跑通。失败时命令返回非 0,报错看得懂。

    常见问题
    • 写"运行测试",不写具体命令。作业原话:要写 pixi run pytest tests/,不要写 "run the tests"。(2026 W4 作业 L52)
    • 命令依赖一个没写下来的前置步骤。
    质量反馈写错了能发现吗?管:验证、修正放在:tests/、类型检查、lint、CI
    必须做到
    • 每条需求至少一条测试,既测"该有的有",也测"不该有的没有"。
    • 覆盖边界情况:大小写、空输入、搜不到。
    • 测试数据和开发数据分开。(conftest.py 换成了临时库,但看原则 ① 练习的第五句)
    • 失败时看得出哪条错、为什么错。
    • 新功能先写一个会失败的测试,再实现。(2025 W4 作业 L115 的例子)
    怎么算合格

    故意写错一处(像小实验那样),至少一条测试会失败。

    常见问题
    • 只查状态码和"结果不为空"。(test_notes.py L13–19)
    • 结果依赖数据库的特殊行为,自己却不知道(SQLite 的大小写)。
    • 没测"不该发生"的情况。2026 W3 作业专门要求测一个近似但不该触发的提示词。(L67)
    操作边界哪里不能碰?谁来拦?管:修改放在:运行环境:权限设置、沙箱、钩子(hooks)、CI 权限。文档里只能写说明,拦不住
    必须做到
    • 能写的目录有范围,超出就拒绝。
    • 密钥不进仓库,Agent 默认拿不到。
    • 删除、强推、发布、对外发消息这类操作,要人批准。
    • 轮数、花费、时间有上限。
    • 工具出错时,把错误交回模型,而不是整个崩掉。
    怎么算合格

    真去试一次:让 Agent 写仓库外的文件、读密钥、做没批准的操作,看会不会被拒(原则 ③ 的路径实验)。

    常见问题
    • 只在 AGENTS.md 里写"不要……",没有任何机制真拦。
    • 只限制了路径,命令和网络照样随便用。
    • 课程教学 Agent 这几项都没有,是反面例子。(L28–32、L67–94)
    交付证据交什么给人看?管:交付放在:分支、commit、PR 说明、测试输出
    必须写清(2025 W7 作业 L16–22)
    • 一件事一个分支、一个 PR。(L16)
    • 改了什么、为什么这样改。(L20)
    • 跑了哪些命令、结果是什么,贴上输出。(L21)
    • 取舍、限制、之后还要做的。(L22)
    • 怎么撤回、有什么风险。(2025 W4 作业 L147)
    • 有人逐行看过改动。(W7 L18)
    怎么算合格

    审的人不看聊天记录,也能判断能不能合并;任何一个改动都能单独撤回。

    常见问题
    • 只写"已完成,测试通过",不给命令和结果。
    • 一个 PR 混了好几件事,没法单独撤回。
    六 · 落地

    从哪开始:看症状,补一样

    别一上来就把六样全写一遍。先看你最常遇到哪种情况:

    你遇到的情况先补对应原则
    做出来的不是你要的任务规格① 写清楚
    每次都要重新讲目录和规矩项目上下文① 写清楚
    命令老猜错,跑不起来执行入口① 写清楚
    测试全过,还是有 bug质量反馈② 查得出
    改到不该改的地方操作边界③ 拦得住
    看不懂它交的活,不敢合并交付证据④ 交得明白

    拿你自己的一个仓库,对照第五章的规范逐项看:哪样已经有,哪样只写在文字里、没有东西真拦,哪样完全没有。

    补完之后,做一次交接演练

    1. 挑三个真实小任务,比如修一个 bug、加一个小功能、改一页文档。每个写清:目标、范围、不做什么、用什么命令验收。
    2. 开一个新会话,只给任务单,不额外解释。
    3. 记下:Agent 找没找对地方、用没用仓库里的命令、你插手了几次、交活时附了什么证据。
    4. 检查结果,记下漏掉的错和返工花的时间。
    5. 每次只改一处(命令、限制、测试或需求),用同样三个任务再跑一遍,前后对比。
    看什么怎么记说明什么
    完成率验收命令通过的任务占几成仓库能不能撑起 Agent 独立干活
    人工插手每个任务你补充或纠正了几次还有哪些知识只在你脑子里
    漏掉的错审查时或事后才发现的问题测试和验收够不够严
    返工成本返工花的时间,或被撤回的改动数改动够不够小、好审、好撤
    自测

    五道题,看看学会没有

    1. 为什么规矩要写进仓库,不能每次在聊天里讲?

      看答案

      新会话默认看不到上次的聊天,靠聊天传的规矩每次都会丢。写进仓库的东西每个会话都能读到,还有版本、能审、能撤回(第一章)。

    2. 哪条检查能分出"搜索正常"和"不管搜什么都返回全部"?

      1. assert r.status_code == 200
      2. assert len(items) >= 1
      3. 结果里没有无关的笔记
      看答案

      C。A 和 B 两种实现都满足。只有检查"不该出现的没出现",才能抓住它,就是小实验里的 ②(原则 ②)。

    3. 提示词里写"只能改仓库里的文件",能拦住教学 Agent 写 ../secret.txt 吗?

      看答案

      拦不住。路径函数照单全收,改文件的函数直接写。得在运行环境里检查路径,或者放进沙箱(原则 ③)。

    4. 仓库里有 AGENTS.md,测试全过,就算 AI-native 了吗?

      看答案

      不一定。要看新开的 Agent 能不能只靠仓库走完五步,并交出你能核对的证据。AGENTS.md 只是指路,测试还得抓得住错(第二章、原则 ②)。

    5. 改了 AGENTS.md,怎么知道有没有用?

      看答案

      拿同一组真实任务前后各跑一次,模型、版本、工具不变,比完成率、插手次数、漏掉的错和返工成本。也看 Agent 有没有用文件里写的命令、守里面的规矩(第六章)。

    依据和局限

    这份讲义靠什么说话

    读码看过的代码

    页面里的代码按行原样摘自课程公开仓库的固定提交(2025:ca2df55,2026:a6dcbf2)和课程公开的 Google Drive 文件,行号就是原文行号。点代码块右上角能打开原文。

    实测跑过的

    • search_mutants.py:四版搜索在新旧测试下的结果,以及 LIKE 的大小写和通配符规则。
    • path_boundary.py:课程路径函数和加检查版本的对比。
    • agent_functions.py:从课程代码取出工具函数和循环,用写死的回复驱动。
    • 环境:Python 3.14.6 自带库、SQLite 3.53.3,2026-10-26。输出都在 results.txt。

    推断没跑过、靠推的

    • 课程测试会在 data/app.db 不存在时新建它并灌数据:依据 conftest.py L36、main.py L21–24、db.py L43–56 和 FastAPI 文档。
    • 课程搜索放到 PostgreSQL 会分大小写:依据 PostgreSQL 文档,没在 PostgreSQL 上跑。

    没做的

    • 没跑课程的 FastAPI 应用和测试:本机缺依赖,沙箱挡住了下载。
    • 没调用模型,没用真 Agent 做交接演练。
    • 没有教学效果数据。"建议"是看法,不是实验结论。

    来源