运行中的修改,到底什么时候生效

拆解 pi(DeepSeek 开源终端 Coding Agent)v0.83.0 的 setter 与 pending writes:调用 setModel() 返回后,「新模型生效」有四个不同的观察面,其中两个还是旧的。源码依据:pi-internals 21 章

setter 返回了,然后呢

Agent 运行中,你调用了 await harness.setModel(second),它返回了。直觉上「模型已经是 second 了」。

但如果你同时问四个地方,会得到四个答案:

  • harness.getModel()second------setter 已更新 Harness 的最新配置
  • 已经发出的 provider request:旧模型------请求用的是 active turn state,不重读字段
  • 下一次 createTurnState()second------下一份快照会读到新值
  • session.buildContext()(保存点 flush 前):还是旧的 branch 配置------busy 时 setter 只把变更放进 pending queue

一次修改,四个观察面,其中两个还停在旧值。这不是 bug,是设计:当前请求必须用稳定的输入(turn snapshot),修改只对下一轮生效

setter 的两个时钟

以 setModel() 为例。它先保存 previousModel。phase 为 idle 时,等 appendModelChange() 成功;phase 非 idle 时,只向 pending queue 放入一条 model_change。接着无论哪条路径,都把 this.model 指向新模型,并发出 model_update 事件。

setThinkingLevel() 和 setActiveTools() 结构相同。setTools() 还会先校验工具名唯一、active name 都存在,再决定追加还是排队。setResources() 与 setStreamOptions() 不写 Session entry------它们只改变当前实例,进程重建时需要宿主重新提供。

pending write 为什么不能立即插队

这是这一章最值得细看的地方。assistant message 可能带多个 tool call。低层 loop 要先把 assistant message 和对应的 tool results 形成相邻、完整的对话片段,再进入下一轮。

如果一个 subscriber 在 message_end(assistant) 里追加 custom message,并且立刻写入 Session------这条消息就会落在 assistant 与 tool result 之间。下一次从树构建上下文时,模型 API 所需的工具配对可能被切断:模型看到 tool call,却看不到对应的 result。

所以 Harness 让运行中的 appendMessage() 只排队,idle 时才直接追加。flushPendingSessionWrites() 始终读数组首项,按 entry type 调 Session 对应方法,成功后才 shift()。某项失败不会越过它写后面的内容------简单的 FIFO,没有重试计数、没有 durable queue id、没有跨进程恢复。

Hook 是顺序的,不是并发的

subscribe() 注册全事件观察者,存放在专门的 handler set 里。emit 时按注册顺序等待每个 listener;任意一个抛错,错误被规范成 Hook error,后续 listener 不再执行。它不是 fire-and-forget 的埋点。

on(type, handler) 注册带类型的 Hook,同样顺序等待,保存最后一个非 undefined 结果。所以 context、tool_call、tool_result 这些 Hook 的默认 reducer 是 last-result-wins,不是自动合并所有对象。provider options 和 payload 是例外:链式处理,前一个 handler 改出的结果交给下一个。

失败不会回滚

message_end 到来时,Harness 先 session.appendMessage(event.message),成功后才通知 subscriber。subscriber 抛错,已经追加的消息不会从树上删除。setter 也是先提交自己负责的状态,再发 update 事件;update listener 失败会让 public Promise reject,却没有补偿性回滚。

拆完这章,我的感受是:Agent 框架的「修改」语义,比普通系统复杂得多------因为同一份状态同时活在内存配置、turn 快照、pending queue 和 Session storage 四个地方。pi 的处理是给每个观察面明确的语义:修改立即可见于内存,只对下一轮生效于请求,只在保存点落盘于存储。做 Agent 平台的人,最怕的就是把四个观察面混成一个「当前状态」------那才是真正找不到 bug 的根源。

想看完整拆解(setter 四观察面状态表与 Hook 失败语义源码),这里有 pi-internals 小册子

源码依据:packages/agent/src/harness/agent-harness.ts L225-L317、L442-L484、L512-L536、L538-L554、L884-L955、L961-L1023,pi v0.83.0,commit 845d6ff1。

相关推荐
Shota Kishi6 小时前
Solana Shreds 的 UDP 直投架构:Shredstream UDP Forwarding 的设计与实现
网络协议·架构·udp·区块链·solana
mldong10 小时前
一份 JSON,一条能跑的审批流:把报销流程送上工作流引擎
后端·架构
65岁退休Coder12 小时前
PI Agent 开发一个生产级 Harness
后端·node.js·agent
贾伟康12 小时前
【HarmonyOS 7新能力|026】Agent Framework Kit工程封装:把接入逻辑放进可维护的分层结构
agent·harmonyos·arkts·a2a·harmonyos 7
这个DBA有点耶12 小时前
异构数据集成怎么做?5 种同步方案对比 + 金融级 CDC 实战解析
数据库·oracle·架构
深蓝电商API13 小时前
MCP 与 AI Agent 如何改变爬虫开发模式?
爬虫·agent·mcp
这个DBA有点耶13 小时前
MySQL 8.0.20移除了Block Nested Loop,之前学的JOIN优化知识还适用吗?
数据库·mysql·架构
陆柒14514 小时前
从洋葱模型到 Elpis Core:我对 Node.js 服务端开发的理解
架构
懂软件的胡子个哥14 小时前
微信 API 消息回调怎么设计,才能避免丢消息和重复处理
运维·微信·架构·wechatapi·个人微信号二次开发
Ticnix14 小时前
多租户 RAG:让每个用户只检索到自己的知识库
后端·python·agent