Files

116 lines
5.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# decisions.md — confidence-feedback
## Question Pool(grill 阶段)
| # | 问题 | 模式 | 状态 |
|---|---|---|---|
| Q1 | 置信度由谁计算 | user-interview | 已确认 |
| Q2 | 反馈触发哪些后端操作 | user-interview | 已确认 |
| Q3 | CaseLibrary 结构化字段从哪里填 | evidence-driven | 已确认(方案变更) |
| Q4 | 验收口径 | user-interview | 已确认 |
---
## Evidence-Driven 结论
### Q3:CaseLibrary 内容来源
**初始结论**:从 `agent_step.thought` 提取(grill 阶段)
**修正(apply 阶段讨论后)**:
- 代码证据:`agent_step.thought` 截断为 2000 字符,`modelOutput` 截断为 500 字符,均不是完整答案
- `ChatService.executeChat` 第 269 行已有完整答案 `answer = response.getText()`,但未持久化
- 决策:给 `DiagnosisSession` 加 `answer TEXT` 字段,Flyway V008 迁移,案例内容直接从 `session.answer` 取
---
## User-Interview 确认记录
### Q1 — 置信度由谁评估
- 用户原话(grill):"两者都要:规则兜底 + Verifier 主打分"
- **apply 后修正**:讨论后决定去掉 LLM 自评,仅用规则引擎(见"apply 阶段决策")
- 最终实现:`EvaluationService` 纯规则,预留 `llm_opinion` 扩展位
### Q2 — 反馈触发操作
- 用户原话:"写入 DiagnosisSession.feedback 字段, not_useful → 打 BAD_CASE 标记"
- **apply 后修正**:BAD_CASE 不改 status,feedback 字段本身即为标记(见"apply 阶段决策")
- 最终实现:`FeedbackService` 只写 feedback + 可选写 case_library,不改 status
### Q4 — 验收口径
- 用户原话:"端到端可验证:发一次 chat → 查 DB 看 selfEvaluation 有值 → 提交 feedback → 查 DB 看 feedback + case_library"
- 确认状态:已确认,未变化
---
## Apply 阶段决策(post-grill 重要变更)
### 决策 A:DiagnosisSession 加 answer 字段
- **问题**:案例沉淀需要完整答案,agent_step.thought 被截断,不可用
- **决策**:新增 `answer LONGTEXT` 字段,ChatService SUCCESS 分支写入
- **影响**:V008 Flyway 迁移,CaseLibraryService 直接读 session.answer
### 决策 B:去掉 LLM 自评,只用规则引擎
- **问题**:LLM 评估自己的答案系统性偏高分;多一次调用消耗 token;Verifier Agent 当前未实现
- **决策**:MVP 阶段仅用基于 tool_invocation 的规则引擎
- **理由**:规则可解释、可复现、不撒谎;Verifier 留待诊断全链路实现时再做
- **预留**:`selfEvaluation` JSON 结构保留 `llm_opinion` 扩展位,代码底部注释说明接入点
### 决策 C:BAD_CASE 不改 status 字段
- **问题**:status 是执行状态语义(RUNNING/SUCCESS/FAILED),BAD_CASE 是质量标签,两个维度不同;覆盖 status 会破坏统计
- **决策**:`not_useful` 通过 `feedback` 字段本身标识,查 BadCase 用 `WHERE feedback = 'not_useful'`
### 决策 D:评分字段重命名为 evidence_score
- **问题**:原名 confidence 容易误解为"答案准确性",实际衡量的是"证据收集充分度"
- **决策**:重命名为 `evidence_score`,明确语义边界
- **边界说明**:工具调用能证明 Agent 有尝试收集证据,但无法证明答案无幻觉;这个分数过滤最差情况(无工具调用就给答案),不能识别"调用了工具但结论仍错误"
### 决策 E:规则输入来源仅限 tool_invocation 事实
- **问题**:DateTimeTools、QueryMetricsTools 等非检索工具调用未写入 tool_invocation
- **接受**:evidence_score 定义本来就是检索证据充分度,非检索工具排除在外是合理的,不是 bug
- **已知限制**:调用了时间工具但 evidence_score = 0 的 session 存在
---
## 架构审计记录
- 接口影响:`POST /api/feedback` 是新接口(L2);ChatService 主流程返回值不变(L1)
- 时序验证:tool_invocation 在工具执行时同步写入,evaluate @Async 在 Agent 完成后触发,无竞态问题
- 已接受风险:
- `@Async` 失败时 selfEvaluation 保持 null,前端需处理 null
- 案例结构化字段(faultCategory 等)暂时填 GENERAL,后续可人工补充
- LLM 自评预留但未实现,Phase 2 再迭代
### 决策 F:ChatResult record + ChatResponse.sessionId 回传
- **问题**:`ChatService` 内部生成 8 位 sessionId,但从不返回给前端;前端用自己的 sessionId 调 feedback 接口,后端查不到 session(400)
- **决策**:新增 `ChatResult(answer, sessionId)` record,`executeChatWithStrategy` 链路全部返回 `ChatResult`;`ChatResponse` 增加 `sessionId` 字段;前端读取并闭包绑定至对应消息的反馈按钮
- **影响**:`ChatService` 三个方法签名变更(内部链路),`ChatController` 调用方更新,前端 `app.js` 读取新字段
### 决策 G:反馈 sessionId 闭包绑定而非全局变量
- **问题**:最初实现用 `this.lastSessionId` 全局变量,多轮对话时点击早期消息的反馈按钮会提交最新 sessionId
- **决策**:`createFeedbackBar(sessionId)` 接收 sessionId 参数,`submitFeedback(feedback, bar, sessionId)` 直接用传入值,不读全局状态
- **效果**:每条 AI 回复绑定自己那轮的 sessionId,多轮对话下行为正确
### 项目技术栈清单
- ChatModel 注入:`@Autowired ChatModel chatModel`,通过 `ModelRoutingConfig` 路由
- Repository:Spring Data JPA,`Optional<T>` 返回,方法命名约定
- DTO:独立文件放 `dto/` 包
- 异步:新建 `AsyncConfig.java` 加 `@EnableAsync`(项目原无此配置)
- 无 MQ,无加密,工具类直接用 UUID.randomUUID()
- 日志:SLF4J Logger,`LoggerFactory.getLogger()`
- `ToolInvocationRepository.findBySessionId` 已有,可直接用
### 参考实现文件
- `ChatService.java`:executeChat/executeChatComplex 流程
- `CaseLibraryRepository.findByDiagnosisId`:幂等检查用
- `DiagnosisSessionRepository.findBySessionId`
- `ToolInvocationRepository.findBySessionId`