LearnGraph 开发者文档
MVP · 当前代码
Developer platform

理解 LearnGraph
从一条真实调用链开始

LearnGraph 是一个目标驱动、证据驱动的学习图谱智能体。本页描述当前仓库中可验证的架构边界, 以及 Agent、Tools、Skills、MCP、沙箱、记忆和系统提示词如何协同工作。

G Goal 结构化目标
R Representation 可审核图谱
E Evidence 可追溯证据
M Mastery 掌握度判断
A Action 下一步行动
i
本文档的事实边界

“已注册接口”不等于“外部服务已连通”,“支持 Provider”不等于“当前部署已配置”。 文中始终把代码能力、运行配置和真实远程验收分开描述。

01

Reading guide

实现状态与阅读约定

LearnGraph 仍处于早期开发阶段。开发者文档采用三种状态词,防止将未来设计或配置入口误解为已完成能力。

当前实现

可在路由、服务、仓库或 Provider 适配器中追踪到完整调用链,并有持久化模型支撑。

条件可用

代码已接入,但依赖部署配置、外部凭据、Docker 或远程服务;缺失时应显式返回 unavailable。

设计目标

仅存在于总体架构或设计 TODO 中,不应作为当前 API 行为或验收结论。

事实优先级 设计共识设计 TODO总体架构实现 TODOOpenAPI / 模型 / 代码
02

Quick start

本地启动

根目录脚本负责编排 React/Vite 前端与 FastAPI 后端。默认数据库和对象存储均为本地实现。

PowerShell
# 安装依赖并启动(首次运行)
npm.cmd run dev:install

# 后续联合启动
npm.cmd run dev

# 静态检查、现有测试与生产构建
npm.cmd run check
Webhttp://127.0.0.1:5173
APIhttp://127.0.0.1:8000
OpenAPIhttp://127.0.0.1:8000/docs
Health/api/v1/health
!
默认没有模型回退

未配置模型 Provider 或远程调用失败时,服务必须明确报错。 确定性的本地演示 Provider 仅在 LEARNGRAPH_ENABLE_LOCAL_DEMO_PROVIDER=true 时启用, 不能作为真实验收证据。

03

Architecture

系统架构

当前实现是前后端分离的模块化单体。浏览器只调用 LearnGraph 后端;外部模型、搜索、抓取、研究、Memory、 MCP 和存储都由后端经 Port/Adapter 边界访问。

Client
React 19 · TypeScript · Vite Router · TanStack Query · React Flow · Streamdown
JSON / SSE
Gateway
FastAPI · /api/v1 Bearer Session · Workspace Scope · RBAC / ACL · Error Envelope
typed use cases
Domain
Services + Repositories Goal · Graph · Chat · Evidence · Mastery · Memory
Runtime
Agent + Tool Registry Skills · MCP · Sandbox · Provider Gateway
ports
Facts
SQLAlchemy 2 · SQLite 规范业务事实源
Adapters
Local + Remote Providers Filesystem · HTTP APIs · Docker

后端依赖方向

api / routersservicesrepositories / domain provider portslocal / remote adapters

业务服务不直接依赖厂商 SDK。新增外部能力应先定义或复用 Port,再提供适配器、能力探测和明确失败状态。

来源:backend/app/main.py · backend/app/api/router.py · backend/app/providers/ports/
04

Request gateway

API 网关与请求边界

当前仓库没有独立的网关微服务。FastAPI 的统一 /api/v1 路由层就是应用网关: 它终止认证、解析工作区作用域、校验权限、稳定错误结构,并把请求交给领域服务。

01
ApiClient添加 Bearer、X-Workspace-ID 与请求 ID
02
Router / Schema类型化输入、错误边界、HTTP/SSE 契约
03
Authorization重新校验 Membership、Permission 与资源 ACL
04
Service编排事务、Provider、审计与幂等策略
05
Repository / Port持久化事实或显式调用外部能力

网关职责

身份

正式登录接口签发不透明 Bearer Session;浏览器不持有 Provider Secret。

作用域

X-Workspace-ID 只是请求提示,不能替代服务端授权。

契约

普通资源使用 JSON;Chat 使用可恢复 SSE,但消息与事件仍落库。

失败

Provider unavailable、权限拒绝与输入错误必须保持可区分,禁止伪造成功。

路由域

authdashboardgoalsgraphssessions filesresearchsourcesevidenceexercises memorymcp-skillsprovidersusageplugins componentsmigrationsauditworkflowsandbox
05

Durable facts

持久化与事实源

SQLite 是 MVP 的规范业务事实源。本地文件系统承载默认对象存储和 Markdown Memory 投影, 但文件路径、外部 UUID 或 SSE 事件都不能替代数据库中的稳定业务身份。

保存内容关键边界
SQLAlchemy / SQLite账号、RBAC、Goal、Graph、Session、Evidence、Provider、授权、审计当前规范事实源
Message timelineMessage、MessageVersion、MessagePart、SSE 事件、Provider TraceSSE 只负责传输
Object Storage上传文件、生成产物、内容寻址 Blob默认本地,可经迁移边界切换
Memory projectionWorkspace 隔离的 Markdown 文件树或 Mem0 记录Canonical ID/Revision 仍在 SQLite
i
迁移不是双写

数据库、对象存储和 Memory Provider 切换需要维护锁、预检、校验、切换点与回滚;不能静默双写或降级。

06

Capability adapters

Provider 层

Provider 是外部能力网关,不是业务事实源。业务层依赖 Protocol 定义的 Port; 适配器负责协议差异、探测、超时、限额和 Provider Trace。

ModelOpenAI Responses · OpenAI-compatible Chat · Anthropic Messages · DeepSeek统一为 ProviderChatMessage / ProviderStreamEvent
SearchSearXNG · Cloud / AnySearch搜索不可用时显式失败,不生成来源
FetchCrawl4AI HTTP · FirecrawlURL 安全校验、超时和响应结构限制
ResearchDeep Research HTTP独立 Provider,不与普通搜索混淆
MemoryLocal Markdown · Mem0 PlatformProvider Binding 可重建,Stable ID 不变
StorageLocal filesystem · MinIO通过迁移流程切换
SandboxDocker backend无 Docker 时明确 unavailable,不落回宿主执行

模型消息抽象

ProviderChatMessage 保留 system/user/assistant/tool 角色、tool calls、reasoning summary 与协议原生 response items。原生 continuation state 作为不透明数据保存,不能被业务层臆造或跨协议消费。

来源:backend/app/providers/ports/model.py · backend/app/providers/remote/
07

Agent runtime

Agent 执行循环

Agent 模式是在持久化 Chat Session 上运行的受控工具循环。模型决定是否发起工具调用, 但工具可见性、授权、执行、结果裁剪、审计和持久化均由 LearnGraph 控制。

Agentmodel turn
1编译上下文system + scope + history
2注册工具capability + grant
3流式推理text / reasoning summary
4执行调用validate + audit
5回填结果tool role message
6完成回答persist + SSE

一次 Agent Turn

  1. 01
    持久化用户输入

    用户消息、附件引用、所选节点与 Session 绑定先成为可追踪事实。

  2. 02
    构建授权上下文

    只加入本次允许访问的节点、文件、选区、Memory 和 Skill 指令;文档片段被标记为不可信参考数据。

  3. 03
    计算工具注册表

    内置工具按角色开放;声明式 Skill 与 MCP 还必须具有 enabled 状态和持久 always Grant。

  4. 04
    调用模型 Provider

    适配器把结构化消息与 JSON Schema 工具定义发送给已配置远程模型。

  5. 05
    受控执行 Tool Call

    服务端解析参数、重新校验作用域与授权、执行领域服务或 Provider,并保存 Invocation / Audit。

  6. 06
    继续或结束

    工具结果作为 tool 消息回填;模型可继续调用工具,最终文本和所有 MessagePart 一并持久化。

!
Agent 不能直接修改正式目标图谱

lg_graph_propose_change 只创建可审核的 GraphChangeSet 与组件, 不改变已发布图谱;Evidence 由 Agent 写入时保持 pending,不会直接授予 mastery。

08

Prompt compiler

系统提示词策略

提示词由多个 system message 分层编译,而不是把所有内容拼成无法审计的单块文本。 核心规则稳定,工作区风格和本次授权上下文动态注入。

优先级 1
Core Instructions

身份、真实性、安全、隐私、指令优先级与通用回答行为。

优先级 2
Response Style

基础风格 + 温和、热情、标题、Emoji、详细度五个离散特征。

优先级 3
Mode & Tool Policy

普通 Chat 禁止工具;Agent 模式允许使用本次注册的函数。

优先级 4
Agent Stream Guidance

工具前给简短可见说明,工具后可更新进展,结束时给完整答案。

优先级 5
Authorized Context

选中节点、附件、文档选区、Memory 与最多 8 个已授权 Skill 包。

优先级 6
Durable History + User Turn

协议有效的历史消息、必要的上下文压缩,以及当前用户输入。

风格策略

工作区可选择 defaultprofessionalfriendlycandidefficientexploratoryquirkycynical。 五个附加特征均使用 -2…2。风格只控制表达方式,不得改变事实、工具权限或用户当前明确格式。

提示词注入防线

参考数据降权

文档与网页摘录明确视为不可信参考,不作为系统指令。

授权上下文

只注入当前用户和工作区有权读取、且与本轮相关的内容。

Skill 限额

单包最多 8,000 字符、每轮最多 8 个;脚本不会因提示词自动执行。

上下文压缩

接近窗口阈值时保留协议有效的最近后缀,旧事务用持久摘要表达。

来源:backend/app/prompts/fragments.py · backend/app/prompts/compiler.py · backend/app/services/chat.py
09

Tool registry

Tool 注册与调用

Tool 是给模型看的 JSON Schema 函数定义与服务端执行器的配对。注册本身无副作用; 只有模型输出 tool call 后才进入参数校验、权限检查和执行。

工具族代表能力写入边界
会话与时间检索 Session 片段、读取历史区段、读取当前时区时间只读
图谱读取目标/能力图谱、候选节点更新、提出图谱变更正式图谱须用户审核
学习闭环路线读取/重规划、行动计划、Mastery 读取、Evidence 草稿Evidence 只写 pending
记忆检索会话证据、读取记忆证据、提出 Memory Draft草稿与正式记忆分离
Provider列 Provider/模型、能力查询、配置与 Secret 轮换管理写入要求 workspace.manage
Websearch_webparallel_web_research仅在 SearchProvider 可用时注册
内容产物图片生成、可信组件、Magic Card、沙箱文件 Artifact不允许任意代码进入宿主 DOM
扩展声明式 Skill、已授权 MCP 工具沿用各自 Grant 与 Invocation 边界

调用结果

执行器返回规范化的成功或失败对象,并可附带来源、Artifact、Extension Invocation ID、Sandbox Session ID 等安全元数据。意外异常不会把 SQL、HTTP、Provider 或沙箱实现细节泄露给模型;权威堆栈保留在服务端日志。

Normalized tool result
{
  "status": "completed",
  "data": { "…": "domain result" },
  "meta": {
    "extension_invocation_id": "…",
    "source_count": 3
  }
}
10

Instruction & workflow extensions

Skills

LearnGraph 区分两类 Skill。它们的安装、授权和运行语义不同,不能把文件包中的脚本当作自动 Tool。

Agent Skill Package

指令型文件包

  • 至少包含 SKILL.md
  • 启用且具有 always Grant 后按需注入 system context
  • scripts/* 不注册为函数工具
  • 脚本仅可通过 Docker 无网 sandbox-run 显式试运行
  • 文件按 ContentBlob 内容寻址保存,禁止绝对路径与 ..
Declarative Skill

声明式工作流

  • Manifest 类型为 declarative_reviewdeclarative_workflow
  • 精确声明受审计的内置领域工具与最小权限
  • 启用且持久授权后可注册为 Agent function tool
  • 不允许 Shell、Python、JavaScript 或用户可执行代码进入宿主进程
  • 图谱写入只产生候选修订;Evidence 保持 pending

生命周期

authorization_requiredready_once / enabledauthorization_required 来源、版本、Manifest、权限或内容哈希变化会废止旧 Grant

Skill Market 只提供系统级预缓存卡片;安装后才复制进工作区授权边界。本机 Skill 探测默认关闭, 只适用于前后端同机环境。翻译是按 content hash、locale 与 model 缓存的查看层,不修改源文件。

来源:backend/docs/mcp-skills.md · backend/app/services/mcp_skills.py · backend/app/services/skill_package.py
11

Model Context Protocol

MCP

MCP Server 是工作区级外部工具目录。运行时不会信任注册表中的旧描述: 每次调用前重新发现能力并保存不可变 CapabilitySnapshot。

01Register端点、来源、认证引用
02Discoverinitialize + tools/list
03Authorize身份 + 快照 + 权限指纹
04Invoketools/call + audit

Transport 与网络边界

streamable_http

真实执行 JSON-RPC 初始化、工具发现与调用;公网只允许 HTTPS,本机 HTTP 仅限 loopback。

stdio

当前没有隔离命令运行器,明确返回 available=false;不会在宿主启动任意命令。

Bearer

静态 Token 只保存为加密 Secret 引用,API 响应只返回掩码。

OAuth

授权码、动态客户端注册与刷新令牌流程尚未实现,不能宣称可用。

重授权规则

服务身份、工具、资源、Prompt、Schema 或注解变化会改变快照哈希;来源、版本、端点、认证指纹、 Manifest、权限或运行边界变化会改变授权哈希。任一变化都使旧 Grant 失效。 allow_once 在调用前消费,即使远程执行失败也不会恢复。

i
Agent 可见性比“注册过”更严格

只有当前快照 enabled 且具有明确持久 always Grant 的 MCP 工具才进入 Agent Tool Registry。

12

Isolated execution

沙箱

沙箱是 Docker-only、默认断网、按「聊天会话 × 属主用户」隔离的代码与文件执行边界。 宿主机永远不是 fallback:Docker、镜像 digest 或配置缺失时 probe 返回明确 unavailable,不会退化执行。 系统内有两条互相独立的执行路径——sandbox-policy-v1 固定任务(只能跑内置 runner 检查已上传文件)与 sandbox-agent-v1 Agent 工作区(模型写文件、跑 .py/.js 脚本)——共用同一张 SandboxSession 表与容器后端,但按 policy_revision 严格互斥。

LearnGraph host
SandboxAgentWorkspaceServiceargv 策略 · 授权 · 配额 · 审计 · 计费桥(ASR)· Artifact
Docker boundary · network=none · read-only rootfs · uid 65532
Unified Runner 镜像 Python 3.12 + Node + Chromium + ffmpeg · digest pin
/workspace bind mount inputs / work / outputs · 用户×会话隔离

容器硬化基线

网络与文件系统

network_mode=none、根文件系统只读、/tmp 为 noexec/nosuid tmpfs(64 MiB);容器以 sleep infinity 常驻,命令经 exec 注入。

身份与能力

非 root(uid/gid 65532)、cap_drop=ALLno-new-privileges、默认拒绝的 seccomp 白名单(显式省略 io_uring)。

镜像 digest pin

镜像必须以 @sha256: 固定;未 pin 时 probe 直接不可用。基础镜像同样按 digest 固定,Bootstrap 冒烟通过后才原子落盘。

执行环境净化

Python 强制 -I -B 隔离模式;PIP_NO_INDEX=1、代理变量置空;前端工具链预装在镜像 /node_modules,零下载、不占工作区配额。

生命周期与双 TTL

状态机 · services/sandbox.py + core/scheduler.py
CREATED → COLD → STARTING → RUNNING → WARM_IDLE → (COLD | EXPIRED)
# STARTING 先落库占位再调 Docker,容量统计含 STARTING/RUNNING/WARM_IDLE
# 超时 kill:容器被丢弃回 COLD;工作区数据保留
# 清理调度器对 STARTING/RUNNING 会话不动 bind mount(看门狗保护)
维度闲置 TTL绝对 TTL到期动作
容器(runtime)180s1800s删除容器,会话降级 COLD(cool-down,工作区保留)
工作区(workspace)1800s(活动可外推)86400s(创建即定死,不可外推)删容器 + 二次逃逸校验后 rmtree,会话 EXPIRED

资源护栏

180sWall time
2 CPUCPU 配额
2 GiBMemory(禁 swap)
512PIDs(含线程)
256 MiBWorkspace disk
5 MiBOutput 截断

磁盘配额是双机制:内核级 fsize ulimit 限单文件 + 宿主侧聚合统计在写入前后与执行轮询每一拍检查。 宿主层另有保护:单用户 2 个活跃容器、部署级 20 个、宿主内存分配 ≤70%、CPU ≤80%、保留磁盘 ≥20 GiB、 单用户留存工作区 ≤10 个。默认值见 backend/app/core/config.pyLEARNGRAPH_SANDBOX_*)。

一次 Agent 命令的执行管线

  1. 01
    argv 策略

    解释器白名单(python/node),禁止 -c/-m/-e/--eval/-p/-i 内联代码;入口必须是工作区内相对 .py/.js 文件;cwd 只能是 .;参数数与单参字节受限。

  2. 02
    破坏性预授权

    rm / dd / mkfs / Remove-Item 等命令按路径逐一核对会话级 Grant(仅 work/ 子树,TTL 60s–24h);缺失则 403 授权挑战经 SSE 弹窗回传。

  3. 03
    幂等与审计

    Idempotency-Key 去重;持久化 SandboxAgentCommand 只存 argv 摘要与脱敏副本,stdout/stderr 落库前同样脱敏。

  4. 04
    容量与容器

    进程锁 + 跨进程文件锁下校验用户/宿主容量,先提交 STARTING 占位再 docker create;失败回滚 COLD。

  5. 05
    快照 → 执行 → 恢复

    执行前对工作区做 inode 级快照;100ms 粒度轮询超时与聚合配额;执行后凡未授权的删除一律从快照恢复并抛授权挑战——argv 拦不住的 shutil.rmtree 类软删除由此兜底。

  6. 06
    结果与 SSE

    exit code / 超时 / 截断 / 延迟落库;结果转成 sandbox_status / sandbox_artifact MessagePart 流式呈现。

双层存储:物理工作区 + 逻辑工作区

物理层(bind mount)

宿主 {root}/{user}/{session} 挂载为容器 /workspace;随沙箱会话过期被清理。

逻辑层(内容寻址)

SessionWorkspaceEntry + ContentBlob(sha256 去重、引用计数)随聊天会话存续。写入双写两层、读取优先逻辑层——Docker 不可用时附件读取与文件列举依然可用

Agent 工具面

六个工具(sandbox_write_file / read_file / list_files / exec / transcribe_audio / publish_file) 仅在 workspace.manage 权限且 SANDBOX_AGENT_ENABLED 时注入;chat_session_id 由服务端注入,模型不可伪造。Agent 模式开流前先过 agent_sandbox_readiness() 就绪契约, 不可用则整轮拒绝并给出中文修复步骤。音频转写是宿主侧桥:容器不联网、不接触凭据,ASR 调用在宿主完成计费与执行后回写工作区。

API 面

端点组权限职责
/sandbox/profiles · /bootstrap* · /agent/readiness成员 / workspace.write能力探测、一键镜像构建(进度/日志)、Agent 就绪契约
/sandbox/agent/sessions · /agent/commands · /agent/files/*workspace.manageAgent 会话、命令执行(幂等)、文件读写列举
/sandbox/tasks* · /sessions*成员固定 runner 任务(file_inspect / extract_inert_text)、会话查询与手动清理
/sandbox/workspace/* · /authorizations*workspace.manage / workspace.write逻辑工作区条目与发布;破坏性删除 Grant 的创建与吊销
!
已知权衡与占位(阅读代码前请先了解)

seccomp 相对 Docker 默认档有意放行 clone/unshare/chroot 以支持 Chromium 的 user-namespace 沙箱;删除 Grant 在 TTL 窗口内可重复使用(非一次性); runtime_kind 的两个取值已解析到同一镜像(python-node-browser 已标记废弃); network_policy.allowed_hosts、任务队列(SANDBOX_QUEUED_TASKS_PER_USER)与 SANDBOX_TASK_TTL_SECONDS 为占位,当前执行全部同步阻塞。 沙箱验收依赖需要真实 Docker 的 backend/scripts/verify_sandbox_runtime.py 端到端脚本。

i
三个不同的 “sandbox”

本节指 Docker 执行沙箱;前端另有 iframe 生成式组件预览(sandbox-artifact.tsx,严格 CSP、connect-src 'none'),以及 MessagePart.type="sandbox" 这一混合渲染类型。三者互不相同,勿混用。

来源:backend/app/services/sandbox.py · backend/app/services/sandbox_authz.py · backend/app/services/session_workspace.py · backend/app/providers/remote/sandbox.py · backend/sandbox/
13

Durable memory

记忆系统

记忆系统是一套 Goal-Scoped Memory Graph:Canonical 事实存 SQLite,Provider 只做可重建投影。 每条记忆由 LearnGraph 生成稳定 lgm_<uuid>;Provider 路径或 Mem0 UUID 只是 Binding。 基线召回不依赖任何外部模型;抽取、语义检索、会话摘要三条增强管线按工作区独立开启。

Canonical SQLite ID · Revision · Hash · Journal · Policy
verified projection →
Active Provider Markdown 或 Mem0 Binding · provider_epoch · read-back hash

记忆类型注册表

九种类型集中定义在 domain/memory_types.py,每种声明默认知识作用域、跨作用域合并策略与衰减策略。 权威业务状态(掌握分、路线版本、存储路径等)禁止写入记忆正文,创建时会被 422 拒绝。

类型默认作用域合并策略衰减
semantic_memory 语义事实workspaceUNIONSLOW
learning_preference 学习偏好workspaceINHERIT_UNTIL_OVERRIDENONE
teacher_focus 教学侧重goalUNIONGOAL_LIFECYCLE
misconception 错误概念nodeLOCAL_ONLYFAST(验证驱动)
strategy_effectiveness 策略有效性goalKEYED_MERGESLOW
decision 决定goalAPPENDSLOW
goal_constraint 目标约束goalOVERRIDEGOAL_LIFECYCLE
ai_observation AI 观察sessionLOCAL_ONLYFAST(需确认)
event_summary 事件总结workspaceAPPENDSLOW

召回管线(每轮对话)

  1. 01
    策略闸门

    工作区总开关与 Session 开关必须同时开启,否则返回空包;Agent 的记忆/跨会话检索工具随同一开关一起消失,关记忆等于真隔离。

  2. 02
    候选筛选

    只取 active 且位于 hot / recent / topics 区的记录;archive 区不参与召回。会话命名空间只见本 Session。

  3. 03
    作用域动态继承

    子作用域不复制父记忆,查询时按 workspace → goal → node 组装有效视图;当前消息与选中节点作为召回上下文传入。

  4. 04
    打分与语义放大

    启发式得分乘上可选的 Embedding 余弦相似度放大项;Embedding 未配置、失败或预算耗尽时静默退回纯启发式。

  5. 05
    类型感知合并

    OVERRIDE / INHERIT_UNTIL_OVERRIDE 只保留最近作用域赢家并记录冲突;LOCAL_ONLY 不跨界。

  6. 06
    Top-8 + Token 预算

    注入块受输入预算约 8%(400–3000 tokens,CJK 感知估算)约束,低排名条目被丢弃而非溢出;只有实际注入的记忆才累计访问强化。

打分公式 · services/memory.py
strength = importance + 0.25·ln(1+access) + 0.30·confirm + 0.20·success
           + goal_bonus − decay_rate·elapsed_days − conflict_penalty
score    = strength × proximity × confidence × zone_factor × boost
# proximity: node 1.0 / goal 0.85 / session 0.8 / workspace 0.55
# zone_factor: hot 1.0 / recent 0.9 / topics 0.8;resolved 误区降至 0.15
# 配置 Embedding 后: score ×= 1 + weight·max(cosine, 0)

草稿流:唯一的自动写入通道

Agent 与后台抽取都不能直写长期记忆,一切变更先落 MemoryDraft(八种操作)。 CREATE 在置信度 ≥ 0.75 且类型不要求确认时可自动提交;UPDATE 一律人工审核; SUPERSEDE 会创建新记忆并以 supersedes_id 记录血缘,旧记录移入 archive 冷区留作审计。

写入与删除语义

  1. 01
    Canonical mutation

    创建新 Revision、Provider-neutral Journal 与内容 Hash;更新走 expected_revision 乐观锁,冲突返回 409。

  2. 02
    Provider projection

    写入 Active Provider,并按稳定 ID + Revision 精确回读校验。

  3. 03
    Commit binding

    只有回读 Hash 一致才提交 Binding 与业务事务。

  4. 04
    Recoverable delete

    删除后正文以每记忆独立密钥加密保留 30 分钟,密钥落在 SQLite 之外;Revision 正文立即清空。

  5. 05
    Cryptographic destruction

    窗口到期由保留期调度器销毁内容密钥与恢复密文;删除 Journal 元数据最长保留 7 天。

可选增强管线

配置集中在 WorkspaceSetting memory.enhancement,三条管线互相独立、默认关闭; 全部调用计入 usage_events(feature 分别为 memory_extractionmemory_embeddingcontext_summarization),常见模型自动落价。

自动记忆抽取(Dreaming 式)

后台调度器在会话安静(默认 180s)后,用独立配置的模型从新增轮次抽取候选记忆; 游标存 memory_extraction_states,按 content hash 去重,严格走草稿流。预算耗尽时跳过且不推进游标。

语义检索插件(Embedding)

任意 OpenAI 兼容 /embeddings 端点(如 Qwen text-embedding-v4); 向量缓存于 memory_embeddings 并在召回时懒回填,支持一键重建索引。移除配置即恢复无 Embedding 行为。

会话滚动摘要

长会话较早内容由模型滚动压缩为 ContextSummary kind='model'; 聊天压缩优先复用覆盖前缀,仅对未覆盖尾部降级为机械截断。模型留空时复用抽取模型。热路径零额外延迟。

注入预览(透明度)

GET /memory/package 返回某 Session 下一轮实际注入的记忆清单、得分、作用域冲突与完整 prompt 文本; 前端记忆页提供「AI 眼中的我」一键预览。

API 面

端点组职责
/memory · /{id}/revisions · /{id}/journal · /{id}/bindingsCRUD、版本历史与回滚、审计日志、Provider Binding
/memory/drafts · /drafts/{id}/decision草稿提交与 commit / reject 审核
/memory/policy · /memory/package工作区 / Session 双开关;注入预览
/memory/enhancement · /reindex · /extract/{sid} · /summarize/{sid}增强管线配置、向量重建、手动抽取 / 摘要触发
/memory/export · /maintenance/purge-expiredMarkdown ZIP 导出(含 manifest 哈希);保留期清理
!
切换 Provider 必须迁移

记录属于另一 Provider 世代时,Mutation 返回 409 memory_provider_migration_required;不会静默双写到新 Provider。

来源:backend/app/services/memory.py · backend/app/services/memory_enhancement.py · backend/app/domain/memory_types.py · backend/tests/test_memory_subsystem.py
14

Streaming contract

消息与 SSE

SSE 是传输层,不是事实源。Session、Message、MessageVersion、MessagePart 与流事件均持久化, 从而支持刷新读取、断点续传、分支、版本比较和 Provider 协议续接。

user_message持久化输入
reasoning_delta仅 Provider 暴露的 summary
tool_call参数与调用状态
tool_result规范化结果 / Artifact
text_delta可见回答
completed最终版本与用量

前端以 Message Part 渲染文本、来源、推理摘要、工具状态、可信组件和沙箱 Artifact。 未知组件安全降级为数据预览,不注入任意 HTML、脚本或 React 代码。

15

Trusted components

可信组件

可信组件是助手消息流里的声明式 UI 卡片(选择题、填空、天气卡、指标卡、图片框等)。它用 JSON Schema 声明数据面,而不是把任意 HTML/React 注入宿主 DOM。Agent 可通过 canvas_emit_trusted_component 发布内置组件,也可注册并授权第三方组件 Manifest 再发布。所有写操作经后端 Schema 守卫、哈希与审计, 前端对未注册或未通过 Schema 的组件安全降级为 JSON 预览,绝不执行脚本。

Channel A · 声明式

内置目录 · 宿主 DOM

  • 8 个内置 component_typeweather_cardmetric_cardoption_groupsingle_choicemultiple_choicefill_blankshort_answer_tableimage_frame
  • 渲染器 trusted-bundle,由前端编译好的 React 组件在宿主 DOM 直接渲染
  • 端到端可用,是 Agent 默认的表单 / 展示通道
  • 权限由系统白名单固定,工作区不可改写
Channel B · 沙箱

第三方 Manifest · 隔离浏览器

  • 任意 component_id,经工作区导入 Manifest 注册
  • 渲染器固定为 sandbox,结果以 sandbox_artifact 交付
  • 条件可用:依赖未配置的隔离浏览器渲染器,缺失时 runtime_status=unavailable 安全降级
  • 需工作区显式授权后才可发布或生成 Artifact

协议生命周期

registerhealth_checkauthorize(+enable)artifact / event_validate 版本、Schema、权限或包哈希变化会废止旧授权,需重新授权;同一 version 的 Manifest 不可替换。
  1. 01
    register

    提交完整 Manifest,服务端做静态 Schema 守卫、签名记录与 example_data 校验,落 Plugin 与 ManifestVersion。

  2. 02
    health_check

    对当前 Manifest 跑 JSON Schema 校验(render 检查在隔离浏览器未配置时标记 unavailable,不阻断)。

  3. 03
    authorize + enable

    工作区对当前版本 + 权限指纹授权并启用插件;内置组件由系统固定,工作区不可改。

  4. 04
    artifact / event_validate

    用授权后的组件把 data 校验成 Artifact,或把用户事件按 event_schema 校验后再处理。发布前由 assert_can_enable 校验 Manifest、授权与 health 全部当前。

Manifest 字段规范

component_id

全局唯一标识,^[A-Za-z0-9][A-Za-z0-9._-]{1,119}$;内置 8 个 ID 与 source=builtin 保留,第三方不可占用。

version

SemVer,max 40 字符;同一 version 落库后不可替换。

display_name

展示名,1–160 字符。

renderer

第三方导入固定为 sandboxtrusted-bundle 仅系统内置可用。

source

来源标签,1–160 字符;builtin 为系统保留值。

package_hash

组件包 sha256(64 位十六进制),由发布方计算并声明;服务端标记 declared_unverified

signature

可选签名声明(ed25519ecdsa-p256-sha256);当前无信任锚,仅记录为 unverified

data_schema

组件数据的 JSON Schema,必须顶层 type=objectadditionalProperties=false

event_schema

用户事件 JSON Schema,同样要求顶层闭合对象。

permissions

network_domains(精确 DNS 主机,禁通配/带 scheme)、file_readclipboard_writemessage_actions(小写标识)。

size_limits

min_height ≥40、max_height ≤2000,且 min ≤ max。

example_data

必须通过自身 data_schema 校验的最小示例。

skill_triggers

最多 64 条触发词,可选。

Schema 安全约束

闭合对象

data_schema / event_schema 顶层必须 type=objectadditionalProperties=false

禁止可执行内容

字段名不得为 htmlraw_htmljavascriptscriptsrcdocreact_codedangerouslysetinnerhtml;实例字符串不得含 <scriptjavascript:<iframesrcdoc= 等标记。

禁止外部引用

Schema 不得用非 #/ 开头的 $ref;不得声明 contentMediaTypetext/htmlapplication/javascripttext/javascript

禁正则执行

Schema 不得含 pattern 字段(不执行调用方提供的正则)。

体量上限

单 Schema ≤64KB、单实例 ≤64KB、深度 ≤16、节点 ≤1000。

禁 null

可选字段省略即可,不要传 null;后端对内置 props 会做 null 剥离。

内置组件最小合法 props

option_group / single_choice / multiple_choice
{
  "title": "你更希望怎样验收这次学习?",
  "description": "单选一项后继续",
  "options": [
    { "id": "project", "label": "完成一个小项目" },
    { "id": "explain", "label": "能够清楚讲解" }
  ],
  "allow_custom": true,
  "allow_skip": true,
  "submit_label": "确认并继续"
}
fill_blank
{
  "title": "请补全 ACID 中的 A",
  "prompt": "ACID 中的 A 代表 ____",
  "placeholder": "Atomicity / 原子性",
  "multiline": false,
  "submit_label": "提交",
  "blank_ids": ["answer"]
}
short_answer_table
{
  "title": "简答题",
  "columns": ["问题", "你的回答"],
  "rows": [["为什么需要索引?", ""]]
}
weather_card
{
  "title": "杭州明日天气",
  "location": "杭州",
  "condition": "多云",
  "temperature_c": 27,
  "high_c": 29,
  "low_c": 21,
  "summary": "适合户外轻量复习",
  "unit": "C",
  "actions": [
    { "id": "create_plan", "label": "生成明日学习计划", "event": "create_plan" }
  ]
}
metric_card
{
  "title": "今日学习指标",
  "description": "来自当前目标进度",
  "metrics": [
    { "id": "mastery", "label": "掌握度", "value": "62%", "hint": "近 7 日" },
    { "id": "reviews", "label": "待复习", "value": 3 }
  ]
}
image_frame
{
  "title": "示意图",
  "alt": "B+ 树结构示意",
  "status": "placeholder"
}

完整第三方 Manifest 示例

以下是一个自定义 quiz_card 的完整 Manifest,可直接用于 POST /api/v1/plugins/components 或智能体的 component_register_manifest 工具。它满足全部 Schema 安全约束:顶层闭合对象、无禁用字段、 无 pattern / 外部 $refexample_data 能通过自身 data_schema

quiz_card Manifest · POST /plugins/components
{
  "component_id": "acme.quiz_card",
  "version": "1.0.0",
  "display_name": "Quiz Card",
  "renderer": "sandbox",
  "author": "Acme",
  "source": "acme-marketplace",
  "package_hash": "0000000000000000000000000000000000000000000000000000000000000000",
  "compatible_learngraph": { "minimum": "0.1.0" },
  "uninstall_behavior": "retain_data",
  "data_schema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["question", "answer"],
    "properties": {
      "title": { "type": "string", "maxLength": 500 },
      "question": { "type": "string", "maxLength": 2000 },
      "answer": { "type": "string", "maxLength": 2000 },
      "hint": { "type": "string", "maxLength": 500 }
    }
  },
  "event_schema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["type", "value"],
    "properties": {
      "type": { "type": "string", "enum": ["submit", "change", "select"] },
      "value": {
        "oneOf": [
          { "type": "string", "maxLength": 10000 },
          { "type": "array", "maxItems": 100, "items": { "type": "string", "maxLength": 1000 } }
        ]
      }
    }
  },
  "permissions": {
    "network_domains": [],
    "file_read": false,
    "clipboard_write": false,
    "message_actions": ["submit"]
  },
  "size_limits": { "min_height": 80, "max_height": 480 },
  "skill_triggers": [],
  "example_data": {
    "title": "练习",
    "question": "2 + 2 = ?",
    "answer": "4",
    "hint": "十以内加法"
  }
}

事件协议

用户在卡片上的交互以事件形式回传,按组件 Manifest 的 event_schema 校验。内置组件的默认 event_schema 要求 typesubmit / change / select) 与 value(字符串或字符串数组)。allowed_events 限定可触发的事件名, 选项类默认 ["submit"]weather_card/metric_cardactions[].event 推导,image_frame 默认为空。

智能体创建并应用

Agent 在拥有 workspace.manage 权限时,可直接在对话里创建并应用可信组件,无需切到设置页:

  1. 01
    component_register_manifest

    提交第三方 Manifest,服务端做静态与健康检查并落审计;内置 ID 被拒绝。

  2. 02
    component_authorize

    对刚注册的 plugin_id + manifest_version_id 授权当前工作区并启用插件(enable=false 可仅授权不启用)。

  3. 03
    component_list

    查询已注册组件及其授权/启用状态,决定下一步是授权还是发布。

  4. 04
    canvas_emit_trusted_component

    对自定义 component_type 传其 component_id 发布;已授权则按 sandbox_artifact 交付。

!
第三方组件渲染是条件可用

第三方组件渲染器固定为 sandbox,依赖隔离浏览器渲染器;当前未配置,发布会以 sandbox_artifact 安全降级(runtime_status=unavailable)交付,不会把任意代码注入宿主 DOM。 内置 8 类组件不受此限制,端到端可用。

API 面

端点组权限职责
POST /plugins/componentsworkspace.write导入并校验第三方 Manifest(注册)
GET /{plugin_id}/manifests · /authorizations · /checksworkspace.write列出版本、授权与检查记录
POST /{plugin_id}/authorizations · /authorizations/revokeworkspace.write授权或撤销当前工作区
POST /{plugin_id}/checksworkspace.write触发 health / render 检查
POST /{plugin_id}/artifacts已授权按授权边界生成受控 Artifact
POST /{plugin_id}/events/validate已授权按 event_schema 校验用户事件
i
Agent 工具与 HTTP 复用同一服务

component_register_manifest / component_authorize / component_list 复用 ComponentService,与上方 HTTP 端点共享 Schema 守卫、哈希、审计与重授权逻辑; Agent 工具额外要求 workspace.manage

来源:backend/app/domain/schemas/components.py · backend/app/services/components.py · backend/app/services/canvas_cards.py · frontend/src/components/chat/trusted-component-renderer.tsx · backend/app/skills/canvas_emit_trusted_component/SKILL.md
16

Security model

安全与授权

安全边界贯穿路由、服务、扩展授权、Provider Secret、沙箱和输出渲染,而不是单独依赖前端隐藏按钮。

01Workspace scope

所有资源查询由后端重新校验 Membership、Permission 与 ACL;跨工作区 ID 返回不可枚举错误。

02Secret isolation

Provider Key 由后端加密保存,不进入浏览器、日志、SSE、审计或导出。

03Exact grants

MCP/Skill 的权限集合必须与服务端推导的最小集合完全一致,少一项或多一项都拒绝。

04Human review

正式目标图谱的重要变更、删除影响与高风险执行保留用户确认。

05No silent fallback

远程 Provider、Docker 或 Transport 失败时保持失败事实,不落回 mock、宿主执行或硬编码结果。

06Audit trail

授权、拒绝、撤销、失败、超时、大小阻断和成功调用均记录工作区审计。

17

Repository map

代码地图

frontend/src/main.tsxReact 入口
frontend/src/App.tsx页面路由总表
frontend/src/api/client.ts认证、工作区头、JSON/SSE 客户端
frontend/src/features/按业务领域组织页面与交互
backend/app/main.pyFastAPI 生命周期与调度器
backend/app/api/routers/HTTP/SSE 契约与依赖边界
backend/app/services/chat.pyChat、上下文、Agent 循环与持久化
backend/app/services/agent_runtime.py工具定义、注册与执行分派
backend/app/services/mcp_skills.pyMCP/Skill 生命周期、Grant 与 Invocation
backend/app/services/sandbox.py沙箱任务与 Agent Workspace
backend/app/prompts/系统提示词片段与风格编译器
backend/app/repositories/工作区作用域数据访问
backend/app/providers/ports/外部能力契约
backend/app/providers/local|remote/适配器实现
backend/app/domain/models.py核心持久化模型
backend/app/domain/schemas/API 输入输出 Schema
18

Extension guide

扩展指南

新增 Provider

  1. 01
    定义 Port

    优先复用现有 Protocol;不要让业务 Service 依赖厂商 SDK。

  2. 02
    实现 Adapter

    显式建模可用性、超时、响应校验、远程能力和安全诊断。

  3. 03
    接入 Catalog / Probe

    配置保存后执行真实探测,失败保持 disabled。

  4. 04
    记录 Trace / Usage

    保存 Provider ID、请求标识、用量与安全错误分类。

  5. 05
    真实验收

    用部署方明确配置的远程服务验证,缺凭据时标记未完成。

新增 Agent Tool

  1. 01
    从领域用例开始

    Tool 只调用现有 Service 或受控 Port,不直接访问数据库句柄。

  2. 02
    声明严格 Schema

    限制字段、长度、枚举与 additionalProperties。

  3. 03
    确定授权与副作用

    按用户角色、工作区、资源范围与是否需二次确认注册。

  4. 04
    规范化结果

    裁剪大小、脱敏错误、记录 Invocation / Audit,并返回可追踪来源。

  5. 05
    验证完整循环

    真实模型发起调用、真实服务执行、刷新后仍可读取结果。

19

Verification

验证与完成定义

“现有测试通过”不等于业务闭环已完成。重要变更需要同时验证可见结果、后端事实和一个高风险失败/恢复边界。

Verification commands
# 常规检查(不自动包含 E2E 与真实远程 Provider)
npm.cmd run check

# 真实浏览器 E2E
npm.cmd --prefix frontend run test:e2e

# 已配置真实远程模型后
.\scripts\verify-real-provider.ps1
从真实目标到可追溯成长

保持来源、权限、事务、审计和用户审核边界一致。

已复制到剪贴板