内容
<p align="center">
<img src="https://raw.githubusercontent.com/metravod/zymi-core/main/assets/zymi-badge.png" alt="zymi" width="220" />
</p>
<h1 align="center">zymi-core</h1>
<p align="center"><em>适用于代理的可审计MCP后端 — 工具即声明式YAML流水线:事件驱动、可重放、审批控制。</em></p>
<p align="center"><sub>发音为 <em>zoomi</em> — 就像狗的快速奔跑。</sub></p>
<p align="center">
<a href="https://pypi.org/project/zymi-core/"><img src="https://img.shields.io/pypi/v/zymi-core.svg?logo=pypi&logoColor=white" alt="PyPI" /></a>
<a href="https://pypi.org/project/zymi-core/"><img src="https://img.shields.io/pypi/pyversions/zymi-core.svg?logo=python&logoColor=white" alt="Python versions" /></a>
<a href="https://github.com/metravod/zymi-core/actions/workflows/ci.yml"><img src="https://github.com/metravod/zymi-core/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT" /></a>
<a href="llms.txt"><img src="https://img.shields.io/badge/llms.txt-%E2%9C%93-8A2BE2" alt="llms.txt" /></a>
</p>
---
## 为什么选择zymi-core?
代理框架竞争栈的*前端* — 循环、规划器、IDE。zymi拥有*后端*:代理调用的工具。
[`zymi mcp serve`](#zymi作为mcp服务器--工具适用于任何代理) 以声明式YAML流水线形式将MCP工具暴露给任何主机 — Claude Code、Claude Desktop、Cursor或具有MCP适配器的任何框架(LangGraph、CrewAI、OpenAI Agents SDK)。不像端点后面的脚本,zymi工具是:
- **声明式,像dbt一样。** 代理、流水线、工具、连接器、审批 — 全部为YAML。引擎验证并将它们作为DAG运行。
- **事件驱动。** 每个状态更改都是不可变的、哈希链接的事件。运行可重放、可恢复且可审计,无需额外日志记录。
- **边界安全 — 交互式。** 步骤发出*意图*(运行shell、写入文件、调用HTTP),在执行前通过策略 + 合同 + 可选的人工审批。在MCP上,审批呈现为调用代理UI中的批准/拒绝表单;风险操作不会在某人确认之前发生。
- **自我调试。** 使用`--expose-observability`服务,代理可以内省自己的运行 — 列出它们,拉取事件跟踪,读取任何步骤的精确I/O — 并在不打开日志文件的情况下解释失败。
zymi故意*不*是一个自主编码代理、IDE插件或聊天UI — 它是这些之下的受控工具层。它也可以独立运行:[两分钟内启动一个Telegram代理](#两分钟内运行一个telegram代理),无需MCP。无论哪种方式,一年后,您仍然可以准确回答*这个代理做了什么*,在任何过去的运行中。
📚 **AI助手友好开箱即用。** 每次`zymi init`脚手架都会在用户项目中生成一个`AGENTS.md` — 词汇、文件映射、任务→文件路由。Claude Code / Cursor / Aider自动读取它;您编写的YAML他们帮助您编写,准确性明显提高。对于*构建*zymi项目的代理(而不是在其中工作),请在您的助手上安装[zymi-skill](https://github.com/metravod/zymi-skill) — 具有激活规则和渐进披露引用的有意见的代理技能,以便助手生成zymi本地YAML而不是通用代理建议。
---
## 两分钟内运行一个Telegram代理
典型的独立演示(无需MCP主机) — 一个真正的聊天机器人,以声明式连接。
```bash
uv tool install zymi-core # 一次性;全局将`zymi`放入PATH
mkdir telegram-agent && cd telegram-agent
zymi init --example telegram
# 1. 通过@BotFather在Telegram上创建一个机器人;复制令牌。
# 2. 填充.env:
cp .env.example .env # 编辑TELEGRAM_BOT_TOKEN + OPENAI_API_KEY
# 3. 打开project.yml,将"your_username_here"替换为您的实际
# Telegram用户名(无@)。防止陌生人进入机器人。
zymi fetch # uv sync — 从pyproject.toml构建./.venv
zymi serve chat # .env自动加载;流水线在./.venv中运行
```
> **为什么使用`uv tool install`和`zymi fetch`?** `zymi`是一个全局CLI;您的项目保留自己的`pyproject.toml` + `.venv`用于任何Python依赖项,您的`@tool`文件导入。`zymi fetch`包装`uv sync`以构建该venv,流水线运行命令在其中透明地重新执行([ADR-0032](adr/0032-install-ux-fetch.md))。还没有`uv`? `curl -LsSf https://astral.sh/uv/install.sh | sh`(macOS / Linux)或`irm https://astral.sh/uv/install.ps1 | iex`(Windows)。
给机器人发消息。它几秒钟内回复。每条消息、LLM调用、审批决定和输出回复都存储在`.zymi/events.db`中;使用`zymi observe`实时观看。
整个连接 — Telegram I/O、两步DAG(`assistant`草稿,`reviewer`润色)、声明式 + Python工具、审批通道 — 都存在于YAML中。脚手架还会生成`AGENTS.md`,以便AI编码助手可以安全地扩展项目。具体演示:
- **`http_poll`连接器** — 长轮询Telegram的`getUpdates`,无需HTTPS / ngrok
- **`http_post`输出** — 将每个`ResponseReady`发送回用户
- **Telegram审批通道** — 当代理调用`broadcast`(`requires_approval: true`)时,通过DM向管理员发送 ✅ / ❌ 按钮
- **Python `@tool`自动发现** — 丢弃`tools/get_weather.py`(同步)或`tools/translate.py`(异步),代理会拾取它们
让机器人“宣布我们下午5点关门” — 代理调用`broadcast`,您收到一个带有批准/拒绝按钮的DM,在您点击之前不会发出任何内容。 `zymi events`中的端到端审计跟踪。
完整设置请参见[docs/getting-started.md](docs/getting-started.md)。连接器深入解析请参见[docs/connectors.md](docs/connectors.md)。审批请参见[docs/approvals.md](docs/approvals.md)。
---
## zymi-core包含的内容
### 流水线 — DAG、代理步骤、确定性工具步骤、询问步骤
流水线是具有`depends_on:`边的步骤列表。独立步骤并行运行。每个步骤都是一个**代理步骤**(LLM ReAct循环)、一个**确定性工具步骤**([ADR-0024](adr/0024-deterministic-tool-steps.md))— 直接调度具有模板参数的工具,无需LLM跳转,但具有相同的事件信封 — 或一个**询问步骤**([ADR-0042](adr/0042-mcp-sampling-ask-step.md)):将推理问题委托给调用流水线的人,而不是配置第二个单独计费的模型。运行暂停,询问调用者,并带有答案后继续(终端下的用户或`zymi run`下的连接代理)。
自由混合:
```yml
steps:
- id: fetch # 确定性 — 无LLM
tool: http_get
args: { url: "https://api.example.com/${inputs.id}" }
- id: classify # LLM
agent: classifier
task: "${steps.fetch.output}"
depends_on: [fetch]
- id: sanity # 询问 — 调用者回答,无llm:需要
ask: "此分类是否正确?\n${steps.classify.output}"
depends_on: [classify]
```
**条件分支** ([ADR-0028](adr/0028-conditional-dag-edges.md)) — 步骤可以控制上游输出。跳过的分支会级联到后代并发出`StepSkipped`事件,因此路由决策落在跟踪中,而不是LLM的头部:
```yml
- id: router
agent: concierge
task: "选择:${inputs.q}" # 调用route('short' | 'rag')
- id: rag_lookup
tool: pinecone_query
args: { query: "${inputs.q}" }
depends_on: [router]
when: "${steps.router.output} == 'rag'"
```
架构、示例、陷阱 → [docs/pipelines.md](docs/pipelines.md)。
### 工具 — 四种类型,一个目录
所有四种类型都发出相同的`ToolCallRequested` / `ToolCallCompleted`事件;代理不知道工具来自哪个目录。
- **声明式HTTP / shell** 在`tools/<name>.yml` — 无代码。
- **Python `@tool`** 在`tools/<name>.py` — 同步或异步,签名 → JSON模式,自动发现。
- **MCP服务器** — 一个`mcp_servers:`条目提供N个工具,命名为`mcp__<server>__<tool>` ([ADR-0023](adr/0023-mcp-client-integration.md))。
- **内置工具** — `read_file`、`write_file`、`write_memory`、`execute_shell_command`、`spawn_sub_agent`.
```python
# tools/get_weather.py — 在运行时自动发现。
from zymi import tool
@tool
def get_weather(city: str) -> str:
"""返回一个城市的当前天气。"""
return f"晴天在{city}"
```
架构和四种类型详解 → [docs/tools.md](docs/tools.md)。
### zymi作为MCP服务器 — 流水线作为任何代理的工具
MCP客户端的镜像:`zymi mcp serve`通过stdio将您的流水线作为MCP工具暴露给任何主机,因此**任何**MCP主机(Claude Code、Claude Desktop、Cursor、OpenAI Agents / LangGraph / OpenHands运行时通过其MCP适配器)都可以将zymi流水线作为单个工具调用 — 无需每个运行时的胶水([ADR-0033](adr/0033-mcp-server-pipelines-as-tools.md))。
这是**zymi的主要方向**:拥有可审计、事件驱动的代理栈的*后端*,而不是在前端竞争。流水线是一种工具,它的每个步骤都是哈希链接、可重放和可恢复的 — 这正是代理的工具目录所缺少的。
暴露是按流水线选择的(因此内部/ cron流水线不会泄漏到代理工具目录中):
```yml
# pipelines/research.yml
expose:
mcp:
name: research # 工具名称(默认为文件茎)
mode: sync | async # 异步提示调用者进行任务增强(SEP-1686)
description: "深入研究一个主题并返回简要介绍。"
```
```bash
zymi mcp serve # 通过stdio提供所有expose:-d流水线
zymi mcp serve --include 'research_*' --exclude '*_internal'
```
- **同步** — `tools/call`在流水线完成之前阻塞;今天在每个MCP客户端上都有效。工具输入模式从流水线的`inputs:`自动生成。
- **异步** — 支持任务增强的客户端立即获得`CreateTaskResult`,并轮询`tasks/get` / `tasks/result` / `tasks/list`; `tasks/cancel`和`notifications/cancelled`取消它。流水线在后台运行,并在事件存储中完全可观察。
**人类审批在调用代理的UI中呈现。** 触发[审批](#approvals--event-sourced-restart-safe)的流水线步骤通过活动`tools/call`将服务器发起的`elicitation/create`发送回 — 在Claude Code中,这是一个原生批准/拒绝表单。批准后流水线继续;拒绝后它将决定写入审计跟踪;不支持询问的客户端将失败关闭(`ApprovalDenied{reason: client_no_elicitation}`)。在Claude Code上验证。
**流水线可以借用调用者的脑。** [`询问:`步骤](#ask-步骤adr-0042) 将推理问题委托回调用代理,而不是配置第二个模型。在任务增强的调用中,运行暂停,任务变为`input_required`,带有`{ prompt, resume_token }`,调用者在自己的循环中推理并调用`zymi/reasoning/resume { resume_token, answer }` — 无需`sampling`,无需过时基元,只需工具 + 暂停/恢复。提示和答案被记录,因此重放读取答案字节相同。纯工具 + 询问流水线根本不需要`llm:`。在`zymi mcp serve`上验证。
**代理可以调试自己的运行。** `zymi mcp serve --expose-observability`添加了四个只读工具 — `zymi.runs.list` / `.get` / `.events` / `.step_io` ([ADR-0034](adr/0034-mcp-observability-tools.md))。询问代理*“为什么最后一次运行失败?”* 它拉取事件跟踪并用确切的策略判决和审批决定回答 — 其他堆栈无法公开的内省,因为每步的事件粒度不存在。默认情况下范围限定在服务会话;`--observability-scope all`为单个用户开发打开整个存储。
**当前限制(诚实的清单):**
- **异步任务不会暂停*审批*。 上面的交互式审批桥是同步模式;异步任务中的审批等待主机采用并超时(自动拒绝)。注意这是特定于审批的 — *推理委托*(`询问:`步骤,ADR-0042)工作精确*因为*它利用任务`input_required` + 恢复表面,因此`询问:`步骤内的异步任务通过`zymi/reasoning/resume`得到回答。同步调用对两者都完全交互。
- **取消是尽力而为:** 任务被中止,但已经在运行的流水线步骤(及其副作用)可能会运行完成。
---
## 贡献与许可
zymi-core由Rust构建,通过PyPI发布。错误报告、示例、PR欢迎 — 请参阅[CONTRIBUTING.md](CONTRIBUTING.md)获取开发循环、测试矩阵、ADR工作流程以及如何从源代码构建。
MIT — 请参阅 [LICENSE](LICENSE)。
[mcp]: https://modelcontextprotocol.io
连接信息
猜你喜欢
暂无推荐服务器