第 1 章 · Flue 概述与 Harness 理念
本章目标:理解从"裸 LLM API 调用"到"自主 Agent"的架构演进,弄清 Harness(马具架)到底是什么,掌握 Flue 的核心特性全景。
1.1 从裸 API 到自主 Agent 的三代演进
第一代:裸 LLM API 调用。 你把提示词发给模型、拿回一段文本。它能写诗、能翻译,但每一步都要人来驱动——它不会自己查数据库、不会自己重试、也没有记忆。
// 第一代:一次请求一次响应,模型只能"说话",不能"做事"
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
model: 'claude-sonnet-4-6',
max_tokens: 1024,
messages: [{ role: 'user', content: '帮我看看 issue #42 是什么问题' }],
}),
});
// 模型只能回答"我无法访问你的 GitHub"——它没有任何行动能力第二代:脚本化工作流。 你在代码里写死步骤:先调摘要接口、再调分类接口、最后写库。可靠但僵硬——任何计划外的输入都会让流程崩掉。
第三代:自主 Agent。 Claude Code、Codex 这类产品证明了一件事:给模型一个目标而不是一串步骤,让它自主决定调用哪些工具、循环迭代直到完成——它能完成远超脚本的复杂任务。
1.2 Harness:让模型真正能干活的那套"马具"
一匹好马没有马具拉不动车;一个强模型没有 Harness 也干不了活。Harness 就是围绕 LLM 的那层运行时基础设施:
| 组成部分 | 作用 |
|---|---|
| 会话(Session) | 让对话有持久状态,跨轮次记住上下文 |
| 工具(Tools) | 让模型能调用你的应用代码、影响外部系统 |
| 技能(Skills) | 按需加载的领域知识,教它"怎么做某类事" |
| 沙箱(Sandbox) | 安全的文件与命令执行环境 |
| 循环控制 | 处理工具调用→结果回传→继续推理的循环 |
一句话理解
LLM 是发动机,Harness 是整车——方向盘、油门、刹车、仪表盘。Flue 要做的就是把造车这件事标准化。
1.3 Flue 是什么
Flue 是 Astro 团队打造的开源 Agent Harness 框架。它的核心洞察是:用 React 的心智模型来写 Agent——Agent 就是一个函数,能力通过 Hook 组合进来:
// 一个完整的 Flue Agent 长这样——是不是很像 React 组件?
'use agent';
import { useModel, useSandbox, useSkill, useTool } from '@flue/runtime';
import { local } from '@flue/runtime/node';
import triage from '../skills/triage/SKILL.md';
import verify from '../skills/verify/SKILL.md';
import { openIssue, searchCode } from '../tools/github.ts';
// Agent 即函数:函数体声明能力,返回值就是任务指令
export function Triage() {
useModel('anthropic/claude-sonnet-4-6'); // 选模型
useSandbox(local()); // 给它本地沙箱
useSkill(triage); // 挂载分诊技能
useSkill(verify); // 挂载验证技能
useTool(openIssue); // 挂载 GitHub 工具
useTool(searchCode);
// 返回值成为 agent 的 system instructions(系统指令)
return `
分诊一个 bug 报告:复现问题、定位根因、
判断该行为是否符合预期,并尝试修复。`;
}1.4 核心特性总览
| 特性 | 说明 | 对应 Hook / 包 |
|---|---|---|
| Agents | 自主完成目标的智能体,跨对话保持上下文 | 'use agent' 函数 |
| Models | 接入任意 Pi 支持的 Provider(Anthropic/OpenAI/DeepSeek 等) | useModel() |
| Tools | 类型安全的应用代码调用 | defineTool() + useTool() |
| Skills | 开放 Agent Skills 格式的可复用技能包 | useSkill() |
| Subagents | 专家子代理委派 | useSubagent() |
| Sandboxes | 本地/远程容器执行环境 | useSandbox() |
| Durability | 崩溃与重启后恢复任务进度 | 内置持久化 |
| Channels | Slack/Teams/Discord/GitHub 等事件接入 | src/channels/ |
| MCP | 连接开放 MCP 工具生态 | useMcpConnection() |
| Observability | OpenTelemetry/Sentry 等遥测导出 | @flue/opentelemetry |
部署同样灵活:Node.js、Cloudflare Workers、GitHub Actions、GitLab CI/CD、Render 都是一等公民。
1.5 技术栈与包结构
Flue 构建在 Pi(Earendil Works 的 agent 运行时)之上,复用其全部 Provider 支持。核心包分工明确:
@flue/runtime # 核心:harness、sessions、tools、sandbox
@flue/vite # Vite 插件:vite dev / vite build 构建
@flue/cli # flue 命令行:本地运行、项目初始化
@flue/sdk # 客户端 SDK:消费已部署 agent 的对话
@flue/opentelemetry # OpenTelemetry 追踪适配器
@flue/postgres # Postgres 持久化适配器// 典型的开发依赖安装
// npm install @flue/runtime @flue/cli
// 部署时追加:
// npm install @flue/vite hono vite
// flue.config.ts —— 项目级配置,target 决定构建目标
import { defineConfig } from '@flue/runtime/config';
export default defineConfig({
target: 'node', // 或 'cloudflare'
});// 部署形态下的最小服务端入口(第 2 章详解)
// src/app.ts —— 把 Triage agent 挂到 HTTP 路由
import { createAgentRouter } from '@flue/runtime/routing';
import { Hono } from 'hono';
import { Triage } from './agents/triage.ts';
const app = new Hono();
app.route('/agents/triage', createAgentRouter(Triage));
export default app;版本要求
Flue 要求 Node.js ≥ 22.19.0。动手前先 node --version 确认。
本章小结
- Agent 演进三阶段:裸 API → 脚本工作流 → 自主 Agent;
- Harness 是围绕 LLM 的会话、工具、技能、沙箱等运行时基础设施;
- Flue 用 React 式心智模型写 Agent:函数即 Agent,Hook 即能力;
- 核心包是
@flue/runtime,构建走 Vite,部署支持 Node 与 Cloudflare。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. 裸 LLM API 调用最大的局限是什么?
2. Flue 中 Agent 函数的返回值是什么?
3. Flue 的核心运行时包是哪一个?
4. 下列哪一项不属于 Harness 的职责范围?
🛠️ 动手实践
- 用自己的话向同事解释"Harness 为什么不能省略":如果只给你裸 API,让模型帮你统计仓库 star 数缺了哪几块能力?
- 浏览 https://github.com/withastro/flue 的 packages 目录,列出六个核心包各自的一句话职责。
- 对照 1.4 的特性表,想想你手头哪个重复劳动最适合交给一个自主 Agent,写下它的目标和需要的工具清单。
概念清楚了?下一章我们搭建项目并跑通第一个 Agent。