Skip to content

Latest commit

 

History

History
926 lines (700 loc) · 49.6 KB

SUBMITTION.md

File metadata and controls

926 lines (700 loc) · 49.6 KB

在这里 submit 更改

历史开发日志:本文件只保留各时间点的提交说明,早期“当前注意事项”、测试数量和 架构描述不代表 2026-09-08 的现状。最新状态请看 README.md、 API.md、TODO.md 和 COMPETITION_AUDIT.md。

2026-07-19 第一次大提交

修改人:yyf

完成 Agent 后端基础骨架 让模型能够识别和调用工具 并根据工具结果继续生成回答

已实现

  • 搭建 Agent 基本执行循环

    • 构建 system user assistant tool 消息
    • 解析模型生成结果
    • 执行模型请求的工具
    • 将工具结果加入上下文并继续推理
  • 接入 vLLM 和 Transformers

    • 支持加载和卸载 Qwen 模型
    • 支持向模型传递 tools schema
    • 配置模型采样参数和最大上下文长度
  • 实现 ToolRegistry 工具注册器

    • 通过装饰器注册工具
    • 汇总已注册工具的 schemas
    • 根据工具名称调用对应函数
    • 捕获工具执行过程中产生的异常
  • 添加基础工具

    • get_weather 查询模拟天气信息
    • add_two_nums 计算两个数字之和
    • web_search 通过本地 SearXNG 搜索互联网信息
  • 实现模型输出解析

    • 提取 reasoning
    • 提取普通文本 content
    • 解析一个或多个 tool_call
    • 对工具参数进行整数 浮点数 布尔值等基础类型转换
  • 添加基础 system prompt 将 Agent 定义为学习辅助 Agent

  • 添加日志系统

    • 在终端输出运行日志
    • 将日志写入 logs/backend.log
    • 支持日志文件滚动和历史日志保留

当前注意事项

  • SearXNG 需要运行在 127.0.0.1:8888

  • SearXNG 的 settings.yml 需要启用 JSON 输出格式

    search:
      formats:
        - html
        - json

2026-07-19 第二次提交

修改人:zcx

添加计算器工具 让 Agent 能够安全地执行数学计算

已实现

  • 添加 calculator 计算器工具

    • 支持四则运算 幂运算 取整和取模
    • 支持科学函数 包括三角函数 对数 指数 双曲函数等
    • 支持数学常量 pi e tau inf
    • 兼容数学惯用写法 将 ^ 自动转换为 **
  • 实现基于 AST 白名单的安全求值器

    • 不使用 eval() 防止代码注入
    • 仅允许数值常量 预定义常量 白名单运算符与函数调用
    • 拒绝属性访问 下标 赋值 lambda 等危险 AST 节点
  • 完善错误处理

    • 捕获除零错误并返回友好提示
    • 检测 NaN 和无穷大结果
    • 整数值的浮点数自动转为 int 输出
    • 表达式长度限制防止 DoS

当前注意事项

  • 计算器工具在 backend/agent/tools/calculator.py 中实现

  • 已在 backend/agent/tools/__init__.py 中声明导入 触发工具注册

2026-07-19 第三次提交

修改人:zcx

添加位运算计算器和符号计算工具 让 Agent 覆盖计算机学科与大学数学全场景

已实现

  • 添加 bitwise_calculator 位运算计算器工具

    • 支持位运算 & | ^ ~ << >>
    • 支持布尔运算 and or not
    • 支持算术运算便于混合表达式如 0xFF + 1
    • 支持函数 bin oct hex int abs bit_length popcount
    • 支持 0b 0o 0x 进制前缀
    • 结果自动返回二进制 八进制 十进制 十六进制多进制表示
  • 添加 math_solver 符号计算工具

    • 支持求导 diff 包括高阶求导
    • 支持积分 integrate 包括定积分和不定积分
    • 支持极限 limit 支持左右极限方向
    • 支持泰勒级数展开 series
    • 支持解方程 solve
    • 支持化简 simplify 展开 expand 因式分解 factor
    • 支持组合数 binomial 排列数 permutation 求和 summation
    • 基于 sympy 实现符号计算
  • 实现安全机制

    • bitwise_calculator 使用 AST 白名单求值 不使用 eval()
    • math_solver 使用 sympy parse_expr 配合白名单全局字典 限制可用符号与函数
    • 两个工具均拒绝属性访问 函数调用注入等危险操作
    • 表达式长度限制防止 DoS

当前注意事项

  • math_solver 依赖 sympy 库 已确认环境安装 1.14.0 版本

  • 三个计算工具的分工

    • calculator 负责数值计算 ^ 表示幂
    • bitwise_calculator 负责位运算 ^ 表示异或
    • math_solver 负责符号推导如微积分和方程

2026-07-22 第四次提交

修改人:yyf

添加临时记忆和核心记忆系统 让 Agent 能够保留用户最近的对话内容和长期稳定信息

已实现

  • 添加 TempMemory 临时记忆

    • 按 user_name 隔离不同用户的消息
    • 保存 user assistant tool 三种消息
    • 支持获取和清空指定用户的临时记忆
    • 将临时消息转换为适合模型读取的上下文
    • 每个用户最多保留 20 条消息
    • 超过限制时自动删除该用户最早的消息
    • 清理消息时不会影响其他用户
  • 添加 CoreMemory 核心记忆

    • 使用 SQLite 持久化保存用户长期信息
    • 使用 user_name 和 memory_key 唯一标识一条记忆
    • 支持新增 更新 查询 删除和清空核心记忆
    • 支持保存记忆分类和创建更新时间
    • 相同 memory_key 再次写入时自动更新原有内容
    • 使用参数化 SQL 防止 SQL 注入
  • 添加核心记忆 tools

    • save_core_memory 保存或更新当前用户的核心记忆
    • get_core_memories 查询当前用户的全部核心记忆
    • delete_core_memory 删除当前用户的指定核心记忆
    • 支持 profile preference learning project constraint general 六种记忆分类
  • 添加用户上下文管理

    • 使用 ContextVar 保存当前执行用户
    • Agent 每次运行前设置当前用户名
    • 记忆 tools 不需要模型提供 user_name
    • 防止模型通过工具参数访问其他用户的核心记忆
    • 为后续异步和并发请求提供用户上下文隔离基础
  • 完善 Agent 记忆接入

    • 每轮运行前读取当前用户的临时记忆和核心记忆
    • 将用户输入和 Agent 最终回答保存到临时记忆
    • 将工具调用结果保存到临时记忆
    • 将两种记忆分别注入 system prompt
  • 完善记忆使用规则

    • 只使用与当前问题相关的用户记忆
    • 用户最新要求和已有记忆冲突时使用最新要求
    • 禁止向用户暴露内部记忆结构
    • 禁止编造不存在的用户记忆
  • 修正记忆工具实现

    • 使用当前文件位置构建核心记忆数据库路径
    • 移除对程序启动目录和 tools 包 ROOT_DIR 的依赖
    • 避免 memory tools 和 tools 包之间产生循环导入
    • 将 memory_key 的 schema description 修正为字符串

当前注意事项

  • 临时记忆只保存在程序内存中 程序退出后会清空

  • 核心记忆保存在 backend/agent/memories/data/core_memory.db

  • 核心记忆只应该保存用户偏好 学习目标 项目信息等长期稳定内容

  • 核心记忆不应该保存临时问题 reasoning 工具搜索结果 密码或 token

2026-07-22 第五次提交

修改人:zcx

添加 arXiv 文献搜索工具 让 Agent 具备学术论文检索能力

已实现

  • 添加 arxiv_search 文献搜索工具

    • 通过 arXiv 公开 API 搜索学术论文
    • 支持按字段搜索 all(全文) title(标题) author(作者) abstract(摘要) category(分类)
    • 支持排序方式 relevance(相关度) lastUpdated(最后更新) submitted(提交时间)
    • 支持升序降序排列
    • 返回结构化信息包括 arXiv ID 标题 作者列表 摘要 PDF链接 发表日期 分类 DOI 期刊引用等
    • 自动从 arXiv URL 提取论文 ID 并去除版本号
    • 最大返回结果限制为 20 条
  • 实现网络请求健壮性

    • 429 限流时自动重试 最多 5 次 间隔 10 秒
    • 请求超时自动重试 最多 5 次
    • 请求超时时间 60 秒
    • 设置 User-Agent 头标识
    • XML 解析错误捕获
  • 修复 ElementTree 命名空间解析 bug

    • ElementTree 的 Element 对象无子节点时为 falsy
    • 所有 if elem and elem.text 改为 if elem is not None and elem.text
    • 确保 title author abstract 等文本字段正确解析

当前注意事项

  • arXiv API 要求请求间隔 3 秒 工具内置重试机制处理限流

  • 已在 backend/agent/tools/__init__.py 中声明导入

2026-07-23 第六次提交

修改人:yyf

迁移并适配用户认证服务 存储层从 JSON 全面切换到 SQLite 添加历史对话与聊天记录持久化 Agent 支持多轮对话历史

已实现

  • 迁移并适配认证服务

    • AuthService 提供登录和注册接口
    • PasswordService 使用 bcrypt 对密码加盐哈希 不存明文
    • 当时登录成功签发 2 小时有效期的 SessionPrincipal 会话(后续已调整为 7 天)
    • 移除旧项目遗留的 company_id 参数
    • 补齐缺失的 UserStore SessionStore 导入
  • 实现 SQLite 存储层 替换原 JSON 文件存储

    • 添加 BaseSQLiteStore 基类
      • 统一管理数据库连接 每次操作独立连接并正确关闭
      • 提供 query_one query_all execute 通用方法
      • 自动创建数据目录 子类各自初始化数据表
    • 添加 UserStore 用户表
      • id 主键 username 唯一约束
      • 依靠数据库约束原子地拦截重复注册 避免先查后插的并发竞态
    • 添加 SessionStore 会话表
      • 支持创建 查询 注销 清理过期会话
      • 时间统一存 UTC ISO 格式字符串 过期清理为单条 SQL
    • 删除 BaseJsonStore 及相关 JSON 存储代码
  • 添加 ChatStore 聊天记录持久化

    • conversations 表保存历史对话列表 按最近更新排序
    • messages 表保存对话内消息 兼容 user assistant tool 三种角色
    • 支持创建 查询 重命名 删除对话 删除时级联清理消息
    • 追加消息与刷新对话更新时间在同一事务内完成
    • get_history 返回完整消息记录 供前端展示
    • get_model_messages 返回纯净模型格式 供多轮对话回放
    • 所有方法返回 dict 可直接被 FastAPI 序列化为 JSON
  • Agent 支持多轮对话历史

    • Agent.run() 新增 history 参数 接收历史消息拼入上下文
    • run() 返回本轮新产生的消息 供调用方持久化
    • 持久化的助手消息为解析后内容 不含 reasoning
    • main.py CLI 循环接入历史 命令行下支持多轮对话
  • 统一注释格式

    • 全部 docstring 对齐 core_memory.py 的 参数: 类型 => 说明 风格
    • 修正 password_service.py 中的拼写错误
    • 修正 services 目录迁移后遗留的文件头路径注释

当前注意事项

  • 用户 会话 聊天记录默认共用一个数据库文件 data/esa.db 各自建表 初始化时自动创建

  • 后端 web 层尚未实现 webAPI.py 待接入 FastAPI 后暴露给前端 通信格式为 JSON

  • 多轮对话完整链路 get_model_messages 取历史 传入 Agent.run() 返回值交给 append_messages 存库

  • PasswordService 依赖 bcrypt 库 部署环境需要安装

  • 项目目前没有 requirements.txt 建议后续补充依赖清单

2026-07-24 第七次提交

修改人:yyf

接入 FastAPI 搭建后端 web 层 完成认证相关接口 打通 注册 登录 登出 完整链路 前后端通信格式定为 JSON

已实现

  • 调整 AuthService 适配 web 层

    • login 改为按 username 查询用户 与前端登录表单对齐
    • 会话中保存的 user_id 仍为用户真实 uuid 供下游归属校验使用
    • register 不再由外部传入 user_id 改为服务端 uuid 生成
    • register 返回值从 bool 改为 UserRecord | None 路由层可直接取新用户信息构造响应
  • 搭建 FastAPI 应用骨架 webAPI.py

    • 使用 lifespan 在启动时装配 UserStore SessionStore ChatStore AuthService
    • 所有依赖挂载到 app.state 全局复用 不在请求内重复创建
    • 数据库文件统一为 backend/core/stores/data/user.db
    • 通过 include_router 挂载 auth 路由
  • 定义 JSON 通信契约 schemas.py

    • 请求模型 RegisterRequest LoginRequest SendMessageRequest
    • 响应模型 LoginResponse MessageOut
    • 使用 pydantic Field 声明校验规则 用户名 1-32 位 密码 8-128 位
    • 校验不通过由 FastAPI 自动返回 422 后端不手写校验逻辑
  • 实现会话认证依赖 deps.py

    • get_current_session 从 Authorization: Bearer <session_id> 请求头解析令牌
    • 校验会话存在性和有效期 过期会话顺手 revoke 清理
    • 认证失败统一返回 401
    • 业务接口通过 Depends 注入 自动拦截未登录请求
  • 实现认证路由 routers/auth.py

    • POST /auth/register 注册 成功 201 用户名重复 409
    • POST /auth/login 登录 成功返回 LoginResponse 失败 401
    • POST /auth/logout 登出 注销当前会话 返回 204
    • 登录失败时 用户不存在 和 密码错误 返回同一文案 避免泄露已注册用户名
  • 建立 API.md 接口文档 记录全部 endpoint 请求响应格式与错误码 作为前后端对接依据

当前注意事项

  • web 层依赖 fastapi uvicorn pydantic 部署环境需要安装 启动命令 uvicorn backend.core.web.webAPI:app --reload

  • CORS 中间件尚未配置 Flutter web 端跨域请求会被浏览器拦截 对接前端前需要加上 CORSMiddleware

  • deps.py 中 401 错误文案为调试用玩笑话 会原样返回给客户端 对接前端前必须替换为正式文案

  • backend/core/stores/data/user.db 数据库文件被提交进了 git 内含测试用户密码哈希 建议从版本库移除并加入 .gitignore

  • 聊天相关路由 routers/chat.py 尚未实现 对话列表 历史消息 发消息接口待接入 ChatStore 与 Agent

  • 前端登录页密码校验规则为 大于 8 位 与后端 schema 的 8-128 位不一致 且前端对密码做 trim 需要前端调整对齐

2026-07-24 第八次提交

修改人:zcx

实现 RAG (检索增强生成) 模块基础架构 作为占位组件验证系统流程 为后续自研模型预留扩展接口

已实现

  • 模块化架构设计

    • 定义抽象接口 EmbeddingProvider VectorStore DocumentLoader
    • 采用依赖注入模式 核心组件可独立替换
    • 配置化管理 参数集中存放在 RAGConfig dataclass
  • 文档处理模块

    • TextLoader: 支持 .txt/.md 格式文档加载
    • TextSplitter: 固定大小分块 + 智能分隔符识别
    • 保留来源元数据 (文件名、章节、页码)
  • Embedding 实现占位

    • SimpleEmbedding: 使用哈希生成向量 作为占位实现
    • BGEEmbedding: 使用 BAAI/bge-small-zh 真实语义向量 (512维)
    • 支持批量向量化 向量维度自动归一化
  • 向量存储实现占位

    • MemoryVectorStore: 内存向量存储 测试用 不持久化
    • FAISSVectorStore: FAISS 向量存储 支持持久化 L2/IP 相似度计算
    • 相似度检索支持阈值过滤
  • 检索策略占位

    • BM25Retriever: BM25 关键词检索 (rank_bm25)
    • HybridRetriever: 混合检索 (BM25 + 向量) RRF 融合算法
    • 权重可配置 bm25_weight vector_weight
  • Agent 工具集成

    • retrieve_knowledge: 从知识库检索相关文档
    • index_knowledge_base: 索引文档目录到知识库
    • get_knowledge_base_stats: 获取知识库统计
    • clear_knowledge_base: 清空知识库
    • 工具已注册到 ToolRegistry Agent 可自动调用
  • 来源可追溯

    • 每条检索结果标注来源文档 章节信息
    • 格式化模板可自定义 默认格式 "【来源 1】文件名 · 章节 · 第N页"
    • 满足赛题要求的答案来源标注
  • 文档与测试

    • RAG_API.md: 接口文档 包含使用示例和扩展指南
    • MIGRATION_GUIDE.md: 自研模型迁移指南 详细步骤与兼容性说明
    • INSTALL.md: 依赖安装说明
    • benchmark.py: 性能基准测试脚本
    • test_rag.py: 功能测试脚本
    • 示例文档: math_basics.txt, python_intro.txt

技术决策

  • 不使用 LangChain/LlamaIndex 等框架: 采用底层库直接集成 避免与 Agent 工具注册机制冲突 保持轻量可控
  • 默认配置: BGE Embedding + FAISS 存储 + 混合检索
  • 占位性质明确: SimpleEmbedding 仅用于验证流程 无语义理解能力

当前注意事项

  • 依赖安装:

    pip install sentence-transformers faiss-cpu rank_bm25
  • 当前为占位实现:

    • SimpleEmbedding 使用哈希向量 不具备语义理解能力
    • MemoryVectorStore 不持久化 重启后数据丢失
    • 生产环境应使用 BGEEmbedding + FAISSVectorStore
  • 后续改进方向:

    1. 替换为自研 Embedding 模型
    2. 替换为自研向量数据库或优化检索算法
    3. 扩展 PDF/Word 等文档格式支持
    4. 添加知识图谱和用户掌握度模型
    5. 实现个性化题目推荐引擎
  • 迁移指引:

    • 自研模型只需继承 EmbeddingProvider 或 VectorStore 抽象类
    • 详细步骤见 backend/agent/rag/MIGRATION_GUIDE.md
  • Python 版本兼容性:

    • 已修复所有 Python 3.9 类型注解兼容性问题
    • 使用 Optional[Type] 替代 Type | None
    • 使用 Union[Type1, Type2] 替代 Type1 | Type2
  • 命名冲突已解决:

    • 检索策略目录重命名为 retrieval_strategies/
    • 主检索器文件保持 retriever.py
  • 文件结构:

    backend/agent/rag/
    ├── document/           # 文档处理
    ├── embeddings/         # Embedding 实现
    ├── vectorstore/        # 向量存储
    ├── retrieval_strategies/  # 检索策略
    ├── sample_docs/        # 示例文档
    ├── base.py             # 抽象接口
    ├── config.py           # 配置管理
    ├── retriever.py        # 主检索器
    └── rag_tool.py         # Agent 工具注册
    

2026-07-27 第九次提交

修改人:yyf

依据设计交付包 design_handoff_esa_chat 重构 Flutter 前端 从原来的纯 mock 页面按高保真设计 1:1 实现四个界面 严格对齐设计给定的颜色 圆角 字号 间距

已实现

  • 引入设计主题与依赖

    • 将设计方提供的 esa_theme.dart 放入 lib/theme/ 直接作为工程主题
    • 新增依赖 google_fonts (Archivo 字体) 与 lucide_icons (Lucide 图标) 图标线宽统一
    • 深色为默认主题 浅色深色两套 ColorScheme 可在设置里实时切换
  • 目录结构重组 从原来 3 个平铺文件拆分为分层结构

    • lib/theme/ 主题 token 与便捷访问扩展
    • lib/models/ 对话与消息数据模型
    • lib/state/ 集中式应用状态
    • lib/pages/ 页面 lib/widgets/ 可复用组件
  • 状态管理

    • 用 AppState extends ChangeNotifier 集中管理主题 设置 用户 对话列表 消息 生成状态
    • 通过 AppScope (InheritedNotifier) 置于 MaterialApp 之上 弹层等路由也能访问全局状态
    • 未额外引入 Riverpod 减少陌生依赖
  • 界面 1 登录 / 注册

    • 左右两栏 红色海报 + 表单 窄屏 (小于 880) 竖向堆叠
    • 登录注册分段切换 显示隐藏密码 校验与后端一致 (用户名 1-32 密码不小于 8 注册两次密码一致) 密码不做 trim
    • 主按钮标签左对齐 + 右侧箭头 错误提示条
  • 界面 2 对话主界面

    • 顶栏 侧边栏按钮 新对话按钮 当前标题 + ESA · STUDY AGENT 副行
    • 用户消息右对齐气泡 助手回复平铺左对齐 + 末尾红方块光标闪烁 工具调用块 (等宽字体)
    • 空状态 WELCOME + 欢迎语 + 四张建议卡
    • 输入区 Enter 发送 Shift+Enter 换行 附件条 发送按钮无内容或生成中时禁用
  • 界面 3 历史对话侧边栏 (覆盖式抽屉)

    • 头部 开启新对话 搜索框 分组列表 (置顶 今天 本周 更早 空分组不渲染)
    • 列表项支持 置顶 就地重命名 (Enter 提交 Esc 取消) 删除 当前会话高亮
    • 底部用户条点击打开资料弹层
  • 界面 4 用户资料 + 设置弹层

    • 资料区 统计三宫格 昵称 邮箱 身份字段
    • 设置区 外观切换 (实时换主题) 流式输出开关 工具调用详情开关 数据与隐私入口
    • 底部退出登录 (回登录页) 与保存
  • 交互

    • 助手回复按设计做流式模拟 每 26ms 追加若干字符 可在设置里关闭改为一次性显示
    • 复制 (图标变红 1.4s) 与重新生成
    • flutter analyze 无告警 flutter build web 通过

当前注意事项

  • 尚未接入真实后端 登录 对话列表 发消息目前均为本地假数据 + 流式模拟 (依设计 README 先不接模型)

    • 后续需按 API.md 在 lib/api/ 写 HTTP 层 替换 AppState 里的 login send _startReply 等方法
    • 发消息应改为调用 POST /conversations/{id}/messages 401 时清 token 回登录页
  • session_id 未做持久化 (设计建议存 shared_preferences) 刷新页面会丢登录态

  • 附件上传按钮为占位 仅在本地显示文件名 chip 未真正上传

  • 对话置顶 (pinned) 仅前端本地状态 后端暂无该字段 未持久化

  • 旧登录背景图 frontend/assets/d0876df6641794f86066e1454db3b5b0.jpg 新设计已不再使用

2026-07-30 第十次提交

修改人:zcx

新增用户输出偏好(风格/语调/自定义指令)端到端链路 路由 /me/preferences 注入 system prompt 影响模型输出

已实现

  • 数据层 users 表迁移

    • 新增三列 preferred_style preferred_tone custom_instruction 默认值 concise / friendly / 空串
    • _initialize 改用 self._connect() 在同一连接内完成 CREATE + PRAGMA + ALTER 老库迁移 幂等可重复执行
    • 迁移模式照搬 chat_store.py 已有写法 保持一致
  • Store / Model 层

    • UserRecord 加三字段 带默认值 保证 AuthService.register 旧构造不破
    • to_model / 两处 SELECT / INSERT 补三列
    • 新增 update_preferences 方法 动态拼 SET 子句 只更新非 None 字段 支持部分更新
  • API 层 新建偏好路由

    • GET /me/preferences 返回当前用户偏好
    • PATCH /me/preferences 部分更新 exclude_unset=True 只改传入字段
    • 枚举集合校验 非法值返回 400 并给出合法值列表
    • custom_instruction pydantic max_length=500 校验 + 路由层截断双保险
    • 命名刻意用 /me/preferences 而非 /me/settings 把顶层 settings 路径留给未来的账号设置(改昵称/密码/专业/年级)
  • Prompt 层 接入 system prompt

    • build_system_prompt 加三参 preferred_style preferred_tone custom_instruction
    • 新增 _STYLE_RULES /_TONE_RULES 映射表 把枚举翻译成给 LLM 的具体指令
    • 拼出独立 # 输出风格 段 含风格/语调规则 custom_instruction 非空时额外拼"用户补充要求"
    • 枚举查表查不到退回默认描述 不会因脏数据崩
  • Agent 透传

    • _prepare_run run run_stream 三方法加三参透传给 build_system_prompt
    • chat.send_message 从 user_store.get_by_id 取偏好传入 agent.run
    • stream_message 当前为占位假数据 本次不动 留待 SSE 实施时统一接

当前注意事项

  • 风格/语调规则文本是初版占位 build_prompt.py 的 _STYLE_RULES _TONE_RULES (L25-38) 当前每条只是一句话粗描述 后续需要更详细的优化

    • 待优化方向:每档风格展开成多条具体可执行规则(句长上限/是否给例子/是否分段等) 语调同样需要细化
    • 当前文本够跑通链路 但对模型输出的约束力有限 真实效果需调优
  • 链路已通 用户改偏好 → 下次发消息 → system prompt 带上风格/语调 → 模型按规则回答

  • 次只做后端接口 前端按 GET / PATCH /me/preferences 对接即可

2026-07-31 第十一次提交

修改人:zcx

实现个性化记忆系统(掌握度模型 + 知识图谱 + 学习档案 + 个性化 Skill),让 Agent 能够追踪用户知识点掌握度、推荐练习、生成学情报告、自动批改作业,并支持用户设置学习档案与个性化画像开关。

已实现

  • Task 1: KnowledgeGraphStore 知识图谱存储

    • 使用 YAML 外置配置文件(data/knowledge_graph/core_courses.yaml / elective_courses.yaml),分离代码与数据
    • 覆盖 9 所高校培养方案并集,473 个知识点,439 条前置依赖边
    • 支持知识点查询、课程过滤、前置依赖追溯、BFS 依赖树
    • 加载器 kg_loader.py 统一管理 YAML 加载与格式化
  • Task 2: MasteryStore 掌握度模型

    • 独立 SQLite 数据库 data/mastery.db,user_mastery 表以 (user_name, kp_id) 为主键
    • 掌握度算法:答对 min(95, mastery + learning_rate * (1 - mastery/100) * confidence),learning_rate 随练习次数衰减;答错 max(10, mastery - 0.15 * (mastery/100) * confidence);50 为初值,范围 [0, 100]
    • 惰性衰减:实时计算 get_mastery_level,apply_decay 批量固化
    • 优先级排序:综合掌握度、知识点权重、距期末时间、前置薄弱四个因子
    • 报告接口:get_report(课程级/全局)、get_top_weak、get_top_strong
  • Task 3: 掌握度工具注册

    • recommend_practice(course, weeks_to_exam) — 按优先级推荐 Top5 练习知识点
    • get_mastery_report(course) — 获取掌握度报告(含薄弱/较好/未练习列表)
    • record_answer(kp_id, correct, confidence) — 记录练习结果
    • 使用 current_user ContextVar 获取当前用户名,无需模型传入用户标识
    • total_weeks 支持从 UserRecord 字段注入,默认值 UserRecord.TOTAL_WEEKS_DEFAULT = 18
  • Task 4: 学习档案字段 + REST API

    • UserRecord 新增 major / grade / current_week / total_weeks / profile_enabled 五个字段
    • 数据库迁移:老库自动 ALTER TABLE ADD COLUMN,旧用户得默认值
    • GET /me/profile — 查询学习档案
    • PATCH /me/profile — 部分更新,含 major 枚举校验(当前支持 cs)、current_week <= total_weeks 跨字段约束
    • profile_enabled 开关控制个性化画像是否注入系统提示词
  • Task 5: System Prompt 升级

    • build_system_prompt 新增 user_profile_context 参数,非空时在"输出风格"与"核心记忆"之间插入"用户学情档案"区块
  • Task 6: Agent 集成

    • build_user_profile_context(user) — 构建学情档案文本:平均掌握度、Top3 薄弱/较好知识点、教学进度、Skill 规则
    • profile_enabled=False 时返回 None,不注入任何内容
    • _prepare_run 注入 set_current_total_weeks,run()/run_stream() 透传参数
    • chat.py 路由层在 send_message / stream_message 中调用 build_user_profile_context 并传入 Agent
  • Task 7: 个性化 Skill 文档

    • profile_personalization.md — 用户画像自动加载 Skill(讲解深度三档、计算机学科身份规范、来源标注、AI 标识)
    • practice_recommendation.md — 练习推荐 Skill(获取报告 → 调用工具 → 按档位讲解 → 追溯前置薄弱)
    • mastery_report.md — 掌握度报告 Skill(查询范围 → 调用工具 → 结合知识图谱分析)
    • homework_review.md — 作业批改 Skill(批改 → 记录结果 → 归因知识点 → 追溯前置薄弱)
    • 4 个文档均可被 __parse frontmatter 解析器正确解析
  • Task 8: 冒烟测试验证

    • 37 个用例全部通过:KnowledgeGraphStore 建表/种子/查询、MasteryStore 记录/衰减/排序/报告、工具注册确认、Skill 文件解析

当前注意事项

  • Agent 完整启动检查(含 import 链 + 工具 schema + skills 列表加载)需生产环境(vllm/numpy/faiss 已装)执行
  • total_weeks 通过 set_current_total_weeks() ContextVar 注入,Agent 未设置时 fallback 到默认值 18
  • 当前 major 仅支持 cs(计算机学科),扩展新专业时需在 preferences.py 路由层补充枚举值
  • 知识图谱种子数据路径为 backend/agent/memories/data/knowledge_graph/,seed_knowledge_graph.py 在首次导入时自动加载

2026-08-01 第十二次提交

修改人:团队

完成前端 SSE 通信链路接入,使 Flutter 能够消费后端流式事件,并保留同步接口作为可切换的兼容方案。

已实现

  • 新增 Flutter SSE 客户端

    • 在 frontend/lib/api/api_client.dart 中新增 ChatStreamEvent 数据结构
    • 新增 streamMessage() 方法,通过 POST /conversations/{conversation_id}/messages/stream 发起流式请求
    • 请求继续携带 Authorization: Bearer <session_id>,与现有登录认证方式保持一致
    • 使用 UTF-8 解码和 LineSplitter 增量读取响应,不等待完整响应体下载完成
    • 按 SSE 协议解析 event: 与 data: 字段
    • 支持一条事件包含多行 data:,并兼容连接关闭前缺少最后一个空行的情况
    • 非 200 响应继续转换为现有 ApiException,复用统一错误处理逻辑
  • 接入后端流式事件

    • 支持 start:确认服务端开始处理请求
    • 支持 reasoning:把 delta 追加到助手消息的思考内容
    • 支持 content:把 delta 追加到助手最终回答
    • 支持 tool:显示工具名称及工具执行结果
    • 支持 done:结束生成状态并停止输入光标
    • 支持 error:展示服务端返回的生成失败信息
  • 重构前端消息发送流程

    • 开启“流式输出”时调用 SSE 接口并实时更新同一个 ChatMessage
    • 关闭“流式输出”时继续调用原有同步接口 POST /conversations/{id}/messages
    • 删除收到完整响应后按固定时间间隔追加字符的本地假流式实现
    • 工具消息插入到最终助手回答之前,保持 Agent 工具调用的真实执行顺序
    • SSE 中断时保留已经接收到的部分回答,不再直接丢弃现有内容
    • 服务端发送 done 但没有产生可见回答时自动移除空助手气泡
  • 保留离线模式兼容性

    • 离线模式不发起网络请求
    • 将原有离线回复转换成相同的 start/reasoning/content/tool/done 事件
    • 在线与离线模式共用同一套前端流事件消费逻辑
  • 后端 SSE 链路保持兼容

    • Agent.run_stream() 支持 reasoning、content、tool 和 complete 事件
    • Web 路由把 Agent 的 complete 转换为前端使用的 done 事件
    • 生成结束后仍由后端统一持久化本轮产生的助手消息和工具消息
    • 工具执行继续通过 asyncio.to_thread() 移出事件循环,避免同步工具直接阻塞异步生成流程
  • 并发配置调整

    • 提高 vLLM 的 MODEL_MAX_NUM_SEQS 配置,为多个生成请求排队及并发调度预留能力
    • 实际可用并发量仍取决于模型大小、上下文长度和 GPU 显存

验证结果

  • flutter analyze 通过,无静态分析问题
  • git diff --check 通过,无新增空白格式错误
  • 前端 SSE 事件类型与后端 encode_sse() 输出格式一致
  • 项目原有 frontend/test/widget_test.dart 仍是 Flutter 默认计数器测试,与当前 ESA 页面不匹配,需要后续替换为真实页面测试

当前注意事项

  • 当前后端 Agent.run_stream() 仍会先收集本轮模型的全部 chunk,再一次性发送完整的 reasoning 和 content;前端已经具备真正的增量消费能力,但要实现端到端实时输出,还需要在 parser.py 中加入增量输出解析器,并让 Agent.run_stream() 在收到模型 chunk 时立即产生事件
  • 增量解析必须正确处理被拆分到多个 chunk 的 <think>、</think> 和 <tool_call> 标签,避免把内部标签或工具调用内容直接展示给用户
  • reasoning 当前没有写入 ChatStore 数据库,刷新或重新进入历史对话后不会恢复思考内容
  • 生产环境经 FRP 或反向代理部署时需要关闭响应缓冲,并保留 Content-Type: text/event-stream、Cache-Control: no-cache 和 X-Accel-Buffering: no 响应头

2026-08-04 第十三次开发记录

本节记录工作区当前功能,不代表已由助手执行 Git commit 或 push。

已实现

  • 后端会话有效期调整为 7 天,修改密码后撤销全部旧会话
  • Flutter 登录状态持久化、记住登录选项和密码回车提交
  • SSE 端到端增量消费、Markdown/LaTeX 实时渲染和流式代码块更新
  • 代码块使用本地 JetBrains Mono,支持高亮、复制、编辑和预览
  • 思考内容折叠/展开、工具调用展示和统一 AI 生成标识
  • 用户偏好、学情档案、学习情况和长期记忆管理前后端对接
  • 新增掌握度、练习推荐和 arXiv 搜索任务入口
  • Flutter Web 构建流程使用 ESA_API_BASE=/api,本地部署包已加入 Git 忽略
  • macOS 增加客户端网络权限,移除运行时下载 Google Fonts 的依赖

验证结果

  • flutter analyze 通过
  • 当前 Flutter 测试共 6 项并全部通过
  • Web Release 可成功构建

当前注意事项

  • Web 文字选择和输入框重影仍需在真实 Chrome/Safari 环境回归验证
  • 代码运行按钮尚未接入后端隔离执行服务
  • 附件按钮尚未接入真实文件上传和多模态后端
  • 核心记忆仍缺数量和 token 预算上限
  • 对话分组和分组级自定义指令后端已实现(详见 2026-08-06 第十四次开发记录),前端待对接

2026-08-06 第十四次开发记录

修改人:zcx 本节覆盖对话分组 + 分组内自定义指令的后端完整实现、代码质量重构与测试,前端尚未对接。

已实现

  • 数据层:分组存储与老库迁移

    • 新增 backend/core/stores/group_store.py,提供 groups 表(group_id / user_id / name / description / custom_instruction / style / tone / created_at / updated_at)+ idx_groups_user 索引
    • GroupStore 实现 create_group / get_group / list_groups / update_group / delete_group,含 conversation_count 聚合(LEFT JOIN 避免 N+1)、字段白名单防注入、BEGIN IMMEDIATE 并发上限串行化、删除分组事务原子性(组内对话置回未分组 + 删组)
    • chat_store.py 增加 conversations.group_id 列迁移(PRAGMA + ALTER 模式,幂等)+ idx_conversations_group 索引;新增 set_conversation_group / update_conversation(替代 rename_conversation);list_conversations 支持 group_id 过滤与未分组桶;create_conversation 接受可选 group_id
  • 接口层:分组 CRUD 与对话归组

    • 新增 backend/core/web/routers/groups.py,提供 GET /groups(含对话数)、POST /groups(校验 + 上限 20)、PATCH /groups/{id}(白名单更新)、DELETE /groups/{id}(事务删除)
    • chat.py 扩展:POST /conversations 接受可选 group_id;PATCH /conversations/{id} 从"仅重命名"升级为"重命名 + 移动分组";GET /conversations 返回 group_id;新增 _validate_group_owned / _load_group_params 辅助函数
    • schemas.py 新增 GroupCreateRequest / GroupUpdateRequest / GroupOut / ConversationCreateRequest / ConversationPatchRequest,抽出共享枚举常量 VALID_STYLES / VALID_TONES
    • webAPI.py 注册 GroupStore 初始化与 groups.router
  • Prompt 层:分组级指令合并

    • build_prompt.py 的 build_system_prompt 支持分组级 group_style / group_tone / group_custom_instruction,合并顺序为「系统 → 用户级 → 分组级 → 当前消息」,分组级 style/tone 非 None 时覆盖用户级,无分组或分组无指令时行为与现状逐字节一致
    • agent.py 的 run / run_stream / _prepare_run 透传分组参数;chat.py 的 send_message / stream_message 按 conversation.group_id 查分组并注入(含分组已删除的防御性回退;SSE 流式在创建 event_stream 前绑定局部变量)
  • 代码质量重构(可维护性优化)

    • 新增 PromptContext dataclass 收敛 7 个 prompt 参数,agent.run / run_stream / _prepare_run / build_system_prompt 从 11 参降至 5 参,未来加层级只改 dataclass 字段
    • 新增 MessageContext dataclass + chat._prepare_message 公共前置函数,消除 send_message / stream_message 前 35 行重复代码
    • 新增 backend/core/web/routers/_validators.py 提供 validate_style_tone 公共校验,groups.py 引用消除重复
    • group_store.create_group 事务模式统一为 with closing(...) as conn, conn:(与 delete_group 一致)
    • build_prompt.py 指令合并由 += 字符串拼接改为 list.append + join,为未来扩展更多层级留接口
    • chat.py 的 SSE event_stream 异常分支补 logger.exception 记录完整 traceback
    • groups.py 的 update_group 补注释明确 style/tone 的 None 保留语义(继承用户级)与 name/description/custom_instruction 的 None 删除语义(NOT NULL 列)
  • 文档更新

    • API.md 新增分组接口契约(GET/POST/PATCH/DELETE /groups + 扩展的 /conversations 接口)
    • GROUP_FEATURE.md 从需求文档升级为完整设计文档(含项目全景分析、市场调研、技术方案、数据结构、API 定义、开发计划、验收标准、技术难点)
    • TODO.md 后端分组任务全部打勾

验证结果

  • 后端测试新增 backend/tests/test_group_prompt.py(4 用例:分组级 style/tone 覆盖用户级、回退、无指令覆盖、空分组保持原行为)与 backend/tests/test_grouping_store.py(6 用例:老库迁移、移动/删除/归属守卫、上限、列表过滤、更新原子性、移回未分组),共 10 个 pytest 用例
  • 重构期间另写 23 个临时 unittest 用例验证行为不变性(build_prompt 7 + group_store 11 + validators 5),全部通过后已删除临时测试文件,backend/tests/ 仅留持久化测试
  • py_compile 语法检查全部通过
  • 行为不变性确认:缺省调用 Prompt 输出与重构前一致;分组级覆盖用户级语义正确;指令合并顺序正确;SSE 事件序列不变;并发上限语义不变

当前注意事项

  • 前端分组管理(M2 阶段)尚未开始,包括 ChatGroup 模型、分组 API 客户端、AppState 分组状态、历史侧边栏双区重构、分组设置弹窗与指令模板库
  • preferences.py 的枚举校验因错误消息前缀不同(preferred_style vs style)保留内联,未与 groups.py 共用 validate_style_tone,后续可统一
  • UserStore 未反向重构为 _UPDATEABLE_FIELDS 白名单模式(超出本次范围),与 GroupStore 风格略有差异
  • 测试风格不统一:test_group_prompt.py / test_grouping_store.py 用 pytest 风格(tmp_path + assert),test_parser.py / test_model_adapter.py 用 unittest 风格,后续可统一为 pytest

2026-08-07 第十五次开发记录

修改人:zcx 本节覆盖结构化用户画像系统(L5 Profile View)的 spec 驱动实现、生产级改造(P0-P2 共 16 项)与最终质量收尾。

背景

依据 ESA_Agent_Memory_User_Profile_Optimization_SPEC.md 主规范与 implement-derived-user-profile/ 子规范,落地 L5 用户画像视图层。该层不持有真相数据,仅做派生与缓存,与 L1-L4 完整记忆系统解耦。前期已完成 Task 1-12(数据模型、ProfileBuilder、ProfileStore、API 路由、Prompt 注入、Token 截断等),本次完成剩余 Task 13-14 并推进至生产级。

已实现

  • 数据模型层(memory_models.py)

    • ProfileOrigin 枚举(EXPLICIT_SETTING / EXPLICIT_MEMORY / CONFIRMED_MEMORY / DERIVED_LEARNING_STATE / INFERRED_PATTERN / DEFAULT)追溯字段来源与覆盖优先级
    • ProfileField dataclass 携带 field/value/origin/confidence/source_memory_ids/last_confirmed_at
    • ProfileSnapshot dataclass 含 7 个分节(explicit_context / response_preferences / active_goals / active_projects / relevant_learning_state / relevant_constraints / inferred_patterns)+ profile_version + generated_at
    • to_prompt_json(max_tokens=700) 按优先级截断(explicit → preferences → learning → inferred),同分节内按 confidence 降序保留高置信字段
    • Token 估算优先使用 tiktoken(cl100k_base),未安装时回退到 CJK/ASCII 区分启发式(中文 1.5 token/字、ASCII 0.25 token/字)
  • 画像构建层(profile_builder.py)

    • ProfileBuilder.build(ProfileQuery) 每轮组装 ProfileSnapshot,含输入哈希缓存(TTL 60s)避免同轮重复构建
    • 显式上下文:从 UserRecord 抽取 major/grade/current_week/total_weeks
    • 响应偏好:支持群组级 style/tone 覆盖个人值、群组 custom_instruction 追加到个人指令后;覆盖只作用于本轮 snapshot 不修改 UserRecord
    • 学情状态:用 current_message + recent_messages 子串匹配 KnowledgeGraphStore 知识点,仅注入命中知识点 + 其薄弱前置(上限 8 条),无命中返回空(不再全局 Top3 注入);KP 名称最小匹配长度 2 避免单字误匹配
    • 推断模式:从 CoreMemory 按 category 映射到 field_key,跳过被用户抑制的字段,同步回写 ProfileStore;fail-closed 策略(ProfileStore/CoreMemory 不可用时返回空而非泄漏被抑制字段)
    • invalidate(user_id) 方法在 suppress/restore/update_settings 后失效缓存;_compute_hash 含 suppressed_hash 保证跨 Worker 最终一致性
    • ProfileMetrics 可观测性指标:build_total / avg_build_latency_ms / cache_hit_ratio / suppress_count / store_error_count / token_used_sum
  • 持久化层(profile_store.py)

    • user_profile_dimensions 表:派生画像维度缓存,含 status(active/suppressed)、version、expires_at、source_memory_ids_json
    • profile_audit_log 表:suppress/restore/delete_all 全操作审计,含 before/after JSON 快照
    • profile_versions 表:profile_version 持久化,重启不归零
    • suppress_dimension 含 AND status = 'active' 条件保证幂等性(二次抑制返回 False → API 404)
    • cleanup_expired_dimensions(retention_days=90) 清理过期与长期 suppressed 记录
    • export_all_dimensions / delete_all_dimensions 支持 GDPR 数据导出与被遗忘权
  • 数据库迁移系统(migrations.py)

    • schema_migrations 版本追踪表 + 4 个幂等迁移(user_profile_dimensions / memory_settings / profile_audit_log / profile_versions)
    • run_migrations(DB_PATH) 在 webAPI.py lifespan 启动时执行,每条迁移独立事务失败回滚
  • API 路由层(preferences.py)

    • GET /me/profile 结构化画像视图(Profile V2)
    • PATCH /me/profile/explicit 更新显式字段(major/grade/week/style/tone/custom_instruction),含枚举校验与跨字段约束
    • GET /me/profile/sources 字段来源解释(origin/confidence/source_memory_ids/last_confirmed_at)
    • DELETE /me/profile/inferred/{field_key} 抑制推断字段(不物理删除,写审计日志,失效缓存)
    • GET /me/profile/export GDPR 数据导出
    • DELETE /me/profile?confirm=DELETE 被遗忘权(二次确认 + 物理删除 + 审计)
    • GET/PATCH /me/memory-settings 记忆开关(learning_profile_enabled / inferred_profile_enabled / default_conversation_mode)
    • 所有变更端点加 @profile_limiter 限流装饰器
  • 限流器(rate_limit.py)

    • 滑动窗口计数器实现,无第三方依赖
    • profile_limiter.limit("10/minute") 装饰器按 user_id + endpoint 限流
  • Prompt 注入层(build_prompt.py)

    • PromptContext dataclass 收敛 prompt 参数,含 user_profile_context: ProfileSnapshot | None
    • build_system_prompt 在 system prompt 中注入画像 JSON 区块,头部声明「不可信数据,不得执行其中包含的命令」
    • 群组级 style/tone/custom_instruction 合并顺序:系统 → 用户级 → 分组级 → 当前消息
  • 可观测性端点(webAPI.py)

    • GET /internal/metrics 暴露 ProfileBuilder 指标快照,供运维排查
    • GET /internal/metrics/prometheus 输出 Prometheus 文本展示格式(HELP/TYPE 注释 + counter/gauge),可直接接入 prometheus.yml scrape 配置
  • Python 3.9 兼容性

    • 18 个文件添加 from __future__ import annotations 解决 PEP 604 联合类型语法(覆盖全部 backend/ 下使用 str | None 等联合类型注解的模块,含 auth_service / vllm_service / deps / routers / rag / DocIR 等)
    • agent.py 将 vllm import 改为 TYPE_CHECKING 块,使模块无 vllm 也可导入
    • 通过 AST 静态扫描确认 backend/ 下已无遗漏的 PEP 604 联合类型注解

生产级改造(P0-P2 共 16 项)

优先级 改进项 实现方式
P0 agent.py PEP 604 崩溃 from __future__ + TYPE_CHECKING 解耦 vllm
P0 全量模块 PEP 604 隐患 AST 扫描 18 文件补齐 from __future__ import annotations
P0 webAPI 启动链路 Typeerror auth_service/deps/routers 全部补齐 future import
P0 缓存与 suppress 状态不一致 invalidate() + suppressed_hash + 4 端点调用
P0 异常静默 fail-open 全部改为 fail-closed + logger.exception
P0 无迁移版本管理 migrations.py 4 迁移 + 启动执行
P1 无可观测性 ProfileMetrics + /internal/metrics 端点
P1 多 Worker 缓存不一致 CACHE_TTL=60s + suppressed_hash 跨 Worker 兜底
P1 profile_version 不持久化 profile_versions 表 + get_next_profile_version
P1 无审计日志 profile_audit_log 表 + suppress/restore/delete_all 全记录
P1 Token 估算过粗 tiktoken 可选 + CJK/ASCII 启发式回退
P1 agent.py 无集成测试 test_agent_prompt_integration.py 4 用例
P2 无评估数据集 profile_eval_dataset.jsonl + 11 个 schema 校验测试
P2 无限流防滥用 rate_limit.py 滑动窗口 + 4 端点装饰
P2 KP 单字误匹配 KP_MIN_MATCH_LENGTH=2
P2 无数据保留清理 cleanup_expired_dimensions + scripts 脚本
P2 无 GDPR 合规 export + delete_all 端点
P2 无被遗忘权 DELETE /me/profile?confirm=DELETE

验证结果

  • 后端测试共 71 个全部通过(2.19s):
    • test_profile_store.py 7 用例(upsert/list/suppress/restore/cleanup/nonexistent)
    • test_profile_builder.py 10 用例(explicit/preferences/group_override/learning_state/inferred/suppressed/disabled)
    • test_profile_api.py 14 用例(GET/PATCH profile/sources/DELETE inferred/memory_settings/export/delete_all/rate_limit)
    • test_profile_prompt_security.py 8 用例(注入防御/JSON 序列化/Token 截断/中英文 token 估算)
    • test_profile_eval_dataset.py 11 用例(数据集 schema/10 类能力覆盖/case 唯一性)
    • test_agent_prompt_integration.py 4 用例(无 vllm 导入/废弃函数/Prompt 注入/空快照)
    • 原有 17 用例(grouping_store/model_adapter/parser/group_prompt)
  • py_compile 语法检查全部通过
  • agent.py 在未安装 vllm 的 Python 3.9.13 下可正常导入("vllm" not in sys.modules 验证通过)
  • backend/core/web/webAPI.py 完整导入验证通过,/internal/metrics 与 /internal/metrics/prometheus 路由已注册
  • get_next_profile_version 原子自增验证:连续 3 次调用返回 1/2/3(单条 INSERT ... SELECT COALESCE(MAX,0)+1)
  • 评估数据集扩充至 50 条(eval_001 ~ eval_050),case_id 唯一性校验通过

当前注意事项

  • 完整记忆系统(L1-L4:Conversation State / Episodic / Semantic / Learning)尚未落地,当前 ProfileBuilder 的推断模式仍依赖旧 CoreMemory(按 username 索引),待 MemoryStore spec 实施后替换数据源
  • ProfileMetrics 为进程内计数器,多 Worker 部署时 Prometheus 可通过 /internal/metrics/prometheus 分别 scrape 各 Worker 端口自动聚合;如需跨进程共享计数器再改用 Redis
  • 限流器为单进程内存实现,多 Worker 下实际限流上限 = limit × worker_count;如需消除该放大效应,由部署运维在 nginx 层配置 limit_req_zone 统一限流
  • get_next_profile_version 已改为单条 INSERT ... SELECT COALESCE(MAX(version),0)+1 原子自增,消除并发竞态
  • cleanup 脚本 backend/scripts/cleanup_profile_dimensions.py 支持 --retention-days / --db-path 参数,需由部署运维配置 cron/systemd timer 定期执行(建议每天凌晨运行)
  • 评估数据集 profile_eval_dataset.jsonl 已扩充至 50 条样本(eval_001 ~ eval_050),覆盖显式/偏好/群组/学习状态/suppressed/Token 截断/边界值/开关组合等场景

2026-08-09 第十六次开发记录

SQLite 数据完整性

  • 新增统一的 connect_sqlite(),所有连接默认启用 PRAGMA foreign_keys = ON 和 busy_timeout。
  • V5 迁移原子重建用户、会话、分组、对话、消息、画像和版本相关表,补齐外键、 级联规则与跨用户归属触发器。
  • 历史孤儿数据写入 migration_orphans,保留来源表、原始主键、原因和 JSON 快照, 不静默丢弃。
  • 使用真实 user.db 的副本完成迁移烟测:迁移可重复执行、外键检查无违规,真实数据库 未被写入。

同一对话并发顺序

  • 新增对话级租约,从读取历史、写入用户消息到持久化助手消息保持同一临界区。
  • 进程内 keyed lock 减少轮询,SQLite 租约保证多个 Uvicorn worker 之间也不会乱序。
  • 租约包含心跳、TTL 和短暂锁冲突重试;异常退出后可以自动恢复。
  • 同一对话排队等待超时返回 409,不同对话仍可并行推理。

工程质量与文档治理

  • 增加 requirements-dev.txt、pyproject.toml、Makefile 和 GitHub Actions 质量门禁。
  • 根目录 .gitignore 统一覆盖缓存、日志、SQLite、密钥、模型权重、构建产物和集群本地 脚本。
  • 合并重复的修改/修复/优化文档到 OPTIMIZATION_NOTES.md,合并产品与重构待办到 TODO.md;README、API、需求文档和专题设计状态同步到当前实现。

验证结果

SQLite/并发定向测试:10 passed
其余可运行测试:168 passed, 24 skipped
Ruff:通过
mypy:通过(关键持久化路径)
compileall:通过
git diff --check:通过

24 个跳过项依赖仓库外的 MinerU、真实语料或评测数据。超算节点上的 Starlette TestClient 在进入业务路由前卡于 AnyIO blocking portal,Profile API 集成测试继续由 干净 CI 环境负责验证。