会话与对话体验
前面的章节讲的是「知识怎么进来、怎么被检索」,这一章讲对话框本身:一次问答过程中用户看到什么、能做什么。这些能力分散在会话、消息、附件、建议问题几组接口上,这里集中说明。
1. 一轮问答里用户看到的东西
| 界面元素 | 说明 |
|---|---|
| 流水线进度条 | 回答生成前展示当前阶段,如附件解析、检索知识库(和网络)及命中数量、思考;检索步骤可以点开看引用 |
| 思考过程 | 模型的推理内容内联展示在时间线里,可折叠 |
| 引用角标 | 回答正文中的来源标记,点击定位到原文分块 |
| 引用面板(references drawer) | 侧栏列出本轮所有检索来源,含 Wiki 页面的返回结果 |
| 有帮助 / 没帮助 | 回答工具栏上的两个按钮,只在回答引用了知识库文档时出现,见下文「对回答的反馈」 |
| 追问建议 | 回答结束后给出的下一步问题,见 会话与聊天 API的「建议问题」 |
进度条的两种等待态
所有可见阶段都完成、但模型还没吐字时会有一段静默期,进度条据此区分两种提示:确实跑过检索的显示「正在连接模型并生成回答…」,纯附件问答这类没有检索步骤的显示中性的「正在准备回答…」。超过 60 秒(RAG_WAIT_STALL_DELAY_MS)仍无回答转为停滞态「模型响应较慢,仍在等待…」——SSE 断连时后端不会再发完成事件,没有这个上限进度条会一直宣称「马上就好」。实现见 Web 前端。
对回答的反馈
回答引用了知识库文档时,工具栏上有「有帮助」「没帮助」两个按钮;没有引用任何文档的回答不显示,因为没有可以转交的人。
- 点「有帮助」直接记录;再点一次已按下的按钮即撤回反馈。
- 点「没帮助」会先弹出「哪里不对?」,可以写一段意见(最多 1000 字,可选),并可以勾选「附上我的问题,帮助负责人判断」(默认不勾选)。发送后提示「已反馈,谢谢」。
- 弹窗里写明了谁能看到什么:意见和回答开头会出现在被引用文档的知识健康里,交给文档负责人处理,知识库成员也能看到;只有勾选后才附上提问者的问题。
- 「没帮助」是知识健康里「有争议」发现的证据来源:自文档上次被确认以来,引用它的回答收到的「没帮助」会被累计成一条发现交给文档负责人。具体规则见知识健康。
- 反馈只在本工作区内生效:回答引用了其他工作区共享来的知识库时,这里的问题不会出现在对方的知识健康里。
接口(均在 /api/v1/sessions 下,Viewer+;API Key 需 chat 能力或全量权限):
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /:id/feedback | 当前用户在该会话里给出的全部反馈,按消息 ID 索引 |
| PUT | /:id/messages/:message_id/feedback | 设置反馈:rating 为 up / down,空串表示撤回;down 时可带 comment 与 share_question |
导出对话
会话操作栏可以把整段对话导出为 Markdown(frontend/src/utils/sessionMarkdown.ts 的 buildSessionMarkdown()),内容包含会话标题、ID、导出时间与逐轮问答,适合贴进工单或周报。导出走前端,不产生额外接口调用。
2. 会话内临时附件
对话里可以直接丢文件进去问,不必先建知识库——这类文件叫临时文档(temporary_documents 表,migration 000070),只属于当前会话。
接口(均在 /api/v1/sessions 下):
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /:session_id/attachments | 上传附件 |
| GET | /:id/attachments | 列出本会话附件 |
| GET | /:id/attachments/:attachment_id | 附件详情 |
| GET | /:id/attachments/:attachment_id/preview | 预览 |
| DELETE | /:id/attachments/:attachment_id | 删除 |
行为要点:
- 状态机:
uploaded→processing→ready(失败为failed),解析是异步的。发问时如果附件还没解析完,会等待到YUHENG_CHAT_ATTACHMENT_WAIT_TIMEOUT_SEC(默认 60 秒,扫描件建议调大); - 解析产物保留
YUHENG_CHAT_ATTACHMENT_TTL_HOURS(默认 24 小时)后清理,附件不会长期占用存储; - 扫描件/图片型文档走 VLM OCR,并发与页数上限由
YUHENG_CHAT_ATTACHMENT_OCR_CONCURRENCY(默认 8)与YUHENG_CHAT_ATTACHMENT_OCR_MAX_PAGES(默认 8)控制; - 附件走哪个解析引擎由租户级
chat_parser_engine_rules配置(internal/types/tenant.go); - 临时附件与知识库文档是两套东西:它不进向量索引、不出现在知识库列表里,会话结束即失效。需要长期检索的资料应该正式入库。
3. 渠道会话的可见性
除了网页对话,API Key 调用也会产生会话。这些「渠道会话」在控制台里默认不可见,因为它们按 Key 各自隔离。
规则在 internal/application/service/session.go:
- 会话列表的
source过滤器为空或web时,只返回调用者自己的会话; - 过滤
api属于工作区级视角,要求 Admin+,否则返回 403(listing channel sessions requires tenant admin or owner role)。通过校验后会去掉按用户的收窄,管理员因此能观察到这些原本互相隔离的会话; - 侧栏里的 API 分组也是管理员专属,且会先探测数量,有会话才显示,避免给普通用户留一个永远空着的入口;
- 即使是管理员,打开渠道会话也只是只读观察;API Key 产生的会话在写接口上始终按归属收窄。
这个设计的用意是:管理员需要排查「集成昨天怎么调的」,但不该让普通成员翻到别人的调用记录。
4. 跨会话历史搜索
聊天记录可以被索引并跨会话检索:
| 方法 | 路径 | 权限 |
|---|---|---|
| POST | /api/v1/messages/search | Viewer+;API Key 需 message_history 能力或 full-access |
| GET | /api/v1/messages/chat-history-stats | 同上 |
| GET | /api/v1/messages/:session_id/load | Viewer+;API Key 需 chat 能力(只能读自己会话) |
message_history 是一个独立能力,用意是让做数据分析的集成能搜历史元数据,而不必给它一把 full-access Key。消息索引的开关与所用的 Embedding 模型在「设置 → 消息管理」(chathistory 分区,保存需工作区 Admin;已有消息被索引后 Embedding 模型不可再改)。
5. 相关章节
- 「没帮助」反馈如何变成待处理的发现:知识健康
- 建议问题(开场问题与追问):会话与聊天 API
- 回答里的图片与文件怎么送到客户端:API 总览的「文件引用形式」
- 会话与消息的完整接口:API 参考:会话与聊天
实现参考
| 路径 | 内容 |
|---|---|
frontend/src/views/chat/components/botmsg.vue、AnswerFeedback.vue、RagPipelineProgress.vue | 回答卡片、反馈按钮、流水线进度 |
frontend/src/utils/rag-pipeline-state.ts | 等待态与 60 秒停滞判定 |
frontend/src/utils/sessionMarkdown.ts | 导出对话为 Markdown |
frontend/src/stores/answerFeedback.ts、frontend/src/api/feedback/ | 反馈的前端状态与接口 |
internal/handler/message_feedback.go、internal/application/service/message_feedback.go、internal/application/repository/message_feedback.go | 反馈接口、写入与被引用文档的检查 |
internal/application/service/findings/dispute.go | 把「没帮助」累计成知识健康的发现 |
internal/router/routes_chat.go | 会话、附件、消息、反馈路由 |
internal/types/temporary_document.go、migrations/versioned/000070_temporary_documents.up.sql | 会话内临时附件 |
internal/application/service/session.go | 渠道会话的可见性 |