WeClaw_70|第一性原理砍需求:一个"多会话并发"方案从立项到自我否决的完整思辨
第五季系列文章第 1 篇(总第 70 篇) - 第一性原理 · 需求拆解 · 复杂度税 · 收益上限分析 · 分阶段决策门
📚 专栏信息
《从零到一构建跨平台 AI 助手:WeClaw 实战指南》专栏 · 第五季
专栏定位:面向开发者和技术决策者的实战专栏,用真实案例和完整代码带你理解如何构建生产级 AI 应用
本文记录一次罕见的完整决策闭环:一个"多会话并发执行"需求,经历了 UltraPlan 三代理方案设计 → 三视角专业评审(发现 5 个 Critical)→ 两轮修订 → 第一性原理收益/成本评估 → 最终砍掉 65% 的方案,只保留 35%。这不是失败的故事,而是工程决策的最佳实践:最贵的代码是不该写的代码。
👨💻 作者与项目
作者简介:翁勇刚 WENG YONGGANG 新概念龙虾-WeClaw 开发团队负责人,一群专注于跨平台 AI 应用的实践者 理念:"再复杂的技术,也能用代码讲清楚"
- 💻 项目地址:https://github.com/wyg5208/weclaw.git
- 🌐 官网地址:https://weclaw.link
- 📝 作者 CSDN:https://blog.csdn.net/yweng18
- ⭐ 欢迎 Star⭐、Fork🍴、贡献代码🤝
📝 摘要
本文结构概览: 从一个看似理所当然的需求出发——"桌面 AI 助手应该支持多个会话同时执行任务"——完整走一遍方案设计、专业评审、两轮修订的流程,然后在实施前的最后一刻,用第一性原理把需求拆回原子层面,发现"并发"只是手段而非目的,真正的痛点是"可观察性"。最终砍掉多 dispatcher 调度架构,保留会话隔离渲染地基,工作量降至 35%,回归风险降一个量级。
核心问题: 当一个技术方案在评审后已经"技术上完全成立",你还应该问什么?答案是:收益的物理上限在哪里、复杂度税由谁支付、以及——用户真的高频需要它吗?
关键成果:
- 一套可复用的需求拆解方法:把"我想要 X 功能"拆为原子需求 N1/N2,分别评估现状满足度
- "收益上限由瓶颈资源决定"分析框架:并发架构的收益被 LLM 后端焊死
- "永久复杂度税"概念:一次性实施成本可以付清,架构复杂度是付不清的按揭
- 分阶段决策门模式:先做无悔的地基,用真实运行数据决定是否继续
适合读者:技术负责人、独立开发者、任何需要在"做与不做"之间做决策的工程师
阅读时长:约 15 分钟
关键词:第一性原理、需求拆解、复杂度税、方案评审、并发架构、决策门
一、需求的诞生:一个"理所当然"的想法
WeClaw 的桌面端有一套指令队列机制:用户发出的每条指令进入 SQLite 持久化队列,由一个全局串行调度器(SerialQueueDispatcher)逐条执行。这套机制是 v7.0.0 引入的,解决了"任务执行中新指令会丢"的问题——现在指令可以排队,永不丢失。
但很快出现了新的抱怨(来自我自己):
论文生成任务要跑十几分钟。这期间我点「新会话」问一个简单问题——"帮我查个天气"——它排在论文任务后面,十几分钟后才回答我。
于是需求自然而然地浮现:多会话并发执行。当前会话跑长任务时,新会话的指令立即执行;点会话列表切回去,聊天区实时显示那个会话的进行中内容。
这个需求听起来无懈可击。ChatGPT 网页版不就是这样吗?每个对话独立,互不阻塞。
二、方案设计:三代理并行研究 + 三视角评审
2.1 UltraPlan:先摸清家底
我们没有直接开写,而是走了完整的规划流程。三个研究代理并行产出三套候选方案(简洁可维护 / 性能可扩展 / 最小改动),再由主流程亲自读代码核实关键论断。摸清的家底包括:
agent.chat_stream(target_session_id)有会话级锁_session_locks——跨会话天然可并行,会话内互斥- 队列的
claim_next_item用BEGIN IMMEDIATE事务 + 条件 UPDATE——多个调度器并发领取不会重复 - EventBus 的工具调用/思考事件已经携带 session_id——会话级过滤有现成字段
综合出的方案架构相当干净:
每个会话一个独立 dispatcher(scope 分片为 desktop:{session_id})
├── DispatcherManager 统一管理(并发上限 3,=1 时回退旧行为)
├── GuiAgent 全部核心信号追加 session_id 首参
├── UI 按"当前显示会话"过滤渲染
└── 后台会话内容写入 LiveSessionBuffer,切换时重放续流
2.2 三视角评审:5 个 Critical
方案成文后,我们派出三个独立评审代理,分别从完整性(需求覆盖)、正确性(技术论断验证)、影响面(下游契约回归)三个视角审查。合并结果:
| 严重级 | 数量 | 典型问题 |
|---|---|---|
| Critical | 5 | buffer 按内容去重会丢消息;并发槽位补启动存在"永不启动"死区;scope 迁移不彻底会导致同会话双执行破坏串行语义;队列控制 API 仍假设单 dispatcher;版本回滚后新格式队列永久无人消费 |
| Warning | 9 | 删除执行中会话未处理、退出只关一个 dispatcher、无速率限制…… |
注意这个信号:一个经过三代理研究、亲自核实代码的方案,评审仍然发现 5 个 Critical。这不说明方案写得差——每个 Critical 都有清晰的修复路径,我们也确实完成了修订——它说明的是:这个问题域的固有复杂度就是这么高。并发 + 持久化迁移 + UI 状态机的三重叠加,每个角落都藏着时序陷阱。
修订后的方案 v3 有 200 多行,包含迁移 SQL、断言降级、回滚脚本、双触发点补启动、12 类测试。技术上,它成立了。
三、关键转折:实施前的第一性原理拷问
方案技术成立 ≠ 应该实施。在按下开工按钮前,我们做了最后一轮评估,这次不问"怎么做",只问三个第一性问题。
3.1 问题一:剥掉方案外壳,原始痛点到底是什么?
"多会话并发执行"是一个解决方案,不是需求。把它拆回原子层面:
- N1 不阻塞:长任务执行中,我想立刻发新指令,不想等
- N2 可观察:切回后台任务的会话,能看到实时进展
然后逐个对照现状:
| 原子需求 | 现状 | 真实缺口 |
|---|---|---|
| N1 | 队列已支持"边执行边接收",指令排队不丢 | 只是第二条指令的等待延迟 |
| N2 | 完全缺失——切换会话只见陈旧的持久化内容,执行中的流式输出、工具调用状态全部不可见 | 整个能力 |
这一拆立刻暴露了不对称性:N1 已被满足了一半,N2 是零。而"多会话并发"方案把 80% 的复杂度花在了 N1 的那一半上(多 dispatcher、scope 迁移、并发上限、补启动),N2 需要的其实只是信号带上 session_id + 一个实时缓冲。
并发是满足 N1 的一种手段,且是最重的一种。
3.2 问题二:收益的物理上限在哪里?
这是最容易被忽略的一问。并发架构做得再精妙,收益上限被瓶颈资源焊死——对 AI 助手来说,瓶颈是 LLM 推理后端:
| 后端形态 | 并发的真实收益 |
|---|---|
| 云 API | ✅ 真并行;代价是限流风险 + 费用随并发线性上升 |
| 本地 llama-server(单卡) | ⚠️ 两条流在服务端仍是分时/排队;开 -np 2 意味着 KV cache 内存翻倍;吞吐几乎不变,甚至双双变慢 |
| 工具 I/O 段(下载/爬取) | ✅ 真并行,但这部分本来就不长 |
换句话说:如果哪天从云模型切回本地模型为主(本地化恰恰是 WeClaw 的长期方向之一),这套并发架构的收益立即归零——而它的复杂度成本不会退回。
一个架构的收益会随外部条件蒸发,成本却是刚性的。这种不对称本身就是危险信号。
3.3 问题三:复杂度税由谁支付、付多久?
实施成本好算:12 步改造、约 10 个核心文件、4–6 人日。这是一次性成本,付清即止。
真正贵的是永久复杂度税:
- 此后每一个触碰聊天渲染、队列、停止按钮、TTS、工具确认弹窗的新功能,都必须先回答"多会话并发时怎么办"
- 评审发现的那些问题就是首期税单:后台会话的确认弹窗弹给谁?删除一个正在执行的会话怎么办?停止按钮是停当前还是停所有?
- 并发 bug 的调试成本是串行的数倍——日志交织、时序依赖、难以复现
而 WeClaw 是一个高速迭代的项目(v7.0 → v8.1 只用了一个月,期间还塞进了 OA 系统融合)。每个新功能都要过一遍"多会话拷问",这个税会在每次迭代中反复征收。
3.4 灵魂拷问:所以,高频吗?
三个问题问完,决策收敛到一个事实判断:"长任务执行中、第二条指令等不起"这个场景,到底多高频?
诚实的回答:论文生成、批量文献下载这类超长任务,一周也就几次。而为这个低频场景,要永久支付高额复杂度税。
答案不言自明。
四、裁剪:从方案 B 到方案 A
最终决策用一张对比矩阵呈现(这也是我们做技术决策的固定格式——多方案、多维度、明确推荐):
| 需求满足 | 工作量 | 回归风险 | 复杂度税 | 可回退性 | |
|---|---|---|---|---|---|
| 方案0 维持现状 | N1 半、N2 无 | 0 | 无 | 无 | — |
| 方案A 只做可观察性 | N1 半、N2 全 | ~35% | 低 | 低 | git revert 即可 |
| 方案B 完整并发 | N1+N2 全 | 100% | 中高 | 高且永久 | 中(配置回退) |
方案A 的内容:
- 信号携带 session_id:GuiAgent 全部核心信号(message_/reasoning_/tool_call_*)首参加 session_id
- 显示会话过滤 + LiveSessionBuffer:信号归属当前显示会话 → 渲染;否则 → 写缓冲。切回时"持久化重放 + 缓冲续流",思考态、工具日志一并恢复
- 两个存量 bug 修复(评审的意外收获):
_enqueue_and_refresh漏传 session_id——所有消息落同一个队列,归属和审计一直是错的_workflow_item_executor用临时 connect/disconnect 捕获执行结果——存在信号串扰竞态,改为chat()直接返回(content, error)
/new_session语义修正:不再粗暴取消旧会话的执行——旧任务跑完,新指令排队
执行层完全不动:还是那一个 SerialQueueDispatcher,还是全局 FIFO。没有迁移、没有并发配置、没有新调度组件。
4.1 方案A 不是妥协,是"无悔选项"
这里有个精妙之处:方案A 恰好是方案B 的正确性地基。信号 session_id、LiveSessionBuffer、显示会话过滤——如果未来云模型长任务真的变高频、串行等待真的成为实际痛点,重启并发只需补上调度层那一小块,方案A 的全部工作直接复用,零返工。
我们把重启条件也写进了文档,作为未来的决策门:
① 长任务期间"第二条指令等不起"的实际发生频率(方案A 上线后排队是可见的,会有体感数据);② 长任务是否以云模型为主;③ 可否接受并发 API 费用与限流风险。
被废弃的方案B 文档原样保留,头部加废弃说明和重启指引。思考痕迹本身就是资产——半年后如果重启,不需要重新踩一遍 5 个 Critical 的坑。
五、方法论沉淀
这次决策闭环可以压缩成五条可复用的原则:
1. 需求要拆到原子层面再评估。 "我想要多会话并发"是方案,不是需求。拆成 N1/N2 后发现:一个已被半满足,一个完全缺失,而原方案把复杂度花错了地方。
2. 收益上限由瓶颈资源决定,不由架构决定。 在动手前先问:这个架构的收益会不会被某个外部资源焊死?会不会随条件变化蒸发?本地 LLM 后端让"并发"的收益近乎虚幻。
3. 区分一次性成本与永久税。 实施人日可以咬牙付清;架构复杂度是按揭,每次迭代都要还——项目迭代越快,税率越高。评审发现的 Critical 数量是问题域固有复杂度的测量仪。
4. 评审的价值不只是修 bug,更是复杂度探测。 三视角评审发现的 5 个 Critical 全部可修,但"一个精心设计的方案仍有 5 个 Critical"这个元信息,比任何一个具体问题都更有决策价值。
5. 优先选择"无悔选项"。 如果全量方案中存在一个子集:独立有价值、风险低、且是全量方案的必要地基——先做它,把剩余决策推迟到有真实数据的时刻。这不是拖延,是把决策权交给证据。
六、总结
一个需求从"理所当然"到"自我否决",走过了:三代理方案设计 → 三视角评审(5 Critical + 9 Warning)→ 两轮修订 → 技术上完全成立 → 第一性原理三问 → 砍掉 65%。
最终留下的 35%(会话可观察性 + 两个存量 bug 修复)是确定性净收益:无论未来是否重启并发,这些工作都不白做。而砍掉的 65%(多 dispatcher 调度架构)连同全部思考痕迹被封存在废弃文档里,等待——或永远等不到——它的重启条件。
写代码之前最重要的工程能力,是判断哪些代码不该写。
下期预告:会话可观察性改造(方案A)的实施记录——信号签名改造如何做到零遗漏、LiveSessionBuffer 的续流重放如何处理持久化时序竞态。
系列文章:
- WeClaw_69|总结与展望:Harness工程的方法论与被验证的方向
- WeClaw_68|Loop_Detection:检测和中断Agent的死亡循环
- WeClaw_67|Pre-completion_Checklist:AI的交接前自检清单