Phase 2 Handoff — AI Agent Action 白名单 + 配置生成
上一轮 session 的完整决策归档。新 task 开局读这一份 +
docs/ai-assistant-roadmap.md即可无缝接上。
📌 当前状态(2026-04-27)
- Phase 1 已完成并 commit:
[cline 6da5594]— AI Chat MVP 打通,Dify + DeepSeek 双 provider 流式 OK - 分支:
cline(work-cline worktree,.git文件指向04_development/.git/worktrees/work-cline) - 下一步:Phase 2 起草
docs/ai-actions-spec.md,review 通过后再动代码
🎯 Phase 2 七项决策(已对齐,新 task 无需再问)
| # | 维度 | 决策 |
|---|---|---|
| 1 | Action 协议承载 | A3 — AI 在 markdown 里输出 ```action {json}``` fence,前端/后端提取(不用 Dify Agent 的 tool_calls,不用结构化输出,LLM 友好) |
| 2 | 白名单范围 | B3 分批 — Phase 2 先做三个只读/生成类:create_scenario / run_analyze / create_module_schema;写入类(patch_preset / engine_start/stop)留 Phase 2.2 |
| 3 | 端点映射 | C3 边做边查 — 不先搞全量清单,做第一个 action 时再 grep app.Map |
| 4 | 本期交付范围 | D2 骨架 + 1 个端到端 demo — 协议定义 + AiActionExecutor 骨架 + 前端 ActionCard + create_scenario 全链路跑通 |
| 5 | 确认策略 | III 自动模式开关 — 前端 AI 抽屉里加开关,默认关(每个 action 弹确认卡),开时免确认直接执行 |
| 6 | Scenario 落盘 | <workspace>/<activeProject>/integrationtest/ai_generated/<name>.json(用 ai_generated/ 子目录和人工写的隔离) |
| 7 | 工程路径来源 | 后端 GetActiveProjectDir() — Program.cs 已有的辅助函数,从 data/current_pro/active.json 的 sourceWorkspacePath + folderName 拼出绝对路径,不信任 AI 填路径 |
🏗️ 架构数据流(场景:「帮我给当前链路生成集成测试并跑一下」)
[用户] 在 ChatPanel 打字
│
▼
[前端 useAiChat] 打包上下文:用户原文 + 当前 link.json + profile 信息
│ POST /api/ai/chat
▼
[后端 AiAgentEndpoints] 拼 system prompt(含可用 action 列表 + GetActiveProjectDir 信息)
│ 转发到 Dify /chat-messages(SSE 流式)
▼
[Dify → LLM] 根据 prompt + 知识库生成回复
│ 内容含 markdown 正文 + ```action {json}``` fence
▼
[SSE 一路回流] Dify → 后端 → 前端 ChatPanel 实时渲染
│
▼
[前端 ChatPanel] 扫文本里的 ```action``` fence,提取成 ActionCard
│ (若"自动模式"开启:跳过确认直接执行;关闭:等用户点确认)
▼
[用户点确认] POST /api/ai/actions/execute { action }
│
▼
[后端 AiActionExecutor]
├─ 白名单校验(type ∈ 已知 action)
├─ JSON Schema 校验 payload
├─ 检查 IsProjectActive()(没激活工程直接拒)
├─ 调 GetActiveProjectDir() 拼路径
├─ 路由到具体 handler(create_scenario → 写 json 到 ai_generated/)
├─ 写审计日志 data/ai-actions/YYYY-MM-DD.jsonl
└─ 返回执行结果
│
▼
[前端] 把执行结果塞回聊天流,渲染成系统消息:"✅ 已创建 xxx.json"
📄 docs/ai-actions-spec.md 应包含的 7 个章节(新 task 第一步就写这个)
- Fence 格式规范
- 格式:
```action\n{json}\n``` - 允许多个 action 在同一条 AI 回复里(按出现顺序执行)
- 后端/前端解析要宽容:允许 ```action 后跟空格/语言标记、允许 JSON 有多余逗号(用宽松 JSON parser)
-
AI 输出非法 JSON → 前端降级显示成普通代码块 + 提示用户"这个 action 格式有问题"
-
三个 action 的 JSON Schema
create_scenario— 生成集成测试 json(对齐devices_mixer.json的结构)run_analyze— 触发现有分析端点(pysidecar/analyze/rms+/analyze/freq_response)-
create_module_schema— 生成组合级 module schema(preview only,不落盘) -
create_scenario详细 payload schema(对齐 devices_mixer.json){ "type": "create_scenario", "payload": { "name": "xxx", // 文件名(不含 .json) "description": "...", "e2eSpec": "e2e/integration-profile.spec.ts", // 默认值 "testProfiles": [ { "profileName": "testmixer", "runDurationSec": 5, "wavOutput": { sinkId, path, filename }, "expectedResults": { minRmsDb, ch0PeakFreqHz, ch0PeakToleranceHz }, "sinkCriteria": { "<sinkId>": { outputChannels, minRmsDb, maxRmsDb, perChannelFreqChecks } } } ] }, "requireConfirm": true } - 后端落盘路径:
<workspace>/<activeProject>/integrationtest/ai_generated/<name>.json -
若
name已存在:返回错误 + 建议名(name_2等),让 AI 或用户决定 -
后端执行器设计
- 新建
backend_csharp/AIAgent/AiActionExecutor.cs(和AiProviderRegistry.cs/AiAgentEndpoints.cs同目录) - 新建端点
POST /api/ai/actions/execute(在AiAgentEndpoints.MapAIAgent里注册) - 白名单表(
Dictionary<string, IActionHandler>):create_scenario→CreateScenarioHandler,依此类推 - 每个 handler 返回
ActionResult { success, data, error } -
必须复用现有的
IsProjectActive()/GetActiveProjectDir()(在 Program.cs,可能需要重构为可注入的 service,或直接读 active.json) -
前端"自动模式"开关交互定义
aiStore增加autoMode: boolean(默认 false,localStorage 持久化)- AIDrawer 头部加 toggle:🔒 确认模式 / 🚀 自动模式
- 打开自动模式时弹一次确认:"自动模式会跳过确认直接执行 AI 产生的所有 action,仅在安全场景使用"
-
ChatPanel 流式渲染时:扫到 action fence 就调
aiStore.handleAction(action)- autoMode=false:渲染 ActionCard 等用户点
- autoMode=true:直接调
executeAction,执行结果回显
-
审计日志格式 (
data/ai-actions/YYYY-MM-DD.jsonl) - 一行一个 JSON,便于
grep/jq -
敏感字段不记(API key 等本来就不会出现在 action 里)
-
Dify prompt 模板要点(指导 LLM 稳定输出合法 fence)
- 在 system prompt 里明确列出可用 action 列表 + 每个的 JSON Schema 示例
- 强调"任何需要'做事'的意图都必须输出
actionfence,纯聊天不需要" - 给出正反例各 1 个("用户说帮我生成测试" → ✅ 输出 action;"用户说你好" → ❌ 不输出 action)
- 说明"用户当前工程是
${currentProject},你不需要在 payload 里写路径" - 这部分由用户在 Dify 管理后台配置,后端只负责把
${currentProject}等 inputs 塞进去
🔧 实施顺序(新 task 建议按这个跑)
阶段 1:文档(不动代码)
- [ ] 写 docs/ai-actions-spec.md(上面 7 章节)
- [ ] 用户 review,确认 schema 细节
阶段 2:后端骨架
- [ ] 新建 AIAgent/AiActionExecutor.cs(handler 注册表 + JSON Schema 校验)
- [ ] 新建 AIAgent/Handlers/CreateScenarioHandler.cs
- [ ] 在 AiAgentEndpoints.MapAIAgent 注册 POST /api/ai/actions/execute
- [ ] 审计日志写入
- [ ] 用 curl / Postman 直接打这个端点,验证不经前端也能用
阶段 3:前端
- [ ] ai-assistant/types.ts 加 AiAction 类型
- [ ] ai-assistant/aiStore.ts 加 autoMode + pendingActions[] + executeAction()
- [ ] ai-assistant/useAiChat.ts 流式解析 action fence
- [ ] 新建 ai-assistant/ActionCard.vue(待确认动作卡片)
- [ ] ChatPanel.vue 集成 ActionCard 渲染
- [ ] AIDrawer.vue 加自动模式开关
阶段 4:Dify prompt(你侧,人工) - [ ] 在 Dify 管理后台更新 system prompt 模板 - [ ] 添加 action 列表 + JSON Schema 示例 - [ ] 测试输出稳定性
阶段 5:端到端验收
- [ ] 打开一个 workspace,激活 UnitTest_Mixer 工程
- [ ] 在 AI 抽屉里说"帮我给当前链路生成一个 1kHz 正弦波测试"
- [ ] 看到 AI 流式返回带 action fence
- [ ] ActionCard 显示 → 点确认
- [ ] 检查 <workspace>/UnitTest_Mixer/integrationtest/ai_generated/xxx.json 已生成
- [ ] 检查 data/ai-actions/2026-xx-xx.jsonl 有记录
- [ ] 打开集成测试面板,能看到这个 ai_generated 的 scenario
- [ ] 切"自动模式"开关,重复一次,验证免确认直接执行
🧩 需要关注的现有代码位置(新 task 起手直接去看)
| 路径 | 作用 |
|---|---|
backend_csharp/AIAgent/AiAgentEndpoints.cs |
Phase 1 的 /providers、/health、/chat SSE — Phase 2 要在这里加 /actions/execute |
backend_csharp/AIAgent/AiProviderRegistry.cs |
Provider 注册表(Dify / DeepSeek) |
backend_csharp/AIAgent/Abstractions/AiContracts.cs |
AiChatRequest / AiChunk 等数据契约 — 可能要加 AiAction 类型 |
backend_csharp/AIAgent/config/ai-providers.json |
Provider 配置(已有 Dify + 2 个 DeepSeek) |
backend_csharp/Program.cs |
IsProjectActive() / GetActiveProjectDir() / workspacePath 全局变量 — Phase 2 要复用 |
backend_csharp/test/integrationtest/UnitTest_Mixer/integrationtest/devices_mixer.json |
scenario JSON 的 schema 参考样板 |
frontend_vue3/src/ai-assistant/ |
Phase 1 的 ChatPanel / AIDrawer / aiStore / useAiChat / types — Phase 2 要扩展并新增 ActionCard.vue |
⚠️ 已知的小坑(提醒新 task 的自己)
.gitignore刚加了backend_csharp/data/current_link.json+backend_csharp/data/current_pro/,这两个是运行时状态,Phase 2 写代码时不要误以为它们"消失了"——它们在磁盘上,只是不入库- 外层仓库(
d:/work/25_claude/workspacemaster 分支)还有未提交的 md 压缩改动(AGENTS/SOUL/TOOLS/USER 压缩 + 删 NEXT_ACTIONS.md),用户选了"留到下次",Phase 2 期间不要动它们 GetActiveProjectDir()是 Program.cs 里的局部函数(Minimal API 风格),如果AiActionExecutor.cs要复用,要么把它提到独立 service,要么让 executor 直接读data/current_pro/active.json(更解耦)- 前端 vite 首次启动很慢(>1 分钟,预构建依赖),后续再启动会快很多
- 端口约定:后端
BACKEND_PORT=5002+ 前端--port 3002+ pysidecar8001(用户偏好)
📚 关键对话线索
- Phase 2 路径组合:A3 B3 C3 D2 + III
- 用户原话(关键约束):
- "AI 最终生成的不是 ts 文件吧,应该是测试用的哪个 json 文件"
- "这个路径用户一定会选择,在第一次打开的时候需要选择 workspace,然后激活工程...ai 生成的时候直接落盘 workspace+active project 然后是 integrationtest..."
- "III 先设置开关,后续按照白名单进行区分"
- "playwright e2e 的本来就应该放在后端落盘才合理"
本文档由 Phase 1 验收 session 末尾(2026-04-27 18:47)生成,为 Phase 2 新 task 开局所用。新 task 读完本文档 + ai-assistant-roadmap.md 即可直接进入「写 docs/ai-actions-spec.md」阶段。