Lightweight Python agents with tools, memory, MCP, and lazy skills.
Project description
yier-agents
Python Agent 系统,参考 OpenCode 架构设计,支持工具调用、子 Agent 和基于 finish_reason 的循环控制。
特性
- ✅ finish_reason 驱动循环 - 自动处理工具调用和 token 限制
- ✅ Pydantic 参数验证 - 类型安全的工具定义
- ✅ ToolMiddleware - 统一的工具管理和错误处理
- ✅ SubAgent 支持 - Agent 可以作为工具被其他 Agent 调用
- ✅ 并发工具执行 - 使用 asyncio.gather 并行执行
- ✅ OpenAI-compatible API - 支持任何兼容 OpenAI 格式的 LLM
- ✅ 内置 Todo 工具 - AI 自动管理任务列表和进度跟踪
- ✅ Verbose 调试模式 - 美观的彩色输出,实时查看执行过程
- ✅ MCP 支持 - 通过
MCPClient连接任意 MCP server,自动转换为 Tool 实例,支持 stdio 和 SSE 两种传输 - ✅ 会话记忆 - 自动保存和加载会话上下文,支持多轮对话
- ✅ Skill 支持 - 通过
Skill打包 system prompt 和 tools,复用 Agent 能力 - ✅ 上下文压缩 - 长对话可自动摘要旧消息,保留最近上下文
- ✅ 可持久化记忆 - 通过
JSONSessionStore将 session memory 持久化到磁盘 - ✅ 思考过程支持 - 支持 reasoning_content 字段,兼容 o1、Claude thinking 等模型
- ✅ 交互式 CLI 助手 - 内置
yier-cli,支持会话记忆、skills、MCP 和工作区工具 - ✅ 后台命令与任务排队 - 长任务可后台执行,完成后自动提醒并触发后续 follow-up
安装
# 使用 uv
uv pip install -e .
# 或使用 pip
pip install -e .
打包与发版
推荐通过 Makefile 管理版本和构建产物,这样每次打包前都会先清掉旧的 dist/、build/ 和 *.egg-info,避免安装到旧 wheel,或者看到过期的 METADATA。
# 查看当前版本
make version
# 只在本地完成 patch 发版准备
make tag-release-patch
# 本地准备后顺序推送分支和 tag
make publish-release-patch
常用命令:
make build- 清理旧产物后重新生成 wheel 和 sdist,并执行twine checkmake metadata- 查看最新 wheel 中的METADATAmake pkg-info- 查看最新 sdist 中的PKG-INFOmake install-wheel- 使用uv pip install --reinstall安装最新 wheel,避免同版本安装时残留旧元数据make tag-release-patch- 顺序执行 bump、build、test、commit 和 tag,但不推送make publish-release-patch- 在tag-release-patch基础上继续 push 当前分支和版本 tag
如果你刚改了 README.md、依赖或项目描述,建议至少跑一遍:
make build
make metadata
如果你要正式发版,推荐直接走 publish-release-*,这样 commit、tag 和 push 都在同一个顺序化流程里,不容易再出现 tag 指到错误提交的问题。
快速开始
import asyncio
from pydantic import BaseModel, Field
from yier_agents import Agent, LLM, Tool, ToolContext, ToolOutput
# 1. 定义工具参数
class ReadFileParams(BaseModel):
path: str = Field(description="文件路径")
# 2. 定义工具执行函数
async def read_file(params: ReadFileParams, ctx: ToolContext) -> ToolOutput:
with open(params.path) as f:
content = f.read()
return ToolOutput(content=f"File content:\n{content}")
# 3. 创建工具
read_tool = Tool(
name="read_file",
description="读取文件内容",
parameters=ReadFileParams,
execute=read_file
)
# 4. 创建 Agent
llm = LLM(
base_url="https://api.openai.com/v1",
api_key="your-key",
model="gpt-4"
)
agent = Agent(
llm=llm,
tools=[read_tool],
system_prompt="你是一个文件助手",
verbose=True # 启用详细的调试输出
)
# 5. 运行
result = await agent.run("读取 README.md 并总结")
print(result.final_message)
如果你用的是 Z.AI,也可以直接使用内置 provider preset,不必自己记接口地址:
from yier_agents import LLM
llm = LLM(
provider="zai",
model="glm-4.7-flash",
)
# 如果你订阅了 Z.AI Coding Plan:
llm = LLM(
provider="zai-coding-plan",
model="glm-4.7-flash",
)
默认会读取这些环境变量:
YIER_PROVIDER- 可选,支持zai、zai-coding-planYIER_MODEL- 模型名,例如glm-4.7-flashZHIPU_API_KEY- Z.AI / 智谱 API keyYIER_BASE_URL、YIER_API_KEY- 通用 OpenAI-compatible 覆盖项
如果你历史上已经在用 z-ai/glm-4.7-flash 这种写法,现在也兼容,发送请求时会自动归一化为 Z.AI 原生 model id。
调试模式
使用 verbose=True 参数可以查看 Agent 执行的详细过程,方便调试:
agent = Agent(
llm=llm,
tools=[tool1, tool2],
verbose=True # 启用详细输出
)
result = await agent.run("执行任务", "session-id")
输出示例:
ℹ ============================================================
ℹ Starting Agent execution (session: session-i...)
ℹ ============================================================
ℹ Added system prompt
ℹ User: 执行任务
ℹ ────────────────────────────────────────────────────────────
ℹ Iteration 1/20
ℹ ────────────────────────────────────────────────────────────
ℹ Calling LLM...
✓ LLM response received (finish_reason: tool_calls, usage: 150 tokens)
⚙ Executing 2 tool call(s)...
⚙ [1/2] read_file({"path": "README.md"})
⚙ [2/2] grep({"pattern": "Agent"})
✓ Received 2 tool result(s)
⚙ [1] File content: ...
⚙ [2] Found 5 matches
ℹ ────────────────────────────────────────────────────────────
ℹ Iteration 2/20
ℹ ────────────────────────────────────────────────────────────
ℹ Calling LLM...
✓ LLM response received (finish_reason: stop, usage: 200 tokens)
ℹ Content: 任务已完成
✓ Agent completed successfully
ℹ ============================================================
详见 verbose 示例。
架构
Agent (执行循环)
├─> LLM (API 调用层)
├─> ToolMiddleware (工具管理和验证)
│ ├─> Tool (工具定义)
│ └─> Context (执行上下文)
├─> MCPClient (MCP server 连接)
│ ├─> stdio transport (子进程)
│ └─> SSE transport (HTTP)
└─> Message (消息管理)
Skills
Skill 用来打包一组工具和附加的 system prompt,适合构建你自己的可组合 Agent 能力层。
from yier_agents import Agent, LLM, Skill
network_skill = Skill(
name="network-basics",
description="Basic network utilities",
tools=[get_ip_tool],
system_prompt="Use get_ip when the user asks about the local machine IP."
)
agent = Agent(
llm=llm,
tools=[],
skills=[network_skill],
system_prompt="你是一个轻量但可靠的终端助手"
)
Lazy Skills
除了静态 Skill 之外,现在也支持 OpenCode 风格的按需加载 skills。它们从 SKILL.md 目录结构中发现,在系统提示里只暴露 <available_skills> 列表,真正需要时再通过内置 skill_load 工具加载完整内容。
支持的项目级目录:
.opencode/skill/<name>/SKILL.md.opencode/skills/<name>/SKILL.md.claude/skills/<name>/SKILL.md.agents/skills/<name>/SKILL.md
from pathlib import Path
from yier_agents import Agent, LLM, SkillCatalog
catalog = SkillCatalog.discover(
Path.cwd(),
include_project=True,
include_global=False,
)
agent = Agent(
llm=LLM(model="gpt-4"),
tools=[],
skill_catalog=catalog,
system_prompt="你是一个支持 lazy skills 的编程助手",
)
如果某个 skill 目录里包含 scripts/ 或 references/, skill_load 会把 skill 正文、base directory 和采样文件列表注入上下文。脚本不会自动执行,而是由后续普通工具去读取或运行。
内置文件/命令工具:
list_files- 浏览 skill 目录或项目目录read_file- 读取脚本、参考资料和配置文件replace_in_file- 做精确文本替换式编辑write_file- 在允许的工作区内创建或更新文件run_command- 执行 skill 中提到的脚本或命令search_files- 进行 grep-like 文本搜索
ToolOutput 结构
所有内置工具都会返回同一个 ToolOutput 结构:
content: 给模型和 CLI 看的可读摘要metadata: 轻量摘要字段,适合列表、状态栏和简单 UI 绑定raw: 给 UI 和外部调用方看的结构化原始载荷
推荐的消费顺序是:
- 用
raw驱动 UI 展示和交互 - 用
metadata做轻量状态判断或列表摘要 - 把
content当作日志、回退展示或给模型继续阅读的文本
result = await tool.execute(params, ctx)
print(result.content)
print(result.metadata)
print(result.raw)
raw.kind 是最重要的分流字段。当前内置工具大致会返回这些类型:
shell_command:run_commandbackground_command:start_background_command、read_background_command、wait_background_command、stop_background_command、send_background_command_inputfile_read:read_filefile_list:list_filesfile_write:write_filefile_search:search_filesfile_replace:replace_in_filetodo_list:todo_readtodo_update:todo_writeskill_load:skill_loadmcp_tool_result: 通过MCPClient代理的 MCP 工具subagent_result:AgentToolqueued_followup:queue_background_followupnetwork_lookup:get_ip
Shell / Background Command
run_command、start_background_command、read_background_command、wait_background_command、stop_background_command 和 send_background_command_input 都会在 raw 里暴露统一结构:
raw.kind:shell_command或background_commandraw.request: 命令、工作目录、shell 配置等请求参数raw.process: 状态、退出码、时间戳、运行时长raw.events: 终端事件流,包含started、stdout、stderr、stdin、state_changed、exitraw.latest_event_index: 最新事件索引,适合增量轮询raw.streams.stdout/raw.streams.stderr: 当前聚合输出快照raw.events_truncated/raw.dropped_event_count: 事件缓冲是否发生截断
如果你在 UI 里想做更像真实 shell 的展示,优先消费 raw["events"]; content 更适合直接展示给模型或做日志摘要。
result = await run_tool.execute(
run_tool.parameters(command="python3 demo.py", cwd="."),
ctx,
)
print(result.content)
print(result.metadata)
print(result.raw["events"])
print(result.raw["streams"]["stdout"]["text"])
File / Todo / Skill / MCP
除了 shell 类工具,其他工具也会在 raw 里给出稳定结构,避免 UI 再去解析 content:
file_read.raw.lines: 带行号的读取结果file_list.raw.entries: 目录项列表file_search.raw.matches: 搜索命中,包含路径、行号和文本todo_list.raw.todos/todo_update.raw.todos: 完整 todo 列表skill_load.raw.sampled_files: skill 采样文件mcp_tool_result.raw.contents: MCP 原始内容项,按text/binary/resource/unknown归类subagent_result.raw.final_message: 子 agent 的最终消息和摘要信息
这些 raw 结构会随着工具类型变化,但都遵循同一个原则: content 面向模型, metadata 面向轻量状态, raw 面向 UI。
Session Memory
默认 memory 仍可直接使用,但现在也支持持久化 store 和上下文压缩。
from pathlib import Path
from yier_agents import Agent, CompactionConfig, JSONSessionStore, LLM
agent = Agent(
llm=LLM(model="gpt-4"),
tools=[],
session_store=JSONSessionStore(Path(".agent_storage/sessions")),
compaction_config=CompactionConfig(
enabled=True,
trigger_message_count=24,
preserve_recent_messages=8,
),
)
Interactive Assistant CLI
如果你想直接启动一个交互式个人助手,而不是自己写一层循环,可以直接运行包内 CLI:
python -m yier_agents.yier_cli
安装为可执行脚本后也可以直接运行:
yier-cli
如果启动时还没有配置 YIER_PROVIDER 或 YIER_BASE_URL,CLI 会先给一个快捷选择器,默认就是 zai-coding-plan。这时只需要输入模型名,例如 glm-4.7-flash,再提供 ZHIPU_API_KEY 即可。
这个入口默认启用:
- 会话持久化记忆
- 长上下文摘要压缩
- lazy skills 发现与
/skills浏览 - 受限的文件、搜索、写入与命令工具
- 后台命令管理和 follow-up 排队
- MCP 配置热重载
常用交互命令:
/skills [query]- 查看或筛选已发现的 skills/ps [running|all]- 查看后台任务/tail <session_id>- 查看后台任务最近输出/wait <session_id> [seconds]- 等待某个后台任务一小段时间/stop <session_id>- 停止后台任务/queue [list|<session_id> <message>]- 给后台任务挂一个完成后自动执行的 follow-up
一个典型流程是:
- 让 Agent 用
start_background_command在后台启动构建、测试、抓取或同步任务。 - 继续和 CLI 聊别的事情,不阻塞当前对话。
- 用
/queue bg-1 总结结果并告诉我下一步,或者让 Agent 调用queue_background_followup。 - 后台任务完成后,CLI 会提示它已结束,并把输出摘要注入到下一次 Agent 回合里;如果已经排了 follow-up,会自动继续执行。
对应的内置后台工具有:
start_background_commandlist_background_commandsread_background_commandwait_background_commandstop_background_commandsend_background_command_inputqueue_background_followup
可以在 .yier.json 里为 CLI 覆盖这些默认值。默认行为和现在一致,只是搬进了配置层:
{
"assistant": {
"workspaceRoot": ".",
"sessionStoragePath": ".agent_storage/sessions",
"promptHistoryPath": ".agent_storage/prompt_history.txt",
"allowedRoots": [
".",
".agent_storage/sessions"
],
"includeSkillDirectoriesInAllowedRoots": true,
"maxIterations": 100,
"runCommand": {
"allowShell": false,
"shellProgram": "/bin/bash"
},
"compaction": {
"enabled": true,
"triggerMessageCount": 24,
"preserveRecentMessages": 8,
"summaryMaxTokens": 512
}
}
}
runCommand.allowShell 默认为 false,所以 run_command 默认不支持 |、重定向和链式 shell 语法;这是为了避免把普通命令执行提升成完整 shell。只有在你明确开启它时,才会用 shell 模式执行。
shellProgram 是可选覆盖项:类 Unix 系统默认使用 /bin/bash,Windows 默认使用当前系统的 ComSpec。同样地,start_background_command 也遵循这套配置。
MCP 支持
通过 MCPClient 连接任意 MCP server,所有工具自动转换为 Tool 实例,与本地工具用法完全一致。
from yier_agents import MCPClient, Agent, LLM
llm = LLM(model="gpt-4")
# stdio 方式(本地子进程)
async with MCPClient.stdio("npx", ["-y", "@primevue/mcp"]) as client:
tools = await client.get_tools()
agent = Agent(llm=llm, tools=tools)
result = await agent.run("DataTable 有哪些常用 props?", session_id="s1")
# SSE 方式(HTTP 远程)
async with MCPClient.sse("http://localhost:8000/sse") as client:
tools = await client.get_tools()
agent = Agent(llm=llm, tools=tools)
result = await agent.run("执行任务", session_id="s2")
# 多个 MCP server 混合使用
async with (
MCPClient.stdio("npx", ["-y", "@primevue/mcp"]) as mcp1,
MCPClient.sse("http://localhost:8000/sse") as mcp2,
):
tools = await mcp1.get_tools() + await mcp2.get_tools()
agent = Agent(llm=llm, tools=tools)
一次连接,多个 Agent 共享:
async with MCPClient.stdio("npx", ["-y", "@primevue/mcp"]) as client:
tools = await client.get_tools() # 只连接一次
agent1 = Agent(llm=llm, tools=tools, system_prompt="你是前端专家")
agent2 = Agent(llm=llm, tools=tools, system_prompt="你是无障碍专家")
# 两个 agent 共享同一个 MCP 连接
r1, r2 = await asyncio.gather(
agent1.run("DataTable 怎么分页?", "session-1"),
agent2.run("Button 的无障碍属性?", "session-2"),
)
详见 MCP 示例。
SubAgent 示例
# 创建专门的子 agent
search_agent = Agent(
llm=llm,
tools=[grep_tool, read_tool],
system_prompt="你是代码搜索专家"
)
# 包装为工具
from yier_agents import AgentTool
search_tool = AgentTool(
name="search_codebase",
description="搜索和分析代码",
agent=search_agent
)
# 主 agent 可以调用
main_agent = Agent(
llm=llm,
tools=[search_tool, edit_tool]
)
result = await main_agent.run("重构这个模块")
Todo 工具
内置的任务跟踪工具,让 AI 自动管理多步骤任务的进度。
from yier_agents import Agent, LLM, TodoWriteTool, TodoReadTool
# 创建带 todo 工具的 agent
agent = Agent(
llm=llm,
tools=[
TodoWriteTool, # AI 可以创建和更新任务列表
TodoReadTool, # AI 可以查看当前进度
# ... 其他工具
],
system_prompt="对于多步骤任务,使用 todo_write 工具跟踪进度。"
)
# AI 会自动使用 todo 工具管理任务
result = await agent.run("实现用户认证系统,包括登录、注册和密码重置")
AI 自动管理 todos:
- 接收多步骤任务时自动创建 todo 列表
- 开始每个任务前标记为
in_progress - 完成后标记为
completed - 实时跟踪进度
Todo 状态:
pending⏸ - 待执行in_progress▶ - 执行中completed✓ - 已完成
开发
# 运行测试
pytest tests/ -v
# 运行特定测试
pytest tests/test_agent.py -v
# 查看覆盖率
pytest --cov=doc_agents tests/
设计文档
详细设计请参考:
License
MIT
Project details
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 yier_agents-0.1.7.tar.gz.
File metadata
- Download URL: yier_agents-0.1.7.tar.gz
- Upload date:
- Size: 91.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed90d43beb09074096f398bdb6780e41d97ce8fa7f5cabc4753f7a2f71e5009b
|
|
| MD5 |
c5521d4a6d4fe224be3773fcba8aebf5
|
|
| BLAKE2b-256 |
191a19a93f5b26cfc1475f8f9c1480ce33b5f45f918aefd826c3bfc087c7dafc
|
Provenance
The following attestation bundles were made for yier_agents-0.1.7.tar.gz:
Publisher:
publish.yml on Sube-py/yier_agents
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yier_agents-0.1.7.tar.gz -
Subject digest:
ed90d43beb09074096f398bdb6780e41d97ce8fa7f5cabc4753f7a2f71e5009b - Sigstore transparency entry: 1161585988
- Sigstore integration time:
-
Permalink:
Sube-py/yier_agents@08c2f4c66fa7e858cfd3de91f6cd5c1e5c3b0345 -
Branch / Tag:
refs/tags/v0.1.7 - Owner: https://github.com/Sube-py
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@08c2f4c66fa7e858cfd3de91f6cd5c1e5c3b0345 -
Trigger Event:
push
-
Statement type:
File details
Details for the file yier_agents-0.1.7-py3-none-any.whl.
File metadata
- Download URL: yier_agents-0.1.7-py3-none-any.whl
- Upload date:
- Size: 71.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7867feb98a7017ffb6ddd476043768ab3275678b1925fd6d3ba7a9b2bc988eed
|
|
| MD5 |
954f0ec37e15d48d0b4d9432791e1cc5
|
|
| BLAKE2b-256 |
a010064b84ace38d5c7156d165a66b379ddf7441f07ae4e9409b69040eb6e945
|
Provenance
The following attestation bundles were made for yier_agents-0.1.7-py3-none-any.whl:
Publisher:
publish.yml on Sube-py/yier_agents
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yier_agents-0.1.7-py3-none-any.whl -
Subject digest:
7867feb98a7017ffb6ddd476043768ab3275678b1925fd6d3ba7a9b2bc988eed - Sigstore transparency entry: 1161586094
- Sigstore integration time:
-
Permalink:
Sube-py/yier_agents@08c2f4c66fa7e858cfd3de91f6cd5c1e5c3b0345 -
Branch / Tag:
refs/tags/v0.1.7 - Owner: https://github.com/Sube-py
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@08c2f4c66fa7e858cfd3de91f6cd5c1e5c3b0345 -
Trigger Event:
push
-
Statement type: