单个基因已经很强大,但真正的魔法在于组合。基因代数 — Seq、Par、Cond、Try 和 Transform — 让你把简单基因连接成复杂的 Agent 流水线,同时保持类型安全、可验证和自动优化。
本教程将带你构建一个实际的流水线:搜索网络 → 摘要结果 → 格式化输出 — 然后扩展它,加入并行执行、条件分支和错误恢复。
前置条件
- 已安装 Rotifer CLI(
npm i -g @rotifer/playground) - 已初始化项目(
rotifer init my-pipeline && cd my-pipeline) - 了解基本基因概念(参见 5 分钟创建你的第一个基因)
第一步:了解构建块
项目已包含 genesis 基因。查看现有基因:
rotifer arena list┌──────┬─────────────────────┬────────────┬────────┬──────────┐│ # │ Name │ Domain │ F(g) │ Fidelity │├──────┼─────────────────────┼────────────┼────────┼──────────┤│ 1 │ genesis-web-search │ search.web │ 0.9200 │ Native ││ 2 │ genesis-search-lite │ search.web │ 0.7100 │ Native ││ 3 │ genesis-code-format │ code.format│ 0.8800 │ Native │└──────┴─────────────────────┴────────────┴────────┴──────────┘我们将用 genesis-web-search 作为第一阶段。接下来需要一个摘要基因。
第二步:创建摘要基因
mkdir -p genes/summarizer编写 genes/summarizer/index.ts:
export async function express(input: { text: string; maxLength?: number;}) { const maxLen = input.maxLength || 200; const sentences = input.text.split(/[.!?]+/).filter(Boolean);
let summary = ""; for (const sentence of sentences) { if ((summary + sentence).length > maxLen) break; summary += sentence.trim() + ". "; }
return { summary: summary.trim(), wordCount: summary.split(/\s+/).length, };}包装并提交:
rotifer wrap summarizer --domain text.summarizerotifer compile summarizerrotifer arena submit summarizer第三步:第一个组合 — Seq(顺序执行)
Seq 按顺序执行基因,将每个基因的输出作为下一个基因的输入:
Seq(A, B, C) = A → B → C但是 genesis-web-search 的输出是 { results: [...] },而 summarizer 期望 { text: string }。我们需要 Transform 来桥接 schema:
import { Seq, Transform } from "@rotifer/algebra";
const searchAndSummarize = Seq( "genesis-web-search", Transform((searchResult) => ({ text: searchResult.results.map(r => r.snippet).join(" "), maxLength: 200, })), "summarizer");创建 Agent:
rotifer agent create researcher --genes genesis-web-search summarizer运行:
rotifer agent run researcher --input '{"query": "quantum computing 2026"}' --verbose--verbose 标志显示每个阶段的中间输入和输出。
第四步:并行执行 — Par
如果你想同时搜索多个数据源?Par 并发执行基因:
Par(A, B, C) = A ‖ B ‖ C → [resultA, resultB, resultC]import { Par, Seq, Transform } from "@rotifer/algebra";
const multiSourceSearch = Seq( Par( "genesis-web-search", "genesis-web-search-lite" ), Transform((results) => ({ text: results.flat().map(r => r.results?.map(x => x.snippet)).flat().join(" "), maxLength: 300, })), "summarizer");两个搜索通过线程池并行运行。结果收集到数组中,然后由 Transform 合并后传给摘要基因。
第五步:条件分支 — Cond
Cond 根据运行时谓词路由执行:
import { Cond, Seq, Transform } from "@rotifer/algebra";
const adaptivePipeline = Seq( "genesis-web-search", Cond( (result) => result.results.length > 10, Seq( Transform((r) => ({ text: r.results.map(x => x.snippet).join(" "), maxLength: 500, })), "summarizer" ), Transform((r) => ({ summary: r.results[0]?.snippet || "未找到结果。", wordCount: 0, })) ));如果搜索返回超过 10 条结果,进行摘要处理。否则,直接返回第一条摘要。
第六步:错误恢复 — Try
Try 尝试主基因,如果失败则回退到备用基因:
import { Try, Seq, Transform } from "@rotifer/algebra";
const resilientPipeline = Seq( Try( "genesis-web-search", "genesis-web-search-lite" ), Transform((r) => ({ text: r.results.map(x => x.snippet).join(" "), maxLength: 200, })), "summarizer");如果主搜索失败(网络错误、速率限制等),执行自动回退到 lite 版本。无需手动错误处理。
第七步:完整流水线
将所有算子组合成一个生产级流水线:
import { Seq, Par, Cond, Try, Transform } from "@rotifer/algebra";
const productionPipeline = Seq( // 阶段 1:弹性多源搜索 Try( Par("genesis-web-search", "genesis-web-search-lite"), Par("genesis-web-search-lite") // 回退:单一数据源 ),
// 阶段 2:合并并行结果 Transform((results) => ({ text: results.flat() .map(r => r.results?.map(x => x.snippet)) .flat() .filter(Boolean) .join(" "), resultCount: results.flat().reduce((n, r) => n + (r.results?.length || 0), 0), })),
// 阶段 3:自适应摘要 Cond( (data) => data.resultCount > 5, Seq( Transform((d) => ({ text: d.text, maxLength: 400 })), "summarizer" ), Transform((d) => ({ summary: d.text.slice(0, 200), wordCount: 0 })) ),
// 阶段 4:格式化输出 "genesis-code-format");创建并运行 Agent:
rotifer agent create research-bot \ --genes genesis-web-search genesis-web-search-lite summarizer genesis-code-format
rotifer agent run research-bot \ --input '{"query": "rotifer protocol gene evolution"}' \ --verbose类型安全
组合代数在组合时强制执行 schema 兼容性。如果你连接了两个不兼容的基因,会得到清晰的错误:
Error[E0032]: Type mismatch in Seq composition → gene 'web-search' output: { results: SearchResult[] } → gene 'summarizer' input: { text: string, maxLength?: number }
help: Add a Transform between the genes to reshape the data这在运行时之前就能捕获数据流 bug。
组合基因的适应度
组合有自己的适应度评分:
| 算子 | 适应度公式 |
|---|---|
Seq | min(F(组件)) × 延迟惩罚 |
Par | avg(F(组件)) × 并行奖励 |
Try | F(主) × 成功率 + F(备用) × (1 - 成功率) |
Arena 将组合作为整体评估,因此存在选择压力推动高效的组合结构。
你学到了什么
- Seq 将基因链接成顺序流水线
- Par 并发运行基因,提升速度和冗余
- Cond 根据运行时条件路由执行
- Try 提供自动错误恢复与回退
- Transform 桥接基因之间的 schema 不匹配
- 组合是类型安全的,并且有复合适应度评分