第 1 课:Harness 与 Agent 运行时

第 1 课:Harness 与 Agent 运行时

这节课我们不讲复杂的数学公式,而是从一个你熟悉的场景开始:如何设计一个能持续执行任务、调用工具、处理错误,并且不轻易宣告完成的 Agent 系统。

先说明一下阅读范围:原书第 1 章的定义部分明确将 Agent 分成两部分------LLM 和 Harness。书中还将 Agent 的用途分为辅助人类,以及让 Agent 彼此交互两大类。我们这节主要学习前者,也就是工程上最常见的任务型 Agent。

一、先建立一个准确的认识

假设用户对你的 Agent 平台说:

请检查我的 Java 项目,修复所有导致测试失败的问题,并确保项目能够正常构建。

这个任务不是一次问答,而是一段持续的执行过程。

text 复制代码
用户任务(目标、约束、验收标准)
        ↓
LLM:决策引擎(根据上下文决定下一步做什么)
        ↓
Harness:执行与控制系统
  ├─ 工具管理:调用与权限
  ├─ 状态与记忆:进度与上下文
  ├─ 执行循环:继续、重试、终止
  └─ 安全与验证:审批与验收
        ↓
外部执行环境(文件系统、终端、测试工具、Git 等)

这里有一个很重要的细节:LLM 可以提出"运行测试"这个动作,但真正启动进程、检查退出码、收集日志的,应当是 Harness 中受控的执行代码。

这意味着,模型负责提出决策,程序负责落实决策并检查结果。模型可以参与验证,但不能让它仅凭自己的口头判断就决定任务已经成功。

二、Harness 究竟包含哪些东西?

我们先用一个工程化的划分来理解。下面是构建生产级 Agent 时实用的模块划分,不代表原书给出了完全相同的标准架构。

模块 核心职责 典型实现
Execution Loop 控制每一轮的执行和退出 while 循环、状态机
Model Adapter 统一模型请求与响应 OpenAI-compatible API、Responses API
Tool Registry 注册、查找和调用工具 函数注册表、JSON Schema
Context Manager 决定每轮向模型提供什么信息 历史裁剪、摘要、检索
State Store 保存任务进度和中间结果 PostgreSQL、Redis、文件
Policy & Hooks 执行权限检查、审批和拦截 中间件、策略引擎
Evaluator 检查任务是否真正完成 测试、断言、业务验收
Trace & Replay 记录执行过程并支持复盘 结构化日志、事件记录

不必一开始就把每个模块都做成独立服务。个人开发者或小团队完全可以先在一个 Python 应用中实现它们。

三、最核心的部分:Agent 执行循环

这是 Harness 的心脏。

普通聊天程序的流程通常是:

text 复制代码
用户输入 → 模型生成回答 → 返回结果

Agent 的流程则是:

text 复制代码
接收任务
  ↓
准备上下文
  ↓
请求模型
  ↓
模型返回文本或工具调用
  ↓
检查并执行工具
  ↓
收集执行结果
  ↓
更新任务状态
  ↓
继续请求模型,或者验证是否完成

注意:每次工具调用完成,不代表整个任务完成。每次模型回答结束,也不一定代表整个任务完成。

1. 用伪代码理解核心机制

下面是一段刻意简化的 Python 伪代码。它展示的是控制流程,不是可直接运行的 SDK 示例。

python 复制代码
async def run_agent(task):
    state = create_task_state(task)

    while not state.finished:
        context = build_context(state)
        response = await model.generate(context)

        if response.has_tool_calls:
            for call in response.tool_calls:
                check_permissions(call)
                result = await execute_tool(call)
                state.add_observation(call, result)

            persist_state(state)
            continue

        if response.is_final:
            verdict = await evaluate_completion(state, response)

            if verdict.passed:
                state.finish(response.text)
            else:
                state.record_failure(verdict.reason)
                state.request_replanning()

    return state.result

这个版本还没有处理超时、并发工具调用、取消任务、崩溃恢复等生产问题,但足以让你理解 Harness 的主要职责。

2. 实际运行一遍

以修复 Java 项目为例:

第 1 轮:分析任务

  • 模型决定先查看项目结构,调用 list_files。
  • Harness 执行工具,并把文件列表交还给模型。

第 2 轮:执行测试

  • 模型决定运行 mvn test。
  • Harness 启动进程,保存退出码和测试报告。

第 3 轮:分析错误

  • 测试报告显示一个空指针异常。模型决定修改相关代码。
  • Harness 检查工具权限,执行文件修改,并记录变更。

第 4 轮:重新测试

  • 测试仍然失败,模型根据新的错误日志继续修复。
  • Harness 保留失败证据,并限制无效的重复尝试。

第 5 轮:验证完成

  • 测试退出码为 0,测试报告通过,构建也成功。
  • Harness 核对验收条件,满足后才将任务标记为成功。

这就是一个典型的 Observe → Decide → Act → Observe 循环。

它与 ReAct 等 Agent 方法在思想上是有关联的,但这里强调的是软件系统如何控制这个循环,而不是某一种特定的提示词格式。

四、一个容易忽略的区别:模型输出,不等于系统状态

这部分是从普通 Agent Demo 走向可靠 Agent 平台的关键。

假设模型返回:

我已经修复所有问题,测试全部通过。

你的系统能否直接把任务状态设置为 SUCCESS?

不能。这只是模型生成的一段文本,不是独立的成功证据。

Harness 应该区分三个东西:

  • Model Response:模型说了什么。
  • Execution Result:工具实际上执行了什么。
  • Task State:系统根据证据认定任务处于什么状态。

例如:

python 复制代码
if test_exit_code == 0 and build_exit_code == 0:
    task.status = "SUCCESS"
else:
    task.status = "NEEDS_REPAIR"

这里仍需注意,测试通过只能证明测试覆盖范围内的行为符合预期。如果还要求特定文件被修改、接口契约保持不变或没有引入安全漏洞,就必须增加相应的验收条件。

工程原则:模型可以建议状态变化,但关键状态变化应当由确定性的程序规则和可验证证据决定。

这也是为什么生产级 Harness 不应仅仅是一个包装模型 API 的薄层。关于 Harness 的工程研究也强调了执行循环、工具治理、上下文管理、持久化状态与评估之间的协作。

五、Harness 应该如何设计状态机?

如果你只用一个 while 循环写完所有逻辑,初期确实简单,但随着任务变长,会逐渐遇到状态混乱的问题。

例如:

  • 任务还没执行完,用户就关闭页面了。
  • 服务重启后,任务从头开始执行。
  • 模型调用超时,但上一次工具其实已经执行成功。
  • Agent 卡在重复调用同一个工具。
  • 用户要求停止任务,但执行中的子进程仍然在运行。

解决这些问题的第一步,是明确任务状态。

状态 含义
PENDING 等待开始
RUNNING 模型与工具执行中
WAITING_APPROVAL 等待人工审批
VERIFYING 检查验收条件
SUCCESS 终态:任务成功完成
FAILED 终态:任务失败
CANCELLED 终态:任务被取消
text 复制代码
PENDING ──▶ RUNNING ──┬──▶ WAITING_APPROVAL ──▶ RUNNING
                      ├──▶ VERIFYING ──┬──▶ SUCCESS
                      │                └──▶ FAILED
                      └──▶ CANCELLED

示意状态机,实际状态转换应由你的业务规则定义。

1. 为什么要把状态持久化?

假设你正在执行一个 30 分钟的任务,已经修改了 20 个文件。

如果任务进度只保存在 Python 的局部变量里,一旦服务重启,状态就可能丢失。

建议至少保存:

字段 用途
task_id 唯一任务标识
status 当前生命周期状态
goal 原始目标及约束
current_step 当前执行阶段
step_count 已执行轮数
tool_calls 工具调用记录
last_observation 最近的执行结果
acceptance_criteria 验收条件
deadline 任务截止时间
version 并发更新控制

这并不意味着每轮都必须把所有信息重新塞进模型上下文。持久化状态和模型上下文是两回事:前者保存系统事实,后者只提供当前决策需要的信息。

2. 一个特别容易犯的错误:重复执行工具

假设 Agent 调用一个支付接口,接口已经成功扣款,但返回结果时网络断开了。

Harness 只看到超时,于是再次调用接口,就可能扣款两次。

因此,对有副作用的工具,应当考虑:

  • 为每次业务操作生成幂等键。
  • 记录调用是否已提交。
  • 超时后先查询执行状态,而不是盲目重试。
  • 将审批、授权和实际执行分开。
  • 对无法确认结果的操作设置人工介入路径。

这也是 Harness 不只是"模型加几个函数"的原因。它必须处理真实软件系统中的失败语义。

六、结合你的 Agent 平台,应该如何落地?

你之前考虑过用 FastAPI 做管理平面,为每个用户提供隔离的虚拟计算环境,并允许 Agent 使用业务 API、Web 搜索、Python 函数和文件系统。这个场景可以采用下面的架构。

text 复制代码
FastAPI:管理与任务入口(用户、会话、任务创建、鉴权、SSE 事件)
        ↓
Agent Runtime
  ├─ Loop Controller:执行与退出控制
  ├─ Model Adapter:模型切换与请求
  ├─ Tool Registry:工具注册、校验
  └─ Context Manager:上下文构建与压缩
        ↓
持久化层:PostgreSQL(任务、状态、事件)
策略与验证:权限、审批、验收、预算
        ↓
每用户隔离的执行环境(文件系统、命令执行、浏览器、Python 沙箱)

这是一个建议的逻辑架构,不是必须拆分成多个微服务的部署架构。

我建议的技术选型

层次 初期方案 说明
API 与管理 FastAPI 你可以集中开发管理接口和任务入口
Runtime Python 类与异步函数 先做模块化单体,不要过度抽象
状态存储 PostgreSQL 任务、执行事件、审批状态
模型接入 统一 Model Adapter 屏蔽不同模型供应商的协议差异
工具执行 Tool Registry + Policy 统一参数验证、权限检查与结果格式
用户环境 隔离容器或沙箱 不要直接在主服务进程执行任意用户代码
实时事件 SSE 推送步骤、工具调用、错误和进度
知识检索 独立 RAG 模块 由 Runtime 按需调用

前期可以不引入独立消息队列、复杂多 Agent 编排系统或专门的记忆服务。等任务量、并发和可靠性需求明确后,再决定是否需要这些组件。

一个重要的架构边界

不要把业务任务状态、模型上下文和执行环境混成一个对象。

例如:

  • 任务状态:当前是否运行、已完成哪些步骤、是否需要审批。
  • 模型上下文:本轮推理需要看到的目标、历史摘要、工具结果。
  • 执行环境:当前工作目录、文件、运行中的进程、依赖环境。

它们之间有关联,但生命周期不同。把它们分开,会让服务重启、上下文压缩、任务恢复和安全隔离更容易实现。

七、最值得记住的 5 个工程误区

  • 误区 1:模型越强,系统就一定越可靠。 更强的模型可能减少决策错误,但无法自动解决工具超时、状态丢失、重复执行和权限失控。

  • 误区 2:把最大轮数设置得越大越好。 轮数只是预算上限,不是任务成功率。还应限制时间、模型调用、工具调用、费用,并识别无进展循环。

  • 误区 3:每轮都带上完整历史。 应按需构建上下文,并保留不可丢失的任务目标、验收条件和关键证据。

  • 误区 4:所有工具都可以直接暴露给模型。 工具需要类型校验、权限控制、资源限制,以及对危险操作的审批和审计。

  • 误区 5:任务有日志就足够了。 日志只能帮助你回看发生了什么。真正的评估还需要成功率、任务完成时间、成本、失败原因和可复现的测试。

八、最后做一个小练习:判断 Harness 应该如何处理任务

问题 1:模型声称"构建成功",但没有运行构建命令。系统应该怎么办?

  • A. 直接标记成功,因为模型已经判断完成
  • B. 要求提供构建证据,必要时执行构建验证
  • C. 重新调用模型,让它再判断一次

问题 2:工具调用超时,但你不确定它是否已经执行成功。应该怎么办?

  • A. 立即无限重试,直到拿到响应
  • B. 查询执行状态,必要时通过幂等机制安全重试
  • C. 告诉模型工具失败,让它随意选择下一步

进入下一课:实现一个可靠的 Agent Runtime

本课总结:Harness 不是简单的提示词包装器,而是让模型决策能够安全、持续、可恢复、可验证地转化为实际行动的软件系统。原书第 1 章提供了这个概念框架;你真正需要掌握的,是如何把它落实到执行循环、状态管理、工具治理和任务验收中。

相关推荐
智驭未来掌门人1 小时前
AI+行业赋能,到底什么才算落地?——一个差旅差标项目的深度自省
人工智能
不会是要长脑子了吧1 小时前
ChatGPT 网页端报 “Model not found“
人工智能·chatgpt
熊哈哈O_o1 小时前
260+异构同步链路:DDL语法自动翻译在大规模数据同步中的实现原理
后端
史努比的蓝色皮肤1 小时前
从 ChatGPT 到 Agent :AI 发展脉络
人工智能·chatgpt
kyriewen1 小时前
我扒了 npm 三年数据:AI 没把依赖变胖,是把包变多了
前端·人工智能·程序员
面包狗AI4S1 小时前
ChatGPT/Codex Windows:本地桌面端应用离线包安装与免安装启动方法(无需管理员权限)
人工智能·windows·ai·chatgpt
龙粤GEO1 小时前
RAG检索机制如何影响AI引用?一次SaaS品牌GEO优化实战复盘
人工智能
编码小哥1 小时前
YOLO26深度解析:为边缘计算而生的新一代实时视觉模型
人工智能·边缘计算
前端.火鸡2 小时前
Embedding:机器是怎么“理解“语义的
人工智能·embedding