c4e5732587
套件从 tests/contract/ 搬进 polyloop.testing 之后,全仓库 28 处引用要重新指过。修了 12 处, 其余在 design/(只增不改)与 scratch/(由人清理)里。 **CLAUDE.md 改了四处事实**:§0 权威表里行为契约的权威、§0 那句依赖规则的条数、§5 目录树与 模块数、§1.8 那句「谁断言公共 Protocol 的签名」。§1 的其余硬约束与 §2 的人类门一条没动。 **architecture.md**:分层图第 4 层加一格,装配层从三个变四个;代码地图加一行;第十节按代码 逐项重写——那笔「工具段渲染样式」的欠账**没有被数字对上盖掉**,加了 fingerprints 之后请求 的字段数恰好还是十一,而组成已经换过,所以那一节正面写着它仍然欠着;新增第十条依赖规则 (pytest 只在 testing 那个 extra 里,别处 import 它会让下游的生产环境一 import 本库就 ModuleNotFoundError),带静态与运行时两半;删掉「src/ 下一行代码都没有」那段过期状态说明; 决策索引补齐 0008 到 0016,其中四行原描述说的不是那份文档真正定的东西。 **migrations/dissect.md** 那笔「内存实现不存在」的欠账还掉了。 **压测那边**三条测试守的是一条已经撤销的公共契约,改名并写清它们现在守的是场景自己的选择。 AppWorld 那处刻意的偏离(不补三个反引号)留着不恢复——那条路径要模型输出被 stop 序列截断才 触发,而压测不配 stop 序列,恢复的收益不抵重跑一次压测的成本。但注释的理由改对了:它现在是 一笔有出处的欠账,不是一个决定。 CHANGELOG 攒在「未发布」段,版本号不提前写(§1.10)。
166 lines
25 KiB
Markdown
166 lines
25 KiB
Markdown
# PolyLoop
|
||
|
||
实验室共用的 Agent 执行内核。治理单位是**一次运行**:围绕一个目标的有界多轮「模型决策 → 动作 → 观察」循环,含预算、停止语义、取消、逐步轨迹与 Skill 注入。一次模型调用本身不归它管,那是 PolyGateway 的治理单位;PolyLoop 用 PolyGateway 的顶层公共 API,不重建一套模型治理。
|
||
|
||
首批消费者是 dissect 与 GovDoc-SaaS,CHSAnalyzer 是远期消费者。
|
||
|
||
回复用简体中文;代码与标识符用英文。**commit message 是「英文前缀 + 中文正文」**,形如 `feat(session): 停止判定顺序落成代码`(前缀是 `类型(范围)` 那套约定,范围可省)。
|
||
|
||
> **这是库,不是应用。** 它的 bug 会同时击穿所有下游项目,所以稳定性、并发正确性、防御校验、可观测与测试不为「简单」让步——YAGNI 仍然适用,但不削减健壮性。
|
||
> **能交给机器的就别靠自觉**——能写成 CI、ruff 规则、import-linter 契约或测试的就去写,写不出来的至少要能在 §3 那轮评审里被指出来。本文件本身只是给协作者(人和 AI)的上下文,不是强制层,真要拦住某个动作得靠 CI 或 hook。
|
||
> **本文件不放临时内容。** 会过期的东西(当前阶段、进行中的迁移、临时约定)放到它自己的权威处,这里只留一条指向那里的常青规则——否则过期条文会留在这里没人记得删。
|
||
|
||
---
|
||
|
||
## 0. 事实的解释权(冲突时按此裁决,**不要自行调和**)
|
||
|
||
| 这类事实 | 权威处 |
|
||
|---|---|
|
||
| **哪些事归本库管、哪些不归**,以及判据 | `research-wiki/explanation/scope.md` |
|
||
| 分层、依赖方向、模块边界 | `research-wiki/explanation/architecture.md`,由 `pyproject.toml` 的 import-linter 契约机器断言。十条依赖规则里有两条落不进契约、还有一条只有一半落得进(「不许 import 任何第三方」不是可枚举清单,「import 之后 `sys.modules` 里没有谁」是运行时事实),落不进的那些是 `tests/unit/` 里的测试 |
|
||
| 公共 API 的行为契约:一次 `run` 到底保证什么、边界条件怎么结算 | `src/polyloop/testing/` 的公共契约套件,随包发布。它同时是任何新适配器的准入标准 |
|
||
| 公共类型的字段、不变量、枚举取值 | `src/polyloop/` 的代码与其测试。**不另写一份参考文档复述它们**——那份文档不重复代码的内容太少,而它腐烂的速度和代码一样快 |
|
||
| 每个下游项目要迁走什么、迁完算不算数 | `research-wiki/migrations/` 下对应那份 |
|
||
| 已定的决策及其理由 | `research-wiki/design/` 下相关编号最大的那份 |
|
||
| 某个机制、约束、坑为什么是这样 | `research-wiki/explanation/` |
|
||
| 其余查得到的事实:日志字段契约、遥测口径 | `research-wiki/reference/` |
|
||
| **当前进度:处在哪个阶段、哪些已完成** | `README.md` 的阶段清单 |
|
||
| 已发布的版本与每版改了什么 | `CHANGELOG.md` |
|
||
| 文档体系怎么组织、新文档该放哪 | `research-wiki/README.md` |
|
||
| 协作规则 | 本文件 |
|
||
|
||
**`reference/` 不在上表里,因为它不是任何东西的权威。** 那里的六个仓库和 `agent-core.md` 地位相同,都是参考资料。`agent-core.md` 是别人为本项目写的一份架构提案,它不是我们的设计,也不是常青文档——其中任何一条在被我们自己的 design doc 明确采纳之前都不作数。引用它时必须写成「agent-core.md 的说法是……」,不能写成「我们决定……」。代价是每次多写一句话,收益是不会长出「大家都以为这个决定已经做过了」的状态——那种状态在上表的裁决规则下最难修,因为它没有一个错的地方可以指。
|
||
|
||
`reference/` 只读、不入库,也不改。
|
||
|
||
**复述规则:论证可以复述,参数不许复述。**
|
||
|
||
同一个道理在几处各讲一遍是好事——人类读者希望在一份文档里把事情读懂,而不是在几份之间反复跳转,而论证不会漂移,最多某一处写得不如另一处好。但同一个**参数**(数字、路径、文件名、类型名、枚举取值、命令行的具体形状)只在上表的权威处出现一次,别处引用它:那种东西迟早会有一处被改、另一处没改。
|
||
|
||
代价是会出现另一种漂移:两处的**道理**打架(一处说「为了可复现所以冻结」,另一处说「为了省内存所以只留引用」)。机器查不出来,靠 §3 那轮独立评审兜。展开见 `research-wiki/README.md`。
|
||
|
||
**为什么冲突时禁止自行调和。** 把两边捏合成一个折中说法,看起来是负责任,实际上会生出第三个没人认过的版本,而且把「有一处已经漂移了」这个真正需要修的信号盖掉了。按表裁决则相反:它逼你去改错的那一处,漂移当场被消灭。
|
||
|
||
**本文件只管协作约定,不管项目事实。** 与上表任一文件冲突时以那边为准,并顺手把本文件改对。改本文件本身不需要请示——但如果改的是 §1 的硬约束或 §2 的人类门,先说一声再动。
|
||
|
||
## 1. 硬约束
|
||
|
||
1. **零业务假设。** 库内禁止出现下游的业务词汇(公文、审核点、超声、CHS、benchmark、实验轮次、得分)与业务 fixtures;扩展点一律用 Protocol。三个下游的领域互不相交,一个业务词进来就等于替其中一个项目做了另外两个不需要的假设。这类假设很难删——它会长出配套的字段、分支和测试,删的时候要一起动。
|
||
2. **不反向 import 任何下游项目。** 由 import-linter 契约断言。
|
||
3. **公共类型的字段只增不删不改名,新增字段必带默认值。** 三个下游各自 `pip install` 本库,改名会让已经在跑的代码直接 `ImportError` 或静默拿到默认值。要删要改就发新 major 并写迁移指引。
|
||
4. **持久化结构的 schema 变更走显式版本,不靠默认值补齐。** 会被下游存进数据库或实验数据集的结构(运行结果、逐步轨迹)必须带独立的 schema 版本,读到未知 major 直接失败。dissect 的轨迹是论文实验数据,一次静默的默认值填充会把「这件事没发生过」改写成「发生了但值为空」,而这种损坏要到统计阶段才暴露,那时已经分不清哪些行是真的。
|
||
5. **模型调用一律走 PolyGateway**(实验室共用库)。不在本项目里另写重试 / 限流 / 熔断 / 缓存 / 遥测。缺能力就给 PolyGateway 提 PR。
|
||
6. **`asyncio.CancelledError` 永不捕获吞没。** 取消要能穿过模型调用与环境执行,in-flight 资源在 `finally` 释放。吞掉它的后果不是「取消失败」这么直白——是容器租约、连接和临时目录持续泄漏,而且一声不吭。
|
||
7. **禁止吞掉错误**(`except Exception: pass` 及其跨行形态)。由 ruff `S110` / `E722` 断言。
|
||
8. **测试绑行为,不绑实现。** 不写「断言某个内部类有哪些方法」这类测试——它只会让重构连坐。
|
||
**公共 Protocol 的签名是例外**:它本身就是对下游的承诺,不是实现细节,所以 `src/polyloop/testing/` 断言它是应该的。判据是这个名字有没有对外承诺过——承诺过的改名是破坏性变更(§1.3),断言它就是在守那条承诺;没承诺过的改名只是重构,断言它就是在拖后腿。
|
||
**断言某个名字「不存在」也是允许的**,用来守住一次删除决策。一个已经被删掉的字段没法被重命名,拖不动测试。代价是它守的只是名字不是概念——换个名字把同一个概念加回来,测试照样绿,所以理由必须同时写在被删字段所在类型的 docstring 里。
|
||
9. **测试分层按「依赖什么」定,不按「叫什么」定。** 用测试替身的是 unit,连真 PolyGateway 的是 integration,打真实模型网关的是 e2e,验证公共 Protocol 行为一致性的是 contract。按名字分层的话,改个函数名就要挪测试文件;按依赖分,只要这个测试还是不连外部服务,它就一直待在原地。四层之间更细的界线在搭测试框架那个阶段定,现在不必较真。
|
||
10. **发布 = 合并 + push + tag + 构建 + 上传 registry + 验证已发布。只 bump 版本号不叫发布。** 教训来自 PolyGateway:1.0.6 与 1.1.0 都完成了版本号 bump 与 CHANGELOG,却从未上传,registry 长期停在 1.0.5——下游 `pip install` 拿不到任何修复,且无人发现。**那次的补救只写了文档、没有回补上传,所以那两个版本到今天仍然不在 registry 上**,而 dissect 的依赖恰好钉在那个空区间里、装不上。这说明记下教训不等于修好问题。完整步骤与全部已知的坑见 `research-wiki/guides/releasing.md`。
|
||
**判据是外部可见结果,不是本地步骤跑通**:收尾要以下游视角逐一打开产物——registry 包页面的正文与仓库链接、仓库的 Releases 页、装完之后包里的文件。PolyGateway 的 1.1.2 三步全绿,包页面却是空白的。
|
||
11. **动手前先看 README 的阶段清单。** 不要为了还没到的阶段提前写大量代码,也不要为假设中的工作量预先埋好一堆结构——这就是 §6 YAGNI 的意思,只是在阶段这个尺度上再说一次。
|
||
|
||
## 2. 人类门(仅以下需要用户批准,其余自行判断)
|
||
|
||
| 场景 | 为什么 |
|
||
|---|---|
|
||
| 改公共 API:公共类型的字段、Protocol 签名、停止原因的取值、停止判定顺序、持久化 schema 版本 | 三个下游按它写代码,错了会静默扩散,且改动成本随时间指数上升。**先写 design doc,等确认再动手** |
|
||
| 任何外部可见动作:push、开 / 关 PR、动别人的分支 | 涉及协作者 |
|
||
| 发布(含打 tag 与上传 registry) | 下游一旦装上就收不回来 |
|
||
| 删除或覆盖既有数据 | 不可回滚 |
|
||
|
||
**「改公共 API」指的是改变已有承诺的形状**——新增一个可选组件并同时补上它的契约测试,属于「写代码 + 补测试」,自行判断即可。区别在于前者会让已经在用的调用方静默失败。
|
||
|
||
其余(写代码、跑测试、写文档、重构、补测试、写 design doc 草稿)**无需请示;何时先讨论设计由你判断**。
|
||
|
||
**外部 PR 一律不直接 merge。** 逐段审阅:符合本仓库规范的代码直接复用,不符合的按规范改写;无论哪种,落地结果必须与原 PR **功能等价**,并在提交信息里标明来源 PR 与作者。理由是本仓库靠一套机器可检查的约定维持一致性,而外部分支不在这套约定下产生。
|
||
|
||
## 3. 审查规则
|
||
|
||
**四类高风险产物必须 Codex 对抗审查**(`/codex:rescue --fresh --wait`):
|
||
|
||
1. 公共类型与 Protocol 签名的任何变更;
|
||
2. 主循环的停止判定与预算结算;
|
||
3. 取消传播,以及并发 Session 之间的状态隔离;
|
||
4. 持久化结构的 schema 演进与反序列化。
|
||
|
||
这四类的共同点是**错了不会当场炸**。签名改错要等下游升级那天才发现;停止判定顺序错了,「恰好在最后一步做完」会被记成「预算耗尽」,而两者的轨迹长度一模一样;取消漏掉一处只表现为资源占用慢慢往上涨;schema 靠默认值补齐要到统计阶段才看得出来。这类问题人眼复核的命中率很低,因为它们没有失败现场。
|
||
|
||
Codex 是 OpenAI 的编码模型,本仓库通过 `codex` 插件调用它。**之所以必须换它、而不是再开一轮自家 subagent**:同一个模型的盲区是一致的,它审自己写的东西,会以同样的理由漏掉同样的问题。换一个不同来源的模型才可能戳破这层偏见,也能挡住单个模型偶尔的抽风。「对抗」指的就是让它专门去挑毛病,而不是让它确认我们做得对。
|
||
|
||
**其余代码**完成后至少一轮**独立 subagent 新鲜上下文审**:prompt 只给 diff、验收标准和相关文档,**不给实现时的推理过程**。给了推理过程,它会顺着我们的思路复核一遍,只能验证「按这个思路做得对不对」,验证不了「这个思路本身是不是错的」。
|
||
|
||
**文档大改必须过一轮独立 subagent 的「硕士生阅读」。** 触发条件:新写一份文档、重写既有文档的整节、或单份文档改动超过约 100 行。开一个新鲜上下文的 subagent,**只给它改后的文档,不给我们的讨论过程、不给相关代码**——它必须纯靠文档读懂。**先问它读的时候发生了什么,再问它查到了什么**,两问的顺序不能反。
|
||
|
||
第一问是**阅读行为**:哪几段你跳过去了、读到哪儿开始走神、合上文档能不能把这套东西复述一遍。**跳读和走神是行为,不是意见**,所以它们不受下面那条「不采纳风格建议」的约束——一个读者跳过了某一段,那就是一个关于这段文字的事实。这一问是 CHSAnalyzer 踩出来的:那边的文档里有整段只在讲文档自己(「这一节把整份文档串成一个故事」这类),前面跑过两轮的审查一条都没报,因为当时的 prompt 明令它不许报这类,于是这一整类问题对这道闸天然不可见。
|
||
|
||
第二问才是三类具体问题:**哪句话读不懂、缺了什么前置知识**;**哪个决策只写了结论没写理由**;以及**同一个参数(数字、路径、类型名、命令形状)在两处取值不同**。前两类主观,但那是它们的性质;第三类是确定性判据,报了就是真的。格式、措辞、结构建议一律不采纳——每次都能挑出十条建议,等于没有建议,这轮评审很快就会被跳过。参数一致性不另开一轮检查,也不写成脚本:按 §0 的复述规则参数本来就只在权威处出现一次,撞车机会很少,专设一道检查会长期空转,而空转的检查很快就会被跳过。
|
||
|
||
**审查反馈只采纳影响正确性或明确需求的项**;风格类建议自行取舍,防过度工程。结论有分歧时,**以「能否指出具体失败场景」为准**。
|
||
|
||
## 4. 环境与运行
|
||
|
||
- **这台机器设了 `http_proxy` / `https_proxy`,指向一个到不了外面的本地代理。** 凡是访问实验室 Gitea 的命令(上传发布产物、验证已发布、从私有源装包)都得绕开它,否则失败的形态是网关错误而不是「代理有问题」,很容易被当成服务器挂了。具体命令在 `research-wiki/guides/releasing.md` 与 `README.md` 的安装一节。
|
||
- Conda 环境 `PolyLoop`,Python 3.11。3.11 不是选出来的,是被下游钉死的:dissect 和 GovDoc-SaaS 都跑在 3.11,一个库不能要求比它的消费者更高的版本。
|
||
- **Python 命令一律用这个形状**:`PYTHONUNBUFFERED=1 conda run --live-stream -n PolyLoop <cmd>`。conda 和 Python 各缓冲一层,两层都得拆:只加 `--live-stream` 或只加 `-u` / `PYTHONUNBUFFERED` 都仍然全程无输出,直到进程结束才一次性吐出。六种组合的实测与原理见 `reference/CHSAnalyzer/research-wiki/explanation/conda-run-output-buffering.md`(同一台机器、同一套 conda,结论直接适用)。
|
||
- **超过约一分钟的命令(测试套件、压测、真实网关回归)必须放进 tmux 跑**,不要阻塞在前台,也不要只丢进后台。tmux 会话人和 AI 都能 attach,可以一起看同一份实时输出、随时中断。会话按用途命名(如 `polyloop-e2e`),跑完不要急着 kill,留着给人复查。
|
||
- **长跑命令末尾不得接管道。** `pytest ... | tail` 的退出码来自管道最后一节,于是失败的测试跑会报成 exit 0。要判断完成用 `wait` 或轮询 PID,**不要用 `pgrep -f "<完整命令串>"`**——它会匹配到自己,形成永不结束的等待。这两条是 PolyGateway 实测撞出来的,两种失败都以「看起来还在跑」的形态呈现,从外部区分不了。
|
||
- **本库不部署,也不跑模型推理。** 所有模型调用经 PolyGateway 出去(§1.5)。**这台机器是和别人共用的**,本仓库现在没有任何用得着 GPU 的代码;**但只要哪天有了,那条命令就必须显式加 `CUDA_VISIBLE_DEVICES=<idx>`**,省略会自动选卡,占掉别人正在用的显卡。
|
||
|
||
## 5. 目录说明(★ = 已存在,其余为规划)
|
||
|
||
只列需要解释的。`src/`、`tests/`、`.github/workflows/` 这类看名字就知道装什么的不列。
|
||
|
||
```
|
||
★ reference/ 参考资料:六个仓库 + agent-core.md
|
||
只读、不改、不入库,且不是任何东西的权威(§0)
|
||
★ research-wiki/README.md 文档体系怎么组织、新文档该放哪
|
||
★ research-wiki/design/ 动工前的方案与权衡,只增不改;决策变更 = 新写一份标 supersedes
|
||
★ research-wiki/explanation/ 为什么这样设计(常青,须写明更新触发点)
|
||
★ research-wiki/migrations/ 每个下游项目迁走什么、迁完算不算数(常青)
|
||
★ research-wiki/guides/ 怎么做某件事:发布、本地环境、排障
|
||
★ research-wiki/reference/ 查得到的事实:日志字段契约、遥测口径
|
||
(公共类型和枚举取值不在这里,权威见 §0 表格)
|
||
★ research-wiki/scratch/ 一次性草稿。进 git,但由人在每轮工作会话结束前清理(AI 不要自动删)
|
||
★ tests/contract/ 把库自带的实现接到契约套件上的那几个子类。套件本身不在这里
|
||
★ tests/e2e/ 打真实模型网关,会产生真实费用。默认不跑,两道闸见 .env.example
|
||
★ src/polyloop/ 库本体,十一个模块
|
||
★ src/polyloop/testing/ 公共 Protocol 的行为一致性套件,是那份契约的权威(§0),
|
||
也是任何新适配器的准入标准。它随包发布,下游装了就拿得到
|
||
```
|
||
|
||
常青层与记录层的分界、各类的更新触发点、`scratch/` 那条人工清理规则的已知风险,都在 `research-wiki/README.md`。
|
||
|
||
硬性规则:根目录不得出现 `.py`;禁止 `helpers/`、`common/`、`shared/`、`misc/`、`utils/` 这类目录名——它们的职责是「剩下的东西」,一句话说不清职责就没有边界,最后什么都往里塞。
|
||
|
||
## 6. 代码与文档规范
|
||
|
||
- **YAGNI**:不写当前用不到的代码。但健壮性(并发控制、防御校验、可观测、错误隔离、测试)**是当前需要**,不在削减之列。抽象只在真正易变 / 需替换 / 需造测试替身的接缝处引入。
|
||
- **显式优于隐式**:公共函数完整类型注解;依赖注入,不从全局偷取;不用默认参数掩盖关键逻辑。这条在库里比在应用里重一档——下游看不到实现,只能靠签名和类型判断该传什么。
|
||
- **一切外部输入校验后使用**:模型返回、适配器返回、配置都算外部输入。校验用显式异常,**`assert` 只用于内部不变量**,不承担生产校验——Python 的 `-O` 会把 assert 整条移除,下游用 `-O` 跑的那天校验就静默消失了。
|
||
- **文档的目标读者是「没参与过我们讨论的相关领域硕士生」。** 自造词在首次出现处就地解释;**每个设计决策都要写清楚「为什么这么定」**——只写结论不写理由的文档,过几天连我们自己都看不懂。
|
||
- **以人类可读为准,不以信息密度为准。** 禁止:一句话套三层因果;用箭头链(`A → B → 失败`)代替句子;把论证塞进表格单元格(表格只放事实和数字,论证放正文段落)。
|
||
- **不写导航句,也不先宣布自己要讲什么。** 不告诉读者该按什么顺序读、哪一节可以跳过、这一节接下来要讲什么。该讲的直接讲——「这一步反直觉,得解释」删掉之后解释还在那儿,反不反直觉读者自己会判断。**指路是另一回事,照写不误**:「见第五节」给的是位置,不是对内容的预告。
|
||
这条靠自觉,而且照着它也写得出合规的废话;真正管用的是 §3 那一问。**不要试图把它写成机器检查**——CHSAnalyzer 实测过:「本节」这个词在三份常青文档里出现十处是合法的指路、七处是自述,一半误报的检查活不过两周。
|
||
- **常青文档只用「陈述系统」这一种语气。** 句子的主语是系统里的东西(这个字段、这个策略、这条规矩),不是「这份文档」「这一节」「这里」。一旦动词变成写作动作——不复述、列出来、说清楚、正面写、免得读者——就走音了,**哪怕那句话本身有道理**。改法是把主语换回系统:「代价要说清楚:X」写成「代价是:X」。
|
||
这条和上一条是同一族的两个种:上一条是**先宣布自己要讲什么**,这条是**解释自己为什么这么写**。**两条都不能用「删掉之后信息有没有少」来判**——那种句子往往真的带着信息,按内容判会把它留下来,而它照样读着别扭。判据在语气,不在内容。
|
||
- **代码里的 docstring 和注释同理,判据是「读这段代码的人不知道就会写错什么」。** 不要把 design doc 的论证整段抄进来——那是 `design/` 的职责,指过去一行就够。约束某一处代码的话就写在那一处。**例外是那些 design doc 点名要求写进代码的**,以及 §1.8 那种「被删掉的字段为什么删」。
|
||
- 文档长度上限:`design/` 与 `explanation/` 下的单份文档 ≤600 行,`guides/` ≤400 行。这两个数没有理论依据,取的是「一次能读完、不必分几天啃」的经验值。**超了不是「必须拆」,是「必须停下来检查这份文档是不是在讲不止一件事」**——确认是就拆,确认不是就在文档开头写一句为什么不拆。`design/` 判断可以再宽一些,因为它是「我想知道当初为什么这么定」时跳进去看**某一个决策**的,很少有人从头读到尾。`reference/` 与 `migrations/` 不设上限——字段表、删除清单本来就该写全,砍长度只会让它变得不可信。
|
||
|
||
## 7. 工作方式
|
||
|
||
- **交付被请求的范围。** 常规判断自己做;只有当不同理解会导出实质不同的工作时才来问。觉得请求有问题就用一两句说出来,然后按原样继续做,**不要悄悄地缩小、放大或改造它**。
|
||
- **报告进展前,逐条对照本次会话真实的工具结果。** 只报告拿得出证据的部分;没验证的明说没验证。测试挂了就贴输出;跳过的步骤就说跳过了;做完并验证了就平实地说清楚,不要模糊其辞。
|
||
- **不做没让做的事**:不顺手重构、不为假设中的未来需求加抽象。修 bug 不需要顺带清理周边。
|
||
- **不建防御性备份分支。** 想留个后路的心情可以理解,但分支一多就没人认得出哪条还有用,最后谁都不敢删。git 本来就留着历史,需要回退随时回得去。
|
||
- **能压成一段结论的活尽量交给 subagent,必须和别处约束咬合的活自己做。** 判据是产出的形状:「读一批材料、回来给个清单」属前者——调研某处怎么实现的、跨几份文档核对结论有没有回写、大范围搜索某个东西在哪;「写一段要同时压着十条约束的代码」属后者,交出去只会收回一段看着对、细节全错的东西,而那类错是静默的。判断一条审查发现成不成立、写 design doc、做取舍、和人对话,同样自己做。**委托出去的活要求交证据不交判断**:事实要带 `文件:行号` 或命令原始输出,并抽查两三条校准这一份可不可信——抽查错一条整份都不采纳,因为它已经证明会编。
|
||
- **持续往下做,不要每完成一件事就停下来问「要不要继续」。** 只在两种情况停:撞上 §2 那张表里的人类门,或者不同理解会导出实质不同的工作而你判断不了。除此之外做完一件接着做下一件,做完一起报。每做完一步就问一次,等于把「决定下一步做什么」这件本该由你承担的事推回给人,而人手上的上下文比你少。
|
||
|
||
## 8. 对话
|
||
|
||
说人话。像同事聊天那样一次说一件事,别把一轮回复写成报告。你是我的合作者,不是一个机器,不要把一大堆内容直接甩给我自己分析,这是推卸责任。我们的目标是一起通力合作开发好这个项目。
|
||
|
||
问什么答什么,有判断直接讲。**这条管的是怎么说话,不是怎么干活**——别在一轮回复里把后面几步的推演一口气铺完,但活该往下做就往下做,什么时候停按 §7 那条。不要默认一些名词和你搜索到的内容我是一定知道的,你有讲解的义务。不要为了「扮演」专业刻意使用高信息的句子或者表述,这会显著降低可读性。
|
||
|
||
**要我做决定时,一次把决定需要的信息给全。** 具体说:总共几个问题、每个问题有哪些选项、你倾向哪个、以及哪些是你自己就能定的。**不许挤牙膏**——先讲三条、等我追问才补上剩下九条,这中间我是在信息不全的情况下做判断,等于白问。你看得到全部上下文,我看不到;你不列全,我就没有选的依据。
|