AgentRun 模型
一次执行实例 = Agent + Task + Session + 四层,Execution 层的最小执行单元
Vyane 里,「谁在干、干什么、怎么跑」被拆成几个不同的东西。AgentRun 就是把它们捏在一起、真正跑起来的那一次执行——它是 Execution 层(怎么跑)不可再分的最小单元。
如果说四层架构回答的是「用什么脑子、在什么壳里、走什么协议、找谁要额度」,那 AgentRun 回答的是「这一次,某个身份,为了某个任务,实际拉起了一次运行」。
AgentRun 是什么
一句话:AgentRun = 一次具体的执行实例。
它由这几块拼成:
AgentRun =
agent (谁的身份)
+ task (为哪个任务)
+ session (挂在哪个上下文容器里)
+ { model, harness, provider, protocol, ← 四层:用什么脑子/壳/账号/协议
tool_grant, ← 这次实际能用的工具
memory_view, ← 这次能读到的记忆视图
policy_set } ← 这次受哪些权限约束用类比讲:Agent 像一个演员,AgentRun 就是这个演员在某一场戏里的一次实际登台。同一个演员可以在不同的戏、用不同的妆造、在不同的舞台上演很多次——每一次登台都是一个独立的 AgentRun。
最小执行单元
AgentRun 不可再分。一次 AgentRun 就是一份 {agent, task, session, model, harness, provider, protocol, tool_grant, memory_view, policy_set} 的快照。想追踪一次执行到底用了什么脑子、能碰什么文件、受什么限制,看这一份快照就够了。
Agent 和 Task 是几对几
调度的基本单位是 Task(任务),不是 AgentRun。一个 Task 的生命周期里可以产生多个 AgentRun——不同身份、不同模型、不同壳互相接力或并行协作。
一个 Task ──触发──▶ AgentRun #1(Developer 写代码)
──▶ AgentRun #2(Reviewer 独立审)
──▶ AgentRun #3(额度用光后接力续跑)所以验收的是这个 Task 的验收标准,不是某一个 AgentRun 的输出。这条是 Vyane 锁死的硬规则:Task 对 AgentRun 是「一对多」。
Task 和看板上的「卡」是一回事吗
概念上是同一层东西:一个 Task 通常就对应看板上的一张卡(issue)——它是"要做完的一件事",而 AgentRun 是"为做这件事而拉起的一次次执行"。看板管"有哪些事、做到哪了",AgentRun 管"每次具体谁在跑、怎么跑"。
agent vs role:身份和职责是两回事
这是最容易搞混、也最要紧的一组区分。
| agent(身份) | role(职责) | |
|---|---|---|
| 回答 | 「这是谁」 | 「这次扮演什么」 |
| 稳定性 | 长期稳定,跨 session 存在 | 临时的,一次执行一贴 |
| 有没有独立记忆 | 有,独立 memory namespace | 没有,只是个模板 |
| 例子 | Architect、Operator、System | Developer、Reviewer、Researcher、Operator |
agent 是持久身份。 一个长期 agent 应有稳定职责、独立 profile、长期记忆,并跨多个 session 承担相近工作。普通短期任务不需要新造身份,用默认的 System agent 即可。
role 是职责模板。 它不绑身份——同一个 System agent 这次可以当 Developer,下次当 Reviewer。role 只说明「这次执行负责干什么」。
别把这些写进 agent 或 role
Codex、Claude Code、Gemini CLI 这些是执行壳(harness),不是身份,也不是职责。
正确写法举例:agent = System、role = Developer、harness = codex-cli、model = 某个 GPT 模型。
错误写法:把 Codex 塞进 role,或把模型名当成 agent。
那六个字段:harness / provider / protocol / model 的语义
除了 agent 和 role,一次 AgentRun 还要落实「具体怎么跑」——这就是四层架构里的四层,加上 agent、role 一共六个字段:
| 字段 | 语义 | 一句话 |
|---|---|---|
| agent | 身份 | 用哪个「谁」的身份跑 |
| role | 职责 | 这次扮演什么角色 |
| harness | 执行壳 | 在哪个壳里跑,决定能不能碰文件 / shell / MCP / skills |
| provider | 账号来源 | 谁给 endpoint、key、额度、计费 |
| protocol | 线上协议 | 请求 / 响应长什么样(wire 格式) |
| model | 推理引擎 | 真正做推理的模型 |
这六个字段的关系可以这样理解:
- agent / role 属于 Identity 层,回答「谁、扮演什么」——是语义身份。
- harness / provider / protocol / model 属于四层,回答「在哪跑、找谁要额度、走什么协议、用什么脑子」——是执行配置。
它们互相解耦、自由组合。同一个 agent 可以换不同 model 跑;同一个 model 可以走不同 provider(官方账号 vs 聚合网关)、装进不同 harness(Codex CLI vs 纯 API)。正因为解耦,一个额度用光时才能换另一套组合继续跑,而身份(agent)和职责(role)保持不变。
记住这条分界
身份(agent)、职责(role)是语义,跟着「谁在负责」走;harness / provider / protocol / model 是执行细节,跟着「这次怎么跑」走。前者稳定,后者可换。绝不把执行细节(尤其是 harness 名和 model 名)写进身份或职责字段。
一个子进程 = 一个 AgentRun
落到运行时:每个 AgentRun 由一个独立子进程承载,生命周期内不复用。 跑完这一次就结束,下次是全新的子进程。
这样设计的好处很直接:
- 崩溃不互相污染 —— 一个壳崩了,不会带塌其他正在跑的 AgentRun。
- 权限可以用进程边界兜底 —— PolicySet 的约束能落到操作系统级的进程隔离上。
- 能真并发 —— 多个 AgentRun 各跑各的子进程,不共享内存状态,互不干扰。
子进程和 session 的关系
子进程不复用,但 session 可以。当壳支持续接(比如 Claude Code 的 session-id、Codex 的 session),下一次 AgentRun 会是新的子进程 + 接上旧的 session——上下文接住了,进程还是干净的。详见 session 与 goal。
owner:谁在用这个系统
比 agent / role 更外一层,还有个 owner 的概念。owner 大致对应「哪个使用者」——任务、会话、goal、历史、反馈这些数据都按 owner 归属存放,一个 owner 看不到另一个 owner 的数据。这是为多用户 / 多身份共用同一个底座打的地基。
你会在不少地方碰到它:CLI 的 --owner-user-id、HTTP API 里 token 绑定的 owner、monitor 默认的 legacy owner。
单人使用通常不用管 owner
一个人自己用时,所有东西默认落在同一个 owner(legacy)名下,你完全不用碰这些参数。owner 是给"多个使用者共用一个 Vyane 实例、彼此数据要隔离"的场景准备的。
代码里长什么样
当前代码里,AgentRun 对应的实现类是 WorkerState(在 daemon/worker_registry.py)。子进程的拉起 / 续接由 subprocess_manager.py 负责,一个 worker 对一个子进程。
WorkerState → AgentRun 的正式改名是规划中的动作,还没落地——读代码时看到 WorkerState,心里对应的就是 AgentRun 这个概念。
🚧 设计中 / 未落地
概念模型里的 Tool / ToolGrant 三层抽象、Policy 统一 dataclass、WorkerState → AgentRun 改名都属于规划或部分落地。当前实现里,工具权限和记忆视图更多是靠 harness 自身机制 + 派发参数隐式表达,还没抽成独立的统一入口。