feat: add AI research chatbot with confirmed business tools

This commit is contained in:
yuxuanhui
2026-09-07 23:02:55 +08:00
parent 3cd280d068
commit 79ab20b4ea
44 changed files with 4647 additions and 197 deletions
+134
View File
@@ -0,0 +1,134 @@
# AI Chatbot 首版开发计划
确认日期:2026-09-07。本文件保存实施范围;实际验证结果见 [验收记录](verification.md)。
## 1. 目标与范围
在现有 WorldQuant Alpha 工作空间中增加全局右侧 chatbot,支持展开、收缩、跨页面保留会话,以及基于当前页面上下文查询和操作业务数据。
采用 **React + Semi Design + AI SDK UI,FastAPI + Pydantic AI,PostgreSQL**。模型通过用户自定义的 `baseUrl`、`apiKey` 和 `model` 接入。
首版交付完整的“查询 → 展示结果 → 预览修改 → 用户确认 → 执行并刷新页面”闭环,包含本地研究记录修改和现有同步任务操作。MCP、知识检索、多 Agent、回测及 WorldQuant 平台回写不在本期范围。
保持现有单管理员、单后端进程部署。AI 未配置或服务不可用时,原有业务功能正常使用。
## 2. 产品行为与模型配置
### 模型设置
在“个人信息”页新增独立的“大模型服务”配置区域:
- 提供 Base URL、API Key、模型标识、接口协议和启用开关。
- 接口协议支持 `chat_completions` 与 `responses`,默认前者,用户明确选择;不自动切换协议或供应商。
- 模型标识手动填写,不依赖供应商提供模型列表接口。
- Base URL 按服务端可访问的完整 API 根地址填写,支持 HTTP/HTTPS;界面说明是否需要包含 `/v1`。
- API Key 使用现有 Fernet 加密能力保存在数据库,查询接口仅返回“是否已配置”。编辑时不回填密钥;更换 Base URL 必须重新输入密钥。
- 保存配置不发起模型请求。“测试连接”使用合成文本与无副作用的测试工具,验证回答、流式输出和完整工具调用往返,并分别显示结果。
- 未通过能力测试时,允许保存配置用于修正,但不启用业务聊天。配置变更后需要重新测试。
通过 Pydantic AI 的 OpenAI provider 和对应模型适配器接入两种协议;供应商兼容性最终以测试结果为准。[模型配置文档](https://github.com/pydantic/pydantic-ai/blob/main/docs/models/openai.md)
### 聊天与页面联动
- chatbot 挂载在登录后的工作区根部,默认收缩;展开宽度默认 420px,可在 360–640px 之间调整。
- 页面切换、面板收缩不取消当前执行。提供独立的“停止生成”按钮。
- 桌面端为聊天预留布局空间,Alpha 详情和任务面板使用剩余区域;空间不足时切换显示,保留聊天和编辑草稿。统一焦点、遮罩和 Esc 行为。
- 支持新建会话、查看历史和切换会话。首版不提供消息编辑、会话分叉和历史删除。
- 发送消息时附带当前页面、详情 Alpha ID、选中 ID、筛选和排序的快照;未保存的备注草稿不自动发送。
- 服务端根据引用 ID 重新读取业务数据。切换页面不改变正在执行的请求对象。
- 使用固定组件展示 Alpha 卡片、指标表、PnL、修改预览和任务进度;提供“打开详情”“应用筛选”等按钮。
- 业务修改成功后刷新相关数据;已有未保存草稿保留,并提示数据发生变化。
## 3. 后端模块、工具与执行规则
### 共用业务模块
将现有路由中的 Alpha 查询、研究记录修改、任务创建与控制逻辑提取为共用业务模块。REST 路由和 AI 工具调用同一实现,保留现有校验、事务、任务去重与同步行为。
AI 工具只使用明确的业务接口,不接触 ORM、任意 SQL、任意 HTTP 请求或平台凭据。新增接口沿用现有 Cookie 鉴权、来源校验和请求头要求;执行工具及确认操作时重新校验登录状态。
### 首批工具
| 类别 | 工具 | 执行规则 |
| --- | --- | --- |
| 查询 | `search_alphas`、`get_alpha_facets`、`get_alpha`、`get_alpha_pnl` | 读取本地数据,分页与数量限制沿用业务规则 |
| 任务查询 | `list_jobs`、`get_job_status` | 返回进度、错误及关联对象 |
| 研究记录 | `update_research`、`bulk_update_research` | 展示修改前后差异,用户确认后执行 |
| 任务操作 | `create_sync_job`、`cancel_job`、`retry_job` | 展示操作目标和影响,用户确认后执行 |
- 工具输入输出使用类型化契约,服务端始终校验模型参数。单位、空值、数据时间和来源明确返回。
- 查询结果按需裁剪,不将整个数据库、原始平台响应或完整 PnL 序列直接放入模型上下文。
- 批量修改固定为预览时的 ID 集合,上限 100 条;明确区分“当前选中项”与“全部筛选结果”。
- 确认记录绑定登录用户、工具、参数与目标版本,客户端仅提交确认记录 ID 和同意/拒绝。确认后不能替换目标或参数。
- 为研究记录增加递增版本号。页面保存和 AI 修改均检查读取时的版本;不匹配返回冲突,保留草稿或要求重新预览。
- 使用唯一执行标识防止重复确认、重试和刷新导致重复写入;本地变更、执行结果与审计记录在同一事务提交。
- 同步类工具只创建或控制已有业务任务,返回 `job_id`。任务进度沿用现有轮询,不让模型循环等待上游。
### 对话执行与恢复
- 会话历史以服务端数据库为准;客户端不能提交系统提示、已完成工具结果或伪造确认历史。
- 使用 AI SDK UI Message Stream,通过 SSE 输出文本、工具状态和结构化结果。[协议文档](https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol)
- AI 执行由后端独立管理,与现有同步队列分开。关闭面板或网络断开不等于取消。
- 首版断线后通过历史与执行快照恢复显示,活动执行每 3 秒查询一次;不实现逐 token 断点续传。
- 停止操作先请求后端取消,再终止前端接收。已提交的研究记录修改和已创建的同步任务不回滚,结果明确展示。
- 服务重启后,未完成生成标记为中断,不自动重放写操作;持久化的待确认操作可在重新登录后继续处理,但必须重新校验版本。
- 默认每个会话同时执行一轮;每轮最多 6 次模型请求、12 次工具执行、每次模型输出上限 4096 tokens,活动执行总时限 180 秒。等待用户确认不计入时限,以上限额由后端配置。
- 模型上下文使用最近 10 个完整交互轮及本轮上下文,保持工具调用与结果成对。首版不增加额外的自动摘要模型调用。
- 记录模型、耗时、工具结果及供应商返回的 token 用量;供应商未返回用量时标为未知,不推算费用。
## 4. 接口、存储与部署变更
所有新增接口位于 `/api/v1/ai`,使用独立路由模块。
| 接口 | 职责 |
| --- | --- |
| `GET /settings`、`PUT /settings` | 读取脱敏配置、更新模型服务设置 |
| `POST /settings/test` | 测试已保存配置的必要能力 |
| `GET /conversations`、`POST /conversations` | 会话列表与创建 |
| `GET /conversations/{id}` | 获取会话历史、活动执行和待确认操作 |
| `POST /conversations/{id}/runs` | 提交新消息及页面上下文,返回 SSE |
| `GET /runs/{id}` | 获取执行状态与持久化结果快照 |
| `POST /runs/{id}/cancel` | 请求停止执行 |
| `POST /approvals/{id}/decision` | 接受或拒绝已保存的操作,并流式返回后续结果 |
运行创建请求携带客户端生成的请求 ID,用于网络重试去重。运行状态区分执行中、待确认、成功、失败、取消和中断;每个状态均有明确的界面展示。
通过新增 Alembic 迁移建立模型配置、会话、消息、执行及工具调用记录;确认信息保存在工具调用记录中。会话关联当前单管理员。已有研究记录补充版本号,旧数据从初始版本开始。
前端新增聊天传输模块,沿用现有会话失效处理,不复用只支持 `response.json()` 的普通请求函数。Caddy 验证 SSE 实时转发、连接关闭及超时行为。
锁定新增依赖版本,更新前后端锁文件。无需增加 Redis、向量数据库、Node 服务或额外容器。数据库备份覆盖新增配置密文、会话和执行记录。
## 5. 开发顺序与验收
| 阶段 | 主要工作 | 完成标准 |
| --- | --- | --- |
| 1. 业务基础 | 提取共用业务模块,增加研究记录版本校验和 AI 数据迁移 | 原有查询、修改、同步测试通过,页面能正确处理编辑冲突 |
| 2. 模型接入 | 配置界面、密钥加密、两种协议适配、能力测试 | 模拟供应商验证两种协议;错误可定位,密钥不出现在响应和日志 |
| 3. 只读聊天 | 全局面板、会话持久化、SSE、上下文、只读工具和结果卡片 | 能查询当前 Alpha,跨页面保留会话,断线后恢复结果 |
| 4. 操作闭环 | 修改预览、确认、幂等、任务操作和页面刷新 | 确认前无写入,重复确认只执行一次,冲突不覆盖数据 |
| 5. 整体验收 | 自动化回归、浏览器验证、Docker 升级验证和真实模型联调 | 满足以下场景并记录实际验证边界 |
测试覆盖:
- **模型接入:** 两种协议、错误 Key、错误模型、工具能力缺失、流式中断、429、超时,以及错误正文脱敏。
- **上下文与查询:** 选中对象指代准确;切换页面不串对象;换手率 15% 正确转换为 `0.15`;空指标保持为空;PnL 缓存缺失可解释。
- **权限与确认:** 未登录、会话失效、伪造工具结果、拒绝确认、篡改确认目标、重复提交、批量修改中存在无效 ID。
- **并发与恢复:** 页面与 AI 同时编辑产生版本冲突;执行中刷新和断线;取消前后状态一致;服务重启不重复修改或创建任务。
- **界面:** 聊天与详情同时使用、窄屏切换、键盘焦点、收缩后继续执行、未保存草稿保留、退出登录后清理界面状态。
- **回归:** 执行后端 Ruff/Pytest、前端类型检查与构建、Playwright,以及独立 PostgreSQL/Docker 的迁移和持久化验证。
自动化测试使用隔离数据库、合成 Alpha 和模拟模型服务,不调用真实供应商或 WorldQuant。真实模型联调在用户配置完成后进行,分别记录流式回答与业务工具调用是否通过。实际供应商未确定前,兼容性仅能由模拟协议测试覆盖,不能宣称已完成真实服务验证。
## 6. 实施落点
- `backend/app/business.py`:REST 与 AI 共用的业务操作;调用方管理事务,任务提交后才唤醒同步执行器。
- `backend/app/ai/contracts.py`、`provider.py`:输入契约、两种模型协议、合成能力测试和安全错误提示。
- `backend/app/ai/tools.py`:白名单工具,限制参数和返回体;写入分为预览与执行。
- `backend/app/ai/runtime.py`:独立任务、持久化执行、确认事务、调用预算、取消、历史和 SSE 投影。
- `backend/app/ai/routes.py`:沿用 Cookie 和来源检查的 AI API。
- `frontend/src/ai/`:模型设置、AI SDK 传输、全局面板及固定业务卡片。宽度不足 1440px 时切换聊天与详情/任务显示;640px 以下聊天占满屏幕。
- 数据库迁移 `0002` 增加 AI 表与 `research.version`;研究记录的普通 PATCH 必须携带 `version`,批量 PATCH 必须携带完整 `versions` 映射。
- 失败、取消或中断的轮次使用服务端保存的用户消息与工具审计事实补足完整历史,不重放未配对的模型调用,也不增加摘要模型请求。
模型设置变更会使现有待确认轮次失效,需要停止该轮并重新预览。自动化仅验证固定模拟行为与协议;真实模型对自然语言指代和工具选择的效果,需要配置供应商后另行联调。
+10 -2
View File
@@ -5,6 +5,7 @@
## 已确认范围
- 首期:个人信息与会话、Alpha 列表与详情、本地研究记录、可靠同步、Docker 部署。
- 当前扩展:全局右侧 AI 研究助手,自定义模型服务,通过查询工具及用户确认操作业务;具体范围见 [AI Chatbot 开发计划](ai-chatbot-plan.md)。
- Python + React + TypeScript + Semi Design,前后端分别位于 backend/ 和 frontend/,独立依赖与测试。
- PostgreSQL 存储数据,FastAPI 提供 OpenAPI 契约,HTTPX 统一异步调用 WorldQuant。
- React 19 使用 @douyinfe/semi-ui-19。Caddy 提供静态资源、API 代理与公网 HTTPS。
@@ -34,9 +35,15 @@
- 批量加减标签及改研究状态;CSV 按当前筛选与排序导出全部结果,不限制为 500 条。
- 指标缺失保留 null,不伪装成零;本地研究状态与平台状态、检查结果分开。
### AI 研究助手
React + Semi Design + AI SDK UI 提供可调整宽度的聊天面板;FastAPI + Pydantic AI 管理独立异步执行,PostgreSQL 保存模型密文、会话、消息、执行及确认审计。用户明确选择 Chat Completions 或 Responses,能力测试通过后启用。AI 工具仅通过 `business.py` 共用业务模块读取本地数据、预览研究修改和同步操作;写入必须通过持久化确认,研究记录使用版本检查。会话历史由服务端决定,断线通过快照恢复,生成中断不重放写操作。
不引入 MCP、知识检索、多 Agent、向量库、Redis、额外容器、回测或平台回写。单管理员、单后端进程约束保持。模型不可用时现有业务仍可用。
## 模块与接口
模块为账户、Alpha、同步任务、WorldQuant 集成。所有上游认证、会话、分页和退避集中封装。
模块为账户、Alpha、同步任务、WorldQuant 集成和 AI;业务查询、研究修改、任务控制统一进入 `business.py`。所有上游认证、会话、分页和退避集中封装。
页面读取本地数据库。`/api/v1/auth` 管理登录,`/account` 管理配置与资料,`/alphas` 管理查询及研究记录,`/alphas/{id}/pnl` 读取缓存,`/sync-jobs` 创建、查询、取消和重试任务。
长任务返回 job ID;前端轮询。首期单后端进程运行异步任务,任务及分页检查点持久化。
每页原子落库、按 Alpha ID 更新、失败重试及重启恢复;429 遵守 Retry-After,其余暂时性错误有界退避。
@@ -47,9 +54,10 @@
| 阶段 | 能力 | 依据 |
| --- | --- | --- |
| 一 | 账户、列表、研究记录、同步、部署 | 本文件首期范围 |
| 一扩展 | AI 聊天、模型配置、只读业务工具、修改确认闭环 | [AI Chatbot 开发计划](ai-chatbot-plan.md) |
| 二 | 数据集/字段/算子、模板、批次队列、AST 校验、实验去重、暂停恢复 | 旧系统采样→密度→深度回测,以及 [回测台账](https://mail.google.com/mail/#all/19ea68a7dde5ceaa) |
| 三 | PnL 稳定性、比较、相关性、稳健性、跨区变体、Super Alpha 组合 | 旧系统有效分析能力 |
| 四 | 假设与实验记录、CLI/MCP、论坛检索、模型接入、预算及停止条件 | [决策摘要](https://mail.google.com/mail/#all/19fc16ce3f17311c)、[可复盘流程](https://mail.google.com/mail/#all/1a00ee69df671d4c) |
| 四 | 假设与实验记录、CLI/MCP、论坛检索与进一步的研究编排 | [决策摘要](https://mail.google.com/mail/#all/19fc16ce3f17311c)、[可复盘流程](https://mail.google.com/mail/#all/1a00ee69df671d4c) |
| 后续 | 平台回写、检查、提交、顾问表现 | 另行确认业务范围 |
AI 复用系统接口,不直接写数据库,模型可替换。论坛效果与阈值必须验证后才可成为规则。首期不提前建设后续空模块。
+28 -4
View File
@@ -1,4 +1,4 @@
# 首期验收记录
# 项目与 AI 助手验收记录
日期:2026-09-07。验证范围为本地实现、模拟 WorldQuant 上游、实际 PostgreSQL/Docker。未访问真实 WorldQuant 账户,没有调用平台回测、检查、属性修改或提交接口。
@@ -7,9 +7,9 @@
| 检查 | 结果与证据 |
| --- | --- |
| 后端静态检查 | `uv run ruff check app tests` 通过 |
| 后端自动化测试 | `uv run pytest -q`:31 项通过 |
| 后端自动化测试 | `uv run pytest -q`:68 项通过 |
| 前端类型与生产构建 | `pnpm build` 通过;React 19.2.8、Semi UI 19 2.103.0,含 React 19 adapter |
| 浏览器验收 | `pnpm test`:2 项端到端测试通过,使用 620 条合成记录 |
| 浏览器验收 | `pnpm test`:4 项端到端测试通过,使用 620 条合成记录 |
| 空库部署与迁移 | Docker `web + backend + db` 从新卷启动成功,`alembic upgrade head` 成功 |
| 迁移与模型一致性 | PostgreSQL 上 `alembic check` 返回 `No new upgrade operations detected` |
| 持久化 | 强制替换三个容器后,服务端登录会话、Alpha、备注、标签与研究状态保留 |
@@ -20,7 +20,7 @@
Docker 运行检查脚本为 `backend/tests/docker_acceptance.py`,仅允许操作独立 `wq-alpha-acceptance*` 项目。测试容器与测试卷已清理;合成数据不进入正式本机实例。
正式本机项目 `wq-alpha` 已启动于 `http://localhost:8080`,空库登录/退出、迁移一致性和健康检查通过;Alpha 与任务表初始均为 0,WorldQuant 尚未配置。初始凭据保存在权限为 `0600` 的项目 `.env` 中。
此前首期验收时,正式本机项目 `wq-alpha` 已启动于 `http://localhost:8080`,空库登录/退出、迁移一致性和健康检查通过;Alpha 与任务表初始均为 0,WorldQuant 尚未配置。初始凭据保存在权限为 `0600` 的项目 `.env` 中。本次 AI 开发未修改或重新部署该正式实例。
## 已覆盖行为
@@ -41,6 +41,27 @@ Docker 运行检查脚本为 `backend/tests/docker_acceptance.py`,仅允许操
构建仍有 Semi 间接依赖 `lottie-web` 的 `eval` 提示,构建成功;当前页面不使用该表达式动画能力,未放宽生产 CSP 的 `script-src`。端到端测试未发现 JavaScript 运行异常。
## AI 助手追加验收
AI SDK UI `6.0.277` / `@ai-sdk/react 3.0.280`、Pydantic AI slim `1.97.0` 均锁定精确版本;两种适配器使用锁定的 OpenAI SDK。新增范围与代码落点见 [AI Chatbot 开发计划](ai-chatbot-plan.md)。
| 检查 | 实际验证 |
| --- | --- |
| 两种模型协议 | 用真实 Pydantic AI/OpenAI SDK 适配器访问 HTTPX 模拟 SSE,分别通过回答、流式输出及随机标记工具往返 |
| 供应商错误 | 两种协议覆盖 401、404、429、超时、损坏帧、缺少结束帧、缺失工具能力;公开错误和测试日志未包含测试密钥或供应商错误正文 |
| 历史与授权 | Cookie 鉴权、过期确认拒绝、伪造历史/确认参数拒绝、相同请求 ID 去重与冲突、重新登录处理待确认记录 |
| 确认事务 | 研究修改、创建/取消/重试同步任务在确认前不写入,重复确认只执行一次;两次连续 deferred 确认能正确续答 |
| 冲突与批量 | 页面保存和 AI 确认使用版本 CAS;冲突不覆盖新记录;批量无效 ID 与部分版本冲突无部分写入 |
| 失败恢复 | 断开 SSE 不取消运行;显式取消、超时、请求预算;生成中断不重放,已提交操作即使续答失败仍保留在下一轮上下文 |
| 本地读取 | 搜索、详情、筛选选项、任务和 PnL 摘要;来源、时间和单位明确返回,空指标保留 null,缺失 PnL 可解释,完整序列不进入模型上下文 |
| 浏览器 | 配置、测试并启用;当前详情指代、筛选 15% 转为 0.15、固定结果卡片与应用筛选、确认后刷新并保留人工草稿、历史刷新恢复、页面切换/收起继续执行、窄屏、Esc、停止及退出失效 |
| 独立 Docker | 项目 `wq-alpha-acceptance-ai`,入口 `127.0.0.1:18089`,隔离 PostgreSQL 17;模拟模型仅在测试容器内监听,不调用真实供应商或 WorldQuant |
| Caddy SSE | 读取到文本帧时后端运行仍为 running;关闭连接后后台运行完成 |
| 跨重启确认 | 保存待确认记录后重建全部容器,配置密文及能力测试状态保留,确认可继续处理;重复确认版本只递增一次 |
| 备份与升级 | 自定义格式备份恢复到独立库,AI 会话/运行/工具确认/配置密文存在;仅对该测试恢复库降至 0001 再升级 head,原备注保持、version 初始化为 1,Alembic check 无差异 |
截图已人工查看:`output/playwright/ai-approval.png` 展示详情和聊天并排、修改差异及确认;`ai-query.png` 展示业务结果卡片和筛选操作。自动化使用合成文本,**没有验证真实模型的自然语言理解质量或真实供应商兼容性**。供应商不返回完整用量时显示“用量未提供”,不估算费用。测试快照与数据库备份均在忽略目录内。
## 待真实环境验证
这些项目需要用户自己的账户或域名,尚未取得实测证据:
@@ -48,6 +69,9 @@ Docker 运行检查脚本为 `backend/tests/docker_acceptance.py`,仅允许操
1. 当前 WorldQuant 账户的实际认证、人工验证页面及权限限制。
2. 真实账户的完整 Alpha 分页、实际 REGULAR/SUPER/PYTHON 字段和 PnL schema。
3. 真实域名的 DNS、ACME 证书签发/续期和公网 HTTPS 访问。
4. 用户自定义供应商的真实 Base URL、API Key、模型权限、两种协议的兼容性以及工具选择效果。
真实模型联调步骤:保存自己的模型配置,分别检查回答、流式输出、测试工具;启用后对一个已同步 Alpha 做只读查询,再预览一次本地备注修改。核对目标和差异后确认,记录模型返回与业务结果。未配置之前不开展有费用的模型联调。
只读联调步骤:在正式本机页面登录并配置 WorldQuant,连接成功后先刷新个人资料、导入一个已知 Alpha ID、获取其 PnL,再执行全量同步。对一条记录保存本地备注后再次刷新,并重启后检查记录和任务。未完成上述步骤前,不把模拟测试结论视为真实平台兼容性保证。