> For the complete documentation index, see [llms.txt](https://levon.gitbook.io/agent-engineering/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://levon.gitbook.io/agent-engineering/02agent-yun-xing-shi.md).

# 第 2 课：Agent Runtime——Model、Harness、Tool 与 Environment

上一课确定了只读排查助手的范围。现在它申请读取 `server.log`，界面却一直停在“正在读取”。订单服务为什么报 500 还没查清，排查助手自己先卡住了。

该换模型，还是检查文件？本课用这个假设情境拆开运行过程。下面的状态记录用于教学，不是配套程序已经复现的阻塞故障。

## 1. Runtime 组成：四种职责与具体对象

模型提出的读取申请，可以先用下面的简化形式表示；这里只展示工具名和参数，不代表某个模型 API 的完整响应：

```json
{"name":"read_file","arguments":{"path":"server.log"}}
```

申请交出以后，宿主程序要检查它、找到对应的工具函数，再把执行结果交回模型。这套组织和控制运行的代码通常叫 **Harness**。它可以由多个函数、模块或框架共同承担，不必是一个名为 Harness 的大类。

读取函数还要向文件系统索取数据。文件放在哪里、进程能否访问、底层存储是否响应，这些运行条件属于 **Environment（环境）**。

| 部分          | 在本例中对应什么            | 主要职责                  |
| ----------- | ------------------- | --------------------- |
| Model       | 收到排查目标和材料的语言模型      | 判断接下来需要什么信息，生成调用申请或回答 |
| Harness     | 组织请求、检查调用、处理结果的宿主代码 | 推动运行，落实执行规则，决定继续或停止   |
| Tool        | `read_file` 的实现函数   | 按约定读取内容，返回结果或错误       |
| Environment | 文件系统、进程身份、挂载与访问权限   | 提供工具实际接触的数据和运行条件      |

本书把这些部分协同工作的可运行整体称为 **Agent Runtime（Agent 运行时）**。这是一种职责划分，不要求拆成四个独立服务。本地 Python 程序里可以同时包含 Harness 和 Tool，模型则通过 API 调用。

## 2. Harness：输入组织、执行控制与结果回传

Harness 需要在具体位置作决定。沿这次日志读取看：

| 时刻    | 宿主程序的工作       | 本例需要核对什么                  |
| ----- | ------------- | ------------------------- |
| 请求模型前 | 选择输入和工具说明     | 是否提供了正确的日志位置与读取能力         |
| 收到申请后 | 校验工具名、参数与执行规则 | 是否只申请了允许的 `read_file` 和路径 |
| 调用工具时 | 找到实现，在选定环境执行  | 是否进入了正确的读取函数              |
| 工具返回后 | 保存并回传实际结果     | 内容或错误是否进入下一次模型请求          |
| 需要继续时 | 检查预算与停止条件     | 是否还能请求模型，是否应当停止或交给人       |

例如，申请读取 `server.log` 可以进入检查；申请读取 `../../secret.txt` 则要按路径规则判断，不能因为是模型生成的就放行。若应用要求审批，还须核对可信的批准记录。模型自己补一句“用户已同意”，不算批准。

结果回传同样会出错：文件已经读完，但程序没有把内容加入后续请求，模型仍然看不到日志。此时继续催它“认真分析”，相当于催一个没收到附件的人写结论。

Harness 可以处理失败，但处理方式要看证据和动作性质。返回错误、等待人工处理、停止运行都是可能的选择；不能把任何异常都当成可以重试，也不能把任何停止都当成任务完成。

## 3. Tool 与 Environment：实现逻辑和运行条件

`read_file` 规定怎样接收路径、读取字节、解码并返回内容；文件系统决定该路径上实际有什么，以及当前进程是否能访问。两者配合才能完成读取。

设想同一段工具代码运行在三个位置：

```
开发机：server.log 存在，进程可以读取
容器中：日志目录没有挂载，目标路径找不到文件
沙盒中：文件存在，但访问被系统策略拒绝
```

工具把路径拼错了，要检查输入与路径处理逻辑；路径正确却无法访问，再核对部署环境和进程权限。换一个模型，并不会替容器挂上日志目录。

应用自己的路径检查也可能先于文件系统拒绝请求。因此，看到“无权限”时，要继续问拒绝来自哪里：Harness 的规则，还是工具调用系统时收到的错误？这决定了下一步应该检查哪处配置或代码。

这个区分帮助确定排查位置，不保证一个故障只涉及一层。例如模型给错了路径，可能同时暴露出工具说明含糊和校验不足；还要沿输入与返回结果继续核对。

## 4. 故障定位：沿执行证据缩小范围

回到开头，先确认下面的记录属于同一次日志读取。假设检查后拿到了这些状态：

```
模型请求：已返回 read_file("server.log") 申请
工具查找：找到了 read_file 实现
参数与执行规则检查：通过
读取函数：已经进入
读取结果：尚未看到返回记录
```

前四行把排查重点移到了读取函数及其后续处理。这次模型请求已经返回，不能继续把等待都算在“模型还在思考”上。

但最后一行还不是根因。函数可能仍在等待，进程也可能已经退出，或者返回记录没有保存。**缺少一条记录，不等于已经证明那一步没有发生。** 先查进程是否存活、读取调用是否仍在等待、记录是否完整，再决定怎样处理。

如果随后确认读取调用确实在等网络文件系统返回，才进一步检查挂载、网络和存储响应。如果已有读取结果，就继续向后查回传环节。

| 已确认的现象          | 下一步优先核对                |
| --------------- | ---------------------- |
| 申请返回了，但找不到同名工具  | 工具注册、名称和路由             |
| 尚未进入读取函数，就被拒绝   | 参数、允许路径和审批规则           |
| 读取内容无法解码        | 实际文件编码与工具的解码方式         |
| 工具读完了，模型请求里没有内容 | Harness 的结果回传与输入组装     |
| 结果已回传，却持续重复同一动作 | 输入是否充分、模型选择以及循环预算和停止条件 |

我会先找出哪一步的输入或结果不符合预期，再决定改提示词、工具代码还是运行配置。

## 5. 框架定位：LangChain 与 LangGraph

LangChain 与 LangGraph 都是可以安装到程序中的代码库，能承担一部分 Harness 工作。

![小黑把 LangChain 的模型与工具循环装在 LangGraph 编排底座上，底座的抽屉表示可按配置保存的执行进度。](https://3256184984-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FO56Bk11JpENsvGCw6xhb%2Fuploads%2Fgit-blob-33161081671019b5089bfab2d2e2503ec93122a2%2F01-agent-loop-on-runtime.png?alt=media)

做排查助手时，把模型、读取工具和任务要求交给 LangChain 的 Agent，它可以组织“请求模型—执行工具—回传结果”的循环。文件具体怎样读取，仍由工具实现。\[5]

LangGraph 用来连接任务步骤，安排接下来去哪，并可按配置保存运行进度。图里的底座和抽屉表示这些能力，不是两台独立设备，也不代表故障恢复已经自动做好。\[6]

LangChain 的 Agent 建立在 LangGraph 之上；直接使用 LangGraph，也不要求先使用 LangChain。\[5]\[6]

现阶段先记住它们承担什么职责。等[第 10 课](/agent-engineering/10agent-bian-pai.md)真正遇到“修改—验收—返工”时，再完整解释节点、分支和状态怎样对应到代码。

开源 Agent 不一定使用这些框架，模块名称也未必叫 Harness。本书核验的 OpenCode 版本把会话处理、工具查找和权限判断放在不同模块中，合起来承担运行控制的职责。\[1]\[2]\[3] 阅读源码时，应追踪谁接住请求、谁执行动作、谁处理结果，而不是只找一个同名文件。

下一课把这些职责接成一个最小 **Tool Calling Loop**：保存调用申请，执行工具，带着对应编号回传结果，再决定继续或结束。第 10 课再对照框架怎样组织更长的任务。

本课不要求额外写程序。工具申请、执行和回传将在[第 3 课](/agent-engineering/03-gong-ju-diao-yong-xun-huan.md)展开。

## 资料

1. [OpenCode：会话处理](https://github.com/anomalyco/opencode/blob/50efc055de282e0e54a87ccebb8e2054cc45efd2/packages/opencode/src/session/processor.ts)
2. [OpenCode：工具注册](https://github.com/anomalyco/opencode/blob/50efc055de282e0e54a87ccebb8e2054cc45efd2/packages/opencode/src/tool/registry.ts)
3. [OpenCode：权限判断](https://github.com/anomalyco/opencode/blob/50efc055de282e0e54a87ccebb8e2054cc45efd2/packages/opencode/src/permission/evaluate.ts)
4. [固定源码与核验记录](https://github.com/unix2dos/agent-engineering-book/tree/main/research/01-05-chapter-promotion-sources.md)
5. [LangChain：Agent 框架与模型接口](https://docs.langchain.com/oss/python/langchain/overview)
6. [LangGraph：编排运行时与 LangChain 的关系](https://docs.langchain.com/oss/python/langgraph/overview)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://levon.gitbook.io/agent-engineering/02agent-yun-xing-shi.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
