尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
AI Agent记忆系统设计实战:分层、存储与召回
1. 定制记忆机制Agent 为什么必须“记住你”如果你玩过几款对话式 AI 工具大概会有一种很典型的感觉刚聊完一个复杂需求换个会话再问它就像失忆了一样又得从头交代背景。最开始我以为是产品设计缺陷后来自己动手写 Agent 才明白这恰恰是当前大多数 Agent 的基础形态——无状态推理。每一次请求进来模型看到的就是一段独立的上下文聊完即焚什么都不留。这就带来了一个很实际的问题我们想要的 Agent应该是越用越懂我的助手而不是每次见面都要重新自我介绍的陌生人。所以当我在搭建自己的 Agent 项目时记忆模块就成了优先级最高的事情之一。这篇博文我用实际项目的经验把 Agent 记忆从概念到落地完整拆一遍包括我踩过的坑、改过的设计、实测下来的方案尽量讲得直白可复现。先说清楚一个容易混淆的点记忆不是简单地“把聊天记录存下来”然后一股脑塞回提示词里。如果真是这么干上下文窗口再大也会被撑爆而且模型会分不清哪些信息是当前任务需要的、哪些只是历史噪音。真正可用的 Agent 记忆是一个有分层、有写入策略、有召回机制的系统。好的记忆设计直接影响 Agent 在复杂任务里的连贯性和个性化表现而这两点恰恰是 Agent 从“玩具”走向“生产力工具”的关键。这篇文章适合这几类人看正在自己搭 Agent、但对记忆模块无从下手的开发者使用 Claude、开源编程助手等工具时发现“换会话就失忆”、想理解背后原理的进阶用户准备面试 AI Agent 相关岗位需要系统梳理记忆系统设计的人。我会从最基础的设计思路开始讲然后落地到存储、写入、召回、清理这几个核心环节最后分享一套我在实际项目里验证过的方案和踩坑记录。2. 先想清楚短期记忆与长期记忆到底该怎么分层2.1 双网络记忆模型的启发性思路在设计记忆系统之前建议先了解一下“双网络记忆模型”这个思路。它不是某个产品的专利而是一种很有参考价值的架构划分把记忆分为快速更新的短期网络和稳定积累的长期网络。短期网络负责当前任务上下文里的即时信息长期网络负责跨会话、跨任务持续保留的用户偏好与事实。放在 Agent 场景里这套思路刚好和人类的记忆机制形成类比。你和一个同事协作短期记忆是你俩正在讨论的这份文档的细节长期记忆是你知道他习惯用 Python、讨厌冗长邮件、项目背景是金融风控。同事之所以好用是因为他两套记忆都在线。Agent 要成为好用的数字同事也一样。我之前看过一份记忆系统设计文档里面有一句话我特别认同短期记忆要“快进快出”长期记忆要“精挑细选”。什么意思呢短期记忆追求的是准确和时效当前对话里用户刚提到的需求、刚修改的文件必须原样保留不能丢长期记忆追求的是稳定和泛化得从多次交互里提炼出真正值得跨会话保留的东西而不是把流水账全塞进去。2.2 三层结构工作记忆、短时记忆、长时记忆我在实际项目里把记忆划分成了三层比“短/长”两分法多了一层工作记忆用起来更顺手工作记忆Working Memory当前这一次任务执行过程中的动态信息。比如 Agent 正在读的代码文件内容、正在处理的用户指令、上一次工具调用的返回结果。这层记忆生命周期极短任务结束就基本作废但它决定了一次任务内的推理质量。短时记忆Short-term Memory最近几次会话里的对话摘要和关键上下文。比如用户昨天让我写了个爬虫脚本今天说“那个脚本再加个重试机制”短时记忆要能帮 Agent 知道“那个脚本”指的是什么。这层记忆通常以会话摘要或最近 N 轮对话的形式存在。长时记忆Long-term Memory跨天、跨月仍然有效的稳定信息。用户的工作领域、常用技术栈、代码风格偏好、项目的业务背景、曾经明确纠正过的错误。这层记忆要求最高需要抽取、去重、验证不能随便什么东西都往里面写。这三层的关系我自己的理解是工作记忆是“寄存器”短时记忆是“内存”长时记忆是“磁盘”。寄存器数据丢了无所谓内存丢了影响当前会话磁盘丢了相当于失忆。2.3 分层设计带来的实际收益把记忆做成分层之后最直接的收益是提示词成本的下降。以前我每开一个新会话都得把项目背景、技术栈、用户偏好写一大段塞进 system prompt现在这部分可以完全交给长期记忆自动注入。实测下来新会话的“冷启动”时间缩短了一大截用户不需要重复交代背景Agent 也能给出更贴合个人习惯的回答。另一个收益是降低了记忆相互污染的风险。如果不分层把所有历史记录混在一个池子里很容易出现一种尴尬情况Agent 在当前这个编程任务里突然想起了用户上个月聊的旅游计划然后给出了一个莫名其妙、混杂了无关信息的回答。分层之后召回时按场景和类型过滤这种串味问题基本杜绝了。注意分层不是越细越好。我最初设计过四层、五层的方案加了“技能记忆”“事实记忆”“偏好记忆”之类的细分结果维护成本爆炸召回逻辑复杂到我自己都调试不过来。三轮迭代之后稳定在三层结构简单、够用、好维护。3. 存储与写入让记忆真正沉淀下来3.1 向量库选型不要一上来就上重型武器记忆大概率要用向量检索来找回最相关的内容所以向量数据库是绕不开的一环。市面上可选的东西不少有专业的 Milvus、Qdrant、Weaviate也有轻量的 Chroma、LanceDB还有各云厂商的向量检索服务。很多人一上来就选功能最全的我觉得没必要得看你自己的场景和规模。我自己在个人项目和中小型项目里用得最顺手的是 Chroma原因很实际零配置、嵌入式运行、API 简洁。对于一个会话量不大的 Agent 来说Chroma 的单机性能完全够用数据存在本地不用额外维护一套数据库服务。等规模真的大到单机扛不住了再迁到 Qdrant 或者 Milvus那时候你的数据模型和召回逻辑已经成熟了迁移只是换 client 的事。如果你的场景是团队协作、数据量很大、需要高并发检索那可以直接上专业的向量库。但注意选型之前先想清楚三个问题你的数据量级有多大检索延迟要求多高运维人力够不够这三个问题没想清楚就选型容易陷入“用大炮打蚊子”的尴尬。3.2 结构化记忆与向量记忆的配合使用纯靠向量检索做记忆有一个隐藏的问题向量检索擅长找“相似”但不太擅长找“精确”。比如用户明确说过“我的项目部署在 8080 端口”这是个精确事实如果把它向量化存起来召回时靠相似度匹配很可能召回的是一堆“端口”“部署”相关的相似内容真正的答案反而被淹没在排序结果里。所以我的方案是双轨制结构化记忆 向量记忆。结构化记忆用 JSON 或数据库表存用户偏好、项目配置、明确的键值对信息。查询时走精确匹配比如获取用户的技术栈、常用路径、历史纠错记录。向量记忆存对话摘要、经验教训、文本片段这类“语义型”的信息。查询时走相似度检索。在实际调用时我会先查结构化记忆把确定的硬事实注入提示词然后再用向量检索补充相关内容。两条路并行互补性很强。这里有一个很实用的做法给每条记忆打上类型标签比如fact、preference、summary、correction召回时按类型过滤。这样既能保证精确信息不走偏也能让语义内容有足够的召回空间。3.3 写入策略什么值得记什么不值得记记忆系统的关键其实不在存储而在写入。存什么、不存什么直接决定了记忆的质量。如果你把每轮对话都原样存进长期记忆过不了一周记忆库就全是噪音召回质量迅速恶化。我自己用了一套写入规则实测下来效果很好值得记用户明确表达过两次以上的偏好用户纠正过 Agent 的说法项目的核心背景信息用户主动介绍的个人信息和工作习惯任务完成后的关键结论。不值得记一次性的问候和闲聊临时性的调试过程当前任务中的过程性噪音已经过时的临时信息。需要经过摘要再记长对话的关键结论。这里我用摘要模型做一个信息压缩把一轮长对话提炼成 3-5 句话只保留关键事件、结论、用户偏好变化再写入长期记忆。这个筛选过程我一开始是靠手工设计的规则后来逐步升级成“两条路并行”的写法一条规则路径处理精确信息一条模型路径处理需要理解和提炼的内容。规则路径用正则和简单的条件判断保证可靠模型路径用大模型做摘要和实体抽取保证灵活。实操心得在写入长期记忆之前一定要做一次“相似度去重”检查。先检索一下库里有没有意思相近的记录如果相似度超过阈值要么跳过要么合并后覆盖旧记录。不然同一个信息可能会以不同措辞存上七八条将来归回时会出现内容重复、互相矛盾的情况。4. 召回与注入记忆怎么在对话里“活”起来4.1 召回策略按场景、时间、相关性三维过滤记忆存进去了怎么取出来用才是难点。如果每次对话都把库里所有记忆全塞进上下文一是浪费 token二是引入噪音。我的召回策略是三维过滤第一维是场景过滤。你当前在做什么任务写代码、查资料、聊天按记忆的scene标签过滤比如编程任务只召回编程相关的历史记忆不把用户聊旅行时的偏好翻出来。第二维是时间衰减。记忆不是越久越重要。我给每条记忆打了一个last_accessed时间戳在相关性计算时叠加一个时间衰减因子。很久没用的记忆相关性会被适当降低最近反复用到的高频记忆权重会提高。第三维才是相关性检索。经过前两轮粗过滤再进向量库做相似度检索取 top K 条。我一般取 5-10 条根据任务复杂度动态调整。召回的时间点也很有讲究。我一开始是在每次用户发消息时都做召回后来发现很多轮对话根本不需要新的记忆注入——比如用户只说了一句“继续”。后来改成每次新会话开始、用户提到历史相关内容、任务上下文发生明显切换时才触发召回。这样既省 token也避免提示词太臃肿。4.2 上下文注入的位置与格式召回出来的记忆放在提示词哪里是有讲究的。我自己常用的套路是分两块放把稳定的长期记忆用户偏好、项目背景、纠错记录放在 system prompt 里作为 Agent 的“人设底座”。把当前任务相关的短时记忆和召回结果插入到对话历史的开头作为背景参考。格式上我用了一个很简单的 XML 标签包裹记忆块模型理解起来非常干净memory user_profile 技术栈Python, TypeScript偏好简洁风格用过 FastAPI 和 Next.js /user_profile project_context 正在开发一个个人博客系统部署在 8080 端口 /project_context relevant_history 用户不喜欢冗长的代码注释偏好自解释的命名 /relevant_history /memory实测下来这种带标签的记忆块比纯文本拼接更容易让模型区分“哪些是背景记忆、哪些是当前上下文”回答时也更不容易把记忆内容当成用户当前的指令。如果你在用 Claude 或 GPT 系列模型这个格式基本都是兼容的。4.3 防止“记忆中毒”的隔离设计记忆系统最怕的一类问题是“记忆中毒”——即某一次对话里的错误信息被当成长期事实写入记忆库从此每一次对话都被污染。这种情况在 Agent 场景里很容易发生毕竟大模型也会犯错如果它犯的错被当成“事实”存了下来后续所有任务都会基于这个错误事实推理。我在项目里加了两层防线。第一层是写入前的置信度校验不是所有模型抽取出的“事实”都允许直接入长期库只有满足以下条件之一的才写入——用户明确确认过的信息、规则路径抽取的结构化硬数据、已经被验证多次的模式。第二层是定期的人工/模型复核我用一个独立的审计任务每周扫描一次长期记忆库把可疑的、矛盾的、过时的记录清理掉。这个隔离设计一开始被我想得过于简单觉得“抽取出事实、存进去、召回”三步就完了。实际跑了两周之后发现问题比预想的多得多模型会把“我觉得”“可能”这类猜测性表达直接抽成事实会把某个单次任务里的临时上下文写进长期库甚至会把用户的一句反话当成偏好记下来。加了审计之后记忆库的“纯度”才真正可控。5. 实操案例借助 Hindsight 式经验库和双网络模型做升级5.1 从工具型 Agent 到“经验增长型” Agent前面讲的这套短时 长时记忆方案解决的是“记住用户”的基本问题。但如果你想往更高级的方向做就要开始思考另一件事Agent 能不能记住“经验”这里说的经验不是用户的偏好而是 Agent 自己踩过的坑和总结出的方法。比如在编程场景里Agent 上次改一个模块时发现某种写法会导致报错它下次遇到类似任务时能不能自动避开这个坑这种能力就是所谓的“经验增长型” Agent。Hindsight 记忆库事后复盘式记忆就是解决这个问题的思路每次任务结束后让 Agent 做一次回顾提炼出“什么做法有效、什么做法有问题、下次怎么做更好”这类元经验存入独立记忆库。下次遇到相似任务时这个经验库会参与召回让 Agent 的表现超出单个模型的基础能力。我实测过这个机制效果确实明显。一个多轮调试任务里第一次跑的时候 Agent 绕了三个弯才找到问题根因跑了七八个任务、积累了复盘经验之后再遇到同类问题时它往往第一轮就能直接命中正确的排查方向。这个提升不是来自模型本身变聪明了而是记忆系统把它过去的经验“喂”给了它。Hindsight 式经验库的关键在于复盘触发机制。不能每个任务都复盘那样浪费 token 且噪音多也不能完全不复盘。我的做法是设定触发规则任务失败或做了多次尝试才成功的时候强制复盘任务顺利完成的由模型快速判断是否有值得沉淀的经验。复盘输出统一格式目标、尝试过的方案、失败原因、有效方案、可复用的经验。5.2 双网络记忆模型在长对话 Mult-Agent 场景里的落地前面提到过双网络记忆模型。在简单的单 Agent 场景里这个模型的实现相对直接一个短期存储 一个长期存储。但如果你做的是 Multi-Agent多智能体系统比如用 Spring AI Multi-Agent 的架构编排多个角色协作记忆的复杂度会上一个新台阶每个子 Agent 有没有自己的独立记忆它们之间要不要共享记忆共享到什么程度我的项目里有三个角色 Agent一个负责用户需求理解一个负责技术方案设计一个负责最终代码实现。最开始我让三者共享同一个长期记忆库结果很糟糕需求理解 Agent 写入的用户偏好被技术方案 Agent 当成了技术约束技术方案 Agent 写的讨论过程被代码实现 Agent 当成了最终决策。各个角色的记忆互相串味。后来我改成了“分工独立 共享摘要”的模式每个 Agent 有自己的私有短期记忆和私有长期记忆只在必要节点向共享记忆层写入经过摘要的结论。比如需求理解 Agent 最终确认的用户意图写入共享层技术方案 Agent 的选择和理由写入共享层代码实现 Agent 的过程性探索只留在私有层不进共享。这套设计和双网络记忆模型的结合点在于每个 Agent 内部是双网络结构多 Agent 之间则通过共享摘要形成第三层“团队记忆”。5.3 一个可复制的本地记忆迁移思路最后分享一个很多人在实际使用中都会遇到的场景本地已有的历史对话记录怎么迁移到自己的 Agent 记忆系统里让之前积累的信息不白费。我之前的工具里存了大概几个月的对话记录有大量的项目讨论、代码方案、用户偏好这些都是宝贵的记忆素材。迁移思路分三步第一步是数据导出。先把历史对话按会话维度导出成 JSON 格式每条消息保留 role、content、timestamp 字段。第二步是批量清洗和结构化。这一步是关键。原始对话里有大量寒暄、中断、试错过程直接入库就是灾难。我给这个过程写了一个批处理脚本用模型逐条判断这条消息里有没有值得长期保留的用户信息、项目事实、方案决策有的话抽取提炼后生成结构化记忆条目打上类型和场景标签没有价值就当噪声丢弃。第三步是去重验证后批量写入。写入前先向量化所有现有记忆对每条新条目做相似度检查高于阈值就跳过或者合并。全部过完一遍后再随机抽几条做人工验证确认迁移质量没问题。我在实际迁移中几个月的历史对话最终提炼出大概几十条干净的长期记忆条目量不大但每条都是精品。后续对话里Agent 能准确说出我之前的项目背景和技术选型让它的回答明显“更懂我”了。6. 踩坑记录记忆系统常见的四个大坑与排查方案6.1 幻觉记忆覆盖正确的信息被错误覆盖这是我在长期记忆系统里遇过的最隐蔽的问题之一。场景是这样的用户在 12 月说“部署在 8080 端口”后来项目调整又改口说“现在用 80 端口了”。新记忆写入时检测到“端口”信息相似直接覆盖了旧记录。表面上看没问题但如果 Agent 在回答“项目之前部署在哪里”这样的历史问题时正确答案已经在覆盖过程中丢失了。排查思路覆盖策略不能是“见新就覆盖旧的”。我后来加了版本化机制旧记录不是直接删除而是标记为superseded并存到一个归档区。召回时默认用最新版但如果问题明显是询问历史情况则可以在摘要层看到变更轨迹。6.2 上下文膨胀记忆太多导致模型分心还有一个高频问题召回逻辑太激进每次都注入十几条记忆提示词越来越长模型的注意力反而被稀释。最典型的表现为用户问一个简单问题Agent 却在回答里塞了很多记忆里的背景信息答非所问对话变得笨重。排查方案严格控制注入条数并且引入一个“记忆必要性判断”。不是所有问题都需要记忆加持。简单的事实问答、闲聊、当前上下文中已经有答案的问题都不触发记忆召回。只有用户的问题里出现了历史相关内容的关键词或者系统判断当前任务与长期记忆中的某个场景强相关时才做召回注入。6.3 召回失效看起来存了但用的时候想不起来另一种常见问题是“存了但召回不出来”。我在早期排查时发现很多情况下不是向量检索本身有问题而是存储时的分块策略和召回时的查询语句不匹配。比如存的时候是整段长文本召回的 query 是一句简短的话语义距离可能超过阈值导致该命中的没命中。排查方案一是调整分块长度建议先按 300-500 字一个块做实验比较召回效果后再定二是召回时不只用用户原始的问题去做向量检索还可以配合关键词匹配作为补充通道三是对已经确认有价值、但召回不稳定的记忆额外加一条结构化标签路径保证精确命中。6.4 敏感信息与隐私边界的处理记忆系统越智能越要重视隐私。如果 Agent 记住了用户的银行卡号、密码、身份证信息一旦记忆库泄露后果不堪设想。我在设计时就定了一条规则长期记忆库只允许存“信息”和“偏好”不允许存“凭证”和“隐私”。具体做法是写入前有一个敏感信息检测过滤层用正则和模型双重判断包含手机号、邮箱、地址、账号密码类的信息直接拦截不进入记忆库。如果用户确实需要在上下文里使用这些信息可以用临时的环境变量或专用配置注入而不是沉淀为长期记忆。注意这条红线建议所有做记忆系统的人都严格遵守。技术能力越强越要在数据边界上保持克制。7. 一套经过验证的最小可落地记忆方案参考说了这么多最后给出一套最小的落地参考方便你先跑起来再迭代。首先是记忆存储层的组件选型我的组合是这样功能选型理由向量存储Chroma单机/ Qdrant规模化起步零配置后期可迁移结构化存储SQLite 或 JSON 文件简单、可靠适合个人项目摘要生成大模型二次调用利用模型做信息压缩和提炼记忆去重向量相似度计算检索历史记忆判断是否重复然后是写入流程按照前面的规则整理成四条执行步骤对话结束后先判断这条消息是否包含值得保留的信息规则路径抽取结构化数据用户偏好、明确事实、纠错记录模型路径生成摘要和语义向量用于语义型记忆写入前做去重检查超过相似度阈值就跳过或合并。召回流程则按照这个顺序执行判断当前任务是否需要调用记忆不需要就跳过按场景标签做初步过滤对候选记忆做时间衰减加权进入向量库做相似度检索取 Top 5 条左右格式化后注入提示词的 system prompt 和背景区。再给一个简化版的代码思路方便理解流程# 简化的记忆召回逻辑 def recall_memories(user_query, scene): # 1. 场景过滤 candidates memory_store.filter(scenescene) # 2. 时间衰减加权 candidates [ {**mem, weight: mem[relevance] * decay(mem[last_accessed])} for mem in candidates ] # 3. 相似度检索 query_embedding embed(user_query) results vector_store.query(query_embedding, filtercandidates) # 4. 返回 Top K 条 return sorted(results[:5], keylambda x: x[weight], reverseTrue)这套方案不可能适用所有场景但它最大的优点是好调试、好扩展。你先跑通这套最小闭环再来按自己项目的复杂程度逐步升级。我在实践里也是从这套方案起步慢慢迭代成了前面说的多层结构。根据我个人的实操体会Agent 记忆系统最需要耐心的地方不在存储选型也不在提示词技巧而在“取舍”什么值得记、什么不该记、什么该忘。把这三件事想清楚了你的 Agent 就会真正越来越懂你。
RELATED

相关推荐

混合路由架构:RAG知识库与NL2SQL统一智能问答方案

混合路由架构:RAG知识库与NL2SQL统一智能问答方案

最近在整理企业数据助手项目时,我发现自己陷入了一个不算新、但特别典型的困境:业务方对“知识”的需求和对“数据”的需求,原本是两套系统分别在满足,可我越做越觉得哪里不对劲。我们当时给公司搭了一个基于RAG知识库的智能问答机…

📅 2026/9/14 7:35:45
Wasp 如何为自定义 API 添加 Swagger UI 文档页并在线测试端点

Wasp 如何为自定义 API 添加 Swagger UI 文档页并在线测试端点

Wasp 如何为自定义 API 添加 Swagger UI 文档页并在线测试端点 【免费下载链接】wasp The batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack fe…

📅 2026/9/14 7:35:45
2026 AI应用与智能体开发:Java+Python双栈实战课程全拆解

2026 AI应用与智能体开发:Java+Python双栈实战课程全拆解

2026年了,AI应用开发和智能体开发已经不是要不要学的问题,而是怎么学才不踩坑的问题。我做了几年线下实战课程,最大的感受是:网上教程很多,但从“看懂”到“能上线”之间,隔着一整条沟。就拿最常见的困惑来…

📅 2026/9/14 7:30:45
MORE NEWS

更多资讯

📰

移动应用安全测试全流程指南与最佳实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

基于YOLOv5与Flask的钢材表面缺陷检测完整落地指南

简介:基于Yolov5与Flask的钢材缺陷检测系统完整方案,面向计算机视觉方向的毕业设计、课程设计以及软件工程实践者。项目整合深度学习目标检测与Web服务,可完成裂缝、腐蚀、变形等缺陷的实时识别与可视化展示。压缩包共2000个文件,…

📰

第30讲:可验证交付的全流程落地方法论

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

QT四轴上位机实战:串口通信、姿态绘图与指令控制

简介:面向QT与无人机开发初学者,这份资源提供了四轴飞行器上位机软件的初级版本。内容涵盖基于Qt的GUI控制面板、串口通信模块、下位机协议解析以及简单的实时数据显示逻辑,适合希望上手无人机地面站基础开发、理解上位机与飞控交互流程的读者…

📰

开发者注意力管理:从科学原理到工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

基于深度学习的3D MRI分类:从数据集预处理到模型训练与评估

简介:本项目是一套面向医学影像分析入门者与深度学习初学者的3D MRI分类演示代码包,聚焦将对比学习中的InfoNCE损失扩展至弱监督场景,利用受试者年龄、性别等辅助信息改进数据表示。压缩包共12个文件,涵盖Python源码、图解图片与说…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬