b123a36aae
后端修复: - main.go: 恢复 /api/v1/chat 路由中丢失的 handleChat 调用 (空响应回归) - orchestrator.go: splitChatByLines 改为双换行分割, 避免单换行误拆 - chat_handler.go: multi_message 增加 !hasReview 守卫, 消息延迟 200→800ms - thinker.go: RecordUserMessage 追踪活跃会话ID, 推送主动消息到正确会话 - thinker.go: 增强思考提示词 — 禁止在用户休息/离开时发送主动消息 前端修复: - useWebSocket.ts: stream_segments 不再创建消息气泡, 消除重复回复 - MessageBubble.tsx: 动作消息居左对齐无头像, 时间戳移至气泡外侧 hover 显示 - ChatInput.tsx: 昔涟输入提示移至输入框上方, 波点动画效果 - MessageList/TypingIndicator/ChatContainer: 清理冗余 isTyping 传递 - MemoryPanel.tsx: 新增记忆面板组件 文档重整: - docs/debug/ → docs/debug_log/ 重命名统一 - 新增 debug_log/README.md 索引 - .gitignore: 新增 android/ 排除规则 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
15 KiB
15 KiB
Cyrene 持续性调试报告 — 10轮汇总
日期: 2026-05-19 时间范围: UTC+8 约21:30 — 23:35 总轮次: 10 环境: 本地开发 (非Docker),7个核心服务 + PostgreSQL + DevTools
一、调试轮次总览
| 轮次 | 角度 | 关键发现数 |
|---|---|---|
| 第1轮 | 服务间通信与API契约验证 | 4 |
| 第2轮 | IoT设备控制与工具链验证 | 2 |
| 第3轮 | 端到端功能测试与安全验证 | 2 |
| 第4轮 | LLM思维记忆优化与工具扩展 | 3 |
| 第5轮 | 独立服务抽取与调用记录 | 4 |
| 第6轮 | 多会话架构、自主思考重构与综合Bug修复 | 8 |
| 第7轮 | 认证安全与前端消息类型完整性 | 2 |
| 第8轮 | 并发安全与跨服务韧性 | 3 |
| 第9轮 | 部署配置与Docker完整性 | 4 |
| 第10轮 | 编译产物与构建完整性 | 2 |
二、所有Bug汇总 (按优先级)
🔴 P0 — 严重/阻塞 (5个)
| # | 来源轮次 | 问题 | 文件位置 | 影响 |
|---|---|---|---|---|
| 1 | R6 | Session randomID() 确定性输出导致ID冲突 |
session_handler.go:576-582 |
使用 letters[i%len(letters)] 而非 crypto/rand,每次生成相同序列;会话/消息ID可预测且可能碰撞 |
| 2 | R6 | TTS fallback不可达 | tts_handler.go:55-65 |
handler层 IsAvailable() 检查在第55行就返回503,导致 voice_handler.go 中Gateway配置的fallback逻辑永远不会被触发 |
| 3 | R8 | 编排器/子会话goroutine缺少 defer recover() |
orchestrator.go:81, manager.go:90/137 |
3处 go func() 启动的goroutine中任何panic都会导致整个进程崩溃,无优雅恢复机制 |
| 4 | R9 | 管理员权限中间件逻辑错误 | router.go:231 |
adminAuth() 检查 admin_ 前缀但实际 user_id 为 user_admin 格式(auth_handler.go:97),导致管理员永远无法通过中间件鉴权 |
| 5 | R10 | 40MB编译产物被Git追踪 | voice-service/main, voice-service/main2, voice-service/voice-svc-new, gateway/cmd/gateway |
.gitignore 未覆盖 voice-service/main、voice-service/main2、voice-service/voice-svc-new、gateway/cmd/gateway 四个二进制文件;每次提交携带约40MB无用二进制 |
🟡 P1 — 高优先级 (5个)
| # | 来源轮次 | 问题 | 文件位置 | 影响 |
|---|---|---|---|---|
| 6 | R6 | Gateway缺少IoT代理路由 | router.go |
Gateway未注册IoT设备查询/控制的代理路由,前端无法通过Gateway统一入口访问IoT功能 |
| 7 | R7 | 普通用户登录不验证密码 | auth_handler.go:99-101 |
MVP阶段注释写明"简化逻辑",任意用户名无需密码即可登录获取JWT Token;需实现bcrypt密码哈希验证 |
| 8 | R8 | IoT Client不使用context | iot_client.go:71 |
使用 client.Get() 而非 NewRequestWithContext,无法传递超时/取消信号;IoT服务不可用时调用方会无限阻塞 |
| 9 | R8 | 跨服务HTTP调用无重试/熔断 | Gateway → ai-core / memory-service / tool-engine 等多处 | 所有跨服务HTTP调用均为单次请求,无重试策略、无熔断器、无降级逻辑;下游服务短暂不可用即导致请求失败 |
| 10 | R9 | 登录用户名无输入校验 | auth_handler.go:91 |
用户名接受任意字符包括SQL注入payload ('; DROP TABLE--);虽然使用参数化查询但无长度/字符白名单限制,存在潜在风险 |
🟢 P2 — 中优先级 (4个)
| # | 来源轮次 | 问题 | 文件位置 | 影响 |
|---|---|---|---|---|
| 11 | R6 | Briefing AI摘要降级 | AI-Core /api/v1/briefing/summarize 端点 |
AI-Core返回404时前端无友好降级提示;摘要生成失败静默 |
| 12 | R7 | 前端缺少 multi_message/stream_segments 消息类型 |
types/chat.ts, MessageBubble.tsx |
第6轮引入的子会话架构产生的 MultiMessage 和 StreamEvent 类型在前端无对应渲染组件;多段消息被当作普通文本显示 |
| 13 | R9 | Docker Compose缺少3个服务 | docker-compose.dev.yml, docker-compose.yml |
memory (8091)、tool (8092)、voice (8093) 三个服务未加入Compose编排;无法一键启动完整环境 |
| 14 | R10 | PWA缺少192x192图标 | manifest.json, public/images/ |
PWA manifest中引用的192x192图标文件不存在;影响PWA安装体验 |
🔵 P3 — 低优先级/改进建议 (5个)
| # | 来源轮次 | 问题 | 文件位置 | 影响 |
|---|---|---|---|---|
| 15 | R5 | 2个fire-and-forget goroutine无错误处理 | thinker.go, hub.go |
后台goroutine中的错误仅log.Printf,无告警/重试/降级;出现问题后运维难以发现 |
| 16 | R5 | .gitignore需添加gateway编译产物 | .gitignore |
缺失 backend/gateway/cmd/gateway 条目;已在P0#5中汇总 |
| 17 | R6 | Reminder created_at 为零值 |
reminder_store.go |
创建提醒时未设置 created_at 字段,数据库中为 0001-01-01;影响提醒列表排序和展示 |
| 18 | R9 | voice-service无Dockerfile | voice-service/ |
其他5个Go服务均有Dockerfile,voice-service缺失;无法通过Docker部署 |
| 19 | R9 | Dockerfile Go版本与go.mod不一致 | ai-core/Dockerfile, gateway/Dockerfile 等多处 |
部分Dockerfile使用 golang:1.22 但 go.mod 声明 go 1.26;可能导致编译失败或运行时行为差异 |
三、已验证通过的功能清单
编译验证 (6/6 Go服务 + 1前端)
| 模块 | 命令 | 结果 |
|---|---|---|
backend/ai-core |
go vet ./... |
✅ 通过 |
backend/gateway |
go vet ./... |
✅ 通过 |
backend/iot-debug-service |
go vet ./... |
✅ 通过 |
backend/memory-service |
go vet ./... |
✅ 通过 |
backend/tool-engine |
go vet ./... |
✅ 通过 |
backend/voice-service |
go vet ./... |
✅ 通过 |
frontend/web |
tsc --noEmit |
✅ 通过 |
frontend/web |
vite build |
✅ 构建成功 |
API端点测试 (已验证通过)
- ✅ Gateway 健康检查:
GET /api/v1/health - ✅ 管理员登录:
POST /api/v1/auth/login→ 正确校验密码 - ✅ 错误密码拒绝:
POST /api/v1/auth/login→ 401 - ✅ 创建/列出/获取/删除会话
- ✅ 消息持久化 (分页加载)
- ✅ 管理员端点 (所有会话/活跃会话)
- ✅ Memory-Service 记忆 CRUD + 语义查询 + 合并 + 衰减
- ✅ Tool-Engine 工具列表 (13个工具) + 调用记录 + 统计
- ✅ IoT Debug Service 设备列表 + 属性设置 (8种操作)
- ✅ DevTools 仪表盘 + 数据库管理 + STT日志面板
- ✅ WebSocket 实时通信 + SSE流式降级
- ✅ 前端URL哈希路由 + 会话切换 + 竞态条件修复
架构功能验证
- ✅ 子会话并行分发架构 (IntentAnalyzer → Manager.Dispatch → Synthesizer)
- ✅ 事件驱动自主思考 (
post_chat+silence触发) - ✅ 记忆三层注入 (核心/常用/其他)
- ✅ Gateway代理层 (memory + tool-engine)
- ✅ ai-core HTTP客户端调用外部服务
- ✅ 前端MediaRecorder降级方案 (STT)
- ✅ 前端双重WebSocket修复
- ✅ 数据库模式演化 (ALTER TABLE ADD COLUMN IF NOT EXISTS)
四、统计
| 指标 | 数值 |
|---|---|
| 测试覆盖的API端点 | 30+ |
| 通过的API测试 | 25+ |
| 发现Bug总数 | 19 (P0: 5, P1: 5, P2: 4, P3: 5) |
| Go服务编译 | 6/6 通过 |
| 前端TypeScript编译 | 通过 |
| 前端Vite构建 | 通过 |
| 涉及Go源文件 | 50+ |
| 涉及前端文件 | 20+ |
五、建议优先修复路线
第一阶段: 安全与稳定性 (P0)
- R9-P0#4 — 管理员权限中间件: 修改
router.go:231adminAuth()的HasPrefix检查,使其匹配auth_handler.go:97生成的admin_前缀格式;当前因user_admin格式不匹配导致管理员鉴权完全失效 - R6-P0#1 — Session randomID: 将
session_handler.go:576-582的确定性伪随机替换为crypto/rand或uuid.New() - R8-P0#3 — Goroutine panic recovery: 在
orchestrator.go:81、manager.go:90、manager.go:137三处go func()开头添加defer recover() - R6-P0#2 — TTS fallback: 将
tts_handler.go:55的IsAvailable()检查移除或改为返回特定错误码,让Gatewayvoice_handler.go的fallback逻辑可触发 - R10-P0#5 — 二进制文件清理: 在
.gitignore添加缺失条目并使用git rm --cached移除已追踪的二进制文件
第二阶段: 功能完善 (P1)
- R7-P1#7 — 普通用户密码验证: 在
auth_handler.go:99实现bcrypt密码哈希存储与验证 - R8-P1#8 — IoT Client context传递: 修改
iot_client.go:71使用NewRequestWithContext - R8-P1#9 — HTTP重试/熔断: 引入重试库 (如
go-resiliency) 包装跨服务HTTP调用 - R6-P1#6 — Gateway IoT代理路由: 在
router.go注册IoT代理端点 - R9-P1#10 — 用户名输入校验: 在
auth_handler.go:91添加长度和字符白名单验证
第三阶段: 体验与运维 (P2/P3)
- R9-P2#13 — Docker Compose补全: 在
docker-compose.dev.yml和docker-compose.yml添加 memory/tool/voice 三个服务 - R7-P2#12 — 前端多消息类型渲染: 在
types/chat.ts和MessageBubble.tsx添加multi_message/stream_segments渲染支持 - R10-P2#14 — PWA 192x192图标: 生成并放置缺失的图标文件
- R9-P3#18 — voice-service Dockerfile: 参照其他服务为voice-service创建Dockerfile
- R6-P2#11、R6-P3#17、R9-P3#19、R5-P3#15 — 其余P2/P3项择机修复
六、附录: 各轮次详细发现
第1轮 — 服务间通信与API契约验证
- 发现1: WebSocket
Message结构体缺少ID字段 → 前端React key为空无法渲染 - 发现2:
chat_handler.go缓存消息时未生成ID - 发现3: 前端
sessionStore和useWebSocket缺少消息fallback ID生成 - 发现4: 跨会话切换时旧消息闪现 (缺少
activeSessionRef)
第2轮 — IoT设备控制与工具链验证
- 发现1: AI-Core只注册了
IoTQueryTool未注册控制工具 - 发现2: IoT Debug Service
Toggle()写锁内调用读锁导致死锁
第3轮 — 端到端功能测试与安全验证
- 发现1:
auth_handler.go:89管理员密码错误时静默降级为普通用户 - 发现2: 会话列表查询
user_id匹配方式与存储不一致
第4轮 — LLM思维记忆优化与工具扩展
- 发现1: 记忆表缺少
importance/keywords/source列 → AutoMigrate不自动补列 - 发现2:
iot_tools.go:88fmt.Sprintf格式字符串参数不足 - 发现3: DevTools数据库管理缺少预检和重连机制
第5轮 — 独立服务抽取与调用记录
- 发现1: Gateway代理记忆失败 → 缺少
MEMORY_SERVICE_URL和TOOL_ENGINE_URL环境变量 - 发现2: 前端会话切换3个竞态条件
- 发现3: 二进制文件未被
.gitignore完全覆盖 - 发现4: DevTools
startAllSequential未包含新服务
第6轮 — 多会话架构、自主思考重构与综合Bug修复
- 发现1: 前端双重WebSocket →
ChatContainer.tsx和App.tsx各自调用useChat() - 发现2: Memory-Service数据库迁移失败 →
CREATE TABLE IF NOT EXISTS不补列 - 发现3: 语音STT不可用 → MediaRecorder降级方案
- 发现4: DevTools仪表盘数据库按钮失效 → 缺少
id属性 - 发现5: Session
randomID()确定性输出 (P0#1) - 发现6: TTS fallback不可达 (P0#2)
- 发现7: Gateway缺少IoT代理路由 (P1#6)
- 发现8: Briefing AI摘要降级 (P2#11)
第7轮 — 认证安全与前端消息类型完整性
- 发现1: 普通用户登录不验证密码 (P1#7)
- 发现2: 前端缺少
multi_message/stream_segments消息类型 (P2#12)
第8轮 — 并发安全与跨服务韧性
- 发现1: 编排器/子会话goroutine缺少
defer recover()(P0#3) - 发现2: IoT Client不使用context (P1#8)
- 发现3: 跨服务HTTP调用无重试/熔断 (P1#9)
第9轮 — 部署配置与Docker完整性
- 发现1: 管理员权限中间件逻辑错误 (P0#4)
- 发现2: 登录用户名无输入校验 (P1#10)
- 发现3: Docker Compose缺少3个服务 (P2#13)
- 发现4: voice-service无Dockerfile (P3#18)
- 发现5: Dockerfile Go版本与go.mod不一致 (P3#19)
第10轮 — 编译产物与构建完整性
- 发现1: 40MB编译产物被Git追踪 (P0#5)
- 发现2: PWA缺少192x192图标 (P2#14)
报告由Cyrene持续性调试流程自动生成 — 2026-05-19