02:一次 Run 的完整链路:从请求进入系统到生成产物
沿一次 Feedback Analysis Run 的时间线,梳理请求、插件、能力解析、模型循环、工具调用、产物落盘与最终验证之间的完整交接过程。
02:一次 Run 的完整链路:从请求进入系统到生成产物
上一篇介绍了 RunLens 的三层结构:API 接住请求,Plugin 声明业务,Runtime 负责执行和收束。
这篇把三层放回同一条时间线,沿一次 Feedback Analysis Run 看它们怎样交接。
用户提交的内容很简单:选择 feedbacklens 插件,指定 CSV 文件,再给出分析目标。RunLens 最终会留下三个业务产物、一组运行状态文件和一条完整事件时间线。
中间发生的事情,可以浓缩成一句话:
RunLens 先把用户目标解析成一组明确能力,再让模型在这些能力内循环行动,最后用确定性规则验证结果。

Run 是 RunLens 的执行单位
RunLens 围绕一次 Run 组织所有数据。
每次执行都会生成唯一 run_id,例如:
run_20260714_153012_123456
这个 ID 同时关联:
- 用户输入。
- 插件和 Skill。
- 最终工具白名单。
- Prompt 快照。
- Plan 和 Todo。
- 模型与工具事件。
- 业务产物。
- Run 状态和 Metrics。
- Manifest 公开文档。
一次任务结束以后,排查和展示都以 Run 为入口。
第一步:API 接住目标和输入
创建 Run 的入口是:
POST /api/runs
通用请求大致包含:
{
"plugin": "feedbacklens",
"goal": "找出最重要的产品问题并给出优先级",
"input": {
"product_name": "TaskFlow Pro",
"csv_path": "sample_feedback.csv"
},
"model": {
"provider": "deepseek"
}
}
CreateRunRequest 先校验请求结构和运行限制。随后 app/api/routes.py 把参数交给 run_registered_plugin()。
API 在这里承担两类职责:
- 把 HTTP 请求转成通用 Run 参数。
- 把插件、Skill、Provider 和输入错误映射成清晰状态码。
CSV 读取、模型调用和文件写入都留在后续 Runtime 链路中。
第二步:插件注册表选择业务
run_registered_plugin() 会先生成 Run ID,再为本次请求装配内置插件注册表。
注册表当前包含:
feedbacklensfile_summary
根据请求中的 plugin 字段,Registry 返回对应 BusinessPlugin。
Feedback Analysis Plugin 已经绑定了本次 Run 的工作区路径和默认 CSV 文件,因此它创建的 Tool Handler 天然指向当前 Run。
拿到 Plugin 后,Runtime 先执行插件输入 Schema 校验。
这一层会检查:
csv_path是否存在于输入。- 字段类型是否符合声明。
- 是否出现额外字段。
- 字符串长度是否满足要求。
输入校验通过后,通用插件运行器组装 AgentRunRequest。
第三步:创建独立工作区
run_agent() 首先创建:
runs/{run_id}/
├─ input/
├─ runtime/
└─ artifacts/
用户请求会写入:
input/request.json
工作区承担三个作用。
1. 隔离每次运行
工具写入的文件只能进入当前 Run。多个 Run 的 Prompt、Plan、事件和产物互相分开。
2. 保存运行快照
模型、权限、Skill 和 Prompt 可能随配置变化。当前 Run 把实际解析结果写进自己的 runtime 目录,后续可以复盘当时配置。
3. 提供统一文件 API
业务 Tool Handler 通过 RunWorkspace 写文件。路径解析会检查目标仍位于当前工作区内。
工作区创建后,Runtime 初始化 TraceLogger、LocalEventStore 和 RunStateMachine,并发布最早的 Run 事件。
第四步:加载 Skill
Feedback Analysis Plugin 的默认 Skill 是:
feedback_analysis
Skill 由两个文件组成:
skill.json
SKILL.md
Manifest 声明:
- 兼容哪个插件。
- 需要哪些工具。
- 需要哪些输入。
- 最终要生成哪些产物。
- 读写权限范围。
Markdown 文件提供任务方法,例如:
- 先读取源 CSV。
- 每条洞察引用真实 feedback_id。
- 三个产物都通过工具创建。
Runtime 会验证 Skill 和 Plugin 的兼容性,再写入:
runtime/skill_activation.json
这里会记录 Skill 名称、版本、匹配原因、所需工具和产物。
第五步:生成能力快照
Plugin 和 Skill 汇合后,Runtime 解析 ResolvedRunCapabilities。
这份快照包含:
- 插件名称和版本。
- Skill 名称和版本。
- 本次允许的工具。
- 读取根目录。
- 写入根目录。
- 最终产物契约。
对 Feedback Analysis 来说,Skill 会把写权限收窄到:
runs/{run_id}/artifacts/
Runtime 根据请求选择真实 Provider,并把最终能力、模型和 Provider 写入:
runtime/resolved_config.json
这份文件记录“这次 Run 实际拥有哪些能力”,并与插件声明的完整能力集合区分开。
第六步:准备 Prompt、Plan 和工具
能力解析完成后,Runtime 进入 planning 状态。
创建 Plan
Feedback Analysis 的 Plan 包含四步:
| 步骤 | 目标 | 允许工具 |
|---|---|---|
| 1 | 读取并验证反馈数据 | read_feedback_csv |
| 2 | 创建结构化分析 | 统计、证据提取、JSON 写入 |
| 3 | 创建产品 Backlog | 证据提取、JSON 写入 |
| 4 | 创建洞察报告 | Markdown 写入、文件列表 |
Plan 写入 runtime/agent_plan.json,Todo 投影写入 runtime/todo_state.json。
注册 Hook
Runtime 注册两组 Hook:
- PlanProgress:在 Tool 前后更新当前步骤。
- Artifact Validators:在 Run 结束时检查产物。
组装 Prompt
System Prompt 包含:
- 当前业务插件。
- 用户目标。
- 业务 Prompt Fragments。
- Run Input。
- Available Tools。
- Permission Boundaries。
- Required Outputs。
- Skill 指令。
最终 Prompt 写入:
runtime/system_prompt.md
生成模型 Tool Specs
每个 ToolDefinition 会转换成 Provider 能识别的 Function Tool Schema。模型看到的工具集合来自已经解析完成的能力快照。
第七步:模型和工具进入循环
准备完成后,状态转为 model_thinking,AgentLoop 开始运行。
第一次模型响应通常会请求:
read_feedback_csv
Runtime 收到 ToolCall 后进入 tool_executing,ToolExecutor 按固定顺序处理:
查找工具
→ 校验参数
→ 检查权限
→ 触发 PreToolUse
→ 调用 Handler
→ 校验输出
→ 触发 PostToolUse
→ 返回 ToolResult
CSV 读取成功后,工具会返回规范化 rows,并生成:
runtime/evidence_index.json
ToolResult 会被转换成 role=tool 的 observation,加入下一轮模型消息。
模型基于真实 rows 继续生成分析和 Backlog,再调用写文件工具创建产物。
每个工具批次完成后,状态重新回到 model_thinking。
这条闭环会持续到:
- 模型返回 final answer。
- 触发 iteration、tool call 或 timeout 限制。
- 恢复次数耗尽。
- 重复调用或重复失败达到阈值。
第八步:模型结束后继续验证
AgentLoop 收到 final answer 后,Runtime 进入 validating。
接下来会做两类检查。
Plan 检查
PlanProgress 根据工具成功记录和文件存在情况,确认四个步骤是否全部完成。
如果模型已经结束,某一步的成功条件仍未满足,Run 会转为 failed。
Stop Hook 检查
Stop Hook 会检查:
- 三个必需文件是否存在。
- 两个 JSON 是否可解析。
- 必需字段和枚举是否正确。
- Markdown 是否包含规定标题。
- feedback_id 是否存在于 Evidence Index。
- evidence_text 是否来自对应原始反馈。
所有检查通过后,Run 才进入 completed。
这里形成了一个重要分界:模型结束负责停止循环,Stop Validation 负责判断业务交付是否成立。
第九步:写入最终状态和运行证据
最终化阶段会完成:
- 状态机进入 completed 或 failed。
- 发布
run.completed或run.failed。 - 从统一事件聚合 Metrics。
- 写入
runtime/metrics.json。 - 写入
runtime/run_status.json。 - 生成旧格式 JSONL 兼容投影。
插件运行器随后扫描工作区,排除私有 Runtime 文件,并生成:
manifest.json
Manifest 记录:
- Run ID 和状态。
- 插件名称和版本。
- 公开文档路径。
- 产物受众和敏感级别。
- 文件类型和说明。
最终公开文档列表会回填到 Run Status。
一次成功 Run 最终留下什么
成功的 Feedback Analysis Run 通常包含:
runs/{run_id}/
├─ input/request.json
├─ runtime/
│ ├─ skill_activation.json
│ ├─ resolved_config.json
│ ├─ system_prompt.md
│ ├─ agent_plan.json
│ ├─ todo_state.json
│ ├─ evidence_index.json
│ ├─ events.jsonl
│ ├─ metrics.json
│ └─ run_status.json
├─ artifacts/
│ ├─ feedback_analysis.json
│ ├─ product_backlog.json
│ └─ insight_report.md
└─ manifest.json
这些文件可以分成三类:
| 类型 | 文件 | 用途 |
|---|---|---|
| 输入和能力 | request、Skill、resolved config、Prompt | 复现本次运行条件 |
| 过程 | Plan、Todo、Events、Metrics | 解释运行过程 |
| 结果 | Artifacts、Status、Manifest | 交付和公开结果 |
失败 Run 也会留下证据
RunLens 会尽量在失败路径写入状态和事件。
例如模型遗漏 insight_report.md:
模型返回 final answer
→ Runtime 进入 validating
→ RequiredOutputValidationHook 发现文件缺失
→ hook.blocked
→ artifact.rejected
→ Run failed
工作区中已经生成的 JSON 仍然保留,便于查看模型实际完成到哪一步。
初始化阶段发生异常时,Runtime 也会写入失败状态。Provider 配置缺失、Skill 不兼容和输入错误会通过 API 返回对应错误信息。
小结
一次 Run 从 API 请求开始,经过 Plugin、Skill、能力快照、Prompt、Plan、AgentLoop、ToolExecutor 和 Stop Validation,最终形成业务产物和运行证据。
模型在中间负责动态决策,Runtime 在前后提供稳定契约。工作区把输入、过程和结果放在同一个 Run ID 下,事件和 Manifest 再把这些内容交给前端和排查工具。
下一篇继续深入模型开始行动前的准备过程:Skill、Prompt、Plan 和 Tool 怎样共同把一句用户目标变成可执行任务。