# 后端 Agent 说明 ## 领域与代码映射 - `oid` 和 `workspace_id` 是同一个工作空间 ID 的历史命名。 - `AssistantModel.type` 实际值域 `0`–`4`:`0` 普通小助手;`1` 高级应用;`4` 页面嵌入;`2`、`3` 为遗留兼容值,行为分别等同 `0`、`1`,当前无创建入口。 - `AssistantModel.domain` 表示对接目标系统的域名,不是业务领域。 - `DataTraining` 是「SQL 示例库」概念的持久化命名。 - `Chat.chat_type` 目前只有 `chat` 一个有效值;`datasource` 是为未实现的表字段备注自动生成功能预留的遗留值。 - `ChatRecord.recommended_question` 同时承载两种内容:开场记录中是数据源配置的推荐问题,普通记录中是模型生成的猜测问题。 ## 代码组织 - 领域代码放在 `backend/apps//`。多数域采用 `api/`、`crud/` 或 `curd/`、`models/` 分层;`schemas/` 仅 `system` 和 `settings` 有,`chat` 另有 `task/`,`ai_model`、`db`、`mcp`、`template`、`swagger` 不遵循该布局——新代码跟随所在域的既有形态。 - 项目同时存在 `crud` 和 `curd` 拼写;不要为统一命名制造无关重构。 - 新 router 注册到 `backend/apps/api.py`。 - 应用组装、中间件、MCP 和 MCP 图片静态挂载属于 `backend/main.py`;`init_fastapi_app` 在此触发 xpack 初始化,前端 dist 静态挂载与 `/xpack_static` 提取由 xpack 包内完成(见 `docs/agents/xpack.md`)。 - SQLModel 结构变更必须配套 Alembic 迁移;细节见 `docs/agents/migrations.md`。 - 用户可见后端消息使用 `backend/locales/`,不要硬编码新文案。 ## API 黄金路径 新 endpoint 参考 `terminology`、`data_training` 域和 `datasource` 域内的 `recommended_problem` 模块(`backend/apps/datasource/api/recommended_problem.py`)的分层: 1. 在 `api/.py` 定义 router、prefix、tags 和 Swagger summary; 2. 使用 `SessionDep`、`CurrentUser`、`Trans` 等依赖注入; 3. 资源型接口配置 `@require_permissions`,确认 `keyExpression` 指向真实资源; 4. 需要审计的操作配置 `@system_log`,新代码优先让权限装饰器位于审计装饰器外层,只记录已授权操作; 5. handler 只做参数解析、权限上下文提取和分支,业务规则下沉到 CRUD/service; 6. 返回领域对象、DTO 或既有分页 dict;正常 JSON 由 `ResponseMiddleware` 包装,不要手工包一层 `code/data/msg`; 7. 用户可见异常通过 `Trans` 使用 locale key;`HTTPException` 留在 API 层,不要让 CRUD 依赖 FastAPI 响应细节。 Endpoint 命名沿既有风格: - 分页:`GET /page/{current_page}/{page_size}`; - 新增或更新:`PUT ""`,按 `info.id` 分支; - 删除:`DELETE ""`,传 ID 列表; - 启用/禁用:`GET /{id}/enable/{enabled}`; - 导出:`GET /export`; - 导入:`POST /uploadExcel`。 只在确实与现有 API 兼容性冲突时发明新形态,并说明原因。 ## CRUD 与查询 - 查询构建参考 `build__query` 的分层: 1. `get__base_query` 构造工作空间过滤; 2. `build__query` 追加搜索、作用域、join、count 和分页; 3. `execute__query` 转换为 DTO/result; 4. `page_` 返回 API 需要的分页元数据。 - 默认过滤当前 `current_user.oid`;管理员或助手场景必须显式说明为何可以切换工作空间。 - 使用 SQLAlchemy `select` / `and_` / `or_` 表达查询;不要为用户输入拼接 SQL 字符串。 - 分页先 count,再计算 `total_pages`,最后构造 offset/limit 子查询。 - 创建/更新前完成重复性、必填和作用域校验;不要先写入再依赖唯一约束报错。 - 事务提交通常发生在 CRUD/service 边界;API handler 不要随意中途 commit。 - embedding、缓存清理或后台任务沿用当前领域的线程任务模式,不在请求路径中阻塞等待长任务。 ## 异步与阻塞 - FastAPI handler 可以是 `async def`,但不要在事件循环中执行外部 HTTP、pandas 大文件解析、CPU 密集转换或长时间文件 IO。 - 这些操作参考现有 `asyncio.to_thread(inner)` 模式。 - 数据库 session 由依赖注入管理;在线程中需要新 session 时使用对应 `session_maker()` 并确保清理。 - 不要把 `asyncio.to_thread` 当成绕过权限或事务边界的手段。 ## 模型与 DTO - 表模型继承 `SQLModel, table=True`;输入/输出 DTO 使用 Pydantic BaseModel 或非 table SQLModel。 - 大 ID 使用 `BigInteger`;返回给前端时按既有 DTO 规则处理超过 JavaScript 安全整数的情况。 - 时间、启用状态、工作空间归属和高级应用/数据源作用域要显式建模,不依赖调用方隐式状态。 - 新增字段同时考虑迁移、导入/导出、embedding、缓存和 xpack 调用。 ## 安全与事务边界 - 保留认证、工作空间/数据源权限、审计日志和既有错误响应模式;不要在 handler 中绕过它们。 - 生成 SQL、路径、Host 头和上传文件都按不可信输入处理。 - 不要削弱行数限制、权限过滤、元数据查询控制、Host 校验或路径穿越防护。 - 修改连接池、事务和异步执行边界时,先阅读相邻实现和回归测试;不要把阻塞调用移回事件循环。 - 商业实现留在 xpack;本仓库只保留对已发布包的调用和初始化。xpack 是必装硬依赖(启动即 import,无降级),许可证只做功能门控;加载场景见 `docs/agents/xpack.md`。 ## Chat 问题流程 主要入口在 `backend/apps/chat/api/chat.py`: 1. `POST /chat/start` 与 `POST /chat/assistant/start` 在工作空间内创建会话,并可绑定初始数据源或助手上下文。 2. `POST /chat/question` 先解析快速命令。普通问题进入 `stream_sql`;`/regenerate` 直接再生。`/analysis` 和 `/predict` 在会话内会直接拒绝(temporary not supported),实际通过 `POST /record/{chat_record_id}/{action_type}` 触发。 3. `stream_sql` 构造 `LLMService`,创建 `ChatRecord`,并启动异步执行。 4. 已绑定数据源时,服务先提取关键词并扩展术语,再筛选适用的术语、SQL 示例和自定义提示词,随后组装 SQL 消息;筛选的作用域、命中和组合规则见 `docs/agents/knowledge-enhancement.md`。 5. 未绑定数据源时,先由模型选择数据源;服务随后校验数据源访问权和连接可用性。 6. 模型生成 SQL 后,服务解析 SQL、对照允许的表元数据校验引用表,并按需应用行权限或助手动态 SQL 变换。 7. 服务执行最终 SQL,规范化大数字和带限定名的列结果,并持久化查询结果。 8. 模型基于实际使用的表结构生成图表配置;服务校验并持久化配置。非会话式流式调用还可请求渲染图片。 9. 分析和预测是基于既有图表记录的独立后续执行。 10. 猜测问题与已配置的推荐问题分开生成。 `ChatFinishStep` 允许一次执行在生成 SQL、查询数据或生成图表后停止。不要假设所有调用方都需要完整图表流程。 ### 记录状态与衍生关系 - 记录终态二元:`finish=true` 即终态,`error` 非空即失败。生成 SQL、执行、图表任一阶段失败都写同一个 `error` 字段;失败阶段从已填充字段推断(有 SQL 无数据为执行失败,有数据无图表为图表失败),精确失败点看 ChatLog 的 `error` 标记。 - 分析和预测各生成一条新的完整记录,复制源记录的问题、图表和数据,以 `analysis_record_id` / `predict_record_id` 指回源记录;衍生记录不能再被分析、预测或再生。 - 再生记录以 `regenerate_record_id` 指向被再生记录,形成链,沿链回溯可取到原始问题。 - 开场记录(`first_chat=true`)不能被分析、预测或再生;查找"上一条记录"时排除开场记录。 - 问题快捷入口按位置分两个标签:"猜你想问"是会话级快捷提问入口(开场记录展示数据源配置的推荐问题,输入框区域展示生成的猜测问题);"继续问"是每次成功回答后的追问入口(生成的猜测问题)。 验证要求与测试选择标准见 `docs/agents/testing.md`。