AgentLoom 总体技术设计
更新:2026-10-09。代码核对基线:9941e31(master)。本文描述该基线的实际架构,并单独列出尚未落地的设计。产品处于开发测试阶段。
AgentLoom 是面向团队的低代码 Agent 平台。用户集中管理模型连接、Skill、MCP 工具和知识资料,通过配置并发布 Agent,让团队成员从网页或 API 发起任务。Agent Runtime 是核心,管理端负责把可运行配置交给 Runtime。
配套文档:产品需求、Runtime 详细设计、平台、API 与数据设计、部署运维、源码目录。
1. 需求与实现对照
“已实现”表示代码路径和本地测试已存在,不等于真实供应商、Docker、NFS 或生产集群均已完成联调。
| 用户需求 | 当前实现 | 边界与后续工作 |
|---|---|---|
| 多人使用,Agent 属于空间 | 账号、邀请码、owner/member、空间资源、API Key | 没有完整 RBAC、多空间切换和企业组织体系;个人运行记录不向全空间开放 |
| 配置后发布才能调试 | 草稿与发布版本分离;网页/API 仅运行已发布配置 | 同一会话固定版本;配置快照不等于所有外部资产永久可用 |
| DeepSeek 与 OpenAI,Key 后发现模型 | 模型发现、目录元信息、测试连接、Chat Completions 工具调用 | 供应商列表未必给窗口大小;使用返回元信息、已知目录或保守回退,不能保证自动知道所有限制 |
| Codex 类自主 Loop | 模型决策、工具执行、结果反馈、完成检查、继续/等待补充 | 模型完成检查是判断机制,无法代替真实测试证据 |
| ReAct / 自动 Plan | 共用 Loop,Plan 通过 update_plan 生成和调整计划后执行 | 没有人工批准每一步的 Plan 模式 |
| 运行时按需创建子 Agent | 内嵌模板、独立 Prompt/资源/上下文,继承主模型 | 不单选模型或模式;不递归;当前顺序执行;每 Run 最多 8 次委派 |
| Skill 文件夹与 Git 导入 | SKILL.md、附件、按需读取、容器命令 | 公开 HTTPS Git;不能据此宣称完整兼容所有 Codex/Claude Code 宿主能力 |
| 外部或自建工具快速接入 | 外部 MCP HTTP/SSE、托管 Python MCP、ToolServer SDK | 托管构建与调用需要 Docker;私有 Git、独立执行集群尚未实现 |
| Loop 与实际执行解耦 | 工具请求总线、工具注册表、Handler、统一结果 | 总线在进程内;一次执行请求只交一个处理器,通知才支持多订阅者 |
| 各执行边界可扩展 Hook | 模型、工具、上下文、压缩、主/子任务、Embedding Hooks | 可信 Python 注册;未开放上传/Git Hook、隔离 Worker 和管理页面 |
| 连续会话与主动压缩 | 原始消息记录、模型视图、压缩快照、默认 80% 阈值及轮数条件 | Token 是估算值;不是精确供应商 tokenizer;长期 MemoryService 尚未实现 |
| 失败或中断后恢复 | 加密检查点、阶段恢复、已保存结果复用、未知结果保护 | 恢复原 Run;不保证外部系统 exactly-once;不等于自动跨节点接管 |
| list/grep/read/write 等系统工具 | 10 个文件/命令工具、共享 POSIX 适配、隔离工作区 | 没有多文件 patch、交互 PTY、后台进程会话等能力 |
| 上传业务知识文本 | MD/TXT/SQL 入库、混合检索、文档引用、Embedding Hooks | 当前是数据库中的 RAG 文档;文件式 Wiki、目录阅读及在线 Wiki 编辑不在本轮新增范围 |
2. 总体架构
采用模块化单体:一个 FastAPI 进程承载管理接口、运行服务、Runtime 与进程内事件总线。模块边界已经部分通过 Protocol、注册表、回调和组装参数表达;不通过“先拆成多个服务”实现模块化。
| 层 | 负责什么 | 不负责什么 | 当前入口 |
|---|---|---|---|
| 网页与 HTTP 接入 | 表单、鉴权上下文、请求校验、事件展示、文件下载 | 模型密钥解析、工具实际执行 | Vue、routes |
| 平台应用服务 | 资源管理、发布、会话准入、运行生命周期、历史与索引 | 在路由中编写模型决策循环 | services |
| Runtime 组装 | 将冻结配置、策略、存储和能力装配为实例 | 登录、草稿管理、文档上传 | runtime.py |
| Runtime 核心 | Loop、上下文、模型请求、计划、完成判断、预算、Hooks | 根据工具名实现文件/MCP 等功能 | engine.py、模块契约 |
| 能力执行 | 工具契约、授权/校验、工作区、Skill、MCP、知识检索、委派 | 向模型开放任意宿主路径或平台凭据 | tool_runtime.py、handlers |
| 基础设施 | SQL、文件存储、供应商 HTTP、Docker、持久化回调 | 产品配置与模型决策 | database.py、workspace_store.py、sandbox.py |
Runtime 不反向依赖 apps/api。API 负责提供资源快照、检索等执行服务,以及保存状态和观察事件的回调。当前部分 SQL 仍在路由内,数据访问还没有全部收口到 Repository;“逻辑分层”不能理解为所有目标类都已创建。
3. 可插拔边界
模块替换在可信宿主的 Python 组装阶段进行;这与普通用户从页面上传任意插件是两个不同的能力范围。
| 边界 | 当前契约/对象 | 替换时必须保持的约束 |
|---|---|---|
| 模型网关 | ModelGateway.invoke(ModelRequest) | 统一消息/工具调用结构;通过公共调用计数、Hooks 和响应校验 |
| 上下文管理 | ContextManager | 连续追加、恢复、原记录与可见视图区分、合法消息组 |
| 压缩 | CompactionPolicy.compact(...) | 只处理完整组;保留任务;失败不推进压缩水位 |
| 完成检查 | CompletionPolicy.review(...) | 返回 complete / continue / blocked |
| 执行策略 | ExecutionStrategy | 注入指令、授权行动、候选结果检查;复用 Loop |
| 预算 | ExecutionLimits | 正整数模型调用与迭代限额;其他平台限额尚未全部统一成策略对象 |
| Hook | HookPointRegistry / HookRegistry / HookManager | 挂点白名单、输出校验、版本与代码指纹、恢复语义 |
| 工具 | ToolDefinition / ToolRegistry / ToolRuntime | 服务端绑定权限、JSON Schema、超时/取消、恢复策略 |
| 文件与命令 | WorkspaceProvider、POSIX Store、Sandbox | 由宿主限定空间/Agent/会话/实例;模型不指定存储根目录 |
| 执行服务 | build_tool_context 与 PlanEditor / ChildRunner / CitationRecorder / InvocationState | 将执行状态适配为受限接口;检索、MCP、技能由各 Handler/适配器处理,避免依赖 Engine 内部状态 |
| 状态与观测 | persist、事件回调、Observer | 持久化成功后才推进事实;观察失败不能伪造工具结果 |
RuntimeModules.bindings() 把实现的 module_id 与 JSON 配置写入检查点;恢复校验模块身份。它不是从检查点动态导入代码的加载器。更换实现由宿主通过 create_engine 显式注入对象并校验绑定,同时处理旧检查点兼容;当前没有通用 ModuleRegistry,工具与 Hook 则各有注册表。生命周期关闭只关闭归属自己的资源,同一对象不重复关闭。
仍缺少的独立边界:统一 CheckpointStore 端口、分布式 Scheduler/LeaseStore、独立子任务调度器、MemoryService、完整资源引用追踪与撤销过滤。persist 回调已经隔离了保存动作,但 Engine 仍持有执行状态并知道哪些边界必须保存;这部分不能由观察者异步替代。
4. 从配置到运行
4.1 配置和发布
- 空间成员配置主 Agent 的模型、Prompt、模式、资源、子模板和上下文策略。
- 发布服务校验资源,并保存发布快照;Hooks 绑定、模块相关配置和知识文档集合随快照固定。
- 网页/API 指定版本或选择最新发布版本。未发布草稿不能启动。
- 创建会话时固定 Agent 版本;后续新提问沿用该会话版本。已有 Run 的恢复使用其原发布与检查点。API 省略
version时仍取 Agent 最新版,因此继续旧会话须显式传原会话版本;若已发布新版却省略版本,会因 Session 版本不匹配被拒绝。
主模型运行时按原资源 ID 读取当前 Key,模型 ID/provider/base URL 仍取发布快照。目前凭据轮换只能安全用于同一连接身份;更换供应商或端点应创建新的模型连接并重新发布。代码尚未对聊天连接的身份迁移建立完整约束,详见平台设计中的发布边界。外部 MCP 凭据和文件资源另有快照/存储规则,不能把“发布不可变”理解为所有凭据都自动轮换。
4.2 一次任务
网页 / API
→ 认证 + 空间/版本校验 + 会话/并发准入
→ 创建 Run、工作区绑定、事件和运行句柄
→ 读取连续历史,create_engine 装配模块
→ ContextManager 准备当前模型视图
→ 模型 Hook → 预算/协议校验 → ModelGateway → 保存结果 → 后置 Hook
→ 模型有 tool_calls:逐个通过 EventBus 请求 ToolRuntime
→ 工具 Hook → 核心授权/参数校验 → Handler → 保存真实结果 → 后置 Hook
→ 将有效观察追加到上下文,继续 Loop
→ 候选回答 → 完成检查 → 继续 / needs_input / succeeded
→ 事务提交终态和事件,清理归属资源Plan 通过 update_plan 工具维护结构化步骤。Loop 不充当固定 DAG 调度器。子任务由主模型委派,子实例使用自己的 Prompt 和资源集合,继承主模型;内部对话保持隔离,结果通过委派工具回到父实例。
4.3 三种通道必须区分
| 通道 | 目的 | 失败和消费方式 |
|---|---|---|
tool.execute 请求/响应 | 执行一次能力并等待结果 | 关联 ID;单处理器;超时/取消传递到执行方 |
| 通知/Observer | 记录调用开始、完成与诊断等观测 | 可以有多个订阅者;观察异常不能替代实际结果 |
| SQL 事件 → SSE | 将已记录的运行变化交给前端/API 客户端 | 按序号续接和去重;断开浏览器不等于取消 Run |
因此写共享存储仍先经过总线,但不会把一个写请求广播给所有节点。未来若接入消息队列,必须保留“单执行权、关联结果、持久化和重复投递控制”的语义。
5. 会话、上下文、压缩与记忆
| 标识/记录 | 生命周期 | 内容 |
|---|---|---|
| Session | 多次提问 | 绑定空间、用户、Agent 版本;组织已提交主实例历史 |
| Run | 一次新提问及其恢复 | 任务状态、模型预算、事件、检查点、主/子实例 |
| Instance | 主实例或单个子任务 | 独立 Prompt、对话、计划和调用进度;逻辑线程为 (run_id, instance_id) |
session_messages | 连续来源记录 | 用户输入、补充、模型与工具记录;保留失败/取消中已提交的有效事实 |
session_views | 可复用的上下文视图 | 已压缩的模型视图、覆盖水位与计数基线;不是原文替代品 |
| Checkpoint | 原 Run 的恢复点 | 实例状态、pending 调用、模块绑定、Hook 阶段、压缩与预算相关状态 |
同会话的新提问建立新 Run,继承兼容历史视图并接上后续记录;不会复制旧 pending 调用和取消标记。恢复旧 Run 则沿用旧执行线程,不自动吸收其后新建的 Run。子任务内部对话不会全部摊入主会话;父实例只看到显式返回的结果。
默认压缩在有效输入预算的 80% 触发,压缩后目标为 60%,也可按新提问轮数或当前实例 action 模型步骤触发;子实例不增加父实例计数。有效预算扣除输出预留与安全余量,并受模型输入上限约束。新发布使用的 BudgetCompactionPolicy 无论软阈值是否启用,仍执行硬预算校验,消息、工具 schema 与 Hook 增补都纳入检查。旧字符策略及未实现可选 validate_request 的自定义压缩器不自动获得窗口硬校验;替换模块时必须显式保持这项约束。
原始记录不因压缩删除。当前按完整消息组和保守 Token 估算压缩,covered_seq 是视图覆盖水位,尚不是每句摘要对应的精细来源范围。工具结果进入模型视图时有 24,000 字符上限,完整事实的保留不代表每轮模型都读取完整内容。
长期记忆尚未实现。会话历史和压缩摘要解决“本会话能继续处理什么”,未来 MemoryService 才负责跨会话提取、整理、版本、撤销及按需回查。目标设计见上下文管理设计,当前算法和恢复细节见Runtime 设计。
6. Hooks 与可恢复操作
HookManager 是 Runtime 的正式模块。挂点决定允许读写的字段、返回 schema、异常策略与超时;Hook 不能获取任意 Engine 引用后直接修改执行状态。修改请求后仍进行核心授权、协议和预算校验。
一次 durable operation 的要点是:保存有效输入 → 调用底层能力 → 保存真实结果 → 执行 after Hook → 保存有效输出。没有绑定 Hook 时仍使用同一路径,因为这些记录也服务调用级恢复。后置处理失败后恢复会复用真实结果,不重新调用已经完成的外部能力。
当前挂点契约为 v2,严格校验必需字段和额外字段;旧检查点使用宿主已知的 v1 契约兼容。绑定保存 Hook 版本、代码指纹与配置,恢复校验后再执行。文件源码指纹与动态字节码指纹都有明确范围;闭包、全局状态和外部依赖不能仅靠函数指纹覆盖,需要部署者提供完整工件 code_hash。
Hook 使用单调时钟预算;墙上时钟 deadline 只用于展示。可信异步 Handler 在进程内执行,超时不是对任意阻塞代码的强制隔离。上传执行、独立 Worker、按用户安装 Hook 和可视化调试仍待建设。Embedding 使用独立的持久化操作记录和冻结索引处理链,见Embedding 专题。
7. 持久化、文件与恢复
业务数据、发布、Run、事件、加密检查点、会话消息和知识索引保存在 SQL。默认测试使用 SQLite;用户部署可以使用 PostgreSQL。二者都有 001–005 编号迁移。供应商 Key、检查点及会话敏感记录按各表处理加密,不是整个数据库加密;知识正文、部分配置和运行事件仍需数据库访问保护。
文件分为三类:导入包 data/assets;新工作区 data/workspaces 或配置的共享卷;旧 Run 兼容目录 data/runs。加密根密钥 data/encryption.key 需要单独保护和备份。共享工作区不自动同步技能包、托管镜像或平台密钥。
主文件域按空间、Agent、Session 隔离,同会话多次 Run 共用。子文件域再按 Run/实例隔离。数据库 run_workspaces 固定存储 backend、volume ID 和逻辑 scope,节点的绝对挂载路径可以不同。shared_posix 必须验证已有 .agentloom-volume,不匹配时失败,不悄悄回退到本地目录。
POSIX 文件适配执行路径校验、描述符相对访问、拒绝符号链接/硬链接等、原子替换、内容哈希条件写和锁。命令容器仅挂载当前工作区与只读技能;若执行或清理结果未知,保留隔离标记,阻止进一步写入和命令执行,避免在状态未明时继续修改文件。
| 中断位置 | 当前处理 |
|---|---|
| 调用前 | 恢复校验配置与检查点,继续合法阶段 |
| 真实结果已保存,after Hook 未完成 | 继续后处理,复用保存的结果 |
| 外部工具已经发出但结果未知 | 根据工具恢复策略处理;不可安全重放的操作要求先核实实际状态 |
| 模型请求已发出但响应未知 | 需要显式 retry_unknown_models 授权,防止无意重复计费/请求 |
| 容器清理不确定 | 保留隔离标记;由运维确认容器及文件状态后处理 |
| 完成后持久化失败 | 单进程内保留待收尾记录并重试提交;不能替代跨进程持久队列 |
当前不支持安全的多 Worker/集群运行。 Run 句柄仍在内存,启动数据库初始化会处理中断任务,没有 Worker 租约或 fencing token。把数据库和文件都共享后直接启动第二个应用进程,会破坏任务归属判断。未来集群还需要持久调度、执行权租约、单调隔离令牌、幂等与状态接管协议。
8. 安全与权限边界
- 管理资源与发布 Agent 在空间内共享;Run 详情、事件、恢复/取消、会话历史和产物由发起用户访问。API Key 也通过所属用户/空间进入同一检查路径。
- 模型只看到已绑定工具及服务端限定的资源。空间 ID、真实文件根目录、模型 Key 和数据库凭据不由模型提供。
- 用户文档、工具返回和 Skill 文件是执行输入,不能提升平台权限。Prompt 约束不能替代 Handler 的授权和路径边界。
- Docker 系统命令要求宿主非 root、匹配 UID/GID、预加载镜像、本地 socket;默认无网络、只读根文件系统、限制 CPU/内存/进程。Docker 或普通子进程本身不等于完整多租户恶意代码隔离。
- 远程模型和 MCP 是网络信任边界;应由部署环境限制可访问端点。当前没有完整统一的出口代理和目的地址策略。
- 历史正文按资源撤销做精细过滤、跨节点执行权、完整审计/限流、聊天模型连接身份迁移约束仍有待补齐。不要把当前 owner/member 和文件隔离视为完整企业安全体系。
9. 验证依据与交付边界
本次为文档整理,代码基线不变。基线最近一次隔离回归记录为 540 项 Python 测试、12 项前端测试通过,静态/格式检查、TypeScript 与 Vue 构建通过;使用临时 SQLite、替身模型/Embedding 和测试 MCP。该记录不代表本次重新跑过,也不证明真实供应商、远程 PostgreSQL、Docker/NFS/gVisor 已完成本轮联调。
复验命令、安全范围、环境限制见部署运维文档。常见能力的真实验收证据应分开记录:协议替身测试、真实供应商调用、容器执行、共享卷多机探测、故障恢复测试不能互相替代。
10. 后续演进顺序
| 顺序 | 工作 | 完成判据 |
|---|---|---|
| 1 | 固化契约与数据边界 | 发布连接身份保护、API/类型契约检查、Repository/CheckpointStore 收口,兼容旧数据 |
| 2 | 执行环境真实验证 | 非 root Docker、技能/托管 MCP、NFS/NAS 锁与断连恢复的独立环境验收 |
| 3 | 补齐运行模块 | 统一限额、可替换子任务调度器、资源来源与撤销过滤、工具大结果按需回查 |
| 4 | 可持久调度与集群 | Run 归属、租约/fencing、消息重复投递、取消/接管与清理协议;再允许多 Worker |
| 5 | 用户扩展与长期记忆 | 隔离 Hook Worker、版本化扩展管理;独立 MemoryService 的提取/授权/撤销 |
业务 Wiki 的新增形态暂缓;现有 RAG 作为能力适配器继续独立于 Loop。是否新增文件型知识阅读,应在后续需求明确后设计,不借本次整理扩大实现范围。