Skip to main content

Liorium

Liorium 是一个可独立发布的 Agent 框架:一个发行版 liorium,内含 12 个模块、 realm 扩展机制、可热重载的运行时、流式事件出口、混合记忆、技能库、MCP 与子代理, 全部只依赖标准库与公开的 LangChain / LangGraph。

  • 模块:liorium.core / liorium.vfs / liorium.realm_base / liorium.core_tool / liorium.core_tool_realm / liorium.agent / liorium.memory / liorium.skills / liorium.mcp / liorium.todo_realm / liorium.provider / liorium.cli
  • 安装:pip install "liorium[all]"(全家桶:MCP + 向量记忆 + 三家 provider 适配 + 图片); 只要框架运行时用 pip install liorium;单独选装见下
  • 仓库:https://github.com/liwusen/liorium-framework

架构决策记录:docs/plans/2026-11-04-liorium-agent-core.md。 实现与决策冲突时以决策记录为准;要改结论先改决策记录。

当前状态:Phase 1(v1.0)骨架 + Phase 2(v1.1)能力包完成 —— 12 个模块的 workspace、 6 个核心工具、Agent 运行时(run/inject/interrupt/apply)、基座中间件链、realm 系统、 子代理、checkpoint 兼容旧库;liorium-memory / liorium-skills / liorium-mcp / liorium-todo-realm 四个 realm 能力包(挂载 + 工具 + 状态 + prompt 片段),以及 conversation scope、profile 语法糖、 MCP mark-dirty reconcile、realm 的第五拍(context_items() 按回合节奏注入)、多 Agent 宿主示例。liorium-memory 已完整迁移旧 GraphStore:FTS5 关键词 + nano-vectordb 兼容向量 + RRF 混合检索 + 实体图谱(递归 CTE)

模块(liorium.*,12 个,同一个发行版)

发布形态:PyPI 上只有一个 liorium(12 个模块的源码由根 pyproject.toml 的 force-include 打进同一个 wheel),安装时的分档只有 extras: liorium[all] / [mcp] / [vector] / [openai] / [anthropic] / [google] / [images]。 下表描述的是 workspace 里的模块边界(开发期 uv sync --all-packages 逐个装成可编辑包, 架构守卫按这些边界检查依赖方向);它们不再各自发到 PyPI。

包 职责 依赖
liorium-core 类型 / URI / 指纹 / 日志 / 端口 零第三方依赖
liorium-vfs VirtualFileSystem / VfsNode / mount + 环检测 零第三方依赖
liorium-memory 与旧 memory.sqlite 同 schema 的存储 + 检索/图谱/抽取 + MemoryRealm(memories://) core, vfs, langchain-core([vector] extra:numpy/nano-vectordb/httpx)
liorium-skills SKILL.md 目录 + SkillsRealm(skills:// + 技能清单) core, vfs, langchain-core
liorium-mcp MCP 客户端(stdio/sse/http)+ McpRealm(运行时发现工具) core, langchain-core, mcp
liorium-todo-realm 状态化待办 + TodoRealm(todo / todo_list,每 50 回合提醒) core, realm-base, langchain-core
liorium-core-tool 六个核心工具的实现 + ToolRuntime core, vfs, langchain-core
liorium-core-tool-realm 核心工具的 realm 外壳:写 RealmSpec(id="core") 才装(Agent 不再自带任何工具) core-tool, realm-base, vfs
liorium-realm-base realm 契约与写作 API:Realm / BaseRealm / RealmContext / JsonStateStore / @realm_tool core, vfs([tools] extra:langchain-core)
liorium-provider-manager Provider schema / 四种 API 格式 / 思考 / models.dev 目录 / 模型构建 core, pydantic, httpx, langchain-core([openai/anthropic/google/all])
liorium-agent LioriumAgent / runtime / middlewares / scheduler / realms core, vfs, realm-base, langchain, langgraph
liorium-cli 官方命令行 Agent:REPL / 斜杠命令 / 子代理事件查看 liorium-agent[core,memory-vector,skills,todo], liorium-provider-manager[all]

依赖方向:core 是叶子;开发期 liorium-agent 对 realm 模块走 extra([core] [memory] [skills] [mcp] [todo]),发布版这些模块都已在 wheel 里、由上面的 extras 只控制第三方库。 Agent 不依赖 liorium-core-tool:六个核心工具由 liorium-core-tool-realm 提供,装不装、装哪几个 由用户在 AgentSpec.realms / toolsets 里决定。 realm 契约与写作 API 在 liorium-realm-base(2026-11-07 从 agent 搬出):写一个 realm 只需要 core + vfs,不背 langchain / langgraph;liorium-agent 依赖它并 re-export 旧名字。 能力包(liorium-core-tool / liorium-core-tool-realm / liorium-memory / liorium-skills / liorium-mcp)允许 import liorium.agent 或更轻的 liorium.realm_base(2026-11-06 起);liorium-todo-realm 只依赖 core + realm_base,是"能力包不必背 Agent"的示范。能力包之间仍互不依赖。

realm 实例作用域(2026-11-08):每个 realm 声明 instance_scope。 "tree"(memory / skills / mcp / subagents)整棵 Agent 树共享一份实例,子代理只借它的工具 —— 状态文件、VFS 挂载、外部连接都只有一份;"agent"(core / todo)每个 Agent 各一份,状态落在 自己的 inbox/realm_state/ 下。框架强制约束:"agent" 级 realm 返回挂载点会在启动期直接报错, 所以"父子两套状态抢同一路径"在结构上不可能发生。

第五拍(2026-11-07 接线):realm 用 context_every / context_first 声明节奏、 用 context_items(turn) 返回要注入的内容;RealmManager.context_for_turn() 在拿到执行位后 问一次,内容在下一个安全点物化成独立的 <context> user 消息(不改历史前缀、不吃缓存)。 返回空不消费周期 ⇒ 待办清单空着不浪费额度,一有 pending / processing 立刻提醒。

文档

完整文档入口:docs/README.md(按使用者 / 扩展者 / 维护者分三条线, 附术语表)。

文档 内容
docs/GUIDE.md 从零到跑起来:安装、最小 Agent、事件表、中断/注入、压缩与成本、多 Agent 并发(每段都能跑)
docs/API.md 12 个模块全部公开名字的签名、默认值、异常与不变量
docs/EXTENDING.md 写自定义 Realm / Middleware / 调度参数(priority / FLAG)/ model_factory / 工具,以及常见坑
docs/MEMORY.md 记忆子系统:磁盘布局、检索流水线、内存预算、设计取舍
docs/ARCHITECTURE.md 实现视角的模块地图与一个回合的时序
docs/PUBLISHING.md 发布流程:Trusted Publishing(OIDC)到 PyPI

快速开始

配置:.env 或命令行

CLI 的每项配置都能放进当前目录的 .env(在仓库里就是仓库根;已被 gitignore,模板见 .env.example):

Copy-Item .env.example .env      # 填 provider / 模型 / 记忆目录 / embedding
uv run liorium-cli                # 或 python -m liorium.cli

优先级 命令行 > 环境变量 > .env > 默认;--env-file 指定文件、--no-env 不读。 键名规则:LIORIUM_ + 选项名大写(LIORIUM_MODEL、LIORIUM_MEMORY_DIR、LIORIUM_EMBED_MODEL …), 完整清单见 .env.example 与 MEMORY。

最小 Agent

import asyncio
from pathlib import Path

from liorium.agent import AgentSpec, Limits, LioriumAgent


def make_chat_model(label: str):
    from langchain_openai import ChatOpenAI
    provider, model = label.split("::", 1)
    return ChatOpenAI(model=model, base_url="https://api.deepseek.com", api_key="...")


async def main() -> None:
    agent = LioriumAgent(
        spec=AgentSpec(
            id="main",
            inbox_dir=Path("agents/main"),
            model="deepseek::chat",
            prompt_sources=("AGENT.md", "ROLE.md", "COREMEMORY.md"),
            limits=Limits(context_window=128_000, max_turns=200),
        ),
        model_factory=make_chat_model,
    )
    await agent.start()                       # 不调模型(计划 §F7)
    try:
        async for event in agent.run("今天出门要带伞吗?"):
            print(event.to_dict())            # start / delta / reasoning_delta / tool_* / done
    finally:
        await agent.close()


asyncio.run(main())
  • 叫停 = await agent.interrupt(reason="user_stop") + 一个新的 run()(两个回合)。
  • 运行中补充信息 = await agent.inject([ContextItem(source="trigger:desktop", text="开始下雨了")]), 永不打断,在下一个安全点物化成独立 user 消息。
  • 热重载 = await agent.apply(new_spec):只重建指纹变化的部件;失败保留旧部件。
  • 清空对话 = await agent.reset_dialog()(纯状态写入,不调模型;同时清空 state_scope="conversation" 的 realm 状态)。

CLI Agent(liorium.cli)

packages/liorium-cli 是官方命令行 Agent(不是示例):realm 能力包(核心工具 read/write/edit/search/find/execute、长期记忆(memories://)、技能库(skills://)、 待办、子代理)、流式渲染、/model 热切换、inject、clear、Ctrl+C 中断。模块路径 liorium.cli,入口 liorium-cli(等价 python -m liorium.cli)。发布版里 CLI 就在 liorium 同一个 wheel 中,装 pip install "liorium[all]" 即可,不需要额外的 liorium-cli 包。

六个核心工具现在是 core realm(liorium.core_tool_realm):CLI 默认装上,--no-core-tools 则不装(Agent 就一个工具都没有),--tools read,find 只装子集。

# 装好工作区后直接跑(默认用 provider 配置里的 main_model)
uv sync --all-packages
uv run liorium-cli

# 指定 provider / 模型
uv run liorium-cli --provider Go --model deepseek-v4.1-flash

# 思考强度(默认 medium;off 关闭)
uv run liorium-cli --thinking high
uv run liorium-cli --thinking off --temperature 0.3

# models.dev:默认只读本地缓存;refresh 才联网(结果只改内存)
uv run liorium-cli --models-dev refresh --list-models

# 挂上示例技能(skills://session-log,演示"读技能 → 写记忆")
uv run liorium-cli --skills-dir examples/skills

# 只要核心工具,不要记忆 / 技能 / 待办 / 子代理
uv run liorium-cli --no-memory --no-skills --no-todo --no-subagents

# 核心工具只装一部分(读 + 查找 + 执行)
uv run liorium-cli --tools read,find,execute

# 一个工具都不要(零工具装配是合法的)
uv run liorium-cli --no-core-tools --no-memory --no-skills --no-todo --no-subagents

# 把记忆库指到别处(默认 <inbox>/memory,可直接读写既有 memory.sqlite)
uv run liorium-cli --memory-dir ~/liorium-memory

# 单轮 / 管道 / JSON 事件(便于脚本与测试)
uv run liorium-cli -p "统计仓库里有多少个 .py 文件"
echo "总结 README" | uv run liorium-cli --json

# 列出配置里的全部模型(带格式与上下文长度)
uv run liorium-cli --list-models

配置查找顺序:--config → $LIORIUM_PROVIDER_CONFIG → ~/.liorium/providers.json → 当前目录 providers.json。全都找不到时逐项询问(base_url / key / 模型 / API 格式 / 上下文长度 / 思考方言),并可选保存到 ~/.liorium/providers.json。 Provider 管理(四种 API 格式、思考参数、models.dev 识别、模型构建)由 liorium-provider-manager 提供。

交互命令:/help /model [Provider::model] /provider <name> /thinking [off|low|medium|high] /models-dev [status|refresh] /clear /status /tools /memory [query] /skills /todo [all] /realm [enable|disable] [id] /subagent /reload /inject <text> /context /history [n] /exit。

  • 记忆:read memories:// 看目录、read memories://<path> 读全文、/memory <词> 检索; Agent 用 write memories://<path> 自己存长期事实(路径当标题)。
  • 技能:<skills_dir>/<slug>/SKILL.md,清单自动预载进 system prompt; 装/卸/改完打 /reload 立刻生效(重挂载 + 重取工具 + 重建 prompt,CacheEpoch +1)。
  • 子代理:默认启用,模型用 newSubagent / invokeSubagent / wait_for_subagents 驱动 (并行数量不设上限)。父回合进行中只实时打印关键事件(创建 / 工具 / 完成 / 失败); /subagent 列状态,/subagent <name> [n] 看最近 n 条事件(默认 20), /subagent stop|rm <name> 停止 / 删除(名字也接受 subagent-<name> 或 agent_id)。
  • realm 开关:/realm 列出每个 realm 的状态 / 工具数 / 挂载 / 上下文节奏,/realm <id> 看详情; /realm disable <id> 与 /realm enable <id> 运行期开或关(工具、挂载、prompt 段一起撤下或恢复, epoch +1,不需要重启 CLI)。装配集合仍由启动参数决定:--no-memory 这类要重启才会变。
  • 记忆 / 技能 / 待办在发布版里都在同一个 liorium wheel 中,CLI 默认全部装配; 只有第三方库需要按需选装(liorium[vector] / [mcp] / [openai] …), 缺这些库时 CLI 打印一条提示并降级,核心工具(core realm)照常可用。

工作区默认是当前目录(read/write/edit/search/find/execute 的相对路径基准), Agent 根目录(prompt + checkpoint + 记忆库 + 技能目录 + 子代理)默认是 <workspace>/.liorium-cli/agent,可用 --workspace/--inbox/--system/--memory-dir/--skills-dir 改。Ctrl+C 在生成中是 中断当回合(不退出),在提示符下是退出。

realm 能力模块(v1.1)

四个 realm 能力模块都是"工具 + 状态 + prompt_fragment()"(前三个还有 VFS 挂载):

from liorium.agent import AgentSpec, RealmSpec, LioriumAgent
from liorium.memory import MemoryRealm
from liorium.skills import SkillsRealm
from liorium.mcp import McpRealm
from liorium.todo_realm import TodoRealm

agent = LioriumAgent(
    spec=AgentSpec(
        id="main",
        inbox_dir=Path("agents/main"),
        model="deepseek::chat",
        prompt_sources=("AGENT.md",),
        realms=[
            RealmSpec(id="memory"),          # <inbox>/memory/memory.sqlite
            RealmSpec(id="skills"),          # <inbox>/skill.d/*/SKILL.md
            RealmSpec(id="mcp", params={"servers": {"playwright": {"command": "npx", "args": ["@playwright/mcp"]}}}),
            RealmSpec(id="todo"),            # <inbox>/realm_state/todo.json;每 50 回合提醒
        ],
    ),
    model_factory=make_chat_model,
    realm_factories={
        "memory": MemoryRealm,
        "skills": SkillsRealm,
        "mcp": McpRealm,
        "todo": TodoRealm,
    },
)
包 挂载 / 工具 说明
liorium-memory memories://(懒加载投影)、memory_search / memory_list / memory_delete / memory_tag / memory_score / memory_graph / memory_attach SQLite schema 为 v1,可直接读写既有 memory.sqlite;读/写/编辑走核心 read/write/edit
liorium-skills skills://(只读)、list_skills <inbox>/skill.d/<slug>/SKILL.md;技能清单预载进 system prompt,装/卸技能 ⇒ CacheEpoch +1
liorium-mcp 无挂载、动态工具 工具名 <server>_<tool>;realm.set_servers(...) 或 realm.mark_dirty() 后,下一个回合边界自动重连换工具
liorium-todo-realm 无挂载、todo / todo_list 状态化待办(pending/processing/blocked/finished);每 50 回合把未完成清单注入上下文(只在有 pending/processing 时)

已知缺口:McpRealm 目前没有实现 Realm.mounts(),经 AgentSpec 装配时会被 RealmManager 标 failed(降级,不影响其它 realm)。docs/API.md 的 MCP 一节也标注了同一件事。

realm 的 v1.1 可选钩子(能力包实现,Agent 在回合边界 / 拿到执行位后调用):

  • dirty() / mark_dirty():真相源变了就刷新工具/挂载/提示词; clear_dirty() 由能力包自己实现(BaseRealm 没有默认实现,缺省时管理器用 mark_dirty(False) 兜底);
  • async refresh():刷新前重连(MCP 用)或重新对账(memory 用);
  • skills():该 realm 想预载进 prompt「技能清单」段的条目;
  • context_every + context_items(turn)(第五拍):每 N 回合给一次"要不要说点什么"的机会, 返回非空才注入、返回空不消费周期;ctx.inject() 是同一管道的推送侧。

宿主自己知道真相源变了(刚装了技能、另一个进程写了记忆库)时,可以不等下一个回合:

await agent.refresh_realms()          # force=True:先全部置脏,再刷新 + 重建运行时
await agent.refresh_realms(force=False)  # 只刷新自报 dirty() 的 realm

refresh_realms() 返回是否真的刷新过;工具 schema / system prompt 变了 CacheEpoch 才 +1。

运行期开关某个已装配的 realm(工具 / 挂载 / prompt 段 / 后台任务一起撤下或恢复):

await agent.set_realm_enabled("todo", False)   # 返回调用后是否在运行
await agent.set_realm_enabled("todo", True)

装配集合仍由 AgentSpec.realms 决定(未装配的抛 RealmNotFoundError);CLI 的 /realm 就是它的薄前端。

conversation scope:state_scope="conversation" 的 realm 状态按 thread 分桶 (realm_state/<id>/conversation-<thread>.json),await agent.reset_dialog() 时清空; state_scope="agent" 的状态跨对话保留。

profile 语法糖:

from liorium.agent import Profile

profile = Profile(id="chat", realms=(RealmSpec(id="memory"), RealmSpec(id="skills")))
spec = spec.with_profile(profile)     # 显式声明优先;指纹覆盖合并结果

示例:多 Agent(2 个 Agent + 调用方 semaphore)

examples/multi_agent.py 演示"并发由调用方控制":两个身份独立的 Agent 并发跑同一条 任务,用 asyncio.Semaphore 包住每个回合的 async for(库只保证同一个 Agent 内部排队)。

python examples/multi_agent.py -p "用一句话介绍 Liorium" --concurrency 1

开发

uv sync --all-packages --all-extras     # 建 .venv 并装好 12 个模块(可编辑包)
uv run pytest -q                        # 全量测试(含架构守卫)

# 本机 PyPI 慢时用离线模式
uv sync --all-packages --all-extras --offline

# 直接跑测试(用 .venv 里的解释器)
.\.venv\Scripts\python.exe -m pytest -q -p no:cacheprovider
.\scripts\test.ps1 -q

# 真模型端到端(OpenCode Go)
$env:OPENCODE_GO_KEY = "<key>"
$env:OPENCODE_GO_BASE_URL = "https://opencode.ai/zen/go/v1"
$env:OPENCODE_GO_MODEL = "deepseek-v4.1-flash"
.\scripts\test.ps1 -q -m live

本地联调(把工作区 12 个包以可编辑模式装进任意解释器):

./scripts/dev-install-liorium.ps1                       # 装进 .venv
./scripts/dev-install-liorium.ps1 -Python C:\Python311\python.exe -AllExtras

发布走 GitHub Actions 的 Trusted Publishing(OIDC,无需任何 API token): 推一个 v* tag 即可把 liorium 发到 PyPI(12 个模块在同一个 wheel 里,PyPI 侧只需 1 条 pending publisher,见 docs/PUBLISHING.md)。

不变量(违反即跑偏,计划 §8)

  1. liorium 任何包不许 import 旧后端(tests/test_architecture.py 用 AST 守这条线)。
  2. 任何包不许读产品配置文件。
  3. 基座中间件顺序不可被 realm 改变。
  4. 不许出现裸 asyncio.create_task(一律 ctx.spawn / 宿主托管)。
  5. 不许新增 LangChain 消息类型;Context 只存在于独立 channel。
  6. 工具 schema 变化必须伴随 CacheEpoch +1。
  7. 工具名冲突必须报错。
  8. run() 之外没有第二条 Agent 事件流。
  9. VFS 里不放真相(只放投影);realm 状态不放 checkpoint。
  10. 每个 realm 能力包必须提供自己的 realm;只提供工具实现、不提供 realm 的包(如 liorium-core-tool) 由 realm 壳包(liorium-core-tool-realm)负责装配,Agent 自己不添加任何工具。

Metadata

Release files for liorium 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for liorium 0.1.0
File Size Uploaded Provenance Actions
liorium-0.1.0.tar.gz 311.8 kB With provenance Details for liorium-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for liorium 0.1.0
File Interpreter ABI Platform Actions
liorium-0.1.0-py3-none-any.whl Python 3 none any Details for liorium-0.1.0-py3-none-any.whl

Total release size: 695.3 kB

Release files / liorium-0.1.0.tar.gz

Download URL liorium-0.1.0.tar.gz
Size 311.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e7015ff47bc4f29f2028c81130854047fb390427e06039a42f706fdd623bd31d
BLAKE2b-256 checksum
How to use checksums
52578afe20190304ba3459280a8edeaac36eb757966c37bd82940ff2dacc7472
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Release files / liorium-0.1.0-py3-none-any.whl

Download URL liorium-0.1.0-py3-none-any.whl
Size 383.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3c8d9427dca8262b7536c2ffaa2b077ca4ae8ecd3a579280a1f67d82765004c1
BLAKE2b-256 checksum
How to use checksums
e1c078855c1b8239b3b2e40ac1b5243ed6baca454644563c322525debf12f7e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

Security for liorium 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for liorium-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page