Files
ars-backend/CLAUDE.md
Roog fa00da5966 调整 Docker 环境与依赖配置:
- 替换基础镜像为 `php:8.4.15-cli-alpine3.23`,重构依赖安装流程
- 切换包管理工具为 `apk`,添加必要系统库及扩展
- 更新 Composer 脚本及依赖映射
- 优化命令与环境变量配置,增强一致性与兼容性
2025-12-17 17:13:37 +08:00

318 lines
9.3 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.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
自然语言使用中文。
## 项目概述
这是一个基于 Laravel 12 + Octane + Docker 的 Agent Runtime Server (ARS),用于提供可部署的 Agent 运行时服务。核心特性包括:
- 兼容多种 Agent 模型
- Web 终端实时交互,支持断线重连
- 后台任务持续执行,重连后可续传会话
## 技术栈
- **PHP**: 8.2+
- **Laravel Framework**: 12.x
- **Laravel Octane**: 2.x (FrankenPHP)
- **Laravel Horizon**: 5.x (队列监控)
- **Laravel Telescope**: 5.x (调试工具)
- **数据库**: PostgreSQL 16
- **缓存/队列**: Redis 7
- **认证**: JWT (php-open-source-saver/jwt-auth)
- **容器化**: Docker Compose
## 核心架构
### 数据模型
#### ChatSession (会话)
- `session_id` (UUID, 主键): 会话唯一标识
- `session_name`: 会话名称
- `status`: 会话状态 (OPEN/LOCKED/CLOSED)
- `last_seq`: 最后消息序号
- `last_message_id`: 最后消息ID
#### Message (消息)
- `message_id` (UUID, 主键): 消息唯一标识
- `session_id`: 所属会话ID
- `role`: 消息角色 (USER/AGENT/TOOL/SYSTEM)
- `type`: 消息类型 (user.prompt/agent.message/run.status等)
- `content`: 消息内容 (text)
- `payload`: 附加数据 (jsonb)
- `seq`: 会话内序号 (单调递增)
- `reply_to`: 回复的消息ID
- `dedupe_key`: 幂等去重键
- **约束**: `unique(session_id, seq)``unique(session_id, dedupe_key)`
### 会话状态与门禁规则
- **OPEN**: 正常追加所有消息
- **LOCKED**: 拒绝 `role=USER && type=user.prompt`
- **CLOSED**: 拒绝追加,例外允许 `role=SYSTEM && type in [run.status, error]`
- **状态变更规则**: CLOSED 状态的会话不能重新打开
### Agent Run 执行流程
1. 用户发送 `user.prompt` 消息后自动触发,或通过 API 手动触发
2. `RunDispatcher` 检查幂等性(基于 `trigger_message_id`
3. 检查会话是否已有 RUNNING 状态的 run单会话单任务限制
4. 创建 `run.status=RUNNING` 消息并派发 `AgentRunJob`
5. `RunLoop` 执行 Agent 调用流程:
- `ContextBuilder` 构建上下文
- `AgentProviderInterface` 调用 Agent当前为 DummyAgentProvider
- `CancelChecker` 检查取消信号
- `OutputSink` 写入 agent.message
6. 完成后写入 `run.status=DONE/FAILED/CANCELED`
### 实时消息推送 (SSE)
- **端点**: `GET /api/sessions/{id}/sse?after_seq=123`
- **机制**:
1. 先从数据库补发历史消息seq > after_seq
2. 订阅 Redis 频道 `session:{id}:messages` 监听新消息
3. 支持 `Last-Event-ID` 自动续传
- **事件格式**: SSE event id 为消息 seq
### 服务层架构
- **ChatService**: 会话和消息的核心业务逻辑
- 使用行锁 (`lockForUpdate`) + 事务保证消息 seq 单调递增
- 通过 `dedupe_key` 实现幂等性
- 消息追加后发布 Redis 事件用于 SSE 推送
- **RunDispatcher**: Agent Run 调度器
- 检查 trigger_message_id 幂等性
- 确保同会话只有一个 RUNNING 状态的 run
- **RunLoop**: Agent 执行循环
- 协调 ContextBuilder、AgentProvider、OutputSink、CancelChecker
- **OutputSink**: 统一的消息写入接口
- `appendAgentMessage()`: 写入 agent 回复
- `appendRunStatus()`: 写入 run 状态
- `appendError()`: 写入错误信息
## 常用开发命令
### Docker 容器操作
```bash
# 构建并启动所有服务
docker compose build
docker compose up -d app horizon pgsql redis
# 停止服务
docker compose stop
# 查看日志
docker compose logs -f app
docker compose logs -f horizon
# 进入容器 shell
docker compose exec app bash
```
### 数据库操作
```bash
# 运行迁移
docker compose exec app php artisan migrate
# 回滚迁移
docker compose exec app php artisan migrate:rollback
# 刷新数据库(危险:删除所有表并重新迁移)
docker compose exec app php artisan migrate:fresh
# 运行 seeder
docker compose exec app php artisan db:seed
```
### 测试
```bash
# 运行所有测试
docker compose exec app php artisan test
# 运行特定测试套件
docker compose exec app php artisan test --testsuite=Feature
docker compose exec app php artisan test --testsuite=Unit
# 运行特定测试文件
docker compose exec app php artisan test tests/Feature/ChatSessionTest.php
# 运行特定测试方法(使用 filter
docker compose exec app php artisan test --filter=testCreateSession
docker compose exec app php artisan test --filter=testAppendMessageWithDedupe
# 显示测试覆盖率
docker compose exec app php artisan test --coverage
```
### 代码质量
```bash
# 运行 Laravel Pint 格式化代码
docker compose exec app vendor/bin/pint
# 只检查格式问题(不修改)
docker compose exec app vendor/bin/pint --test
# 格式化脏文件git 变更的文件)
docker compose exec app vendor/bin/pint --dirty
```
### 队列与任务
```bash
# 查看 Horizon 仪表板
# 访问 http://localhost:8000/horizon
# 手动运行队列 worker开发调试用
docker compose exec app php artisan queue:work
# 查看失败的任务
docker compose exec app php artisan queue:failed
# 重试失败的任务
docker compose exec app php artisan queue:retry all
```
### 开发调试
```bash
# 启动 Tinker REPL
docker compose exec app php artisan tinker
# 查看路由列表
docker compose exec app php artisan route:list
# 清除缓存
docker compose exec app php artisan cache:clear
docker compose exec app php artisan config:clear
docker compose exec app php artisan route:clear
# 查看实时日志(使用 Laravel Pail
docker compose exec app php artisan pail
```
### Artisan 生成器
```bash
# 生成 Model推荐带选项一次性生成相关文件
docker compose exec app php artisan make:model ChatSession -mfs
# -m: migration, -f: factory, -s: seeder
# 生成 Controller
docker compose exec app php artisan make:controller ChatSessionController
# 生成 Form Request用于验证
docker compose exec app php artisan make:request AppendMessageRequest
# 生成 ResourceAPI 响应格式化)
docker compose exec app php artisan make:resource ChatSessionResource
# 生成 Job
docker compose exec app php artisan make:job AgentRunJob
# 生成 Service 类
docker compose exec app php artisan make:class Services/ChatService
# 生成测试
docker compose exec app php artisan make:test ChatSessionTest --phpunit
docker compose exec app php artisan make:test ChatServiceTest --unit --phpunit
```
## API 路由结构
所有 API 路由均在 `/api/*` 下,除登录和健康检查外均需 JWT 认证:
- `POST /api/login`: 用户登录
- `GET /api/health`: 健康检查
- `GET /api/me`: 获取当前用户信息
### 用户管理
- `GET /api/users`: 用户列表
- `POST /api/users`: 创建用户
- `PUT /api/users/{user}`: 更新用户
- `POST /api/users/{user}/deactivate`: 停用用户
- `POST /api/users/{user}/activate`: 激活用户
### 会话管理
- `POST /api/sessions`: 创建会话
- `GET /api/sessions`: 会话列表(支持分页、状态过滤、关键词搜索)
- `GET /api/sessions/{session_id}`: 获取会话详情
- `PATCH /api/sessions/{session_id}`: 更新会话(重命名、状态变更)
- `POST /api/sessions/{session_id}/archive`: 归档会话(幂等,设为 CLOSED
### 消息管理
- `POST /api/sessions/{session_id}/messages`: 追加消息(支持幂等 dedupe_key
- `GET /api/sessions/{session_id}/messages`: 获取消息列表(支持 after_seq 增量拉取)
- `GET /api/sessions/{session_id}/messages/{message_id}`: 获取单条消息
### 实时与 Agent Run
- `GET /api/sessions/{session_id}/sse`: SSE 实时消息流
- `POST /api/sessions/{session_id}/runs`: 手动触发 Agent Run
## 开发注意事项
### Laravel 12 新特性
-`app/Console/Kernel.php``app/Http/Kernel.php`
- 中间件、路由、异常处理在 `bootstrap/app.php` 配置
- 服务提供者在 `bootstrap/providers.php` 注册
- Commands 自动注册(无需手动注册)
### 数据库操作规范
- 消息追加必须使用 `ChatService::appendMessage()`,不要直接操作 Message 模型
- 会话状态变更必须通过 `ChatService::updateSession()`
- 所有涉及 seq 递增的操作必须在事务 + 行锁中完成
### 测试规范
- 所有测试使用 PHPUnit非 Pest
- Feature 测试必须测试完整的 HTTP 请求流程
- 测试中使用 Factory 创建模型数据
- 修改代码后必须运行相关测试确保通过
### 队列配置
- 开发环境可使用同步队列:`.env` 中设置 `QUEUE_CONNECTION=sync`
- 生产环境使用 Redis 队列 + Horizon 监控
- `AgentRunJob` 在队列中异步执行
### 幂等性设计
- 所有可能重复调用的操作都使用 `dedupe_key`
- `RunDispatcher` 通过 `trigger_message_id` 确保不会为同一 prompt 重复创建 run
- SSE 通过 `Last-Event-ID` / `after_seq` 支持断线续传
## 环境变量关键配置
```bash
# Octane 服务器
OCTANE_SERVER=frankenphp
# 数据库PostgreSQL
DB_CONNECTION=pgsql
DB_HOST=pgsql
DB_PORT=5432
DB_DATABASE=ars_backend
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
# 队列
QUEUE_CONNECTION=redis # 或 sync开发用
# JWT 认证
JWT_SECRET=<生成的密钥>
AUTH_GUARD=api
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:5173
```
## 相关文档
- API 详细文档:`docs/ChatSession/chat-session-api.md`
- OpenAPI 规范:`docs/ChatSession/chat-session-openapi.yaml`
- 用户管理文档:`docs/User/user-api.md`