会话归属
同伴登录后列出会话,不应出现你的会话;用你的会话编号直接读取,返回 404,且与读取一个不存在编号的响应完全一致。
每位同学在第 4 课产出的本人学期仓上增量实现,不新建仓库。下面按依赖关系给出实现顺序:先有存储层,再有编排层与接口层,最后是前端;每一层做完先自验一次,再往上走。
顺序可以合并,但不能颠倒:没有会话存储就无从谈流式落库,没有检索就无从谈引用。
| 层次 | 顺序 | 实现项 | 完成后的可验证点 |
|---|---|---|---|
| 存储层 | 1 | 幂等建表:会话、消息、智能体三张主表,加两张绑定表 | 重复启动不报错,不重建已有表 |
| 接口层 | 2 | 会话接口:列表、新建、按编号读取 | 新建时未选定本班已启用的智能体返回 404;他人与他班的会话也都返回 404 |
| 3 | 智能体读写与两份绑定:名称 64 字内、提示词 2000 字内,绑定本班技能与本班材料 | 学生调用写接口返回 403;提示词留空时回退到默认角色 | |
| 4 | 消息读写:落库、取最近 6 条消息、每条截断 500 字 | 超过 6 条后,更早的消息不再进入上下文 | |
| 5 | 技能文件解析:字段、长度与工具名校验 | 缺字段、重复字段、非法工具名都被拒并给出可读提示 | |
| 6 | 技能增删改查:写操作仅教师,班内名称唯一 | 同名提交返回 400;他班技能按编号直取返回 404 | |
| 编排层 | 7 | 路由:只在智能体绑定的已启用技能里打分,至多选一个 | 两个技能同时适用时只出现一条引导正文 |
| 8 | 检索接入:只在智能体绑定的材料内取前 4 条,再按学科过滤 | 引用列表只含该学科材料,编号连续 | |
| 9 | 消息组装:角色与技能进系统消息,资料进用户消息,附最近 6 条历史 | 有资料时要求标编号;落空时不写编号,也不许整段回一句「未找到」 | |
| 10 | 流式接口:meta、delta、done、error 四类事件 | 抓包可见多次 delta,且每次是新增文本 | |
| 接口文档 | 11 | 由处理器注解生成 OpenAPI,挂载 Swagger 页面 | 打开 /swagger 能对照文档实际发一次请求;文档与注解同源,改代码即改文档 |
| 前端 | 12 | fetch 提交并自行解帧,逐段渲染 | 文字逐段出现;结束后能打开引用材料 |
.env,不入库、不进镜像,也不要提交到 Git。课内以个人为单位完成;需要第二方复核的环节走同伴交叉验证,见第 3 节。排查时先分清两类:一类是真故障,另一类只是设计如此。把第二类当成缺陷去改,往往会把「跨班与不存在表现一致」这条硬约束改坏。
| 现象 | 常见原因 |
|---|---|
| 响应一次性返回,无增量渲染 | 反向代理仍在缓冲,或服务端写入后未 flush;检查 proxy_buffering off 与 X-Accel-Buffering: no |
| 提问返回 400 | 提问少于 2 个字或超过 500 字;提示词超过 2000 字;或本班还没有任何已启用的智能体 |
| 提交技能即被拒绝 | 文件缺名称、适用条件或启用;重复写了同一字段;工具名不是 knowledge_search;空行以下缺少正文;超过 8000 字 |
| 技能同名提交失败 | 班内名称唯一是数据库约束,换个名称或先改已有的那一条 |
| 禁用技能后回答行为未变 | 先确认该技能是否仍被这个智能体绑定着。会话锁定的只是「用哪个智能体」,而它当前绑了哪些技能与材料是每次提问重读的,所以停用或解绑应当立即生效,不必新建会话 |
/swagger 打不开,或清单里少接口 | 文档路由挂在了业务路由之后;openapi.Mount 须在注册接口之前调用。另一个原因是处理器上缺注解,或注解的路径与注册路径不一致 |
以下三种现象是预期行为,不是缺陷
| 现象 | 为什么这样设计 |
|---|---|
| 新建会话返回 404 | 所选智能体不存在、已停用或不属于本班,一律按「不存在」处理,响应与一个真的不存在的编号完全一致 |
| 他班会话返回 404 | 跨班与不存在必须返回完全一致的响应,否则状态码本身就成了探测他班资源是否存在的信息泄露 |
| 回答里没有出处编号 | 检索没有命中,或该智能体还没有绑定材料。此时仍会作答,只是引用列表为空、正文不含编号 |
以下四项无法自测完成,需要同伴以自己的账号在同一套环境上交叉验证。
同伴登录后列出会话,不应出现你的会话;用你的会话编号直接读取,返回 404,且与读取一个不存在编号的响应完全一致。
同伴列出本班智能体,不应看到别班的;拿别班的智能体编号去新建会话,返回 404。再把某个智能体停用,用它已建好的会话仍可继续提问。
同伴在请求体里写入你所在班级的编号再提问,结果仍是本班的命中;用只存在于你班材料里的词提问,对方得到空结果而不是报错。
同伴把某个技能改为「启用:否」后再问同一句,回答方式应当明显不同:该技能不再进入候选集,改为直接给结论。技能与材料的绑定是每次提问重读的,因此开关立即生效,不必新建会话。