Lightweight composable multi-agent framework with StateGraph, RAG, Memory, MCP, and structured output
Project description
ClearAgent
轻量、可组合的多智能体框架 —— 基于 OpenAI 原生 API,单包提供图编排、检查点、HITL、RAG、Memory、Multi-agent、MCP、结构化输出、Eval-harness 等能力。
✨ 核心能力
编排与执行
- StateGraph 声明式图构建(节点 / 边 / 条件边 / 字段级 reducer)
- Checkpointer 自动每节点快照(Memory / JsonFile / Sqlite),kill 进程也能 resume + 时间旅行
- Human-in-the-Loop
interrupt()+resume(value=...)暂停-续跑,支持同节点多次中断顺序回放 - Multi-agent 三种范式:supervisor(中心化)/ swarm(去中心化)/ handoff 原语
- LCEL-lite Runnable +
|管道组合(自研,零 langchain 依赖)
LLM 与工具
- 多 provider 自动适配:OpenAI 兼容(DeepSeek/Qwen/Kimi/Ollama 等)、Anthropic、Gemini
- 同步 / 真异步 / 流式 全套接口(
AsyncOpenAI/AsyncAnthropic真异步,不走线程池假异步) - 结构化输出
llm.with_structured_output(MyPydanticModel)一行打通三种 method - 工具系统
ToolResponse协议 + 熔断器 + 权限过滤 + Pydantic 自动 Tool schema 推导 - 工具并行
run_tools_parallel/arun_tools_parallel多 tool_calls 并发 - Resilience Retry / Fallback / 负载均衡装饰器
- Multimodal vision / audio / file content parts 构造器
- Prompt caching Anthropic ephemeral helper
数据与记忆
- 完整 RAG Pipeline 7 大职责(加载 / 分块 / 索引 / 检索 / 重排 / 合并 / 压缩)+ MQE / HyDE 查询扩展
- 多层 Memory WorkingMemory(短期)+ SemanticMemory(长期 + 内存知识图谱)+ MemoryManager 协调
- 向量库 QdrantVectorStore + SQLiteDocumentStore
- 嵌入抽象 Local / DashScope / TFIDF + 工厂回退
- 文档加载 MarkItDown 50+ 格式(PDF/DOCX/XLSX/图像 OCR/音频转写/HTML/代码/配置)
生态与工程化
- MCP 协议 Client(吃外部 MCP 工具)+ Server(暴露给 Cursor / Claude Desktop)
- Skills 系统 知识按需注入,~85% Token 节省
- 子代理机制 TaskTool 派发隔离子任务,工具权限可精确裁剪
- Eval-harness Dataset + 4 种 Evaluator(含 LLMAsJudge)+ 并发 Runner + Markdown 报告
- Callbacks 13 个 hooks(LLM/工具/节点/检索)+ 内置 Logging / Metrics handler
- TraceLogger JSONL + HTML 双格式 + SFT / DPO 训练数据导出
🚀 快速开始
# 最小安装
pip install clear-agent
# 按需扩展
pip install "clear-agent[retrieval-qdrant,rag]" # 完整 RAG
pip install "clear-agent[memory]" # 多层记忆 + spaCy NER
pip install "clear-agent[anthropic,gemini]" # 多 provider
pip install "clear-agent[mcp]" # MCP 协议
环境变量(参考 .env.example):
LLM_MODEL_ID=gpt-4o
LLM_API_KEY=sk-...
LLM_BASE_URL=https://api.openai.com/v1
1 分钟示例:ReActAgent
from clear_agent import ClearAgentLLM, ReActAgent, ToolRegistry, CalculatorTool
llm = ClearAgentLLM()
registry = ToolRegistry(); registry.register_tool(CalculatorTool())
agent = ReActAgent(name="demo", llm=llm, tool_registry=registry)
print(agent.run("计算 (123 + 456) * 2"))
StateGraph + Checkpoint
from clear_agent import ReActAgent, SqliteCheckpointer
from clear_agent.core.graph import RunConfig
agent = ReActAgent(name="x", llm=ClearAgentLLM())
graph = agent.as_graph(checkpointer=SqliteCheckpointer("memory/runs.db"))
result = graph.invoke(
{"messages": [{"role": "user", "content": "..."}], "max_steps": 5},
config=RunConfig(thread_id="thread-1"),
)
# 进程崩了?任意时间:graph.resume("thread-1") 续跑
Human-in-the-Loop
from clear_agent.core.interrupt import interrupt, GraphPaused
def risky_node(state):
decision = interrupt({"type": "approval", "message": "Send email?", "draft": state["draft"]})
if not decision.get("approved"):
return {"messages": [...]}
...
try:
graph.invoke(state, config=RunConfig(thread_id="t1"))
except GraphPaused as p:
# 把 p.payload 展示给用户,待决策后:
graph.resume("t1", value={"approved": True})
结构化输出
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
structured = llm.with_structured_output(Person)
p = structured.invoke([{"role": "user", "content": "Alice 是 30 岁的老师"}])
print(p.name, p.age) # Alice 30
完整 RAG
from clear_agent.retrieval.rag import create_rag_pipeline
rag = create_rag_pipeline(qdrant_url="http://localhost:6333", rag_namespace="my_kb")
rag["add_documents"](["docs/a.pdf", "docs/b.md"])
hits = rag["search"]("如何配置 LLM?", top_k=5)
hits = rag["search_advanced"]("...", enable_mqe=True, enable_hyde=True)
Multi-agent supervisor
from clear_agent.multiagent import build_supervisor_graph, HANDOFF_END
def supervisor(state):
n = state.get("handoff_count", 0)
return {"active_agent": ["researcher", "writer", HANDOFF_END][n] if n < 3 else HANDOFF_END}
graph = build_supervisor_graph(supervisor, {"researcher": researcher_fn, "writer": writer_fn})
result = graph.invoke({"messages": []})
Pydantic 自动 Tool schema
from pydantic import BaseModel, Field
from clear_agent.tools.from_pydantic import pydantic_tool
class AddArgs(BaseModel):
a: int = Field(description="第一个数")
b: int = Field(description="第二个数")
@pydantic_tool(description="加法")
def add(args: AddArgs) -> int:
return args.a + args.b
registry.register_tool(add)
Resilience
from clear_agent.core.resilience import retry, with_fallbacks
@retry(max_attempts=3, retry_on=(ConnectionError,), backoff=0.5)
def call_api():
return llm.invoke(...)
safe_llm = with_fallbacks(primary_llm.invoke, [backup_llm_1.invoke, backup_llm_2.invoke])
response = safe_llm(messages)
更多示例见 examples/ 目录。
📦 项目结构
clear_agent/
├── core/ # Agent 基类 / LLM / Config / 编排基础
│ ├── graph.py # StateGraph + reducers
│ ├── checkpoint.py # Memory/JsonFile/Sqlite
│ ├── interrupt.py # interrupt() + GraphPaused
│ ├── structured.py # with_structured_output
│ ├── runnable.py # LCEL-lite Runnable + |
│ ├── callbacks.py # 13 hooks 协议
│ ├── parallel.py # 工具并行 helper
│ ├── resilience.py # Retry / Fallback / 负载均衡
│ └── multimodal.py # vision / audio + cache_control
├── agents/ # 4 种范式(Simple/ReAct/Reflection/PlanSolve)+ graph builders
├── multiagent/ # supervisor / swarm / handoff
├── mcp/ # MCP client / server / adapter
├── hitl/ # Human-in-the-Loop patterns
├── eval/ # Dataset / Evaluator / Runner
├── retrieval/ # 嵌入 + Qdrant + SQLite + RAG pipeline
│ ├── embeddings.py
│ ├── rag/ # document + pipeline (7 大职责)
│ └── storage/ # SQLite + Qdrant
├── memory/ # WorkingMemory + SemanticMemory + Manager
├── context/ # GSSC 流水线
├── tools/ # 工具系统 + Pydantic 自动推导 + 内置工具
├── observability/ # TraceLogger(JSONL + HTML + SFT/DPO 导出)
└── skills/ # SkillLoader
skills/ # 18 个内置 Skill 包(pdf/docx/xlsx/ASR/TTS/VLM/web-search…)
docs/ # 用户指南
examples/ # 演示
tests/ # 740+ pytest 测试
📚 文档
- 快速开始:
docs/quickstart.md - 核心架构:
docs/graph-architecture.md·docs/hitl.md - 数据与记忆:
docs/rag-guide.md·docs/memory-guide.md - 工具与协议:
docs/tool-system.md·docs/structured-output.md·docs/mcp.md - Multi-agent:
docs/multi-agent.md - 评估与可观测性:
docs/eval-harness.md·docs/observability.md - 进阶:
docs/context-engineering.md·docs/skills.md·docs/async-streaming.md
🛠️ 本地开发与调试
1. 克隆与环境
git clone https://github.com/Perlou/clear-agent.git
cd clear-agent
python3.10 -m venv .venv && source .venv/bin/activate # 推荐 3.10/3.11/3.12
pip install --upgrade pip
装依赖三选一:
# A. 一键装齐(runtime + 轻量 extras + 全 dev/test 工具)—— 贡献者推荐
pip install -r requirements.txt
pip install -e . # editable 安装本包
# B. editable + 自选 extras(更精细)
pip install -e ".[mcp,retrieval-qdrant,memory,anthropic,gemini,dev]"
# C. 仅装最小核心(不跑测试 / 不写 RAG)
pip install -e .
# RAG(拉 sentence-transformers + torch ~2GB,按需)
pip install "clear-agent[rag]"
# 配置 .env
cp .env.example .env # 填 LLM_MODEL_ID / LLM_API_KEY / LLM_BASE_URL
📌
pip install -e .后任何位置都能from clear_agent import ...,且改clear_agent/源码即时生效,无需重装。 📌requirements.txt是给贡献者一键装齐的;终端用户pip install clear-agent走 PyPI 不需要它。
2. 在 examples/ 里调试新 demo
examples/ 下的脚本(如 examples/trip-planner/)默认就用本仓库的源码:
# 单文件 demo
python examples/async_agent_demo.py
# 子项目 demo(trip-planner 等需要后端 / 前端)
cd examples/trip-planner/backend
pip install fastapi 'uvicorn[standard]' pydantic-settings python-dotenv uv
python run.py
如果想验证「外部用户 pip install clear-agent 后是否能跑」,把整个子目录复制出去用 requirements.txt 重装即可(trip-planner 已带)。
3. 测试
pytest # 全量
pytest tests/test_graph_basics.py -v # 单文件
pytest -k structured -v # 关键字过滤
pytest -m "not integration" -q # 跳过需真 API 的集成测试
首次跑测试常见坑:
| 现象 | 原因 | 解决 |
|---|---|---|
Using SOCKS proxy, but socksio not installed |
系统设了 all_proxy=socks5://... |
已包含在 requirements.txt 的 httpx[socks];或 unset all_proxy http_proxy https_proxy |
async def functions are not natively supported |
缺 pytest-asyncio | 已包含在 requirements.txt |
| 真实 LLM 测试 401 / 超时 | .env 没配 / endpoint 不通 |
先 pytest -m "not integration" 跑单测,再单独修 |
*_when_*_missing 这类反向测试失败 |
装了对应可选依赖 | 这是测试桩问题,不影响实际功能 |
4. 代码风格 / 类型检查
black clear_agent tests && isort clear_agent tests # 格式化
mypy clear_agent # 严格类型
提交前可选挂 pre-commit:pip install pre-commit && pre-commit install。
5. 调试技巧
最小复现环境变量:
export PYTHONBREAKPOINT=ipdb.set_trace # 让 breakpoint() 进 ipdb
export CLEAR_AGENT_LOG_LEVEL=DEBUG # 打开 framework 内部日志
pytest tests/test_xxx.py::test_yyy -v -s # -s 不吞 print/输入
只跑挂掉的那一个:
pytest --lf -x # last-failed + 第一个失败就停
pytest tests/test_xxx.py -k "name and not slow" --pdb # 失败处自动进 pdb
调试 LLM 真实调用 + 工具循环:
import logging; logging.basicConfig(level=logging.DEBUG)
from clear_agent.observability.trace_logger import TraceLogger
TraceLogger().enable() # 每一步落 JSONL + HTML 时间线
追踪 MCP 子进程: 给 MCPClient.connect_stdio(...) 传 env={"DEBUG": "1", ...},子进程的 stderr 会原样透出到父进程。
📦 发布到 PyPI
scripts/release.sh 是一键发布脚本,按 11 个 Phase 顺序执行;任何一个 Phase 失败都会停下并给出可恢复的提示。
脚本流程
| Phase | 做什么 | 失败后怎么办 |
|---|---|---|
| 0 工具与环境检查 | 校验 python / build / twine / git |
装缺失工具 |
| 1 Git 工作区检查 | 确认 working tree 干净 | git stash 或 git commit |
| 2 版本号 | 校验 pyproject.toml 版号未在 PyPI 占用 |
--bump patch 或 --version X.Y.Z |
| 3 必备文件 | 检查 README / LICENSE / MANIFEST / py.typed | 补齐对应文件 |
| 4 全量 pytest | 跑所有测试(可 --skip-tests) |
修代码或确认是环境问题再 --skip-tests |
| 5 清理 + 构建 | rm -rf dist build + python -m build |
看 build 日志 |
| 6 twine check | twine check dist/* 检查长描述/元数据 |
修 pyproject.toml |
| 7 包内容审查 | 列 wheel/sdist 内容确认没漏 / 没多 | 调 MANIFEST.in 或 [tool.setuptools] |
| 8 干净环境装机验证 | 临时 venv 装 wheel + 冒烟 import | --skip-clean-install 跳过 |
| 9 上传 | twine upload(pypi / testpypi) |
看凭证 / 网络 |
| 10 Git tag | git tag vX.Y.Z + 可选 git push --tags |
--skip-tag 跳过 |
常用姿势
# 1) 干跑:只构建 + 校验,不上传(强烈建议每次发版前先跑一遍)
bash scripts/release.sh --dry-run
# 2) 先发 TestPyPI 验证(推荐流程)
bash scripts/release.sh --test
# 3) 正式发到 PyPI
bash scripts/release.sh # 交互式
bash scripts/release.sh --yes # CI 用,全部自动 yes
# 4) 自动 bump 版本号
bash scripts/release.sh --bump patch # 2.0.0 → 2.0.1
bash scripts/release.sh --bump minor # 2.0.0 → 2.1.0
bash scripts/release.sh --version 2.0.0rc1 # 显式指定
# 5) 紧急发版组合(不推荐)
bash scripts/release.sh --skip-tests # 跳测试(环境问题暂时绕过)
bash scripts/release.sh --skip-clean-install # 跳干净环境验证(提速)
bash scripts/release.sh --skip-tag # 不打 git tag
完整参数详见 scripts/release.sh 头部注释;端到端 SOP 与版本策略见 docs/pypi-release.md。
退出码
0 成功 | 1 通用失败 | 2 参数错误 | 3 环境/工具缺失 | 4 版本检查失败 | 5 测试失败 | 6 构建失败 | 7 上传失败
凭证配置(任选其一)
# 方式 A:环境变量(CI 推荐)
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=pypi-AgEIcHlwaS5vcmc...
# 方式 B:~/.pypirc(本地推荐)
cat > ~/.pypirc <<EOF
[pypi]
username = __token__
password = pypi-AgEIcHlwaS5vcmc...
[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-...
EOF
chmod 600 ~/.pypirc
发版前自查清单
-
pyproject.toml与clear_agent/version.py版本号一致 -
CHANGELOG/ commit history 已整理 -
pytest全绿(环境问题除外,见上文表格) - PyPI 上目标版本号未被占用(脚本会自动检查)
- 本地
--dry-run通过 - 先打 TestPyPI 验证
pip install -i https://test.pypi.org/simple/ clear-agent==X.Y.Z
📄 License
CC BY-NC-SA 4.0 —— 允许学习/研究/分享,禁止商业使用。商用请联系作者 perloukevin@gmail.com。
Project details
Release history Release notifications | RSS feed
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 clear_agent-2.0.0.tar.gz.
File metadata
- Download URL: clear_agent-2.0.0.tar.gz
- Upload date:
- Size: 4.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ea2b2fac2e32d533ddd2cb2bd4f175b41f77f4bc3b4b68e19b0b2c6525eb2ed
|
|
| MD5 |
f8dde965fec073e4dc8eaed302319931
|
|
| BLAKE2b-256 |
9b932f5cedcc367a08afe4f2bd238fd940af495901f2a561f75dedf194b3dbe6
|
File details
Details for the file clear_agent-2.0.0-py3-none-any.whl.
File metadata
- Download URL: clear_agent-2.0.0-py3-none-any.whl
- Upload date:
- Size: 257.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a57b2d89f7c923780da208d7c71e4d8c242c6d4c2ea9e7f5893128597ed9518
|
|
| MD5 |
7aae5afdc89ef2a634739f16b2e860ad
|
|
| BLAKE2b-256 |
8cafe5ce2bd2e754e7ffd43af4d02ce4ab5a447882de878c38524017f9c97b99
|