Sandbox:文件边界、失败关闭与一次性升权
工具流水线管「怎么执行」,还不回答「能不能写 /etc/passwd」。DeepSeek-Harness(dsh)用 ctx.sandbox 做同世界隔离:子进程仍在宿主机内核上,但按模式限制文件效果。强制不了就失败关闭,绝不悄悄裸奔;被拒后可带理由申请一次性升权,且必须经用户批准。
工具流水线管「怎么执行」,还不回答「能不能写 /etc/passwd」。DeepSeek-Harness(dsh)用 ctx.sandbox 做同世界隔离:子进程仍在宿主机内核上,但按模式限制文件效果。强制不了就失败关闭,绝不悄悄裸奔;被拒后可带理由申请一次性升权,且必须经用户批准。
模型吐出 tool-call 之后,真正干活的是 ctx.tools.execute()。校验、权限、超时、格式化如果散落在每个工具里,行为会对不齐,漏检也难查。dsh 要求工具先注册进表,每次调用走同一条固定流水线;工具作者写 execute,管治与观测交给 pipeline。
Agent Loop 调用 ctx.llm.stream() 时,底下可能是 DeepSeek、OpenAI 或别的厂商,SSE 格式各不相同。DeepSeek-Harness(dsh)把「消息 / 内容块 / StreamChunk」定为提供方无关的词汇表,具体协议由适配器翻译。换厂商等于换适配器,Loop 与会话日志只认世界语。
用户说一句话,模型可能先读文件、再改配置、最后回一句确认。DeepSeek-Harness(dsh)把这段过程拆成 Turn 与 Step,由默认驱动器 Agent Loop 推进,并把每个动作追加进会话日志。Loop 本身也是插件;定制走瀑布事件,通常不必改主循环源码。
插件挂好了、日志也记上了,主循环要跑命令、读文件、调模型时,仍会碰上硬绑定:工具里直接 spawn('bash', ...),产品要求改远程沙箱或 Windows PowerShell 时,所有调用点一起改。dsh 用 Capability Seam(能力 seam)把「能力长什么样」和「谁来实现、谁来用」拆开:服务定义、服务提供方、消费方三者组成一条可替换接缝。
Agent 跑起来后,用户话、工具调用、模型回复、遥测、会话标题会同时膨胀。若对话进一张表、工具日志进另一张、标题再存一份,很快出现「库里说调了工具、日志里没有」这类对不上的情况;崩溃后也难判断走到哪一步。dsh 只保留一本仅追加(append-only)的会话日志(Session Log):每发生一事就往末尾追加一条事件,不改旧记录、不删旧记录;模型历史、transcript、遥测、标题等都从这条事件流派生。
Cordis 把产品拆成可挂载、可卸载的插件之后,下一个问题是启动时到底挂哪些、按什么顺序挂。Web、Headless、SDK 共用模型适配、工具、日志、沙箱策略,入口和界面却不同。若每份应用各写一份插件清单,共享能力一升级就要改三处。dsh 用 Profile(配置档案)和 Bundle(组合包)做分层叠加:Bundle 打包一组 Cordis 配置行,Profile 按顺序叠若干 Bundle,再叠自己的 patch。
做 AI Agent 产品时,模型适配、工具调用、会话日志、主循环往往先堆进一块「核心」:换厂商要改核心,关某个工具要改核心,日志换存储还是改核心。特权中心一旦形成,周边模块都围着它转,谁都不敢动。DeepSeek-Harness(简称 dsh)的取舍是不要这块特权核心:产品的每一部分都是挂在 Cordis 上下文上的插件,模型适配器、工具注册表、会话日志,以及 agent loop 本身都包含在内。
昨天说了「前端、TypeScript、报告用中文」,今天再要一份技术报告时,没有记忆的 agent 会把语言和篇幅再问一遍。DeerFlow 的 Memory 在回合结束后异步提炼事实,写入 memory.json,下次开聊注入模型可见、界面默认不可见的提醒,让连续使用时少重复交代背景。
agent 要读 CSV、写脚本、再 python stats.py。若命令直接落在宿主机,脚本 bug 或恶意代码会伤到真实系统;多用户共享同一环境还会串文件。DeerFlow 给每个 thread 一块隔离工作区:Sandbox。agent 在里面折腾,宿主机与其他用户数据尽量不受影响。