记忆张量亿元Pre A融资后,AI记忆如何成为Agent的长期基础设施
2026/9/29 2:59:03
“您好,请稍等,正在为您转接人工客服……”
这句熟悉的开场白,平均要让人等 30-60 秒。传统客服系统大多基于“关键词+正则”或“if/else 规则树”,维护成本高、扩展性差,一旦业务上新,就要重新写规则、重新发版。更尴尬的是,用户换种说法问同一问题,机器人就“装傻”,体验瞬间翻车。
过去三年,我们团队先后踩过三种技术路线:
对比之后,我们决定把宝押在大模型上,但很快发现“会跑 demo”和“敢上生产”是两回事:并发一高 GPU 就爆显存、问答一深就丢上下文、用户一调皮就触发敏感词。于是有了下面这份“从 0 到 1”的实战笔记。
整体思路一句话:“异步解耦 + 缓存提速 + 弹性扩缩”。先上图,再拆讲。
下面给出最常被问的三块代码:负载均衡调用、对话状态管理、敏感词过滤。全部单文件可跑,已按 PEP8 格式化,可直接集成到现有仓库。
# llm_client.py import asyncio import hashlib import httpx from typing import List from redis import asyncio as aioredis CACHE_TTL = 300 WORKERS: List[str] = ["http://gpu-worker-1:8000", "http://gpu-worker-2:8000"] class LlmClient: def __init__(self): self.rds = aioredis.from_url("redis://redis:6379/0", decode_responses=True) self.client = httpx.AsyncClient(limits=httpx.Limits(max_connections=100)) async def ask(self, user_id: str, query: str) -> str: # 1. 构造缓存 key key = "cache:" + hashlib.md5(query.encode()).hexdigest() cached = await self.rds.get(key) if cached: return cached # 2. 轮询负载均衡选 worker worker = WORKERS[hash(user_id) % len(WORKERS)] payload = {"prompt": query, "max_tokens": 512, "temperature": 0.3} resp = await self.client.post(f"{worker}/generate", json=payload, timeout=15) resp.raise_for_status() answer = resp.json()["text"] # 3. 写缓存并返回 await self.rds.setex(key, answer, ex=CACHE_TTL) return answer# dialog_state.py from datetime import datetime from typing import Dict, List from pymongo import MongoClient, ASCENDING, IndexModel mongo = MongoClient("mongodb://mongo:27017/chat") session_coll = mongo["chat"]["session"] # 建复合索引,防止全表扫描 session_coll.create_indexes([IndexModel([("user_id", ASCENDING), ("ts", ASCENDING)])]) class DialogState: """负责拉取、追加、压缩多轮上下文""" MAX_HISTORY = 6 # 经验值,再大显存吃不消 @staticmethod async def load(user_id: str) -> List[Dict[str, str]]: cursor = session_coll.find({"user_id": user_id}).sort("ts", -1).limit(MAX_HISTORY) return [{"role": x["role"], "content": x["content"]} for x in cursor][::-1] @staticmethod async def append(user_id: str, role: str, content: str): session_coll.insert_one({ "user_id": user_id, "role": role, "content": content, "ts": datetime.utcnow() })# sensitive_filter.py import re from typing import Set class DFAFilter: def __init__(self, word_set: Set[str]): self.root = {} for w in word_set: self._add_word(w.lower()) def _add_word(self, word: str): node = self.root for ch in word: node = node.setdefault(ch, {}) node["end"] = True def exists(self, text: str) -> bool: text = re.sub(r"\s+", "", text.lower()) for i in range(len(text)): node = self.root for ch in text[i:]: if ch not in node: break node = node[ch] if "end" in node: return True return False把上面三段代码拼进 Worker,主循环大概长这样:
async def consumer(): while True: msg = await redis.xreadgroup({"stream": "chat", "group": "gpt", "consumer": "c1"}) user_id, query = parse_msg(msg) history = await DialogState.load(user_id) answer = await llm.ask(user_id, build_prompt(history, query)) await DialogState.append(user_id, "assistant", answer) await redis.xack("chat", "gpt", msg.id)--gpu-memory-utilization 0.9,预留 10% 给临时 Tensor,防止 OOM。retry_on_timeout=False),本地内存 LRU 兜底 30 s,保证核心链路可用。nvidia-fabricmanager,否则驱动升级后 P2P 通信会掉速 30%。把系统怼到 140 QPS 后,新的矛盾出现了:
“再拉大模型尺寸到 30B,效果还能涨 2 个点,可 TTFT 直奔 1.2 s,客服主管不答应;砍回 7B,延迟是稳了,准确率又掉 3 个点,运营不答应。”
如何优雅地平衡“效果 vs 延迟”?目前能想到三条路:
哪条路更香?或者你有第四条路?欢迎留言一起拆坑。