Repository navigation
长时间重度使用中遇到的 3 个问题:编辑观察状态不持久、工具调用被静默丢弃、调度器失败不留结果 #6759
YOUKNOWWHOOO
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
先说清楚这份反馈的来龙去脉
我在一台 Windows 机器上把 dsh 当日常主力工具用:Web UI 常开,会话动辄连续几十轮,上下文经常堆到几十万 token,并且大量使用子代理委派(一个主会话派出若干子代理,子代理再派孙代理)。这套用法有两个特点,正好把一些平时不容易碰到的问题放大了:一是进程会经历多次重启与插件热重载,二是会话状态会长期累积、委派会形成多层树。
下面 3 个问题就是在这种用法下暴露出来的。其中第 1 个我真实撞到 4 次;第 2、3 个是排查"工具调用会不会丢"时在代码里发现的路径,本机没有真实触发过——我会如实标明每一条的证据强度,不会把"读代码推断"讲成"实测发生"。
写每一条时我都尽量照顾三件事:我遇到的情况(怎么发现的、当时看到什么)、为什么会这样(机制,以及包内的确切位置)、你可以怎么核验。
本文不含本机路径、会话 ID 与任何凭据。版本:
@deepseek-ai/dsh0.1.5-rc.1,相关插件包(dsh-subagent、dsh-llm、dsh-agent-loop、dsh-fs-observation-policy、dsh-tool-fs、dsh-tools)0.1.5-rc.2。速览
file has not been read — read the file, then retry;重读一次后立刻成功问题 1:重启或恢复会话后,第一次编辑一定会失败
我遇到的情况
在一个会话里,我让 agent 读过某个文件、也成功改过它。之后我重启了 dsh(Web UI)并继续同一个会话,再让 agent 改那个文件,结果它报:
agent 按提示重新读了一遍,再改就成功了。
一开始我判断错了方向:我以为是"编辑工具偶发失效",甚至怀疑过"同一条消息里的多个工具调用互相干扰"。后来我把会话的原始事件日志(dsh 会把模型返回的原始流和装配后的 assistant 消息都记录下来)做了逐条对账,才确认真相:这既不是偶发,也不是我的错觉——只要进程重启过(或插件热重载过),该会话此前读过的文件在系统眼里就全部退回"从未读过",于是重启之后对这类文件的第一次编辑必然被拒。
为什么会这样
dsh 有一条"先读后写"的安全策略:要编辑一个已存在的文件,必须先在本会话里读过它。这条设计本身没问题,问题出在它把"读过哪些文件"记在了哪里:
dsh-fs-observation-policy/lib/index.js:22;读取与登记见同文件:24-39。:44-45、:88-89)。:60-68:查不到"读过"的记录,直接抛FS_NOT_OBSERVED。dsh-tool-fs/lib/index.js:537、:547,那里注释自己称之为 remedy),所以它读起来像"你没读就想改"——但模型或用户在本会话里确实读过了,只是那份记录随进程一起没了。影响
session/end-seed)之后;每一次补读之后立刻成功。这个分布和"状态随进程丢失"完全一致。怎么复现
file has not been read — read the file, then retry。问题 2:响应被输出长度上限截断时,工具调用会被静默丢弃
我是怎么发现它的
我没有在本机撞上这条路径(0 次)。它是在排查"工具调用有没有可能被丢掉"时读代码发现的。我认为它值得报告,因为到目前为止它是我找到的唯一一条会把工具调用整体丢弃、却不留任何痕迹的路径——一旦发生,使用者拿不到任何线索。
为什么会这样
当一次模型响应因为达到输出长度上限而结束时(结束原因是
max-tokens),dsh 会把这次响应里的全部工具调用块丢弃。这个取舍可以理解:被截断的调用可能不完整,不该拿去执行。问题在于它做得完全无声。代码在dsh-llm/lib/index.js:996-1016:同文件
:991-995的注释说明这个判断对"发给模型的内容"和"重放元数据"同时生效,保证两者不会不一致;但没有任何日志、事件或提示说明发生过丢弃。同族的还有一处中断路径:1033-1040(interruptedBlocks)也会省略工具调用块,本机触发过 2 次,但那两次没有工具调用在飞,所以没有实际后果。影响
模型可能已经流式输出了"接下来我要调用某个工具",甚至界面上都闪过这个调用,然后它凭空消失:使用者看到的是"agent 说要做事,然后什么都没发生",而事后翻日志也找不到原因。这类不一致最难排查,因为所有证据都在系统里被抹掉了。
问题 3:工具调度器失败时,已开始的调用不会留下结果
我是怎么发现它的
同样是在排查"工具调用会不会丢"时读代码发现的,本机 0 次触发。
为什么会这样
一次 assistant 消息里的多个工具调用由调度器统一执行。如果调度器自身出错,已经启动、但还没提交结果的调用会被直接排空(
Promise.allSettled)然后抛错,这些调用的结果不会写进会话:dsh-agent-loop/lib/index.js:636-651。作为对照,同一个函数里处理"用户中止"的路径(
:652-659)会给还没来得及开始的调用补写一条合成的错误结果,所以中止场景不会留下悬空记录——差别就在这里。影响
会话日志里会出现"有
tool/call、没有tool/result"的记录。模型和界面都无法区分"这次调用根本没执行"和"这次调用还在跑",只能选择重试,而重试并不总是安全(有些调用有副作用,例如改写文件)。这些结论是怎么来的
附:可能的修复方向(供参考,可删)
old_string)的逐字命中来承担安全性。两种做法都能让重启后的第一次编辑不再失败。All reactions