状态:设计草稿(2026-06-09) 范围:MVP(v1) 关联:
docs/research/AGENTOS_POSITIONING.md(竞争壁垒 claim ③)、docs/OLLAMA_VERIFICATION.md、docs/theory.md(Guard/Compose 形式化)
把一次科研任务拆成有序阶段(计划→文献→仿真→分析→论文),每个阶段产出可审计的产物,并由一个验收谓词(gate)判定通过与否——只有通过才进入下一阶段。失败则按策略重试 / 暂停 / 人工介入。
这是把竞争分析里"完全 aspirational、0 代码"的 claim ③ 落到地的最小可用实现。差异化来源:通用编码 agent 不做垂直科研工作流 + 逐级验收带审计证据链。
Guard(stage_agent, predicate, retry);阶段串联 ≈ Compose(g1, g2, ...)。产物 gate 本就能用现有演算表达——这同时坐实 AgentOS"形式化内核"叙事。Pipeline 一条流水线
├── id / name / version
├── input 初始输入
├── stages: [Stage, ...] 有序阶段
└── defaults 全局默认(on_fail、gate 类型等)
Stage 单个阶段
├── id / name
├── agent 本阶段执行体(lambdagent 配置引用 或 内联 YAML)
├── consumes: [artifact_ref] 消费的上游产物
├── produces: [ArtifactSpec] 声明应产出的产物(name/type/path-glob/required)
├── gate: Gate 验收谓词
├── on_fail: OnFailPolicy retry(N) | halt | escalate | skip
└── budget? 可选:本阶段成本/步数上限(v1.1)
Gate 验收谓词(pass/fail)
├── kind: rule | llm_judge | human
├── rule: <safe-eval 表达式> kind=rule 时
├── judge: {rubric, threshold, model} kind=llm_judge 时
└── prompt? kind=human 时给人看的说明
Verdict 验收结果(持久化)
├── stage_id / passed: bool
├── score?: float llm_judge 给的分
├── reasons: [str]
├── kind / attempt / timestamp
└── evidence_ref 指向该阶段 manifest.json
ArtifactSpec 产物声明
├── name / type(file|dir|json|md|...)
├── path: <glob,相对阶段 workspace>
└── required: bool
| 层 | 职责 | 复用 |
|---|---|---|
agentpaas/engine/pipeline.py(新) |
Pipeline/Stage/Gate 编排、状态机、持久化、恢复 | run workspace、manifest、Sandbox |
专用 gate 求值器(新,非 _safe_eval) |
规则型 gate 的受限 DSL 求值(仅 has/count/contains/regex/json_len,无属性访问/方法链) | pipeline.py 内(见 §7.1、§15 P1-A) |
lambdagent compiler from_config |
把每阶段 agent 配置编译成可执行 term | compiler.py |
lambdagent Guard |
控制流对应物(retry 语义参考,非直接复用 validator) | extensions.py:146 Guard |
agentpaas/engine/sandbox.py |
阶段执行 + 每阶段 workspace + manifest | 已实现(含 build_change_manifest);需加 workspace_root 显式参数(§15 P3-F) |
关键设计决定:编排器(pipeline.py)放在 agentpaas 服务层,因为它依赖 run workspace(agentpaas)且是产品级特性。gate 求值不复用 _safe_eval——_safe_eval 只允许单名 x + 白名单 builtins,无法表达 outputs.has(...),放开属性访问又会能力逃逸(§15 P1-A)。改为 pipeline.py 内一个受限 gate DSL 求值器(固定函数集,无任意属性/方法)。
形式化对应(设计锚点,非严格等价 — 见 §15 P1-C/P2-D):一条 pipeline 的控制流对应
Compose(Guard(s1.agent, gate1, r1), Guard(s2.agent, gate2, r2), …);但数据流不是 Compose 的单值穿引——多上游 consumes 经共享 artifact store(CEK 的 store σ / Memory,即 state effect)读取。严格说法是"Compose(控制)+ store 读写(数据)",而非 plain Compose。v1 用专用 PipelineRunner 实现,保持这条对应关系,为将来"pipeline 即 term、可进 CEK 机"留路。
PENDING ─run─▶ RUNNING ─done─▶ GATING ─pass─▶ PASSED
│
└─fail─▶ FAILED
├ on_fail=retry & attempt<N ─▶ RUNNING
├ on_fail=halt ─▶ (pipeline HALTED)
├ on_fail=escalate ─▶ AWAITING_HUMAN
└ on_fail=skip ─▶ SKIPPED ─▶ 下一阶段
RUNNING ─▶ COMPLETED (所有 required 阶段 PASSED/SKIPPED)
─▶ HALTED (某阶段 halt)
─▶ AWAITING_HUMAN (某阶段 escalate;等待外部 resume 信号)
pipeline_state.json,记 stage_status / attempt_no / attempt_id / workspace_path / started_at / completed_at / verdict_path。原子写(temp 文件 + rename)+ pipeline 锁防并发。RUNNING/GATING 的 attempt(崩在半途),确定性处理——检查 output.json/manifest.json/verdict.json 是否完整:完整则继续 gating,不完整则判该 attempt 失败并恰好消耗一次 retry 预算(不重复、不跳过)。PASSED/SKIPPED 阶段,从首个非通过阶段重入;上游产物从其 workspace(artifact store)读取,不重算。approved → 该阶段 PASSED(写一条 human verdict);rejected → FAILED,再走 on_fail。_safe_eval(§15 P1-A):它只允许单名 x,表达不了产物访问;放开属性访问会能力逃逸。改用一个受限 gate DSL 求值器(pipeline.py 内)。has(name) → 该 required/declared 产物是否存在count() → 本阶段产物文件数contains(name, sub) / regex(name, pattern) → 文本匹配(读取上限 max_bytes)json_len(name) / json_get(name, path) → JSON 产物访问size(name) → 字节数ast.parse(expr, mode="eval") → 节点白名单(仅 BoolOp/UnaryOp(Not)/Compare/Call-到-固定函数/Constant;禁 Attribute/Subscript/Lambda/推导式/import)→ 在仅含上述函数、__builtins__={} 的命名空间内 eval。pure。has("plan.md") and contains("plan.md", "hypothesis")json_len("refs.json") >= 10count() >= 1{score, reasons};score ≥ threshold 即通过。pipeline.py 的 default_judge(JudgeRequest) -> JudgeResult,可注入(run_pipeline(judge=...),测试用 fake judge)。model: {provider, name},默认 ollama(本地,省钱/隐私)。已用本地 ollama qwen2.5:7b 实测:好产物 0.80 通过、跑题 0.00 不通过。_parse_judge_response 先抓 JSON {score,reasons},失败回退抓 0..1 数字,clamp 到 [0,1]。verdict.json 供审计。llm(m)(effectful gate,对齐 §14.4 G3)。⚠️ judge token 成本暂未进 stage cost.json——须把 judge 建成 term 图里的真 agent(stage≫judge≫parser)才计入,留 v1.1(§15.2 P2-D)。当前 usage 已记入 verdict.reasons。AWAITING_HUMAN,把产物 + prompt 暴露给外部;收到 resume(approved/rejected) 信号后继续。pipeline:
id: research-v1
name: 科研五阶段流水线
defaults:
on_fail: retry
retry: 2
stages:
- id: plan
name: 研究计划
agent: { ref: agents/planner.yml } # 或内联 type/model/systemPrompt
produces:
- { name: plan.md, type: md, path: "final/plan.md", required: true }
gate:
kind: rule
rule: 'has("plan.md") and contains("plan.md", "hypothesis")'
- id: literature
name: 文献综述
agent: { ref: agents/lit-mapper.yml }
consumes: [plan]
produces:
- { name: refs.json, type: json, path: "results/refs.json", required: true }
- { name: survey.md, type: md, path: "final/survey.md", required: true }
gate:
kind: rule
rule: 'has("refs.json") and json_len("refs.json") >= 10'
- id: simulation
name: 仿真实验
agent: { ref: agents/simulator.yml }
consumes: [plan, literature]
produces:
- { name: sim_results, type: dir, path: "results/sim/*", required: true }
gate:
kind: rule
rule: 'count() >= 1'
on_fail: halt # 仿真失败不自动重试,直接暂停人工查
- id: analysis
name: 结果分析
agent: { ref: agents/analyst.yml }
consumes: [simulation]
produces:
- { name: analysis.md, type: md, path: "final/analysis.md", required: true }
gate:
kind: llm_judge
judge:
model: { provider: ollama, name: qwen2.5:7b }
rubric: "分析是否覆盖了所有仿真指标、是否有统计显著性讨论、结论是否有数据支撑"
threshold: 0.7
- id: paper
name: 论文成稿
agent: { ref: agents/writer.yml }
consumes: [plan, literature, analysis]
produces:
- { name: paper.md, type: md, path: "final/paper.md", required: true }
gate:
kind: llm_judge
judge:
rubric: "结构完整(摘要/方法/结果/讨论)、引用与 refs.json 一致、无明显逻辑断裂"
threshold: 0.8
{agent_dir}/workspace/pipeline_{YYYYMMDD_HHMMSS}/
├── pipeline.yml ← 流水线配置快照
├── pipeline_state.json ← 全局状态(可恢复)
├── input.json
├── plan/ ← 各阶段 = 一个 run workspace
│ ├── code/ results/ final/
│ ├── manifest.json ← 该阶段产物清单(已实现)
│ ├── trace.json / cost.json
│ └── verdict.json ← 该阶段验收结果
├── literature/ ...
├── simulation/ ...
├── analysis/ ...
└── paper/ ...
{
"stage_id": "plan",
"passed": true,
"score": null,
"kind": "rule",
"attempt": 1,
"reasons": ["rule passed: outputs.has('plan.md') and ..."],
"evidence_ref": "plan/manifest.json",
"timestamp": "2026-06-09T..."
}
from agentpaas.engine.pipeline import Pipeline, run_pipeline, resume_pipeline
# 加载并运行
result = run_pipeline(
pipeline_cfg="pipelines/research-v1.yml",
input_text="研究方向:...",
agent_dir="/data/agents/researcher",
)
# result: PipelineResult(status, stages=[StageResult...], workspace_path, final_artifacts)
# 恢复(从上次未通过阶段续跑)
result = resume_pipeline(workspace_path="/data/.../pipeline_20260609_...")
# 人工 gate 放行
resume_pipeline(workspace_path=..., human_decision={"stage_id": "simulation", "approved": True})
CLI(薄封装):agentpaas pipeline run research-v1.yml --input "..." / ... resume <workspace>。
| 能力 | v1 | v1.1+ |
|---|---|---|
| 线性顺序阶段 | ✅ | |
| 规则型 gate(safe-eval) | ✅ | |
| LLM-judge gate | ✅ | |
| 人工 gate(暂停+API resume) | ✅ 最小 | UI 审批流 |
| on_fail: retry / halt / escalate / skip | ✅ | |
| 每阶段 workspace + manifest + verdict | ✅ | |
| 恢复续跑 | ✅ | |
| 科研五阶段 preset | ✅ | 更多领域模板 |
| DAG / 并行阶段 | ❌ | ✅ |
| 回滚 / 分支重跑 | ❌ | ✅ |
| 成本预算 gate(cost_grade 集成) | ❌ | ✅ |
| REST API + WebUI | ❌ | ✅ |
| 降解为 Compose-of-Guard term(进 CEK) | ❌(保持语义一致) | ✅ |
read/read_json 等够用的访问器。_safe_eval,PipelineRunner 仅做编排/持久化;保持与 Compose-of-Guard 等价。| 阶段 | 产出 |
|---|---|
| P0 骨架 | pipeline.py:Pipeline/Stage/Gate 数据类 + YAML 解析 + ArtifactSpec 静态校验 |
| P1 执行 | 顺序执行 + 每阶段 workspace(PipelineRunner 拥有 stage 目录,§15 P3-F)/manifest/verdict 落盘 + artifact store(多上游 consumes,§15 P1-C)+ 运行时 ArtifactSpec 契约校验(§15 P2-E) |
| P2 gate | 规则型(受限 gate DSL 求值器,非 _safe_eval,§15 P1-A)✅ → LLM-judge ✅ 已实现(可注入 default_judge,默认本地 ollama,已实测)→ 人工最小版(TODO) |
| P3 状态机 | on_fail 策略 + write-ahead pipeline_state.json + 孤儿处理 + resume/续跑(§15 P1-B) |
| P4 preset+测试 | 科研五阶段 preset + 端到端测试(含 ollama judge 跑通)+ CLI |
| P5 文档 | 用法文档 + 把 claim ③ 从 aspirational 更新为 shipped |
每阶段都应有可跑的测试(参考 test_run_workspace.py / test_ollama.py 的 skip-if-unavailable 模式)。
agentexample/pipelines/research-demo.yml 本地 ollama 实跑 COMPLETED:plan 规则 gate 过、lit judge 0.80 过。五阶段模板见 research-v1.yml(sim/analysis/paper 需带工具 react agent,v1.1)。结论:产物 gate 与 LambdaAgent 形式化(Papers I/II/III)高度自洽——线性流水线 v1 完全在现有构造(
Guard+Compose+ store σ + graded cost)的表达力之内。其中三项理论结果直接产生产品红利(运行前成本预测、可化简、可恢复)。需要的理论补丁仅 4 处,v1 只触及其中 2 处小扩展。
| gate 概念 | 形式化构造 | 出处 | 契合度 |
|---|---|---|---|
| 单个验收阶段 | Guard(stage_agent, predicate, retry=N) |
Paper I 构造 10 | 字面相同 |
| 阶段串联(线性) | Compose(g1, g2, …) |
Paper I 构造 3 | 字面相同 |
| 阶段间产物传递 | CEK 机 store σ 读写 / Memory |
Paper II ⟨C,E,K,σ,c⟩ / Paper I 构造 11 | 契合 |
| 中断恢复(resume) | CEK 状态序列化;pipeline_state.json = 序列化机器状态 |
Paper II CEK + YIELD | 优雅契合 |
| 人工 gate(AWAITING_HUMAN) | YIELD 挂起 + Human Oracle | Paper IV(Oracle Duality) | 契合(依赖 Paper IV) |
| 流水线必然终止 | Bounded Termination,retry 有界 | Paper II Thm 5.4 | 契合 |
对应式(非严格等价 — 见 §15 P1-C):线性流水线的控制流对应
Compose(Guard(s1.agent, gate1, r1), Guard(s2.agent, gate2, r2), …);数据流经共享 store σ(多上游 consumes),不是 Compose 单值穿引。故严格说法 = "Compose(控制)+ store 读写(state effect,数据)"。v1 用专用 PipelineRunner 实现,保持这条对应,为"pipeline 即 term、可进 CEK"留路。
Paper III Def 12 的成本组合规则给出 gate 成本的目标对应(非"已严格覆盖" — 见 §15 P2-D):
(p₁·p₂, t₁+t₂, l₁+l₂, m₁+m₂)Guard.apply 的 1+retry 循环一致)→ (1-(1-p)^k, k·t, k·l, k·m)因此流水线成本上界 = 各阶段 grade_guard 再 grade_serial 折叠,原则上跑前可推断 "≤ $X、≤ T tokens、成功率 ≥ p";p_fatal:gate 没过 = 非致命(重试),API 5xx = 致命。
✅ 已实现 estimate_pipeline_cost(pipeline)(pipeline.py):把 judge 建成真 Lam term(build_judge_term),用 grade_serial(stage_agent, judge_term) 再按 retry grade_guard、阶段间 grade_serial 折叠,给出运行前成本上界。实测 research-demo:lit 阶段 judge 计入 ≤800 tokens / ≤$0.0024 / p≥0.99。这是 Paper33/34 "actual ≤ predicted" 实证的预测侧。
⚠️ 残留差距:estimate_cost 只认 Lam,不认 simple agent 编出的 ConversationLam → 上面 plan 阶段 agent 成本算成 0(只有 judge 那段被计)。要全保真,需给 estimate_cost 加 ConversationLam 分支(小改 cost_grade.py,留 v1.1)。规则型 gate 成本近 0(pure)可忽略。
(s1≫s2)≫s3 = s1≫(s2≫s3):子流水线嵌套/分组不改变语义。Guard(Guard(f,P),P) = Guard(f,P,retry×2):叠 gate = 叠重试,可用于静态化简。| gap | 现状 | 需要的扩展 | v1 是否受影响 |
|---|---|---|---|
| G1 多上游 consumes | Compose 只串一条数据流;但v1 preset 本身就有 simulation 消费 [plan,lit]、paper 消费 [plan,lit,analysis](§15 P1-C 纠正了"v1 不受影响"的错误) | 数据流改走共享 artifact store(每阶段从上游 workspace 读 declared 产物),即 state effect;成本/DAG 拓扑折叠留 v1.1 |
⚠️ v1 受影响:数据流必须经 store,已纳入 §5/§6.3 设计;控制流仍线性 |
| G2 谓词作用域 | Paper 的 Guard 谓词 P(r) 只看返回值;gate 要看 workspace 产物(store) |
Guard 谓词 P(r) → P(r, ctx)(值 + store/产物访问器) |
✅ v1 采纳(自然扩展,σ 本就在 CEK 内) |
| G3 effectful gate | Paper 隐含谓词 pure;LLM-judge gate 有 llm effect |
T-Guard 允许 ε_P ≠ pure,validator 的 effect/cost 计入组合 |
✅ v1 采纳(cost 折叠多加一项) |
| G4 人工 gate | 需 Human Oracle 形式化 | Paper IV:Oracle Duality(LLM oracle ≃ human oracle) | Paper IV 未成文;v1 人工 gate 仅工程最小版 |
P(r, ctx)(见 §7.1),而非 Paper 原始的 P(r)——对齐 G2。ctx 暴露 store/产物访问器。_compile_guard 的 validator_fn 相应从 validator_fn(x) 扩展为 validator_fn(x, ctx=None),向后兼容(旧 Guard 不传 ctx)。llm(m))——对齐 G3;其 token/latency/money 计入该阶段 cost。codex 评审在动手前找出 6 个问题,全部接受并已修订本文档。摘要如下:
| # | 严重度 | 问题 | 修订 |
|---|---|---|---|
| P1-A | 致命 | _safe_eval 表达不了 outputs.has(...),放开属性访问会能力逃逸——"复用 _safe_eval"既不可行也不安全 |
§5/§7.1:改为 pipeline.py 内受限 gate DSL 求值器(固定函数集 has/count/contains/regex/json_len,禁属性/方法链,size/time 上限,路径按 ArtifactSpec 白名单) |
| P1-B | 致命 | 只在"阶段结束"写状态,崩在半途会重复/跳过 retry、孤儿 workspace;retry 计数只在内存;人工 resume 语义未定义 | §6.3:write-ahead(attempt 前 + gate 前各写一次,原子 rename + 锁);孤儿确定性处理(恰好消耗一次 retry);人工 resume 语义明确(approved→PASSED / rejected→FAILED→on_fail) |
| P1-C | 致命 | 多上游 consumes 与"v1 plain Compose"矛盾——v1 preset 本身就需非相邻上游读取 |
§5/§14.1/§14.4-G1:数据流改走共享 artifact store(state effect),对应式降级为"Compose(控制)+ store(数据)",不再声称严格 plain-Compose 等价 |
| P2-D | 中 | §14 成本声称过强:estimate_cost(Guard) 不含 validator 成本;k 含糊 |
§14.2:降级为"目标对应";统一 k = 1+retries;LLM-judge 须建成 term 图里的真 agent(stage≫judge≫parser)其成本才计入 |
| P2-E | 中 | ArtifactSpec 静态校验太弱,只证名字存在,不防契约漂移 | §12-P1:加运行时契约校验(每 attempt 后、gate 前解析 spec、校验 type/cardinality、把路径+hash 记进 verdict、required 缺失即 fail);静态校验另查 consumes 引用合法 |
| P3-F | 低 | workspace 布局与现有 create_run_workspace(时间戳 run 目录)不符,无 API 强制 stage 目录在 pipeline 下 |
§5/§12-P1:PipelineRunner 自己拥有 stage 目录创建(或给 create_run_workspace 加 workspace_root 参数),不依赖时间戳发现 |
结论:三个 P1 在 v1 就必须处理(已纳入 §5/§6.3/§7.1);P2/P3 纳入 P1/P2 实施阶段。原 §14 "高度自洽/严格等价"的措辞过乐观,已据实修正为"控制流对应 + 数据流经 store"。
骨架 pipeline.py 写完后第二轮 codex review,又找出 8 个实现级问题,已修(除完整孤儿恢复):
| # | 严重度 | 问题 | 状态 |
|---|---|---|---|
| P1-1 | 致命(安全) | ArtifactSpec.path 可用绝对路径/.. 逃逸 stage_ws,gate 能读 /etc/passwd |
✅ 已修:_is_safe_relpath + glob 后 commonpath 强制在 ws 内 |
| P1-2 | 致命 | 阶段在重试 attempt 通过后,resume 从 base stage_dir 取数(错目录),下游消费陈旧产物 |
✅ 已修:持久化通过 attempt 的 workspace_path,resume 用它 |
| P1-3 | 致命 | create_run_workspace(run_dir=) 用 exist_ok=True 不清空,复用目录旧产物虚假满足 has() |
✅ 已修:attempt 目录复用前 rmtree 清空 |
| P1-4 | 致命 | on_fail=halt 仍跑 1+retry 次,与"直接 halt"矛盾 |
✅ 已修:retry 预算仅 on_fail==RETRY 时给;halt/escalate/skip = 单次 |
| P1-5 | 致命 | 终态失败只在内存设置、由 caller 后续持久化,留崩溃窗口 | ✅ 部分修:_apply_on_fail 立即原子持久化终态;完整孤儿恢复仍 P3 |
| P2-6 | 中 | 契约校验未做 type/cardinality:json 不解析、dir 可指文件、one 命中多个静默忽略 | ✅ 已修:_type_ok 校验 + cardinality=one 多命中记问题 |
| P2-7 | 中 | regex() 无 timeout,ReDoS |
⚠️ 缓解:pattern 长度上限 200 + 搜索窗 64KB;真 timeout/RE2 留 v1.1 |
| P2-8 | 中 | 规则 gate 未静态校验,执行后才报错 | ✅ 已修:validate_pipeline 对 kind=rule 调 ast.parse + _validate_gate_expr |
codex 同时确认:AST 白名单 + {"__builtins__":{}} 无直接 Python 对象逃逸(Attribute/Subscript/推导式/f-string/walrus/lambda/starred/方法调用全被拒)。
测试 test_pipeline.py 加了负向用例(路径穿越、非法 JSON、静态 gate 校验、halt 不重试、retry-pass resume 取对目录),共 26 个。遗留 P3:崩溃-孤儿 attempt 的确定性恢复、真正的 regex timeout。