View a markdown version of this page

Multi-turn 对话缓存 - Amazon ElastiCache

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Multi-turn 对话缓存

对于具有多回合对话的应用程序,根据上下文,相同的用户消息可能具有不同的含义。例如,在关于 Valkey 的对话中,“告诉我更多” 的含义与关于 Python 的对话中的 “告诉我更多” 不同。

面临的挑战

Single-prompt 缓存非常适合无状态查询。在多回合对话中,您必须缓存完整的对话上下文,而不仅仅是最后一条消息:

# "Tell me more" means nothing without context # Conversation A: "What is Valkey?" -> "Tell me more" (about Valkey) # Conversation B: "What is Python?" -> "Tell me more" (about Python)

策略:上下文感知缓存密钥

嵌入完整对话上下文的摘要,而不是只嵌入最后一条用户消息。这样,相似对话流程中的类似后续问题就可以重复使用缓存的答案。

def build_context_string(messages: list) -> str: """Build a cacheable context string from conversation messages.""" # Use last 3 turns (6 messages: user + assistant pairs) recent = messages[-6:] parts = [] for msg in recent: role = msg["role"] content = msg["content"][:200] # Truncate long messages parts.append(f"{role}: {content}") return " | ".join(parts)

Per-user 使用 TAG 过滤器进行缓存隔离

使用 TAG 字段按用户、会话或其他维度隔离缓存的对话。这样可以防止将一个用户的缓存对话返回给另一个用户:

# Create index with TAG field for per-user isolation valkey_client.execute_command( "FT.CREATE", "conv_cache_idx", "SCHEMA", "context_summary", "TEXT", "response", "TEXT", "user_id", "TAG", "turn_count", "NUMERIC", "embedding", "VECTOR", "HNSW", "6", "TYPE", "FLOAT32", "DIM", "1024", "DISTANCE_METRIC", "COSINE", )

使用混合过滤进行搜索(TAG + KNN):

def lookup_conversation_cache(messages: list, user_id: str, threshold: float = 0.12): """Search cache for similar conversation contexts, scoped to a user. Note: FT.SEARCH with COSINE distance returns a distance score where 0 = identical and 2 = opposite. A lower score means higher similarity. The threshold here is a maximum distance: only return results closer than this value. """ context = build_context_string(messages) query_vec = get_embedding(context) # Hybrid search: filter by user_id TAG + KNN on context embedding results = valkey_client.execute_command( "FT.SEARCH", "conv_cache_idx", f"@user_id:{{{user_id}}}=>[KNN 1 @embedding $query_vec]", "PARAMS", "2", "query_vec", query_vec, "DIALECT", "2", ) if results[0] > 0: fields = results[2] field_dict = {fields[j]: fields[j+1] for j in range(0, len(fields), 2)} distance = float(field_dict.get("__embedding_score", "999")) if distance < threshold: # Lower distance = more similar return {"hit": True, "response": field_dict.get("response", ""), "distance": distance} return {"hit": False}
注意

@user_id:{user_123}TAG 过滤器可确保用户 A 缓存的对话不会泄露给用户 B。混合查询 (TAG + KNN) 作为单个原子操作运行,即按用户进行预过滤,然后找到最近的对话上下文。

缓存隔离策略

Strategy 标签过滤器 适用于
Per-user @user_id:{user_123} 个性化助手
Per-session @session_id:{sess_abc} Short-lived 聊天
全球(共享) 没有过滤器 (*) FAQ 机器人、常见查询
Per-model @model:{gpt-4} Multi-model 部署
Per-product @product_id:{prod_456} E-commerce 助手