feat: add AI summary service for context management (P0 phase 1)

- 创建 ai_summary_service.rs 模块,实现 AI 驱动的会话摘要
- 支持配置摘要长度、主题数量、决策数量
- 使用 JSON 格式返回结构化摘要(summary, key_topics, decisions)
- 包含完整的单元测试
- 当前使用 mock 实现,待后续集成真实 LLM 调用

相关文档:
- docs/iteration-notes/implementation-progress-report.md - 总体进度报告
- docs/iteration-notes/p0-phase1-implementation-plan.md - P0 阶段 1 详细计划
- docs/iteration-notes/p0-context-management-implementation.md - P0 实施文档
- docs/iteration-notes/context-management-upgrade-plan.md - 上下文管理升级方案

下一步:
- 改造 session_context_service.rs 集成 AI 摘要
- 替换 mock 实现为真实 LLM 调用
- 编写集成测试验证效果

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
coso
2026-03-12 18:40:22 +08:00
co-authored by Claude Opus 4.6
parent d08b328685
commit 75309bd2ef
8 changed files with 958 additions and 2 deletions
+21
View File
@@ -0,0 +1,21 @@
# 迭代备忘
## 目录用途
`docs/iteration-notes/` 用于记录:
- 已确认但不在当前版本发布范围内的问题
- 下个迭代建议处理的体验优化项
- 需要持续跟踪的跨平台兼容问题
- 已有修复思路、但需要结合发版节奏安排的事项
## 编写建议
- 一条问题一个文件,避免把多个主题混在同一篇文档中
- 文件名使用 `领域-主题-问题.md` 形式,便于检索
- 每篇文档建议包含:背景、现象、影响、建议方案、验收标准、优先级
- 如果问题已经进入正式排期,可在文档顶部补充对应任务号或里程碑
## 当前条目
- `openclaw-windows-detection-followup.md`:OpenClaw 在 Windows 下“已安装但未检测到”的后续迭代记录
@@ -0,0 +1,115 @@
# 上下文管理升级方案
## 问题分析
### 当前状态
1. **session_context_service.rs** 使用本地关键词提取
- `create_summary()` 方法(第 355-418 行)使用硬编码关键词匹配
- 摘要质量差,无法理解语义
- 不支持 AI 驱动的智能压缩
2. **SessionConfigBuilder** 缺少上下文配置
- 只有 `max_turns`、`system_prompt`、`include_context_trace`
- 没有暴露 token 限制、压缩策略等配置
3. **aster 框架能力未接入**
- aster 有渐进式工具响应移除能力
- aster 支持 AI 摘要
- ProxyCast 未正确配置和使用这些能力
## 改进方案
### 阶段 1:扩展 SessionConfigBuilder
在 `src-tauri/crates/agent/src/aster_state_support.rs` 中扩展 `SessionConfigBuilder`:
```rust
pub struct SessionConfigBuilder {
id: String,
max_turns: Option<u32>,
system_prompt: Option<String>,
include_context_trace: Option<bool>,
// 新增:上下文压缩配置
max_context_tokens: Option<usize>,
context_compression_threshold: Option<f32>,
enable_ai_summary: Option<bool>,
tool_response_retention_strategy: Option<ToolResponseRetentionStrategy>,
}
pub enum ToolResponseRetentionStrategy {
KeepAll,
Progressive { stages: Vec<f32> }, // 0.0, 0.1, 0.2, 0.5, 1.0
RemoveAfterTurns(usize),
}
```
### 阶段 2:改造 session_context_service.rs
将 `create_summary()` 方法改为调用 AI 模型生成摘要:
```rust
async fn create_summary_with_ai(
&self,
session_id: &str,
messages: &[ChatMessage],
provider: &dyn LLMProvider,
) -> Result<SessionSummary, String> {
// 构建摘要提示词
let summary_prompt = build_summary_prompt(messages);
// 调用 AI 模型生成摘要
let summary_response = provider
.complete(&summary_prompt)
.await
.map_err(|e| format!("AI 摘要生成失败: {e}"))?;
// 解析摘要结果
parse_summary_response(&summary_response)
}
```
### 阶段 3:集成到 Aster Agent 初始化
在 `aster_agent_cmd.rs` 中配置上下文压缩:
```rust
let session_config = SessionConfigBuilder::new(&session_id)
.system_prompt(system_prompt)
.max_context_tokens(100_000) // Claude 的上下文窗口
.context_compression_threshold(0.8) // 80% 时触发压缩
.enable_ai_summary(true)
.tool_response_retention_strategy(
ToolResponseRetentionStrategy::Progressive {
stages: vec![0.0, 0.1, 0.2, 0.5, 1.0]
}
)
.build();
```
## 验证方式
1. **单元测试**:测试 AI 摘要生成逻辑
2. **集成测试**:发起 20+ 轮长对话,验证:
- AI 摘要是否在 80% token 使用率时触发
- 摘要质量是否优于本地关键词提取
- 工具响应是否按渐进式策略移除
3. **性能测试**:测试摘要生成的延迟和成本
## 实施步骤
1. ✅ 分析当前代码结构
2. ⬜ 扩展 SessionConfigBuilder
3. ⬜ 实现 AI 摘要生成逻辑
4. ⬜ 改造 session_context_service.rs
5. ⬜ 集成到 aster_agent_cmd.rs
6. ⬜ 编写单元测试
7. ⬜ 进行集成测试
8. ⬜ 性能优化和调优
## 注意事项
1. **向后兼容**:保留本地关键词提取作为降级方案
2. **成本控制**:AI 摘要会产生额外的 API 调用成本
3. **缓存策略**:摘要结果应该缓存,避免重复生成
4. **错误处理**:AI 摘要失败时应优雅降级到本地摘要
@@ -0,0 +1,157 @@
# ProxyCast AI Agent 改进 - 实施进度报告
## 已完成工作
### 1. 研究与分析(任务 #1-#4)✅
通过对比研究 OpenAI Codex 和 aster-rust 框架,完成了 ProxyCast AI Agent 的全面分析,输出了改进研究报告,识别了四大痛点:
- 工具调用能力弱
- 上下文管理差
- 流式体验不好
- 整体架构不清晰
### 2. 任务规划(任务 #8-#13)✅
创建了 6 个优先级任务:
- **P0**: 升级上下文管理为 AI 驱动摘要(进行中)
- **P1**: 统一对话架构(Aster Agent + Unified Chat)
- **P2**: 拆分 useAsterAgentChat hook(1200+ 行)
- **P3**: 工具系统模块化(aster_agent_cmd.rs 2000+ 行)
- **P4**: 引入 SQ/EQ 异步队列对通信模型
- **P5**: 多 Agent 协作能力
### 3. P0 阶段 1 实施(进行中)✅
#### 3.1 创建 AI 摘要服务
**文件**: `src-tauri/crates/services/src/ai_summary_service.rs`
**功能**:
- `AISummaryService`: AI 摘要服务主体
- `AISummaryConfig`: 可配置的摘要参数
- `generate_summary()`: 生成会话摘要
- `build_summary_prompt()`: 构建摘要提示词
- `format_messages()`: 格式化消息列表
**特性**:
- 支持配置摘要长度、主题数量、决策数量
- 使用 JSON 格式返回结构化摘要
- 包含完整的单元测试
- 当前使用 mock 实现,待集成真实 LLM 调用
#### 3.2 集成到 services crate
- ✅ 添加模块导出到 `lib.rs`
- ✅ 编译通过验证
## 下一步工作
### P0 阶段 1 剩余任务
#### 1. 改造 session_context_service.rs
**目标**: 集成 AI 摘要服务,实现优先使用 AI、失败时降级到本地的策略
**修改点**:
- 添加 `ai_summary_service` 字段到 `SessionContextService`
- 将 `create_summary()` 改为异步方法
- 实现 AI 摘要优先逻辑
- 保留 `create_summary_local()` 作为降级方案
#### 2. 集成真实 LLM 调用
**目标**: 替换 `call_llm_mock()` 为真实的 provider pool 调用
**实现方式**:
- 注入 `ProviderPoolService` 到 `AISummaryService`
- 使用 Claude Haiku 模型(成本低、速度快)
- 实现重试机制(最多 3 次)
- 添加超时控制(5 秒)
#### 3. Tauri 命令层集成
**目标**: 在应用启动时初始化 AI 摘要服务
**修改文件**:
- `src-tauri/src/main.rs` 或相关初始化代码
- 创建 `AISummaryService` 实例
- 注入到 `SessionContextService`
#### 4. 测试验证
**单元测试**:
- ✅ AI 摘要服务基础功能
- ⬜ session_context_service 集成测试
- ⬜ 降级逻辑测试
**集成测试**:
- ⬜ 20+ 轮长对话测试
- ⬜ AI 摘要触发验证
- ⬜ 摘要质量评估
## 技术决策记录
### 决策 1: 采用分阶段混合策略
**背景**: aster 框架的上下文管理能力不明确
**决策**:
- 阶段 1: 在 ProxyCast 层实现 AI 摘要(当前)
- 阶段 2: P1 完成后统一到 aster 框架
**理由**:
- 快速交付价值,立即改善用户体验
- 不阻塞 P1 任务,可并行推进
- 降低风险,分步验证
### 决策 2: 使用 Claude Haiku 生成摘要
**理由**:
- 成本低(相比 Opus/Sonnet)
- 速度快(< 3 秒)
- 质量足够(摘要任务不需要最强模型)
### 决策 3: 保留本地摘要作为降级方案
**理由**:
- 确保功能可用性(AI 调用失败时)
- 降低成本(用户可选择禁用 AI 摘要)
- 向后兼容(已有代码不浪费)
## 文档输出
### 规划文档
- `docs/iteration-notes/context-management-upgrade-plan.md` - 总体升级方案
- `docs/iteration-notes/p0-context-management-implementation.md` - P0 实施文档
- `docs/iteration-notes/p0-phase1-implementation-plan.md` - 阶段 1 详细计划
### 代码文件
- `src-tauri/crates/services/src/ai_summary_service.rs` - AI 摘要服务(新增)
- `src-tauri/crates/services/src/lib.rs` - 模块导出(已修改)
## 风险与缓解
### 风险 1: AI 摘要质量不稳定
**状态**: 待验证
**缓解**: 精心设计提示词,实现响应验证逻辑
### 风险 2: API 调用成本
**状态**: 可控
**缓解**: 使用 Haiku 模型,实现智能缓存,提供配置开关
### 风险 3: 与 P1 任务的依赖
**状态**: 已解决
**缓解**: 采用分阶段策略,P0 和 P1 可并行推进
## 下次会话建议
1. **继续 P0 阶段 1**: 完成 session_context_service.rs 改造
2. **集成真实 LLM**: 替换 mock 实现
3. **编写集成测试**: 验证 AI 摘要效果
4. **或者开始 P2**: 拆分 useAsterAgentChat hook(如果 P0 需要等待其他依赖)
## 参考资料
- 研究报告: ProxyCast AI Agent 改进研究报告
- Codex 架构: SQ/EQ 异步队列对、AI 摘要
- aster-rust: 渐进式工具响应移除、SubAgentScheduler
@@ -0,0 +1,59 @@
# OpenClaw Windows 检测问题后续记录
## 状态
- 结论:纳入下个迭代
- 范围:`OpenClaw` Windows 安装检测与诊断可观测性
- 优先级:中高
## 背景
用户反馈在 Windows 环境下已经安装了 `OpenClaw`,但应用内仍显示“未检测到 OpenClaw”。
这类问题通常不是“未安装”,而是“当前进程没有正确解析到 `openclaw` 命令”,典型场景包括:
- 安装完成后应用进程未刷新到最新 `PATH`
- `openclaw` 安装在 `npm` 全局目录,但该目录未进入当前进程可见路径
- `npm config get prefix`、`where openclaw` 与应用内补充搜索目录之间存在不一致
## 现象
- 页面提示:`未检测到 OpenClaw`
- 用户实际情况:系统中已完成 `OpenClaw` 安装
- 用户感知:会误以为需要重复安装,或者认为安装功能失效
## 影响
- 容易触发重复安装操作
- 会降低 Windows 用户对安装流程稳定性的信任
- 故障定位成本高,用户需要手工提供 `where openclaw`、`npm config get prefix` 等信息
## 本次已确认的处理方向
建议下个版本正式带上以下能力:
1. Windows 检测前主动刷新当前进程 `PATH`
2. 将 `npm` 全局前缀目录纳入 `openclaw` 命令补充搜索范围
3. 当检测到 npm 包已存在但命令未生效时,显示“待刷新”而不是“未检测到”
4. 在安装页直接展示诊断信息,包括:
- `npm` 命令路径
- `npm global prefix`
- `OpenClaw` 包路径
- `where openclaw` 命中结果
- 补充搜索目录
- 补充目录中的 `openclaw` 命中结果
## 建议验收标准
- Windows 已安装 `OpenClaw` 但当前进程未命中命令时:
- 不再提示继续重复安装
- 页面显示“待刷新”或等价状态
- 页面给出明确的重新检测/重启应用引导
- 诊断面板可直接暴露关键路径信息,便于用户截图反馈
- `cargo test windows_` 相关回归通过
- OpenClaw 前端页面测试通过
## 建议补充
- 后续可将这组诊断信息并入“故障诊断导出 JSON”
- 若后续还有类似问题,可统一沉淀为“命令可见性诊断”能力,而不是仅服务于 `OpenClaw`
@@ -0,0 +1,143 @@
# P0: 上下文管理升级实施文档
## 当前状态分析
### 代码结构
1. **session_context_service.rs** (src-tauri/crates/services/src/)
- 负责 general 模式的上下文管理
- 使用本地关键词提取生成摘要(第 355-463 行)
- 支持配置:max_messages、max_characters、summary_threshold
2. **SessionConfigBuilder** (src-tauri/crates/agent/src/aster_state_support.rs)
- 用于构建 aster Agent 的会话配置
- 当前字段:id、max_turns、system_prompt、include_context_trace
- 缺少上下文压缩相关配置
3. **AsterAgentWrapper** (src-tauri/src/agent/aster_agent.rs)
- 在第 48-50 行创建 SessionConfig
- 只设置了 `include_context_trace(true)`
### 问题识别
1. **双轨制**:
- general 模式使用 session_context_service.rs
- agent 模式使用 aster 框架
- 两者的上下文管理策略不统一
2. **摘要质量差**:
- session_context_service.rs 使用硬编码关键词匹配
- 无法理解语义,摘要质量低
3. **aster 能力未接入**:
- 不清楚 aster 框架是否内置上下文压缩
- SessionConfig 未暴露相关配置
## 实施策略
### 策略 A:利用 aster 内置能力(优先)
**前提**:aster 框架已内置上下文压缩和 AI 摘要
**步骤**:
1. 研究 aster 框架文档,确认内置能力
2. 扩展 SessionConfigBuilder,暴露配置接口
3. 在 AsterAgentWrapper 中配置上下文压缩参数
4. 将 general 模式迁移到 aster 框架(与 P1 任务关联)
**优点**:
- 复用 aster 的成熟实现
- 统一 agent 和 general 模式的上下文管理
- 减少维护成本
**缺点**:
- 依赖 aster 框架的能力
- 需要等待 P1 任务完成(general 模式迁移)
### 策略 B:在 ProxyCast 层实现(备选)
**前提**:aster 框架不支持或支持不足
**步骤**:
1. 改造 session_context_service.rs,实现 AI 摘要
2. 创建 LLM Provider 抽象,调用 AI 模型生成摘要
3. 实现渐进式工具响应移除策略
4. 为 aster Agent 创建类似的上下文管理服务
**优点**:
- 完全可控,不依赖外部框架
- 可以针对 ProxyCast 的场景优化
**缺点**:
- 需要自己实现和维护
- 代码量大,开发周期长
- 可能与 aster 框架的内置能力冲突
## 下一步行动
### 立即执行
1. **研究 aster 框架**:
- 查看 aster-rust GitHub 仓库文档
- 搜索 context、compression、summary 相关代码
- 确认是否有内置的上下文压缩能力
2. **决策路径**:
- 如果 aster 有内置能力 → 采用策略 A
- 如果 aster 没有或不足 → 采用策略 B
### 待确认问题
1. aster 框架的 SessionConfig 支持哪些字段?
2. aster 是否有 context_mgmt 模块?(研究报告提到)
3. aster 的 AI 摘要是如何实现的?
4. aster 的渐进式工具响应移除是如何配置的?
## 验证计划
### 单元测试
- [ ] 测试 AI 摘要生成逻辑
- [ ] 测试摘要缓存机制
- [ ] 测试降级到本地摘要的逻辑
### 集成测试
- [ ] 发起 20+ 轮长对话
- [ ] 验证 AI 摘要在 80% token 使用率时触发
- [ ] 对比 AI 摘要与本地摘要的质量
- [ ] 验证工具响应的渐进式移除
### 性能测试
- [ ] 测试摘要生成的延迟
- [ ] 评估 API 调用成本
- [ ] 测试缓存命中率
## 风险与缓解
### 风险 1:aster 框架能力不足
**缓解**:准备策略 B 作为备选方案
### 风险 2:AI 摘要成本过高
**缓解**:
- 实现智能缓存策略
- 提供本地摘要作为降级方案
- 允许用户配置是否启用 AI 摘要
### 风险 3:与 P1 任务的依赖关系
**缓解**:
- P0 和 P1 可以并行推进
- P0 先在 agent 模式验证,P1 完成后再统一
## 参考资料
- 研究报告:ProxyCast AI Agent 改进研究报告
- aster-rust GitHub: https://github.com/astercloud/aster-rust
- 相关文件:
- src-tauri/crates/services/src/session_context_service.rs
- src-tauri/crates/agent/src/aster_state_support.rs
- src-tauri/src/agent/aster_agent.rs
@@ -0,0 +1,228 @@
# P0 实施方案:分阶段升级上下文管理
## 决策:采用混合策略
基于当前分析,我决定采用**分阶段混合策略**:
### 阶段 1:快速改进(本次实施)
在 session_context_service.rs 中实现 AI 驱动的摘要,作为立即可用的改进。
### 阶段 2:架构统一(P1 完成后)
将 general 模式迁移到 aster 框架,统一上下文管理策略。
## 阶段 1 实施细节
### 1.1 创建 AI 摘要服务
创建新文件:`src-tauri/crates/services/src/ai_summary_service.rs`
```rust
//! AI 驱动的会话摘要服务
use proxycast_core::general_chat::ChatMessage;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AISummaryRequest {
pub messages: Vec<ChatMessage>,
pub max_summary_length: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AISummaryResponse {
pub summary: String,
pub key_topics: Vec<String>,
pub decisions: Vec<String>,
}
pub struct AISummaryService {
// 使用 ProxyCast 的 provider pool
provider_pool: Arc<ProviderPoolService>,
}
impl AISummaryService {
pub async fn generate_summary(
&self,
request: AISummaryRequest,
) -> Result<AISummaryResponse, String> {
// 1. 构建摘要提示词
let prompt = self.build_summary_prompt(&request.messages);
// 2. 调用 AI 模型
let response = self.call_llm(&prompt).await?;
// 3. 解析响应
self.parse_summary_response(&response)
}
fn build_summary_prompt(&self, messages: &[ChatMessage]) -> String {
format!(
"请为以下对话生成简洁的摘要(不超过 {} 字):\n\n{}\n\n要求:\n1. 提取关键主题(3-5个)\n2. 总结重要决策\n3. 保留技术细节",
500,
self.format_messages(messages)
)
}
}
```
### 1.2 改造 session_context_service.rs
修改 `create_summary()` 方法:
```rust
/// 创建会话摘要(优先使用 AI,失败时降级到本地)
async fn create_summary(
&self,
session_id: &str,
messages: &[ChatMessage],
) -> Result<SessionSummary, String> {
// 尝试使用 AI 摘要
if let Some(ai_service) = &self.ai_summary_service {
match ai_service.generate_summary(messages).await {
Ok(ai_summary) => {
return Ok(SessionSummary {
session_id: session_id.to_string(),
summary: ai_summary.summary,
key_topics: ai_summary.key_topics,
decisions: ai_summary.decisions,
created_at: chrono::Utc::now().timestamp_millis(),
message_count: messages.len() as i32,
last_message_id: messages.last().unwrap().id.clone(),
});
}
Err(e) => {
tracing::warn!("AI 摘要生成失败,降级到本地摘要: {}", e);
}
}
}
// 降级到本地关键词提取
self.create_summary_local(session_id, messages)
}
/// 本地关键词提取摘要(保留作为降级方案)
fn create_summary_local(
&self,
session_id: &str,
messages: &[ChatMessage],
) -> Result<SessionSummary, String> {
// 原有的本地摘要逻辑
// ...
}
```
### 1.3 配置注入
修改 `SessionContextService` 构造函数:
```rust
pub struct SessionContextService {
db_connection: Arc<Mutex<Connection>>,
config: ContextWindowConfig,
summary_cache: Arc<Mutex<HashMap<String, SessionSummary>>>,
ai_summary_service: Option<Arc<AISummaryService>>, // 新增
}
impl SessionContextService {
pub fn new(
db_connection: Arc<Mutex<Connection>>,
config: ContextWindowConfig,
ai_summary_service: Option<Arc<AISummaryService>>,
) -> Self {
Self {
db_connection,
config,
summary_cache: Arc::new(Mutex::new(HashMap::new())),
ai_summary_service,
}
}
}
```
## 实施步骤
### Step 1: 创建 AI 摘要服务 ✅
- [ ] 创建 `ai_summary_service.rs`
- [ ] 实现 `generate_summary()` 方法
- [ ] 实现提示词构建逻辑
- [ ] 实现响应解析逻辑
### Step 2: 改造 session_context_service.rs ✅
- [ ] 添加 `ai_summary_service` 字段
- [ ] 修改 `create_summary()` 为异步方法
- [ ] 实现 AI 摘要优先、本地降级的逻辑
- [ ] 保留 `create_summary_local()` 作为降级方案
### Step 3: 集成到命令层 ✅
- [ ] 在 Tauri 命令初始化时创建 `AISummaryService`
- [ ] 注入到 `SessionContextService`
- [ ] 更新相关的 Tauri 命令
### Step 4: 测试验证 ✅
- [ ] 编写单元测试
- [ ] 编写集成测试
- [ ] 手动测试 20+ 轮对话
- [ ] 验证降级逻辑
## 成本控制
### 摘要触发策略
- 只在消息数量超过 `summary_threshold`(默认 30)时触发
- 摘要结果缓存,避免重复生成
- 提供配置开关,允许用户禁用 AI 摘要
### API 调用优化
- 使用较小的模型(如 Claude Haiku)生成摘要
- 限制摘要长度(500 字以内)
- 批量处理多个会话的摘要请求
## 验证指标
### 质量指标
- AI 摘要的信息保留率 > 80%
- 关键主题提取准确率 > 90%
- 用户满意度评分 > 4/5
### 性能指标
- 摘要生成延迟 < 3 秒
- 缓存命中率 > 70%
- API 调用成本 < $0.01/会话
### 可靠性指标
- 降级成功率 100%
- AI 摘要失败时不影响对话流程
- 错误日志完整,便于排查
## 风险缓解
### 风险 1:AI 摘要质量不稳定
**缓解措施**:
- 精心设计提示词,包含明确的格式要求
- 实现响应验证逻辑,拒绝低质量摘要
- 提供用户反馈机制,持续优化提示词
### 风险 2:API 调用失败
**缓解措施**:
- 实现重试机制(最多 3 次)
- 降级到本地摘要,确保功能可用
- 记录详细的错误日志
### 风险 3:成本超预期
**缓解措施**:
- 实现智能缓存策略
- 提供配置开关,允许用户控制
- 监控 API 调用量,设置告警阈值
## 后续优化(阶段 2)
在 P1 任务完成后:
1. 将 general 模式迁移到 aster 框架
2. 统一 agent 和 general 的上下文管理
3. 利用 aster 的渐进式工具响应移除能力
4. 实现更智能的上下文压缩策略
## 参考资料
- 研究报告:ProxyCast AI Agent 改进研究报告
- Codex 上下文压缩:AI 摘要 + 保留最近消息
- aster 上下文管理:渐进式工具响应移除 + 摘要