package com.xly.service; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.time.Duration; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 会话账本(append-only 事件流)—— 会话里发生过的**一切**按序落账,包括不经过 LLM 的确定性路径 * (表单弹出/澄清/写提议/确认结果),修补「确定性路径不进对话记忆」的记忆空洞;前端历史从账本重放。 * *
键:Redis LIST {@code chat:ledger:{convId}},元素为事件 JSON {@code {t,type,...}},30 天 TTL。
* 事件类型:{@code user}(text)/ {@code assistant}(text)/ {@code clarify}(text)/
* {@code form}(entity,message)/ {@code question}(question,options)/ {@code tool}(name,digest)/
* {@code proposal}(opId,summary)/ {@code confirm}(opId,status,msg)/ {@code cancel}(opId,description)。
*/
@Service
public class LedgerService {
private static final Logger log = LoggerFactory.getLogger(LedgerService.class);
private static final String PREFIX = "chat:ledger:";
private static final Duration TTL = Duration.ofDays(30);
private final StringRedisTemplate redis;
private final ObjectMapper mapper;
public LedgerService(StringRedisTemplate redis, ObjectMapper mapper) {
this.redis = redis;
this.mapper = mapper;
}
/** 追加一条事件(绝不抛异常——账本失败不能影响对话主流程)。 */
public void append(String convId, String type, Map