mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-28 05:13:27 +00:00
refactor(parallel): 内置工具的并发声明改为 SDK 同构的结构体字段
上一提交(2232d54)把并发安全改成了声明式,但内置工具那一路仍是将就:
声明靠往 required 变参里塞字符串 "toolParallel" 传递。
## 为什么那不算声明式
对照 SDK 的 NoMemory 逐条看:
| | SDK NoMemory | 当时的内置工具 |
|---|---|---|
| 载体 | `ToolDef.NoMemory` 字段 | required 里的字符串 |
| 拼错后果 | 编译器报错 | **静默失效** |
| 内核读取 | 查结构体字段 | 遍历工具表 + 解析字符串 |
"少一个工具能并发"恰恰是最难察觉的一类问题 —— 没有任何报错,
只是并行的批悄悄退化成串行。
## 改法
### 1. sdk.BuiltinToolDef 补声明项(与 NoMemory 同构)
```go
type BuiltinToolDef struct {
Name, Description string
Parameters map[string]interface{}
ParallelSafe bool // 零值 false = 默认串行(保守)
Serial bool // 优先于 ParallelSafe
}
func (d BuiltinToolDef) ConcurrencySafe() bool { return d.ParallelSafe && !d.Serial }
func (d BuiltinToolDef) ToSchema() map[string]interface{}
```
### 2. 工具定义处声明
```go
toolDef("memory_merge", ...) // 默认串行
toolDefWith("knowledge_search", ..., []string{"query"}, parallelOpts()) // 已核实只读
```
### 3. 内核一次聚合并缓存(照 StageHost.NoMemoryToolNames)
```go
graphOf() // 快照
declareParallelTool(name) // init 里登记
concurrencySafeOf(name) // 查表
```
不再每次 toolParallelSafe 都重跑 buildToolDefs()(O(工具数) 重复劳动,
而声明是静态的)。
## ★ 一个更隐蔽的问题:声明表曾经是空的
`declareParallelTool` 最初挂在 `toolDefWith` 的**运行时调用**上。而那 9 个
工具全在 `if a.knowledge != nil` / `if a.social != nil` / `if a.parentID != ""`
之类的条件分支里 —— 测试环境根本不走进这些分支 ⇒ 聚合表始终为空。
而判据查的是同一张表,于是**自证通过**:全绿,并发能力为零。
这就是判据设计的教训 —— 判据和数据源同源时,它证明的只是"我和我一致"。
现在判据双向核对:名单里的必须真声明了,声明了不在名单里的也会报出来;
并额外验证内核**真的读得到**(concurrencySafeOf 而非读同一份 map)。
## 顺带修掉的迁移事故
用正则批量改造 30+ 个 toolDef 调用点时,把 `person_set_trait("name", "content")`
这类**变参**调用误改成 toolDefWith(... "name", "content") —— 那是**写工具**,
差点被标成可并发。已全部回退并逐一核对:9 个声明并发,0 误伤。
This commit is contained in:
@ -63,6 +63,33 @@ type BuiltinToolDef struct {
|
||||
Name string
|
||||
Description string
|
||||
Parameters map[string]interface{}
|
||||
// ParallelSafe 与 ToolDef.ParallelSafe 同义:声明此工具可被并发执行。
|
||||
// 零值 false = 默认串行(保守)。
|
||||
//
|
||||
// ⚠️ 内核曾经没有这个字段,于是内置工具的并发声明无处安放 ——
|
||||
// 先后试过"内核里一张硬编码 map"和"往 required 变参塞字符串"两种错做法。
|
||||
// 声明项必须落在**工具自己的结构体**上,与 NoMemory 同构。
|
||||
ParallelSafe bool
|
||||
// Serial 声明此工具必须串行,优先于 ParallelSafe。
|
||||
Serial bool
|
||||
}
|
||||
|
||||
// ToSchema 转成下发给模型的 function schema。
|
||||
func (d BuiltinToolDef) ToSchema() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "function",
|
||||
"function": map[string]interface{}{
|
||||
"name": d.Name,
|
||||
"description": d.Description,
|
||||
"parameters": d.Parameters,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ConcurrencySafe 报告该工具是否可并发执行。
|
||||
// Serial 优先:显式声明"必须串行"不允许被 ParallelSafe 或默认值覆盖。
|
||||
func (d BuiltinToolDef) ConcurrencySafe() bool {
|
||||
return d.ParallelSafe && !d.Serial
|
||||
}
|
||||
|
||||
// BuiltinProvider 由内核注入(导出:core 需实现它)。
|
||||
|
||||
Reference in New Issue
Block a user