01:整体架构:为什么把业务插件和 Agent Runtime 分开
拆解 RunLens 的接口层、业务插件层与通用 Runtime,解释为什么业务能力应通过契约声明,而执行、权限、恢复和观测由统一底座承接。
01:整体架构:为什么把业务插件和 Agent Runtime 分开
上一篇从一份反馈 CSV 出发,介绍了 RunLens 想解决的问题:让一次 Agent 任务能够执行、限制、恢复、验证和解释。
沿着这条主线继续往下看,第一个架构选择是业务插件和 Agent Runtime 的分离。
Feedback Analysis 需要读取 CSV、提取证据、生成产品待办。File Summary 需要读取文本、分析标题结构、生成摘要。两类任务的输入和产物差异很大,运行过程却共享很多机制:模型循环、工具执行、权限、计划、恢复、验证和事件记录。
我把这两部分拆成业务声明层和通用执行层。
Plugin 描述这次任务需要什么,Runtime 负责让这次任务稳定地跑完。

从单一业务代码到通用执行底座
反馈分析的第一版很容易写成一条固定流程:
读取 CSV
→ 调用模型分析
→ 写 JSON
→ 写 Markdown
这种写法适合快速验证需求。随着工具、权限、重试、Plan 和产物检查逐渐加入,固定流程会承担越来越多通用职责。
如果后续再加入文档摘要、日志诊断、研究报告或代码审查,每条业务链路都需要重新实现一遍:
- 模型客户端选择。
- Tool Schema 转换。
- 工具参数校验。
- 文件权限判断。
- 运行次数限制。
- Provider 重试。
- 任务状态记录。
- 最终产物验证。
- Events 和 Metrics。
这些能力和具体业务关系较弱,更适合沉到统一 Runtime。
业务代码保留直接相关的内容:输入、工具、任务步骤、产物和质量规则。
RunLens 的三层结构
当前后端可以分成三层。
| 层次 | 主要职责 | 典型代码 |
|---|---|---|
| 接口层 | 接收请求、返回 Run 状态和文档 | app/api/ |
| 业务声明层 | 声明任务输入、工具、Skill、Plan 和产物 | app/plugins/feedbacklens/、app/plugins/file_summary/ |
| 通用执行层 | 执行模型循环、权限、Hook、恢复和观测 | app/agent_engine/ |
这三层沿着一次请求依次交接。
FastAPI Request
→ PluginRegistry
→ BusinessPlugin
→ AgentRunRequest
→ Agent Runtime
→ Run Status / Artifacts
接口层知道用户选择了哪个插件,业务声明层知道这类任务如何完成,Runtime 知道一次 Agent Run 如何推进。
API 只负责接住请求
Run 创建入口位于 app/api/routes.py。
请求中包含:
plugin:本次运行的业务插件。goal:用户目标。input:插件输入。skill:可选 Skill。model:Provider 和模型配置。limits:迭代、工具调用、重试和超时限制。
API 层完成 Pydantic 请求校验,再把参数交给 run_registered_plugin()。
这一层专注 HTTP 传输和错误映射,CSV 读取与文件写入继续交给 Runtime 工具链。
Run 检查接口也遵循同样思路:
/api/runs/{run_id}读取状态。/plan和/todos读取任务进度。/events和/metrics读取可观察数据。/documents根据 Manifest 暴露运行文件。
API 面向调用者提供统一形态,插件差异留在业务声明中。
Plugin 负责声明业务能力
RunLens 使用 BusinessPlugin 聚合一类业务任务需要的能力。
一个 Plugin 会声明:
| 内容 | 作用 |
|---|---|
plugin_name 和 version | 标识插件和版本 |
input_schema | 校验业务输入 |
tool_definitions | 提供模型可调用的动作 |
prompt_fragments | 描述业务规则和输出要求 |
required_outputs | 定义最终交付产物 |
plan_template | 定义任务步骤和成功条件 |
skill_roots | 提供任务方法和权限声明 |
hook_config | 增加业务质量校验 |
以 Feedback Analysis 为例,它声明了:
- 输入文件是反馈 CSV。
- 模型可以读取反馈、提取证据、统计分类和写入产物。
- 任务按读取、分析、Backlog、报告四步推进。
- 最终需要两个 JSON 和一个 Markdown。
- 证据 ID 和原文片段要回溯到源 CSV。
Plugin 负责把这些业务要求交给 Runtime。
Runtime 负责执行和收束
app/agent_engine/ 处理所有插件共享的运行问题。
Runtime 初始化
runtime/runner.py 会创建工作区、加载 Skill、解析能力、生成 Plan、组装 Prompt,并准备 ToolExecutor。
模型与工具循环
runtime/loop.py 负责模型调用、tool_calls、observation 回流、恢复和终止。
工具执行
tools/executor.py 依次完成 Schema、权限、Hook、Handler 和结果记录。
任务状态
planning/ 和 runtime/state.py 分别记录业务步骤和 Runtime 生命周期。
结果验证
hooks/validation.py 在模型结束后检查必需文件、JSON、Markdown 和 Evidence。
可观察性
observability/ 记录统一事件并聚合 Metrics。
Runtime 只依赖 Plugin 提供的契约,执行时关注工具、状态和产物规则,具体业务含义留在插件中。
中心注册表怎样形成可信边界
RunLens 当前通过 app/plugins/builtins.py 显式注册内置插件:
feedbacklens
file_summary
PluginRegistry 在注册时检查:
- 插件名称唯一。
- 版本符合语义化格式。
- 工具名称无重复。
- 产物路径无重复。
- 插件拥有输入 Schema。
显式注册让可执行代码来源保持清楚。Runtime 只运行项目代码中明确启用的插件。
这也是当前版本的信任模型:RunLens 面向可信内置插件,第三方插件系统需要额外的代码签名、依赖隔离和执行沙箱,适合放到后续阶段。
第二个插件 file_summary
file_summary 是一个很小的插件,却承担了重要验证作用。
它的业务流程是:
读取文本文件
→ 分析标题和行数
→ 写 document_analysis.json
→ 写 summary.md
与 Feedback Analysis 对比:
| 对比项 | Feedback Analysis | File Summary |
|---|---|---|
| 输入 | CSV 反馈 | Markdown 或文本 |
| 核心工具 | CSV、Evidence、统计 | 文本读取、结构分析 |
| Plan | 四步 | 三步 |
| 最终产物 | 三个 | 两个 |
| 特殊验证 | 证据回溯 | Markdown 标题 |
两者共享:
- Skill Loader。
- Prompt Assembler。
- AgentLoop。
- ToolExecutor。
- PermissionGuard。
- PlanProgress。
- Stop Hook。
- EventBus 和 Metrics。
- RunWorkspace 和 Manifest。
当第二个插件能够沿同一 Runtime 跑通时,业务和执行层的边界也得到了实际验证。
架构约束也进入测试
只靠目录命名维持分层很容易发生漂移。
RunLens 增加了架构约束测试,例如:
- Runtime 源码不导入具体业务插件。
- Tool Layer 不导入 LLM Provider。
- API 不直接调用 Tool Handler。
- Skill 模块不执行 Handler,也不写工作区。
- 测试用 ScriptedLLM 不进入生产 Provider Factory。
这些测试把架构边界变成可以自动验证的规则。
业务迭代时,如果某次修改把 FeedbackLens 逻辑重新塞进 Runtime,测试会直接暴露依赖方向变化。
这种拆分带来的收益和代价
收益
- 业务扩展更集中。 新插件主要声明自己的输入、工具、Plan 和产物。
- 运行机制保持一致。 不同业务共享权限、恢复、观测和验证语义。
- 测试更容易分层。 Runtime、插件和业务工具可以分别测试。
- 前端接口更稳定。 Run、Events、Metrics 和 Documents 对所有插件保持统一。
- 运行证据可比较。 不同插件使用同一 Event Schema 和 Metrics。
代价
- Plugin Contract 会增加前期设计工作。
- 简单任务也需要经过统一 Run 初始化。
- Runtime 和业务之间要维护清晰的数据契约。
- 插件能力较多时,Skill、Plan 和 ArtifactContract 需要同步演进。
这些代价换来的是长期边界。当前项目规模已经足以让这套拆分产生价值。
小结
RunLens 把系统分成接口层、业务声明层和通用执行层。
API 接住请求,Plugin 声明任务,Runtime 负责执行和收束。Feedback Analysis 和 File Summary 拥有各自的输入、工具和产物,同时共享同一套 Agent 工程底座。
下一篇沿着一条真实请求继续看:用户创建 Run 以后,插件、Skill、Prompt、Plan、模型、工具、验证和 Manifest 怎样依次接力。