编号连续,不跳号
先把空正文的切片剔除,再依次编号。若先编号再剔除,回答里的 [2] 就会指向引用列表里已经不存在的条目。每条资料截断 800 字,避免单条过长挤占上下文。
本页把前几页接成一条链。一轮提问要经过十一步:先确定会话用的是哪个智能体、本次命中哪个技能,再从该智能体绑定的材料里取依据,把角色与依据分别装进两条消息送入生成,最后落库。检索落空不会让链路终止,只是清空引用列表。
顺序取自服务端处理一轮提问的那一个方法:前七步都在准备输入,第八步起才开始产生输出。
第 5 步把提问先落库,是为了让下一轮读到的历史里一定包含本轮提问。第 8 步刻意排在组消息之前:引用列表与技能名先发出去,页面立刻能显示出处,而读历史、拼消息、等首字这三段耗时都藏进同一次首字延迟里。第 7 步筛完可能一条不剩——链路不因此中断,引用列表以空数组下发,第 10 步照常生成。
| 步骤 | 落在哪一层 | 失败时怎么返回 |
|---|---|---|
| 1–2 切会话与智能体 | 两次数据库查询 | 不存在或跨班 → 404 |
| 3–5 取技能、落库提问 | 一次查询,两次写入 | 数据库不可用 → 503 |
| 6 检索 | 调用检索服务 | 服务不可用 → 503 |
| 7–9 筛切片、推 meta、组消息 | 全部在进程内 | 没有失败分支 |
| 10–11 生成与收尾 | 对话网关,随后一次写入 | 首片之前 → 503;之后只能补一条 error 事件 |
检索命中与否,改变的是消息的措辞与引用列表,而不是这段回答要不要写。
[1] 这样的编号,也不得把回答写成整段的「资料中未找到相关内容」。生成之后还有几件事要做对:编号怎么发、落空后怎么清、这一轮凭什么可回溯。
先把空正文的切片剔除,再依次编号。若先编号再剔除,回答里的 [2] 就会指向引用列表里已经不存在的条目。每条资料截断 800 字,避免单条过长挤占上下文。
无依据那一支的模型输出,在推给浏览器之前会先删掉所有 [n] 形式的编号,免得出现指向不存在出处的引用。系统消息里也已写明不要编号,两道措施取其一都够用,叠在一起是不去指望模型每次都听话。
助手消息除正文外,还写入引用列表与本次命中的技能名。done 事件返回这条消息的编号。事后可按会话回放:这一轮用的是哪个智能体(记在会话行上)、命中了哪个技能、引了哪几份材料、材料属于哪个班。
生成过程中若已产出若干片段才失败,则以已生成的内容收尾并持久化;一个片段都未产出时,才向上返回错误。增量推送开始后状态码已不可变更,只能以 error 事件收尾。
meta 里,状态字段恒为「ok」:这一轮有没有依据,从引用列表是否为空即可读出,不必再借状态区分。第 4 课的问答接口则把「没有依据」单列成一个独立状态——同一件事,两条链路各有一套口径。