pChronicle 产品架构设计¶
| 项目 | 内容 |
|---|---|
| 状态 | Current Product Boundary |
| 文档层级 | 产品边界、命令树规范与参数概要 |
| 目标读者 | Agent 平台工程师、训练数据工程师、CLI/服务端/存储开发者 |
| 目标入口 | 独立 pchronicle CLI、pChronicle Core、只读 Warehouse API 与 Web |
| 相关设计 | Dataset Catalog · 轨迹存储 · Storyline 三表 Lance · Ownership RFC |
本文定义 pChronicle 当前的产品边界、核心模型和交互契约。完整 flags、wire schema、物理布局与 索引算法由详细设计规定;公共命令和 HTTP 路由必须与当前实现一致,未实现能力不作为预留命令出现。
当前可用命令以 pchronicle 命令参考和二进制 --help 为准。
截至本文更新时,公共产品面如下:
| 产品能力 | 当前状态 |
|---|---|
ls/status/query/analysis/find/import/export/serve |
已实现并有独立 CLI 合同测试 |
| Query 输出 | table/JSONL/CSV;内置汇总使用 analysis |
| Warehouse 服务 | 强制 loopback、无认证,只提供当前路由表列出的只读 API |
1. 产品定位与边界¶
pChronicle 是 path-first 的 Agent 轨迹数据层:它从本地目录和对象存储发现轨迹,将不同交换 格式投影到统一模型,并提供 SQL、精确定位、导入导出和只读可视化。
| 产品形态 | 用法 | 持久状态 |
|---|---|---|
| 路径直用 | CLI 直接浏览本地目录或 S3 prefix | 无额外状态 |
| 原生 Dataset | create-only import 或 Gateway/native writer 写入 | Dataset 自身版本和 manifest |
| 只读 Warehouse | 静态挂载多个 Dataset,提供 API 与 Web | 配置文件和可重建 cache |
| 本地默认 Warehouse | 单个本地目录作为默认 Dataset 根 | 用户设置中的规范化绝对路径 |
flowchart LR
P[Gateway / Native Writer / Files] --> D[Dataset URI\nlocal or S3]
D --> C[pChronicle Core]
C --> Q[Query / Analysis / Find]
C --> E[Import / Export]
W[Static mounts\nread-only API + Web] --> C
产品遵循以下约束:
- Dataset URI 就是身份;本地和 S3 使用同一资源与查询模型。
- Dataset 可保留复杂目录、多种 Source 和原始相对路径。
- 每次读取报告 Catalog Snapshot,不虚构跨 Source 的全局原子快照。
- 核心不依赖全局 ID 服务、后台 Job、远程 embedding 或可变 Warehouse 状态。
- 共享服务是只读视图,不是数据湖控制面。
以下能力不进入核心产品,只有真实需求证明必要后才单独立项:
| 非核心能力 | 当前替代方案 |
|---|---|
| Dataset 全局 canonical ID、跨 Source 唯一索引 | 使用 Dataset URI、Source 路径和原始 ID 组成完整地址 |
| Dataset 物理删除 | 使用文件系统、对象存储或基础设施工具 |
| lexical/vector/hybrid Search、embedding provider | 使用 SQL 条件或仓库外的检索系统;当前 CLI/API 不提供 Search |
| 动态 Warehouse、服务端写入与后台 Job | 静态配置和同步只读 API |
| pChronicle 内执行用户脚本或 transform | SQL pipeline、pPilot 或独立执行系统 |
| Langfuse/OTLP 兼容入口 | Gateway 或独立 adapter |
| 分布式 SQL、内建用户系统和多租户控制面 | 交由外部基础设施 |
2. 核心模型¶
2.1 Dataset 与 Source¶
Dataset 是经过规范化的本地目录 URI 或对象存储 prefix,也是所有数据命令的资源边界:
- 同一 URI 在 CLI 与 Warehouse 中代表同一个 Dataset;
- Warehouse 挂载名只是别名,不参与身份计算;
- 复制或移动到新 URI 后得到新的 Dataset;
- URI 不得包含 access key、secret、签名 query 或其他凭证。
Source 是 Dataset 中可独立发现、固定版本、查询和诊断的最小物理单元,例如一个 events Lance store、Storyline 三表 store、外部交换文件或同版本分区。每个 Source 至少暴露:
| 字段 | 含义 |
|---|---|
source_path |
Dataset 内的相对逻辑路径 |
format |
物理格式或交换格式 |
snapshot_ref |
Lance/manifest version、对象 version/ETag 或文件指纹 |
read_consistency |
native、conditional 或 fingerprint |
capabilities |
可查询关系、是否可写、是否支持历史版本 |
status |
ready、degraded 或 error,以及脱敏原因 |
pchronicle ls 展示逻辑 Source,只有 --physical 才展开普通文件和对象;Lance fragment 默认
保持折叠。
2.2 轨迹模型与地址¶
Dataset
└── Source
└── Run
└── Trajectory / Session
└── Step
├── Event / Message / Generation
└── Tool Call / Result
- Run 表示一次 Agent 任务执行组,可包含主 Agent、subagent 和重试轨迹。
- Trajectory/Session 表示 Run 中一条有序、连续的交互序列。
- Step 是规范化分析单元;Event 是 append-only 的细粒度采集事实。
- Judgment 是独立于事实层的评测或标注。
pChronicle 原样保留外部 run_id、session_id 和 trace/span ID,不为满足 Dataset 级唯一性而
改写。完整实体地址是:
ID 只要求在 Source 的对应实体类型内可用。输入缺少必需 ID 时,importer 可以生成 Source-local
ID,并在报告中标记。find 未指定 Source 时只做候选发现:一个候选直接返回,多个候选返回
完整地址并要求调用方补充 --source。
2.3 Catalog Snapshot、权威层与 SQL¶
Catalog Snapshot 是一次 query、analysis、find 或 export 实际读取的 Source 集合及其固定
引用。snapshot_id 是 Dataset URI、Source 路径、snapshot_ref 和发现错误的稳定摘要。
| Source | 操作内保证 | 后续可复现性 |
|---|---|---|
| Storyline Lance | 固定 CURRENT generation/table versions |
版本保留期间可复现 |
| events Lance | 固定 manifest revision 和可见 segments | 版本保留期间可复现 |
| S3 version | 按 version 条件读取 | 对象版本保留期间可复现 |
| S3 ETag | 条件读取,变化则失败 | 覆盖后不保证 |
| 普通本地文件 | 读取前后校验身份、大小和指纹 | 修改后不保证 |
多个 Source 分别固定,不宣称来自同一全局时刻。CLI 将 snapshot_id、警告和 report 路径写入
stderr;REST 通过 metadata 或 headers 返回相同信息。
pChronicle 区分三层数据:
| 层次 | 示例 | 作用 |
|---|---|---|
| Exchange | ATIF、ACTF、OpenAI messages、Storyline | 导入导出与互操作 |
| Logical | Run、Trajectory、Step、ToolCall、Event、Judgment | 查询与产品语义 |
| Physical | events Lance、Storyline Lance、外部文件 | 持久化、版本和性能 |
Gateway/native writer 写入 append-only events,采用 at-least-once 语义;重复事实可以存在,
规范化投影必须暴露 duplicate count。Storyline 是分析模型,不反向覆盖事实层。全文索引和统计
是记录输入 snapshot_id 的可重建派生数据。
每个 Dataset 挂载为 SQL schema;位置参数使用 dataset,额外挂载使用 --dataset name=uri。
稳定逻辑关系如下:
| 关系 | 一行表示什么 |
|---|---|
sources |
一个 Source 及其版本、能力和状态 |
runs |
一个 Source 内的 Run |
trajectories |
从 Storyline 表派生的 Source-local Trajectory |
steps |
一条规范化 Step/Observation |
tool_calls |
一次工具调用及可关联结果 |
events |
一条事实事件 |
judgments |
一条评测或人工标注 |
所有实体关系都携带 source_path 和原始 ID。SQL 只允许只读语句,不开放写入、DDL、网络函数
或文件函数。
3. CLI 产品面¶
独立 pchronicle 是产品入口。以下各节只描述当前公共命令;完整参数以
命令参考和二进制 --help 为准。数据命令可显式接收 Dataset URI;配置本地默认 Warehouse 后,
支持该形态的命令可以省略 URI。TTY 默认输出人读表格,结构化输出使用 --format。stdout
只承载主结果,进度、Snapshot 和警告写入 stderr。
| 命令 | 职责 |
|---|---|
default |
设置或读取单目录本地默认 Warehouse |
ls/list、status |
Source 发现、能力、版本、数量与健康状态 |
query |
只读 SQL 与结构化结果输出 |
analysis |
稳定内置分析:overview、agents、models、tools |
find |
按 Source-local ID 精确定位或发现候选 |
import |
从单一格式创建新 Dataset |
export |
导出完整 Trajectory |
serve |
启动静态挂载的只读 API 与 Web |
3.1 Query 与 Find¶
pchronicle query <dataset-uri> \
"SELECT * FROM dataset.trajectories LIMIT 20"
pchronicle query --dataset live=<uri> --dataset archive=<uri> \
"SELECT * FROM live.runs UNION ALL SELECT * FROM archive.runs"
pchronicle query <dataset-uri> --format table|jsonl|csv \
--output <path-or-> "<read-only-sql>"
pchronicle find <dataset-uri> --session-id <id> [--source <source-path>]
每次读取先构造 Catalog Snapshot。Query 承担任意 SQL 投影的结构化输出;find 带 --source 时
是精确地址查询,不带时只发现候选。两者都受内存、行数、并发、超时和 spill 上限约束。
3.2 Import 与 Export¶
pchronicle import --from <path-or-> --output <new-dataset-uri> \
--format auto|atif|actf|openai-messages|storyline
pchronicle import --from <path> # 在默认 Warehouse 下创建确定性子目录
pchronicle import --stream --from - --output <new-dataset-uri> --format atif
pchronicle export --from <dataset-uri> --output <path-or-> \
--format atif|actf|openai-messages|storyline \
[--source <source-path>] [--run-id <id>] [--session-id <id>] [--where <expr>]
Import 只有 create 语义:目标已存在时拒绝,不提供 append/upsert/replace。一次调用只接受一种
输入格式;目录 auto 必须得到唯一格式,stdin 必须明确格式。导入先写不可见 staging,完成
格式、schema 和 Source-local ID 校验后再原子发布;失败或断流不留下可查询半成品。
Export 只输出完整 Trajectory,不编码任意 SQL 行。复杂筛选可先由 query 产生地址列表。
--strict 在转换无法保留原交换文档时失败。stream 均是读取到 EOF 后退出的有限记录流。
3.3 Query Pipeline 与维护边界¶
pChronicle 不启动、上传、分发或 sandbox 用户脚本,也不解释脚本输出。公共 CLI 不提供存储维护
命令;原生 Storyline compaction、index refresh、vacuum 和内容 GC 仅通过 Rust
StorylineLanceStore::maintain API 调用。pChronicle 不提供 rm/drop,Dataset 物理删除和失败
staging 清理由文件系统、对象存储或基础设施工具负责。
3.4 Built-in Analysis¶
analysis 是稳定逻辑表上的有界内置查询,不引入新的存储或执行引擎:
pchronicle analysis overview [<dataset-uri>]
pchronicle analysis agents [<dataset-uri>]
pchronicle analysis models [<dataset-uri>]
pchronicle analysis tools [<dataset-uri>]
四个子命令分别提供总体规模与 Source 健康、Agent 活动、模型声明/观测使用和工具调用/时延
覆盖。它们共享默认 Warehouse、Catalog Snapshot、超时、输出字节和行数上限,并支持 table、
JSONL、CSV。任意 SQL 与自定义分析继续使用 query,避免形成第二套查询语言。当前稳定 schema
没有用户身份字段,因此不提供会把消息角色误当用户的 users 分析。
4. 只读 Warehouse¶
4.0 本地默认 Warehouse¶
最基础 Warehouse 不需要服务端:用户通过 pchronicle default <DIRECTORY> 将一个本地目录
保存为默认 Warehouse。该目录同时是一个递归发现 Source 的 Dataset 根;设置后,ls、
status、query、find 和 export 可以省略 Dataset URI。显式 URI 始终优先。
pchronicle default ./trajectory-data
pchronicle query "SELECT COUNT(*) FROM dataset.runs"
pchronicle find --session-id session-42
配置只保存规范化绝对路径,不保存凭证;数据、Catalog Snapshot 和查询仍由 pChronicle Core
直接从该目录构建。此形态没有 HTTP、认证、守护进程、后台 Job 或额外数据库,可用于完整开发
和集成测试。default 无目录参数时只读取并打印当前设置。
4.1 静态配置与服务¶
Warehouse 是 operator-managed 配置定义的只读多 Dataset 视图,例如:
[[datasets]]
name = "production"
uri = "s3://agent-data/production/"
[[datasets]]
name = "local-evals"
uri = "/srv/evals"
名称必须唯一,URI 在启动时规范化并固定。公开 API 只接受配置名称,不接收任意 URI、自定义
endpoint、凭证或写权限。--open 打开同一 Web UI,取代单独的 dashboard 命令。
需要在本机同时接入在线模型流量时,serve 可以显式组合 Gateway:
Gateway TOML 继续作为转发路由、模型凭证、网络策略、代理端口和管理端口的唯一配置源;两个
Gateway 端口与 Warehouse 端口都必须绑定 loopback。捕获的 canonical events 由 Gateway sink
直接写入静态挂载的目标 Dataset,不经过 Warehouse HTTP 写接口,因此 Warehouse 的只读契约
不变。对象存储目标还必须用 --gateway-state 指定本地 session index/WAL 目录;本地 Dataset
默认复用其根目录。--gateway-stream-markdown 仅额外维护便于诊断的 AgenticMD 投影。
前台排障时可加 --debug(别名 --gateway-debug),将 Gateway dispatch/capture 日志直接
输出到 stderr;日志可能包含经过长度限制的请求与响应 body,因此不应在常规生产运行中开启。
Web 提供 Dataset/Source overview、Run/Trajectory 列表与详情、基础筛选、SQL 和查询结果下载。 API 只提供 health、Catalog、Explorer、evidence query 及当前路由表列出的只读详情/导出接口; 不提供 Search、import、Dataset mutation、maintenance、删除或在线 ingest。所有请求同步且有界, 不创建隐藏后台 Job。
4.2 在线写入边界¶
Gateway/native writer 可以按原生协议直接写入指定 Dataset,但不经过只读 Warehouse API。需要 OTLP/Langfuse 接入时,由独立 adapter 将固定入口映射到固定 Dataset;请求 header 不能动态指定 URI。认证、重试、attribute mapping 和写入语义由 adapter RFC 定义。
5. 系统保证¶
5.1 一致性与故障¶
| 场景 | 对外行为 |
|---|---|
| Source 在读取中变化 | 当前操作失败,不混合新旧内容 |
| 单个 Source 损坏 | strict 失败;report 模式标记 degraded 并跳过 |
| import 中断 | staging 不可见;残留由文件系统或对象存储运维工具清理 |
| export 无法无损转换 | --strict 失败;非 strict 按目标格式能力导出 |
| Warehouse 请求断开 | 同步操作取消或失败,不转为后台 Job |
| 反向代理身份缺失 | fail closed,不猜测 Dataset 或 principal |
错误响应包含稳定 error code、request ID、Dataset、Source 和 snapshot_id,并脱敏 URI 与
payload。所有读取和结果下载具备大小、时间、并发与输出上限。
5.2 安全与可观测性¶
共享服务只有静态配置会引入本地路径、S3 URI 和可选 S3 endpoint;HTTP 请求不接受这些字段。 远程目标必须经过统一校验:
- 配置加载时拒绝非法 scheme、内嵌凭证、签名 query、loopback、metadata、私网地址和未允许 端口;私有 MinIO/S3 需要独立 host/IP/CIDR allowlist;
- 实际连接时重新解析 DNS 并校验 peer IP;
- 默认禁用 endpoint 重定向;必须支持时逐跳复验,并在跨 origin 时删除敏感 header;
- 凭证只来自服务端 credential provider 或标准云凭证链。
负向测试至少覆盖 loopback、metadata IP、RFC1918/ULA、DNS 指向私网、内嵌凭证、跨域跳转 私网和空 allowlist。非 loopback endpoint 默认要求 HTTPS。
Server 默认监听 loopback;对外服务必须配置可信代理,丢弃非可信来源注入的身份和 Dataset
header。Web 将轨迹内容按文本渲染。访问日志记录 request ID、可信 principal、配置别名、Dataset
摘要、snapshot_id 和结果,不记录凭证或完整 payload。
实现至少观测 Source 发现与版本固定、query 扫描量和 spill、staging/orphan bytes、同步取消和 资源峰值;每个阶段提供本地/S3 的可复现基准。
6. 交付与演进¶
Dataset 产品能力只通过独立 pchronicle 命令发布,不保留跨组件转发层。
交付顺序为:
- 独立 CLI、Dataset/Source/Catalog Snapshot、统一 SQL 和 create-only import/export;
- Source-scoped find、内置 analysis 和 Catalog/status;
- 静态 Warehouse、只读 API/Web、可信代理和服务端可重建 cache。
核心验收聚焦以下结果:
- 同一 URI 在 CLI 与 Warehouse 中产生相同 Dataset identity 和逻辑关系。
- 嵌套、混合格式目录形成确定 Source 列表,读取中变化不会被静默混读。
- 外部 ID 原样保留;跨 Source 冲突返回完整候选地址。
- 任意读取报告
snapshot_id与 Sourcesnapshot_ref。 - Import 只创建新 Dataset 且原子发布;query/export 职责分离,strict export 拒绝有损转换。
- Find 返回含
source_path的地址,并在跨 Source 冲突时要求调用方消歧。 - pChronicle 不执行用户脚本、不物理删除 Dataset、不提供服务端写接口。
- 共享 API 只解析静态别名;远程连接、凭证和可信代理边界通过负向测试。
后续详细设计只覆盖 URI/Source discovery、轨迹地址与 Snapshot schema、import/export framing、 静态 Warehouse API 及出站连接校验。OTLP adapter、Search、动态 Catalog、物理删除和远程执行 均保持为独立可选扩展,不得成为核心依赖或未实现的公共命令。