CLAUDE.md实现参考
该文件为使用 Claude Code(claude.ai/code)在本仓库中的代码工作提供了指导。
项目概述
OmniAgent — 一个 Spring Boot 3.5.10 AI 代理系统,支持多厂商 LLM,具备工具调用功能,RAG 文档处理,并支持 React/Vite 前端。设计为毕业论文项目。
构建与运行命令
“砰
后端
./mvnw clean package -DskipTests # 构建
./mvnw spring-boot:run # 运行(开发配置文件默认激活)
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
./mvnw 测试 # 运行所有测试
./mvnw test -Dtest=ClassName#methodName # Single test
./mvnw 编译 # 快速检查
前端(独立节点项目)
光盘前端
npm run dev # 开发服务器 :9500
npm 运行构建 # 生产构建
npm run test # Vitest
---
## 后端架构('src/main/java/top/javarem/omni/')
### 包结构
| 包裹 |责任 |
|---------|---------------|
| 'controller/' |REST 端点:聊天、认证、问题、知识库、宠物 |
| '服务/' |业务逻辑:ChatService,AskUserQuestionService,RAG ETL |
| '服务/rag/' |RAG 流水线:ETL、文本拆分、令牌计数 |
| '服务/聊天/' |LLM 聊天编排,ChatModelStrategy 多厂商适配器 |
| '服务/聊天/策略/' |'深度搜寻聊天策略','迷你极大聊天策略','人类聊天策略' |
| '顾问/' |春季 AI 顾问链:生命周期、上下文压缩、消息格式、任务进度 |
| 'tool/' |所有 AgentTool 实现 |
| 'tool/file/' |读/写/编辑/Grep/Glob 文件工具 |
| 'tool/web/' |WebSearch,WebFetch 工具 |
| 'tool/bash/' |带安全验证的 bash 执行 |
| 'tool/rag/' |RAG 查询工具 |
| 'tool/agent/' |子代理系统:启动、会话管理、工作树隔离 |
| '工具/批准/' |AskUserQuestion 和 DangerousCommand 审批流程 |
| 'repository/chat/' |MySQL 聊天历史(MemoryRepository) |
| 'repository/rag/' |PostgreSQL kb_file 操作(RagFileRepository) |
| 'config/' |Spring 配置:安全、web、thread pool、RAG、技能 |
| '模型/' |DTO、实体、记录 |
| '安全性/' |JWT 认证、用户详情、过滤器 |
| 'loader/' |技能加载器,SystemMessageLoader |
### 控制器
| 控制器 |端点 |目的 |
|------------|-----------|---------|
| “聊天控制器” |“帖子 /聊天/直播” |SSE 流式聊天,多厂商调度 |
| 'AuthController' |'/api/auth/login', '/register', '/logout', '/me' |基于 JWT 的认证 |
| “AskUserQuestionController” |“获取 /api/questions/pending”,“POST /api/questions/{id}/answer” |问题轮询与回答 |
| '批准控制器' |'获取/批准/待处理','发布/批准','获取/批准-事件' |危险命令批准 + SSE 推送 |
| '知识库控制器' |'/api/knowledge-base/stats', '/files', '/files/upload', '/files/{id}', '/files/{id}/retry', '/search' |知识库 CRUD + 搜索 |
| “宠物控制者” |“/api/pet” CRUD |宠物管理演示 |
### LLM 多供应商适配器(“服务/聊天/”)
多 LLM 支持的策略模式:
ChatService → ChatModelStrategyFactory → ChatModelStrategy(界面)
├── DeepSeekChatStrategy
├── MiniMaxChatStrategy
└── AnthropicChatStrategy
- 每个策略都实现了“doStream()”,返回“Flux<String>”(原始 JSON 块)
- “SseChunkEncoder” 封装原始 JSON,提取 SSE 事件 ID 的 'id'
- 后端发送:'data:{json}\n\n' — 'data:'后无空格,'event:'字段无
- 协议:兼容 OpenAI 的 delta 格式('delta.content', 'delta.reasoning_content', 'delta.tool_calls')
- 备份链:如果主供应商失败,下一步尝试;如果全部失败,则返回 DeepSeek
### 顾问链系统
春季 AI 顾问流程(按 'getOrder()' 排序):
| 顾问 |秩序 |责任 |
|---------|-------|----------------|
| “消息格式顾问” |“ORDER_BEFORE_PROMPT_CONVERSION”(10000) |加载系统提示,注入技能,加载历史 |
| “ContextCompressionAdvisor” |4000 |压缩长对话(正字+尾+摘要) |
| “生命周期工具呼叫顾问” |“Integer.MAX_VALUE - 1000” |工具调用生命周期、消息持久性、流/调用模式 |
| “任务进展顾问” |“Integer.MAX_VALUE - 100” |追踪 exec_rounds,检测停滞任务 |
**呼叫流程**: 'MessageFormatAdvisor.before()' → 'LifecycleToolCallAdvisor.doInitializeLoop()' → ToolCall Loop → 'LifecycleToolCallAdvisor.doFinalizeLoop()' → 'MessageFormatAdvisor.after()'
**流模式流程**:
请求 → MessageFormatAdvisor.before() → LifecycleToolCallAdvisor.doInitializeLoopStream()
→ ToolCall 循环 (doGetNextInstructionsForToolCallStream)
→ ChatClientMessageAggregator.aggregateChatClientResponse()
→ LifecycleToolCallAdvisor.doFinalizeLoopStream() → 响应
### 工具系统(“tool/”)
| 包装 |工具 |
|---------|-------|
| 'file/' |'ReadToolConfig', 'WriteToolConfig', 'EditToolConfig', 'GrepToolConfig', 'GlobToolConfig' |
| 'web/' |'WebSearchToolConfig', 'WebFetchToolConfig' |
| 'rag/' |'RagToolConfig'(向量存储上的语义搜索) |
| 'bash/' |'BashToolConfig'(带安全流水线) |
| root |'SkillToolConfig', 'AskUserQuestionTool', 'TaskToolConfig', 'AgentTool'(标记界面),'ToolsManager' |
- 'AgentTool' — 标记界面;'ToolsManager' 通过 'ToolCallbacks.from()' 自动发现所有 'AgentTool' 豆子
- “AskUserQuestionTool” — 暂停执行,创建“CompleTableFuture”,通过“AskUserQuestionYieldException”生成。前端轮询随后提交答案以完成未来。
### 代理子系统(“tool/agent/”)
| 类别 |目的 |
|-------|---------|
| 'AgentToolConfig' |入口点:'launchAgent' + 'agentOutput' 工具 |
| “SubAgentChatClientFactory” |按代理类型创建独立 ChatClient,工具过滤,单次模式 |
| “AgentSessionManager” |代理恢复的内存会话历史 |
| “AgentTaskRegistry” |带所有权检查的异步任务跟踪 |
| “WorktreeManager” |agent 任务的 Git 工作树隔离 |
| “代理类型” |枚举:“探索”(单次冒险),“计划”(一次性事件),“验证”(一次性事件),“通用”,“CODE_REVIEWER” |
**工具过滤**:每个“AgentType”都有“allowedTools”设置;出厂设置相应过滤。
### Bash 安全架构(“tool/bash/”)
| 组成部分 |责任 |
|-----------|---------------|
| “危险模式验证器” |基于正则表达式的危险命令模式匹配 |
| “自杀指令探测器” |检测系统破坏命令(rm -rf,叉炸弹) |
| “CommandApprover” |中央审批门与 SSE 推送至前端 |
| “ProcessTreeKiller” |超时/终止时的清理 |
| “路径批准服务” |批准执行路径管理 |
### RAG 系统(“服务/rag/”)
| 组件 |目的 |
|-----------|---------|
| “AdvancedRagEtlService” |ETL 流水线:提取文本→分割→嵌入→存储 |
| “递归文本分叉器” |令牌感知递归文本分块 |
| “MarkdownHeaderSplitter” |Markdown 结构感知拆分 |
| “代币计数器” |基于 JTokkit 的代币计数 |
| “ParentChildSplitter” |父子块关系(父=800 个 token,child=200 个 token) |
**ETL 流程**:上传文件→ Tika 文本提取 →父子拆分 →嵌入(ZhipuAI/BAAI/bge-m3)→存储在 PostgreSQL pgvector
### 技能系统(“装载手/”)
- “SkillLoader” — 扫描已配置的目录中的“SKILL.md”文件
- “SystemMessageLoader” — 从“agent_system_prompt.md”加载系统提示符
- 技能发现源:'bundled'(classpath)、'managed'(~/.claude/skills/)、'user'(~/.omni/skills/)
- 技能使用 YAML 前置句(“名称”、“描述”、“工具”)
- 每个技能定义自己的行为规则
### SSE 流媒体协议
**线路格式**(后端→前端):
data:{“id”:“...”,“choices”:[{“delta”:{“content”:“...”,“reasoning_content”:“...”,“tool_calls”:[...]},“finish_reason”:“tool_calls”}]}
数据:[完成]
- 后端:“SseChunkEncoder”返回原始 JSON,Spring Boot 的“ServerSentEventHttpMessageWriter”添加“data:'前缀
- 'finish_reason:“tool_calls”表示圆尾(刀具循环迭代完成)
- 前端“streamChat()”:读取原始“可读流”,解析“数据:”行,生成“StreamEvent”对象
- 事件:'文本'、'思考'、'工具调用'、'圆端'
- 批准事件使用独立的 SSE 通道:“/批准-事件”(EventSource)
### 安全与认证
- **Auth**:基于 JWT,存储在 Cookie 中(仅 HttpOnly),由“JwtAuthFilter”验证
- “SecurityConfig”:允许“/api/auth/”、“/chat/stream”、“/approval-events”、“/api/knowledge-base/static”
- **密码**:BCrypt
- 'UserDetailsServiceImpl':从 MySQL 'users' 表加载
- CORS:允许“localhost:5173”(Vite 开发者),“localhost:9090”
---
## 前端架构(“frontend/src/”)
### 目录结构
src/
├── App.tsx # 主聊天页面:SSE 流媒体、州级、投票
├── main.tsx # React 条目 + BrowserRouter
├── index.css # Tailwind v4 + 自定义风格 + 动画
├── api/
│ ├── auth.ts # 登录/注册/注销 API
│ ├── chat.ts # SSE streamChat() 异步生成器 + 轮询 API
│ ├── knowledgeBase.ts # KB CRUD + 统计 + 搜索
│ ├── pet.ts # 宠物垃圾 API
│ └── rag.ts # RAG ETL 上传 API
├── 组件/
│ ├── AuthRoute.tsx # 若已认证,重定向
│ ├── PrivateRoute.tsx # 未认证重定向
│ ├── ChatInput.tsx # 消息输入:textarea + 发送 + workspace + bypass
│ ├── ChatMessage.tsx # 块渲染消息:想法、工具调用、短信
│ ├── CommandApprovalInline.tsx # Inline 命令批准卡
│ ├── DangerousCommandModal.tsx # 模态指令批准(未使用)
│ ├── HtmlArtifact.tsx # HTML 预览:代码标签页 + iframe 预览标签页
│ ├── KnowledgeBasePanel.tsx # 全知识库管理界面
│ ├── MarkdownRenderer.tsx # react-markdown + 棱镜语法高亮
│ ├── QuestionInline.tsx # 多步题表带导航
│ ├── RagUploadTool.tsx # 独立 RAG 上传工具
│ ├── Sidebar.tsx # 对话列表(今天/昨天/较老)
│ ├── ToolsSidebar.tsx # 浮动键键 + 全屏覆盖
│ └── pet/PetManagement.tsx # 宠物 CRUD 网格+模态形式
├── context/AuthContext.tsx # 全局认证状态(用户,登录,注销)
├── 页/
│ ├── LoginPage.tsx # 登录表单
│ └── RegisterPage.tsx # 报名表
├── 类型/index.ts # 消息、对话、提问、聊天步等。
└── utils/
├── messageParser.ts #
└── parseBlocks.ts # 备份块解析器(未使用)
### 流媒体状态机(App.tsx)
1. 'handleSend(text)' →创建对话,启动 SSE 流 + 批准 SSE + 问题轮询
2. 通过“streamChat()”进行事件循环生成“StreamEvent”:
- 'thought' →附加在 'thoughtBufferById[roundIndex]' 上,更新流式块
- “tool-call” →在最新思考块中设置 “toolName”/“toolInput”
- 'text' →附加在 'textBufferById[roundIndex]' 上,更新流式块
- “round-end”→增量“roundIndex”
- “dangerous-command” →停止流,显示批准 UI。
3. 流结束→构造带有“blocks[]'数组的”消息“→推入历史
### 问题投票流程
- 'setInterval' 每 2 秒轮询 'GET /api/questions/pending'
- 当“hasQuestion === true”时,停止轮询,<QuestionInline>表示“''
- 用户回答“POST /api/questions/{id}/answer”→→回答附加于用户消息→继续轮询
### 批准流程
- “EventSource” 连接 “/approval-events”,监听“dangerous-command”
- “CommandApprovalInline”带批准/拒绝按钮进行渲染
- 'submitApproval(ticketId, command, approved)' →后端恢复或取消
### 关键依赖关系
- React 18 + react-router-dom 6 + lucide-react(图标)
- react-markdown + react-syntax-highlighter(棱镜)+ remark-gfm
- Tailwind CSS v4 + '@tailwindcss/排版'
### 路由
/ → PrivateRoute → 聊天页面(主聊天)
登录→ AuthRoute → 登录页面
/register → AuthRoute → RegisterPage
- → 导航到“/”
---
## 数据库
### MySQL(“rem-agent”)
| 表格 |目的 |
|-------|---------|
| 'spring_ai_chat_memory' |聊天历史:ID、conversation_id、内容、类型(用户/助手/系统/工具)、时间戳 |
| “kb_file” |知识库文件记录:ID、kb_id、文件名、状态、total_chunks、时间戳 |
| '用户' |认证:ID、用户名、密码(BCrypt) |
| 'chat_memory' |带 parent_id 树的链接列表消息存储 |
| 'ai_tasks' |任务进度追踪 |
### PostgreSQL (“springai”) with pgvector
| 表格 |目的 |
|-------|---------|
| 'vector_store' |嵌入(1024d)+ 元数据,HNSW 指数,余弦距离 |
| 'rag_parent_chunks' |RAG 父块(800 个令牌) |
| 'spring_ai_chat_memory' |聊天历史镜像(用于矢量搜索)|
| 'ai_tasks' |任务追踪 |
---
## 配置
- **主**:“application.yml”(默认提供者,内存阈值)
- **开发者**:“application-dev.yml”(数据库、AI 厂商、RAG、线程、CORS)
- **测试**:“application-test.yml”
- **前端代理**:'vite.config.ts'代理 '/chat', '/api', '/approval' → 'localhost:9090'
- **已批准命令**:'approved-commands.properties'
- **系统提示符**:“agent_system_prompt.md”
### 人工智能供应商
| 供应商 |型号 |密钥配置 |
|--------|-------|------------|
| 深度搜寻 |通过 OpenAI 适配器“deepseek-v4-flash” |“spring.ai.openai.*” |
| 迷你极限 |“迷你极限-M2.7” |“spring.ai.minimax.*” |
| 人类 |'MiniMax-M2.7'(通过 MiniMax 代理) |'spring.ai.anthropic.*' miniMax 代理的 base-url |
| ZhipuAI |'embedding-3'(用于嵌入)|'spring.ai.zhipuai.*' |
| 嵌入 |“BAAI/bge-m3”(1024d)通过 SiliconFlow 访问 |“spring.ai.openai.embedding.*” |
| 重新排序 |通过 SiliconFlow 实现的“BAAI/bge-reranker-v2-m3” |top-n=3 |
---
## 发展指南
**参见**:[docs/DEVELOPMENT_GUIDELINES.md](docs/DEVELOPMENT_GUIDELINES.md)
- **评论**:中文,结构化 Javadoc——解释为什么,而不是什么
- **日志**:'[ClassName]'前缀(例如,'[RagFileRepository]')
- **代码样式**:提前返回,语义命名,无模糊变量
- **测试**:TDD,测试中的 UUID 隔离
- **Git**: <type>'(<scope>): ' 在<subject>**中文**中
- **前端**:Tailwind v4,通过“.dark”类实现暗黑模式,移动响应型,受 Shadcn 启发的极简主义
- **添加供应商**:创建新的“ChatModelStrategy”实现 + “@Component”,无需更改路由
- **添加工具**:实现“AgentTool”界面,“ToolsManager”通过“ToolCallbacks.from()”自动发现
- **添加技能**:在扫描的技能目录中用 YAML 前言创建“SKILL.md”
浙公网安备 33010602011771号