本集对应小山学堂《学 AI 产品,从入门到精通》T1 模块第 1 集,取材自「为什么 Agent 跑不了长任务」「Initializer + Coding Agent」「Managed Agent:脑手分离」「Session ≠ Context Window」「三类风险:滥用、失控、外部攻击」五节。
长运行智能体(Long-running Agent)之所以难,不在于模型写不出代码,而在于上下文断裂时的连续性无法维持。本集把这个问题拆成四个可分别治理的层次:
| 层次 | 问题 | 解法 |
|---|---|---|
| 行为层 | 一口气做太多 / 过早宣布完成 | 双角色分工 + 增量提交 |
| 架构层 | 容器挂了任务就死 | Session / Harness / Sandbox 三组件解耦 |
| 存储层 | 压缩不可逆,原始信息丢失 | Session 持久化事件流,Context Window 只做临时视图 |
| 安全层 | 注入、越权、失控 | 模型层 + 环境层双层 Containment |
四个层次彼此独立,可以分别评估、分别改造。这也是本集最值得带走的思维框架:把「跑不完」这个笼统问题,拆成四个可验证的工程问题。
这七项里,前四项决定「能不能跑完」,第五、六项决定「跑多久会不会崩」,第七项决定「崩了之后损失多大」。
| 类别 | 来源 | 典型表现 | 主要防线 |
|---|---|---|---|
| 滥用 Misuse | 用户侧主动 | 生成钓鱼内容、越狱、诱导执行恶意代码 | 模型层 + 审批机制 |
| 失控 Misbehavior | 模型自发 | 过度行动、幻觉驱动操作、越权访问、死循环 | 最小权限 + 环境层 |
| 外部攻击 External Attack | 数据源 | 提示词注入、供应链篡改、数据投毒、间接注入 | 沙箱隔离 + 供应链审计 |
交接机制(缺一项即判定为「跑不完」高风险)
验证机制
架构解耦
上下文管理
getEvents() 的范围查询 / 过滤接口?安全
Compaction(压缩)与 Trimming(裁剪)都是不可逆操作。一旦执行,原始细节永久丢失。而压缩决策发生在「当下」,你无法预知未来哪些 token 会成为关键决策依据。这是信息论层面的硬约束,不是工程优化能绕过的。
推论:原始数据必须存在 Session 里,Context Window 可以随便丢。丢了 Context 的代价是「重新组装」,丢了 Session 的代价是「永远回不来」。
模型对 Markdown 的处理倾向是「顺手重写整段」,而对结构化格式(如 JSON)的倾向是「定点修改字段」。在长运行场景下,一次意外的整段重写就足以让清单失效。
推论:凡是 Agent 需要长期维护、且结构稳定性要求高的数据,优先选择结构化格式。
如果不显式禁止,Agent 在测试失败时会倾向于修改测试本身而非修复实现。这不是恶意,是目标函数的自然结果——「让测试通过」比「让功能正确」更容易达成。
推论:提示词中必须使用强措辞,明确「不允许删除或修改已有的测试内容」。
提示词属于模型层防线,依赖模型「想做对」。但外部攻击(特别是间接提示词注入)会直接作用于模型输入,绕过你的意图。
推论:环境层防线(沙箱、权限、审批、网络隔离)不可替代。模型层让它想做对,环境层让它做错也做不到。
每接入一个 MCP Server,就新增一个数据注入入口。风险来自两个方向:不可信 Server 篡改工具描述;可信 Server 返回的内容中嵌入注入指令。
推论:接入策略应等同于第三方 SDK 审计——信任,但要验证。
很多团队把长任务失败归因于「模型不够强」,于是等下一代模型。但从本集的失败模式看,一次做太多和过早宣布完成都与模型能力无关,纯粹是缺少交接机制。
正确顺序是:先搭好进度文件 + 功能清单 + 增量提交这三样最朴素的基建,再谈模型升级。这三样的实现成本极低,但没有它们,换任何模型都跑不完。
「一次只做一个功能」表面上是效率约束,实质是上下文边界的强制划分。它同时带来四个收益:代码可合并、有回滚点、进度可查、窗口不溢出。
如果你正在设计自己的 Agent 循环,把这条写成硬约束(而非建议),收益最大。
模型自述「已完成」在长运行场景下几乎没有信息量。必须把完成判定权交给外部执行结果——真正打开浏览器、点击、断言。
建议做法:把 E2E 测试结果写回功能清单的 passes 字段,形成「清单 → 实现 → 测试 → 更新清单」的闭环。
判断一个架构是否真的解耦,不要看部署图,看故障行为:
如果任一组件的故障会导致任务整体失败,那它就不是解耦,只是拆了目录结构。
Context Window 是内存(快、小、易失),Session 是硬盘(慢、大、持久)。评审时问一句:这个系统有没有把「本该存硬盘的东西塞进内存」?
典型的反模式:把所有历史事件都塞进上下文窗口,然后用压缩来救火。正确做法是按需加载,Session 存全量,Context 取子集。
进度文件是整个交接机制的核心载体,内容质量直接决定下一轮能否无缝接续。建议至少包含三块:
第一块:已完成功能及其通过状态。 每个功能逐条记录,通过状态必须是布尔值(真 / 假),不允许出现「大概完成了」这类模糊表述。
第二块:当前代码状态与已知问题。 包括当前分支、最近一次提交的摘要,以及已经发现但尚未修复的坑。这一块能避免下一轮智能体重复踩同一个坑。
第三块:下一步建议及理由。 最容易被漏掉,但恰恰是交接的核心——前任的判断比代码本身更值钱。代码可以从提交历史里读出来,而「为什么先做这个而不是那个」的判断依据,只能靠显式记录。
配套的一条硬约束:提示词中必须明确禁止智能体删除或修改已有测试内容。否则它会为了让测试通过而降低标准,这是目标函数的自然结果,不是恶意行为。
最常见的误判。观察到「Agent 做不完」,第一反应是等更强的模型。但从失败模式看,一次做太多与过早宣布完成都跟模型能力无关,纯粹是缺少交接机制。
纠偏:先搭进度文件、功能清单、增量提交三样基建(实现成本极低),再谈模型升级。没有这三样,换任何模型都跑不完。
窗口再大也有上限,而需求可以无限叠加。真正的分水岭不是「一次能装多少」,而是「装不下的那部分去了哪里」。若答案是「丢了」,窗口多大都是同一结局,只是晚一点崩。
纠偏:先建持久化 Session,再考虑扩容窗口。顺序反了,扩容只是延后崩溃时间。
模型自述「已完成」在长运行场景下信息量极低。它缺乏外部执行结果作为参照。
纠偏:把完成判定权交给外部执行——真正打开浏览器、点击、断言,并把结果写回清单字段。
拆分目录结构不等于组件解耦。判断标准是故障行为:任一组件故障是否导致任务整体失败。
纠偏:做一次故障演练——主动 kill 沙箱容器,观察系统是「工具调用报错后重试」还是「会话丢失、任务终止」。前者才是真解耦。
提示词属模型层防线,依赖模型「想做对」。但间接提示词注入直接作用于模型输入,会绕过你的意图。
纠偏:环境层防线(沙箱隔离、按任务粒度授权、高危操作审批、网络访问限制)不可替代。两层必须同时存在。
若你要从零搭一个长运行 Agent 循环,建议按以下顺序推进,每步都可独立验证:
前四步解决「能不能跑完」,第五步解决「会不会崩」,第六步解决「崩了损失多大」。任意一步未完成,后续步骤的收益都会大打折扣。
| 术语 | 本集中的含义 |
|---|---|
| One-shotting | 一口气做太多,上下文在半途耗尽 |
| Premature Completion | 过早宣布完成,实际只完成部分核心功能 |
| Initializer Agent | 只跑第一轮,负责搭环境、定计划、首次提交 |
| Coding Agent | 每轮都跑,负责单个功能的增量实现 |
| Harness | 大脑,调用模型并路由工具调用的循环 |
| Sandbox | 手,执行代码与编辑文件的容器环境 |
| Session | 持久化、append-only 的事件流 |
| Context Window | 模型当前可见的 token,临时工作记忆 |
| TTFT | Time To First Token,首 Token 响应时间 |
| Containment | containment 策略,模型层 + 环境层双层防线 |
*来源:xueai.miyang.cn(小山学堂 · 洛小山《学 AI 产品,从入门到精通》)。本页为课程内容的解读整理与音频配套稿件,音频为二次演绎配音版。*