章节 01
导读 / 主楼:Fascicle:以函数式组合重新定义智能体工作流的 TypeScript 工具包
Fascicle 是一个轻量级的 TypeScript 库,它将 LLM 调用、工具调用和普通函数统一抽象为可组合的 Step 单元,通过 16 种组合原语构建复杂的智能体工作流,同时保持零框架开销和无状态设计。
正文
Fascicle 是一个轻量级的 TypeScript 库,它将 LLM 调用、工具调用和普通函数统一抽象为可组合的 Step 单元,通过 16 种组合原语构建复杂的智能体工作流,同时保持零框架开销和无状态设计。
章节 01
Fascicle 是一个轻量级的 TypeScript 库,它将 LLM 调用、工具调用和普通函数统一抽象为可组合的 Step 单元,通过 16 种组合原语构建复杂的智能体工作流,同时保持零框架开销和无状态设计。
章节 02
step() 函数创建基础单元,使用组合原语构建复杂逻辑。例如,一个简单的顺序执行流程:\n\ntypescript\nconst flow = sequence([\n step('add', (n: number) => n + 1),\n step('double', (n: number) => n * 2),\n]);\n\nawait run(flow, 1); // 输出: 4\n\n\n## 十六种组合原语:从简单到复杂\n\nFascicle 提供了 16 种组合原语,覆盖从基础流程控制到高级智能体模式的各类场景:\n\n### 基础控制流\n- sequence:顺序执行多个 Step,前一个的输出作为后一个的输入\n- parallel:并行执行多个 Step,返回结果数组\n- branch:条件分支,根据谓词选择执行路径\n- map:对数组中的每个元素应用同一个 Step\n- pipe:函数式管道,将多个单输入单输出 Step 串联\n\n### 容错与重试\n- retry:失败时自动重试,支持指数退避\n- fallback:主 Step 失败时切换到备选方案\n- timeout:为 Step 执行设置时间上限\n\n### 智能体模式\n- ensemble:多模型投票,聚合多个 LLM 的结果\n- tournament:锦标赛模式,两两比较选出最优\n- consensus:共识机制,需要多数模型达成一致\n- adversarial:对抗验证,用评判模型检验输出质量\n\n### 状态与检查点\n- checkpoint:持久化中间状态,支持断点续跑\n- suspend/resume:暂停和恢复工作流执行\n- scope/stash/use:作用域管理,隔离临时状态\n\n这些原语可以任意嵌套组合,构建出从简单数据管道到复杂多智能体协作系统的任意架构。\n\n## 多提供商统一接口\n\nFascicle 的 create_engine() 函数创建一个统一的生成接口,底层适配七个主流 LLM 提供商:\n\n| 提供商 | SDK 依赖 | 认证方式 |\n|--------|----------|----------|\n| Anthropic | @ai-sdk/anthropic | API Key |\n| OpenAI | @ai-sdk/openai | API Key |\n| Google | @ai-sdk/google | API Key |\n| OpenRouter | @openrouter/ai-sdk-provider | API Key |\n| Ollama | ai-sdk-ollama | 本地 base_url |\n| LM Studio | @ai-sdk/openai-compatible | 本地 base_url |\n| Claude CLI | 无(子进程) | OAuth 或 API Key |\n\n引擎支持模型别名(如 'sonnet'、'gpt-4o')和推理强度配置(low/medium/high),开发者可以在不改动业务代码的情况下切换底层模型。成本估算功能基于内置的定价表,帮助团队在开发阶段就预估运行开销。\n\n## 可观测性:从黑盒到白盒\n\n智能体系统的调试历来是痛点。Fascicle 通过轨迹(trajectory)机制提供全程可观测性:\n\n- 执行轨迹:每个 Step 的输入、输出、耗时、错误都被记录\n- 流式事件:run.stream() 返回事件流,支持实时监控\n- 可视化查看器:内置的 fascicle-viewer 命令可以打开浏览器界面,以树形结构展示执行过程\n\n开发者可以注入自定义的轨迹记录器,比如写入文件或发送到远程日志服务:\n\ntypescript\nawait run(flow, input, {\n trajectory: filesystem_logger({ output_path: '.trajectory.jsonl' }),\n checkpoint_store: filesystem_store({ root_dir: '.checkpoints' }),\n});\n\n\n## 与框架的对比\n\n相比 LangChain、LlamaIndex 等框架,Fascicle 的定位更接近"工具库"而非"框架":\n\n| 特性 | Fascicle | 传统框架 |\n|------|----------|----------|\n| 生命周期管理 | 无 | 有(需遵循框架约定) |\n| 状态管理 | 显式传递 | 通常隐式/全局 |\n| 装饰器/注解 | 无 | 常见 |\n| 提供商耦合 | 运行时注入 | 通常编译期依赖 |\n| 学习曲线 | 低(掌握组合原语即可) | 高(需理解框架架构) |\n| 灵活性 | 高(任意组合) | 中(受框架约束) |\n\n这种设计使得 Fascicle 特别适合以下场景:\n- 需要精细控制执行流程的复杂智能体系统\n- 对类型安全有严格要求的金融、医疗等敏感领域\n- 希望避免框架锁定、保持代码可移植性的团队\n- 需要嵌入现有代码库、渐进式引入 LLM 能力的遗留项目\n\n## 实践启示\n\nFascicle 的设计哲学对智能体开发有几点重要启示:\n\n1. 组合优于继承:通过小型的、可复用的 Step 单元构建系统,比继承框架基类更灵活\n2. 显式优于隐式:状态、依赖、副作用都应当显式传递,降低心智负担\n3. 延迟绑定:提供商配置延迟到运行时注入,便于测试和切换\n4. 可观测性内建:调试能力应当从设计之初就纳入考量,而非事后补丁\n\n对于正在构建智能体系统的开发者,Fascicle 提供了一个值得认真考虑的轻量级替代方案。它证明了:构建复杂的 LLM 应用并不一定需要重量级框架,有时候,一套精心设计的组合原语就足够了。章节 03
背景:智能体编排的复杂度困境\n\n随着大型语言模型(LLM)能力的快速演进,开发者们越来越倾向于构建多步骤的智能体系统来完成复杂任务。然而,现有的解决方案往往陷入两难:要么使用重量级框架,被迫接受其生命周期管理和隐式状态带来的心智负担;要么自行拼凑代码,在异步流程控制、错误处理和可观测性之间疲于奔命。\n\nFascicle 的出现正是为了打破这一困境。它不提供框架式的约束,而是将"组合"作为核心抽象——任何操作,无论是简单的数学计算、外部 API 调用,还是 LLM 推理,都被封装为统一的 Step<i, o> 类型,开发者通过声明式的原语将它们编织成完整的工作流。\n\n核心设计:Step 即值\n\nFascicle 的哲学可以用一句话概括:Everything is a Step<i, o>。Step 是一个泛型抽象,代表"接受输入类型 i,产出输出类型 o 的异步计算单元"。这种设计的精妙之处在于:\n\n- 统一性:普通函数、LLM 调用、工具调用都被视为同构的 Step,可以无缝衔接\n- 可组合性:Step 可以像乐高积木一样被拼接、嵌套、并行执行\n- 可测试性:每个 Step 都是纯值,易于单独测试和 mock\n- 类型安全:完整的 TypeScript 类型推导,输入输出类型在编译期即被约束\n\n开发者使用 step() 函数创建基础单元,使用组合原语构建复杂逻辑。例如,一个简单的顺序执行流程:\n\ntypescript\nconst flow = sequence([\n step('add', (n: number) => n + 1),\n step('double', (n: number) => n * 2),\n]);\n\nawait run(flow, 1); // 输出: 4\n\n\n十六种组合原语:从简单到复杂\n\nFascicle 提供了 16 种组合原语,覆盖从基础流程控制到高级智能体模式的各类场景:\n\n基础控制流\n- sequence:顺序执行多个 Step,前一个的输出作为后一个的输入\n- parallel:并行执行多个 Step,返回结果数组\n- branch:条件分支,根据谓词选择执行路径\n- map:对数组中的每个元素应用同一个 Step\n- pipe:函数式管道,将多个单输入单输出 Step 串联\n\n容错与重试\n- retry:失败时自动重试,支持指数退避\n- fallback:主 Step 失败时切换到备选方案\n- timeout:为 Step 执行设置时间上限\n\n智能体模式\n- ensemble:多模型投票,聚合多个 LLM 的结果\n- tournament:锦标赛模式,两两比较选出最优\n- consensus:共识机制,需要多数模型达成一致\n- adversarial:对抗验证,用评判模型检验输出质量\n\n状态与检查点\n- checkpoint:持久化中间状态,支持断点续跑\n- suspend/resume:暂停和恢复工作流执行\n- scope/stash/use:作用域管理,隔离临时状态\n\n这些原语可以任意嵌套组合,构建出从简单数据管道到复杂多智能体协作系统的任意架构。\n\n多提供商统一接口\n\nFascicle 的 create_engine() 函数创建一个统一的生成接口,底层适配七个主流 LLM 提供商:\n\n| 提供商 | SDK 依赖 | 认证方式 |\n|--------|----------|----------|\n| Anthropic | @ai-sdk/anthropic | API Key |\n| OpenAI | @ai-sdk/openai | API Key |\n| Google | @ai-sdk/google | API Key |\n| OpenRouter | @openrouter/ai-sdk-provider | API Key |\n| Ollama | ai-sdk-ollama | 本地 base_url |\n| LM Studio | @ai-sdk/openai-compatible | 本地 base_url |\n| Claude CLI | 无(子进程) | OAuth 或 API Key |\n\n引擎支持模型别名(如 'sonnet'、'gpt-4o')和推理强度配置(low/medium/high),开发者可以在不改动业务代码的情况下切换底层模型。成本估算功能基于内置的定价表,帮助团队在开发阶段就预估运行开销。\n\n可观测性:从黑盒到白盒\n\n智能体系统的调试历来是痛点。Fascicle 通过轨迹(trajectory)机制提供全程可观测性:\n\n- 执行轨迹:每个 Step 的输入、输出、耗时、错误都被记录\n- 流式事件:run.stream() 返回事件流,支持实时监控\n- 可视化查看器:内置的 fascicle-viewer 命令可以打开浏览器界面,以树形结构展示执行过程\n\n开发者可以注入自定义的轨迹记录器,比如写入文件或发送到远程日志服务:\n\ntypescript\nawait run(flow, input, {\n trajectory: filesystem_logger({ output_path: '.trajectory.jsonl' }),\n checkpoint_store: filesystem_store({ root_dir: '.checkpoints' }),\n});\n\n\n与框架的对比\n\n相比 LangChain、LlamaIndex 等框架,Fascicle 的定位更接近"工具库"而非"框架":\n\n| 特性 | Fascicle | 传统框架 |\n|------|----------|----------|\n| 生命周期管理 | 无 | 有(需遵循框架约定) |\n| 状态管理 | 显式传递 | 通常隐式/全局 |\n| 装饰器/注解 | 无 | 常见 |\n| 提供商耦合 | 运行时注入 | 通常编译期依赖 |\n| 学习曲线 | 低(掌握组合原语即可) | 高(需理解框架架构) |\n| 灵活性 | 高(任意组合) | 中(受框架约束) |\n\n这种设计使得 Fascicle 特别适合以下场景:\n- 需要精细控制执行流程的复杂智能体系统\n- 对类型安全有严格要求的金融、医疗等敏感领域\n- 希望避免框架锁定、保持代码可移植性的团队\n- 需要嵌入现有代码库、渐进式引入 LLM 能力的遗留项目\n\n实践启示\n\nFascicle 的设计哲学对智能体开发有几点重要启示:\n\n1. 组合优于继承:通过小型的、可复用的 Step 单元构建系统,比继承框架基类更灵活\n2. 显式优于隐式:状态、依赖、副作用都应当显式传递,降低心智负担\n3. 延迟绑定:提供商配置延迟到运行时注入,便于测试和切换\n4. 可观测性内建:调试能力应当从设计之初就纳入考量,而非事后补丁\n\n对于正在构建智能体系统的开发者,Fascicle 提供了一个值得认真考虑的轻量级替代方案。它证明了:构建复杂的 LLM 应用并不一定需要重量级框架,有时候,一套精心设计的组合原语就足够了。