为Claude外挂长期记忆:claude-mem实现原理与工程实践

发布时间:2026/10/26 16:04:32
为Claude外挂长期记忆:claude-mem实现原理与工程实践

1. 先聊聊为什么需要给Claude加记忆

做AI应用开发的朋友应该都有过这种体验:和Claude聊得正起劲,它突然忘了你十分钟前刚说过的关键信息。不是Claude不聪明,是LLM本身就没有持久记忆——每次对话结束,它的"大脑"就清空了,下一次会话完全是白纸一张。这个问题在个人使用场景还算能忍,但在实际项目里就是硬伤。

我最早做AI客服机器人时就栽过这个跟头。用户第一次来咨询说"我家孩子三岁,对花生过敏",第二次来又问"有什么适合的零食推荐",Claude完全不记得之前的对话,又按普通成年人标准给了花生酱推荐。这种体验别说用户了,我自己看着都尴尬。后来也试过把历史聊天记录全部塞进system prompt,但token用量暴涨,上下文一长,模型注意力就分散,回答质量明显下降。

这个场景对应的解决方案,就是给Claude外挂一个"记忆系统"。而claude-mem这个项目,做的正是这件事。它把Claude从一个"健忘的天才"变成一个"有记性的助手"——记住你的偏好、记住项目的上下文、记住用户的历史行为,然后在新会话中自动调用这些记忆。

我自己是从一个朋友的推荐下接触到这个项目的,当时正好在做一版带长期记忆功能的AI知识库,需要频繁在会话之间传递用户画像和业务知识。折腾了几个方案后,最终选择基于claude-mem做二次开发。这篇博文就把我从选型、部署到实际运行的全过程记录下来,包括踩过的坑和排过的错,希望能帮到同样在做Claude应用开发的朋友。

2. claude-mem的整体设计思路拆解

2.1 它解决的不是"对话历史存储",而是"记忆的管理"

市面上很多方案只做"历史消息存档",比如把对话记录按用户ID存进数据库,下次会话前再查出来拼进prompt。这种方案有两个致命问题:第一,随着历史积累,prompt越来越大,成本和延迟同步飙升;第二,大量无关信息混在prompt里,反而干扰模型对当前任务的理解。你问的是"今天天气怎么样",结果前面塞了两百条上周的闲聊记录,模型光过滤噪声就耗掉不少能力。

claude-mem的设计出发点就不一样。它要做的是把对话内容转化为结构化记忆,而不是简单地回放历史。想象一下你有一个私人秘书,你跟他每天聊天,他不会把每句话都记下来,而是会提炼重点:"这人姓张、做跨境电商、有个三岁孩子、对花生过敏、最近在找一款自动核算关税的工具"。下次你再找他帮忙,他调用的就是这些精炼后的档案,而不是上个月的聊天录音。

这个思路上的差异,是整个方案最核心的价值。它意味着两件事:第一,记忆是结构化的、可检索的,不是一堆原文堆在那里;第二,记忆是有优先级的,重要事实被单独提取出来,随时可以在新会话中激活。

2.2 核心工作链路:提取、存储、检索三层架构

claude-mem的整体结构可以拆成三个环节,对应一条完整的"记忆流水线"。

第一层是记忆提取。它监听你和Claude的对话,每轮交流结束后,后台把对话内容交给一个小型提取模型或规则引擎,识别出其中有长期价值的"事实"。比如用户说"这次项目截止日期是3月20日",提取器会把"截止日期=3月20日"这个结构化信息抽出来,而不是把整句话存下来。这一层的关键是识别什么值得记、什么不值得记。闲聊、寒暄、临时指令都不需要进入长期记忆;而用户的身份信息、项目关键参数、业务规则、明确的偏好声明,这些才是该沉淀的。

第二层是存储。提取出来的事实被写入一个持久化存储,一般是SQLite或向量数据库。每条记忆除了内容本身,还会带上时间戳、来源会话ID、关联的用户或项目上下文。这个设计让记忆不只是"存下来",而是"存得有条理"。我现在这个项目里用的是SQLite加轻量向量索引,因为我的场景偏单机、数据量不算大,不需要上重型数据库。

第三层是检索激活。当用户开启新会话时,claude-mem会把当前会话的初始信息(比如用户ID、会话主题)作为查询条件,从记忆库中检索出相关条目,然后注入到系统提示词或上下文窗口里。这里做的不是全量召回,而是top-k相关的精准匹配。检索策略的好坏,直接决定了记忆系统是"神来之笔"还是"乌烟瘴气"——如果检索不准,模型拿到一堆无关记忆,比没有记忆还糟糕。

2.3 为什么选择"外挂式"而不是"内嵌式"方案

当初我评估过几条技术路线:

  • 直接在prompt里手动拼接历史记录(低成本,但没法长期用)
  • 用LangChain的ConversationSummaryBufferMemory做摘要记忆(好用,但绑定框架,折腾起来不够灵活)
  • 自建向量库加定时任务做记忆归档(可控,但开发量大,迭代慢)
  • 用claude-mem这类外挂工具(开箱即用,且不绑定特定框架)

最终选claude-mem,核心原因就一句话:它站在API外面,不干扰我的主业务逻辑。我只需要在Claude的请求流程里插入一个中间层——发送前注入检索结果,收到回复后触发记忆提取。就像给已有的对话流程加了一个插件,而不是重新搭一套系统。这对于已经在跑生产环境的项目尤其重要,你不需要重写业务代码,只需要接入一个旁路模块。

另外一点,这类工具通常实现了MCP(Model Context Protocol)协议。MCP是Anthropic推动的一个开放标准,它定义了外部工具/数据源与Claude之间的统一接口。你不需要针对每个记忆存储方案写一堆适配代码,符合MCP标准的东西都能互相配合。这个生态价值会随着时间越来越大,我理解这一点之后果断在另外两个项目里也统一换成了MCP架构。

3. 核心细节解析与实操要点

3.1 记忆提取:规则驱动还是模型驱动?

记忆提取是整个系统的灵魂,这一环做得不好,存储和检索都白搭。我在实际使用中试过两种提取策略。

一种是最朴素的规则驱动。通过正则表达式和关键词匹配,识别出像"我叫XXX"、"我是做XXX的"、"截止时间是XXX"这类模式。好处是准确、零成本、完全可预期,坏处是覆盖面太窄——现实对话千变万化,你不可能穷举所有的信息表达方式。用户说"这周五交方案"和"咱们周五汇报,别忘了",表达方式完全不同,但含义都是"这周五有一个截止节点"。规则引擎很难把所有这种变体都识别出来。

另一种是模型辅助提取。claude-mem支持调用一个小模型(可以是Claude Haiku,也可以是本地的小型LLM)对每轮对话做二次分析,把"可能值得记录的事实"提炼成统一的JSON格式。这个方式的准确率和覆盖面远超规则,但代价是每一轮对话都会产生额外的模型调用和延迟。我在跑的过程中体会是,正常聊天场景下,每一轮多出几百毫秒到一两秒的处理时间是能接受的,但如果你的应用交互频率非常高、对延迟极其敏感,就需要考虑异步执行——把提取任务丢到后台队列里,不让它阻塞主流程。

我的建议是混合策略:简单明确的信息用正则直接命中,复杂语义的用模型兜底。实际跑下来,正则大概能覆盖60%左右的常见记忆提取场景,剩下的40%交给模型。这样既控制了成本,又保证了覆盖率。

3.2 存储字段设计与更新时间策略

claude-mem的记忆条目不只是"一段文字"。每条记忆会有几个核心字段:

  • content:记忆内容本身,比如"用户偏好使用Python写脚本"
  • entity_type:记忆的对象类型,比如user、project、task
  • entity_id:对应对象的唯一标识
  • metadata:附加信息,比如提取时间、来源消息ID
  • importance_score:重要度评分,一般在0到1之间

这个importance_score很关键。记忆库跑久了肯定会有大量低价值信息,"用户今天说了一句你好"这种东西存下来毫无意义。claude-mem会通过提取阶段给每条记忆打分,检索时权重高的优先被召回。实际跑起来,这套机制能有效避免"记忆库越大,检索越垃圾"的恶化趋势。

更新策略也值得注意。用户可能会在后续对话里推翻之前的信息,比如一开始说"我下周去北京出差",后来又说"行程取消了"。如果系统只是不断追加新记忆而不处理旧记忆,就会出现记忆冲突。claude-mem的做法是在提取到冲突信息时,对旧记忆做"过期/替换"标记,而不是物理删除。这样既保留了修改轨迹,又确保下次检索时优先给模型返回最新的事实。我在自己的调试中特意测试了这个场景,取消了行程之后,再开新会话问"用户下周有什么安排",返回的是"行程已取消",而不是两个互相矛盾的结果同时出现。

3.3 检索策略:为什么不能只做关键词匹配

刚开始我天真地以为,记忆检索嘛,SQL里like一下不就完了。实际跑起来发现完全不是这么回事。

用户第一次说"我想做一批铁艺置物架的外贸订单",数据库里记录的是["铁艺置物架", "外贸"]。下个月他来问"之前那个金属收纳架还能不能加急出货",关键词里根本没有"铁艺置物架"这几个字,但语义上是同一件事。如果用关键词推理,这条记忆就永远召不回来。

所以检索层一定要有语义能力。claude-mem支持把记忆内容向量化,也就是把文本转成一个高维向量,然后用向量相似度检索召回。用户当前会话的提问也会转成向量,然后算其他向量跟它之间的距离(一般用余弦相似度),取最接近的前几个。这套机制本质上是把"我该记住什么"从字符串匹配升级成了语义匹配。

我实际测试过一个小场景:记忆库里有三百条记录,涵盖了用户的工作信息、家庭成员、项目进度、购物偏好等。我用了个完全不同的说法问"家里小孩能吃什么零食",系统成功召回了"孩子对花生过敏"这条原始记忆。就这一个案例,就足够让我深信向量检索在这类场景里的必要性。

3.4 记忆注入:放哪里、放多少、什么时候放

记忆注入是claude-mem的出口,这一环决定模型到底有没有"用上"记忆。

有朋友可能会想,既然有记忆就全部存进prompt呗,让模型自己判断用哪些。这个想法大错特错。CLAUDE模型的上下文窗口虽然越来越大,但有效注意力是有限的。塞进20条记忆,模型可能会平均分配给每条记忆,而没有重点聚焦当前真正相关的那一两条。claude-mem的做法是,严格控制在5条以内的高相关度记忆注入,并且以一种明确的格式标注出来,比如:

用户事实档案: 1. [用户ID: U12345] 三岁孩子,对花生过敏 2. [用户ID: U12345] 偏好购买低糖零食

这样一来,模型能非常明确地知道这些是"长期记忆中的事实",而不是普通对话内容。我在实验中也对比过:注入5条高度相关记忆 vs 注入30条混合记忆,前者在后续回答中的准确率明显更好,而且回答风格更稳定。所以记忆注入的核心原则是:少而精。

4. 实操过程:从零接入claude-mem

4.1 环境准备与安装

我的运行环境是macOS + Python 3.11,项目本身是Node.js服务,两端用HTTP通信。claude-mem的安装很简单,如果你用的是Python生态,直接通过pip安装即可:

pip install claude-mem

如果你用的是Node.js项目,也可以通过npx或者npm直接调用它提供的MCP服务。我这里以Python方式演示,因为它的自定义能力更强,方便我做二次开发。

安装完成后,第一步是初始化配置文件。claude-mem会生成一个默认配置,我习惯在自己的项目目录里放一份,单独维护:

claude-mem init --config-dir ./config

生成的配置文件基本长这样:

storage: provider: sqlite path: ./memory_store/mem.db vector_index: true vector_model: text-embedding-3-small extraction: strategy: hybrid extraction_model: claude-3-5-haiku rules_enabled: true max_new_facts_per_turn: 5 retrieval: max_memories: 5 min_relevance_score: 0.35 include_metadata: true server: port: 8765

这里边的每个参数我都实际调试过,挑几个重点说说。

storage.provider我用的sqlite,因为单机场景够用了。如果你做的是高并发的线上服务,可以考虑换成PostgreSQL或专门的向量数据库。vector_index: true意味着开启向量索引,对应需要配置vector_model。我用的是OpenAI的text-embedding-3-small,向量维度小、速度快、中文语义效果也不错。你也可以换成其他Embedding模型,只要能输出稳定的向量就行。

extraction.strategy: hybrid就是前面说的混合策略,正则加模型双重保障。max_new_facts_per_turn我设为5,这个值很关键——如果设得太高,一轮对话可能会提取出一堆低价值记忆;设得太低,又会漏掉重要信息。我压测过几组数值,5在大多数场景下平衡得最好。

retrieval.max_memories设为5,配合min_relevance_score为0.35做相关度阈值。这里有个坑:相关度阈值如果设太高(比如0.7),会导致很多有用的记忆被过滤掉;设太低(比如0.1),又会召回一堆没用的。0.35是我跑了近千条测试对话后调出来的经验值,在不同场景可能不同,建议你自己用小批量数据先测一轮。

4.2 接入Claude对话流程

安装配置完成后,接入工作主要分两步:对话前检索记忆,对话后提取记忆。

第一步,在发起Claude请求之前,先调用claude-mem的检索接口:

import requests memory_server = "http://localhost:8765" def get_relevant_memories(user_id, current_query): resp = requests.post( f"{memory_server}/retrieve", json={ "entity_id": user_id, "query": current_query, "max_memories": 5 } ) return resp.json()["memories"]

拿到记忆后,需要把它们拼装进发送给Claude的消息里。我的做法是塞在system prompt的最前面,和其他系统指令分开,单独用一块区域标注:

def build_system_prompt(base_prompt, memories): if memories: memory_text = "\n".join( [f"- {m['content']} (时间: {m['created_at']})" for m in memories] ) base_prompt = f""" 以下是该用户的历史长期记忆,如果与当前对话相关请参考,不相关请忽略: {memory_text} {base_prompt} """ return base_prompt

这段代码的核心逻辑是"相关才参考,不相关就忽略",给模型明确的指令弹性,而不是逼迫它每条都要用上。

第二步,在收到Claude的回复之后,把整轮对话发送给记忆提取接口:

def extract_memories(user_id, conversation_turn): resp = requests.post( f"{memory_server}/extract", json={ "entity_id": user_id, "conversation_turn": conversation_turn } ) return resp.json()

这个调用可以同步做,但在高并发场景下我强烈建议放到消息队列里异步执行。我用过最简单的方式是把它丢到一个后台任务队列,主线程不等待结果。因为提取接口哪怕是调用Haiku,也要上百毫秒,同步等待会影响用户的回复速度。

4.3 完整接入示例

下面是我实际项目里的一个最小可运行示例,串起了整个流程:

import requests from openai import OpenAI MEMORY_SERVER = "http://localhost:8765" client = OpenAI( api_key="your-api-key", base_url="https://api.anthropic.com" # 根据你的实际API端点调整 ) USER_ID = "user_001" def chat_with_memory(user_message): # 1. 检索记忆 memories = requests.post( f"{MEMORY_SERVER}/retrieve", json={"entity_id": USER_ID, "query": user_message} ).json()["memories"] # 2. 组装prompt memory_context = "" if memories: memory_lines = "\n".join([f"- {m['content']}" for m in memories]) memory_context = f"长期记忆:\n{memory_lines}\n\n" messages = [ {"role": "system", "content": memory_context + "你是我的AI助手。"}, {"role": "user", "content": user_message} ] # 3. 调用Claude response = client.chat.completions.create( model="claude-3-5-sonnet", messages=messages ) assistant_message = response.choices[0].message.content # 4. 提取新记忆(异步推荐) requests.post( f"{MEMORY_SERVER}/extract", json={ "entity_id": USER_ID, "conversation_turn": { "user": user_message, "assistant": assistant_message } } ) return assistant_message # 测试对话 print(chat_with_memory("你好,我想了解一下适合三岁小孩的低糖零食")) print(chat_with_memory("有什么品牌可以推荐吗?")) # 第二句会带出"花生过敏"记忆

注意,这里我用的是OpenAI SDK兼容模式调Claude API。Anthropic官方也提供了自己的SDK,就看你的项目本身用的是哪套协议栈。核心逻辑一样,都是"检索记忆 → 拼装prompt → 调用模型 → 提取记忆"。

4.4 命令行模式:快速体验效果

如果你只是想先看看效果,不想写代码,claude-mem还自带了一个交互式命令行模式:

claude-mem chat --user-id test_user

进去以后可以像和Claude聊天一样对话,但它背后会实时维护记忆。退出再进来,你会发现它还记得之前的对话内容。我第一次跑这个模式时,故意在第一轮说了"我最近在研究瓷器修复",退出重进后问"我之前在研究什么",它准确给出了答案。那一刻我意识到,这套记忆方案确实可行。

4.5 引入MCP协议接入Claude官方生态

py

如果你用的是Claude Desktop或者Claude Code这类官方工具,claude-mem还支持通过MCP协议直接接入。MCP的设计理念是"给Claude一双能摸到外部世界的手",memory server就是其中典型的一类。

接入方式不复杂,在Claude的MCP配置里加一个server项,指向claude-mem的MCP端点。之后Claude应用就能原生地调用记忆工具的读、写、检索能力,不需要自己写HTTP调用了。我试过在Claude Code里接入之后,整个CLI工具就具备了跨会话记忆能力——昨天用命令行交代过的事情,今天再问它,它还记得。这个体验对于频繁使用命令行工具的人来说,相当于给自己的AI助手装了"长期硬盘"。

5. 常见问题与排查技巧实录

5.1 问题速查表

自己在接入和运行claude-mem的过程中,踩过不少坑。整理成一张表,方便大家对照排查:

问题现象可能原因解决方案
新会话中模型完全不记得任何历史信息记忆检索没生效或检索结果为空检查检索接口返回;确认entity_id统一;调低min_relevance_score试试
模型回答时引用了错误的记忆记忆冲突未处理,旧记忆被覆盖前仍被召回检查冲突处理策略;为旧记忆增加过期标记
提取延迟太长,用户端等待过久同步调用了提取接口改为异步队列处理,把提取任务放到主流程之外
记忆库越来越大但检索效果变差低价值记忆太多,或没有用语义检索提高importance_score阈值,开启向量索引;定期清理低分记忆
向量检索返回结果和当前话题无关Embedding模型和场景不匹配换用更合适的中文Embedding模型,或者在检索时混用关键词和向量双重召回
多轮对话中系统重复注入同一条记忆记忆去重逻辑没生效检查存储层是否有唯一约束,或在上游对内容做hash去重
提取到明显错误的"事实"并污染记忆库模型辅助提取的准确率问题增加人工复核通道,或者调整提取模型的temperature接近0

5.2 踩坑一:记忆污染

我发现一个很典型的问题,就是对话里的反事实、假设、玩笑会被提取成"事实"存进记忆库里。比如用户说"如果我有个亿级用户量,我肯定做电商平台",这句话本质上是假设而非真实目标,但提取模型很可能把"用户目标:做电商平台"存进去。下次检索到这条记忆,Claude就会默认用户真的要做电商平台,回答方向就跑偏了。

这类问题的本质是"提取模型的判断能力有限"。我的对策是两招:

  • 把提取模型的temperature调到接近0,减少创造性输出,让模型更谨慎地判断到底什么值得提取。
  • 在提取提示词里明确加一句"只提取用户明确表达的事实或偏好,忽略假设、感叹、玩笑和情绪性表达"。

这两招配合下来,记忆污染的比例明显下降。

5.3 踩坑二:记忆过期问题

在一个项目里,用户的偏好和计划是动态变化的。上个月用户说"我主要在深圳办公",这个月他搬到上海了。如果系统不更新老记忆,模型就会把"深圳"和"上海"同时当作事实,导致回答自相矛盾。

claude-mem的冲突处理机制能做部分缓解,但我发现它并不总能自动判断"新信息取代旧信息"和"新旧信息并存"的区别。比如"用户有猫"和"用户有狗"并不冲突,但"用户住在深圳"和"用户住在上海"就是冲突的。

我的处理方式是加一层人工审核通道:凡是检测到与旧记忆有明显语义冲突的新记忆,系统不会直接入库,而是标记为"待确认"。我在自己的后台管理页面里定期review这些条目,确认后才会覆盖旧记忆。这也算是人机协同的一个典型场景——AI负责批量处理常态信息,人负责把控关键变更。

5.4 踩坑三:检索结果不准确

排查了一下午,发现根因不是检索逻辑的问题,而是聊天气氛中隐含的信息没有显式表达出来。用户第一轮只说了"帮我看看有什么零食推荐",第二轮问"孩子过敏能吃哪些"——第一轮其实没有"孩子、过敏"这两个关键词,所以没有任何记忆被召回。

这种问题的本质是:记忆系统只能召回"它当时记住了什么"。用户没有明确说出口的信息,提取器再聪明也变不出来。解决思路是把"会话目标"也纳入记忆。我在接入时增加了一个预处理步骤:每轮对话开始前,把用户当下的query向量和记忆中已有的实体进行偏好匹配,如果匹配上了,直接把对应实体信息注入。相当于在系统底层加了一个"隐性关联"层,把关键词和历史档案做模糊关联。实测下来,跨轮次联想的成功率提升了不少。

5.5 踩坑四:多用户隔离没做好

如果你的应用是多人同时使用的,千万别把所有人的记忆混在一起。我第一版没注意这一点,测试时两个测试账号的记忆互相干扰,结果A用户的历史消息出现在B用户的检索结果里。

claude-mem本身支持entity_id级别的隔离,但前提是你每次检索和提取都传对user_id。麻烦的是,有些场景下用户身份是要通过token解析才能拿到的,中间层如果传错了上下文变量,就会张冠李戴。我的建议是封装一个统一的记忆模块,所有入口都强制校验entity_id,绝对不能依赖调用方自觉传对。

6. 性能调优与高级玩法

6.1 延迟优化思路

我实际压测下来,一轮对话接入claude-mem后,端到端延迟的增量主要在三个环节:

环节耗时优化策略
记忆检索(含向量化)100~300ms用缓存减少重复查询;向量索引加上HNSW或IVF索引
Prompt拼接<5ms优化字符串操作,几乎无瓶颈
记忆提取200~800ms异步执行,彻底移出主链路

关键优化点是把记忆提取彻底异步化。我用的方式是引入Redis队列,对话结束后把turn数据推入队列,由worker异步消费、提取并写入存储。主链路只保留检索环节的耗时,实测从用户发出请求到收到回复的额外延迟控制在150ms以内,可以接受。

6.2 多项目多场景的隔离玩法

claude-mem的记忆并不局限于单用户维度。它的entity_type不只是user,还可以是project、team甚至document。我有一次把它用在了知识库场景,entity_id传的是文档ID,记忆内容是对文档的摘要和理解,然后让Claude基于这些"文档记忆"来回答问题。效果出奇地好,因为摘要把文档里的关键点结构化提出来了,模型回答时避免了"大海捞针"式的全文检索。

你完全可以给每个项目建一套记忆空间,用project_id隔离,甚至混合使用多种entity_type。比如电商客服场景,一个用户进来,既能检索到用户画像记忆(entity_type=user),也能检索到订单上下文记忆(entity_type=order),还可以检索到该商品的知识库记忆(entity_type=product)。多维度记忆叠加,会让AI助手的回答质量明显上一个台阶。

6.3 数据可视化:记忆管理后台

跑了一段时间后,你需要一个地方来审视整个记忆库的健康度。我给自己搭了一个极简的管理后台,就是读SQLite里的记忆表,展示出来:

  • 记忆总量、各entity_id的分布
  • 最近7天新增记忆数量
  • 高分记忆(importance_score > 0.8)列表
  • 待确认的冲突记忆

这个后台不用很复杂,一张表格加几个筛选条件就够了。但它能帮你发现很多隐患——比如某个用户突然产生大量低质量记忆,或者某个实体类型的记忆增长速度异常。提前发现,提前处理,总比记忆库彻底烂掉再重建要好。

7. 最后聊几句我的个人体会

claude-mem这个项目最大的价值点不在"记忆"本身,而在于它提出了一套清晰的分层思路——提取什么、怎么存、怎么取。很多类似工具要么只做存储搜索,要么就是把历史记录全堆给模型,都缺少"该记什么"这一层判断。而这恰恰是长期记忆系统能真正落地、不是沦为玩具的关键。

根据我个人的经验,如果你的AI应用已经在生产环境跑着了,想快速给Claude加记忆能力,claude-mem是个非常稳妥的入手点——它不改变你现有的业务逻辑,只是在你和模型之间加了一层"档案管理员"。先跑一两周,把检索效果、提取准确率调到满意了,再逐步扩展场景,比如接入多维度记忆、增加人工审核通道、或者把后端存储替换成更适合线上部署的方案。

最后再分享一个小技巧:记忆系统上线初期一定要人工审核高频用户的前几十条记忆。这个阶段是校准提取策略的最佳时机,等观察清楚了规律,再把审核放宽。别一上来就全自动放养,在记忆这类反向影响模型输出的环节上,初期的人工介入能帮你避免后面大量的返工。