← 全部极客知识库

工程化 / 大模型应用工程化

13. 搭建最小智能体运行环境:给智能体一个可以持续工作的项目环境

原文备份 · 第 15 / 21 篇 · 查看极客时间原知识库 ↗

本篇目录 · 9 节

来源:大模型应用工程化

上一篇,我们把“导出复习资料”整理成了脚本、Skill 和可讨论的工具接口。现在,你把项目交给一个新的 AI 会话,对它说:“按之前的方法,再导出一份。”

它仍然可能卡住:之前确认的任务在哪里?应该运行哪个脚本?输出目录能否覆盖?脚本显示成功以后,还需要检查什么?如果上次执行到一半,目录里的文件算成果,还是半成品?

这些问题不会因为模型更会写代码就自动消失。模型负责理解和决策,项目还需要提供明确的入口、可执行的动作、可靠的反馈,以及能留给下一次工作的记录。本篇要搭建的最小 Harness,就是围绕一次任务组织这些条件。

你会运行一个不需要模型账户的练习:读取固定教学卡片,导出复习材料,独立验证,把每一步的证据和当前状态保存在一个新目录里。最后,它会明确停在“待人工审核”。

配套:完整工作区 · 下载 ZIP。这是作者编写的参考实现,执行对象是公开教学样例,不是 Kimi 生成代码的实录,也没有连接你的真实问答历史。

一、Harness 到底包住了什么

Harness 在不同产品中的范围不完全相同。讨论 Agent 工程时,可以把它理解为:让模型能够在具体环境中开展工作的外围设施,例如提供上下文、执行工具、收集反馈、记录状态、处理权限和停止条件。

它没有一个“必须安装这些组件才算合格”的统一清单。Anthropic 关于长任务的工程文章就指出,即使给出了清晰的高层目标,Agent 仍可能一次做得太多、留下难以接手的中间状态,或者过早宣告完成;环境准备、明确任务、进度记录和验证都需要专门设计。参考:Effective harnesses for long-running agents。

落到我们的笔记助手,前面学过的内容可以这样组合:

一次任务需要什么 本篇放在哪里 解决的具体问题
目标与完成条件 docs/harness/TASK.md 这次只做固定样例导出,不能顺手改网页
必要上下文 docs/harness/CONTEXT.md 去哪里找事实,不把全部历史塞进会话
可以执行的能力 export_review.py 确定性地生成资料与清单
独立反馈 verify_export.py、verify_harness.py 检查真实产物,不只听执行者说成功
状态与证据 runs/运行名/ 记录哪些步骤发生过、结果是什么
行为边界 AGENTS.md、任务和运行手册 新目录、固定输入、失败停止、人工审阅

这里有两个层次。Kimi Code 自身已经提供模型交互、工具执行等 Agent 运行能力;我们搭建的是项目这一侧的任务环境,让它进入这个项目时能找到路。

配套的 harness.py 也有明确边界:它只是一个固定任务执行入口,按顺序调用已有函数。它不会自己理解新需求,不会挑工具,不会改代码,更不会失败后偷偷请求模型修复。读者可以自己运行它,Kimi 也可以在明确授权后使用它。

这样安排是为了先看清一轮工作的结构。模型如何根据反馈决定下一步,留到第14篇讲执行 Loop。

二、先确认你的起点

解压配套文件,进入包含 harness.py 的 lesson-13 目录。不要进入内层 project 执行本篇命令。

lesson-13/
├── README.md
├── AGENTS.md
├── harness.py
├── verify_harness.py
├── export_review.py
├── verify_export.py
├── docs/
│   ├── STATUS.md
│   └── harness/
│       ├── TASK.md
│       ├── CONTEXT.md
│       └── RUNBOOK.md
└── project/
    └── ...原笔记助手的代码与公开样例

project 的38个文件与第12篇一致,笔记助手的应用模型仍然是 DeepSeek。历史搜索也没有重做。本篇新增的是外层任务组织,不涉及切换应用模型。

先打开任务说明,确认三件事:输入只接受固定教学样例;产物只能进入新的运行目录;机械检查通过后仍要人工对照原文。再看上下文索引,按需要找到对应文件。

本篇主练习只需 Python 3.11 或更高版本、标准库和配套文件。不需要安装 SDK,不需要 API Key,也不需要先登录 Kimi。旧材料中其他练习的依赖要求不代表这个入口也需要它们。

macOS / Linux:

python3 harness.py --check

Windows PowerShell:

py -3 harness.py --check

作者环境的结果如下,读者的版本号可以不同:

{"ready": true, "python": "3.11.8", "missing": [], "watched_files": 14}

这个检查只说明 Python 版本符合要求、14个指定文件存在。它没有证明导出正确,也没有证明文件内容没有语法错误。 程序是否能完成任务,要靠下一步的实际执行来回答。

--check 不创建运行目录。若 missing 非空,优先确认是否解压完整;不要让 Agent 临时编造缺失的规格或样例来凑齐文件数。

三、让一次运行有自己的身份和证据

在同一目录执行第一轮。

macOS / Linux:

python3 harness.py --run run-01
python3 verify_harness.py runs/run-01

Windows PowerShell:

py -3 harness.py --run run-01
py -3 verify_harness.py runs/run-01

第一条的预期结果:

{"status": "needs_review", "steps": 2, "semantic_review": "pending"}

第二条的预期结果:

{"result": "pass", "run_status": "needs_review", "semantic_review": "pending"}

运行名 run-01 是你给本次执行起的名字。它只能包含字母、数字、下划线、短横线,以字母或数字开头,长度1—40位。固定命名规则可以减少把任意路径误当输出位置的机会,但不构成完整的文件系统隔离。

打开新生成的目录:

runs/run-01/
├── context.json
├── state.json
├── 01-export.json
├── 02-verify.json
└── artifact/
    ├── review.md
    └── manifest.json

不要只盯着最后两行终端输出。先打开 artifact/review.md,确认里面有三张卡片、原文及教学样例和待审核标记。再读 state.json:应该有两个通过的步骤,但整个任务状态仍为 needs_review。

各文件承担不同责任:

  • context.json 保存本次任务关联的14个文件的 SHA-256 指纹,用来对比版本是否变化。
  • state.json 保存运行名、输入情景、真实开始时间、步骤状态和下一步动作。
  • 01-export.json 保存导出返回的清单;02-verify.json 保存验证结果。
  • artifact 保存读者真正需要审阅的资料。

指纹是一种用于比较文件内容的摘要,不是文件备份。如果后来改了规格或脚本,旧记录仍保留当时的指纹,但不能靠指纹还原旧内容;旧版本仍要由 Git 或保留的快照提供。

第二条命令会重新读取真实产物,并核对回执、任务归属、步骤和当前文件指纹。它不是简单地打印第一条的“成功”字段。

四、拆开入口,看懂它怎样连接已有能力

本篇流程如下。图中的步骤是固定顺序,不包含模型自己规划的分支。

flowchart TD
    A[检查环境与固定输入] --> B[预留全新的运行目录]
    B --> C[保存上下文指纹与运行状态]
    C --> D[执行导出并保存回执]
    D --> E[独立检查导出产物]
    E --> F[核对观察文件是否变化]
    F --> G[停在 needs_review]
    D -->|失败| H[记录失败并停止]
    E -->|失败| H
    F -->|发生变化| H

核心调用并不长,完整代码在harness.py:

step('export', lambda: export_review.export(fixture, folder/'artifact'))
step('verify', lambda: verify_export.verify(folder/'artifact', fixture))

这里的 step 是一个包裹函数:先记录“准备执行这一步”,再调用真正的导出或验证函数,然后保存结果并更新状态。lambda 只是把“稍后调用这个函数”传给 step,并不额外请求模型。

这种组织让业务能力和运行记录可以分开理解。导出器仍负责导出;验证器仍负责核对;入口负责先后顺序、目录和状态。以后修改导出内容,不必把所有运行记录逻辑也塞进导出器。

程序在运行前后比较指定文件的指纹。如果有人在运行期间改了任务或输入,即使导出和验证两步通过,也会停为失败,要求检查这次证据究竟对应哪个版本。这个检查只覆盖清单内的14个文件,不能监视整个计算机,更不是安全扫描。

状态文件采用先写临时文件、再替换目标文件的方式,减少直接覆盖 JSON 时留下半截内容的机会。但一次运行有多个文件,它们并不是一个数据库事务;断电、强制结束或磁盘错误仍可能留下部分记录。不能因此宣称已经实现了可靠的断点恢复。

五、为什么完成两步以后,还不能叫“任务完成”

needs_review 的意思是:该生成的文件生成了,该做的固定机械检查做了,现在需要人看内容。

第12篇已经提供了一个很有用的反例:semantic-wrong 情景里的第一张卡片把流程写成“先生成回答,再检索资料”。这份卡片可以有合法结构、真实引文,也能被完整导出,但答案对原文的理解是错的。

运行它:

macOS / Linux:

python3 harness.py --run semantic-01 --fixture semantic-wrong
python3 verify_harness.py runs/semantic-01 --fixture semantic-wrong

Windows PowerShell:

py -3 harness.py --run semantic-01 --fixture semantic-wrong
py -3 verify_harness.py runs/semantic-01 --fixture semantic-wrong

你仍会看到 needs_review 和 pending。打开这轮的 artifact/review.md,把第一张卡片和原文对照,就能发现问题。

这不是验证器失职。此处固定验证器承担的是“是否忠实导出了指定样例、回执和文件是否一致”,并不是替人判断样例知识是否正确。我们故意保留错误答案,正是为了避免把“管道运行正常”偷换成“所有内容都可靠”。

本篇没有提供一个按钮把 pending 改成 approved。人工审阅意见可以另外记录,但不要直接改原样例、旧回执或指纹来制造一份全绿结果。评测和审阅的结论需要自己的依据。

六、让失败成为有意义的停止

再运行一次带假引用的输入。

macOS / Linux:

python3 harness.py --run bad-01 --fixture bad-quote
python3 verify_harness.py runs/bad-01 --fixture bad-quote

Windows PowerShell:

py -3 harness.py --run bad-01 --fixture bad-quote
py -3 verify_harness.py runs/bad-01 --fixture bad-quote

第一条预期退出码为1,输出:

{"status": "failed", "steps": 1, "semantic_review": "pending"}

这次导出器发现引用不在原文中,在创建产物前抛出 ValidationError。打开 01-export.json 可以读到错误;state.json 记录失败;不应出现 artifact 和 02-verify.json。入口不会自动删掉引用、重写答案,再宣告成功。

第二条却应退出0,报告 result=pass、run_status=failed。这里的通过表示:程序按预期拒绝了坏输入,留下的失败证据符合约定。 不是说复习资料已经成功导出。

想检查退出码,macOS / Linux 在目标命令之后立即运行 echo $?;PowerShell 使用 $LASTEXITCODE。后一条命令会更新退出码,所以不要执行一串命令以后,再把最后一个退出码算到第一条头上。

看到的状态 可以得出的结论 下一步
needs_review 固定步骤通过,内容待审 对照原文阅读产物
failed 有环节失败或观察文件变化 阅读状态、回执和实际目录
interrupted 入口捕获到了 Ctrl+C 中断 检查是否已有部分产物
running 记录尚未更新到最终状态 检查进程及文件,不能假定没执行

尤其要注意最后一行:如果进程被强制结束,记录可能停在“开始执行”,实际动作却已经发生过。因此本篇不提供“看到 running 就再执行一次”的规则。如何恢复,需要在第15篇结合真实执行结果继续讨论。

七、做一次不相信状态字段的检查

现在做一个小实验:在文件管理器中复制 runs/run-01,把副本命名为 runs/copy-01。只在副本里删除 artifact/review.md,保留 state.json 的通过记录。

macOS / Linux:

python3 verify_harness.py runs/copy-01

Windows PowerShell:

py -3 verify_harness.py runs/copy-01

验证应该失败,因为真实产物丢了。由此可以看出,状态是定位工作的索引,不是能替代文件和事实的权威声明。

再直接重复 --run run-01,程序应退出2,提示运行目录已存在;旧目录不被覆盖。要开展新的尝试,用新的运行名,例如 run-02。

假如你真的修改了任务文档,再验证旧运行,指纹检查也会失败。这时应比较新旧版本,确认运行依据,而不是让 Agent 重新计算一遍旧 context.json,把历史证据改成今天的样子。

这三项检查分别覆盖了产物丢失、重复执行和版本错位。它们比一句“所有步骤成功”更能说明运行记录有没有实际价值。

八、可选:把这个入口交给 Kimi Code

前面的练习已经完整,不必为了学习 Harness 再付费调用一次模型。如果你希望自己体验,可以在本篇工作目录运行:

kimi --plan

该选项已按写作日官方命令文档和本机 Kimi Code 2.0.2 的帮助核对;作者没有发起真实会话。Plan 模式用于先讨论计划,不等于操作系统层面的只读沙箱。参考:Kimi CLI 命令。

可使用以下任务说明:

先读 AGENTS.md、docs/harness/TASK.md、docs/harness/CONTEXT.md 和 docs/harness/RUNBOOK.md。解释当前任务、允许的动作以及需要人工审核的内容,先给计划。经我确认后,只执行一次固定 valid 样例的 Harness 和独立验证,使用未占用的运行名。不要改 project 或样例,不读取私人资料,不调用真实应用 API,不加载 MCP。失败就报告证据位置并停止;机械通过也保持语义待审。请区分你实际执行过的命令与建议我执行的命令。

确认计划、准备执行时,再按当前客户端提示切换相应模式并审核工具动作。真实 Kimi 会话可能消耗开发工具额度;我们限定的是不要另外触发笔记助手的真实 DeepSeek 请求,不能把这两类消耗混为一谈。

第12篇的 Skill 仍保存在工作区,但它直接调用导出脚本,不会自动生成本篇完整的运行记录。当前任务应走 harness.py。这也说明“项目里存在一个可复用能力”和“本次任务应该使用哪个入口”是两件需要明确区分的事。

九、遇到问题,沿着证据找原因

现象 优先核对 处理方式
找不到 harness.py 是否进入了内层 project 返回 lesson-13 根目录
ready=false Python版本、missing列表 使用3.11以上版本,恢复完整配套
已有目录退出2 同名运行是否存在 保留旧记录,使用新名字
两步通过但总体失败 观察文件是否在执行期间改变 查看版本差异,不重写旧指纹
验证旧运行提示文件变化 当前资料是否已经编辑 用对应版本核查历史运行
只留下部分 JSON 或临时文件 中断、磁盘空间或写权限 保留现场,先检查实际产物
语义错误也能通过 是否误把机械检查当内容判断 回到原文和评测标准审阅

这个入口没有任意程序沙箱、超时终止或自动修复能力。它在同一个 Python 进程里调用两个固定函数;以后如果换成外部命令或不受信任的工具,执行隔离、超时、输出限制等都必须重新设计,不能把本课的小入口原封不动当作通用运行平台。

作者已在阻断网络的离线环境验证正常、假引用、语义错误、重复命名、缺输入、产物丢失、伪造完成状态、运行中资料变化和中断情景。原应用38文件及已有导出器保持不变。没有真实 Kimi / DeepSeek 调用,也没有 Windows 实机或浏览器视觉验证;Windows 命令采用对应 Python 启动方式提供。

最后检查自己的理解:

  1. --check 返回 ready=true,能否直接把任务标为完成?不能,它只检查版本和指定文件是否存在。
  2. 一个运行没有 review.md,但状态写着两步通过,应该相信哪一个?应核查实际产物,独立验证必须拒绝这种不一致。
  3. 为什么 semantic-wrong 没有被自动“修好”?本轮任务是忠实导出并留待审阅;改写内容需要新的明确任务和验证标准。

现在,你已经有了一个能找入口、能执行、能检查、能记录、能停止的项目环境。下一篇会在这个基础上讨论执行 Loop:什么时候允许继续,什么时候应停止,以及怎样防止“再试一次”变成没有边界的循环。