Files
nexus/openclaw/xingshu/projects/agentbase-design.md

304 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: AgentBase 项目设计文档
source:
author: shenwei
published:
created:
description:
tags: []
---
# AgentBase 项目设计文档
> 设计日期2026-04-05
> 状态:已确认,等待实施
> 项目位置:`~/Workspace/agentbase/`
---
## 1. 项目概述
**项目名**agentbase
**项目类型**Django Web 应用 + 数据归档系统
**核心目标**:遍历 OpenClaw Agent 的 session JSONL 文件,解析并保存到 MariaDB通过 Django Admin 提供 Web 查询界面。
**使用场景**
- 查找某个 Agent 在某天的所有对话记录
- 查找某个 Agent 在处理任务时调用了哪些工具(特别是 `exec` 命令的具体内容)
- 查看 Agent 的思考过程thinking block
- 增量解析,只解析未处理过的文件
---
## 2. 数据库设计
### 2.1 服务器与 Agent 映射
| 服务器 | 标识 | Session 根目录 |
|--------|------|----------------|
| Mac Mini | `macmini` | `/Users/weishen/.openclaw/agents/` |
| Ubuntu1 | `ubuntu1` | `/home/shenwei/.openclaw/agents/` |
| Ubuntu2 | `ubuntu2` | `/home/shenwei/.openclaw/agents/` |
**纳入的 Agent**main、xingyao、xinghui、xingjiang、opencode、sisyphus
### 2.2 Session 文件类型
所有 `.jsonl` 文件均需解析,包括:
- `*.jsonl` — 正常 session
- `*.jsonl.reset.*` — reset 快照
- `*.jsonl.deleted.*` — 删除快照
- `*-topic-*.jsonl` — 线程 session
**session_type 判定**
- 文件名含 `.reset.``reset`
- 文件名含 `.deleted.``deleted`
- 文件名含 `-topic-``topic`
- 默认 → `normal`
**忽略文件**`sessions.json`(索引文件,不解析)
### 2.3 数据库 Schema
#### 表:`parsed_files`(增量解析控制)
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | INT AUTO_INCREMENT | 主键 |
| `server` | VARCHAR(32) | 服务器标识 |
| `agent_id` | VARCHAR(64) | Agent ID |
| `file_path` | VARCHAR(512) | 文件绝对路径 |
| `file_mtime` | BIGINT | 文件最后修改时间Unix timestamp |
| `file_size` | BIGINT | 文件大小(字节) |
| `status` | VARCHAR(16) | `pending` / `success` / `failed` |
| `parsed_at` | DATETIME | 本次解析时间 |
| `error_message` | TEXT | 失败时的错误信息(可空) |
**UNIQUE 约束**`UNIQUE(server, agent_id, file_path)`
**增量解析逻辑**
```sql
-- 插入前检查:同一文件 + 同一修改时间是否已解析
WHERE NOT EXISTS (
SELECT 1 FROM parsed_files
WHERE server=? AND agent_id=? AND file_path=?
AND file_mtime=? AND file_size=? AND status='success'
)
```
---
#### 表:`sessions`Session 根记录)
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | INT AUTO_INCREMENT | 主键 |
| `server` | VARCHAR(32) | 服务器标识 |
| `agent_id` | VARCHAR(64) | Agent ID |
| `session_uuid` | VARCHAR(64) | Session UUID文件名去掉.jsonl等后缀 |
| `file_path` | VARCHAR(512) | 来源文件路径 |
| `session_type` | VARCHAR(32) | `normal` / `topic` / `reset` / `deleted` |
| `cwd` | VARCHAR(512) | Session 工作目录 |
| `started_at` | DATETIME(3) | Session 开始时间 |
| `first_message_at` | DATETIME(3) | 第一条 message 的时间 |
| `last_message_at` | DATETIME(3) | 最后一条 message 的时间 |
| `message_count` | INT | 该 session 的消息总数 |
| `created_at` | DATETIME | 记录创建时间 |
**UNIQUE 约束**`UNIQUE(session_uuid, server, agent_id)`
---
#### 表:`messages`(消息内容)
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | INT AUTO_INCREMENT | 主键 |
| `session_id` | INT | 外键 → `sessions.id` |
| `server` | VARCHAR(32) | 服务器标识 |
| `agent_id` | VARCHAR(64) | Agent ID |
| `session_uuid` | VARCHAR(64) | Session UUID冗余存储方便查询 |
| `message_uuid` | VARCHAR(64) | 消息 UUID |
| `parent_message_uuid` | VARCHAR(64) | 父消息 UUID可空 |
| `role` | VARCHAR(32) | `user` / `assistant` / `toolResult` |
| `content_blocks` | JSON | **原文**:原始 content 数组 |
| `text_preview` | VARCHAR(512) | 纯文本摘要前512字符 |
| `first_tool_call` | VARCHAR(128) | 首个 toolCall name |
| `tool_call_count` | INT | toolCall 总数 |
| `tool_calls_json` | JSON | **拆出**:所有 toolCall block |
| `thinking_text` | TEXT | **拆出**:首个 thinking block |
| `has_thinking` | TINYINT | 是否有 thinking0/1 |
| `has_tool_calls` | TINYINT | 是否有 toolCall0/1 |
| `is_error` | TINYINT | 整条 isError 标记 |
| `provider` | VARCHAR(64) | AI Provider`minimax` |
| `model` | VARCHAR(128) | 模型 ID`MiniMax-M2.7` |
| `api` | VARCHAR(64) | API 类型(如 `anthropic-messages` |
| `stop_reason` | VARCHAR(64) | stopReason 字段值 |
| `input_tokens` | INT | 输入 token 数 |
| `output_tokens` | INT | 输出 token 数 |
| `cache_read_tokens` | BIGINT | Cache Read token 数 |
| `cache_write_tokens` | BIGINT | Cache Write token 数 |
| `total_tokens` | INT | 总 token 数 |
| `cost_usd` | DECIMAL(12,8) | 该消息美元成本 |
| `timestamp` | DATETIME(3) | 消息时间 |
| `created_at` | DATETIME | 记录创建时间 |
**Indexes**
- `idx_agent_timestamp` ON `(agent_id, timestamp)`
- `idx_first_tool_call` ON `(first_tool_call)`
- `idx_session_id` ON `(session_id)`
- `idx_role` ON `(role)`
### 2.4 Content Block 结构
JSONL 中每条 `type:message``content` 数组,成员类型如下:
| content block type | 关键提取字段 |
|---|---|
| `text` | `text`(纯文本) |
| `thinking` | `thinking``thinkingSignature` |
| `toolCall` | `id``name``arguments`JSON 对象) |
| `toolResult` | `toolCallId``toolName``content``isError``details` |
**`text_preview` 提取规则**(按优先级):
1. 找第一个 `type=="text"``text` 字段
2. 找不到则找 `type=="thinking"``thinking` 字段
3. 再找不到则找 `type=="toolResult"` 里第一个子 `type=="text"` 的内容
4. 截取前512字符strip HTML
---
## 3. Django 项目结构
```
~/Workspace/agentbase/ # Git 仓库根目录
├── manage.py
├── agentbase/ # Django 项目
│ ├── __init__.py
│ ├── settings.py # 数据库配置在此
│ ├── urls.py
│ └── wsgi.py
├── messages/ # Django App
│ ├── __init__.py
│ ├── models.py # ParsedFile / Session / Message
│ ├── admin.py # Django Admin 配置
│ ├── views.py # Web 查询视图
│ ├── urls.py
│ ├── management/
│ │ └── commands/
│ │ └── parse_sessions.py # Django command
│ └── templates/
│ └── messages/
│ └── message_list.html
├── scripts/
│ └── parse_and_import.py # OpenClaw cron 调用的入口脚本
├── tests/
├── requirements.txt
└── README.md
```
### 3.1 配置方式
数据库连接信息直接写在 `settings.py` 中(不使用 config.yaml
### 3.2 Django Admin 预期界面
**Messages核心**
- 列表页支持按 `agent_id` + `timestamp` 范围 + `role` + `first_tool_call` 过滤
- 详情页展示 `content_blocks` 原始 JSON、`thinking_text``tool_calls_json`
- 适合查找"某 Agent 某天所有对话和思考记录"
**Sessions**:列出所有 session按 server/agent_id 过滤。
**ParsedFiles**:记录已解析文件列表,支持按 server/agent_id/file_path 搜索。
---
## 4. 解析脚本设计
### 4.1 入口脚本
`scripts/parse_and_import.py`
- OpenClaw cron 任务调用此脚本
- 也可单独运行:`python parse_and_import.py --server macmini --agent xingyao`
- 内部加载 Django settings调用 Django ORM 写入数据库
### 4.2 解析流程
1. **遍历服务器和 Agent**macmini/ubuntu1/ubuntu2 → 各 Agent 目录
2. **扫描 session 文件**:列出所有 `.jsonl` 文件,跳过 `sessions.json`
3. **增量检查**:查 `parsed_files` 表,文件 mtime+size 未变且 status=success → 跳过
4. **解析 JSONL**:逐行读取,提取 `type:session``type:message` 记录
5. **写入数据库**:先插入 `sessions`,再批量插入 `messages`
6. **更新 `parsed_files`**status=success 或 status=failed + error_message
### 4.3 OpenClaw Cron 任务
每日 00:05 执行00:00 照片整理完成后错开):
```bash
python ~/Workspace/agentbase/scripts/parse_and_import.py
```
- 在 Mac Mini 上执行
- 通过 SSH 访问 ubuntu1/2 的 session 目录
- 所有 Agent 的当日新 session 均被解析
---
## 5. 典型查询示例
### 5.1 查某 Agent 某天的所有消息
```sql
SELECT id, message_uuid, role, text_preview, has_thinking, first_tool_call, timestamp
FROM messages
WHERE agent_id = 'xingyao'
AND timestamp BETWEEN '2026-04-05 00:00:00' AND '2026-04-05 23:59:59'
ORDER BY timestamp;
```
### 5.2 查某 Agent 某天调用过的所有 exec 命令
```sql
SELECT m.id, m.timestamp, m.text_preview, m.session_uuid
FROM messages m
WHERE m.agent_id = 'xingyao'
AND m.timestamp BETWEEN '2026-04-05 00:00:00' AND '2026-04-05 23:59:59'
AND m.first_tool_call = 'exec';
```
### 5.3 查包含 thinking 的消息
```sql
SELECT id, message_uuid, role, thinking_text, timestamp
FROM messages
WHERE agent_id = 'xingyao'
AND has_thinking = 1
AND timestamp BETWEEN '2026-04-05 00:00:00' AND '2026-04-05 23:59:59';
```
---
## 6. 待确认事项
- [ ] 数据库类型MariaDBSQLite开发测试用
- [ ] 数据库名称
- [ ] MariaDB 部署在哪里Mac Mini 本地NAS独立服务器
---
## 7. 后续步骤
1. 用户确认以上设计
2. 创建 Git 仓库 `~/Workspace/agentbase/`
3. 初始化 Django 项目
4. 编写 `settings.py`(含数据库配置)
5. 编写 `messages/models.py`(三张表)
6. 编写 `messages/admin.py`Admin 配置)
7. 编写 `scripts/parse_and_import.py`(解析入口)
8. 编写 `messages/management/commands/parse_sessions.py`Django command
9. 配置 Django Admin 模板message_list.html
10. 创建 OpenClaw cron 任务