一、文档生成
参考 ai coding工具共性(六)spec driven(2)claude code实战&SDD-CSDN博客
先让ai梳理需求
帮我梳理 claude code这个产品的核心功能模块,按类别分组,每个模块用一两句话说明它做什么。
再让ai生成初步文档
我想实现一个类似claude code的code agent,我的需求是:做一个可视化的web界面来和用户交互,用户选择工作区、输入指令、运行--》agent输出--》如果涉及文件改动,需要用户点击确认--》文件落盘。后端语言使用python,可以使用langchin、mcp等主流框架,考虑用户指令涉及的修改文件比较多,需要像cursor、claude code这些主流软件一样实现流式修改文件。代码规范:目录需要按功能划分,代码不要分割成很多函数,这只是个人demo,不需要过于包装,代码简单可读即可,你帮我出一个详细的设计文档,让ai可以一键生成代码
关键逻辑补充
对于生成的文档,追问细节(claude code是怎么实现的),ai回答后,让它补充到文档中。
比如claude code和llm是怎么交互的?
用户指令 → Claude Code 构造 prompt → LLM 返回 tool call → 执行工具 → 结果反馈给 LLM → 循环直到完成
带了哪些信息给llm?
怎么找到关键文件的?
Claude Code 给 LLM 配了一套工具,然后让 LLM 自主规划搜索路径,通过多轮 tool call + 结果反馈的 ReAct 循环,逐步定位目标文件------本质上是 LLM 在"自己摸索"代码库。
简答:混合检索,不是只靠一种。
在 Claude Code 这类 Agent 里,典型优先级通常是:
- 关键词/符号检索(主力)
最常用、最快、可解释性最好(函数名、类名、报错、路径词)。
- 结构化线索检索
路径模式、import/call 关系、邻近代码块扩展。
- 语义检索(按需)
当用户描述很抽象时再启用("处理登录态的逻辑在哪")。
一般会是下面几层,从快到慢:
- L0:会话内上下文
当前对话、你刚打开的文件、最近修改、光标附近代码,这些是"最高优先级、零检索成本"的信息。- L1:符号/结构级检索(高精度)
先用代码结构信息(函数、类、引用关系、import 图)缩小范围,比纯文本 grep 更懂代码语义。- L2:关键词检索(高召回)
类似 ripgrep/BM25,速度非常快,擅长精确词命中(函数名、配置项、报错文本)。- L3:语义检索(向量)
当你说"找处理鉴权的地方"这种不带精确关键词的问题时,embedding 检索能补上关键词检索的盲区。- L4:重排与裁剪(质量控制)
候选片段会再做相关性排序、去重、邻近扩展(补 imports/调用方),并控制 token 预算再喂给 LLM。
diff是谁决定的?
- 选哪些文件:LLM 根据上下文自主决定 read/edit 哪些文件
- 改成什么内容:LLM 直接输出新代码,App 原样写入
- 改动范围大小:一次改1个文件还是10个,LLM 说了算
App 本身不会对"改动内容的正确性"做任何校验,它只是个忠实的执行器。
"返回修改块/补丁语义,而不是返回整个文档内容
后续处理是什么?
对于 LLM 产出的 diff,Claude Code 这类 Agent 一般会做一整套后处理,不是直接写盘:
格式与结构校验
先检查 diff/patch 是否可解析、文件路径是否合法、操作类型是否受支持。
安全校验
防路径越权(如
../)、防改动工作区外文件、必要时限制敏感文件写入。冲突检测
用文件哈希或版本戳比对当前文件是否已变化;变了就报冲突,不盲写。
预览与确认
把改动展示给用户(按文件、按 hunk),通常需要用户确认后才 apply。
应用策略
不是"整包替换",通常按 patch 精确应用;失败时做回滚/部分失败提示。
验证步骤(可选但推荐)
自动跑 lint/test/typecheck;失败会反馈并可能触发下一轮修复。
状态与审计记录
更新任务状态(
waiting_confirm/applied/failed),记录失败原因与上下文。
内置tools是怎么用的?
在 Claude Code 里,内置 tools 本质上是给 LLM 的"可执行手脚",让它不只会说,还能查、改、跑、验。可按职责分这几类:
代码与文件工具
读文件、搜索代码、改文件、看 diff。
作用:拿证据、定位改动点、生成精确修改而不是瞎写。
终端执行工具
跑命令(测试、构建、安装依赖、git 状态等)。
作用:把"建议"变成"可验证结果"。
项目上下文工具
获取工作区状态、打开文件、光标、诊断信息等。
作用:让 LLM 基于当前 IDE 情境做决策。
版本控制/协作工具
看分支、提交、PR/MR(取决于环境权限)。
作用:把改动进入团队协作流程。
外部系统工具(可选)
比如 Jira、GitLab、文档系统、聊天系统。
作用:跨系统查信息或执行工作流。
浏览器/自动化工具(可选)
用于页面操作、E2E 验证、抓取结果。
作用:验证前端行为而不只看静态代码。
其他细节打磨
其他不确定(代码怎么实现的)也可以让ai列出来,比如后端项目结构、前端交互细节、task有哪些状态,然后对照文档,继续沟通改进。比如结构精简、交互调整。
最后的文档
你是一个资深的软件架构师、技术负责人(Tech Lead)、产品经理和技术文档专家。
我会给你一份经历过多轮迭代的软件需求/设计文档。
背景:
文档经过多次补充与修改
存在明显的"更新痕迹"
有些内容可能重复、前后矛盾、表达不一致
有些章节可能已经过时,但未被清理
文档风格不统一,部分内容像讨论稿而不是正式方案
你的目标不是局部修改,而是:
**把这份文档 review 并重构为"项目启动前可直接定稿"的正式版本。**

需求
# 类 Claude Code 可视化 Code Agent 需求与总体设计文档(V1)
## 一、文档说明
### 1.1 文档定位
本文档为 Code Agent 项目 V1 的需求与总体设计基线,用于项目启动、评审、开发对齐与测试验收。
- 面向角色:产品经理、Tech Lead、前后端工程师、测试工程师。
- 使用阶段:立项评审 -> 开发实施 -> 联调验收。
- 权威性:本文档是范围、流程和约束的统一口径。
### 1.2 文档关系
- 本文档:定义产品目标、系统边界、状态机、核心流程、验收标准。
- `design/后端设计.md`:后端实现细则(API、存储、执行编排、错误处理)。
- `design/前端设计.md`:前端实现细则(页面、状态展示、交互行为、E2E)。
若细则文档与本文冲突,以本文为准。
---
## 二、项目背景与目标
### 2.1 背景
目标是实现一个简化版 "Claude Code" 的可视化代码助手,用户通过 Web 界面提交自然语言任务,由 Agent 在受控条件下进行代码分析与改动提案,并在用户确认后写入工作区文件。
### 2.2 核心目标
用户可以稳定完成以下闭环:
1. 登录系统。
2. 选择工作区。
3. 输入任务指令。
4. 查看流式执行输出与关键步骤。
5. 查看文件改动 diff。
6. 确认后写盘。
### 2.3 MVP 范围
- 单用户、单工作区、单任务会话。
- 支持 REST + WebSocket 协议。
- 支持混合检索与多轮补充上下文。
- 支持文件修改提案预览与确认写盘。
- 支持任务状态追踪与标准错误码返回。
### 2.4 非目标(V1 不做)
- 多人协作编辑与复杂权限体系。
- 跨仓库检索与跨项目上下文共享。
- 自动 Git 提交、推送、MR 流程。
- 自动降级成功、离线兜底等复杂容错策略。
---
## 三、术语定义
- **Task**:一次用户指令执行实例,覆盖检索、分析、提案、确认全生命周期。
- **Change**:Task 下单文件改动提案。
- **Diff**:改动前后差异展示,不代表写盘已发生。
- **Phase**:`running` 状态内部阶段,如 `retrieval`、`retrieve_more`、`patch_planning`。
- **Workspace**:用户被授权的项目根目录。
---
## 四、系统总体架构
```text
前端(React/Vue) <-> 后端(FastAPI) <-> MySQL / Redis / 文件系统
```
### 4.1 前端职责
- 工作区选择与任务输入。
- 流式输出展示(token/status/diff/error/done)。
- 变更列表与 diff 预览。
- 确认写盘、取消任务等用户操作。
### 4.2 后端职责
- 任务生命周期管理与状态机控制。
- LLM 调用编排与上下文注入。
- 检索、diff 生成、写盘安全校验。
- 持久化与可观测信息输出。
### 4.3 存储职责
- MySQL:任务主数据、工作区、变更记录等长期数据。
- Redis:实时状态、流式缓存、会话短期数据。
- 文件系统:工作区读写(必须在沙箱范围内)。
---
## 五、核心设计原则
1. **受控执行**:LLM 只给建议,写盘必须经校验与用户确认。
2. **检索优先**:仅注入必要上下文,不做全仓全文透传。
3. **协议驱动**:前后端通过固定 REST/WS 契约协作。
4. **状态一致**:前端状态以后端状态机为准,不推断业务结果。
5. **可追踪**:关键链路需提供错误码、状态、耗时、日志信息。
---
## 六、任务流程与状态机
### 6.1 主状态机(后端权威)
- 主链路:`running -> waiting_confirm -> done`
- 分析链路:`running -> done`
- 失败链路:`running -> failed`
- 取消链路:`running/waiting_confirm -> cancelled`
### 6.2 状态约束
- 进入 `waiting_confirm` 前必须有可展示 diff。
- `done` 可由纯分析任务直接到达。
- `cancelled` 仅允许从 `running` 或 `waiting_confirm` 进入。
### 6.3 澄清策略(V1)
当意图不明确或上下文不足时:
- 本次任务返回澄清建议并结束为 `done`。
- 用户通过新任务补充信息并继续。
- V1 不引入独立 `waiting_user_input` 中间态。
---
## 七、上下文构建与检索策略
### 7.1 上下文构建原则
- 先传候选文件路径,再按需读取代码片段。
- 仅传相关目录片段与命中证据,不传完整目录树和全量文件内容。
- 采用 token 预算限制,超限时截断并返回可解释信息。
### 7.2 混合检索策略
1. 关键词/符号检索优先。
2. 召回不足时补充语义检索。
3. 融合重排后裁剪注入。
4. 仅增量补充,避免重复上下文。
5. 文件路径/文件名命中优先于内容命中(优先高精度信号)。
6. 融合排序后做"多样性约束"(避免结果过度集中到单目录/单类型文件)。
检索实现口径(快且准):
- 快:先走低成本的路径、文件名、符号线索,减少全仓扫描与无效注入。
- 准:将关键词命中与语义命中做融合重排,再截取最小必要片段。
- 稳:所有轮次受预算与轮次上限约束,超限返回可解释原因。
### 7.3 多轮补充机制
- 当模型返回 `need_more_context=true` 时继续检索。
- 每轮必须包含新增检索证据与预算更新。
- 受 `max_context_rounds` 与 token 上限双重约束。
- 若 `need_more_context=true` 但缺少 `next_search_queries`,立即终止并返回错误原因。
---
## 八、API 与协议约束
### 8.1 REST 接口
- `POST /api/auth/login`
- `POST /api/workspace/select`
- `POST /api/tasks`
- `GET /api/tasks/{task_id}`
- `POST /api/tasks/{task_id}/confirm`
- `POST /api/tasks/{task_id}/cancel`
统一响应格式:
```json
{
"code": 0,
"message": "ok",
"data": {}
}
```
### 8.2 WebSocket 协议
- 连接:`/ws/tasks/{task_id}/stream`
- 事件:`token` / `status` / `diff` / `error` / `done`
- 前端以 `payload.status` 驱动状态展示,不可自行推断后端结果。
---
## 九、文件改动与确认写盘
### 9.1 改动提案
- LLM 输出结构化改动提案,后端完成 schema 校验后生成 diff。
- 改动写入前必须进入 `waiting_confirm` 并展示可选变更。
### 9.2 确认写盘硬约束
- 未确认不得写盘。
- `confirm` 时必须校验 `old_hash`,冲突返回 `3001`。
- `confirm` 时按操作类型校验载荷:
- `operation in {update,create}`:`new_content` 必须为非空字符串;
- `operation == patch`:`diff_unified` 必须为非空字符串。
- `patch` 写盘采用"strict unified diff -> fallback"两阶段应用;若所有阶段均无法命中替换锚点,返回 `3002`,禁止部分写入。
- 所有写盘路径必须位于 workspace 根目录内。
---
## 十、前端交互规范(总览)
### 10.1 页面结构
- 登录页
- 工作区选择页
- Agent 主界面(左:目录树,中:Chat,右:任务详情与 diff)
### 10.2 交互约束
- `submitting/streaming/applying` 时禁用发送按钮。
- `submitting/streaming/waiting_confirm` 时允许"终止任务"。
- `waiting_confirm` 默认不全选变更。
- 选择为空时"确认修改"按钮置灰。
- 关键 phase 可展示,但最终结果以后端状态为准。
---
## 十一、后端实现约束(总览)
### 11.1 分层约束
- `api`:协议层,不承载复杂业务。
- `services`:流程编排和状态推进。
- `llm`:模型调用、工具协议、响应解析。
- `repositories`:数据访问,不承载决策逻辑。
- `infra`:文件系统与运行时基础能力。
### 11.2 Tool 调用约束
- 写工具必须受阶段控制。
- `apply_patch` 仅允许在 `waiting_confirm` 阶段执行。
- 所有 tool 调用必须在 workspace 沙箱内。
---
## 十二、错误码基线
- `0`:成功
- `1001`:工作区不存在或不可访问
- `1002`:工作区越权访问
- `1101`:用户名或密码错误
- `1102`:账号被禁用
- `1103`:登录频率受限
- `2001`:模型调用失败
- `2002`:模型输出格式不合法
- `2003`:上下文不足(预算/轮次上限)
- `3001`:写入冲突
- `3002`:写入失败
- `9000`:系统异常(含 `invalid new_content`)
---
## 十三、非功能要求(NFR)
- **可靠性**:任务可取消、可失败、可恢复。
- **性能**:上下文注入受预算控制,避免无界增长。
- **安全性**:路径沙箱、确认写盘、防冲突。
- **可观测性**:任务状态、阶段、错误码、耗时可追踪。
- **可维护性**:文档边界清晰,约束来源唯一。
---
## 十四、测试与验收标准
### 14.1 必测链路
1. 登录成功/失败链路。
2. 工作区选择与安全校验链路。
3. 正常链路:`create -> stream -> waiting_confirm -> confirm -> done`。
4. 分析链路:`running -> done`(无 diff)。
5. 取消链路:`running/waiting_confirm -> cancelled`。
6. 异常链路:`2001/2002/2003/3001/9000`。
### 14.2 验收判定
满足以下条件可视为 V1 可验收:
- 状态机行为与文档一致。
- API/WS 契约稳定并完成联调。
- 写盘安全约束均有自动化覆盖。
- 关键错误码路径可复现、可定位。
- 端到端闭环稳定可演示。
---
## 十五、里程碑建议
- **M1**:需求与协议冻结(本文档评审通过)。
- **M2**:最小闭环打通(登录到确认写盘)。
- **M3**:异常与稳定性补齐(冲突、取消、超限等)。
- **M4**:验收回归通过并准备发布。
---
## 十六、实施说明
- 当前版本为 V1 定稿基线,后续变更必须走评审并记录版本差异。
- 建议在 `后端设计.md` 与 `前端设计.md` 中补充"与总览一致性"章节,避免实现口径漂移。
# 类Claude Code的可视化Code Agent设计文档
## 一、项目概述
本项目旨在实现一个简化版的"Claude Code"式代码智能助手(Code Agent),通过可视化Web界面与用户交互,实现以下流程:
1. 用户登录(username/password)
2. 用户选择工作区(本地项目目录)
3. 用户输入自然语言指令
4. Agent调用模型生成响应,并展示当前执行步骤
5. 若涉及文件修改,展示修改预览并等待用户确认
6. 用户确认后将修改落盘
后端使用 **Python** 实现,可选框架包括 **LangChain** 或 **MCP**。前端采用 **React/Vue + WebSocket** 实现流式交互。
### 范围与目标
- **本期目标(MVP)**:单工作区、单会话、单用户,支持文本指令、流式响应、文件修改预览、用户确认写入。
- **非目标(MVP不做)**:多人协作编辑、复杂权限系统、跨仓库检索、自动提交远端仓库。
- **成功标准**:用户可在前端完成"输入指令 -> 预览修改 -> 确认落盘"闭环,且有可追踪的任务记录与失败错误码。
### 术语定义
- **Task**:一次用户指令执行实例,包含从检索到确认写入的完整生命周期。
- **Change**:某个 Task 下的单文件修改提案(可被用户选择性确认)。
- **Diff**:文件修改前后差异展示,不等于直接写盘结果。
- **Phase**:`running` 状态下的子阶段(如 `retrieval`、`retrieve_more`、`patch_planning`)。
---
## 二、系统架构
### 1. 总体架构
```
┌──────────────────────────────┐
│ 前端界面 │
│ - 工作区选择 │
│ - 指令输入框 │
│ - Agent输出流式展示 │
│ - 文件修改预览与确认 │
└──────────────┬──────────────┘
│ WebSocket / REST
┌──────────────┴──────────────┐
│ 后端服务 │
│ - 指令解析与模型调用 │
│ - 文件修改流式生成 │
│ - 文件写入与版本管理 │
│ - 工作区管理 │
└──────────────┬──────────────┘
│
┌──────────────┴──────────────┐
│ 文件系统 │
│ - 用户项目目录 │
│ - 临时修改缓存 │
└──────────────────────────────┘
```
---
## 三、功能模块设计
### 1. 前端模块
| 模块 | 功能说明 |
|------|-----------|
| **工作区选择器** | 允许用户选择本地或服务器上的项目目录。 |
| **指令输入区** | 用户输入自然语言任务描述。 |
| **输出展示区** | 实时展示Agent的流式输出。 |
| **文件修改预览区** | 展示模型建议的文件修改diff,用户可确认或拒绝。 |
**技术建议:**
- 使用 React/Vue + TailwindCSS
- WebSocket 实现流式输出
- Diff 组件可使用 `react-diff-viewer` 或 `diff2html`
---
### 2. 后端模块
| 模块 | 功能说明 |
|------|-----------|
| **API层** | 提供 REST 接口(工作区选择、任务提交、确认修改)与 WebSocket 通道(流式输出)。 |
| **Agent核心模块** | 负责调用模型接口(OpenAI API),解析用户指令,生成修改建议。 |
| **文件修改管理模块** | 负责生成文件diff、缓存修改、等待用户确认后落盘。 |
| **工作区管理模块** | 管理用户选择的项目路径,提供文件读写接口。 |
| **任务状态机模块** | 管理任务生命周期(running/waiting_confirm/done/failed/cancelled)。 |
---
## 四、前后端项目结构总览
```text
project_root/
├── app/ # 后端服务(FastAPI)
│ ├── main.py # 应用入口
│ ├── api/ # 路由与协议适配层
│ │ └── api.py # REST/WS 路由 + DTO/事件模型
│ ├── services/ # 核心流程编排层(task/confirm)
│ ├── domain/ # 领域类、枚举与状态机
│ ├── llm/ # LLM 模块(llm_client)
│ │ └── tool_registry.py # 内置工具定义与schema
│ ├── repositories/ # MySQL/Redis 访问层
│ ├── infra/ # 文件系统等基础设施
│ ├── utils/ # 通用工具
│ └── config.py # 配置管理(含 APP_PORT)
├── frontend/ # 前端应用(React/Vue)
│ ├── src/
│ │ ├── pages/ # 页面容器
│ │ ├── components/ # UI组件
│ │ ├── stores/ # 状态管理
│ │ ├── services/ # 接口调用与WS客户端
│ │ └── styles/ # 主题与样式
│ └── package.json
├── design/ # 设计文档
│ ├── 需求设计文档.md
│ ├── 后端设计.md
│ └── 前端设计.md
└── requirements.txt # 后端依赖
```
说明:
- 本节用于全栈目录对齐,详细实现规范仍以 `design/后端设计.md` 与 `design/前端设计.md` 为准。
- 后端结构采用"编排(services) 与 LLM(llm) 解耦"原则,`services` 仅保留核心流程文件。
- `api` 层可合并为 `api.py`(路由 + schema);`config.py` 独立维护全局配置。
- 内置 tools 独立定义在 `llm/tool_registry.py`,通过 schema 注入模型,避免工具定义散落在业务代码中。
- `llm_client.py` 合并网关、模型调用、prompt组装与响应解析;`domain_types.py` 合并领域类、枚举与状态机定义。
- 检索不单独拆 `retrieval_service.py`,由 `task_service.py` 直接编排并调用内置检索 tools。
---
## 五、详细设计文档索引
为避免总览文档过长,详细实现已拆分:
- 后端实现细节:`design/后端设计.md`
- API 契约、WebSocket 协议、状态机
- MySQL schema 与 Redis key 规范
- 并发策略、错误码与配置规范
- 前端实现细节:`design/前端设计.md`
- 页面布局、样式 token、状态模型
- 接口映射、交互细则与 E2E 用例
---
## 六、交互流程
1. 用户登录并通过身份校验
2. 选择工作区并进入 Agent 主界面
3. 前端通过 WebSocket 发送指令
4. 后端调用模型接口,流式返回输出
5. 前端根据 `status` 展示关键处理步骤
6. 若输出包含文件修改建议,展示 diff 与确认栏
7. 用户确认后,后端执行文件写入
### 任务状态流转(建议)
`running -> waiting_confirm -> done`
`running -> failed`
`running/waiting_confirm -> cancelled`
说明:
- 进入 `waiting_confirm` 时必须已有可展示的 `diff` 列表。
- `done` 后记录备份点,支持后续回滚能力扩展。
---
## 七、未来扩展方向
- 增加多文件修改预览与批量确认
- 集成Git版本控制
- 增加任务历史记录与回滚功能
- 支持多模型切换与上下文记忆
---
## 八、开发环境建议
- **后端框架**:FastAPI + LangChain(可选)
- **前端框架**:React + WebSocket
- **依赖管理**:Poetry 或 pip
- **运行环境**:Python 3.10+
## 九、非功能要求(NFR)
- **可靠性**:任务执行可中断、可超时、可恢复;异常必须返回标准错误码。
- **性能**:上下文检索与装配需受 token 预算控制,避免无界增长。
- **安全性**:仅允许工作区内合法路径写入,禁止路径逃逸与未确认自动写盘。
- **可观测性**:至少暴露任务状态、阶段、错误码、耗时等基础指标。
- **可维护性**:总览与实现文档分层,避免同一约束在多文档重复定义。
- **排障性**:关键链路(登录、选区、建任务、LLM 调用、确认、取消、WS 连接)需有可检索日志。
---
## 十、核心设计原则
- **受控执行**:LLM 只生成建议,文件落盘必须经过结构校验、安全校验和用户确认。
- **检索优先**:上下文通过关键词/符号检索与按需语义检索构建,不传完整工作区。
- **协议驱动**:前后端通过固定 REST + WebSocket 协议协作,避免隐式约定。
- **状态一致**:前端状态以任务状态机为准,不在客户端推断业务结果。
- **可恢复**:任务主数据落 MySQL,会话与实时态落 Redis,服务重启后可恢复。
### 1. 指令解析与执行链路
- **自然语言解析**:用户输入的任务描述由 LLM 解析为具体操作意图(如修改文件、新增函数等)。
- **目标文件定位(混合检索)**:先使用关键词/符号检索(如函数名、类名、报错信息、路径关键词)召回候选文件;当用户描述偏语义(如"登录态处理逻辑")时,再补充语义检索(向量检索)。语义检索不是每次必用,而是按查询类型按需启用。
- **上下文构建与裁剪**:不会默认把完整工作区目录树和全部文件内容传给 LLM,而是仅传递"相关目录片段 + 命中文件路径 + 关键代码片段"。执行顺序为"先带候选文件路径,再按需读取文件片段并注入上下文"。在 token 预算内按相关性排序并截断,减少噪声并控制成本。
- **流式响应**:通过 WebSocket 将 LLM 输出实时推送至前端,用户可实时查看生成过程。
- **受控决策**:LLM 负责生成建议,但系统仍需执行结构校验、路径安全校验、冲突检测与用户确认,避免高风险自动写入。
- **迭代式检索执行**:一次检索不足时,Agent 会继续发起下一轮文件搜索/读取,再将新增上下文补充给 LLM,直到能够完成任务。
#### 混合检索策略(关键设计)
- **默认策略**:关键词/符号检索优先(高精度、低成本、可解释)。
- **按需语义**:仅当关键词召回不足或用户描述抽象时启用语义检索(向量)。
- **融合重排**:将关键词命中与语义命中合并后重排,再做上下文裁剪。
- **算法可插拔**:允许使用 BM25、向量召回、规则重排等任一组合,但对上保持统一检索接口。
- **实现不绑死算法**:设计层要求"混合检索能力",不强制依赖单一检索引擎。
#### 信息不足时的继续处理机制(关键约束)
- **分批上下文**:默认只发送首批高相关片段,不一次性发送全部候选文件。
- **不足判定信号**:当 LLM 输出出现"缺少定义/调用链/配置/测试上下文"等信号时,任务保持 `running`,进入补充检索阶段。
- **补充检索范围**:按"同文件邻近片段 -> import 依赖 -> 调用方/被调用方 -> 配置与测试文件"逐级扩展,避免盲目全仓扫描。
- **增量补充原则**:仅补充新增证据片段,避免重复传输已读内容,控制 token 消耗。
- **轮次上限保护**:设置最大补充轮次与 token 预算,超限后返回"信息仍不足"的明确原因与建议操作。
- **可解释性输出**:前端应可看到当前阶段(retrieval/analysis/patch_planning)与补充原因,避免"卡住"体验。
### 2. 传递给 LLM 的上下文参数
- **系统与开发指令**:角色设定、工具使用约束、安全边界、输出格式要求。
- **用户会话信息**:当前用户指令、多轮历史消息、用户附加约束。
- **工作区与 IDE 状态**:操作系统、工作区路径、当前打开文件、光标位置、最近访问文件等环境信息。
- **检索结果与文件片段**:候选文件路径、代码片段、必要的目录结构信息(非完整目录树)。
- **工具执行结果**:搜索输出、命令行输出、lint/test 结果、diff 预览等。
- **模型调用参数**:模型名称、温度、最大输出 token、是否流式输出、停止条件等。
上下文装配顺序:
1. 系统与开发指令
2. 用户当前任务与会话摘要
3. 首批检索结果(先路径候选,再增量片段)
4. 最近一轮工具执行结果
5. 模型调用参数与输出格式约束
### 3. 文件修改与确认流程
- **修改预览**:LLM 生成的改动以 diff 形式展示,用户可逐行查看差异。
- **用户确认**:用户点击"确认修改"后,系统才将变更写入文件;未确认前不做任何写入。
- **临时缓存**:确认前修改内容保存在临时缓存中,不覆盖原文件。
- **确认按钮约束**:当未勾选任何变更时,"确认修改"按钮必须置灰,避免空选择提交。
- **写盘安全约束**:确认阶段若 `new_content` 为空字符串,必须拒绝写盘并返回错误,防止目标文件被清空。
### 4. 前端 UI 逻辑约束
- **页面布局约束**:顶部栏(56px)、左侧栏(280px)、主工作区上下分栏、底部固定输入区。
- **视觉规范约束**:主色 `#3B82F6`,成功 `#22C55E`,警告 `#F59E0B`,错误 `#EF4444`,代码区使用等宽字体。
- **状态模型约束**:`idle/submitting/streaming/waiting_confirm/applying/done|error|cancelled`。
- **一致性约束**:前端状态切换需与后端 `task.status` 一致,前端仅做展示与交互,不自行推断最终结果。
- **终止交互约束**:前端需提供"终止当前任务"入口;点击后调用取消接口并停止当前流式连接。
- **最近工作区约束**:登录成功后若后端返回最近一次工作区,前端应默认回填并允许用户覆盖。
---
## 十一、代码生成约束
- Agent 输出采用结构化 JSON,服务端做 Schema 校验后才生成 diff。
- `POST /api/tasks` 由前端提交态置灰防重复,后端不再维护幂等键存储。
- 变更记录的 `change_id` 仅保证任务内可定位,不做全局唯一约束,避免重复任务提交被数据库唯一键拦截。
- Redis 不维护 `change_id` 的跨任务幂等,仅保留按 `task_id` 组织的短期运行态缓存。
- `confirm` 必须校验 `old_hash`,冲突返回 `3001`。
- `confirm` 额外校验 `new_content` 非空字符串;校验失败返回 `9000/invalid new_content`。
- 所有 Redis 写入需设置 TTL,防止无界增长。
- `config.py` 必须支持 `APP_PORT` 环境变量,避免本地端口冲突。
- 多轮补充检索必须可中断、可超时、可回退,不允许无限循环。
- V1 采用"失败快返"策略:`OPENAI_API_KEY` 未配置、网关错误、网络错误均直接失败透传,不做 mock 降级与成功态兜底。
- V1 禁止在任务主链路增加大范围 `try/except` 吞异常;仅允许必要的最小边界清理逻辑。
### 11.1 约束规范
- `MUST`(强约束):必须实现并有测试;未满足不得标记完成。
- `SHOULD`(默认约束):原则上实现;若不实现需在评审记录中说明原因。
- `MAY`(可选约束):作为优化项管理,不阻塞主链路验收。
执行建议:
1. 每条"约束"后追加级别标签(`[MUST]` / `[SHOULD]` / `[MAY]`)。
2. 评审时逐条核对"文档约束 -> 代码实现 -> 测试用例"三者映射。
3. 对延期项集中维护清单,避免执行口径漂移。
### 11.2 核心约束分级清单
| 约束项 | 级别 | 验收方式 | 备注 |
|---|---|---|---|
| 未确认不得写盘(先 diff 再 confirm) | MUST | E2E:`create -> waiting_confirm -> confirm` | |
| 确认时 `old_hash` 冲突返回 `3001` | MUST | 集成测试:冲突写入场景 | |
| 确认时 `new_content` 为空拒绝写盘(`9000`) | MUST | 单元/集成测试:空内容写盘保护 | |
| `need_more_context` 驱动多轮补充检索 | MUST | 单元测试:多轮 loop 收敛 | |
| 补充检索轮次上限(`max_context_rounds`) | MUST | 配置 + 单测/日志验证 | |
| `need_more_context=true` 但无 `next_search_queries` 时终止 | MUST | 单元测试:限制项断言 | |
| 任务状态机一致性(前后端状态对齐) | MUST | 联调:状态流转核对 | |
| Key缺失/网关/网络异常失败透传(不降级) | MUST | 集成测试:缺 key 与网关故障场景 | V1 口径 |
| 可观测性日志覆盖关键链路 | SHOULD | 日志审计清单 | |
| Redis TTL 防无界增长 | SHOULD | 代码检查 + 运行时键抽样 | |
| 上下文超限错误可解释(`2003`) | SHOULD | 失败路径测试 | |
---
## 十二、文档边界与合并策略
- 本文档仅保留产品与系统总览,不包含 DDL、Redis key 细节、页面组件细节。
- 后端实现规范见 `design/后端设计.md`。
- 前端实现规范见 `design/前端设计.md`。
- 不建议将本总览文档合并到后端文档:总览面向全栈协作与架构对齐,后端文档面向实现与接口落地,读者与维护节奏不同。
---
## 十三、总结
本文档用于统一范围、流程与原则,指导前后端按拆分文档并行实现。实现阶段以 `design/后端设计.md` 与 `design/前端设计.md` 为准。
后端
# Code Agent 后端设计
## 1. 目标与范围
- 负责工作区管理、任务执行、模型编排、变更确认写入。
- 提供 REST + WebSocket 双协议。
- 保障可恢复、可追踪、可并发控制。
### 1.1 文档定位
- 本文档是后端实现基线,面向开发与联调,不承担产品范围定义。
- 术语与范围以 `design/需求设计文档.md` 为上位约束,冲突时以总览文档为准。
### 1.2 后端项目结构拆分(推荐)
```text
app/
├── main.py
├── api/
│ └── api.py # REST/WS 路由 + DTO/事件模型
├── services/
│ ├── task_service.py # 任务主流程(含 loop 编排)
│ └── confirm_service.py # 预检 + 应用改动
├── llm/
│ ├── llm_client.py # 统一 LLM 接口(含调用、prompt组装、响应解析)
│ └── tool_registry.py # 内置 tools 定义与 schema
├── domain/
│ └── domain_types.py # 领域类 + 状态机 + 枚举定义
├── repositories/
│ ├── mysql_repo.py # MySQL 访问(task/workspace/change)
│ └── redis_repo.py # Redis 访问(runtime/conversation)
├── infra/
│ └── runtime_support.py # 文件读写
└── config.py
```
分层职责约束:
- `services` 仅做核心流程编排与决策,不实现模型协议细节。
- `llm` 负责模型交互细节;`services` 只调用 `llm.llm_client`。
- 状态迁移与枚举集中在 `domain/domain_types.py`,禁止在路由层硬编码状态跳转。
- `repositories` 仅负责存储读写,不承载业务分支。
### 1.3 包名与文件清单(骨架规范)
> 当前精简骨架共 **11 个 Python 文件**(不含测试与 `__init__.py`)。
| 包 | 文件 | 主要职责 | 关键类/函数(建议签名) |
|---|---|---|---|
| `app` | `main.py` | 应用启动 | `create_app()`, `main()` |
| `app` | `config.py` | 配置管理 | `class Settings` |
| `app.api` | `api.py` | REST/WS 路由 + DTO/事件结构 | `create_task(req)`, `get_task(task_id)`, `CreateTaskRequest`, `WsEvent` |
| `app.services` | `task_service.py` | 主流程编排(意图判定+loop) | `run_task(task_id: str) -> None` |
| `app.services` | `confirm_service.py` | confirm/apply | `confirm_apply(task_id: str, change_ids: list[str])` |
| `app.llm` | `llm_client.py` | LLM 统一调用(含 chat/prompt组装/响应解析) | `chat(...)`, `build_messages(...)`, `parse_response(...)`, `run_agent_loop(...)` |
| `app.llm` | `tool_registry.py` | 内置 tools 注册与参数校验 | `list_tools()`, `get_tool_schema(name)` |
| `app.domain` | `domain_types.py` | 领域类 + 状态机 + 枚举 | `class Task`, `class Change`, `class Workspace`, `TaskStatus`, `transition(...)` |
| `app.repositories` | `mysql_repo.py` | MySQL 读写 | `create_task(...)`, `update_task(...)` |
| `app.repositories` | `redis_repo.py` | Redis 读写 | `set_status(...)`, `append_stream(...)` |
| `app.infra` | `runtime_support.py` | 文件基础能力 | `apply_patch(...)` |
精简原则:
- 小体量、强相关逻辑优先合并(如 `domain_types.py`、`llm_client.py`、`runtime_support.py`)。
- `services` 只保留核心流程文件(`task_service.py`、`confirm_service.py`)。
- 后续仅在单文件复杂度明显上升时再拆分,不预拆。
- `api` 层采用单文件 `api.py`(路由 + schema);`config.py` 仍保持独立,避免跨层耦合。
检索执行约束(由 `task_service.py` 直接调 tool 实现):
- 检索能力通过内置 tools 提供:`search_code`、`semantic_search`、`read_snippet`。
- `task_service` 负责检索编排(先关键词后语义、融合重排、预算裁剪)。
- 必须输出可解释证据(`path`, `line/snippet`, `score/source`),用于前端展示与 LLM 输入。
## 1.4 内置 Tool 设计(独立模块)
为仿照 Claude Code 的可工具化执行模式,定义独立模块 `app/llm/tool_registry.py`,统一管理工具清单、参数 schema、调用权限与路由。
### Tool Registry 职责
- 声明内置 tool 列表(名称、用途、是否只读、可用阶段)
- 提供 tool 入参/出参 JSON Schema
- 为 `llm.gateway` 提供可注入给模型的工具定义
- 校验模型发起的 tool 调用是否合法
建议接口:
```python
def list_tools() -> list[dict]: ...
def get_tool_schema(name: str) -> dict: ...
def is_tool_allowed(name: str, phase: str, requires_patch: bool) -> bool: ...
```
### 内置 Tool 清单(MVP:8个)
1. `search_code`(只读)
- 作用:关键词/符号检索代码
- 入参:`query`, `path`, `limit`
- 出参:`[{path, line, snippet}]`
2. `semantic_search`(只读)
- 作用:语义检索相关代码片段
- 入参:`query`, `path`, `limit`
- 出参:`[{path, score, snippet}]`
检索执行策略(适用于 `search_code` + `semantic_search`):
- Step1:先执行 `search_code` 召回高精度候选。
- Step2:若候选数量不足或覆盖面不够,再执行 `semantic_search`。
- Step3:融合结果并重排(可基于规则/BM25/向量得分)。
- Step4:按 token 预算裁剪后注入 `retrieval_context`。
检索性能与精度优化(MUST):
- 分层优先级:路径提示命中 > 文件名命中 > 符号/标识符命中 > 关键词命中。
- 混合评分:路径与文件名用于高精度定位,内容预览用于召回补充;避免只依赖单一规则。
- 结果多样性重排:限制同目录/同后缀文件过度集中,降低"同文件簇"噪声。
- 预算裁剪:按相关性排序后做上下文预算裁剪(字符/token 预算),禁止无界增长。
- 增量合并:多轮补检索仅合并新增片段,去重键至少包含 `path + start_line + end_line`。
3. `read_snippet`(只读)
- 作用:读取文件片段用于证据补充
- 入参:`path`, `start_line`, `end_line`
- 出参:`{path, content}`
4. `list_directory`(只读)
- 作用:查看目录结构(受工作区限制)
- 入参:`path`, `depth`
- 出参:`[{name, type, path}]`
5. `get_task_state`(只读)
- 作用:读取任务状态
- 入参:`task_id`
- 出参:`{status}`
6. `prepare_diff`(写前处理)
- 作用:将 `final_changes` 转换为 diff 预览
- 入参:`changes[]`
- 出参:`{diffs[], change_ids[]}`
7. `validate_patch`(写前处理)
- 作用:做路径安全、冲突、schema 校验
- 入参:`task_id`, `selected_changes[]`
- 出参:`{ok, violations[], conflicts[]}`
8. `apply_patch`(写操作)
- 作用:执行确认后的文件写入
- 入参:`task_id`, `selected_changes[]`
- 出参:`{applied_files, failed_files[]}`
### 调用约束(关键)
- `analysis_only` 场景禁止 `apply_patch`。
- `requires_patch=false` 时仅允许只读 tools。
- `apply_patch` 仅允许在 `waiting_confirm` 阶段触发。
- 所有 tool 调用必须在 `workspace_root` 沙箱内执行。
### Tool Schema 模板(统一)
所有 tool 建议使用统一包装结构,便于 `llm.gateway` 与 `tool_registry` 复用:
```json
{
"name": "search_code",
"description": "Search code by keyword/symbol",
"input_schema": {
"type": "object",
"properties": {},
"required": []
},
"output_schema": {
"type": "object",
"properties": {
"ok": {"type": "boolean"},
"data": {},
"error": {
"type": ["object", "null"],
"properties": {
"code": {"type": "integer"},
"message": {"type": "string"}
}
}
},
"required": ["ok", "data", "error"]
}
}
```
### 8 个内置 Tool 的输入输出示例
#### 1) `search_code`
输入:
```json
{
"query": "UserController getById",
"path": "app/",
"limit": 20
}
```
输出:
```json
{
"ok": true,
"data": [
{"path": "app/api/user_api.py", "line": 42, "snippet": "def get_by_id(...):"}
],
"error": null
}
```
#### 2) `semantic_search`
输入:
```json
{
"query": "where user profile is updated",
"path": "app/",
"limit": 10
}
```
输出:
```json
{
"ok": true,
"data": [
{"path": "app/services/user_service.py", "score": 0.92, "snippet": "def update_profile(...):"}
],
"error": null
}
```
#### 3) `read_snippet`
输入:
```json
{
"path": "app/services/user_service.py",
"start_line": 30,
"end_line": 90
}
```
输出:
```json
{
"ok": true,
"data": {
"path": "app/services/user_service.py",
"content": "def update_profile(...): ..."
},
"error": null
}
```
#### 4) `list_directory`
输入:
```json
{
"path": "app/",
"depth": 2
}
```
输出:
```json
{
"ok": true,
"data": [
{"name": "services", "type": "dir", "path": "app/services"},
{"name": "task_service.py", "type": "file", "path": "app/services/task_service.py"}
],
"error": null
}
```
#### 5) `get_task_state`
输入:
```json
{
"task_id": "task_123"
}
```
输出:
```json
{
"ok": true,
"data": {
"status": "running"
},
"error": null
}
```
#### 6) `prepare_diff`
输入:
```json
{
"changes": [
{"file_path": "app/services/user_service.py", "operation": "update", "new_content": "..."}
]
}
```
输出:
```json
{
"ok": true,
"data": {
"change_ids": ["chg_1"],
"diffs": [
{"change_id": "chg_1", "file_path": "app/services/user_service.py", "diff_unified": "@@ ..."}
]
},
"error": null
}
```
#### 7) `validate_patch`
输入:
```json
{
"task_id": "task_123",
"selected_changes": ["chg_1", "chg_2"]
}
```
输出:
```json
{
"ok": true,
"data": {
"valid": false,
"violations": ["path_outside_workspace"],
"conflicts": ["app/services/user_service.py"]
},
"error": null
}
```
#### 8) `apply_patch`
输入:
```json
{
"task_id": "task_123",
"selected_changes": ["chg_1", "chg_2"]
}
```
输出:
```json
{
"ok": true,
"data": {
"applied_files": 1,
"failed_files": [
{"file_path": "app/services/user_service.py", "reason": "hash_conflict"}
]
},
"error": null
}
```
## 2. API 契约
### 2.1 REST
- `POST /api/auth/login`
- `POST /api/workspace/select`
- `POST /api/tasks`
- `GET /api/tasks/{task_id}`
- `POST /api/tasks/{task_id}/confirm`
- `POST /api/tasks/{task_id}/cancel`
统一响应:
```json
{
"code": 0,
"message": "ok",
"data": {}
}
```
统一约束:
- 除 `GET /api/tasks/{task_id}` 外,写操作接口建议支持 `X-Request-Id`(链路追踪)。
- 所有错误响应必须返回 `{code,message,data}`,其中 `data` 至少包含 `task_id`(如可用)。
#### A. `POST /api/workspace/select`
请求体:
```json
{
"user_id": "u_001",
"workspace_path": "c:/project/demo",
"readonly": false
}
```
响应体:
```json
{
"code": 0,
"message": "ok",
"data": {
"workspace_id": "ws_001",
"workspace_path": "c:/project/demo",
"readonly": false,
"capabilities": ["read", "write", "diff"]
}
}
```
接口逻辑:
1. 校验 `workspace_path` 是否存在且可访问。
2. 执行路径安全检查(禁止越权目录、符号链接逃逸)。
3. 创建或更新 `workspaces` 记录。
4. 返回 `workspace_id` 与能力集。
#### A0. `POST /api/auth/login`
请求体:
```json
{
"username": "alice",
"password": "plain_password_input"
}
```
响应体:
```json
{
"code": 0,
"message": "ok",
"data": {
"user_id": "u_001",
"username": "alice",
"display_name": "Alice",
"token": "jwt_or_session_token",
"expires_in": 7200
}
}
```
接口逻辑:
1. 根据 `username` 查询用户记录。
2. 使用安全哈希算法校验密码(明文密码仅用于输入,不落库)。
3. 校验通过后签发会话令牌(JWT 或 server-side session)。
4. 返回用户基本信息与会话有效期;校验失败返回统一错误码。
错误码建议:
- `1101`:用户名或密码错误
- `1102`:账号被禁用
- `1103`:登录频率受限
#### B. `POST /api/tasks`
请求体:
```json
{
"user_id": "u_001",
"workspace_id": "ws_001",
"instruction": "重构 user service 并补充单测",
"options": {
"stream": true,
"temperature": 0.2,
"max_output_tokens": 4096
}
}
```
响应体:
```json
{
"code": 0,
"message": "accepted",
"data": {
"task_id": "task_123",
"status": "running"
}
}
```
接口逻辑:
1. 校验 `workspace_id` 是否属于 `user_id`。
2. 写入 `tasks`(初始状态 `running`),并初始化 Redis 实时状态。
3. 异步启动任务执行器,直接进入检索与分析阶段。
请求参数约束:
- `instruction` 非空,建议长度 `1..8000`。
- `options.temperature` 建议范围 `0.0..1.0`。
#### C. `GET /api/tasks/{task_id}`
响应体:
```json
{
"code": 0,
"message": "ok",
"data": {
"task_id": "task_123",
"status": "waiting_confirm",
"summary": "已生成 2 个文件变更建议",
"changes": [
{
"change_id": "chg_1",
"file_path": "app/core/agent.py",
"operation": "update",
"risk_level": "low"
}
]
}
}
```
接口逻辑:
1. 查询 MySQL `tasks` 主记录。
2. 读取 Redis 实时状态(若存在则覆盖 `status` 展示值)。
3. 查询 `task_changes` 返回变更摘要(不返回完整 `new_content`)。
4. 按统一响应结构返回任务详情。
#### D. `POST /api/tasks/{task_id}/confirm`
请求体:
```json
{
"action": "apply",
"selected_changes": ["chg_1", "chg_2"]
}
```
`action` 当前仅支持 `apply`,保留后续扩展 `reject` 的兼容位。
响应体:
```json
{
"code": 0,
"message": "applied",
"data": {
"task_id": "task_123",
"applied_files": 2
}
}
```
接口逻辑:
1. 校验任务状态必须为 `waiting_confirm`。
2. 读取 `selected_changes` 对应的 `task_changes`。
3. 逐文件校验 `old_hash`,冲突时返回 `3001`。
4. 分操作执行写入参数校验:
- `operation in {update, create}`:`new_content` 必须为非空字符串。
- `operation == patch`:`diff_unified` 必须为非空 unified diff 文本。
5. 执行写入(必要时先备份):
- `update/create` 走整文件覆盖写盘。
- `patch` 走 unified diff 应用。
任一文件失败返回 `3002` 并停止后续写入。
6. 更新 Redis 状态。
补充说明:
- 为避免误写空内容导致文件被清空,`update/create` 模式必须校验 `new_content`。
- 为兼容 patch-first 模式,`patch` 可不提供 `new_content`,但必须提供 `diff_unified`。
#### D.1 `patch` 回写到工作区的执行细节(实现口径)
写盘入口与职责:
- 入口函数:`app/services/confirm_service.py::confirm_apply`。
- 文件写盘能力:`app/infra/runtime_support.py::apply_unified_patch`(patch)与 `apply_change`(update/create)。
执行步骤(`operation=patch`):
1. 基础校验:`diff_unified` 必须是非空字符串,否则返回 `9000/invalid diff_unified`。
2. 沙箱校验:通过 `safe_join(workspace_root, file_path)` 保证目标路径在工作区内,防止路径逃逸。
3. 读取原文:读取目标文件当前内容,解析 `diff_unified` 的 hunk。
4. Strict 应用:优先按 unified diff 严格上下文应用(要求上下文与删除行精确匹配)。
5. Fallback 应用(仅 strict 失败时):
- 文本块替换 fallback:按 hunk 的 `-`/`+` 块做成对替换;
- 宽松单行替换 fallback:当 LLM 产出的 diff 上下文较弱(例如仅给注解替换)时,按行做规范化匹配替换;
- 方法改名 fallback:针对单行签名改名场景(如 `foo(` -> `foo1(`)做模式替换。
6. 全量成功才写盘:任一 fallback 未命中则整体失败,返回 `3002/patch apply failed:*`,不做部分写入。
失败语义(常见):
- `patch_apply_failed:context_mismatch` / `remove_mismatch`:strict 阶段上下文不一致。
- `patch_apply_failed:fallback_replace_mismatch`:fallback 仍无法在目标文件找到替换锚点。
- `patch_apply_failed:fallback_no_replace_pairs`:diff 中无法提取有效替换对。
工程约束:
- `patch` 写盘以"可验证命中"为前提,不允许"猜测式"落盘。
- 当 `diff_unified` 为弱上下文(如仅 `@@` 占位)时,允许进入宽松 fallback,但仍要求每个替换对可被命中。
- 发生 `3002` 时前端应提示"补充上下文后重试",避免重复提交同一无效 diff。
#### E. `POST /api/tasks/{task_id}/cancel`
请求体:
```json
{
"reason": "user_manual_cancel"
}
```
响应体:
```json
{
"code": 0,
"message": "cancelled",
"data": {
"task_id": "task_123",
"status": "cancelled"
}
}
```
接口逻辑:
1. 校验当前状态是否可取消(`running/waiting_confirm`)。
2. 标记任务为 `cancelled` 并停止后台执行。
3. 清理 Redis 流缓存与工作区锁。
4. 返回取消结果。
### 2.2 WebSocket
连接:`/ws/tasks/{task_id}/stream`
事件:
- `token`
- `status`
- `diff`
- `error`
- `done`
统一结构:
```json
{
"event": "status",
"task_id": "task_123",
"timestamp": 1716370000,
"payload": {}
}
```
事件 `payload` 约定:
- `token`:`{"text":"..."}`
- `status`:`{"status":"running"}`
- `diff`:`{"change_id":"chg_1","file_path":"app/core/agent.py","diff_unified":"@@ ...","risk_level":"low"}`
- `error`:`{"code":2001,"message":"model provider timeout"}`
- `done`:`{"status":"waiting_confirm","change_count":2}`
### 2.3 后端与 LLM 交互编排(Claude Code 风格)
本节定义统一的 LLM 交互契约与 Agent Loop。核心思想是:
- 先判定任务意图(分析/改动/待澄清)
- 再按需多轮补充上下文
- 仅在明确改动意图且信息充足时进入 diff/confirm 流程
#### 触发时机
- `POST /api/tasks` 成功后,执行器进入 `running` 并发起首轮 LLM 调用。
- `need_more_context=true` 时,执行"补充检索 -> 再次调用 LLM"。
- `need_more_context=false` 且 `requires_patch=true` 时,生成变更提案并转 `waiting_confirm`。
- `confirm` 阶段只做预检与写盘,不再调用 LLM。
#### 请求契约(输入)
```json
{
"model": "gpt-4.1",
"temperature": 0.2,
"max_output_tokens": 4096,
"stream": true,
"messages": [
{"role":"system","content":"Output strictly in JSON schema."},
{"role":"developer","content":"Follow workspace safety and patch rules."},
{
"role":"developer",
"content":"Use retrieved context first. {\"retrieval_context\":[{\"path\":\"...\",\"start_line\":10,\"end_line\":26,\"snippet\":\"...\"}]}"
},
{"role":"user","content":"...user instruction..."}
],
"response_format":{"type":"json_schema","json_schema":"agent_loop_v1"}
}
```
输入约束:
- `messages` 按"系统 -> 开发规则 -> 开发上下文包 -> 用户问题"顺序组装。
- `retrieval_context` 仅传增量片段,禁止全仓全文。
- 检索执行顺序为"先路径候选(文件名)-> 再按需读取片段(文件内容)-> 再注入 LLM"。
- 每轮必须带上上一轮检索增量与预算信息(便于模型收敛)。
推荐检索管线(Claude Code 风格):
1. Query 解析:提取 `query_terms / symbol_hints / path_hints`。
2. 候选召回:优先命中路径与文件名;不足时再走内容关键词/语义召回。
3. 混合打分:综合路径、符号、内容命中得分生成候选排名。
4. 多样性重排:限制同目录/同后缀过度集中,提升上下文覆盖面。
5. 片段抽取:围绕命中点截取最小可理解代码片段(非整文件)。
6. 预算裁剪:按预算(字符/token)裁剪,保留最相关证据并注入 `retrieval_context`。
#### 响应契约(显式信号)
```json
{
"intent_type": "analysis_only",
"requires_patch": false,
"intent_confidence": 0.93,
"intent_reason": "用户在做代码分析,无修改诉求。",
"need_more_context": false,
"missing_context_hints": [],
"next_search_queries": [],
"analysis_summary": "...",
"evidence": [{"path":"...","snippet":"..."}],
"limitations": [],
"patch_plan": [],
"final_changes": []
}
```
字段语义:
- `intent_type`:`analysis_only | code_change | unclear`
- `requires_patch`:是否允许进入改动流
- `need_more_context`:是否继续检索补充
- `next_search_queries`:下一轮检索查询(当 `need_more_context=true` 必填)
- `final_changes`:最终改动集合(仅 `requires_patch=true` 且信息充足时允许非空)
`final_changes` 单条结构(关键):
```json
{
"change_id": "chg_xxx",
"file_path": "src/main/java/com/zoom/contactcenter/service/controller/web/UserController.java",
"operation": "patch",
"old_hash": "",
"new_content": "",
"diff_unified": "diff --git ...",
"reason": "rename method from updateUserStatus to updateUserStatus1",
"risk_level": "medium"
}
```
约束:
- `operation=patch`:`diff_unified` 必填,`new_content` 可为空。
- `operation in {update,create}`:`new_content` 必填且非空,`diff_unified` 可选(用于展示)。
- 为兼容存储模型,`task_changes.new_content` 在 patch 场景可存放 `diff_unified` 文本副本。
#### LLM 网关交互入参与响应(内部接口)
> 该接口是后端到模型网关的内部协议,不直接暴露给前端,但必须在设计文档明确,便于联调与错误定位。
请求体(`POST {OPENAI_BASE_URL}/chat/completions`):
```json
{
"model": "gpt-5.4",
"temperature": 0.2,
"max_completion_tokens": 4096,
"messages": [
{"role":"system","content":"Output strictly in JSON schema."},
{"role":"developer","content":"Return required keys only."},
{"role":"developer","content":"{\"retrieval_context\":[{\"path\":\"app/services/task_service.py\",\"start_line\":60,\"end_line\":90,\"snippet\":\"...\"}]}"},
{"role":"user","content":"重命名 updateUserStatus 到 updateUserStatus1"}
]
}
```
响应体:
```json
{
"id": "chatcmpl_xxx",
"choices": [
{
"message": {
"content": "{\"intent_type\":\"code_change\",\"requires_patch\":true,\"need_more_context\":false,\"analysis_summary\":\"...\",\"final_changes\":[{\"change_id\":\"chg_1\",\"file_path\":\"src/main/java/com/zoom/contactcenter/service/controller/web/UserController.java\",\"operation\":\"patch\",\"old_hash\":\"\",\"new_content\":\"\",\"diff_unified\":\"diff --git ...\",\"reason\":\"...\",\"risk_level\":\"medium\"}]}"
}
}
]
}
```
解析要求:
- 从 `choices[0].message.content` 取 JSON 字符串并反序列化。
- 若返回 markdown code fence,需要先去掉 fence 再解析 JSON。
- 非契约结构触发一次"契约修复重试";仍失败则降级为 `analysis_only`。
#### 决策网关(统一路由)
1. `intent_type=unclear` 或 `intent_confidence < 0.6`
-> 直接结束为 `done`(返回澄清建议文本)
2. `requires_patch=false`
-> Analysis Pipeline(输出 `analysis_summary/evidence/limitations`,任务 `done`)
3. `requires_patch=true` 且 `need_more_context=true`
-> 进入补充检索轮次(`phase=retrieve_more`)
4. `requires_patch=true` 且 `need_more_context=false`
-> Patch Pipeline(保存 `final_changes`,发 `diff`,任务 `waiting_confirm`)
安全兜底:
- 未显式 `requires_patch=true` 时禁止进入写盘链路。
- `final_changes` 为空时禁止进入 `waiting_confirm`。
- 若模型声明 `need_more_context=true` 但未提供 `next_search_queries`,必须终止补充轮次并记录限制原因。
### 2.4 V1 异常处理边界(MVP 口径)
- V1 仅保留主链路必需校验与错误透传,不引入"自动降级成功"的兜底分支。
- 禁止因 `OPENAI_API_KEY` 未配置而自动回退本地 mock 结果;配置缺失应直接失败并暴露真实错误。
- 禁止对网关错误/网络错误做"吞异常 + 自动改写为成功态"的处理;应保留失败态用于联调定位。
- 禁止在任务主执行链路外围增加大范围 `try/except` 兜底(仅允许最小边界的资源清理场景)。
- 网关重试、离线兜底、降级策略留待 V2 再引入,V1 不作为默认实现。
#### Agent Loop(伪代码)
```python
round_idx = 0
context_budget = MAX_TOTAL_CONTEXT_TOKENS
context_delta = initial_retrieval(instruction)
while round_idx < MAX_CONTEXT_ROUNDS:
llm_resp = call_llm(compose_messages(instruction, context_delta, context_budget))
validate_schema(llm_resp)
if llm_resp["intent_type"] == "unclear" or llm_resp["intent_confidence"] < 0.6:
emit_clarification(llm_resp["intent_reason"])
update_task_status("done")
break
if llm_resp["requires_patch"] is False:
emit_analysis_answer(
llm_resp["analysis_summary"],
llm_resp.get("evidence", []),
llm_resp.get("limitations", [])
)
update_task_status("done")
break
if llm_resp["need_more_context"] is False:
changes = llm_resp["final_changes"]
if not changes:
fail_task(code=2002, message="empty final_changes for patch flow")
break
save_task_changes(changes)
emit_status(phase="patch_planning")
emit_diff_events(changes)
update_task_status("waiting_confirm")
break
emit_status(phase="retrieve_more")
context_delta = incremental_retrieval(llm_resp["next_search_queries"])
context_budget -= count_tokens(context_delta)
round_idx += 1
if empty(context_delta) or context_budget <= 0:
fail_task(code=2003, message="context budget exceeded")
break
else:
fail_task(code=2003, message="max context rounds exceeded")
```
#### 交互流程图
```mermaid
flowchart TD
A[POST /api/tasks] --> B[Task running]
B --> C[Initial retrieval]
C --> D[Call LLM by schema]
D --> E{intent clear?}
E -->|No| F[Task done with clarification]
E -->|Yes| G{requires_patch?}
G -->|No| H[analysis_summary + evidence]
H --> I[Task done]
G -->|Yes| J{need_more_context?}
J -->|Yes| K[incremental retrieval]
K --> L{budget/round ok?}
L -->|Yes| D
L -->|No| M[Task failed code=2003]
J -->|No| N[Persist final_changes]
N --> O[Emit diff]
O --> P[Task waiting_confirm]
P --> Q[POST confirm]
Q --> R[Precheck + apply]
R --> S[Task done]
```
## 3. 任务状态机
- 主链路:`running -> waiting_confirm -> done`
- 失败链路:`running -> failed`
- 取消链路:`running/waiting_confirm -> cancelled`
- 分析链路:`running -> done`
约束:
- `waiting_confirm` 前必须有至少一条 `diff`。
- `confirm` 时校验文件 `old_hash` 防冲突。
- `confirm` 时按操作类型校验载荷:`update/create` 需要 `new_content`,`patch` 需要 `diff_unified`。
- `running` 允许内部多轮 `retrieve_more`,对外仅暴露关键状态。
- `done` 可由分析链路直接到达,不要求存在 `diff`。
### 3.2 设计约束分级(防止"文档有、实现无")
- `MUST`:必须落地到代码与测试(如状态机约束、写盘安全、循环退出条件)。
- `SHOULD`:默认应实现;若不实现需在评审记录中说明原因与计划。
- `MAY`:可选增强项,不作为当前验收阻塞条件。
落地检查清单(每次改动前后各检查一次):
1. 约束是否标记级别(MUST/SHOULD/MAY)。
2. MUST 是否已有代码实现。
3. MUST 是否有自动化测试覆盖。
4. 若 SHOULD 未实现,是否在评审记录中显式标注原因与计划。
### 3.3 后端落地对照表
| 设计约束 | 级别 | 测试/验证 | 评审要点 |
|---|---|---|---|
| `run_agent_loop` 支持多轮检索 loop | MUST | 单测:loop 收敛与退出条件 | 验证 `need_more_context` 驱动行为 |
| `max_context_rounds` 防无限循环 | MUST | 配置测试 + 单测 | 超限后返回 `2003` |
| `need_more_context=true` 且无 query 时终止 | MUST | 单测:缺失 query 断言 | 输出可解释限制原因 |
| `waiting_confirm` 前必须已有 diff | MUST | 集成测试:patch 流程 | 无 diff 禁止进入确认态 |
| `confirm` 校验 `old_hash` 冲突 | MUST | 集成测试:冲突写入 | 冲突返回 `3001` |
| `confirm` 双模式校验(`new_content`/`diff_unified`) | MUST | 单元/集成测试:update 与 patch 两种路径 | 按 operation 执行参数校验 |
| 前端确认按钮空选择置灰 | MUST | E2E:空选择提交 | 防止空 apply 请求 |
| Key缺失/网关/网络异常默认透传(不降级mock、不吞异常) | MUST | 集成测试:配置缺失与网关失败场景 | V1 严格失败快返,保留真实错误 |
### 3.1 `tasks` 与 `task_changes` 职责边界
- `tasks`:任务主表(一条记录代表一次用户指令执行),存放任务级元数据与总体状态,如 `instruction/status/summary`。
- `task_changes`:任务子表(一条记录代表一个文件变更提案),存放文件级改动明细,如 `file_path/operation/old_hash/new_content`(patch 模式下可存 diff 副本)。
关系说明:
- 一个 `task` 可以对应 0..N 条 `task_changes`。
- `tasks` 用于任务管理与列表查询;`task_changes` 用于 diff 展示、选择性确认和冲突校验。
## 4. 持久化设计
### 4.1 MySQL(长期)
核心表:
- `users`
- `workspaces`
- `tasks`
- `task_changes`
MySQL 8.0 建表示例(可直接执行):
```sql
CREATE TABLE IF NOT EXISTS users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id VARCHAR(64) NOT NULL UNIQUE,
username VARCHAR(64) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
display_name VARCHAR(128) NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'active',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS workspaces (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
workspace_id VARCHAR(64) NOT NULL UNIQUE,
user_id VARCHAR(64) NOT NULL,
workspace_path VARCHAR(1024) NOT NULL,
readonly TINYINT(1) NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_workspaces_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS tasks (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
task_id VARCHAR(64) NOT NULL UNIQUE,
user_id VARCHAR(64) NOT NULL,
workspace_id VARCHAR(64) NOT NULL,
instruction TEXT NOT NULL,
status VARCHAR(32) NOT NULL,
summary TEXT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_tasks_workspace_status (workspace_id, status),
INDEX idx_tasks_user_created (user_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS task_changes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
change_id VARCHAR(64) NOT NULL,
task_id VARCHAR(64) NOT NULL,
file_path VARCHAR(1024) NOT NULL,
operation VARCHAR(16) NOT NULL,
old_hash VARCHAR(128) NULL,
new_content LONGTEXT NOT NULL,
reason TEXT NULL,
risk_level VARCHAR(16) NOT NULL DEFAULT 'low',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX idx_changes_task_id (task_id),
INDEX idx_changes_task_change (task_id, change_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
`task_changes` 约束说明:
- `change_id` 仅作为任务内变更标识,不作为跨任务幂等键。
- 禁止对 `change_id` 建全局唯一索引,避免重复任务提交时触发 `Duplicate entry`。
- 若需要查重,按 `task_id + change_id` 维度处理,不影响不同任务复用同名变更。
状态字段约束建议:
- `users.status` 只允许:`active/disabled`
- `tasks.status` 只允许:`running/waiting_confirm/done/failed/cancelled`
- `task_changes.operation` 只允许:`create/update/delete/patch`
### 4.2 Redis(短期与会话)
Redis 详细设计(key、结构、TTL):
| Key | Type | TTL | 示例值 | 用途 |
|---|---|---:|---|---|
| `agent:task:{task_id}:status` | String | 24h | `running` | 任务实时状态 |
| `agent:task:{task_id}:stream` | List | 30min | token/event 序列 | 断线重连后回放 |
| `agent:task:{task_id}:diff_ids` | Set | 24h | `chg_1,chg_2` | 任务内变更集合(仅当前 task) |
| `agent:ws:{connection_id}` | Hash | 2h | `{"task_id":"task_123","user_id":"u_1"}` | WS 连接上下文 |
| `agent:user:{user_id}:active_task` | String | 24h | `task_123` | 用户当前活跃任务 |
| `agent:conv:{conversation_id}:messages` | List | 7d | `{"role":"user","content":"...","ts":1716370000}` | 对话消息存储(替代 MySQL) |
| `agent:conv:{conversation_id}:meta` | Hash | 7d | `{"user_id":"u_1","workspace_id":"ws_1"}` | 会话元信息 |
建议实现:
- 写 `stream` 时使用 `LPUSH + LTRIM` 限制长度(如保留最近 2000 条事件)。
- `conversation messages` 使用 `RPUSH + EXPIRE`,并通过 `LTRIM` 控制最大消息数(如 500 条)。
Redis 规范建议:
- key 前缀统一为 `agent:`,避免与其他业务冲突。
- TTL 由场景驱动:会话 7d、流缓存 30min。
- 复杂对象统一 JSON 字符串,字段使用小写下划线命名。
- 每个写操作必须定义过期时间,防止无界增长。
- Redis 不作为 `change_id` 的跨任务幂等存储;`diff_ids` 仅用于当前 `task_id` 的会话态展示与确认辅助。
## 5. 错误码
- `0`:成功
- `1001`:工作区不存在或不可访问
- `1002`:工作区越权访问
- `2001`:模型调用失败
- `2002`:模型输出格式不合法
- `2003`:上下文不足(达到补充轮次或 token 预算上限)
- `3001`:写入冲突
- `3002`:写入失败
- `9000`:未知系统异常
错误响应示例:
```json
{
"code": 2003,
"message": "context budget exceeded",
"data": {
"task_id": "task_123",
"phase": "retrieve_more",
"max_context_rounds": 5
}
}
```
登录失败示例:
```json
{
"code": 1101,
"message": "invalid username or password",
"data": {
"task_id": null
}
}
```
## 6. 配置规范(config.py)
使用环境变量,不在代码中硬编码敏感信息。至少支持:
- `APP_HOST`
- `APP_PORT`
- `APP_RELOAD`
- `OPENAI_BASE_URL`(兼容内部 LLM gateway,例如 `https://api.openai.com/v1`)
- `MODEL_NAME`
- `OPENAI_API_KEY`
- `MAX_TOTAL_CONTEXT_CHARS`(单轮注入上下文预算,默认建议 9000)
- `REDIS_HOST/PORT/PASSWORD/DB`
- `MYSQL_HOST/PORT/DB/USER/PASSWORD`
示例环境映射(本地联调):
- LLM gateway:
- `OPENAI_BASE_URL=https://api.openai.com/v1`
- `MODEL_NAME=gpt-5.4`
- Redis:
- `REDIS_HOST=localhost`
- `REDIS_PORT=6379`
- `REDIS_PASSWORD=`(空)
- MySQL(由 JDBC URL `jdbc:mysql://localhost:3308/agent_demo?...` 拆分):
- `MYSQL_HOST=localhost`
- `MYSQL_PORT=3308`
- `MYSQL_DB=agent_demo`
- `MYSQL_USER=root`
- `MYSQL_PASSWORD=<local_secret>`
## 7. 测试要求
- 单元测试:路径校验、diff 生成、状态机、错误码映射
- 集成测试:`select -> create -> stream -> confirm -> apply`
- 回归测试:冲突写入、取消任务、服务重启恢复
## 8. 运维与发布基线
- 启动前校验关键配置:`APP_PORT`、模型配置、Redis/MySQL 连接。
- 生产环境关闭 debug/reload,配置请求超时与并发上限。
- 对外发布前至少完成一轮端到端联调(含 `2003` 与 `3001` 异常场景)。
### 8.1 关键日志(排障基线)
建议在以下关键步骤打印 INFO/WARNING/ERROR 日志,并统一携带 `task_id/user_id/workspace_id`(如可用):
- 登录与工作区选择:`login attempt/success/fail`、`workspace select`。
- 任务生命周期:`create task`、`task started`、`task waiting_confirm`、`task cancelled`、`task failed`。
- LLM 调用:调用开始、调用完成(包含 `requires_patch` 判定)、异常堆栈。
- 检索命中:记录 `filename_hints`、`direct_hit_count`、`direct_hit_paths`(截断展示)以便定位"仅文件名检索"问题。
- Confirm/Cancel:确认入参、冲突命中(`3001`)、写入成功文件数、取消原因。
- WS 连接:连接建立与断开事件。
### 8.2 取消任务执行约束
- 前端触发 `POST /api/tasks/{task_id}/cancel` 后,后端需将任务置为 `cancelled` 并释放工作区锁。
- 任务执行器在关键阶段(LLM 调用前后、写入前)需检查任务是否已取消;若已取消,停止后续流程并避免覆盖状态。
前端
# Code Agent 前端设计
## 1. 目标与范围
- 提供可视化交互入口:任务输入、流式输出、diff 预览、确认落盘。
- 状态展示与后端保持一致,不做业务推断。
- 支持深浅主题,优先深色工程风格。
- 支持账号登录后进入工作区与对话主界面。
## 2. 页面与交互流程
1. 登录页
- 输入 `username/password`,调用登录接口校验身份。
- 登录成功后进入工作区页;失败时展示错误提示。
2. 工作区选择页
- 展示用户可访问工作区列表(支持搜索)。
- 登录成功后若后端返回 `latest_workspace`,默认回填最近一次工作区路径与只读状态。
- 用户确认后进入 Agent 主界面。
3. Agent 主界面
- 左侧工作区树(窄栏)
- 中央 Chat 主区域(主要交互区域)
- 右侧可折叠详情区(任务状态、diff 预览、确认栏)
4. 改动确认流程
- 当任务进入 `waiting_confirm`,展示变更文件列表与 diff。
- 用户可选择变更后点击"确认修改"触发 apply。
5. 任务终止流程
- 在输入区提供"终止"按钮(Stop)。
- 当任务处于 `submitting/streaming/waiting_confirm` 时可点击终止。
- 前端调用 `POST /api/tasks/{task_id}/cancel`,成功后将页面状态置为 `cancelled` 并停止当前流式连接。
- 终止后建议在消息区追加系统提示(如"任务已终止"),避免用户误判为网络断开。
## 3. 布局规格(强调 Chat 主体)
- 顶部栏:56px(应用名、登录用户、当前工作区、连接状态)。
- 左侧工作区树:默认 220px,最小 180px,最大 260px(不能占用过多宽度)。
- 中央 Chat 区:占内容区至少 65% 宽度,优先保证消息阅读和输入体验。
- 右侧详情区:默认 320px,可折叠到 0;在 `waiting_confirm` 时自动展开。
- 底部输入区:固定在 Chat 区底部,包含发送、停止、清空按钮。
## 4. 视觉规范
- Primary:`#3B82F6`
- Success:`#22C55E`
- Warning:`#F59E0B`
- Error:`#EF4444`
- 代码字体:`Consolas, Menlo, monospace`
- 卡片:圆角 8px + 轻阴影
## 5. 状态模型与步骤提示
- `idle`
- `submitting`
- `streaming`
- `waiting_confirm`
- `applying`
- `done`
- `error`
- `cancelled`
交互约束:
- `submitting/streaming/applying` 时禁用发送按钮
- `submitting/streaming/waiting_confirm` 时允许终止按钮
- `waiting_confirm` 默认不全选变更
- "确认修改"按钮在 `selected_changes` 为空时置灰(至少勾选 1 条 diff 才可提交)
- `error` 态展示 `error_code + message + retry_action`
- 工作区选择页优先展示 `latest_workspace`(如存在),用户可手工覆盖后再提交。
- `streaming` 阶段展示关键状态为 `running`,无需展示细粒度 phase
- 当后端返回澄清建议时,当前任务按 `done` 结束,前端展示建议并引导用户发起新任务补充信息
步骤提示组件(建议固定在 Chat 顶部):
- 当前步骤:`retrieval -> analysis -> retrieve_more -> patch_planning -> waiting_confirm/applying`
- 每步显示状态(进行中/完成/失败)与耗时
- 当步骤停留过久(如 >30s)显示"处理中,请稍候"文案
## 6. 接口映射
### 6.1 REST
- 登录:`POST /api/auth/login`
- 选择工作区:`POST /api/workspace/select`
- 创建任务:`POST /api/tasks`
- 轮询详情:`GET /api/tasks/{task_id}`
- 确认修改:`POST /api/tasks/{task_id}/confirm`
- 取消任务:`POST /api/tasks/{task_id}/cancel`
### 6.2 WebSocket
- 连接:`/ws/tasks/{task_id}/stream`
- 事件:`token/status/diff/error/done`
- `status` 事件仅使用 `payload.status` 驱动状态展示,不由前端自行推断细粒度阶段
## 7. 组件建议
- `LoginForm`
- `WorkspaceSelector`
- `WorkspaceTree`
- `TaskInput`
- `TaskTimeline`
- `StreamOutputPanel`
- `DiffFileTree`
- `DiffViewer`
- `ConfirmBar`
- `StatusBadge`
- `PhaseStepper`
## 8. E2E 用例
- 登录链路:登录成功进入工作区;登录失败提示错误
- 选区链路:选择工作区后加载目录树与历史任务
- 正常链路:提交任务 -> 收到流式输出 -> 展示 diff -> 确认落盘
- 异常链路:模型失败 -> 错误提示 -> 重试
- 冲突链路:确认时后端返回 `3001` -> 提示重新生成
- 信息不足链路:收到 `2003` 后展示可操作建议
代码
生成的propmt
你是资深全栈工程师。请严格依据我项目中的设计文档生成"可运行代码骨架 + 核心实现"。
【文档来源】
design/需求设计文档.md
design/后端设计.md
design/前端设计.md
【总体要求】
先完整阅读以上3个文档,再开始实现。
实现必须与文档一致;若发现冲突,按优先级处理:
后端实现细节以 design/后端设计.md 为准
前端实现细节以 design/前端设计.md 为准
范围与原则以 design/需求设计文档.md 为准
不要擅自增加文档未要求的复杂能力。
先生成最小可运行版本(MVP),保证主链路可跑通。
【你需要完成的内容】
A. 后端(Python/FastAPI)
按文档目录创建后端骨架(当前约定的精简结构)
实现接口:
POST /api/auth/login
POST /api/workspace/select
POST /api/tasks
GET /api/tasks/{task_id}
POST /api/tasks/{task_id}/confirm
POST /api/tasks/{task_id}/cancel
实现 WebSocket:/ws/tasks/{task_id}/stream
实现任务状态机与phase机制
实现 llm_client + tool_registry 的最小可用版本
实现 MySQL/Redis 基础读写
提供 config(含 APP_PORT、MySQL、Redis、模型配置,环境变量读取)
B. 前端(按文档交互)
登录页(username/password)
工作区选择页
Agent 主界面(窄工作区树 + chat主区域 + 右侧可折叠详情)
Chat步骤提示(status.phase)
diff确认交互(waiting_confirm)
C. 运行与验证
给出启动方式(后端/前端)
给出最小初始化步骤(如 users 表初始化一条账号)
跑一条主链路自检:登录 -> 选工作区 -> 发消息 -> 返回分析或diff -> 确认
【输出格式要求】
先输出"实现计划(分步骤)"。
然后逐步执行并直接修改代码。
每一步说明改了哪些文件、为什么这么改。
最后输出:
变更文件清单
启动命令
验证步骤
已知限制(如MVP暂未覆盖项)
我们订阅的cursor是按request次数收费的:这次请求总共花费231万 token,对比按token计费划算很多

下面来看下代码。