(开源项目)x-claw (设计)

xsun_chat 系统架构设计

(本项目主要用于测试新技术开发,包括spec,harness(maker-reviewer),loop engineering)

目录


设计目标

xsun_chat (The Doer) 的核心设计理念是:让 AI 不仅能回答问题,还能自主执行任务。系统围绕以下设计目标构建:

  1. 自主执行 --- AI 自主规划步骤、调用工具、检查结果,无需人工逐步指导
  2. 独立审核 --- 用独立的模型审核执行结果,避免"自己审自己"的盲点
  3. 安全可控 --- 沙盒隔离 + 白名单 + 高危确认,确保 AI 不会误操作系统
  4. 可观测性 --- 全链路 SSE 推送,实时展示思考过程、工具调用、审核进度
  5. 多模式适应 --- Chat 模式处理简单对话,Spec 模式处理复杂多步骤任务
  6. 桌面原生 --- Tauri 轻量壳,Web 端和桌面端共用同一套前后端代码

整体架构

复制代码
┌──────────────────────────────────────────────────────────────┐
│                     Tauri Desktop Shell                       │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │  Rust 原生层                                              │ │
│  │  · 自动检测 Python 解释器                                  │ │
│  │  · spawn 后端子进程 (uvicorn)                             │ │
│  │  · 进程生命周期管理 (窗口关闭 -> kill 后端)                  │ │
│  │  · 轮询 /health 端点等待后端就绪                           │ │
│  └─────────────────────────────────────────────────────────┘ │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │  WebView (Vue 3 SPA)                                     │ │
│  │  ┌──────────┐  ┌──────────────────┐  ┌───────────────┐  │ │
│  │  │  Sidebar  │  │    ChatView      │  │  ContextPanel │  │ │
│  │  │  工作区树  │  │  对话流 + Spec卡片 │  │  阶段/工具/审核│  │ │
│  │  └──────────┘  └──────────────────┘  └───────────────┘  │ │
│  │         Pinia Stores (chat/session/spec/workspace)       │ │
│  │         useSSE composable (Fetch Stream Reader)          │ │
│  └──────────────────────┬──────────────────────────────────┘ │
│                         │ HTTP REST + SSE                     │
│  ┌──────────────────────▼──────────────────────────────────┐ │
│  │              FastAPI Backend (127.0.0.1:8787)            │ │
│  │                                                          │ │
│  │  ┌──────────────────────────────────────────────────┐   │ │
│  │  │                  API 层 (REST + SSE)               │   │ │
│  │  │  /chat/send  /chat/stop  /sessions  /settings     │   │ │
│  │  │  /spec/confirm  /spec/continue  /workspaces       │   │ │
│  │  └──────────────────────┬───────────────────────────┘   │ │
│  │                         │                                │ │
│  │  ┌──────────────────────▼───────────────────────────┐   │ │
│  │  │               Core 编排层                          │   │ │
│  │  │  Orchestrator | SpecOrchestrator                  │   │ │
│  │  │  MakerAgent | ReviewerAgent | Harness             │   │ │
│  │  │  SpecGenerator | LoopEngineer                     │   │ │
│  │  │  ContextManager | PromptBuilder                   │   │ │
│  │  └──────────────────────┬───────────────────────────┘   │ │
│  │                         │                                │ │
│  │  ┌──────────────────────▼───────────────────────────┐   │ │
│  │  │              Harness 基础设施层                    │   │ │
│  │  │  LLMGateway | ToolRegistry | Sandbox | Memory     │   │ │
│  │  └──────────────────────┬───────────────────────────┘   │ │
│  │                         │                                │ │
│  │  ┌──────────────────────▼───────────────────────────┐   │ │
│  │  │           Tools 层 + DB 层                         │   │ │
│  │  │  file_ops / shell / web  |  SQLite + Repository   │   │ │
│  │  └──────────────────────────────────────────────────┘   │ │
│  └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘

通信路径

方向 协议 说明
前端 -> 后端 HTTP REST 会话 CRUD、配置管理、Spec 确认
前端 -> 后端 HTTP POST + SSE 对话消息发送,流式接收事件
Tauri Rust -> 后端 进程管理 spawn/kill Python 进程,轮询 health
后端 -> LLM 供应商 HTTPS (OpenAI SDK) 流式/非流式 LLM 调用
后端 -> 本地文件系统 文件 I/O + 子进程 工具执行(read/write/shell)

后端分层设计

后端采用经典的四层架构,上层依赖下层,下层不感知上层:

1. API 层 (app/api/)

负责 HTTP 请求路由、参数校验、响应格式化。所有 API 通过 router.py 统一注册。

模块 端点 职责
chat.py POST /api/chat/send SSE 流式对话入口,根据 mode 参数路由到 Chat/Spec 编排器
chat.py POST /api/chat/stop 取消当前执行任务
chat.py POST /api/chat/approve 高危操作确认放行
chat.py POST /api/chat/path-access 路径授权决定
chat.py POST /api/chat/export 会话导出:全量消息(含思考链/工具调用/审核卡片)渲染为 Markdown
chat.py POST /api/chat/upload-image 图片上传:浏览器 File 落盘到附件目录(≤8MB)
chat.py GET /api/chat/file-preview 文件预览(附件目录持久授权,重启后仍可读)
chat.py POST /api/chat/open-file 在本地系统中打开输出文件
chat.py GET /api/chat/output-files 查询会话输出文件列表
sessions.py CRUD /api/sessions 会话管理
settings.py GET/PUT /api/settings 全局配置管理 + 工作区设置
workspaces.py CRUD /api/workspaces 多工作区注册与管理
spec.py POST /api/spec/confirm Spec 确认后继续执行
skills.py CRUD /api/skills 技能管理(安装/卸载/代码/进化日志/Hub 配置)
scheduler.py CRUD /api/scheduler/tasks 定时任务管理(创建/启停/补跑/删除)
mcp.py CRUD /api/mcp/servers MCP 服务器管理(注册/刷新/删除)
router.py - API 路由统一注册

关键设计:chat.py 在模块级别维护 _orchestrator 单例和 _current_task 引用,通过 asyncio.Queue 实现编排层到 HTTP 层的事件传递。

2. Core 编排层 (app/core/)

这是系统的核心大脑,包含所有 Agent 和编排逻辑:

组件 职责
Orchestrator Chat 模式编排器:判定复杂度 -> Maker 执行 -> Reviewer 审核 -> 修正重试
SpecOrchestrator Spec 模式编排器:Spec 生成 -> Loop 拆解 -> 逐步执行 + Harness 验证
MakerAgent 执行层 Agent,在单会话上下文中完成 LLM 推理 + 工具调用循环(最多 N 轮)
ReviewerAgent 审核层 Agent,用独立模型审核 Maker 的完整执行轨迹
Harness 单步验证器,在 Spec 模式中对每个 LoopStep 独立验证
SpecGenerator 调用 LLM 流式生成结构化 Markdown Spec 文档
LoopEngineer 将 Spec 文档拆解为可执行的 LoopStep 列表(优先结构化解析,降级 LLM 拆解)
ContextManager 构建 LLM 上下文窗口(系统提示词 + 最近 N 条历史 + 新消息),含上下文完整性校验 :自动修复会话中断导致的 tool_calls ↔ tool 配对损坏
PromptBuilder 所有角色的系统提示词模板(Maker/Reviewer/SpecGenerator/LoopEngineer/Harness),Maker 提示词注入当前工作区路径引导文件生成位置

3. Harness 基础设施层 (app/harness/)

为 Core 层提供可复用的基础能力:

组件 职责
LLMGateway 多供应商统一 LLM 网关,支持流式/非流式调用、429 自动切换、500 重试
ToolRegistry 工具注册中心,管理 Tool 协议实现,提供 OpenAI function calling 格式转换
Sandbox Windows 安全沙盒:路径白名单、Shell 命令黑名单、高危操作识别
Memory 会话记忆管理:历史消息加载、上下文窗口截断、Token 估算

4. Tools 层 + DB 层

组件 职责
registry.py 工具统一注册入口(50+ 个工具)+ 工具分类元数据 + 外挂技能/MCP 动态加载
common.py 路径校验(check_path_access)+ 输出文件追踪(OUTPUT_TOOLS 白名单 + output_file 通用约定)
file_ops.py read_file / write_file / list_directory 工具
file_manager.py copy_file / move_file / delete_file / create_directory / search_files / file_info / append_file
text_tools.py search_in_files / replace_in_file / diff_files 文本搜索替换
documents.py Excel/Word/CSV/PDF/PPT 读写(openpyxl / python-docx / pypdf / fpdf2 / python-pptx,惰性导入)
image_tools.py convert_image / image_info 图片处理(Pillow)
archive_tools.py zip_files / unzip_file 压缩解压
code_tools.py run_python / git_operation 开发工具
git_tools.py git_commits 提交历史查询
shell.py execute_shell 工具(PowerShell,含沙盒校验)
web.py web_fetch 工具(httpx 异步 HTTP 客户端)
web_tools.py web_search(DuckDuckGo)/ download_file 下载
jira_tools.py jira_unfinished_issues / jira_worklogs / jira_log_work Jira 集成
system_tools.py calculator / get_datetime / clipboard / system_info
database.py SQLite 连接管理(WAL 模式),支持工作区隔离 + 中央注册表
repository.py 数据访问层,封装所有 CRUD 操作

高危工具(delete_file / move_file / replace_in_file / git_operation 写操作 / 高危 Shell)通过 needs_approval 挂起执行,前端弹窗确认后经 POST /api/chat/approve 放行,Maker 以 _approved=True 重新调用该工具完成实际执行。

5. Skills 层(外挂技能系统,app/skills/

统一技能框架,支持三种技能来源并存:内置工具 (静态 import)、外挂技能~/.xsun_chat/skills/installed/ 动态加载)、MCP 工具 (远程服务器)。外挂技能与内置工具实现同一 Tool 协议,对 Maker 透明。

组件 职责
models.py SkillMeta(skill.json 协议)/ HubSkillInfo / EvolutionRecord 数据模型
security.py AST 静态安全扫描:模块黑名单(subprocess/socket/ctypes 等)、危险调用(eval/exec/os.system)、反射属性(__globals__ 等)+ Tool 协议校验
loader.py importlib 动态加载,独立模块命名空间(xsun_skill_*),支持热重载(清除 __pycache__ 防止秒级 mtime 缓存穿透),skill.json 为注册键唯一权威来源
manager.py 生命周期管理单例:安装(zip/源码)/ 卸载 / 版本备份(.versions/,保留最近 5 版)/ 进化日志(evolution_log.json,保留 500 条)
auto_route.py 技能协作路由引擎:解析式路由确定性优先 (解析 main.py 代码引用 / description 关系词 / SKILL.md 依赖字段),LLM 仅作兜底;create_skills_batch 批量创建后自动写回显式路由
hub_client.py SkillHub 客户端:{hub_url}/index.json 索引协议,支持 http(s) 静态托管与本地目录两种 Hub,SHA256 校验,搜索/下载/安装
self_mod.py 自修改引擎:创建/修改流水线(验证 → 安装 → 试加载 → 热注册到当前 ToolRegistry),修改失败自动回滚
builtin_tools.py Agent 可调用的 6 个技能管理工具:create_skill / modify_skill / delete_skill / list_skills / search_skill_hub / install_skill_from_hub

技能包结构skill.json + main.py):

复制代码
data/skills/                  # 应用数据根目录(<安装目录或项目根>/data)
├── installed/<name>/
│   ├── skill.json      # 元数据:name/version/description/category/parameters_schema/sandbox_required
│   ├── main.py         # Tool 协议实现(入口类自动探测或 entry_class 指定)
│   └── .versions/      # 历史版本备份(自动滚动保留 5 版)
├── cache/              # Hub 下载缓存
└── evolution_log.json  # 自进化日志

自进化闭环 :Maker 发现工具缺失 → search_skill_hub 查 Hub(可安装)→ 或 create_skill 生成代码 → 安全扫描 + 协议校验 → 用户审批(skill_auto_install=false 时)→ 写入技能目录 → 热注册到当前 ToolRegistry → 同一会话下一次 LLM 调用即可用to_openai_tools() 每迭代重建)。安全双保险:安装期 AST 静态扫描 + 运行时 Sandbox 路径白名单。

SkillHub 协议 :静态托管友好(GitHub Raw / 任意静态服务器 / 本地目录),index.json 含技能列表与 download_url(相对/绝对)、SHA256;项目内 hub/ 目录为示例 Hub(python hub/build_hub.py 打包并生成索引)。

APIGET /api/skills(已安装列表)、GET/PUT /api/skills/hub-configGET /api/skills/hub/searchPOST /api/skills/hub/installPOST /api/skills/install-localGET /api/skills/{name}/codePOST /api/skills/{name}/reloadDELETE /api/skills/{name}GET /api/skills/evolution-log

Hub 多协议 :客户端自动探测协议------xsun 格式(index.json,可安装)与 ClawHub 格式(/api/v1/skills,OpenClaw 官方仓库,其技能为指令格式与 xsun 工具不兼容,仅浏览)。默认 Hub 为项目自带 hub/ 目录(开箱即用)。

6. Scheduler 层(定时任务系统,app/scheduler/

组件 职责
cron.py 5 段 cron 解析器(* */n a-b a-b/n 列表,周日 0/7 归一,POSIX 日周规则)+ next_run 计算 + describe_cron 人类可读描述
models.py ScheduledTask:name/prompt/cron/workspace_path/enabled/运行状态
store.py JSON 持久化(data/scheduled_tasks.json,原子写入),CRUD + 运行结果记录(自动推进 next_run_at)
engine.py asyncio 后台循环(15s tick):到期触发 → 工作区匹配检查 → 繁忙错峰(推迟 60s,上限 30min)→ 无头执行 Maker(新会话 ⏰ {name})→ 记录结果;随 FastAPI lifespan 启停,串行执行
builtin_tools.py Agent 工具:create_scheduled_task / list_scheduled_tasks / delete_scheduled_task / run_scheduled_task_now(写操作需审批)

无头执行语义:注入"无用户交互"前缀引导 AI 非交互执行;工作区未打开时标记 skipped;需要审批的操作等待 5 分钟后自动拒绝(安全网)。APIGET/POST /api/scheduler/tasksPOST /api/scheduler/tasks/{id}/togglePOST /api/scheduler/tasks/{id}/runDELETE /api/scheduler/tasks/{id}


双模式执行架构

系统支持两种执行模式,共享同一套 LLM 网关和工具系统:

Chat 模式数据流

复制代码
用户消息
  │
  ▼
Orchestrator.run(session_id, user_message, event_queue)
  │
  ├─ 1. 保存用户消息到 DB
  │
  ├─ 2. _should_review() 判断审核需求
  │     ├─ "never" -> 跳过审核
  │     ├─ "always" -> 始终审核
  │     └─ "complex_only" -> 执行后判断:命中关键词 或 实际调用了写文件类工具
  │
  ├─ 3. MakerAgent.run()
  │     ├─ ContextManager.build_context() -> messages[]
  │     │   └─ 上下文完整性校验:修复中断导致的 tool_calls 配对损坏
  │     └─ for iteration in range(max_loop_iterations):
  │           ├─ llm.chat_stream(messages, tools) -> SSE 事件流
  │           ├─ if tool_calls: 执行工具 -> 结果追加到 messages
  │           │   └─ execute_shell/run_python: 工作区快照差异检测 -> 登记新增文件
  │           └─ else: 最终回复 -> return MakerResult
  │
  ├─ 4. if needs_review: ReviewerAgent.review()
  │     ├─ 构建审核内容(用户目标 + 执行轨迹 + 最终输出)
  │     ├─ llm.chat(review_messages, reviewer_model, temp=0.3)
  │     ├─ _parse_review() -> ReviewResult (passed/score/issues/feedback)
  │     ├─ _persist_review() -> 持久化审核结果(所有分支均落库)
  │     └─ if not passed: 修正重试(最多 1 轮)
  │
  └─ 5. event_queue -> SSE -> 前端

Spec 模式数据流

复制代码
用户消息 (mode="spec")
  │
  ▼
SpecOrchestrator.run_spec_mode()
  │
  ├─ Phase 1: SpecGenerator.generate()
  │     ├─ llm.chat_stream(messages, maker_model) -> 流式 Markdown
  │     ├─ 保存 Spec 到 DB (status=draft)
  │     ├─ 保存 spec_card 消息(metadata.type="spec_card")
  │     └─ 发送 spec_ready 事件 -> SSE 连接断开,前端展示 Spec 卡片
  │
  ▼ (用户点击「确认执行」,调用 POST /api/spec/confirm)
  │
SpecOrchestrator.continue_after_confirmation()
  │
  ├─ Phase 2: 更新 Spec status=confirmed
  │
  ├─ Phase 3: LoopEngineer.decompose()
  │     ├─ 优先:_parse_spec_markdown() 正则匹配 "### 步骤X: 标题" 格式
  │     └─ 降级:_llm_decompose() 调用 LLM 输出 JSON
  │
  └─ Phase 4: _execute_loop_steps()
        for each LoopStep:
          ├─ MakerAgent.run(step_description) -> MakerResult
          ├─ Harness.verify(step, maker_result) -> HarnessResult
          ├─ if not passed: 注入反馈 -> 重试(最多 2 次)
          └─ 保存 HarnessResult 到 DB

降级策略总结

场景 降级策略
Spec 生成失败 降级为普通 Chat 模式
Loop 拆解失败(结构化+LLM 都失败) 返回单步骤"执行任务"
Harness 验证失败 重试 2 次后标记 failed,不阻塞后续步骤
Reviewer 调用失败 降级为"通过"(score=80)
LLM 429 限流 自动切换备用供应商

SSE 事件系统

系统采用 asyncio.Queue 作为编排层到 HTTP 层的事件总线,所有事件通过 SSE 推送到前端。

事件类型一览

事件类型 触发时机 前端处理
phase 阶段切换 (executing/reviewing/correcting/spec_generating/loop_decomposing) 更新阶段指示器
thinking Maker 开始新一轮推理 展开思考链
thinking_delta LLM 推理过程流式文本片段 追加到思考链(重启后从历史恢复)
text_delta LLM 流式输出文本片段 追加到 streamedContent
tool_call_start 工具调用开始 创建 ToolCall 条目
tool_call_result 工具调用完成 更新 ToolCall 结果
approval_needed 高危操作需确认 弹出确认对话框
path_access_needed 路径未在白名单,需用户授权 弹出路径授权对话框
output_file 输出文件被登记(路径+工具名) 添加到右上角输出面板
review_start Reviewer 开始审核 显示审核中状态
review_result Reviewer 审核完成 渲染审核结果卡片
done Chat 模式执行完成 保存 AssistantMessage,清理状态
error 发生错误 保存错误消息
spec_delta Spec 文档流式生成 追加到 SpecStore
spec_ready Spec 生成完毕 展示 Spec 卡片,断开 SSE
loop_steps_ready Loop 拆解完成 填充 SpecViewer 步骤列表
loop_step_start 单步执行开始 高亮当前步骤
loop_step_result 单步执行结果 更新步骤状态 (passed/failed)
loop_step_retry 单步重试 显示重试信息
harness_result Harness 验证完成 显示验证分数
loop_complete Loop 全部完成 显示执行摘要

事件流架构

复制代码
┌─────────────┐     asyncio.Queue     ┌──────────────┐     SSE      ┌──────────┐
│  Core 编排层  │ ──────────────────> │  API 层       │ ──────────> │  前端     │
│  (Producer)  │   event_queue.put()  │  (Consumer)   │  text/stream│  (Reader) │
└─────────────┘                      └──────────────┘             └──────────┘
                                             │
                                     asyncio.create_task()
                                     _current_task 管理
                                     支持取消 (task.cancel())

关键设计点:

  • 异步解耦 :编排层通过 event_queue.put() 生产事件,API 层通过 event_queue.get() 消费并格式化为 SSE
  • 超时保护asyncio.wait_for(event_queue.get(), timeout=300) 防止死等
  • 取消机制_current_task 全局引用支持 POST /chat/stop 取消运行中的任务
  • Spec 模式特殊处理 :收到 spec_ready 后主动 break 断开 SSE,等待用户确认后重新连接

前端 SSE 消费

复制代码
useSSE.connect()
  │
  ├─ fetch(POST /chat/send, body:{session_id, content, mode})
  ├─ response.body.getReader() 逐块读取
  ├─ 解析 "data: {json}\n\n" 格式
  └─ handleEvent() -> handlers 回调
       ├─ onTextDelta -> chatStore.streamedContent += content
       ├─ onToolCallStart -> chatStore.currentToolCalls.push(...)
       ├─ onSpecReady -> specStore.setSpecReady() + isGenerating=false
       ├─ onLoopComplete -> specStore.setLoopComplete() + save message
       └─ onDone -> 保存 AssistantMessage + cleanup()

图片消息与多模态

对话支持发送图片附件(选择文件 / 拖拽 / 粘贴截图),并利用支持视觉的 LLM 理解图片内容。

附件上传与持久授权

组件 说明
POST /api/chat/upload-image 浏览器场景(DOM File 无绝对路径):校验扩展名白名单(png/jpg/gif/bmp/webp/ico)与大小(≤8MB),落盘到 <data_root>/attachments/<session_id>/(UUID 命名),返回绝对路径
POST /api/chat/send (attachments) Tauri 场景附件为本地绝对路径,直接放入 attachments 字段,沙盒对本会话授权读写
GET /api/chat/file-preview 附件目录前缀匹配规则:<data_root>/attachments/<session_id>/ 下的文件持久授权(替代内存授权,后端重启后历史图片仍可预览);其余路径走沙盒校验 + 输出文件判定

多模态上下文构建

  • _model_supports_vision(model):关键词检测视觉能力(gpt-4o / vision / -vl / gemini / claude / glm-4v / qwen-vl / llama-3.2 等)
  • _build_image_data_urls(attachments):将图片附件读取并转为 base64 data URL(单张 ≤4MB)
  • ContextManager._build_user_message:构造 OpenAI 多模态 content 数组(text + image_url),仅当模型支持视觉时启用

前端展示

  • InputBox:附件按钮(Tauri 文件对话框 / 浏览器隐藏 file input)、拖拽上传、粘贴截图(clipboardData)
  • FileRefCard:图片路径自动渲染缩略图(previewUrl),点击放大预览
  • AI 输出图片(工具产物)同样以缩略图展示
  • useApi.tsBASE_URL:Tauri 环境 http://127.0.0.1:8787/api,浏览器环境 /api(Vite 代理)

数据库设计

ER 图

复制代码
┌──────────┐       ┌──────────┐       ┌──────────┐
│ sessions │ 1───N │ messages │       │task_runs │
│          │       │          │       │          │
│ id       │       │ id       │       │ id       │
│ title    │       │session_id│       │session_id│
│ mode     │       │ role     │       │ goal     │
│workspace │       │ content  │       │ status   │
│_path     │       │ metadata │       │plan      │
│created_at│       │created_at│       │review_   │
│updated_at│       └──────────┘       │result    │
└──────────┘                          └──────────┘

┌──────────┐       ┌──────────┐       ┌────────────────┐
│  specs   │ 1───N │loop_steps│ 1───N │harness_results │
│          │       │          │       │                │
│ id       │       │ id       │       │ id             │
│session_id│       │ spec_id  │       │ step_id        │
│ title    │       │session_id│       │ passed         │
│raw_      │       │step_index│       │ score          │
│markdown  │       │ title    │       │ feedback       │
│ status   │       │description│      │ details(JSON)  │
│created_at│       │expected_ │       │ created_at     │
│updated_at│       │output    │       └────────────────┘
└──────────┘       │ status   │
                   │max_retries│
                   │depends_on│
                   │retry_count│
                   │error_msg │
                   └──────────┘

中央注册表(独立数据库 workspaces.db):
┌────────────┐
│ workspaces │
│            │
│ path (PK)  │
│ name       │
│ created_at │
│last_opened │
│_at         │
└────────────┘

关键表说明

用途 关键字段
sessions 会话记录 mode (chat/spec), workspace_path
messages 消息历史 metadata (JSON: tool_calls, tool_call_id, type=spec_card)
task_runs 任务执行记录 plan (Spec 内容), review_result (审核 JSON)
specs Spec 文档 raw_markdown, status (draft/confirmed)
loop_steps Loop 执行步骤 status (pending/running/passed/failed), depends_on
harness_results 单步验证结果 score, details (issues JSON)
workspaces 工作区注册表 path (PK), last_opened_at

数据库隔离策略

所有应用数据(配置、定时任务、技能、日志、数据库)统一存放在应用数据根目录 data/

(开发模式:<backend 项目根>/data/;打包安装版:<安装目录>/data/

旧版 ~/.xsun_chat 数据在首次启动时自动迁移并清理):

  • 全局配置data/config.json (JSON 文件)
  • 工作区注册表data/central/xsun_chat_central.db (中央 SQLite)
  • 会话数据data/workspaces/<文件夹名>_<路径哈希>/xsun_chat.db (每工作区独立)
  • 切换工作区config.set_workspace(path) 会同时更新 workspace_pathdb_dir,后端自动连接对应数据库

前端架构

技术栈

类别 技术 说明
框架 Vue 3 (Composition API) <script setup lang="ts">
语言 TypeScript (strict) 全量类型定义
状态管理 Pinia 6 个 Store (chat/session/spec/workspace/settings/taskflow)
路由 Vue Router 4 / (主页), /setup (向导), /settings (设置)
HTTP Fetch API SSE 流读取 + REST JSON
Markdown markdown-it 代码高亮 (highlight.js) + 数学公式 (KaTeX/texmath)
样式 CSS Variables 玻璃拟态暗色主题 (glassmorphism.css)
桌面壳 Tauri 2.x WebView + Rust 进程管理

组件树

复制代码
App.vue
├── AppLayout.vue
│   ├── Sidebar.vue
│   │   ├── 工作区列表(树形结构)
│   │   ├── 会话列表(按工作区分组)
│   │   └── 底部操作按钮(设置/新建)
│   ├── ChatView.vue
│   │   ├── MessageBubble.vue (用户/AI 消息)
│   │   │   ├── SpecCard.vue (Spec 卡片)
│   │   │   ├── TaskFlowCard.vue (工具调用卡片)
│   │   │   ├── ThinkingChain.vue (思考链)
│   │   │   ├── ToolCallLog.vue (工具调用日志)
│   │   │   └── ReviewResultCard.vue (审核结果)
│   │   ├── MarkdownRenderer.vue
│   │   └── InputBox.vue (输入框 + 模式切换)
│   └── ContextPanel.vue
│       ├── 当前阶段指示器
│       ├── 工具调用统计
│       ├── 审核结果摘要
│       └── SpecViewer.vue (Spec 进度追踪)
└── SetupWizard.vue (首次配置向导)

状态管理 (Pinia Stores)

复制代码
stores/
├── chat.ts       # 核心对话状态
│   ├── messages, isGenerating, currentPhase
│   ├── streamedContent, currentToolCalls, currentReview
│   ├── thinkingChain (思考链)
│   ├── sendMessage() -> SSE 连接 + 事件处理
│   ├── stopGeneration() -> abort + 保存中断消息
│   └── loadHistory() -> 从 DB 恢复消息 + Spec 状态
│
├── session.ts    # 会话列表管理
│   └── sessions[], createSession(), renameSession(), deleteSession()
│
├── spec.ts       # Spec 模式状态
│   ├── currentSpec, loopSteps, isGenerating
│   ├── setSpecReady() -> 展示 Spec 卡片
│   ├── appendSpecContent() -> 流式追加 Spec 内容
│   ├── setLoopSteps() -> 填充步骤列表
│   └── updateStepStatus() -> 更新每步状态
│
├── workspace.ts  # 多工作区管理
│   └── workspaces[], currentWorkspace, switchWorkspace()
│
├── settings.ts   # 全局配置状态
│   └── config, saveConfig(), testConnection()
│
└── taskflow.ts   # 任务流可视化
    └── 当前任务步骤、工具调用日志

数据流 (单向)

复制代码
用户输入 -> InputBox.vue
  │
  ▼
chatStore.sendMessage(content, mode)
  │
  ├─ 添加 UserMessage 到 messages[]
  ├─ 设置 isGenerating=true
  ├─ useSSE.connect(sessionId, content, handlers, mode)
  │     │
  │     ├─ fetch POST /api/chat/send
  │     ├─ reader.read() 循环
  │     └─ handleEvent(event, handlers)
  │           │
  │           ├─ onTextDelta -> streamedContent (响应式)
  │           ├─ onToolCallStart -> currentToolCalls[]
  │           ├─ onSpecReady -> specStore (跨 Store)
  │           ├─ onLoopStepResult -> specStore.updateStepStatus()
  │           └─ onDone -> 构建 AssistantMessage -> messages[]
  │
  └─ cleanup() -> isGenerating=false

安全设计

沙盒三层防御

复制代码
用户请求
  │
  ▼
第一层: 路径白名单 (Sandbox.validate_path)
  ├─ 默认仅允许用户主目录
  ├─ 禁止系统目录 (C:\Windows, C:\Program Files, ...)
  ├─ 禁止 UNC 网络路径
  ├─ 可通过 sandbox_allowed_dirs 扩展
  └─ 工作区路径自动加入白名单
  │
  ▼
第二层: Shell 命令黑名单 (Sandbox.validate_shell_command)
  ├─ 拦截危险命令: Remove-Item -Recurse, Format-Volume,
  │   diskpart, reg delete, bcdedit, ...
  └─ 拦截编码命令: powershell -EncodedCommand
  │
  ▼
第三层: 高危操作确认 (Sandbox.needs_approval)
  ├─ write_file 覆盖已有文件 -> 弹窗确认
  ├─ execute_shell 含 Remove-Item/del/rmdir/move -> 弹窗确认
  └─ 确认超时 (300s) 自动拒绝
  │
  ▼
第四层: 路径访问授权 (API path-access)
  ├─ 工具首次访问白名单外路径时,弹出授权对话框
  ├─ 用户可选择"允许本次" / "加入白名单" / "拒绝"
  └─ 授权决策通过 SSE approval_needed 事件推送到前端

LLM 网关容错

复制代码
LLM 调用
  │
  ├─ 400 Bad Request
  │   └─ 含 "context_length" -> 抛出 LLMContextLengthError
  │       -> ContextManager 截断历史后重试
  │
  ├─ 429 Rate Limit
  │   └─ 自动查找备用供应商 -> 切换重试
  │
  ├─ 500 Server Error
  │   └─ 重试 2 次(间隔 1s, 3s)
  │
  └─ 超时 (60s connect, 10s read)
      └─ 通知前端并取消

上下文完整性保护

ContextManager.build_context() 在构建 LLM 上下文时执行双向修复:

  1. 缺失 tool 响应 :assistant 消息含 tool_calls 但缺少对应 tool 消息 → 注入占位 [执行被中断] 消息
  2. 孤儿 tool 消息tool 消息的 tool_call_id 找不到对应 tool_calls → 移除该消息

这确保了会话中断/窗口截断后,OpenAI API 的 tool_calls ↔ tool 严格配对要求始终满足。

配置安全

  • API Key 存储在 data/config.json(应用数据根目录,已被 .gitignore 排除),不提交到版本控制
  • 配置修改通过 API 层校验(maker/reviewer 的 provider 必须在 providers 列表中)
  • Sandbox 白名单通过配置动态更新,无需重启

LLM 网关设计

多供应商架构

复制代码
LLMGateway
  │
  ├─ _clients: dict[str, AsyncOpenAI]
  │   ├─ "deepseek" -> AsyncOpenAI(base_url="https://api.deepseek.com")
  │   ├─ "openai"   -> AsyncOpenAI(base_url="https://api.openai.com/v1")
  │   ├─ "qwen"     -> AsyncOpenAI(base_url="https://dashscope.aliyuncs.com/...")
  │   └─ "custom"   -> AsyncOpenAI(base_url=任意 OpenAI 兼容地址)
  │
  ├─ _provider_map: dict[str, LLMProviderConfig]
  │   └─ 每个供应商的默认模型名
  │
  └─ 角色模型解析:
      ├─ get_maker_config() -> (client, model, temperature=0.7)
      └─ get_reviewer_config() -> (client, model, temperature=0.3)

流式处理 (chat_stream)

复制代码
async for chunk in llm.chat_stream(messages, tools, provider, model, temp):
    │
    ├─ client.chat.completions.create(stream=True, stream_options={include_usage:True})
    │
    └─ _process_stream(stream):
        async for chunk in stream:
          ├─ delta.content -> yield LLMStreamChunk(type="text_delta", content=...)
          └─ delta.tool_calls -> 缓冲拼接 arguments
              └─ finish_reason="tool_calls" -> yield LLMStreamChunk(type="tool_call", ...)

关键设计:

  • tool_calls 流式拼接 :OpenAI 流式 API 会将 tool call 的 arguments 分多个 chunk 发送,需要在 _process_stream 中按 index 缓冲拼接
  • 空 tool_calls 过滤ContextManager.build_context() 恢复历史消息时,仅当 tool_calls 非空数组时才附加该字段(OpenAI API 不允许空数组)
  • spec_card 消息过滤 :构建上下文时跳过 metadata.type="spec_card" 的消息(content 为空,不应参与 LLM 推理)

调用模式对比

特性 chat() 非流式 chat_stream() 流式
使用场景 Reviewer/Harness/LoopEngineer Maker/SpecGenerator
429 处理 切换备用供应商重试 切换备用供应商重试
500 处理 重试 2 次 重试 2 次
返回类型 LLMResponse AsyncGenerator[LLMStreamChunk]

Tauri 桌面集成

架构

复制代码
Tauri 应用启动
  │
  ├─ lib.rs: run()
  │   ├─ resolve_backend_dir()
  │   │   ├─ 生产模式: exe_dir/../backend/ (sidecar)
  │   │   └─ 开发模式: src-tauri/../../backend/
  │   │
  │   ├─ launch_backend()
  │   │   ├─ find_python() (查找 python/python3/py)
  │   │   └─ Command::new(python).args(["-m","uvicorn","app.main:app",...])
  │   │       .current_dir(backend_dir).spawn()
  │   │
  │   ├─ app.manage(BackendProcess(Mutex<Option<Child>>))
  │   │   └─ Drop 时自动 kill 后端进程
  │   │
  │   └─ tauri::async_runtime::spawn(wait_for_backend_ready())
  │       └─ 轮询 http://127.0.0.1:8787/health (最多 15s)
  │
  └─ 加载 WebView (Vue 3 SPA)

前后端通信

typescript 复制代码
// useApi.ts 自动检测环境(window.isTauri / __TAURI_INTERNALS__)
const BASE_URL = isTauriEnv()
  ? 'http://127.0.0.1:8787/api'  // Tauri 桌面模式(无 Vite 代理,需完整地址)
  : '/api'                        // 浏览器开发模式(Vite 代理 /api 到后端)

打包模式

模式 说明 产物
开发 (tauri:dev) Tauri 自动管理前后端进程 桌面窗口 + 热重载
系统 Python (tauri:build) 依赖用户 Python 环境 .msi / .nsis.exe
PyInstaller (build_exe.py) Python 编译为独立 exe 独立 .exe (无需 Python)

关键技术决策

1. 为什么 Maker 和 Reviewer 必须用不同模型?

同一个 LLM 审核自己的输出存在系统性盲点------它倾向于认为自己的推理是正确的。通过引入独立的 Reviewer 模型(不同供应商或不同模型),实现了真正的交叉验证。这是系统最核心的设计理念。

2. 为什么使用 SSE 而非 WebSocket?

  • 单向推送:系统只需要服务端推送到前端,不需要前端频繁向服务端发消息
  • 更简单的实现:SSE 基于 HTTP,无需额外的握手协议
  • 更好的兼容性:SSE 在 Tauri WebView 中无需特殊配置
  • 取消机制 :通过 AbortControllerasyncio.Task.cancel() 实现优雅取消

3. 为什么 Chat 和 Spec 是两个独立的 Orchestrator?

Chat 模式强调"快速响应 + 整体审核",而 Spec 模式强调"精细控制 + 逐步验证"。两者的执行流程、事件类型和用户体验完全不同。分离为两个 Orchestrator 避免了代码中大量的 if-else 分支,各自独立演进。

4. 为什么 LoopEngineer 优先用正则解析而非 LLM?

  • 确定性 :Spec 格式由 SpecGenerator 的 prompt 控制,输出格式稳定
  • 速度:正则解析是 O(n) 的,无需网络调用
  • 成本:避免为拆解步骤额外消耗 token
  • 降级保障:仅在正则无法匹配时降级为 LLM 拆解

5. 为什么选择 SQLite + WAL 模式?

  • 零配置:无需安装数据库服务,符合桌面应用定位
  • WAL 模式:支持并发读(一个写 + 多个读),满足 SSE 推送时的并发需求
  • 工作区隔离 :每个工作区独立的 .db 文件,天然支持数据隔离和备份
  • 体积小:无需引入 PostgreSQL/MySQL 等重型依赖

6. 降级优先的设计哲学

系统在多个层面实现了降级策略:

  • Reviewer 故障 -> 降级通过,不阻塞执行
  • Harness 故障 -> 降级通过,不阻塞 Loop
  • Spec 生成失败 -> 降级为 Chat 模式
  • Loop 拆解失败 -> 降级为单步骤
  • LLM 限流 -> 自动切换备用供应商

核心理念:审核层/验证层的故障不应该阻塞执行层,用户始终能得到结果(附带降级说明)。

7. 为什么 Tauri 而非 Electron?

  • 包体积:Tauri 应用 < 10MB(不含 Python 后端),Electron 通常 > 100MB
  • 内存占用:Tauri 使用系统 WebView,比内嵌 Chromium 轻量
  • Rust 安全性:进程管理和系统调用利用 Rust 的内存安全保证
  • Python 后端独立性:后端和前端完全解耦,可独立升级或替换
相关推荐
Cicada1282 小时前
ccvt:一个用 Rust 写的中国地图坐标系互转命令行工具
开发语言·后端·rust
奈斯先生Vector2 小时前
2026 大模型 API 路由与基础设施效能深度评测:从开源中继方案到企业级智能调度选型指南
开源
only-qi2 小时前
美的AI Agent面试题的解析与思考
人工智能·ai·llm·agent·react
谢尔登2 小时前
分享一些我常用的Skill
java·人工智能·python·actionscript
科里 Coralyx3 小时前
评测凭什么成为模型护城河:Agent评测的跨厂机制分析
大数据·人工智能·ai
k4m7v2pz3 小时前
macOS 解压 40GB 分卷+中文密码固件镜像的五个深坑与解决方案
python·7-zip·aes加密·踩坑记录·r36s·多卷zip解压
9527出列3 小时前
tumrs简要流程分析(一)—Gateway 启动流程
开源
小白学大数据3 小时前
Python 爬虫实战:抓取汽车之家二手车成交价格与里程数据
开发语言·爬虫·python·汽车
Source.Liu3 小时前
【Uppsala】介绍
xml·rust