跳转至

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.jsonsourceWorkspacePath + 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 第一步就写这个)

  1. Fence 格式规范
  2. 格式:```action\n{json}\n```
  3. 允许多个 action 在同一条 AI 回复里(按出现顺序执行)
  4. 后端/前端解析要宽容:允许 ```action 后跟空格/语言标记、允许 JSON 有多余逗号(用宽松 JSON parser)
  5. AI 输出非法 JSON → 前端降级显示成普通代码块 + 提示用户"这个 action 格式有问题"

  6. 三个 action 的 JSON Schema

  7. create_scenario — 生成集成测试 json(对齐 devices_mixer.json 的结构)
  8. run_analyze — 触发现有分析端点(pysidecar /analyze/rms + /analyze/freq_response
  9. create_module_schema — 生成组合级 module schema(preview only,不落盘)

  10. 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
    }
    

  11. 后端落盘路径:<workspace>/<activeProject>/integrationtest/ai_generated/<name>.json
  12. name 已存在:返回错误 + 建议名(name_2 等),让 AI 或用户决定

  13. 后端执行器设计

  14. 新建 backend_csharp/AIAgent/AiActionExecutor.cs(和 AiProviderRegistry.cs / AiAgentEndpoints.cs 同目录)
  15. 新建端点 POST /api/ai/actions/execute(在 AiAgentEndpoints.MapAIAgent 里注册)
  16. 白名单表(Dictionary<string, IActionHandler>):create_scenarioCreateScenarioHandler,依此类推
  17. 每个 handler 返回 ActionResult { success, data, error }
  18. 必须复用现有的 IsProjectActive() / GetActiveProjectDir()(在 Program.cs,可能需要重构为可注入的 service,或直接读 active.json)

  19. 前端"自动模式"开关交互定义

  20. aiStore 增加 autoMode: boolean(默认 false,localStorage 持久化)
  21. AIDrawer 头部加 toggle:🔒 确认模式 / 🚀 自动模式
  22. 打开自动模式时弹一次确认:"自动模式会跳过确认直接执行 AI 产生的所有 action,仅在安全场景使用"
  23. ChatPanel 流式渲染时:扫到 action fence 就调 aiStore.handleAction(action)

    • autoMode=false:渲染 ActionCard 等用户点
    • autoMode=true:直接调 executeAction,执行结果回显
  24. 审计日志格式 (data/ai-actions/YYYY-MM-DD.jsonl)

    {"ts":"2026-04-27T18:00:00Z","action":"create_scenario","payload":{...},"result":{"success":true,"path":"..."},"project":"UnitTest_Mixer","autoMode":false}
    

  25. 一行一个 JSON,便于 grep / jq
  26. 敏感字段不记(API key 等本来就不会出现在 action 里)

  27. Dify prompt 模板要点(指导 LLM 稳定输出合法 fence)

  28. 在 system prompt 里明确列出可用 action 列表 + 每个的 JSON Schema 示例
  29. 强调"任何需要'做事'的意图都必须输出 action fence,纯聊天不需要"
  30. 给出正反例各 1 个("用户说帮我生成测试" → ✅ 输出 action;"用户说你好" → ❌ 不输出 action)
  31. 说明"用户当前工程是 ${currentProject},你不需要在 payload 里写路径"
  32. 这部分由用户在 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.tsAiAction 类型 - [ ] ai-assistant/aiStore.tsautoMode + 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 的自己)

  1. .gitignore 刚加了 backend_csharp/data/current_link.json + backend_csharp/data/current_pro/,这两个是运行时状态,Phase 2 写代码时不要误以为它们"消失了"——它们在磁盘上,只是不入库
  2. 外层仓库d:/work/25_claude/workspace master 分支)还有未提交的 md 压缩改动(AGENTS/SOUL/TOOLS/USER 压缩 + 删 NEXT_ACTIONS.md),用户选了"留到下次",Phase 2 期间不要动它们
  3. GetActiveProjectDir() 是 Program.cs 里的局部函数(Minimal API 风格),如果 AiActionExecutor.cs 要复用,要么把它提到独立 service,要么让 executor 直接读 data/current_pro/active.json(更解耦)
  4. 前端 vite 首次启动很慢(>1 分钟,预构建依赖),后续再启动会快很多
  5. 端口约定:后端 BACKEND_PORT=5002 + 前端 --port 3002 + pysidecar 8001(用户偏好)

📚 关键对话线索

  • 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」阶段。