跨会话一致性:如何让Agent不变成"精神分裂"
跨会话一致性:如何让Agent不变成”精神分裂”
引言:每次重启都重新认识我?
上个月我测试一个客服Agent,发现了诡异的现象:
会话1: 我告诉它”我是年费会员,经常遇到登录问题” 会话2: 它问我”请问您是什么类型的会员?” 会话3: 它再次问我”能否描述一下您遇到的问题?”
同一个Agent,三次对话,三次让我重复相同的信息。更糟糕的是——
会话4: 它说”根据您的描述,您是免费会员…”
等等,我什么时候说过我是免费会员?它在 hallucinate 我的身份。
这就是跨会话一致性的灾难:Agent在长期交互中失去了对用户的连续认知。
一、什么是跨会话一致性
1.1 三个层面的一致性
身份一致性:
- 用户是谁(偏好、历史、关系)
- Agent是谁(性格、风格、承诺)
知识一致性:
- 已经告诉Agent的事实
- Agent已经生成的结论
- 双方达成的共识
上下文一致性:
- 当前任务的进度
- 之前的决策和理由
- 待办事项和下一步
1.2 不一致的代价
用户体验层面:
- 重复劳动(反复介绍自己)
- 认知负担(需要记住Agent应该知道什么)
- 信任崩塌(Agent显得不可靠)
系统层面:
- 错误累积(基于不一致的假设做决策)
- 冲突爆发(新旧知识矛盾时崩溃)
- 资源浪费(重复处理相同问题)
商业层面:
- 客户流失(73%的用户因为”需要重复解释”而放弃服务)
- 品牌损害(”这个AI助手记不住事”)
二、一致性维护的核心挑战
2.1 时间旅行问题
用户说:”我上周说的那个方案,现在想改一下”
Agent需要:
- 找到”上周的对话”
- 定位”那个方案”
- 理解”改一下”的具体含义
- 更新知识,同时保留历史记录(审计需要)
挑战:如何在海量记忆中准确定位历史上下文?
2.2 冲突解决
场景1:用户改变了主意
- 上周:”我喜欢蓝色”
- 这周:”我喜欢绿色”
- Agent应该:更新偏好,但知道”曾经喜欢蓝色”
场景2:用户纠正了错误
- 之前:”我是1990年出生的”(用户说错了)
- 现在:”抱歉,我是1995年出生的”
- Agent应该:修正年龄,但记录”用户曾误报为1990”
场景3:信息自相矛盾
- 记忆A:”用户是素食者”
- 记忆B:”用户喜欢牛排”
- Agent应该:标记矛盾,询问澄清
2.3 渐进式披露 vs 信息过载
问题: 如果把用户所有的历史信息都塞进每次对话的prompt,很快会超Token限制。
矛盾:
- 信息太少 → 缺乏上下文,显得健忘
- 信息太多 → 噪音淹没信号,推理质量下降
需要: 智能地选择”当前相关的历史信息”
三、工程解决方案
3.1 用户画像(User Profile):不变的核心
维护一个相对稳定的用户画像,跨会话持久化:
@dataclass
class UserProfile:
user_id: str
# 静态属性(很少变化)
preferences: Dict[str, Any] # 喜欢/不喜欢
facts: Dict[str, Any] # 基本事实(年龄、职业等)
# 动态摘要(定期更新)
interaction_summary: str # "用户主要关注技术话题,近期在找工作"
# 关系历史
relationship_stage: str # "新朋友"/"熟客"/"VIP"
trust_level: float # 0-1,基于历史交互质量
# 时间戳
created_at: datetime
updated_at: datetime
def update(self, new_info: dict):
"""更新画像,处理冲突"""
for key, value in new_info.items():
if key in self.facts and self.facts[key] != value:
# 记录历史版本
self._archive_fact(key, self.facts[key])
self.facts[key] = value
self.updated_at = datetime.now()
使用时机: 每次对话开始时加载,作为系统prompt的一部分。
更新策略:
- 高频:每次对话后摘要更新
- 低频:月度完整复盘
- 触发式:检测到重要事实变化时立即更新
3.2 会话摘要链:压缩的历史
不存储完整对话,存储分层摘要:
会话100(原始)→ 摘要(100 tokens)
会话99(原始)→ 摘要(100 tokens)
...
当摘要积累到10个:
→ 合并为"第10-20会话摘要"(150 tokens)
当合并摘要积累到10个:
→ 合并为"第1-100会话总摘要"(200 tokens)
形成金字塔结构:
- 底层:最近5个会话的详细摘要
- 中层:过去20个会话的合并摘要
- 顶层:历史总摘要
检索时:
- 优先加载底层(细节准确)
- 补充中层(近期上下文)
- 顶层作为背景知识
3.3 时间感知的记忆索引
给每个记忆加上时间维度:
class TemporalMemory:
def __init__(self, content, timestamp, ttl=None):
self.content = content
self.created_at = timestamp
self.ttl = ttl # Time to live,过期自动降级
self.access_count = 0
self.last_accessed = timestamp
def relevance_score(self, query_time):
"""计算时间相关性"""
age = query_time - self.created_at
recency = math.exp(-age.days / 30) # 30天半衰期
frequency = math.log(1 + self.access_count)
return recency * frequency
def is_stale(self, current_time):
"""检查是否过期"""
if self.ttl is None:
return False
return (current_time - self.created_at) > self.ttl
查询时排序:
def retrieve_relevant_memories(query, user_id, current_time):
memories = vector_db.search(query, user_id=user_id)
# 按时间相关性重排序
scored = [(m, m.relevance_score(current_time)) for m in memories]
scored.sort(key=lambda x: x[1], reverse=True)
return [m for m, _ in scored[:5]] # Top-5最相关的
3.4 冲突检测与解决
检测冲突:
class ConflictDetector:
def detect(self, new_fact, existing_facts):
conflicts = []
for fact in existing_facts:
# 语义相似但值不同
if (self.semantic_similarity(new_fact, fact) > 0.8 and
new_fact.value != fact.value):
conflicts.append({
'existing': fact,
'new': new_fact,
'type': 'contradiction'
})
return conflicts
解决策略:
def resolve_conflict(conflict):
existing, new = conflict['existing'], conflict['new']
# 策略1:时间优先(新覆盖旧)
if new.timestamp > existing.timestamp:
return new, reason="newer_information"
# 策略2:来源可信度假先
if new.source_credibility > existing.source_credibility:
return new, reason="more_credible_source"
# 策略3:用户显式纠正
if new.is_explicit_correction:
return new, reason="user_correction"
# 策略4:标记矛盾,询问用户
return ConflictResolution.ASK_USER, details=conflict
3.5 会话状态管理
维护跨会话的状态机:
class ConversationState:
def __init__(self):
self.current_topic: str = None
self.pending_questions: List[str] = []
self.agreements: Dict[str, Any] = {} # 已达成的共识
self.action_items: List[Dict] = [] # 待办事项
def save_to_memory(self):
"""会话结束时保存状态"""
return {
'topic': self.current_topic,
'pending': self.pending_questions,
'agreements': self.agreements,
'todos': self.action_items,
'timestamp': datetime.now()
}
@classmethod
def load_from_memory(cls, saved_state):
"""新会话开始时恢复状态"""
state = cls()
state.current_topic = saved_state.get('topic')
state.pending_questions = saved_state.get('pending', [])
state.agreements = saved_state.get('agreements', {})
state.action_items = saved_state.get('todos', [])
return state
开场白示例:
"欢迎回来!上次我们聊到[话题],你提到想[待办事项]。
另外,关于[之前的问题],我找到了一些新信息..."
四、实践中的经验
4.1 一致性校验清单
每次对话前检查:
- 用户画像是否最新?
- 是否有未完成的待办事项?
- 上次对话的承诺是否兑现?
- 时间敏感信息是否过期?
4.2 优雅降级
当一致性维护失败时:
"我注意到我们之前讨论过这个话题,但我的记录可能不完整。
为了给你最好的帮助,能否快速确认一下:
- 你目前使用的是[系统X]吗?
- 你提到的[问题Y]解决了吗?"
不假装记得,主动确认,用户通常很乐意快速更新。
4.3 用户控制
让用户可以:
- 查看Agent记住的关于自己的信息
- 纠正错误信息
- 删除敏感信息
- 选择”这次对话不要带历史上下文”
透明度和控制权建立信任。
五、总结
跨会话一致性不是技术问题,是产品设计问题。
核心原则:
- 分层存储:热数据快速访问,冷数据归档压缩
- 智能更新:不是记住一切,而是记住重要的
- 冲突显式化:不隐藏矛盾,主动解决或询问
- 用户主权:用户控制自己的数据
最好的Agent不是记忆力最强的,而是让用户感觉”它懂我”的。
延伸阅读:
- Kahneman, D. (2011). “Thinking, Fast and Slow”(关于认知一致性)
- Chen, D.L., et al. (2019). “Evaluating Consistency in Text Generation”
- Xu, J., et al. (2022). “Long-term Memory in Conversational AI”
标签: #Agent设计 #一致性 #记忆管理 #长期交互 #用户体验