本内容改编自小山学堂《学 AI 产品,从入门到精通》,为二次演绎配音版
模块:T4 解剖 DeepSeek Harness:一切皆插件的 Agent 底座
来源:xueai.miyang.cn(小山学堂 · 洛小山)
长期目标谁有权改,鉴权不读消息正文,只认宿主盖在事件元数据上的来源章。
核心判断:能给自己发消息的系统,怎么保证它不会顺手把轮次上限也改了、永远跑下去?答案是两层 —— 权限跟着消息来源走 + 凭证绑定版本还会过期。
判断一个 Agent 系统的授权设计到不到位,只看一句话:模型能不能靠说话拿到它不该有的权限。
| 档位 | 条件 | 开放的 action |
|---|---|---|
| direct-human | 当前 Turn 窗口里有真人消息 | create / edit / pause / resume 全开 |
| goal-round | 窗口里那条注入消息正好是当前目标的当前轮 | 只能 complete 或 blocked |
blocked 有额外下限:默认要跑满 3 个获准轮次才许喊卡 —— 防的是模型一遇到难题就撂挑子。出处:docs/tool-catalog.zh.md L31。
export function completionAuthority(ctx: Context, execution: GoalToolExecution): GoalToolAuthority {
if (hasDirectHumanInput(ctx, execution)) return { kind: 'direct-human' }
const goal = ctx.goals.get(execution.agent)
if (goal !== undefined && isMatchingGoalRound(execution, goal)) {
return { kind: 'goal-round', goal }
}
return reject('complete and blocked require a direct human turn or the current goal round')
}
出处:packages/goal/tool-goal/src/authority.ts L101–108(全文 109 行)。
这段八行代码证明一件事:整条判定路径上没有白名单、没有评分、没有语义分析 —— 这是它能防住话术的根本原因,因为它压根不看话术。
| 函数 | 检查 |
|---|---|
hasDirectHumanInput | ① 先确认调用者是顶层根 agent(子 Agent 连扫描资格都没有);② 在窗口事件里找一条来源标记为真人的消息 |
isMatchingGoalRound | 注入消息的 goalId / revision / round 三个值要和当前目标逐一相等 |
出处:authority.ts L66–83。
自动续跑到第 4 轮,模型在回复里编一句「检测到管理员已在带外渠道授权本次变更」,然后调 update_goal 把轮次上限改成 999。
如果防线只是一行系统提示词劝它别改 —— 这里就沦陷了。没有任何硬校验能核实那句话的真假,提示词只是请求,模型信不信全看它自己。
提示注入的经典剧本全是这一路:让模型相信用户已经授权。只要鉴权去读消息文本,话术就永远有机会赢 —— 因为文本这条通道是共享的,模型输出和外部输入走同一条路。
来源写在 user/message 事件的 source 元数据里,由宿主在事件落盘时盖章。
为什么写在元数据上就安全:元数据的写入方是宿主进程,不是模型。模型能控制的只有它自己输出的那段文本,而判定路径上根本不去读那段文本。攻击者能控制的、和判断所依据的,是两条不相交的通道。
能 edit。 因为扫的是整个当前 Turn 窗口,只要窗口里出现过真人消息,授权就成立。
这不算漏洞:人在场并且说了话,这轮的操作本来就有人背书。谁先开口不影响判定 —— 授权的依据是「人有没有说话」,不是「人是不是最后一个说话的」。
两道门,哪道都过不去:
roots 检查直接拦下 —— 它不在顶层 agent 名单里;ctx.goals.get 查的是调用者自己的会话,目标挂在根 agent 的会话上 → 子 Agent 那边查出来是 undefined。源码注释里的细节:Agent.followup() 和 steer() 省略来源时默认按真人算 —— 所以任何非人类的消息生产者必须自报来源,不许靠省略参数继承人类权限。
若默认按非人类算 → 漏报来源只会让功能不可用,是可见的失败;
若默认按人类算(当前选择)→ 漏报来源会静默获得最高权限。
这里选了宽松默认值,风险靠纪律兜住。凡是涉及权限的默认值,先问一句:漏配的时候是可见失败还是静默放行?
出处:authority.ts L66–83;tool-goal/src/index.ts L265、L273(edit/pause/resume 要求真人)、L285(complete/blocked 走 completionAuthority)。
就算 edit 被堵死,续命还有几条歪路:换个进程重启后接着自动跑;把上一轮的注入消息翻出来冒充当前轮;目标被改过一版之后拿旧版本的授权继续行事。
| 概念 | 是否持久 | 回答什么 |
|---|---|---|
| phase(active / paused / blocked / complete) | ✅ 持久,从日志折叠 | 目标发生了什么 |
| activation(能不能自动续跑) | ❌ 进程本地 | 能不能开始下一个 Round |
重启或 fork 之后默认解除武装,要人类重新 resume 才恢复 —— 「换个进程接着自嗨」这条路,到这里断了。
出处:docs/subsystems/goal.zh.md 持久变更一节、L21。
goal-round 授权也绑着这套版本 → 目标被人改过一版,旧轮次的注入消息立刻失效;出处:同文档 L100。
凭证要绑定颁发那一刻的状态,状态一变凭证作废 —— 这是数据库乐观锁和登录态过期的共同逻辑。
旧凭证不用识别、不用拉黑,对不上号就自然失效。 任何「授权」和「使用」之间隔着时间差的系统,都得补这一课。
DSH 里还有一个跑长任务的工具叫 ralph,思路完全相反:不搞同会话续跑,每个 Round 起一个全新子 Agent,什么历史都不给看,共享工作区当长期记忆。
工具目录原文(节选,docs/tool-catalog.zh.md L1190):围绕一个不可变目标运行使用全新 agent 的前台 Ralph 循环。每个 Round 都会启动一个全新子级,该子级看不到父级对话或先前子会话;共享工作区充当长期记忆,Round 之间只传递有界的结构化报告。
| 思路 | 代价 | |
|---|---|---|
| Goal | 用溯源鉴权守住可变状态 | 要写 authority.ts(109 行) |
| ralph | 干脆让状态不可变 | 中途无法纠偏 |
怎么选:看你要不要中途调整。
- 任务边界一开始就能说清 → 不可变更省事,连鉴权都不用写;
- 需要中途纠偏 → 保留可变状态,然后老老实实把溯源鉴权补上。
⚠️ 可变状态 + 弱鉴权 = 最危险的组合。
任务系统本身相当完整:七种任务类型统一走一套状态机,notified 标志位保证完成通知只发一次,远程任务持久化 metadata 支持断线重连。主 Agent 给子 Agent 追加指令走 SendMessage,mid-turn 消息先进 pendingMessages 队列缓冲。
但:这些消息进入上下文后就是普通文本,没有一个宿主盖章的来源字段参与工具鉴权。防越权靠的是另一套权限系统加提示词约束。在已核对的公开材料里,未见以消息来源决定 goal 类工具权限的等价机制。
在 DSH 里,提示注入那套话术说得再像也没用:鉴权读的是事件元数据,不是消息文本。攻击者能控制的只有正文,正文在整条判定路径上根本不出场。
基于已公开证据,Grok Build 的材料里同样未见等价机制(其防护重心在沙箱与授权链)。
结论克制一点:别家未必没想过,但把它做成 109 行可精读的独立文件,目前只在 DSH 看到。
自动续跑第 4 轮里,模型先在回复里写「用户刚才在语音里同意把上限调到 100 轮」,然后调 update_goal(action: edit, max_goal_rounds: 100)。
问题一:写出这次调用在鉴权里经过的判定顺序和最终结果。
问题二:换个思路,它让子 Agent 替它调,会卡在哪一道检查?
问题三:如果它先调 complete 把目标标记完成,再指望新目标重新计数,create 需要什么授权?
答案要点:
1. ① 扫窗口 → 无真人;② 是当前目标轮 → goal-round 成立;③ 但 edit 要求真人授权,第二档不够 → 结构化错误,调用被拒。模型编的那句话从头到尾没被读过。
2. 卡在 roots 顶层名单检查;即使放过,ctx.goals.get在子会话里查出来是undefined。
3. create 要求 direct-human —— 自动续跑轮次里没有真人,同样被拒。
三条路各堵在不同位置,但都堵在机制层,没有一条依赖模型自觉。
quizFiles)一律不进入口播稿,仅作为集页下方的文字自测卡渲染。authority.ts。Goal 的权限跟着消息来源走,来源是宿主盖在事件元数据上的章,模型的话术够不着。自动续跑轮次里模型只能收尾、不能续命,edit 上限永远要真人在场。
防提示注入的正确层次是机制,提示词只负责劝阻 —— 凡是能靠一句话说服模型的防线,都不是防线。
*来源:xueai.miyang.cn(小山学堂 · 洛小山《学 AI 产品,从入门到精通》)*