跳到正文

Agents Universe

一套开源智能体平台,让同一个项目里的人共用一份上下文。项目选中时智能体把全部知识读进上下文,干活过程中再把学到的东西写回同一批文件;知识是磁盘上的 Markdown,数据库只做索引,没有嵌入模型,也没有向量检索。

Screenshot of Agents Universe
编辑截图, 1 Oct 2026Agents Universe ↗

这是什么

一个 Apache-2.0 的智能体平台,把项目当作共享记忆的单位。知识是项目工作区里的 Markdown 文件——domain/、technical/、skills/——数据库按项目与 slug 建索引:选中项目时 primary 文件全文进上下文,detail 文件只给元数据与摘要,等某次工具调用去取。没有嵌入模型,也没有向量检索,结构靠显式 [[slug]] 交叉引用承载。写回是另一半:knowledge_rw 把新接口、指标口径与测试经验写进对应的那份文件,随后重新索引、版本号加一、旧正文存档、五项完整度分数重算,并用过期标记与一步显式退役让「遗忘」也可审计。平台自带十个角色定义——Product Owner、Tech Lead、Quality Assurance 等——一轮可以靠 @ 提及交给另一个智能体,也可以在同一个回合里把子任务委派出去。记忆从单轮上下文一路分层到会话、个人、情景、项目与全局知识,任何智能体都能发布成 API 或系统内嵌页面。

谁做的拥有这个仓库的 GitHub 账号,资料页上的名字是 yanqiu(Ian),2017 年 11 月注册,4 个公开仓库,没有简介也没有关注者。仓库的 235 次提交里有 17 次署名是他,另有 2 次署名「Agents Universe」并带一个 localhost 地址;剩下 216 次署名「Agent Universe」,挂 GitHub 的 noreply 邮箱,且都是经 GitHub 的网页提交流而非本地 git 客户端提交——这和 README 里那句「仓库由它自己的 Product Owner 与 Tech Lead 智能体维护」对得上。108 条提交带共同作者尾注,其中 65 条署名 Claude,42 条署名 Claude Code,1 条署名 Claude Opus 4.8。

它是怎么搭起来的

组成 · 6

文件是事实来源,数据库是派生出来的索引——正是这一点让一份共享上下文可以被审阅、被版本化,也能被人手改,而不只是被智能体改。一个回合是装配出来的,不是存下来的:API 先确定是谁、在哪个项目、用哪个模型,构造一个带着项目、用户、工作区根目录与数据库会话的 ToolContext,再建一个短生命周期的智能体,它的工具注册表里只有那份 Markdown 定义声明过的工具。项目知识分两级读入,detail 文件递延到某次工具调用真的去取,而写回的目标就是同一批文件,读与改因此走的是同一条路而不是两条。所有能碰到外部世界的东西都在工具后面,而权限住在工具里:密钥在服务端解密进子进程环境,执行发生在双层沙箱内,一个没有交互用户的请求会拿到一段可读的拒绝,而不是被静默放行。这个形状的代价是写出来的而不是藏起来的——上下文容量与整理质量变成一等问题,沙箱也被描述为纵深防御,而不是隔离。

packages/agent-core/
编排引擎,199 个文件、2,389 KB(含测试),里面没有 HTTP。agent.py 一个有 120 KB,装着工具循环;sandbox.py 80 KB,旁边是 22 KB 的 CPython audit hook 守卫;知识包分成 loader(43 KB)、index(37 KB)与带 tree-sitter 解析器的代码图谱构建器(37 KB 与 41 KB);约六十个工具模块,从文件系统与 shell 一路到 Jira、Confluence、GitHub、MCP 与密钥保险库。测试比被测的代码还重:test_shell.py 61 KB、test_code_executor.py 56 KB、test_graph_builder.py 56 KB、test_sandbox.py 48 KB。
packages/api/
FastAPI 服务,211 个文件、1,608 KB。22 个路由与 24 个 service,其中 services/agent_turn.py 有 150 KB:WebSocket 处理器、对外发布的 API 与定时任务调用的都是同一个回合内核。40 个 Alembic 迁移把一套 schema 扛过 SQL Server、PostgreSQL、MySQL 与 SQLite,包括把「项目 + slug」改成唯一的那次,以及删掉 workspace 层的那次;websocket/handlers.py 与 manager.py 装着连接与回合状态的机器。它的测试在 SQLite 上跑真实的迁移链,CI 另有一个活的 PostgreSQL job,其中包含 49 KB 的发布测试与 35 KB 的压缩测试。
packages/web/
Vue 3 浏览器端,180 个文件、1,377 KB:60 KB 的会话 store、35 KB 的 WebSocket 组合式函数、130 KB 的样式表,以及两份各 30 KB 的语言文件。界面覆盖带工具调用、思考块、计划卡片与附件的对话;一棵工作区文件树,其中的 Markdown 编辑器保存后会自动重建知识索引;知识完整度、记忆与密钥面板;以及发布、定时任务与运行历史各自的页面。
agents/、agents/skills/、workflows/ 与 knowledge/
可复用的行为资产,全是普通 Markdown:十个角色定义(26 KB 的 Quality Assurance、20 KB 的 Tech Lead、16 KB 的 Product Owner,另有数据分析专家、办公助手、智能客服、渗透测试专家与三个定制角色)、八类共 46 个技能、11 个工作流,以及知识库本身——29 个项目模板、一份 categories.yaml 注册表、17 KB 的工具参考、10 KB 的 schema 文档与框架总览。
Dockerfile、docker/、docker-entrypoint.sh 与 nginx-combined.conf
一个多阶段镜像,在同一个容器里让 nginx 挡在 uvicorn 前面;entrypoint 先跑迁移、重建全局知识索引,然后同时监管两个进程。树里约 12 MB 是七个预编译的 tree-sitter 语法二进制,之所以烘进镜像,是因为运行沙箱没有网络,而按需下载的语言包此前是静默失败的。scaffold/tests/ 放着 Playwright 配置与登录 setup,每个新项目的测试目录都从它初始化。
.github/、scripts/ 与提交契约
持续集成跑 web、agent-core 与 API 三套测试,另有一个活的 PostgreSQL job 和一个卫生 job。scripts/check_commit_hygiene.py 读 git var,也就是 git 真正会用的身份,拒绝命中禁用邮箱子串与未知 URL 主机的提交,规则集中在 .commit-hygiene.toml 里,并对安全夹具留了行内豁免;pre-commit 与 gitleaks 的配置放在旁边,scripts/ 里还有那个可以脱离应用独立跑的命令行代码图谱构建器与语法拉取脚本。

取舍,以及它替代了什么

  • 知识放在 Markdown 文件里,数据库只做索引 替代 把正文存进数据库行

    这条约定被写了两遍:删除一条知识是先 unlink 文件,然后才做「尽力而为」的行清理,因为文件变更才是事实来源,不能为了数据库记账卡住;而工作区编辑器会把只有正文的保存合并回文件原有的 frontmatter,所以一次保存不会把元数据抹掉。同一个选择也解释了为什么 PUT 端点要先提交再响应——否则后台重建索引会和自己持有的行锁死锁。代价就写在同一批文件里:每次写入都要重建索引、存一份历史、让缓存失效,而重建失败必须出现在警告里,因为没有索引行的 detail 文件对递延列表是不可见的。

  • 不用嵌入模型——全文加载加显式交叉引用 替代 对分块做嵌入再向量检索

    实现原理指南把它写成一次有意的取舍:企业知识有稳定的结构,也真的依赖上下文,而「召回几段相似文字」可能漏掉边界条件,所以 primary 文件像手册一样整份读入,detail 文件按需再取。它也写了代价与反方:上下文容量与整理质量会变成一等问题;而当文件很多、单篇很长、问题又横跨一批弱相关资料时,向量检索仍占成本优势。

  • 技能与工作流就是模型照着读的 Markdown 替代 把它们编译成一个固定的执行引擎

    指南把这称作一次有意的取舍:柔性与更容易的开源共建,换来的是质量仍然取决于模型遵循度、工具约束与测试门禁。更新日志里能看到它的运行代价——一个由系统提示驱动固定工作流的智能体从不发出计划卡片,最后得把工作流阶段物化成显式任务,界面才有东西可显示。

  • 委派是嵌套在父轮里的,而不是把会话交出去 替代 把会话移交给另一个智能体

    会话级状态只有一份,所以嵌套轮在每一处都被显式守卫——不抢回合、不注册会话、不消费父轮挂起的注入、不写运行行;它的事件走一个「失败即丢弃」的白名单,因为转发流式事件会提前冻结父轮的气泡并重复计 token。深度由配置封顶(默认 2,0 关闭),链上已有的 slug 会被拒绝,会话级锁必须被继承,否则孙轮会死锁在祖先持有的锁上。委派是有意放权的,所以子智能体自己的确认门照旧生效。

  • 沙箱只做到纵深防御,不宣称隔离 替代 承诺生成的代码跑不出去

    安全章节把自己没覆盖到的地方列了出来:CPython 3.12 的 os.stat 与 os.access 不产生 audit 事件,所以纯粹的存在性探测拦不住;Node.js 没有等效的运行时钩子,node 脚本的越界读取只能靠命令级校验约束;非严格模式下,受守护的 Python 派生出的非 Python 子进程不在文件守卫覆盖内。指南还给高影响动作补了一条通则——最小权限、目标白名单、显式确认,以及一条能回滚的路。

  • 一个假设单副本的进程内调度器 替代 带租约的分布式调度器

    到期任务靠对下次运行时间做一次数据库比较交换来认领,没改到行的认领直接跳过而不是重试;服务停机期间错过的周期跳过不补跑;启动清扫把遗留的 pending/running 行落成 failed;抢不到回合认领的启动记为 skipped,而不是打断正在那个会话里打字的人。文档自己写了这个限制:多副本就需要一把分布式锁。

依据CLAUDE.md(12,471 字节)、knowledge/system/framework-overview.md、knowledge/technical/db-schema.md、docs/agents-universe-implementation-guide.zh-CN.md、README.md(44,593 字节)与 CHANGELOG.md(59,990 字节),以及直接读过的 packages/agent-core/src/agent_core/knowledge/index.py、packages/agent-core/src/agent_core/tools/knowledge_rw.py、packages/agent-core/src/agent_core/tools/memory_rw.py、packages/api/src/api/routers/knowledge.py、packages/api/src/api/routers/project_members.py、packages/api/src/api/services/episodic_service.py、packages/api/src/api/websocket/handlers.py 和四个 Alembic 迁移,加上完整的 731 个文件树及其体积。

制作过程

6 个阶段
  1. 01

    一个人,以及这个项目本身在讲的那些智能体

    仓库建于 2026-09-10,最近一次提交是 2026-09-28,但它最老的一次提交是 2026-08-18,更新日志里第一个版本条目写的是 2026-08-08——大约三周的活是跟着一个当时还不存在的仓库一起到的。235 次提交在八月 99 次、九月 136 次,署名才是有意思的部分:216 次署名「Agent Universe」、挂 GitHub 的 noreply 邮箱、经 GitHub 的网页提交流提交;17 次署名账号本人;另有 2 次带一个 localhost 地址。108 条带共同作者尾注——65 条 Claude、42 条 Claude Code、1 条 Claude Opus 4.8——贡献者列表只有两项:web-flow 216 次,账号本人 17 次。旁边是 383 个星、1 个 fork、0 个 watcher,以及唯一一个未关闭的 pull request;仓库是 Apache-2.0,topics 里写着 deepseek-harness 与 workbuddy-alternative。tag 有六个,从 v1.0.0 到 v1.5.0,而 GitHub release 一个都没有:真正的发布台账是一份 59,990 字节的 CHANGELOG.md,版本标题从 2026-08-08 的 0.1.0 一直排到 2026-09-24 的 1.5.0,最新的修复挤在一个 Unreleased 段里。

  2. 02

    两个写入者,一份文件,以及碰撞都修在哪

    一条知识是一个 Markdown 文件,数据库里的那一行只是它的索引,于是所有一致性问题都落在同一个接缝上。并发的索引器为一个项目与 slug 插出重复行之后,走 scalar_one_or_none 的读取开始抛 MultipleResultsFound;迁移 w5h8k6g9h457 按同一对键保留最新一行(先删掉输家各自的加载事件与历史版本)给表去重,然后把索引改成唯一。现在索引器在保存点里逐文件 flush,一旦输掉插入竞争就重新取回赢家那一行、改走更新分支,而不是让整批作废——代码里还留着一句注解:add() 必须放在保存点里面,因为在保存点之前加进去的对象会以 pending 状态活过回滚,下一次 flush 会在任何保存点之外重抛同一个错误,照样把整批弄挂。最重的一次修复在人这一侧:知识 PUT 之前会把事务一直开着,于是后台重建索引对同一行元数据的更新会被行锁挡住,而响应还在等——这个死锁让 PostgreSQL 的 CI job 挂了 40 分钟。现在这个端点先写文件、把旧正文以「用户」为改动者存进 knowledge_versions、提交,之后才在新会话里重建索引并让进程级缓存失效,否则下一次对话还会拿旧的元数据。

  3. 03

    什么算学习,以及它写回文件的那条路径

    在这里,学习是读与写,不是搜。交给它的资料——Confluence 页面、Swagger 导出、需求文档——走一遍 knowledge-ingestion 工作流:判断该归到哪一条,提取有用的部分,写成带交叉引用的条目;发现已有相似条目就先问是更新还是新建。干活过程中同一件事由 knowledge_rw 完成:新接口进 api-map.md,指标口径进 metric-catalog.md,测试经验进 test-patterns.md。每次写入都会重建索引、刷新完整度分数、把旧正文存进 knowledge_versions 并追加到 history.md;一个全新 slug 会收到一条软提醒,让它先填既有文件,API 与 Kong 的 detail 树和真正的层级子条目除外。遗忘也有流程:过时条目先打标记,经用户确认后退役,purge 负责清掉文件已不存在的索引行。另一条写入路径是自动的——会话的情景记忆摘要,取最近 50 条消息、且用户消息至少 3 条,用该用户第一个可用模型生成,且只在没有轮次在跑时由一次被动 WebSocket 断连触发,因为把半截会话拍成快照之后,「每个会话只留一条」的提前返回会把那份不完整的摘要永久锁住。

  4. 04

    什么算共享,边界又画在哪里

    共享是刻意不均匀的。知识查询永远限定在当前项目或全局框架行内,切换项目会清空会话状态,每个项目在仓库之外的 PROJECTS_ROOT 下有自己的工作区。私有项目带一份成员名单——没有用户名目录,创建人直接粘贴单点登录的 user_id,成员自己也能管理这份名单,而可见性开关只留给创建人;名单上「先查后插」的竞争返回 409 而不是 500。密钥是界线最硬的一处:模型密钥与 Git token 分两个保险库用 AES-256-GCM 加密,只在服务端解密进子进程环境供需要的工具使用,永远不进模型上下文,safe_env() 还会把凭据类变量从子进程环境里剥掉。执行跑在双层沙箱里——Shell 的命令白名单,逐段、逐 token 校验路径;再加一个通过 sitecustomize 注入的 CPython audit hook 限制文件写入——而 README 写的是它的边界而不是「隔离」:os.stat 与 os.access 不产生 audit 事件,Node.js 没有等效的运行时钩子,非严格模式下受守护的 Python 再派生出的非 Python 子进程不在文件守卫覆盖内。

  5. 05

    更新日志自己承认的那些事

    一份 32,376 字符、把自己的修理过程记下来的更新日志,是这个仓库里最有用的一份文档,而它列的失败都很具体。nginx 在 15 小时里静默死了三次,容器还 Up 着,公网则一直 502,原因是 entrypoint 把 PID 1 交给了 uvicorn;现在 entrypoint 是一个监督循环,负责重启 nginx 并清掉仍占着端口的孤儿 worker。一条横幅告诉用户「上次运行被打断,输入继续」,可那次运行其实还在跑——一个 16 秒的 run 被结算成「已中断」,而同一个会话又继续输出了一小时,因为 API 把一次中途注入当成了终态,此后 finish_run 只能空转。一个知识完整度接口在任何 PostgreSQL 部署上都返回 500,而本地开发与 SQLite 测试全绿,原因是那边的取整函数没有 double precision 重载。持续集成从来没装过浏览器,于是七个真实 Chromium 用例在每个 job 里静默跳过;装上之后那个 job 从 1,649 passed/9 skipped 变成 1,656/2。后台任务从结束的用例里漏出去,握着 SQLite 的写事务不放,后面的用例随机报 database is locked——而仓库最新的一次提交就是这个修复:在逐用例拆掉 engine 之前先把游离任务排空。全局索引器还曾把 29 个模板当成「系统行」扫进每个项目的知识面板,谁也删不掉,最后靠一条跳过规则加一次迁移才清干净。

  6. 06

    社区这一轮,以及守着提交的那份契约

    外部贡献是三个 pull request,全部来自同一个账号 Mark-super-code:2026-08-21 注册,1 个公开仓库,0 个关注者,没有显示名。其中两个在开出后大约一分钟就被合并——60 秒与 53 秒——第三个开于 2026-09-28,是这个仓库唯一未关闭的事项,而它那条评论是作者自己的补充,不是评审。那个请求建议把文件系统工具的读取上限从 2 MB 提到 5 MB,并把同一个常量在 API 路由里一起改,理由是那个路由的注释写明它的字节上限是「镜像」这个工具的,不改的话,智能体能读到一个工作区查看器会回 413 的文件。它还如实报了测试结果——1,597 passed、2 skipped、47 failed——并用「把改动 stash 掉再跑一遍」证明这 47 个失败是既有的。这个项目本身还要过一份写下来的卫生契约:提交身份用 GitHub 的 noreply 邮箱,示例主机一律限制在保留的 example.com 家族里,由 scripts/check_commit_hygiene.py 经两个 pre-commit 钩子和一个 CI job 强制执行——加它的原因正是平台自己的智能体是在服务端克隆里提交的,本地钩子装不上。

相关档案

全部档案 →