当前位置: 首页 > news >正文

# 让工具自己声明并发安全:我把调度逻辑砍到一行

让工具自己声明并发安全:我把调度逻辑砍到一行

这是 《写完一个 AI 编程助手之后,我才确定 prompt 工程不是重点》 的第四篇。前几篇讲了进程模型和权限系统,这一篇讲并发调度。

代码:[https://github.com/sishenaichipingguo/code-agent)。

AI 经常一口气甩三个工具:

[ { name: 'read', input: { path: 'a.ts' } }, { name: 'read', input: { path: 'b.ts' } }, { name: 'grep', input: { pattern: 'TODO' } } ]

也经常这样:

[ { name: 'read', input: { path: 'a.ts' } }, { name: 'write', input: { path: 'a.ts', content: '...' } }, { name: 'edit', input: { path: 'a.ts', ... } } ]

第一组并行跑没问题。第二组并行跑就炸——同一个文件被三个操作竞争。

调度器要不要并行?怎么决定?

我试过三种方案,前两种都错了。


一、第一种错法:全部串行

最朴素的方案:永远不并行。

for(consttooloftools){results.push(awaitrunTool(tool))}

正确,但慢得令人发指。读三个文件本来 50ms 能搞定,串行变成 150ms。一次轮次里有四五次 batch,累积下来用户能感觉到。

而且这是个无意义的慢——Read 工具就是无害的,串它干嘛?


二、第二种错法:调度器去猜

第二个直觉是写一张表:

constSAFE_TOOLS=['read','grep','glob','ls']constallSafe=tools.every(t=>SAFE_TOOLS.includes(t.name))

跑了几天就发现 bug。比如:

bash git status ← 只读,应该并行 bash rm -rf foo ← 破坏性,绝对不能并行

是同一个工具bash,但语义完全不同。把bash加进 SAFE 列表是错的,不加进去又把所有bash git status / git log / ls这种纯查询全串行了。

更糟的是,每加一个新工具,就要回到调度器更新这张表。写新工具的人必须改无关的代码——每次都会忘。

调度器不应该知道工具的语义。任何让调度器去"判断"工具的方案,都会在加新工具时退化。


三、第三种做法:让工具自己说

核心改动:在每个工具上加一个方法。

// src/core/permissions/types.tsexportinterfacePermissionCapable{isConcurrencySafe(input:unknown):boolean// ...}

然后调度器只问一句话:

// src/core/agent/loop.tsconstallConcurrencySafe=tools.every(t=>{consttool=this.context.tools.get(t.name)returntool?.isConcurrencySafe(t.input)??false})if(allConcurrencySafe){returnPromise.all(tools.map(runTool))}constresults:any[]=[]for(consttooloftools){results.push(awaitrunTool(tool))}returnresults

调度器一行判断。

工具自己回答:

// read.tsisConcurrencySafe:()=>true,// write.ts、edit.ts、rm.tsisConcurrencySafe:()=>false,

bash是真正有意思的那个:

// src/core/tools/bash.tsisConcurrencySafe:(input)=>{constcmd=(inputasany).commandreturntypeofcmd==='string'&&classifyCommand(cmd)==='readonly'}

注意签名——isConcurrencySafe(input)接收输入。同一个bash工具,对git status返回true,对rm -rf返回false判断粒度不是工具,是工具调用

这是这个设计真正起作用的地方。如果签名是isConcurrencySafe()(无参数),bash 就只能选一个保守的false,损失全部并发收益。


四、默认值要保守,不要乐观

有一个细节决定这套设计能不能在团队里活下来:默认值

createTool的默认实现:

// src/core/tools/registry.tsisConcurrencySafe:spec.isConcurrencySafe??(()=>false)

默认false。新写的工具如果忘了声明,自动按串行处理。忘记声明的代价是慢,不是炸

反过来,如果默认true,每加一个新工具都可能引入并发 bug,而且测试很难发现——因为冲突只在特定时序下出现。

MCP 工具也走这个默认(src/core/mcp/client/tool-wrapper.ts):

isConcurrencySafe:()=>false

这是对的,因为 MCP server 的语义对我们完全不透明,假设它危险是唯一安全的选择。

任何"必须由作者主动声明才安全"的属性,默认值都要选不安全的那一边。


五、为什么不做"部分并行"

最后一个反直觉的决定:不要做部分并行

设想这个 batch:

[ read a.ts, read b.ts, write c.ts, read d.ts ]

聪明的调度器会说:“前两个并行,等第三个串行执行,再起一个并行跑第四个。”

这套逻辑要写一个拓扑排序,要追踪资源依赖(哪些路径在被写?bash 的副作用怎么算?),还要考虑回退。代码量从 5 行膨胀到 200 行,且每个新工具都要重新审视。

我选择了最钝的方案:

全部安全 → Promise.all 否则 → 全部串行

代价是上面那个 batch 退化成全串行,慢一点。但代码简单到不会出 bug,新工具加进来零成本。

能用 5 行代码解决 80% 的问题时,不要写 200 行代码解决 100% 的问题。

实际跑下来,AI 给的 batch 里 95% 要么全是 read 类(全并行),要么含 write/edit(全串行)。混合 batch 罕见,性价比不值得为它写复杂逻辑。


所以呢

这是「工程问题决定 Agent 好坏」系列的第三个例子,跟前两篇讲的是同一个原则:

  • 进程模型:把阻塞操作丢给 Worker,主循环只负责调度
  • 权限系统:把危险性判断丢给工具,引擎只负责仲裁
  • 工具调度(这篇):把并发安全丢给工具,调度器只负责选Promise.all或串行

框架的本职工作只有一件:定义一个让组件自我描述的接口,然后做最钝的调度。

写得越多 AI Agent 我越确信这件事。prompt 工程chain 抽象memory 设计这些被各种框架包装的概念,本质上都是组件自我描述 + 钝调度的问题。一旦你把它从"框架的智能"改成"组件的诚实",复杂度立刻塌一个数量级。

代码:github.com/your-handle/code-agent。


下一篇讲 Agent 长对话的核心问题:上下文窗口快满了怎么办——三种压缩策略和一个自动兜底机制。

http://www.jsqmd.com/news/855007/

相关文章:

  • DeepSeek RAG场景GPU资源黑洞:向量检索+重排序+生成三阶段显存泄漏的48小时定位实录(含perf脚本)
  • 2026年Q2权威APP变现平台排行:APP商业化变现、APP广告变现、APP广告收益提升、APP广告素材合规选择指南 - 优质品牌商家
  • 百度 Agent 安全中心:构筑企业智能体的安全底座
  • 某消费电子终端上市公司实例:德思特衰减器方案以1/3成本精准复现弱网与WiFi干扰场景
  • Perplexity写作辅助效率翻倍:3个被低估的核心技巧,今天不用明天就落后
  • 初创团队如何利用 Taotoken 以最小成本验证多个大模型能力
  • 别只当题做!我把CTFshow Web信息搜集题(11-20)变成了真实漏洞挖掘指南
  • 覆盖20+省市:合豚无人零售SaaS赋能全渠道零售
  • 避开HFSS优化那些坑:Optimetrics模块5大功能深度解读与常见误区纠正
  • 基于STM32的智能扫地机器人设计与实现
  • 阀门耐火试验报告中的关键信息该怎么看?
  • 武汉假发店TOP5评测|专业形象美学指南,揭秘头部信赖之选! - 行业深度观察C
  • 在 Eclipse 中使用 Tabnine
  • 统考通过率最高传媒艺考机构艺天影视
  • AutoCAD C# 二次开发:玩转径向标注(RadialDimension)与防翻转实战
  • CTF基础SQL联合注入超详细教程|从0基础到成功拿到Flag
  • 2026年外墙蜂窝板TOP5厂商排行 实测品质维度解析 - 优质品牌商家
  • LRU缓存机制(保姆级精讲)
  • 别再只盯着IMU了!聊聊CDC减振器控制里,那套用3个加速度+4个高度传感器的“经典组合拳”
  • stitch靶场学习笔记
  • 算法(移动零)
  • 湖北高空作业车技术选型要点与合规租赁实操解析 - 优质品牌商家
  • Linux系统开机启动模式
  • 智能零能耗建筑系统一体化与性能优化【附代码】
  • 如何在3分钟内实现专业级AI背景移除:OBS插件终极指南
  • 武威本地专业承接各类项目落地 本土资深班组全程施工更靠谱
  • 外部系统调用SAP数据?用ABAP RFC函数搭个“桥梁”其实很简单(含Function Group创建避坑)
  • 穿云越巷的“全局视野”:NeurIPS 2026 论文深度解读《Seeing Across Skies and Streets: Feedforward 3D Reconstruction from
  • python学习笔记 | 11.2、面向对象高级编程-使用@property
  • 菩瓦纽课业平台:精准追踪错题根源,让每一份努力都有回响