Saddler
Saddler 是一个白盒、事件溯源的 Agent Harness 运行时。它用声明式配置组合 Prompt、Tool、Middleware、Skill、模型参数和执行预算,并在 Local、Worker 或 HTTP/SSE Service 中运行同一个 Agent。
Quick Start
Saddler 要求 Python 3.10+、uv 和一个 OpenAI-compatible 模型服务。
Saddler 以 saddler-harness 为发行包名发布到 PyPI;Python import package 和命令行入口仍为 saddler。
从 PyPI 安装正式发布版本和可选的 Langfuse 集成。uv tool install 会把
Saddler 安装到用户级的独立环境,并将 saddler 命令持久暴露到 PATH:
uv tool install "saddler-harness[langfuse]"
saddler --help
如果希望 Saddler 只属于当前项目,并通过 pyproject.toml 和 uv.lock 固定版本,把它
加入开发依赖并通过项目环境运行:
uv add --dev "saddler-harness[langfuse]"
uv run saddler --help
如果 Saddler 是应用的正式运行时依赖,省略 --dev。只需临时运行、不修改当前项目或
持久安装时,使用隔离的临时工具环境:
uvx --isolated --from "saddler-harness[langfuse]" \
saddler --help
下文以用户级持久安装后的 saddler 命令为例。使用项目级安装时,在命令前加 uv run;
临时运行时,在上述 uvx ... saddler 后传入相同参数。
在运行目录创建 .env。该文件包含凭证,不应提交到版本控制:
OPENAI_API_KEY=...
OPENAI_BASE_URL=https://your-openai-compatible-server/v1
OPENAI_MODEL=your-model
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_BASE_URL=https://cloud.langfuse.com
后三个变量只在启用 Langfuse 时需要。检查并运行随 wheel 发布的 Coding Agent,同时把 Trace 上报到 Langfuse:
saddler inventory builtin --item coding_agent
saddler run builtin/coding_agent \
"Inspect the current directory and summarize the project." \
--langfuse
启用 --langfuse 后,CLI 会在 Attempt 接纳时打印该次 Trace 的可点击 Langfuse URL,便于直接查看运行中的 Agent。
run 在执行过程中实时显示已提交的 Step、Model、Tool、上下文变化和终态进度,并按实际上下文顺序显示 System、User、Reasoning、Assistant、Tool Call 和 Tool message;结束后再展示 effective System Prompt、完整消息、Tool 请求与响应、最终结果和时间线。同一个 Attempt 可以同时在 Langfuse 中查看。不需要 Langfuse 时,省略三个环境变量、安装地址中的 [langfuse] 和 --langfuse。saddler show 会列出最近 Run 的 input 和结果摘要;运行结束后可以重新查看最近一次完整结果:
saddler show latest
单文件 HTML 报告使用明确的 Run ID:
saddler show RUN_ID --html run.html
源码仓库中的命令需要以 uv run 开头。开发环境通过 uv sync --all-extras --all-groups --locked 安装。
Scope
Saddler 负责解析 Harness、驱动每个 Attempt 的 Agent tool-calling loop、执行 Middleware、编排显式 Agent 调用、提交运行事实并物化审计视图。它不替代模型,不定义训练算法,也不提供不可信代码的 sandbox。
flowchart TD
H["Harness"] --> R["Resolve and admit"]
R --> A["Agent loop"]
A --> M["Model"]
A --> T["Tools"]
W["Middleware"] --> A
A --> E["Canonical events"]
E --> V["Trajectory, playback and evaluation"]
Local、Worker 和 Service 共享 Harness 解析器、Agent loop 和持久化语义。相同 Harness 在不同宿主中具有相同的组件组成和执行规则。
Composable Harness
Inventory 提供积木,Harness 负责选择、配置和排列这些积木。一个 Harness 可以通过 <inventory>/<item-id> 同时组合 builtin、团队或项目 Inventory 中的组件:
flowchart LR
subgraph I["Inventories:可复用组件库"]
P["Instructions / Prompt<br/>告诉模型做什么"]
T["Tools<br/>给模型执行能力"]
M["Middleware<br/>在调用前后扩展行为"]
S["Skills<br/>提供按需知识和流程"]
end
P --> H["Harness<br/>选择、配置和排序"]
T --> H
M --> H
S --> H
B["Sampling / Budget<br/>生成参数和执行上限"] --> H
H --> R["Resolved Harness<br/>校验后的不可变执行配置"]
R --> X["Local / Worker / Service"]
| 组件 | 作用 |
|---|---|
| Instructions / Prompt | 就是 Agent 的基础 System Prompt:直接告诉模型“你是谁、要完成什么、如何工作、哪些规则必须遵守”。可以内联文本,也可以引用 Inventory 中的 Prompt。 |
| Tool | 告诉模型“你能做什么”,声明可调用能力和参数 schema,并绑定 Python、MCP 或宿主提供的实际操作。 |
| Middleware | 在 Model 或 Tool 调用前后插入行为,例如读取项目指令、改写上下文、安全重试、限制输出、压缩历史或清理资源。 |
| Skill | 提供模型可按需加载的领域知识、操作规范和工作流。 |
| Sampling / Budget | 控制模型如何生成,以及最多可使用的 Step、Model、Tool、Agent call、Token 和时间。 |
Middleware 是 Harness 的主要行为扩展点。before_* Hook 正序执行,after_* Hook 逆序执行,wrap_* Hook 以洋葱结构包围实际操作;它可以改变一次 Model 或 Tool 调用的有效输入和结果,但不能绕过 Runtime 的预算、持久化和完整性规则。Python Tool 和自定义 Middleware 都是受信任的进程内代码。完整组装规则见 Agent assembly,内建实现见 Middleware reference。
Capabilities
| 能力 | 行为 |
|---|---|
| Inventory | 从 builtin、本地目录、zip、HTTP 或 OSS 加载 Agent、Prompt、Tool、Middleware 和 Skill。 |
| Harness | 在执行前解析组件引用、配置、Tool schema、模型参数和预算。 |
| Runtime | 执行 Agent tool-calling loop 和一层同步 Agent 调用,并处理预算、超时、取消和上下文变化。 |
| Tool | 支持 Python Tool、MCP stdio 和 MCP Streamable HTTP。 |
| Hosting | 通过 Python API、长生命周期 Worker、CLI 或 HTTP/SSE Service 运行 Agent。 |
| Audit | 将 Canonical Event 作为运行事实来源,并物化 Semantic Trajectory、ATIF-v1.7 和可携带的 Attempt Bundle。 |
| Bundle | 保存完整 Event/model evidence,可选回收 workspace,并通过 filesystem 或 OSS 汇聚批量运行产物。 |
| Session | 通过线性 revision 续接跨 Run 对话,不改变独立 Run 的语义。 |
| Observability | 提供 SSE、结构化日志、Prometheus Metrics 和可选 Langfuse Trace。 |
Langfuse
saddler run --langfuse 直接从当前目录 .env 或进程环境创建 Langfuse client,不需要 Service Config,也不会启动 HTTP Service。源码开发环境先安装 extra:
uv sync --extra langfuse --all-groups --locked
CLI 必须能够读取 LANGFUSE_PUBLIC_KEY、LANGFUSE_SECRET_KEY 和 LANGFUSE_BASE_URL;还可以设置:
LANGFUSE_ENVIRONMENT=development
LANGFUSE_RELEASE=saddler-local
Saddler 会将每个 Attempt 的 Harness、Model、Tool、有效 Middleware 变化和终态异步投影到 Langfuse,并在 CLI 正常退出时 flush。Python 集成也可以通过 langfuse_client 参数直接注入 SaddlerWorker。Langfuse 会接收完整 Prompt、消息、reasoning、Tool 参数和结果,应将对应项目按敏感数据系统管理。完整 Worker 示例见 Langfuse tracing。
运行中的根 saddler.agent 尚未结束,因此不会出现在 Langfuse 默认的 Root Observations 视图。要查看正在执行的 Attempt,在 Observations 页面移除 Is Root Observation = true,筛选 Name = harness.resolved、Tags contains saddler 和 Tags contains trace_schema:v3,再按 Start Time 倒序排列并保存为视图。点击最新一行的 Trace ID,可以查看启动快照和已经完成的 Step、Model 与 Tool observation;根 Agent 会在 Attempt 结束后补齐。
Documentation
文档索引按从整体说明到具体实现的方向组织。
| 主题 | 文档 |
|---|---|
| 官网、公开中英文文档和 GitHub Pages 构建 | Website |
| 从多 Inventory 组合到 Langfuse 与训练证据的端到端教程 | Observable research Harness tutorial |
| 系统定位、核心概念和运行流 | System overview |
| Agent、Tool、Middleware 和 Skill 的组装规则 | Agent assembly |
| Agentic RL 中的集成与使用 | Whitebox Harness usage |
| 配置、接口、运行时和公开组件 | Reference |
| 内部架构和模块设计 | Design |
| 可执行组合样本 | Examples |
| 组件源码布局和开发规范 | Components |
| 项目致谢、设计参考和 AI-assisted development 说明 | Acknowledgments |
| 随组件分发的第三方代码与 license notice | Third-party notices |
| 分支、提交和合并规则 | Contributing |
Development
安装开发依赖并执行检查:
uv sync --all-extras --all-groups --locked
uv run ruff check .
uv run pytest
uv build
官网与公开中英文文档位于 website/,英语为默认语言,首页只维护英文版本。本地预览和静态构建:
cd website
npm install
npm run start
npm run build
静态构建还会为每个文档生成无 front matter 的 Markdown 正文,并在英文和中文 locale 下分别提供 llms.txt、llms-full.txt 索引,方便 Agent 直接发现和读取文档内容。
需要扩展 Tool 时,可以 Fork builtin Inventory,也可以使用 saddler init <name> 自建 Inventory。
贡献代码前必须阅读 CONTRIBUTING.md。发布 Saddler 时,从干净的工作树运行发布脚本;脚本更新版本、执行检查、创建 release commit 和 tag,并推送到远端:
./scripts/release.sh VERSION
在 release commit 的干净工作树中构建 wheel 和 source distribution,使用 PyPI API token 上传:
rm -rf dist
uv build --no-sources
uv run python scripts/check_wheel.py dist/*.whl
uv publish dist/*
License
Saddler 自身代码使用 Apache License 2.0。仓库中移植、改编或兼容的第三方组件仍遵循各自的上游 license 和 notice;具体范围见 Third-party notices 与 Acknowledgments。
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file saddler_harness-0.1.5.tar.gz.
File metadata
- Download URL: saddler_harness-0.1.5.tar.gz
- Upload date:
- Size: 4.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
06f5ca17695dff876d47cc1031e9024ece3e02669083e9adca3487bcaf36b99d
|
|
| MD5 |
1b2738cfa0e4d220741bcc43d5a93556
|
|
| BLAKE2b-256 |
5be6d404e1cd295b0576c69064a1be5eda4eedc9d978bedac504f504f61c72ff
|
File details
Details for the file saddler_harness-0.1.5-py3-none-any.whl.
File metadata
- Download URL: saddler_harness-0.1.5-py3-none-any.whl
- Upload date:
- Size: 342.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5699932301f51fbcc3ea71815cb0b9eef7c59af32c10fb10bb0f1842930d53e7
|
|
| MD5 |
941fdff4285c4caeb13fb000d81c361c
|
|
| BLAKE2b-256 |
5776ed465b17653b8ef9620f136cc336519b057c889d8c12e3d1b912d9ec8e85
|