Harness 工程 全部章节

第4章 运行循环与任务状态

第3章已经有一个能创建摘录文件的循环。但循环不是反复发送消息的另一种名称。每次再次请求模型、开始工具动作、等待结果或宣布停止,都要有依据。模型说“下一步创建”,只能说明它提出了选择;文件存在,只能说明某个对象可以被观察。系统还要知道这是不是当前任务允许的动作,结果属于哪次请求,以及完成判据是否仍然成立。

本章沿同一套 Python 3.11 与标准库实现,解释这些依据怎样形成。建设重点不是增加状态名,而是让每个判断都能指向相应材料。当前程序保留同步模型请求、固定工具与串行业务调度。不把已有账本说成自动恢复系统,也不把粗粒度控制边界说成实时控制服务。

4.1控制状态与外部动作事实

控制状态是程序对下一步合法行为的明确约束。等待模型响应时,不能同时把尚未收到的提议当作工具参数;写入结果未知时,不能因为模型又说了一次创建就重新写入。控制状态不是模型对工作的自述,也不是界面上一个用于显示的进度百分比。

最小形态只需回答三件事:当前在等谁,已知哪些结果,还有哪些动作能够启动。一个同步程序可以用字段、条件分支和异常表达它们,不必先引入状态机框架。状态机是把状态、可接受事件与合法转移显式组织起来的表示方法。它不是现实环境的完整复制,也不保证外部动作按预期发生。最小状态机可以是一张转移表及实际执行这些条件的代码。

第3章没有统一的 RunState 类。Harness 中的 request_pending、response_state、protocol_status、effect_in_flight,加上当前文件、验收结果和停止原因,共同承担控制责任。Harness.__init__ 初始化这些字段,Harness.loop 与 Harness.run 更新它们。解释现有系统时,应沿这些实际字段说明,不要先画出一套更漂亮的状态图,再声称源码已经实现。

这些字段也不能彼此推导。响应已经持久保存,不等于协议解析通过;协议通过,不等于当前授权允许执行;文件已经创建,不等于运行正常结束。把它们压成一个 done,会丢失停止时最需要的信息。可读状态可以合并展示,但合并规则必须保留原始区别。

建设时先列出禁止行为,再安排转移。尚未完整解析响应,不得调度动作。写前记录未确认,不得执行创建。授权修订不匹配,不得启动旧请求中的工具。验收未通过,不得宣布产物完成。这样状态的意义来自可执行规则,而不是来自名称。

状态只回答可以做什么,不回答凭什么。外部动作事实是可靠观察或回执支持的动作情况,例如请求已经提交、创建调用留下了哪些字节、验收在哪个边界通过。它不是模型说“我做了”,也不是程序仅仅进入了名为 writing 的分支。最小形态包含动作对象、关联身份、观察结果、证据位置和所能证明的范围。

事实有形成顺序。写入意图证明程序准备提交哪些内容,不证明文件已经写好。写入回执支持工具已经完成其声明步骤,不证明当前文件从未变化。重新读取文件并比较预期字节,支持验收边界上的内容结论,不证明未来每次读取仍然相同。不同记录应保留不同谓词,不能都叫“完成事件”。

第3章的 Harness.tool 在创建前写 write_intent,完成创建后写 write_result,随后记录 artifact_verified。每条记录都有自己的意义。文件写完而结果记录失败时,控制状态必须保留未知,不能仅凭内存中曾经返回的值认定可靠成功。

未知是对证据缺口的描述,不是对外部世界的第三种物理状态。文件可能没写、部分写了或全部写了;程序没有足够可靠材料区分这些情况,就不能选择其中一种作为事实。停止自动调度不会消除缺口,却能避免在缺口上继续增加副作用。

事实还包括明确拒绝。若固定工具在执行前检查到来源不合法,并按契约返回拒绝,可以记录这项提议未跨过效果边界。若远端只返回模糊的“错误”,则不能直接获得同样结论。事实强度取决于回执契约与发生位置,不取决于错误文字听起来多么确定。

4.2四类材料与关联身份

运行状态 state 是当前控制判断所需的结构化材料。原始记录 ledger 是已经接收的事件及证据关联。模型上下文 model context 是本次实际提交给模型的输入。跨任务记忆 memory 是为以后任务保留的、有适用范围的信息。它们可以使用同一存储设施,但不能因此相互代替。

运行状态不是全部历史,最小形态是当前修订、在途对象、已完成对象与允许的下一步。账本不是新动作的执行许可,最小形态是有顺序和关联身份的事件记录。上下文不是动作事实数据库,最小形态是符合所选接口的消息及能力说明。跨任务记忆不是恢复旧任务的资格,最小形态是一条注明来源、范围和适用条件的可复用记录。

“短期记忆”需要先消除歧义。有人用它指近期消息,有人指当前任务的资料,还有人指压缩后的工作摘要。这些都可以服务本次判断,但这个称呼本身没有增加事实强度,也不要求 harness 必须建立独立模块。当前任务材料可以在内存中,也可以通过工具存取。选择存放位置前,先明确它究竟承担上下文接续、证据保存还是控制状态。

摘要写“已经读取两份材料”,不能代替两次读取结果及其版本。更不能证明材料进入了产生创建提议的请求。第3章的 Harness.loop 从实际请求载荷推导 disclosed_sources。这比从模型自述或一个可变的“已读”集合推断更窄,也更可核对。

建设时给每类材料指定更新者和读取者。工具观察先成为可关联的结果,可靠记录后才能支持状态更新;模型上下文按本次判断需要组装。长期可复用信息是否写入,另按第8章的条件处理。不因摘要更短就替换账本,也不因账本完整就把全部记录塞进每次请求。

四类材料要能互相对应,靠的是身份。request_id 标识一次模型请求,它回答模型选择是基于哪份输入产生的。tool_call_id 标识模型消息中的一项调用提议,用于配对调用与工具结果。action_id 标识一项需要跟踪的业务动作。attempt_id 标识为同一动作进行的一次实际提交尝试。它们不是四种可互换的日志编号。

最小关系是一项调用提议属于某次请求;如果提议通过检查并进入创建,创建动作关联该请求与调用;如果以后允许重试,同一动作的每次提交另有尝试身份。请求重发不天然意味着同一个动作,工具调用编号相同也不天然意味着外部服务只执行一次。身份提供关联,业务语义仍由程序建立。

当前实现有运行、模型请求、模型调用和创建动作身份,但没有独立的 attempt_id,因为它不自动重试创建。write_intent 绑定 action_id 与 request_id,调用结果则绑定 tool_call_id。两类记录通过同次运行及请求处理顺序核对。若扩展为更通用的动作记录,应显式保存这条关联,而不是依赖同名工具或相邻时间戳猜测。

还需要绑定版本。目标与授权修订回答请求依据是否仍然有效;来源 hash 回答摘录依据是哪份字节;工具映射回答调用使用了哪份契约;产物版本回答观察对象对应哪次创建。版本不是装饰字段。相同来源名、工具名和路径可以指向变化后的对象。

本章使用这些身份解释当前运行,不据此设计跨机器接手。持有旧 action_id 不代表可以重新执行,拿到旧请求快照也不代表已经取得恢复资格。跨重启怎样查询尝试、核对旧效果、阻止旧执行者,由第11章建立条件。

4.3事件接收与生效条件

事件是系统收到的一项变化通知、结果或控制输入。接收一项事件,除了收下材料,还要核对来源、关联对象与有效版本,并决定它能改变哪些本地事实。事件不是收到后就必然生效的命令,接收也不等于把整段文本加入消息历史。最小的接收步骤需要指出输入类型、核对条件、记录位置与允许的状态变化。

第3章已用 Coordinator.accept 接收用户控制输入,并在同步响应后的粗粒度边界检查修订,不提供实时撤销。

建设接收规则时,对每类事件分别回答“更新了什么事实”和“允许哪种转移”。收到响应可以结束通信等待,但不一定结束协议检查;取得工具结果可以增加动作观察,但不一定满足当前目标。下面的矩阵列出这些区别,其中旧结果保留规则是扩展要求,不是当前程序已有的迟到结果处理器。

事件可以更新的事实下一步调度条件
当前响应已收到并可靠保存保存响应快照,确认不再等待这份响应;协议仍未验证只进入完整解析,不能执行其中的调用
已收到的响应未通过协议检查保留收到事实,记录协议拒绝及原因停止处理该响应,不抽取部分调用执行
当前响应通过完整解析记录协议通过;工具提议仍不是已执行动作当前修订有效、整批额度足够且接收记录成功后,才进入逐项工具检查
可核对关联的旧请求结果返回可按原请求与原修订保留观察,不标为当前结果不据此推进当前任务;适用性和继续资格须另行核对
工具明确拒绝且未产生效果记录该调用的拒绝原因,不改变既有产物事实可纠正的拒绝在当前许可与剩余预算内接续;未知工具等停止整批的拒绝不能这样处理
目标变更、撤权或取消已确认更新修订与停止条件,保留此前动作事实旧请求不得启动新动作;不自动转入新目标或撤回旧效果

“收到”与“可执行”因此必须分别表示。在 Harness.loop 中,响应保存后仍要经过 parse_response、当前修订和批次预算检查,随后才能接收助手消息。协议通过也只使提议进入下一道检查,不使工具参数、授权或前置条件自动成立。只更新一个 response_ready,会让通信事实被误用成执行许可。

旧结果则需要保留原来的身份与版本。即使结果内容真实,也只能先说明旧请求观察到了什么,不能覆盖当前来源、当前验收或当前待办条件。当前程序遇到失效修订直接停止;以后若允许旧观察入账,仍要把“允许存证”与“允许继续调度”分成两个决定。

每条转移都应只修改它有依据修改的部分。协议拒绝不抹去响应已收到的事实,撤权不抹去文件已创建的事实,成功回执不恢复失效授权。事实记录失败时,不能先修改成可执行状态再等待以后补账。状态分离的作用就在这里:限制一次事件能改变的结论,而不只是增加字段。

4.4串行业务调度与工具内部并发

串行业务调度是由一条明确的控制主线决定哪些业务动作开始,以及何时接收它们的结果。它不是“只能有一个操作系统进程”,也不是要求所有工具内部只能用一个线程。最小形态是一个调度责任者、当前有效请求和按规则处理的动作序列。

工具可以在内部并发读取多个可信对象,也可以调用一个管理后台工作的服务。调度者仍需知道这项工具调用覆盖了哪些子工作、何时算结果完整、失败是否可能留下效果,以及取消能影响什么。并发改变了执行契约,不能只把同步返回替换成一个后台线程,就保留原有成功含义。

第3章的 Harness.loop 按响应中的调用顺序执行工具。整个批次先完整解析,额度不足则在动作前停止。业务参数拒绝与结构错误不同:合法可解释的提议可以得到拒绝结果,后续调用仍按规则处理。未知工具则停止后续批次。已有动作不会回滚。

这里存在两种顺序。程序可以先完成读取,再执行创建;模型却只有在下一次请求中才得到读取结果。同响应“先读后写”只建立程序执行顺序,没有建立模型的观察与选择顺序。因此创建必须检查材料已进入创建请求,不能只检查本进程刚刚读过。

建设串行主线时,让每个动作经过当前修订检查、契约检查和效果前记录,再把结果交回同一控制入口。这样以后替换执行器,不必同时更改业务判断。若要同时保留多个有副作用的在途动作,就超出了当前单线模型;必须增加关联、资源冲突及接收规则,而不是先把线程启动起来再补解释。

4.5拒绝、失败、未知与取消的转移差异

拒绝表示某项提议不满足条件,通常发生在允许效果之前。失败表示约定结果已知没有成立,但是否存在部分效果仍需另行描述。未知表示证据不足,不能确认动作或结果。取消表示系统不再继续这项运行,不表示此前效果不存在。四者不是一个 ok=False 的四种文案。

要由这些情况决定下一步,需要分别记录四个维度:stopreason、knownfact、currentpermission 和 allowednext。它们分别表示停止原因、已知事实、当前许可与合法下一步,是设计上的划分,不是现有程序中四个同名字段。Harness.run 用停止摘要、动作记录、协调者修订与分支条件承担这些责任。

stopreason 回答为什么不再沿当前路径继续,至少关联停止对象与发生边界。现有摘要的 stop_reason 属于整个运行,工具结果里的 reason 则属于一项调用。schema_error 可以是允许模型纠正的调用拒绝,不必成为运行停止原因;finished_without_artifact 才明确表示本次运行未能按要求结束。混用两个层级,会把局部可纠正问题变成整体失败,或让已停止的运行继续执行。

knownfact 回答已经可靠确认什么,仍不知道什么。它应关联请求、动作、对象版本与证据,不因停止原因改变而删除。如果只有写入意图,无法确认是否提交,就保留意图与效果未知,不能记成未执行;已有创建与验收记录,也不能因后来取消而记成从未创建。未知必须说明缺口属于响应、效果还是记录,不能只留下一个没有对象的 unknown。

currentpermission 回答现在还允许以什么范围行动。它依据当前目标、授权修订与停止条件,不从旧成功结果推导。旧请求的修订已经失效,即使调用参数合法、结果真实,也不能启动新动作。预算则另行限制投入:授权仍有效但请求额度用完,仍不得再请求模型。许可、资源和事实需要共同判断,任何一项单独成立都不足以推进。

allowednext 是程序依据前三类材料及预算算出的合法选择,不是模型写下的下一步计划。局部参数拒绝、没有未知效果、当前许可有效且预算足够,可以形成配对结果后请求纠正。运行已知失败不自动产生重试资格;效果未知只允许停止自动扩大效果并核对;接收取消后停止该运行;预算耗尽后不再投入超出额度的动作。保留核对依据不等于实现了自动恢复。

同一个取消原因可以对应不同事实:一项运行尚未创建,另一项已经留下产物。两者都停止,却要说明不同结果。反过来,同一份历史产物也可以对应不同合法下一步:当前条件仍有效时可以检查本阶段是否已经结束,授权撤回后不能继续旧任务。这样记录,停止不再把事实压成一个失败布尔值,产物存在也不再被误当作继续许可。

4.6无进展的判定依据

进展是当前目标所需的不确定性被可靠减少,或一个经过约定检查的阶段结果已经成立。它不是模型说计划更详细了,也不是工具调用次数增加了。最小进展记录应指出改变了哪个待解决条件,以及这项变化依据什么观察。

读取固定来源的同一版本第一次可以满足材料取得条件;重复读取而没有新增必要信息,不会再次满足一个新的条件。合法参数修正可以消除已知拒绝原因;换一种说法重复无效参数,不能据此累计进度。创建并验收了产物,建立产物条件;正常结束则建立完成条件。不同任务需要不同条件,不能预设工具调用必然是唯一进展。

判断无进展时,先限定一个局部阶段及其可比较对象。例如,在修正已知参数错误的阶段,记录当前错误、契约版本与规范化提议。若这些对象未变,且没有新证据、合法状态转移或可解释的等待,便有依据报告重复尝试。这个判断应说明适用阶段,而不是宣称模型普遍陷入失败。

不能用“N轮没有工具”直接判失败。模型可能正在依据已有材料选择摘录,或者准备正常结束。没有调用工具不等于没有必要判断。反过来,连续调用同一读取工具也不一定有进展。可验证判据需要依赖任务条件,单看消息形式不足以得出结论。

等待也不是无进展的同义词。若正在等待一个契约明确的结果,应该记录等待对象、可用查询方法和等待预算。等待边界到了,可以停止等待或报告未知;不能为了显示进度,让模型不断重新提出同一个副作用。

第3章目前只实现请求次数、工具次数和载荷等预算,没有独立无进展检测器。本章提出的是扩展的判断方法。实现它时,应先记录局部条件变化,再测试重复提议与合法等待,不能把现有 model_budget 改名为 no_progress 就声称已经完成。

4.7历史验收事实与当前完成结果

验收是依据预先约定的条件检查一个具体结果。它不是最后再问模型“是否完成”,也不是从成功日志推导当前文件仍然合格。最小验收对象包括预期内容、实际对象、动作与版本绑定、当前要求,以及检查结论的时间范围。

第3章的 Harness.verify_artifact 已经落实具体检查;这里要区分的是历史验收内容 acceptance 与停止时的交付判断 verified_at_stop,而不是再增加一种验收算法。

acceptance 保留验收得到的内容与绑定关系。后来文件变化、授权撤回或运行未能结束,不会使此前观察变成从未发生;但这份观察也不能证明当前条件仍然成立。因此 acceptance 非空只说明留下过验收内容,不能单独推出当前成功。记录可靠性有缺口时,还要核对相应事件,不能把内存中的内容当作完整持久证据。

verified_at_stop 回答这次停止摘要是否允许把产物作为当时已经核验的结果报告。现有 Harness.run 依据最终 status 生成它:success 与 artifact_created_not_finished 为真,其他状态为假。它不是 acceptance != None 的改名。最终记录失败而状态变成 ledger_unknown,即使还留着验收内容,也不能保留停止时已确认的声明。

这两个为真的状态也不相同。success 表示产物核验与运行结束都成立;artifact_created_not_finished 表示预算停止时文件仍通过当前检查,但模型接续没有正常完成。后者允许报告已核验的部分产物,不允许显示整个任务成功。授权撤回或当前检查失败时,旧 acceptance 可以保留,verified_at_stop 却不能因此为真。为假也不反向证明文件不存在或一定损坏,只表示不能作当前交付声明。

消费者读取这份摘要时应按条件判断,而不是搜索某个成功词:

  • 先读运行的 status、stop_reason 与 known_unknown,确定是成功、部分完成还是存在未确认事项。
  • 再看 artifact 的绑定。字段非空可能只是创建意图与预期元数据,不能仅凭它认定文件已经可靠创建。
  • 当前成功声明要求 status=success、verified_at_stop=true 且 currently_authorized=true;部分完成应明确展示尚未结束,不沿用成功文案。
  • acceptance 与 outcome 用于解释历史验收与产物情况。即使 outcome 写着 durably_verified,也不能越过前面的停止状态与当前资格检查。

这些字段是可信程序在停止边界给出的摘要,不是持续有效的证明。摘要返回以后对象或授权再变化,需要新的检查。费用状态也独立:产物成功不证明总费用已知,运行取消不证明没有计费,缺失 usage 不能补为零。

4.8本章判据

读者不必照搬本章的字段名称,但应该能从一次停止结果反向找到它的判断依据。

  • ☐控制状态是否限制具体的下一步,而不是只展示模型自述?
  • ☐意图、动作回执和当前验收是否分别保留,证据缺口是否仍为未知?
  • ☐运行状态、账本、模型上下文和跨任务记忆是否各有责任,短期摘要是否不能代替动作事实?
  • ☐请求、调用提议、动作及可选提交尝试是否可关联,目标、工具、来源和产物版本是否可核对?
  • ☐用户纠正与结果是否经过明确接收边界,旧结果是否不能自动获得当前行动资格?
  • ☐串行主线是否与工具内部执行方式分开,完整批次解析是否没有被说成事务?
  • ☐拒绝、失败、未知、取消、预算和部分产物是否进入不同处理,取消是否不暗示撤回效果?
  • ☐无进展是否有局部条件与证据,而不是简单统计没有工具的轮数?
  • ☐当前交付是否重新检查对象与有效修订,费用未知是否没有被补为零?

本章没有回答什么

本章没有建立跨重启恢复、自动重试、效果补偿或多个更新者的接手规则。身份与账本为核对提供条件,不足以授予继续资格。这些问题由第11章处理。它也没有定义完整上下文压缩与长期记忆方案,第7至9章分别讨论材料怎样进入、使用、退出和复用。固定工具之外的强制执行边界由第10章落实。

实践落点

实践仍沿用第3章的既有验证。第3章记录的110项基础测试已通过,其中本章运行机制对应 book/v2/test_harness.py 的98项检查,覆盖调用配对、控制变更、未知停止与产物验收。这些检查针对已有固定任务,不证明本章提出的所有扩展都已实现。

新增的39项局部实践测试另有范围。与本章直接相关的旧账本只读对账,可以核对部分记录与字节关联,却不恢复运行、不重新取得当前授权,也不等同当前完整验收。局部实践没有实现显式运行状态机或无进展检测器,不能用这批测试的通过替代对这些扩展的验证。