7.1 KiB
7.1 KiB
focus — 纯 Rust 实现的 LLM Agent 框架
参考 pi(TypeScript 原版)与 pi_agent_rust(Rust 移植)实现的 分层、极简依赖的 LLM agent 框架。核心目标:以最小的依赖面实现一个分层清晰、 可独立测试的 agent 框架,重点学习 pi 的核心设计——agent 循环、消息类型、工具抽象、流式协议。
✨ 核心特性
- 双层 agent 循环:外层 follow-up、内层 steering + 工具执行,支持 sequential / parallel 两种工具执行模式
- 流式输出:SSE 增量解析,流式 assistant 消息随 delta 原地更新;
Esc随时中止 - 多 provider 支持:Anthropic(Messages API)+ OpenAI(Responses API 与 Chat Completions 双协议),统一翻译为
StreamEvent事件流,错误编码进事件而非中断循环 - 内置工具:
read/write/edit(pi 风格精确替换)/shell,跨平台(Windows + Linux) - 会话管理:树形会话结构(
id+parentId)+ JSONL 追加写,支持分支与会话切换 - 上下文压缩:token 估算 + 压缩方案(切点 + 摘要指令),自动执行滚动总结
- 交互式 TUI:多行输入、Markdown 渲染、实时 transcript、折叠的思考/工具块、跨平台滚轮滚动
- 类型安全:自研
focus-json手写 JSON 编解码,不依赖 serde / serde_json - 依赖极简:运行时依赖仅 tokio + rustls 生态(另为 TUI 特批 ratatui + crossterm)
🏗️ 架构设计
细粒度 7-crate workspace 拆分,每个 crate 职责单一、边界清晰、可独立测试。依赖严格单向向下,禁止循环。
focus/
├── crates/
│ ├── focus-json/ # 极简 JSON 解析器 / 序列化器(零外部依赖)
│ ├── focus-core/ # ★ 核心层:领域类型 + Agent 循环 + Tool / StreamProvider trait
│ ├── focus-transport/ # 传输层:HTTPS 客户端(tokio + rustls)、HTTP/1.1、SSE 解析
│ ├── focus-providers/ # Provider 实现(Anthropic / OpenAI)
│ ├── focus-tools/ # 文件工具(read / write / edit / shell)
│ ├── focus-harness/ # 会话持久化 + 上下文压缩 + 系统提示模板
│ └── focus-tui/ # 终端交互层(ratatui + crossterm),组装所有模块
├── docs/architecture/ # 架构解读文档(三份精读笔记)
└── AGENTS.md # 工程规范(依赖白名单、代码/测试/提交规范)
分层依赖图
focus-json ← 零外部依赖,纯 std
focus-core ← focus-json, tokio
focus-transport ← focus-json, tokio, rustls, tokio-rustls, rustls-native-certs
focus-providers ← focus-core, focus-transport
focus-tools ← focus-core
focus-harness ← focus-core, focus-json
focus-tui ← focus-core, focus-providers, focus-tools, focus-harness, focus-json, ratatui, crossterm
核心设计要点
- I/O 边界注入:
focus-core是纯逻辑层,不碰网络 / 文件系统;provider 与工具都通过 trait 注入 content/details分离:工具结果的content(模型可见)与details(UI / 日志可见)分开- 错误编码而非抛出:
StreamProvider绝不用Err中断循环,错误编码进StreamEvent::Error - 压缩只出方案:harness 产出「压缩方案」,真正的摘要 LLM 调用由上层(TUI)执行——遵守依赖图约束
🚀 快速开始
构建与测试
# 构建整个 workspace
cargo build --workspace
# 运行全部测试(181 个用例,全绿)
cargo test --workspace
# 代码质量检查
cargo fmt --all --check
cargo clippy --workspace -- -D warnings
运行 TUI
cargo run -p focus-tui
或直接运行构建产物
target/debug/focus。
首次启动后先配置 provider:
- 在 TUI 中输入
/config打开配置表单(或直接编辑~/.focus/config.json) - 填写
apiKey、选择 provider 与模型 - 回到输入框即可开始对话
⚙️ 配置
配置文件位于 <data>/config.json,<data> 默认为 ~/.focus
(Windows 为 %USERPROFILE%\.focus),可用环境变量 FOCUS_DATA_DIR 覆盖。
{
"provider": "anthropic",
"openaiProtocol": "responses",
"baseUrl": "https://api.anthropic.com",
"apiKey": "sk-...",
"model": "claude-sonnet-4-5",
"contextWindow": 200000
}
| 字段 | 说明 |
|---|---|
provider |
anthropic 或 openai |
openaiProtocol |
OpenAI 协议:responses(默认)或 chatCompletions |
baseUrl |
API 基址(可选,缺省用默认端点;具体端点路径由 provider 自行拼接) |
apiKey |
API 密钥 |
model |
模型 id |
contextWindow |
上下文窗口(可选,缺省按已知模型表自动查询,未知模型兜底 128k) |
数据目录
| 内容 | 位置 |
|---|---|
| 配置 | <data>/config.json |
| 会话 | <data>/sessions/<session-id>.jsonl(JSONL 追加写,树结构) |
环境变量
| 变量 | 说明 |
|---|---|
FOCUS_DATA_DIR |
覆盖数据根目录(默认 ~/.focus) |
FOCUS_SHELL |
覆盖 shell 工具使用的 shell 程序(Windows 默认 PowerShell、可回退 cmd;Linux 默认 bash) |
FOCUS_DEBUG_FILE |
设置后,providers 把每个原始网络 chunk 追加到该文件(排查协议不兼容,如推理字段名差异) |
⌨️ TUI 使用
命令
| 命令 | 功能 |
|---|---|
/new |
新建会话 |
/sessions |
查看 / 切换历史会话 |
/config |
编辑配置(provider / 模型 / 密钥) |
/compact |
手动触发上下文压缩 |
/help |
显示帮助 |
键盘
| 按键 | 功能 |
|---|---|
Enter |
发送消息 |
Shift+Enter |
换行 |
Esc |
运行中中止任务;空闲时退出 |
Ctrl+C |
退出 |
Ctrl+D |
继续(追问一轮) |
Tab |
展开 / 折叠最近的思考或工具块(两级:先预览,再全量) |
| 鼠标滚轮 | 逐行滚动(Linux / Windows 均支持;上滚暂停自动跟随) |
Ctrl+U / PageUp / PageDown |
滚动消息区(输入为空时 ↑ ↓ 也可滚动) |
🧪 测试
- 所有测试位于各 crate 的
crates/<name>/tests/,禁止在src/内联测试 - 核心层(
focus-core)测试零网络依赖,用 mock provider 驱动 - provider 测试用录制 / 回放的 mock transport,不打真实 API(真实 API 测试用
#[ignore]标记) - 当前共 181 个测试用例,
cargo test --workspace全绿
📚 文档
AGENTS.md— 工程规范:依赖白名单、双语注释规则、代码 / 测试 / Git 提交规范docs/architecture/00-pi-architecture-overview.md— 参考项目架构全景总览docs/architecture/01-types-and-protocol.md— 类型契约逐行精读docs/architecture/02-agent-loop.md— 核心循环逐行精读