|
|
a402bfd777
|
docs: 删除 7 份已完结的执行计划,把教训与数据提出来
## 为什么删
执行计划在实施完结后**会变成误导性读物**:它记录的是"当时打算做什么",
而读者会读成"现在是什么"。
这在本仓已经造成真实误读 —— `prod-migration-checklist.md` 写着
「状态:HologramAgent 已停机」,那是一次性迁移(2026-10-04)当场的状态,
但照着读会以为服务现在还停着。
## 删了 7 份,删前提取三类内容
| 删掉的文档 | 行数 |
|---|---|
| `memory-restructure-plan.md` | 168 |
| `memory-blockflow-repair-plan.md` | 450 |
| `memory-usability-plan.md` | 309 |
| `scene-memory-fix-plan.md` | 271 |
| `toolcall-parallel-execution-plan.md` | 578 |
| `prod-migration-checklist.md` | 157 |
| `entities-retirement-plan.md` | 118 |
**提取去向**:
1. **教训 → 新建 `engineering-lessons.md`**
这些是它们唯一还有长期价值的部分。汇总成一篇,并按形态归类:
- 判据类(5 条):结构判据不能替代质量判据 / 测「接线之后」≠测「有没有接线」/
验证通过≠架构正确 / fixture 照臆测字段编 / 先改代码再写测试
- 接线类(3 条):机制≠接线 / 依赖图是唯一保证顺序的地方 / 单数改了复数漏了
- 权限与生命周期(3 条):「接上了」有三层 / 以调用方名字为键的表要清理 /
提权口子:让调用方声明自己是谁
- 流程类(3 条):长任务纪律 / 数字要现场取 / 计划不进仓库
文末点出它们共同的形态:**某种"看起来对了"的信号与"真的对了"之间存在缺口。**
2. **实测数据 → 并入 `toolcall-contract-and-sequence-design.md` 附录 A**
那是新旧内核的对比压测(288 条输入 × 两版),核心结论值得留:
```
场景 旧版中位/工具数 新版中位/工具数
slowbatch8 0.220s / 0 个 0.409s / 8 个
```
★ **旧版"更快"是假的** —— 它的 `openai.lua` 缺 `stream_index` 透传,
多个分片并到槽 0 ⇒ 每个工具报参数错误而一个都没真跑。
这是「只看耗时会被骗」的典型。
另附 stage 锁告警的完整归因(不是内核缺陷,成因在插件进程侧运行时)。
3. **未完成的项 → `future-plan.md` §六**
尤其 `entities-retirement-plan` 那条:方案是"三表全退",但 2026-10-31
实测生产库 `entities 1292 / relations 978 / sentences 66` 行**仍在用**。
这个事实不能随文档一起消失。
## 保留两份(它们不是计划,是依据)
- `legacy-table-retirement.md` —— 被 **4 处生产代码注释**引用(`graph.go` ×2、
`commit_blocks_test.go`、`probe_prod_test.go`),是退役判断的依据
- `interrupt-subsystem-split-plan.md` —— 探测事实被 `interrupt_invariant_test.go`
引用;拆分本身确实未实施
## 索引重写
`docs/zh/README.md` 现在是「四类文档」的规则说明:
| 类型 | 回答什么 | 命名 |
|---|---|---|
| 设计文档 | 为什么这样设计 | `*-design.md` |
| 操作手册 | 怎么做 | `*-runbook.md` |
| 教训 | 踩过什么坑 | `engineering-lessons.md` |
| 未做登记 | 还剩什么没做 | `future-plan.md` |
并明确写「**不放执行计划**」及例外条件。
## 顺带修掉的引用
删除后 4 处引用指向不存在的文件:
- `deploy-runbook.md` → 改指 `toolcall-contract-and-sequence-design.md`
- SDK 仓 `guide/stream-tool-call-index.md` / `guide/parallel-tool-declaration.md`
→ 同样改指(这两个在 SDK 仓,随后单独提交)
## 验证
- docs/zh 27 篇,索引里列的全部存在、无遗漏
- 全仓无指向已删文档的引用(代码 + 文档)
- 代码块全部配平
- go build 通过
|
2026-10-31 08:50:39 +08:00 |
|
|
|
345d959e1e
|
docs: 两份 toolcall 文档对齐实现与部署实况
## 契约文档:状态头从「尚未实现」改为「已实现并部署」
生产已注册 7 个 `seq_*` 工具,但文档仍写着"设计定稿,尚未实现" ——
实现者(和读者)会以为 seq 还不存在。
新增 §9.3「实现落点」:设计稿 §8 写的是**六个** `seq_*` 工具,实现时
多了一个 `seq_when_call`(跨序列条件调用独立成工具,否则模型要手写
"先 seq_list 再挑目标再 seq_call",多一次往返且容易挑错),并记下三项
设计之外的修正(`seq_create` O(n²)、`Store.List()` 误认任意 `.json`、
存储用 AST 而非原始文本)。
同时点明:设计条款**仍是契约**,实现与本文冲突时以本文为准并修实现。
## 修一处预先存在的失效引用
§7 末尾 `见 §4.5` —— §4 只到 4.4,该小节不存在。改为按标题名引用
(`§4「结果契约」的 ErrToolNotFound 哨兵`):将来增删小节时不会再次失效。
自查脚本第一版把 8 个**存在**的章节误报成失效引用 —— 标题格式是
`## 1. 背景`(编号后跟 `.`),而我的正则要求编号后是空格。判据自己错了,
改成 `(\d+(?:\.\d+)*)\.?\s` 后才得到真实结果。
## 并行计划文档:部署小节 + 白名单专节
- 原「⚠ 部署前置条件(未完成)」改为「✅ 部署(已完成)」,补实际验证数据
- 记下"实例自述没有编排工具"不是说谎:生产二进制构建于 06:36、seq 引入
于 `699eb33`(更晚)⇒ `strings | grep -c internal/plugins/seq` 为 0。
这类"实例自述与代码状态不一致"应先查二进制构建时间,别急着怀疑提示词
- 新增「设备命令白名单改为可配置」:起因、替换语义、daemon 路径的疏漏
- 明确写下**已知局限**:白名单只匹配命令名、不看参数,
`find -delete` / `sed -i` / `sort -o` 仍放行 ⇒ **不要把它叫"只读白名单"**,
那会让人以为写操作被挡住了
- 记 106 此前无 `online` 日志的成因(旧 waiter 落在未 bind 时收 ping 会断连的
缺陷窗口),以及 `ssh` 吃掉 `read` 输入导致"喂了 yes 却说已取消"
删掉了初稿里一段"反引号内 `+=` 写进 heredoc 导致赋值落到子 shell"的说法 ——
脚本与 git 历史里都没有这种写法,属凭记忆误记,不能留。
文中数字均与现场核对:seq 工具 7、二进制 86784400 / 12691402、白名单 22 条。
|
2026-09-27 20:00:33 +08:00 |
|
|
|
3b5ffc1e71
|
feat(seq): 执行引擎 —— 组内并行 + 具名槽 + 条件求值(插件线 P2)
三个不变量(各有判据钉住):
1. **组内并行、组间串行**。parallel=true 时各工具并发执行。
2. ★ **合并按声明顺序**,不按完成顺序。
并行下完成顺序不确定;若按完成顺序合并,同样的输入产出不同的结果,
整条序列**不可复现**。做法:各工具把结果写进 `results[i]`(按索引),
组屏障处按 tools 数组顺序一次性合并。
顺序合并顺带解决了并发写 map —— **执行期完全不写共享 map**。
3. ★ **条件求值失败必须报错**,不得降级成"条件为假"。
把求值失败当作跳过 = 序列安静地少做一步,而模型以为跑完了
—— 与「静默吞工具」同族(那正是 P1 判据里刚堵上的同类问题)。
条件求值(设计文档 §5 的 L1+L2,不引表达式引擎):
· true/false、$args.key 裸引用(真值)
· == / != / > / < / >= / <= 、contains
· 字面量支持 "str" / 'str' / true / false / 数字 / 裸文本
· 布尔与字符串宽松比较(true == "true"),对齐 utils.getBool 的既有约定
变量插值两种形态(缺一不可):
· **整值引用** "$args.count" ⇒ 替换为**原始值并保留类型**
(数字仍是数字;否则模型收到字符串 "3")
· **文本内插值** "ssh $args.host" ⇒ 在字符串内替换
· 标量渲染:对象/数组用**紧凑 JSON**,绝不用 fmt.Sprintf("%v")
(那会产出 `map[k:v]` 这种模型读不懂的 Go 语法)
on_error:abort(默认)/ continue。失败时也留槽(记错误文本)——
否则后续组读到的是"缺失",而"缺失"与"值为空"在下游难以区分。
判据(exec_test.go,8 条):
· 具名槽写入正确
· ★ 结果按声明顺序合并(用 delay 让完成顺序**确实**打乱)
· array 槽同名 as 按声明顺序确定性追加
· 条件为假 ⇒ 整组跳过、槽**不赋值**、零工具被执行
· ★ 条件畸形(空键 / 引用未声明入参 / 语法不完整)⇒ 报错且**不执行任何工具**
· 条件为真 ⇒ 正常执行
· on_error 的 abort / continue 两种语义
· 插值:文本内替换 + 整值引用保留类型
过程中三次自伤:
1. ★ **toolRunner 接口第一版写成 call(name)**,不收 args ⇒ 插值判据成了
摆设(永远"通过")。改为 call(name, args) 后插值才真正可观察。
2. toolRunner / compactJSON 定义在了 _test.go 里,exec.go 引用不到 ⇒
build 失败。toolRunner 是**引擎的依赖契约**,必须在非测试文件。
3. fixture 里给 "slow" 配了不存在的返回值,误以为它该返回 "B" ——
是我没配就断言,不是实现错。
变异验证:把合并改为"按完成顺序 append"⇒ array 槽顺序判据 FAIL,
报错直指 `[C A ran:slow]` vs 期望 `[A ran:slow C]`。
(第一版变异用了一个 no-op 的 sort.SliceStable,等于什么都没测,
已改成真正模拟完成序的实现。)
`-race` 全绿;回归 internal/agent/... internal/plugins/... 全绿。
顺带修正设计文档:两处 tools 示例原写成 `{tool:cmd_run,...}`,
**不是合法 JSON**(P1 判据实测会解析失败)。已改为合法 JSON 并加注
「键要带引号,这是实现时判据跑出来的真实缺陷,不是假想」。
|
2026-09-27 12:29:56 +08:00 |
|
|
|
a52b982301
|
docs(design): 补 0.2 阶段行
|
2026-09-27 11:56:19 +08:00 |
|
|
|
ca3b3bc669
|
docs: 同步两份文档的实现进度(内核主线 0~2.5 全部完成)
|
2026-09-27 11:56:01 +08:00 |
|
|
|
70b3ddd177
|
fix(toolcall): 工具「不存在」类型化 + 修父 io 兜底吞错误 + 修并行 tool_call 落序随机
主线:工具调用并行化改造(阶段 0 与 0.2)。
① flush 顺序随机(process.go)
flushToolCall 由 `for idx := range accs` 驱动,Go map 迭代顺序随机化
⇒ 同一批并行 tool_call 进入 resp.ToolCalls 的顺序每次运行都可能不同。
对 output_send__ 这类用户可见通道,分段消息到达顺序不可复现。
改为收集 index 后 sort.Ints 再 flush(两个调用点统一走 flushAll)。
判据 stream_flush_order_test.go(8 工具 × 200 轮),已变异验证可检测。
② 工具「不存在」类型化(io/channel.go、core/stages.go、core/toolcall.go)
工具是动态注册的,「不存在」是运行期常态而非异常。原先内核用
strings.Contains(err, "not found in any plugin") 判别——约定而非契约,
插件文案含该子串即被误判。改用哨兵 ErrToolNotFound + errors.Is
(沿用仓内 ErrInputChannelUnknown 的先例)。
⚠️ 顺带修一个静默 bug:IOManager 向父兜底时吞掉父的执行失败,
误报为「工具不存在」。后果是设备离线这类本该 retry 的失败被判为
「工具没了」⇒ 整组被跳过,与「插件真没加载」无法区分。改为只传递
「确实不存在」,其余如实上抛。
「不存在」的文案改为可执行指引(get_plugin_tools / output_list_channels),
而非含糊的「执行失败」——后者会让模型反复重试同一个不存在的名字。
判据:toolcall_error_test.go(类型化 vs 诱饵子串、%w 穿透、执行期文案)、
channel_error_test.go(父失败不吞、真的不存在仍可判别)。
两者均经变异验证。回归:internal/agent/... 与 internal/plugins/... 全绿(14 包)。
设计文档:docs/zh/toolcall-contract-and-sequence-design.md
执行计划:docs/zh/toolcall-parallel-execution-plan.md
|
2026-09-27 08:55:25 +08:00 |
|