两轮法读懂大型仓库:先喂骨架出架构地图,再按点名文件补全文出调用链。
说明
免责声明:本页展示内容均为 AI 模型生成,仅供参考,不构成任何效果承诺;实际产出效果与 Credits 消耗以控制台「用量详情」为准。本篇以 CPython 3.13 的 asyncio 包(33 个模块 / 约 1.5 万行 / 519 KB)跑通两轮调研法:接手陌生仓库最费时的是先搞清它怎么跑起来,真实项目动辄几万行,一次塞不进去也不该塞,正确做法是先给结构骨架让模型指路、点名关键文件,再按它点名的文件补全文,第一轮输入只要十分之一。
调用链:qwen3.8-max(两轮调用)。(1) 只喂签名骨架(52 KB,约为原码 10%)让它出架构地图并点名文件 → (2) 按点名的文件喂全文,出精确调用链。
步骤一:只给骨架,出架构地图并点名文件
用 ast 遍历 *.py、只取类与函数签名和 docstring 首行、丢掉函数体,生成签名骨架,连同下面的指令一起发给 qwen3.8-max:
我接手维护一个 Python 项目,需要先摸清它的架构。这个包有 33 个模块、约 1.5 万行代码,太大没法一次全给你,所以我先给你**结构骨架**(只有类、函数签名和 docstring 首行,没有实现体)。
请基于骨架完成三件事:
一、架构分层
这个包在设计上分成哪几层?各层职责是什么?层与层之间靠什么协作?画一个简明的层次图(文字版)。
二、核心抽象与继承关系
找出这个包最重要的 5-8 个抽象(基类/协议/接口),说明:
- 每个抽象解决什么问题
- 它的主要子类有哪些、按什么维度分化(按平台?按 IO 机制?)
- 用缩进树的形式画出关键的继承关系
三、我该按什么顺序读,以及现在就要看哪几个文件
- 给一个阅读顺序(先读哪个模块、为什么)
- 然后**明确点名 3-5 个文件**,说你需要看它们的完整实现才能讲清核心运行机制。用这个格式单独列一行:
NEED_FILES: a.py, b.py, c.py
要求:
- 类名、方法名必须与骨架一致,不要臆造
- 你只看到了签名,凡是靠推测得出的结论请标注"(推测)"
- 不要复述骨架内容,要给出你的归纳
骨架如下:
【粘贴用 ast 生成的签名骨架】
步骤二:按点名文件补全文,出调用链
把模型点名的文件全文发回,让它基于真实代码画出核心调用链:
好,下面是你点名的文件的完整实现。请基于真实代码回答:
一、一条核心流程的完整调用链
挑「用 asyncio.run() 跑一个协程直到结束」这条最常用的路径,画出从入口到协程真正被执行的完整调用链。要求:
- 用真实的函数/方法名,标注它属于哪个类、哪个文件
- 每一步说明它做了什么关键动作
- 特别说清:事件循环是在哪一步真正开始转的、协程是怎么被包装成可调度对象的
二、事件循环的一次迭代里发生了什么
事件循环跑一圈,依次做哪几件事?按真实代码里的顺序列出,并指出这些动作分别在哪个方法里。
三、三个容易踩的实现细节
基于你读到的真实代码,指出三个使用者容易误解、但代码里其实有明确处理的点。每条要指明对应的代码位置。
要求:所有函数名、类名、属性名必须与给你的代码完全一致;凡是代码里没看到、靠常识补的,明确标注"(未在本次给出的文件中确认)"。
【粘贴它点名的那几个文件的全文】
查看实测产出 · asyncio 调研报告节选(qwen3.8-max)
【二、核心抽象与继承关系(轮 1 · 据骨架归纳)】
1) 事件循环 EventLoop —— 整个包的中枢,负责调度与 IO
AbstractEventLoop(events.py,抽象接口)
`- BaseEventLoop(base_events.py,通用实现)
`- BaseSelectorEventLoop(selector_events.py,基于 selector 的 IO)
`- _UnixSelectorEventLoop(unix_events.py,Unix 平台)
`- BaseProactorEventLoop(proactor_events.py,Windows IOCP)
—— 按「平台 + IO 机制」两个维度分化
2) Future / Task —— 把「未来才有的结果」和「协程的执行」统一成可等待对象
Future(futures.py)
`- Task(tasks.py,把协程驱动起来的那一层)
3) Transport / Protocol —— 一对搭档:Transport 管「怎么传字节」,
Protocol 管「收到字节做什么」,二者通过回调解耦
【一、asyncio.run() 跑一个协程直到结束的调用链(轮 2 · 据真实代码)】
asyncio.run(main) # runners.py(本轮未给,标注未确认)
`- BaseEventLoop.run_until_complete(future) # base_events.py
|- self._check_closed() 确认循环未关闭
|- self._check_running() 确认没有别的循环在跑
|- new_task = not futures.isfuture(future) 判断是否已是 Future
|- future = tasks.ensure_future(future,…) <-- 协程在这一步被包装成 Task
|- future._log_destroy_pending = False 抑制 destroy pending 警告
|- future.add_done_callback( 目标完成后停循环
| _run_until_complete_cb)
|- self.run_forever() <-- 事件循环从这里真正开始转
`- return future.result() 正常返回/重抛异常/抛 CancelledError
【三、三个容易踩的实现细节(模型主动指出)】
· Future = _CFuture = _asyncio.Future(futures.py 末尾)——运行时可能走 C 实现,
纯 Python 版仅在没有 C 扩展时作为回退
· call_soon 注册的回调不会立即执行,而是排到事件循环的下一轮
· 协程被包装成 Task 的时机是 ensure_future,不是 run 的那一刻
说明
- 消耗:本玩法涉及长上下文 + 深度思考(
qwen3.8-max)。两轮实测用量:轮 1 输入约 1.4 万 / 输出约 2.0 万(其中思考约 1.2 万);轮 2 输入约 7.0 万 / 输出约 2.3 万(思考约 1.5 万)。思考消耗普遍接近甚至超过正文输出,估算成本别只看报告字数。 - 两轮法省在哪:519 KB 源码直接进上下文约合十几万 token,而先喂 52 KB 骨架只花了约 1.4 万输入,第一轮点名文件后再补全文,比一次全塞省得多。
- 敏感信息:代码进上下文意味着内容会发送到服务端,含密钥、内网地址、客户数据的文件请先剔除或脱敏。
该文章对您有帮助吗?