DeepSeek Harness:一次 Prompt 的完整执行轨迹

DeepSeek Harness:一次 Prompt 的完整执行轨迹

从输入、Context、Plan 到工具、子 Agent、反馈修复和最终验收

阅读方式:沿一个具体任务逐步前进,每一阶段都说明输入、处理、输出和背后的设计思想。

本文是“源码支持的教学执行轨迹”,不是一次实际项目运行录屏。 假设项目、Skill、模型响应、文件内容、job ID、测试结果均为教学数据;Harness 的机制来自当前源码核验。没有运行示例项目,没有调用示例 API,没有修改用户配置。实际 LLM 的调用顺序和回答可能不同。


先回答最重要的问题

Context 是否靠检索历史消息后拼接?

  • 当前 Session 的历史:通常不是先做相关性搜索,而是从该 Session 的日志派生当前模型可见的消息视图,将未被替换遮蔽的历史带入请求。

  • 其他 Session 的历史:当前 base/Web 默认不自动全文检索;全文搜索配置为 openAt: never。可通过显式会话引用、另行启用的历史工具或外接记忆 MCP 导入相关内容。

  • 项目文件:适用指导与 Skill 目录可由插件注入;普通源文件不是全仓自动塞进请求,通常由模型提出 read/grep 等调用后才进入历史。

  • 长历史:必要时裁剪或摘要,改变后续模型可见的 surface,而不是删除原始日志。

Plan 是怎么来的?

程序切换规划模式、注入指导、提供审阅工具;具体计划由 LLM 根据目标和工具证据生成。用户通过正式 Plan review 批准,后续 Step 才实施。

工具和子 Agent 谁决定用?

Harness 决定“有哪些工具、何时可用、能否执行”;LLM 决定“这一步请求调用什么、传什么参数”。子 Agent 是被调用后创建的独立执行者,不是每次 Prompt 自动必经的模块。


目录

  1. 教学环境、原始 Prompt 与明确目标

  2. 总图:执行控制、数据和反馈

  3. 最重要的三份数据:日志、Surface、请求

  4. 第一次请求:Context 如何真正组装

  5. 主线逐阶段执行:R1—R14

  6. 子 Agent 的独立轨迹与可见范围

  7. 每次模型请求的 Context 增量账本

  8. 工具执行到底发生了什么

  9. 同会话继续、恢复和跨会话检索

  10. 历史过长时的裁剪与摘要分支

  11. Goal、结束 Turn 与自动继续

  12. 失败、取消与不能保证的事情

  13. 谁负责决策,谁负责确定性处理

  14. 实现入口与核验来源

  15. 用 12 句话复述整条流程


 

1. 教学环境、原始 Prompt 与明确目标

1.1 我们假设的环境

应用:Web profile
Agent preset:standard,使用 Native 工具执行
主 Session:S-main,刚创建,此前从未开始 Turn,尚无模型消息 surface
主 Agent:lead
模型:demo-provider / demo-model
模型窗口:131072 tokens,支持工具调用与 medium effort
最大输出:8192 tokens
系统提示更新:本例假设 leading-only
工作区:/workspace/orders-demo
文件策略:workspace-write,根 Agent 审批可用
外部全文历史搜索:默认关闭
外部记忆 MCP:未接入
Team:本例不启用

这些不是你的当前个人模型配置。窗口、ID 和目录只用于展示机制。

假设项目中已有:

/workspace/orders-demo/
  AGENTS.md
  src/orders/routes.py
  src/orders/service.py
  src/orders/csv_export.py
  tests/test_orders_export.py
  .agents/skills/csv-export-guide/SKILL.md

这些项目文件仅作为教学背景,不表示本机真的存在。

1.2 项目指导输入

示意指导内容:

使用项目已有的权限装饰器,不得另造跳过权限的导出通道。
金额数据库单位为分,导出展示单位为元。
测试使用 pytest。
不要访问生产数据库;不得 commit 或 push。

1.3 一个教学 Skill

假设 Skill 目录中有 csv-export-guide,目录只展示:

名称:csv-export-guide
描述:复核 CSV 导出字段、转义、金额格式、权限与测试。

其正文提供这些方法:

先读既有导出与权限实现;规划阶段不实施。
用 CSV 库处理逗号、双引号和换行,不手写字符串拼接。
金额以元展示、两位小数,不使用千分位分隔。
导出检查应考虑电子表格公式解释风险。
核验未授权、边界条数和字段一致性。

该 Skill 是假定已安装的教学资源,不是 DSH 随附保证有的技能,也没有在本次工作中安装或创建它。

1.4 用户原始 Prompt:U0

/plan 为订单后台新增 CSV 导出。
导出当前筛选条件下的订单,最多 10000 条。
字段为订单号、客户名、金额、创建时间。
金额以元显示并保留两位小数,时间使用 Asia/Shanghai。
复用现有权限检查;不要访问生产环境,不要提交或推送。
先研究并给出方案,待我在计划审阅中批准后,再完成实现与测试。
必要时可用一个只读子 Agent 复核,并持续推进到验收完成。

后面把去掉 /plan 控制前缀的任务正文记为 U0-task。

1.5 什么是目标,什么不是目标

本任务的目标不是“调用 read”或“创建子 Agent”。工具是手段,最终验收是:

  1. 筛选条件正确传到导出逻辑;

  2. 导出权限复用已有机制;

  3. 超过 10000 条时按用户选择的策略处理;

  4. 字段、金额、时区和 CSV 转义正确;

  5. 约定的公式风险处理与测试到位;

  6. 测试和最终变更核验完成;

  7. 没有触碰生产环境、commit 或 push。

这是 LLM 对用户需求的具体化。Harness 不会从字符串里自动认证这些条件已经满足。


 

2. 总图:执行控制、数据和反馈

2.1 三种不同的箭头

  • 控制流:谁触发谁执行。

  • 数据流:哪些消息、参数、结果被传入下一组件。

  • 反馈流:执行结果如何改变下一次模型决策。

sequenceDiagram
    participant U as 用户
    participant UI as Web / 命令入口
    participant H as Harness 主循环
    participant C as Context / Session
    participant M as 主 LLM
    participant T as 工具执行器
    participant A as 子 Agent
    participant E as 文件 / 进程环境
    U->>UI: /plan + U0
    UI->>H: 模式选择 + 正文进入 inbox
    H->>C: 准入工具、组装提示、注入相关 context
    C-->>H: 当前派生 messages 与工具定义
    H->>M: R1:规划请求
    M-->>H: Skill / 文件工具调用
    H->>T: 校验、权限、执行
    T->>E: 读取项目材料
    E-->>T: 文件与搜索结果
    T-->>C: 记录 tool/result
    H->>M: 后续请求携带新证据
    M-->>T: exit_plan_mode(plan)
    T->>U: 正式计划审阅
    U-->>T: Approve
    T-->>H: approved=true,排队退出规划
    H->>M: 后续 Step:实施模式
    M-->>T: 修改文件、委派、测试
    T->>A: 自包含只读审查任务
    T->>E: 执行修改与测试
    A-->>C: 完成通知与审查结论
    E-->>C: 测试输出与退出码
    H->>M: 失败与审查意见进入 context
    M-->>T: 修复并再次验证
    T-->>C: 通过结果与最终证据
    H->>M: 汇总请求
    M-->>U: 交付与未覆盖范围

图省略了实际事件与请求准备细节,下面逐步展开。

2.2 本例使用和没有使用的机制

机制

主线是否使用

原因

当前 Session 历史派生

是

每次请求要看到此前对话与工具结果

跨 Session 全文检索

否

默认关闭,也没有本任务需要的已知旧知识

自动全仓知识检索

否

普通文件通过工具按需读取

项目指导

是

已挂载插件按适用范围注入

Skill

是

先目录,后调用加载正文

Plan review

是

用户明确要求先规划、正式批准

Todo

是

批准后跟踪执行步骤

Goal

是

本例 LLM 选择建立长任务目标,作为继续策略

自动 Goal round

否

主线在同一个 Turn 内完成并标记 Goal complete

子 Agent

是,1 个 spawn

独立只读复核;减少主 context 中审查细节

Fork

否

后文对比其种子规则

Jobs

是

演示后台测试与显式收集结果

Context compaction

未触发

本例历史压力保持在阈值下;另设分支讲解

Team / Workflow / Schedule

否

这项任务不需要大规模编排或未来定时输入

Web 搜索

否

当前项目文件足够回答问题

这张表是本教学轨迹的选择,不是“DSH 每次都必定这样做”。


 

3. 最重要的三份数据:日志、Surface、请求

3.1 日志 L:发生过什么

Session 保存有类型的事件,例如:

plan/mode
agent/inbox/spliced
turn/start
step/start
system/message
user/message
request/header
request/context
assistant/message
tool/call
tool/result
step/end
turn/end

这只是事件类型示意,不是本文伪造的一份精确原始日志。每个事件有真实序号、来源、时间和相应数据结构。

3.2 Surface H:现在应让模型看到什么

当前实现从日志维护模型消息视图。可以进入模型消息历史的事件包括:

system/message
 developer/message
 user/message
 assistant/message
 tool/result

其中空内容和插件投影还会影响最终派生。其他 log-only 事件不直接变成一条模型消息。

例如 Goal、Todo 的状态有自己的记录;模型通常看到的是工具返回或插件生成的状态 context,而不是把这些内部事件 JSON 原封不动读一遍。

3.3 请求 Q:这一次传给模型的东西

当前循环的真实构造核心接近:

const request = {
  ...header.config,
  messages: session.deriveMessages(),
  toolHistory: session.toolHistory(),
  tools: header.tools,
  sessionId: session.id,
  signal,
}

这里是为了易读省略条件分支后的源码说明,不是可以直接运行的外部 SDK 示例。实际请求随后由绑定 adapter 转成上游协议。

尤其注意:当前内部请求的系统提示在 messages 中,不是另一个隐藏 header.system。

3.4 最小 Context 公式

Q_i = 本 Step 的控制参数
    + deriveMessages(当前 Session surface 与内容投影)
    + 本 Step 准入的工具 Schema
    + 适配器所需的工具历史信息

不是:

Q_i = 搜一下所有历史 + 任意拼一些相关聊天 + 新问题

后者可以由可选检索插件实现,但不是默认主循环的历史构造算法。

3.5 本文的快照记号

记号

含义

S_plan / S_execute

含/不含规划指导的有效系统提示

U0-task

用户原始任务正文

I

适用项目与用户指导

D_i

当前动态 runtime 事实快照

W_i

独立 time-context listener 条件注入的时间背景

K

Skill 名称与描述目录

A_i

第 i 次主模型输出

O_i

对应工具返回批次

B_child

子 Agent 完成通知和最终回答

T_i

当前准入工具集

后面的快照以逻辑组成展示,而不是宣称是某提供方逐字、逐 token 的 HTTP body。真实排序由已记录消息顺序、插件和 adapter 决定;正文会给出当前标准组合下可以核验的关键顺序。

依据:循环请求构造、Session 派生语义、日志与投影。


 

4. 第一次请求:Context 如何真正组装

以下准备阶段并不各自消耗一次模型调用。直到“发送 R1”才发生第一次主模型推理。

阶段 0:Host 启动,能力注册

输入:profile、bundle、用户 patch、启动 overlays、插件代码。

处理:

  • Cordis 加载服务与实现:Session、Agent loop、LLM adapter、工具 registry/executor、文件与进程后端、权限、持久化、Skill、Plan 等。

  • Web standard 为一个 Agent 提供适合它的 scoped 组合。

  • 建立 Schema、事件监听器、作用域、生命周期清理函数。

输出:一个可创建 Agent 和 Session 的运行环境。

思想:能力组合与任务决策分离。加载了文件服务,不代表已经把文件内容给模型;有 Skill registry,不代表全文技能已经加载。

阶段 1:创建或定位 S-main

输入:用户选择的工作区、preset、模型选择。

处理:创建新 Session 与 Agent;持久化后端建立相应写所有权;初始化工具/提示作用域和 inbox。

输出:

S-main:无已完成 Turn
lead:当前空闲
cwd:/workspace/orders-demo
model:demo-provider/demo-model

思想:先确定“这个任务属于哪个执行者和哪段历史”,而不是每条消息都无身份地直接调用模型。

阶段 2:处理 /plan 和正文

输入:前端发送的原始 U0。

处理:

  • Slash command 走命令入口,不应一概描述为普通 session/prompt。

  • /plan 选择规划模式。

  • /plan <task> 的正文通过 agent.steer() 进入后续输入。

  • 在没有 open Turn 时,模式可直接提交;有 open Turn 时按边界排队应用。

输出:规划模式选中,U0-task 已进入 inbox。

如果输入不是被命令接管的普通Prompt,则走客户端 session.prompt(content, mode, ...) → Host prompt admission:检查内容、身份、附件与requestId,创建带用户来源的消息。mode=steer进入next-step并唤醒,queue/followup进入next-turn并唤醒。没有命令插件接管时,未知斜杠文本也不应假定自动有控制语义。

思想:模式控制与用户自然语言内容是不同数据。/plan 不是让 LLM 自己猜一个开关。

阶段 3:打开 Turn、领取输入

输入:Agent 收件箱中的 U0-task,以及可能存在的 next-step 注入。

处理:

  • 写入 turn/start。

  • 首次先领取全部 pending next-step 输入,再至多领取一个 next-turn prompt;后续 Step 领取 next-step 输入。本例 /plan 正文就在 next-step,next-turn 可以为空。

  • 固定本 Step 的 provider、model、显式 reasoning effort。

输出:本 Step 的已领取消息与模型选择快照。

思想:input claim、排队和模型选择是运行时状态,不能靠对话文字自行同步。

阶段 4:准入工具,组装 sections/contexts/variables

输入:Agent scope、选中模型、当前模式、已注册贡献、取消信号。

处理:

  1. tools.resolve(...):求值条件工具、作用域限制和注册状态,形成 ResolvedToolSet。

  2. systemPrompt.assemble(...):收集有效 prompt sections、动态 contexts、变量、工具声明。

  3. 按规定顺序组织 sections、变量和 Schema。

输出:类似这样的组装结果:

sections:Harness 身份 + persona + 工具指导 + plan policy + 其他有效指导
contexts:cwd、权限等 runtime 动态事实贡献
时间背景:由 time-context 独立 pre-step listener 注入,不属于上述 assembly contexts
variables:当前 model 等可插值变量
tools:read/grep/glob/skill/ask_user_question/exit_plan_mode 等准入定义

这是内容摘要,不是一个固定全产品模板。

思想:同时解决“告诉模型什么”和“允许它调用什么”,避免 prompt 承诺的能力与实际 executor 不一致。

阶段 5:agent/pre-step 注入与决策

输入:领取的消息、组装结果、本 Step 身份。

处理:协作 waterfall 中的插件可以:

  • 加入适用指导 baseline;

  • 加入 Skill 目录;

  • 处理显式会话引用或 /Skill 手势;

  • 检查 Goal round 是否过期;

  • 压力满足条件时进行裁剪/压缩;

  • 接受、改写或拒绝本批输入。

Fallback 将有需要的动态 runtime context 投影成 user-role 候选消息。

输出:enter(messages, ...) 或 reject。

本例第一轮需要注入 I、D_1、K,并由独立 time-context listener 提供时间/时区背景 W_1。该时间消息不是 D runtime 的 assembly context;当前默认至少间隔 10 分钟刷新,不是每 Step 必加。普通源文件内容此时尚未全部读取。

思想:context 是多个拥有明确责任的生产者贡献出来的,不是一个随意往字符串里追加内容的全局函数。

阶段 6:准备真实调用,再录入模型可见消息

输入:已接纳消息、固定模型选择、组装结果。

处理:

  1. 记录 step/start。

  2. prepareCall() 校验 adapter、参数与默认值,绑定本次实际调用和路由能力。

  3. 刷新动态 context,但不重跑本 Step 的整个组装。

  4. 协调系统提示节点;本例 first call 写入 S_plan。

  5. 将已接纳用户消息、指导和 context 写入模型消息 surface。

  6. 必要时记录 request/header、request/context。

  7. deriveMessages() 派生并冻结本次请求。

输出:R1 的不可变请求快照,以及仍然可取消的信号。

关键点:真实 adapter 准备成功之前,不把待接纳系统提示和用户输入提前当成已经发给模型的事实。取消与准备失败有清楚的录入边界。

阶段 7:第一份 Context 快照 C1

当前 standard 的首轮关键消息顺序可理解为:

system:有效 S_plan(首个系统节点)
user:U0-task
user:I,指导 baseline 在领取的用户消息后插入
user:D_1,runtime context
user:K,Skill catalog 后续加入

插件顺序、额外输入、显式 Skill 手势或用户覆盖可改变细节;上面只展示这个教学环境的核心消息。不是一个通用硬编码顺序。

此外还有独立 time-context 注入的 user-role 时间消息 W_1,不是把时间硬塞进 D_1;它相对其他插件的具体排列以 listener 为准。上面的列表展示核心相对顺序,不是完整 wire 数组。

工具 Schema T_1 作为另一组请求输入,不应伪装成普通用户聊天。fresh /plan 首请求没有旧 header 时,不会再凭空多出一条“模式已切换”通知。

C1 的可见事实:用户目标、项目规约、运行范围、可用方法目录。C1 没有:普通源文件全文、别的 Session 记忆、子 Agent 结果、未来测试结果。

依据:preStep 的真实调用顺序、录入与 stream、System Prompt 组装、指导与目录、Skill 目录与正文、baseline插入源码、目录尾附源码、独立时间消息源码、时间刷新默认、plan边界提交。


 

5. 主线逐阶段执行:R1—R14

5.1 数字先说明白

  • R1—R14:主 Agent 的 14 次示意模型请求,没有失败的 API attempt。

  • B1—B3:同一个子 Agent 的 3 次示意模型请求。

  • 工具 batch 中可有多次调用,因此“14 次请求”不等于“14 个工具”。

  • 用户回答问题与正式 Plan review 是工具交互,本例没有因此开启新的主 Turn。

  • 所有主 R1—R14 都属于首次主 Turn T-main-1;直到 R14 无后续欠账才结束。

这些计数只描述教学轨迹,不是运行日志统计。

R1:判断任务,加载方法,找项目入口

输入 C1:S_plan + U0-task + I + D_1 + W_1 + K + T_1。这是逻辑组成,不表示把全部贡献按这个字符串顺序发给模型。

LLM 的判断:这是受权限和格式约束的 CSV 任务,应先加载相关 Skill、找到现有实现;不能直接写新模块。

模型输出 A1:工具调用意图(示意):

[
  {"name":"skill","arguments":{"name":"csv-export-guide"}},
  {"name":"glob","arguments":{"pattern":"**/*export*","path":"/workspace/orders-demo"}}
]

这些 JSON 表示易读的调用意图,不是上游 wire 或 SessionEvent 的完整结构。

Harness 处理:解析参数、检查已准入定义、执行 Skill load 和路径搜索、记录 call/result。

输出 O1(教学):

skill:<skill_content> 完整方法正文与资源说明 </skill_content>
glob:src/orders/csv_export.py、tests/test_orders_export.py

下一轮为什么需要它:R2 现在知道 Skill 的真实操作要求和候选位置,不能只靠目录一句描述猜技能正文。

思想:渐进披露与先定位后读取。Skill 不执行实现,提供的是如何安全组合已有工具的知识。

R2:读取当前实现,形成项目事实

输入 C2:C1 的有效组成,加 A1 + O1;动态事实变化时有更新。

LLM 的判断:需要了解权限、筛选、CSV 和已有测试,而不是读整个仓库。

模型输出 A2(示意):

[
  {"name":"grep","arguments":{"pattern":"permission|filter|export","path":"/workspace/orders-demo/src/orders","include":"*.py"}},
  {"name":"read","arguments":{"file_path":"/workspace/orders-demo/src/orders/routes.py","offset":1,"limit":180}},
  {"name":"read","arguments":{"file_path":"/workspace/orders-demo/src/orders/service.py","offset":1,"limit":180}},
  {"name":"read","arguments":{"file_path":"/workspace/orders-demo/src/orders/csv_export.py","offset":1,"limit":160}},
  {"name":"read","arguments":{"file_path":"/workspace/orders-demo/tests/test_orders_export.py","offset":1,"limit":180}}
]

输出 O2(教学摘要):

路由已有 require_permission("orders:export")。
service 支持当前 filter 参数。
数据库金额字段 total_cents,单位分。
已有 CSV writer 可复用。
已有 8 条相关测试,尚缺公式输入案例。

真实工具返回是文件片段/匹配;上面的摘要只是文档为读者压缩的可核验结论。模型不能仅拿一句“已有权限”代替读源代码。

下一轮影响:形成可依赖项目事实;避免另造权限层、误解货币单位。

思想:工具结果改变模型的知识状态。这里不是 embedding RAG,而是路径/文本搜索加显式文件读取。

R3:澄清人类拥有的取舍

输入 C3:已有需求和项目事实,但“最多 10000 条”尚有产品歧义。

LLM 的判断:超过上限时,是截取前 10000 条还是整体拒绝?源码不能替用户决定。

模型输出 A3(示意):

{
  "name":"ask_user_question",
  "arguments":{
    "questions":[{
      "id":"row-limit-policy",
      "question":"筛选结果超过10000条时,希望如何处理?",
      "options":[
        {"label":"整体拒绝,提示缩小范围"},
        {"label":"只导出前10000条,明确提示截断"}
      ]
    }]
  }
}

用户输入:选择“整体拒绝,提示缩小范围”。

输出 O3(逻辑值):该问题的已选择选项;工具结果进入当前历史。

状态变化:产品要求更明确,Plan mode 仍 active。这次回答不等于批准完整实施计划。

思想:可发现事实通过检查解决,用户取舍通过交互解决。避免把技术猜测伪装成用户要求。

R4:生成计划并进入正式审阅

输入 C4:项目证据 + 完整 Skill + 上限处理选择。

LLM 生成的计划内容(教学摘录):

# 订单 CSV 导出方案

目标:导出当前筛选结果,复用权限,最多10000条,超过整体拒绝。
实现:复用 routes/service/csv_export 三层;CSV writer负责转义。
格式:金额元、两位小数、无千分位;时间Asia/Shanghai。
测试:权限、筛选、上限、转义、金额与公式输入。
约束:不触碰生产,不提交、不推送。
验收:相关测试通过,最终diff可解释,无权限旁路。

模型输出 A4:仅调用 exit_plan_mode,把完整 Plan Markdown 放入 plan 参数。

Harness 处理:

  1. 校验当前 committed plan mode、计划标题与审阅通道。

  2. 展示完整方案给用户。

  3. 等待正式 Approve 或 Keep planning。

用户输入:点击 Approve。

输出 O4:approved: true,并有“从下一 Step 开始实施”的结果提示。

状态细节:

当前工具批次:仍保留 plan guidance
待应用模式:active=false
下一 accepted Step:使用退出规划后的组装,并提交 plan/mode(false)
主 Turn:仍 T-main-1,没有因为审批自动新建 Turn

下一 preStep 中先运行工具准入与 prompt assembly;它们读取所选的 pending 模式。随后 pre-step listener 提交模式事件,再进入本次 request。不能把代码中的“下一 request”误说为“必须下一整轮 Turn”。

思想:方案内容由 LLM 产生,实施批准由用户产生,状态应用边界由 Harness 管理。

R5:退出规划,建立执行状态与具体 Goal

输入 C5:历史中的计划与 O4,S_execute,当前 scope 和工具集。

本例假设 leading-only 路由,系统提示在头节点协调更新;不是把已生效 S_plan 与 S_execute 当两份同等现行指令随意拼接。

模型输出 A5(示意):

[
  {
    "name":"create_goal",
    "arguments":{
      "objective":"在订单工作区实现已批准CSV方案,修复相关失败并完成验收;不访问生产、不提交或推送",
      "max_goal_rounds":3
    }
  },
  {
    "name":"todo_write",
    "arguments":{"todos":[
      {"content":"实现权限、筛选和CSV导出","status":"in_progress"},
      {"content":"子Agent只读复核与运行测试","status":"pending"},
      {"content":"修复问题并最终验收","status":"pending"}
    ]}
  }
]

Harness 处理:

  • Goal 工具检查直接顶层人类授权与当前执行身份;原始 U0 就在本 Turn 中。

  • Goal 服务保存状态并武装继续资格。

  • Todo 保存完整列表;调度按工具安全分类处理,不因同批就一定并行。

输出 O5(教学):

Goal:G-main,revision=1,phase=active,roundsStarted=0,cap=3
Todo:1 in_progress,2 pending

ID 是教学符号;实际 ID 由运行时生成。

思想:把意图和进度显式化。Goal 是 LLM 在本例选择调用的工具,不是每次 /plan 自动生成的目标。roundsStarted=0 不妨碍在普通人类 Turn 中开展大量 Step。

R6:实施文件改动

输入 C6:批准的方案、项目原文、Skill、Goal/Todo 返回。

模型决策:对已读取文件作有限改动,复用既有结构。

动作(教学):

edit routes.py:增加导出入口,复用 require_permission。
edit service.py:传递筛选,检查结果上限。
edit csv_export.py:复用CSV writer,转换金额和时间。

为了教学反馈,我们假设第一版在金额格式中写了:

# 第一版示例缺陷:使用了千分位
amount = Decimal(order.total_cents) / Decimal(100)
amount_text = f"{amount:,.2f}"

它能生成 CSV,但不符合“金额无千分位”的 Skill/测试约定。

Harness 处理:检查参数、权限、读前编辑等策略,执行文件变更并返回结果。

输出 O6(教学):三个编辑操作成功;文件成为版本 V1。

思想:工具“编辑成功”只确认文件效果,不证明业务实现正确。下一步要用独立证据检验,而不是直接宣布完成。

R7:启动一个只读子 Agent,同时启动测试

输入 C7:V1 已写入;主模型知道任务与代码改动。

模型输出 A7:委派 prompt(教学完整示例):

你是订单CSV方案的只读复核者。
目标:检查刚完成的V1是否有权限旁路、字段/金额/时区问题、CSV转义和公式解释风险。
需求:当前筛选、最多10000条、超限整体拒绝、金额元两位无千分位、Asia/Shanghai。
位置:/workspace/orders-demo,重点看src/orders三文件和tests/test_orders_export.py。
约束:只读,不改文件、不访问生产、不提交推送、不调用需要人类审批的操作。
方案已由用户正式批准;你只审查,不替主Agent实施。
必要时加载csv-export-guide正文。
返回:发现、文件与位置、建议测试;没发现也说明检查范围,不能认证全部生产安全。

调用 subagent 时给出独立名称 csv-reviewer,采用 spawn,不传另一个模型路由,默认沿用父选择。

同一模型输出还提出:

{
  "name":"bash",
  "arguments":{
    "description":"运行订单CSV导出测试",
    "command":"pytest tests/test_orders_export.py -q",
    "workdir":"/workspace/orders-demo",
    "run_in_background":true
  }
}

输出 O7(教学):

subagent:已启动 csv-reviewer,先返回名称,不返回完整审查结论
bash:已接纳后台 job J-test-1,尚未完成

调度假设:R6的文件改动全部 settled;R7到R9修复前,V1实现与测试输入保持不变。pytest仅使用合成订单和隔离fixture,不连接生产。测试可能写缓存,因此它不是OS级只读执行;子Agent只读复核与它并行,而后续代码改写必须等第一次测试与本次复核都结束。

思想:两个执行单元可以推进不同工作。主模型不应把“已启动”当“已通过”,也不必复制子 Agent 的全部阅读细节。

只读任务说明是行为约束;父为 workspace-write 时,不能仅靠该说明声称子运行时已切换为 OS 级 read-only。真正固定权限与任务约束要分别说明。

R8:收集第一次测试结果

输入 C8:当前代码 V1、审查者已启动、J-test-1 已知。

模型输出 A8:

{
  "name":"job_output",
  "arguments":{"job_id":"J-test-1","wait":true,"timeout_ms":30000}
}

教学调度假设:本次等待过程中测试结束;子 Agent 也即将结束。实际先后可不同。

输出 O8(教学):

FAILED test_money_format
Expected: 1234.50
Actual:   1,234.50
1 failed, 7 passed
[status: completed, exit code: 1]

这是教学结果,不是本次实际跑过的 pytest。

Harness 处理:返回 producer 输出与状态;被等待收集的结果避免再次重复通知。

思想:job_output 的等待结束不必总是成功;如果超时返回 running,则 job 仍在跑。本例进程已经结束,但测试失败。

特别区分:当前后台Shell的正常进程结算即使exit code非零,也映射为generic job completed;failed主要对应被抛出的启动/运行基础设施故障等路径。completed不是测试通过,exit code和断言才说明业务结果。

R8 与 R9 之间:子 Agent 结果进入主 inbox

我们选择一个清楚的教学时序:子 Agent 在 R9 准备前已经完成。

输入:子 Session 的最终回答。

Harness 处理:普通 parent-delivery 委派将完成通知送入在线父 Agent 的 next-step 输入。

输出 B_child(教学):

csv-reviewer 已完成只读复核。
发现:V1 的客户名等可控文本未处理 =、+、-、@ 开头的公式解释风险。
位置:src/orders/csv_export.py 的字段输出处。
建议:按项目约定处理危险前缀,并补四种前缀的参数化测试。
权限装饰器和超限拒绝路径已核对;未访问生产。
范围限制:这是代码复核,不保证所有电子表格软件或生产环境安全。

主模型会收到这段高价值结论,而不是自动收到 B1—B3 的每份文件和推理。

R9:根据测试与审查共同修复

输入 C9:

原需求与方案
+ 原Skill正文
+ 已写V1
+ O8:金额测试失败
+ B_child:公式解释风险及建议

模型决策:修复金额格式,并针对实际审查问题增加代码与测试,而不是原样重跑失败命令。

动作(教学摘录):

# 版本V2金额格式:保留两位小数,不带千分位
amount_text = f"{amount:.2f}"

# 教学约定的文本风险处理示例,非通用安全保证
if cell_text.startswith(("=", "+", "-", "@")):
    cell_text = "'" + cell_text

新增四种前缀的参数化测试;仍使用 CSV writer 处理逗号、引号和换行。

输出 O9:编辑成功,测试从 8 个案例扩为 12 个案例,文件成为 V2。

思想:LLM 是可被反馈纠正的策略提出者;确定性测试和独立审查提供不同类型的证据。局部文本策略只是本例约定,不能泛化为全部 CSV 安全问题已解决。

R10:重新执行测试

输入 C10:V2 和新测试。

模型输出 A10:同一隔离工作区运行相关测试,后台返回 J-test-2。

输出 O10:测试 job 接纳。

思想:新代码需要新的结果;不能拿 V1 的“7 passed”替 V2 验收,也不能把 J-test-1 的结果误当 J-test-2。

R11:收集通过证据

输入 C11:明确的第二次 job ID。

模型动作:job_output(J-test-2, wait=true)。

输出 O11(教学):

12 passed
[status: completed, exit code: 0]

在这个教学环境中,对应进程成功退出。

思想:结果必须绑定到正确执行实例与代码版本。所谓验收不是“看见过一次绿色文字”,而是知道它验证了什么。

R12:主 Agent 最终检查

输入 C12:V2、通过测试、子 Agent 针对 V1 的发现与修复证据。

模型动作:

read:再次看最终实现和新增测试。
bash:git diff --check 与必要的最终diff核验。
get_goal:读取当前Goal的精确id与revision,供下一R13使用。

输出 O12(教学):

最终V2保留权限检查、筛选和拒绝超限路径。
金额格式与新测试一致。
CSV writer仍处理结构转义;约定公式前缀策略已覆盖。
diff --check通过;无commit/push动作。
get_goal:G-main,revision=1,phase=active,roundsStarted=0。

思想:子 Agent 审查的是 V1,不能把它的结论当 V2 的自动认证。父 Agent 必须对修复后的最终状态负责。

R13:关闭执行状态,不伪造完成

输入 C13:验收证据齐备,本例没有仍相关的运行中 job 或子任务。

模型动作:

update_goal:使用上一R12的get_goal返回,G-main 当前id、revision=1,action=complete。
todo_write:提交全部完成的完整列表。

输出 O13(教学):

Goal:revision=2,phase=complete,roundsStarted仍为0
Todo:全部completed

如果中途另有目标状态变更,就必须重新获取 revision,而不是死用 1。

思想:显式关闭继续意图。完成状态本身不是证明,前面的工具证据才支撑它。Goal cap 3 不是“最多执行 3 个 R”。

R14:最终回答,结束 T-main-1

输入 C14:当前有效 context 包括目标、计划、变更、失败、审查、修复、通过与完成状态。

模型输出 A14:

已实现CSV导出,复用原权限与筛选逻辑,超10000条整体拒绝。
金额元两位、Asia/Shanghai、CSV结构转义和约定前缀处理已落实。
第一轮发现金额失败,复核发现公式风险,均已修复。
相关测试12个通过,最终diff检查通过。
未访问生产,未提交推送;生产数据库和真实浏览器下载未实测。

这里的“未覆盖范围”是重要输出,不能删去以显得更完美。

Harness 处理:记录 assistant message,先写 step/end 并释放本Step的toolSet,再检查 agent/turn-stopping。该扩展点若新增next-step输入,Turn仍会继续;本例没有新增欠账,才写 turn/end 并变为空闲。Goal 已 complete,故无自动 Goal round。

思想:系统收敛于可说明的产物和证据,而不是无限继续。

依据:工具执行与后续请求分支、计划审批与 pending exit、Goal 工具权限、Jobs 等待和通知、后台Shell退出状态映射、Job status渲染。


 

6. 子 Agent 的独立轨迹与可见范围

6.1 Spawn 创建时传了什么

在 R7,父 Agent 传的是:

parent身份:S-main
子名称/描述:csv-reviewer / CSV只读复核
自包含任务prompt:R7中的完整委派说明
初始cwd:/workspace/orders-demo
默认模型选择:沿用父适合的选择
preset:沿用相应父preset revision,建立独立scope

这些创建参数不是全都作为聊天文字发送;身份、权限、cwd 等通过运行时与 context 贡献正确公开。

6.2 第一份子 Context

子system:它的persona、工具指导等有效sections
子user:自包含审查任务prompt
子user:由自身插件重新发现的适用指导I_child
子user:身份、目录、固定权限等D_child
子user:自身Skill目录K_child
子tools:该scope实际准入集合

不存在一项“把 C7 完整复制过去”。Spawn 不继承父聊天;子知道批准计划是因为委派 prompt 告知,而不是偷看了正式审阅结果。

它可以独立读取共享工作区的 V1,所以“没有父聊天”不等于“看不到父写的文件”。

6.3 B1:加载 Skill

输入:子任务、指导、目录。

LLM 判断:任务与 csv-export-guide 匹配,先加载完整正文。

输出:子 Session 自己的 Skill tool-call 和 tool-result。

父已加载正文,并不意味着 fresh 子 Agent 自动继承那份父工具结果。子必须自行加载,或者父在 prompt 中明确提供足够方法摘要;本例采用自行加载。

6.4 B2:读取 V1 并审查

输入:子 Skill 正文、任务和项目约束。

动作:读取三个实现文件和相关测试;不编辑、不提交、不过问生产。

输出:它自己 Session 中的阅读结果。

思想:局部材料留在局部上下文。共享文件是外部状态,同一时刻读到哪个版本需要明确。

6.5 B3:形成最后回答

输入:代码证据和 Skill 检查项。

输出:前述 B_child 文本,包含发现、位置、建议测试和范围限制。

它没有调用额外工具,自己的 Turn 收敛;subagent manager 收集本次结果,按 parent delivery 通知父 Agent。

不会自动返回的内容:

  • 全部子工具调用与原始文件片段;

  • 所有中间 assistant 输出;

  • 模型内部未公开推理;

  • 它执行环境中的任意变量和对象。

若父需要原始证据,可以要求结果包含必要片段、读取共享产物,或使用合适的历史查询接口;不能默认父已经看见全部。

6.6 父子可见内容对照

内容

父lead

Spawn子csv-reviewer

原始U0与澄清回答

有

只有委派prompt重述的部分

正式Approve工具结果

有

没有自动复制,prompt中说明已批准

父Skill正文结果

有

不自动继承;B1重新加载

共享文件V1

可读

可读,B2实际读取后进入context

父Goal/Todo详细记录

有相应状态/结果

不自动复制,也不应替父控制根Goal

子B2完整读取结果

不自动收到

有

子最后审查结论

收到完成通知

自己生成并记录

后续V2结果

R9后有

本次已结束,不自动获得

6.7 只读任务不等于自动只读权限

当前 in-process 子 Agent 权限在开始时固定,不能在子 Session 内部提权;需要审批的操作会自动拒绝,超范围应报告父 Agent。

父的 agent-local tool restriction 不会原样复制到新 scope,但这不等于权限逃逸。父来源和文件权限根、固定委派政策仍有专门管理。

本例“只读复核”还包含 prompt 行为要求。若部署需要强制仅能读取,应另设实际工具守卫、preset 或文件权限,而不是把一句只读当 OS 保证。

6.8 如果 R7 改用 Fork 会怎样

Fork 的种子截到父最后一个已完成 turn/end,不包含当前 in-flight Turn。

本例从新 Session 开始,R1—R14 都还在第一次 T-main-1。因此在 R7 调 fork,父没有已完成 Turn,种子是空。 它不会自动获得本轮 Plan、Approve、Skill 和文件工具历史。

若父此前完成过 T-main-0,Fork 会包含那个已完成前缀,再加本次子任务;当前 T-main-1 新事实仍必须写入 prompt。

普通 UI 的 Session fork 与子 Agent fork-provider 是不同操作,不能把它们的复制边界混用。

6.9 消息与等待的补充

  • send_message:确认 inbox 接受,不等回复;需要回复还要接收后续输入。

  • wait_agent:等调用者自己的 next-step inbox,不等任意 Agent 状态或任务板。

  • interrupt_agent:只确认停止请求接受;local 当前 Turn 停止不自动停止后代,external 不能续问。

  • inactive:只是现在不执行,不是“审查无错误”的证明。

主线只用普通完成通知,没有安排额外 follow-up 消息。完成通知不穿透正在运行的模型请求,也不因到达就让R8的job等待即时重新推理;本例它排在R9的边界消费。

若采用另一种调度,父已经空闲,通知可能唤醒一个只含通知来源的新Turn。那不等于自动Goal round,也没有本例T-main-1中的直接用户authority;要complete Goal,仍需当前直接用户或匹配的Goal round,不能只依赖旧聊天里曾有人类输入。

依据:Spawn seed 与默认选择、Spawn 可见内容与父结果、Fork 种子源码、固定委派权限、控制工具。


 

7. 每次模型请求的 Context 增量账本

7.1 一眼看到模型为什么改变行动

下表省略按条件出现的runtime/独立时间快照更新、内部控制日志和 provider 专有 framing,只记录教学主线的语义新材料。时间注入不是每Step必有。

请求

已有背景

本轮新增输入

模型输出

为什么转入下一步

R1

S_plan、U0、I、D、W、K、工具Schema

首次任务与方法目录

Skill load + glob

有正文与路径才能探索

R2

R1有效历史

A1/O1:Skill正文、候选路径

grep/read

获取真实实现

R3

项目证据

A2/O2:权限、字段、现有测试

ask_user_question

上限策略属于用户取舍

R4

需求+证据+方法

A3/O3:整体拒绝选择

exit_plan_mode

正式批准才实施

R5

已批准计划

A4/O4 + S_execute

create_goal + Todo

建立可持续执行状态

R6

方案与状态

A5/O5:Goal与进度

edit实现

把意图变成代码V1

R7

V1

A6/O6:编辑成功

spawn审查 + 测试job

编辑成功还不足验收

R8

执行实例

A7/O7:名称与job ID

job_output

收集真实测试结果

R9

V1与目标

A8/O8 + B_child:失败、审查

修金额、公式策略和测试

新证据要求修正

R10

V2

A9/O9:修复完成

第二次测试job

V2需要新验证

R11

第二job

A10/O10:J-test-2

job_output

正确绑定执行结果

R12

通过证据

A11/O11:12 passed、exit0

最终read/diff + get_goal

局部通过不替整体复核

R13

最终V2

A12/O12:验收证据、最新Goal

complete Goal/Todo

停止后续继续资格

R14

全过程有效历史

A13/O13:完成状态

最终交付文字

无剩余动作,Turn结束

7.2 C2 不是只发新工具结果

常见误解是第二次只发一句 Skill 或文件返回。一般不是。

在没有压缩的教学阶段:

C2.messages ≈ C1的有效消息
            + A1(含工具调用)
            + O1(配对工具结果)
            + 必要的动态context更新

工具Schema仍作为本 Step 输入。LLM 是在保留的需求和指导之下阅读新证据,不是每次失忆地只看最后一行。

7.3 C9 的逻辑快照

{
  "format":"teaching-logical-snapshot-not-provider-wire",
  "controls":{"provider":"demo-provider","model":"demo-model","reasoningEffort":"medium","maxTokens":8192},
  "effective_system":"S_execute",
  "retained_message_groups":[
    "U0-task、I、Skill目录与已加载正文",
    "项目read/grep证据",
    "上限澄清选择",
    "正式计划与批准结果",
    "Goal/Todo工具返回",
    "V1编辑调用和结果",
    "子Agent启动名称与J-test-1",
    "测试失败:金额格式不符",
    "csv-reviewer完成通知:公式风险"
  ],
  "tool_schemas":"T_9,本Step实际准入集合"
}

这个 JSON 刻意不是实际 API request。要重建真实请求,应按 Session 顺序调用派生器,再交给 adapter,不是把这些字符串分组直接当 wire messages。

7.4 哪些状态不会自动全文拼接

运行时保存的东西

模型何时看见

原始日志中所有事件

不是全都看见;由surface及投影筛选

Goal/Todo内部事件

通常通过工具返回或状态context,不自动全文事件JSON

工具函数实现

不作为Schema发给模型,模型只见声明

上游认证key

用于认证,不应变成prompt文本

未读取源文件

不因存在于磁盘而自动看见

子完整Session

spawn父不自动收全文,只收结果/消息

文件中的新版本

实际读取/注入后才能成为模型观察

已遮蔽历史

不再整体进入当前请求,原日志可另读

7.5 每个 Step 都准备,但不是所有内容都反复新增

  • 工具准入和prompt assembly是 Step 准备动作。

  • 稳定系统提示无须每次新增一条。

  • 不变指导/Skill目录有可见状态和digest检查,不必重复注入同一基线。

  • 动态runtime context在变化或缺失时协调;旧snapshot可仍保留在历史,由新快照的supersedes语义说明当前事实,不是每Step都删除旧runtime。

  • 独立时间消息按refreshIntervalMs条件更新,默认10分钟;它与runtime snapshot不是一个生产者。

  • request/header 在初始、恢复、配置/工具变化或新系列等条件下记录,不是每次重复同一JSON。

  • 当前消息在每次 API 输入中仍可能重复计费,日志没有重复append不等于API没有重复输入。


 

8. 工具执行到底发生了什么

8.1 用 R7 的测试命令拆开

模型输出:Bash 工具调用意图,不是进程已经运行。

输入检查:工具名字在 T_7 中吗?参数符合 Schema 吗?caller 是哪个 Agent?当前信号是否取消?

执行管线:

记录 tool/call
→ pre-execute:允许/拒绝/请求审批
→ monotonic guards:不能被后续重新放宽的否决
→ execute wrappers:期限、观测等
→ 工具body
→ 内容准备和post策略
→ finalizeContent
→ frozen final result
→ 记录tool/result

真实参数校验和批次调度在相应入口发生;上图展示主要策略与结果流程,不冒充完整函数调用栈。

8.2 Shell、实现、模型入口在这里怎样接起来

LLM 的 bash tool-call
→ tool-bash 消费者
→ ctx.shell 统一执行接口
→ 当前配置的 shell backend
→ subprocess / OS 执行
→ stdout、stderr、退出状态

配置本地实现时会使用本地 Bash 能力;配置沙箱后端时还会准备 confinement。不能根据工具名为 bash 就认定所有部署都直接、不受限地调用同一个 bash-local。

普通 Bash 每次新 shell;workdir 决定这一次的执行目录,之前的一次 cd 不自然延续。

8.3 工具结果如何回到下一次模型调用

执行端返回canonical value
→ 生成模型可见内容与展示元数据
→ 日志记录tool/result
→ 下一Step的deriveMessages包含对应结果
→ LLM根据结果继续

渲染文本、UI card 和程序调用者的 canonical value 是相关但不同的层。打码UI文本不是从程序内彻底抹掉值。

8.4 为什么必须配对

模型提出的 tool-call 有关联ID,后续 result必须正确对应。一次调用没有结果,会影响继续、恢复和协议合法性。

若操作开始但结果未可靠提交,运行时不能自信地说“没发生”,会保留 unknown outcome 等恢复信息。

8.5 Skill 与 Bash 的不同

  • Skill load 返回程序性方法知识,本身不完成 CSV 实现。

  • Bash body运行真实进程,可以改文件或产生外部副作用。

  • 二者都可以表现为工具调用与工具结果,但安全风险和职责不同。

所有工具都叫tool,不意味着它们都是纯函数。

依据:工具管线、工具 canonical 与rendered区别、Bash输入输出与后台。


 

9. 同会话继续、恢复和跨会话检索

9.1 变体 A:不是新Session,而是已有当前历史

假设 S-main 此前有两轮已完成消息:

用户:订单金额字段单位是分。
助手:后续导出应除以100显示元。
用户:导出时间使用上海时区。
助手:采用Asia/Shanghai。

下一 Prompt 的请求通常会带这些仍在当前surface中的消息,再加新输入和必要context。

它不是先问向量库“最相关的两句话是什么”。这是会话历史的确定性派生与保留。 当然,长历史压缩后可能只带摘要,而非所有原文。

9.2 变体 B:重启后恢复这个Session

session persistence读取合法日志
→ 构造当前逻辑Session并修复需要的中断配对
→ 恢复surface和模型选择等状态
→ 挂当前preset及服务
→ 后续请求重新派生messages

读取旧 Session 数据不是重载 LLM 隐含脑状态。恢复也不保证文件、外部进程、提供方cache都还在。

9.3 变体 C:明确引用另一个Session

用户从UI显式引用旧会话,运行时捕获一个有预算、不可变、不受信任的文本快照,跟随引用消息进入目标历史。

这是“指定来源后制作快照”,不是默认全库搜索;源以后变化也不会改写已捕获内容。

9.4 变体 D:开启历史搜索工具

当前默认 base/Web:

session-query-sqlite:
  path: ':memory:'
  openAt: never

这是易读字段示意,不是可直接粘贴的完整Cordis patch。

若部署另行启用全文搜索和实验性模型历史工具,可出现:

LLM:调用session_search寻找过去CSV方案
工具:返回候选会话、片段
LLM:继续session_event_read读取精确证据
工具:返回具体事件
下一请求:把检索结果作为工具历史纳入

这里才是真正的“检索历史再加入当前context”。也要区分:当前SQLite方案是全文token/phrase搜索,不是自动embedding语义召回。

9.5 变体 E:外接记忆MCP

LLM:查询某项目长期约定
MCP:返回已保存事实和来源
LLM:核验范围与时效
下一请求:工具结果进入context并影响方案

是否写入、如何召回、embedding、冲突和遗忘由所接服务与指导决定;DSH随附记忆参考配置默认关闭。

9.6 一句话辨别这些“历史”

操作

本质

当前聊天继续

继续同一surface

旧聊天resume

从持久化恢复同一逻辑历史

子Agent fork

捕获父已完成Turn前缀作为seed

明确会话引用

指定旧内容的有界快照

session_search

按需全文检索,需启用

记忆MCP query

外部知识服务召回,能力由提供方决定

依据:默认历史搜索配置、Web覆盖、模型历史工具、会话引用、第三方记忆。


 

10. 历史过长时的裁剪与摘要分支

本主线没有触发压缩。下面是一条条件分支,不计入前面的R1—R14。

10.1 输入

某后续Step准备时,累计文件结果、工具Schema、消息与输出预留使压力达到策略阈值。

本例教学容量如果采用默认政策:

W = 131072
O = 8192
B = 65536
阈值T = floor(min(W×0.8, W−O−B)) = 57344

这是基于假设容量的计算,不是测得你这次会话占用了57344 tokens。

10.2 第一步:计量与确定性裁剪

处理:token meter根据当前surface、路由与usage估算压力;有pruner时先裁剪较早过大工具结果。

输出:保留头尾等受控内容,记录替换,重新计量。

思想:先移除高成本低必要性内容,可能无需额外模型摘要。Pruner不做语义理解,也不保证中间段没有重要信息。

10.3 第二步:辅助摘要调用

仍然过大时:

输入:选择的较早安全范围、系统头、相应工具历史与摘要要求。

处理:compaction-basic直接调用摘要模型,不是新建另一个完整通用子Agent;保留文本摘要,检查确实缩减、配对边界合法等。

输出:记录摘要与一个user-role checkpoint替换,近期尾部保留。

压缩前:S + I + U0 + 很多A/O + 最近失败与修复
压缩后:S + checkpoint(目标、事实、进度、约束) + 最近失败与修复

10.4 后续请求输入

原始日志L:仍保存那些旧A/O及替换证据
当前surfaceH:摘要遮蔽旧范围
下一请求Q:deriveMessages看到摘要+近期,不再整体发送被遮蔽原文

摘要有损,不等于可靠事实认证;需要精确参数时仍可以重读证据。

10.5 费用与缓存

  • Token计量、确定性裁剪:不调用模型。

  • 默认摘要:额外模型调用,可能多次;不保证复用cache。

  • JSONL的Zstd:磁盘编码,与语义摘要不同。

  • KV cache:前缀计算复用,不负责跨会话知识存储。

切换provider/model也会检查目标压力;只有压力检查或压缩失败等对应 MODEL_SWITCH_COMPACTION_FAILED,不是所有模型准备错误都用这个码。

依据:压力公式与流程、辅助摘要机制、Token meter。


 

11. Goal、结束 Turn 与自动继续

11.1 本例为什么没有Goal round

R5创建Goal,R13完成Goal,R14结束Turn。中间所有工作仍是直接用户请求的T-main-1。

Goal记录:roundsStarted=0
主模型调用:R1—R14共14次
矛盾吗?不矛盾。

Goal轮数只计被接纳的自动目标轮次,不计所有Step。

11.2 如果模型阶段性停下但Goal尚未完成

假设另一个合法轨迹中,主Agent已经阶段性收敛,Goal还active:

输入:active+armed目标、剩余round预算、Agent及相关progressing后代空闲。

处理:driver排入一个goal-sourced用户输入,包含目标和轮次;经过revision校验与pre-step准入。

输出:新Turn的新请求系列,继续同一个Session。

T-main-1结束
→ 自动Goal round 1输入
→ T-main-2继续

不是fresh子Agent重跑,也不是Loop无条件递归调用模型。

11.3 Jobs也是另一条继续来源

后台完成可在Agent忙时进入后续Step,空闲时默认唤醒新Turn。因此不能把每个新Turn都归因于Goal,也不能保证先等Goal再等job。

11.4 恢复后不会自行重新武装

Session resume/fork后已有active Goal是disarmed,需要人类授权恢复继续。当前模型工具对phase=paused还有额外拒绝,需要用户操作;active-but-disarmed重新武装是另一情况。

11.5 完成判断是什么性质

目标完成由模型在允许的身份下报告,当前driver没有独立evaluator证明全部需求满足。本例把测试、diff、约束检查放在前面,才让complete有根据。

Goal cap不是token、金额或时间预算;难度高或还有有用工作不能随意写blocked。

依据:Goal driver条件、Goal限制、Goal工具paused限制。


 

12. 失败、取消与不能保证的事情

12.1 模型API失败:Attempt,不是重复用户Prompt

如果R2第一次API attempt失败,可进入有限retry策略。当前Step保留已组装内容与准入工具,不重跑整个pre-step,不把同一U0再录入一次。

失败partial stream通常记录为assistant/attempt用于诊断,不当作成功assistant消息进入后续模型历史。重试可受已落地surface变化影响。

12.2 工具失败:反馈,不一定结束Turn

合法工具调用发生业务错误或命令非零退出,通常返回结构化/文本错误给下一请求;模型可以根据结果修改策略。

这与插件抛出未经处理异常、模型认证失败等不同。不要把所有错误都当成一次工具可自行修复的问题。

12.3 Unknown outcome:不能盲重试

TOOL_NOT_STARTED:没有开始记录
TOOL_OUTCOME_UNKNOWN:有开始记录,无可靠结果
ABORTED_BEFORE_DISPATCH:尚未分发即取消

“删除文件”“发邮件”“支付”结果未知时,应先核验外部状态或用幂等机制,不能像只读grep那样原样重试。

12.4 权限拒绝不是换个写法继续

模型指导、计划批准、子任务描述都不扩大实际文件权限。真实沙箱拒绝应由授权渠道解决,不能换路径、shell或插件偷偷绕开。

子Agent固定scope不能自己提权,必须把限制报告父Agent。

12.5 取消不是回滚

当前合作式工具、进程cleanup和权限层管理停止;已写文件、已发送网络请求和已提交外部动作不会自动撤销。

停止请求接受、工作quiet、持久化完成是不同时间点。

12.6 上下文与记忆也有边界

  • Summary可能遗漏或失真。

  • 旧文件观察可能过期。

  • Skill正文不是模型新增权重。

  • 删除一份笔记不等于清除日志、fork、spill、引用快照和MCP副本。

  • 运行时有日志不意味着断电或存储故障下绝对无损。

  • Sandbox和审批降低风险,不构成完整安全审计证明。

依据:请求重试、循环恢复、安全说明。


 

13. 谁负责决策,谁负责确定性处理

问题

主要负责者

背后的思想

Prompt归哪个Session

UI/Host/Session controller

身份与执行生命周期明确

/plan是否选中

命令与Plan服务

控制信息不靠LLM猜

当前模型参数是否可用

adapter prepareCall

协议与默认值由所有者校验

哪些工具可调用

registry、scope、条件准入

能力与实际执行一致

读哪些文件

LLM提出工具参数

灵活探索,但结果要核验

指导与目录如何加入

指令/Skill/context插件

来源、预算、刷新责任分离

是否自动搜其他会话

配置及检索消费者

不是主循环隐含动作

具体Plan是什么

LLM

基于证据生成方案

是否批准实施

用户审阅

人类取舍与授权

工具动作可否执行

policy、approval、guard、sandbox

不让语言承诺替代强制约束

编辑后的正确性

测试、复核、验收与模型判断

真实证据纠正推断

是否委派

LLM或编排消费者

可分任务减少单context负担

子看到什么

seed规则、子scope、prompt、独立注入

共享文件不共享脑

长历史如何处理

meter、pruner、compaction

有界context而非无限记忆

是否继续新Turn

inbox、Jobs、Goal等driver

继续需要具体输入与策略

最终任务完成

模型报告,证据支撑,用户可验收

当前无自动全能认证器

四个设计思想贯穿全部流程

  1. 决策和执行分离:LLM生成意图,工具及环境产生真实结果。

  2. 状态和视图分离:日志保存事实,surface决定当前可见内容。

  3. 方法和事实分离:Skill教怎么做,read/test告诉现在是什么。

  4. 局部推进和整体收敛分离:子Agent负责局部,Lead负责最终一致性与验收。

可靠Agent不是“总能第一次猜对”,而是知道当前依据是什么、能安全行动、能听取失败、能恢复推进,并能说明完成的证据与限制。


 

14. 实现入口与核验来源

下面源码路径均指向本机当前检出,不指向教学项目。日期固定在本文基线;代码升级后应重新核验。

要追踪的动作

推荐源码/文档

整体Turn flow

Architecture

Web普通Session命令

Session commands

普通Prompt Host入口

Session controller prompt

UI命令接管与Remote执行

UI commands

/plan与模式服务

Plan mode

claim与工具/prompt准备

preStep

Turn循环与结束

turn

prepare、录入、stream

step

工具批次与继续分支

成功响应与tools

请求快照构造

buildRequest

prompt assembly

System prompt

runtime context协调

Runtime context

指导baseline与预算

Agent instructions

Skill目录与正文

Tool skill

工具准入

Tools条件准入

工具policy顺序

Pipeline

持久与surface差别

Session

正式批准后续Step

Plan review实现

Spawn初始数据

Spawn backend

Fork已完成Turn边界

Fork backend源码

子权限

Delegation scope

消息、停止、wait

Subagent control

Bash进程与后台

Tool Bash

Job结果与唤醒

Job tools

Goal自动继续

Goal driver

Goal工具权限

Goal工具

默认FTS关闭

Base配置

历史查询工具opt-in

Session query tools

指定会话快照

Session reference

可选外接记忆

MCP memory

压缩阈值

Compaction basic

默认摘要器

Summarizer机制

安全与支持边界

Safety


 

15. 用 12 句话复述整条流程

  1. 用户Prompt先进入某个Session与模式控制入口,不是立刻裸调用模型。

  2. Harness领取输入,确定模型与当前工具权限。

  3. prompt插件组装系统指导,context插件注入环境、适用规则和Skill目录。

  4. 当前Session通过surface派生历史,默认不是从所有旧聊天做相关性检索。

  5. adapter准备成功后,记录模型可见输入并冻结本次请求。

  6. LLM根据目标和材料选择读文件、加载方法或问用户,而不是运行时替它写好计划。

  7. 正式计划审阅由用户批准,下一Step实施;普通问答同意不等于Plan批准。

  8. 工具执行真实读改测,返回结果进入下一次context。

  9. 子Agent收到自包含任务和自己的context,不自动共享父全部聊天;结果通过通知回到父。

  10. 失败和审查意见改变LLM下一步行动,促使修复再验证。

  11. 长历史可以被裁剪或摘要,原始日志与当前输入仍然是不同层。

  12. 最终由Lead收集正确版本的证据,关闭目标和进度,解释完成与未覆盖范围,然后收敛。

一个Prompt并没有变成一个神奇的“大Prompt”。它被运行时组织成多次有上下文、有动作、有反馈、有状态和有验收的模型决策。

 

posted @ 2026-11-11 10:52  黎歌哈  阅读(0)  评论(0)    收藏  举报