拓冰建站拓冰建站
首页 / 资讯中心 / 正文

OpenClaw数据清洗与去重实战:从预训练语料到Agent记忆库

最近和几个折腾 OpenClaw 的朋友聊下来大家关心的问题已经从最开始的“到底怎么装”慢慢过渡到了“装完之后数据从哪里来、喂进去的数据干不干净”。问得最多的一句就是模型预训练阶段使用了哪些数据清洗和去重技术我先说一个容易踩的认知偏差OpenClaw 本身并不负责大模型的预训练它更像一个智能体运行框架负责把底座模型、工具、记忆、自动化流程串起来。但这个问题不是伪命题。因为在真实使用场景里你至少有三个地方绕不开数据清洗和去重一是给本地底座模型做继续预训练或微调语料二是给 OpenClaw 沉淀长期工作记忆三是用“数据清洗 skill”把杂乱的业务数据整理成 Agent 能直接使用的结构化素材。这篇文章我从实操角度把清洗和去重的技术栈拆开讲包含可复现的代码管线也夹带了不少我实际踩过的坑。1. 先理清楚OpenClaw模型预训练前面的数据链路到底指哪段1.1 OpenClaw在模型生命周期里的实际位置如果你把“模型预训练”理解成从零开始训练 GPT 这种规模的底座模型那 OpenClaw 的定位确实不在这。OpenClaw 更多是 Agent 层软件它负责调用不同的模型、维护工作空间、保存 Active Memory、执行各类 skill也可以跟钉钉、微信等入口对接。但这不意味着预训练话题和 OpenClaw 无关。实际去配置 OpenClaw 的时候你会遇到两种真实需求第一种是只想把 OpenClaw 部署好接一个云端或本地模型就跑起来这种情况下数据清洗影响的是 Agent 的上下文质量第二种是想在 OpenClaw 基础上追加领域能力比如把企业内部文档、客服聊天记录、个人笔记整理成一套语料再对开源底座模型做一次增量预训练或微调。第二种需求一旦出现经典的数据清洗和去重方法就全部用上了。另外很多人容易忽略 OpenClaw 自带的长期记忆机制。它的活跃记忆和 workspace 文件不是随便往里塞文本就能用的塞进去的数据如果有大量重复、噪音、隐私信息Agent 在检索时就会频繁被无关内容干扰表现出的症状就是“记忆混乱”或“答非所问”。这个问题和数据清洗的关系比很多教程里写的都要大。1.2 真正需要你动手做清洗和去重的三个场景我在实际操作中总结下来只要是下面三种情况清洗和去重都不能省。第一类是继续预训练语料。比如你想让本地模型更懂你所在行业的术语找了一批论文、技术文档、工单记录这一步的目标是把这些原始文档变成“干净、不重复、信息密度高”的纯文本语料。第二类是微调指令数据。你可能要根据 OpenClaw 实际执行任务的日志整理成指令对比如“用户输入了什么Agent 应该输出什么动作”。这类数据如果不去重同一条指令反复出现模型会过度拟合这些样本评估时看着 Loss 很低一上线就露馅。第三类是记忆和知识库数据。OpenClaw 的 Active Memory 长期工作记忆本质上有类似向量检索的过程。原始聊天记录如果不做清洗里面混杂的错别字、格式符号、无关闲聊都会干扰检索结果。没有经过隐私清洗的聊天记录还有泄露风险这块很多教程压根不提但非常重要。1.3 一个容易被忽略的事实Agent阅读数据和训练数据的清洗标准并不完全一样给模型训练用的数据清洗追求的是去掉“噪声但保留信息冗余”给 Agent 检索用的数据清洗追求的是“高信噪比 强结构化”。举个例子训练语料里一句重复出现的“欢迎来到本频道”可能是自然表达不需要强行删除但如果你要把聊天记录塞进 Agent 记忆库“欢迎来到本频道”这类高频客套话会反复命中检索词那就是纯噪声。所以后面讲的技术我都尽量分成两条线来理解一种是模型预训练视角的清洗另一种是 OpenClaw 情景下的数据整理。两条线共用不少底层技术只是阈值和调用阶段不同。明白这一点你再看那些零散的 OpenClaw 配置教程就不会被绕晕。2. 数据清洗的核心技术不只是去HTML标签还要去语言噪音和隐私风险2.1 第一层字符编码与HTML残渣清理数据清洗最基础也最容易翻车的是字符层。很多爬虫抓回来的网页文本看着是中文字符其实里面混着大量HTML实体、CSS残留、控制字符、零宽空格甚至因为数据库编码不对出现“锟斤拷”这类乱码。这种数据直接喂给分词器一部分 Token 会被无效字符浪费掉严重时还可能导致特殊字符把样本切得稀碎。正规操作里处理顺序一般是先统一编码为 UTF-8再用工具修复 mojibake接着剥掉 HTML 标签最后清理控制字符和不可见字符。我习惯第一个步骤先做编码规范化Python 里最简单的是 unicodedata.normalize。有人觉得这步可有可无实际遇到全角半角混用、中文标点被输入法改成英文标点的情况时你就知道这步有多重要了。HTML 标签清理可以分两种如果数据源只是网页正文用 BeautifulSoup 提取 text 就够了如果做大规模清洗建议用html2text或自定义规则因为 BS4 在大规模处理时内存开销偏高。下面是一个常见的中文清洗函数import re import unicodedata def clean_text(raw: str) - str: # 1. 统一 Unicode繁体/简体后续再做这里先把兼容字符拆干净 text unicodedata.normalize(NFKC, raw) # 2. 去除 HTML 标签 text re.sub(r[^], , text) # 3. 移除控制字符和零宽字符 text re.sub(r[\x00-\x08\x0b\x0c\x0e-\x1f\u200b-\u200f\u202a-\u202e], , text) # 4. 合并连续空白与换行 text re.sub(r[ \t], , text) text re.sub(r\n{3,}, \n\n, text) # 5. 清理全角空格 text text.replace(\u3000, ) return text.strip()2.2 第二层语种识别与质量信号过滤清洗到字符层之后下一步是语种识别。假如你的目标是高质量中文预训练数据却混进去百分之十五的英文、日文、俄文页面tokenizer 的效率会明显下降。中文混英文在一些技术文档里还算有用但中文混俄文基本就是污染。语种识别我推荐 fastText 的 lid.176 模型它体积小、速度快单机跑百万级文档也没什么压力。用法很简单import fasttext model fasttext.load_model(lid.176.bin) def filter_by_lang(text: str, target_lang: str zh) - bool: labels, scores model.predict(text.replace(\n, ), k1) lang labels[0].replace(__label__, ) score scores[0] # 置信度太低的时候宁可先丢掉避免误删 return lang target_lang and score 0.7注意一个细节fastText 的语种置信度不能完全代表内容质量有时候标题是中文、正文是乱码模型也会给个较高的中文置信度。所以语种过滤之后还应该加一层质量信号打分。质量信号过滤通常包括几种规则统计感叹号密度、全大写字符比例、重复 n-gram 占比、文本长度是否过短、是否包含大量广告链接。这些规则不需要很复杂但能拦住很大一部分“看起来是正常文本、实际上不能训练”的垃圾数据。我常用两个朴素指标有效内容占比。去除非中文字符后剩余汉字数量除以总长度低于某个阈值比如 0.5就判定为低质内容。困惑度。用语言模型算文本困惑度异常低的一般是重复套话异常高的一般是语序错乱或者命名实体堆砌。中小项目不需要每次都训一个模型来打 perplexity可以先用规则代替。这部分没有银弹。多数团队在清洗阶段用的是“规则为主、模型为辅”而不是反着来。2.3 第三层隐私PII清洗避免Agent把别人的密钥当知识学进去隐私清洗在博客和教程里经常被一笔带过但放到 Agent 场景里必须专门说。OpenClaw 的记忆系统在工作时可能会读取聊天记录、邮件、CSV、Markdown 等文件。如果这些文件里直接包含手机号、身份证号、邮箱、密钥那么这些信息不但可能被当作普通文本进入上下文还可能被写入长期记忆甚至被 skill 自动拼到后续输出里。我自己试过让一个 Agent 整理客服聊天记录如果不做脱敏它真的会把对方的手机号和住址连带输出到总结里这个风险不小。处理逻辑很简单正则和替换就能覆盖大部分场景import re pii_patterns { phone: r(?!\d)1[3-9]\d{9}(?!\d), email: r[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}, id_card: r\d{17}[\dXx], ip: r\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b, } def mask_pii(text: str) - str: text re.sub(pii_patterns[phone], [PHONE], text) text re.sub(pii_patterns[email], [EMAIL], text) text re.sub(pii_patterns[id_card], [ID_CARD], text) text re.sub(pii_patterns[ip], [IP], text) return text注意正则的边界。如果手机号正则没加前后断言会把一段数字中的 11 位误伤掉。IP 正则同样要谨慎它会把版本号或者普通小数误判成 IP在文本中埋下隐患。实际使用时我会先跑一遍只做统计的代码看看正则在样本集上的命中分布再决定要不要落地。密钥检测比较特殊比如 sk- 开头的 API Key、AWS Access Key、OpenAI 的 key建议单独做一个字典匹配不要只用正则。因为密钥往往不长正则很容易漏。一个比较简单的方式是把sk-[a-zA-Z0-9]这类特征拿出来模板匹配到以后只保留前四位后面全部替换成[REDACTED]。3. 去重不是只看一眼是否一样精度和成本的把控3.1 精确重复先清掉URL和SHA1哈希的应用去重策略里成本最低的是精确去重。URL 去重适合抓取阶段比如同一个文章网址被重复抓回来直接保留一份。全文本精确去重适合处理格式统一的数据比如 API 返回的 JSON 字段、系统导出的 CSV。精确去重一般用 MD5 或 SHA1。MD5 比较快但有一定碰撞风险在大规模去重场景建议用 SHA1。尽管 SHA1 也被学术界讨论过碰撞可能但面对普通语料去重足够。代码非常直接import hashlib def sha1_hex(text: str) - str: return hashlib.sha1(text.encode(utf-8)).hexdigest() seen set() unique_docs [] for doc in all_docs: h sha1_hex(doc[content]) if h not in seen: seen.add(h) unique_docs.append(doc)但精确去重解决不了“同一篇文章被不同网站稍微改写后再发”的问题。任何人只要改两个字哈希就会完全不同。所以业界真正花力气的是近似去重。3.2 MinHash原理给文本办指纹卡并近似求交集近似去重里被广泛使用的算法是 MinHash。它的核心思路是把一篇文章拆成若干个 shingle也就是连续的 n 个词或字符然后用多个随机哈希函数找到集合的最小值依次生成一个固定长度的签名。这个签名近似等于原始集合的 Jaccard 相似度。Jaccard 相似度可以通俗理解成“两个文档共有的 shingle 数除以两个文档全部 shingle 数”。如果两篇文章的共同片段很多去重的时候就应该考虑删除。那为什么不直接两两比较因为语料规模到百万级以后两两比较是 O(n²) 级别在工程上完全不现实。MinHash 配合 LSH 可以让复杂度降到近似线性。LSH 的思路是把签名再分成多个 band如果两个文档在任何一个 band 里的签名段完全一致就把它们放进同一个候选桶里只对候选桶内的文档做精确比较。给不懂算法的朋友打个比方相当于你给每篇文章做了一张指纹卡指纹被分成几个区块你不需要把所有指纹卡全部比对一遍只需要看相同区块里有没有相同卡片的“编号”有的话再拿出来逐张核对。这样既能发现在超大规模语料里的相似文本又不会把机器跑死。3.3 实际操作中单机去重怎么提效单机处理几百万行文本时我推荐用 datasketch 库里的 MinHashLSH。它封装了大部分细节代码量很小。from datasketch import MinHashLSH, MinHash import jieba def tokenize_zh(text: str): # 这里不要去掉停用词预训练语料去停用词会丢失信息 return list(jieba.cut(text)) def build_minhash(text: str, num_perm: int 128): mh MinHash(num_permnum_perm) for token in tokenize_zh(text): mh.update(token.encode(utf-8)) return mh lsh MinHashLSH(threshold0.8, num_perm128) for idx, doc in enumerate(docs): mh build_minhash(doc[content]) # 先查重再插入 for candidate in lsh.query(mh): if jaccard_compare(candidate, idx) 0.8: print(f发现近似重复: {idx} 与 {candidate}) lsh.insert(idx, mh)这里有两个关键参数threshold是相似度的判定阈值num_perm是哈希函数的条数也决定了 MinHash 签名的长度。一般来说 num_perm128 适合中等规模256 精度更高但内存和时间都会涨。threshold0.8的意思是只有当两个文档相似度估计超过 0.8 才认为重复这个数值比较适合文章类文本。细节很重要MinHash 处理中文前到底要不要分词我试过两种做法。分词的算力开销大但在处理长文档时对语义命中更友好直接按字符切 n-gram 的好处是不需要引入分词误差且对于拼写改写更鲁棒。如果数据里中文和英文混合可以同时把英文按空格切、中文按字符切这样能减少分词器引入的偏差。3.4 大规模语料的分布式去重方向当数据规模到了几十亿条datasketch 单机版就比较吃力这时候要往分布式方向走。一种方案是用 Spark 实现 MinHashLSH。Spark MLlib 自带 MinHashLSH 和 BucketedRandomProjectionLSH。先将数据转成 DataFrame然后用MinHashLSH做桶内自连接。这个方案适合数据已经存在 HDFS 或 S3 的场景。另一种常见做法是 SimHash 配合海明距离。和 MinHash 不同SimHash 的签名对每一个特征做加权向量累加后取符号最终生成一串固定长度的位序列。比较两个文档是否重复时只需要计算两个签名的汉明距离。它的优势是存储紧凑、比较非常快适合超大规模粗筛。在知名开源数据处理方案里类似思路也被实现成 D4 这类模糊去重工具。核心还是先 SimHash 指纹化再对指纹做局部敏感哈希桶。要是你的语料量级还没到“几千台机器跑几个小时”的程度我非常不建议一上来就上 Spark 全家桶先把单机 MinHash 跑通再评估瓶颈到底在 IO 还是算力避免过度设计。4. 从脏语料到干净文件一条端到端参考管线的落地过程4.1 实验场景与配置参数我实验时的场景是准备把一批科技博客 HTML 文件整理成中文继续预训练语料目标是在本地一张消费级显卡上做增量预训练。原始数据大约 5 万个 HTML 文件解压后约 3.2GB。多数文件为中文夹杂少量英文技术名词。处理设备的配置不算高16GB 内存6 核 CPU。这个规模不需要分布式用单机 Python 跑完整个流程大概需要 30 到 50 分钟。流程主要分五个阶段读取 HTML 并提取正文统一字符编码、清理格式噪声语种过滤与质量信号过滤去掉隐私和密钥MinHash 相似去重并输出 jsonl每个阶段的中间结果我都会单独落盘一次。这样如果后面发现某批次清洗规则的参数太激进不需要从头跑只回退到对应阶段就行。清理干净后数据还剩大约 1.6GB这里大头是去重阶段减少了约三成。4.2 在OpenClaw工作空间内跑通的标准脚本上面这种流程完全可以在 OpenClaw 工作车间里跑通。关键点在于不要把清洗脚本当成一次性命令行而要把它当作一个 skill让 Agent 之后可以按需调用。我给出的完整脚本如下你可以直接复制到一个 Python 文件里import os import re import unicodedata from pathlib import Path import pandas as pd import fasttext from bs4 import BeautifulSoup from datasketch import MinHash, MinHashLSH # 配置 INPUT_DIR Path(./raw_html) OUTPUT_DIR Path(./clean_zh_output) OUTPUT_DIR.mkdir(exist_okTrue) lang_model fasttext.load_model(lid.176.bin) # ---------- 第1步: HTML 转纯文本 ---------- def html_to_text(file_path: Path) - str: with open(file_path, r, encodingutf-8, errorsignore) as f: soup BeautifulSoup(f.read(), html.parser) for tag in soup([script, style, nav, footer, aside]): tag.decompose() return soup.get_text(\n) # ---------- 第2步: 字符层清洗 ---------- def clean_text(raw: str) - str: text unicodedata.normalize(NFKC, raw) text re.sub(r[ \t], , text) text re.sub(r\n{3,}, \n\n, text) text text.replace(\u3000, ) text re.sub(r[\x00-\x08\x0b\x0c\x0e-\x1f\u200b-\u200f], , text) # 去掉纯符号行 lines [line.strip() for line in text.splitlines() if line.strip()] return \n.join(lines) # ---------- 第3步: 语言与长度过滤 ---------- def is_zh_and_quality(text: str) - bool: if len(text) 200: return False labels, scores lang_model.predict(text.replace(\n, ), k1) if labels[0] ! __label__zh or scores[0] 0.8: return False zh_chars len(re.findall(r[\u4e00-\u9fff], text)) total_chars len(text) return (zh_chars / total_chars) 0.5 # ---------- 第4步: 一个极简脱敏规则 ---------- def mask_pii(text: str) - str: text re.sub(r(?!\d)1[3-9]\d{9}(?!\d), [PHONE], text) text re.sub(r[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}, [EMAIL], text) text re.sub(rsk-[a-zA-Z0-9]{16,}, [API_KEY], text) return text # ---------- 主流程 ---------- texts [] for file_path in INPUT_DIR.glob(*.html): raw html_to_text(file_path) cleaned clean_text(raw) if not is_zh_and_quality(cleaned): continue cleaned mask_pii(cleaned) texts.append({file: file_path.name, content: cleaned}) print(f清洗后剩余 {len(texts)} 条) # ---------- 第5步: MinHash 去重 ---------- lsh MinHashLSH(threshold0.8, num_perm128) mhs {} for idx, rec in enumerate(texts): mh MinHash(num_perm128) for token in list(rec[content]): # 字符级 shingle mh.update(token.encode(utf-8)) mhs[idx] mh duplicate_flags set() for idx, mh in mhs.items(): if idx in duplicate_flags: continue for cand in lsh.query(mh): if cand idx or cand in duplicate_flags: continue # 大概率相似即可判重实际可以用真实 jaccard 二次确认 duplicate_flags.add(cand) print(f重复: {texts[idx][file]} 与 {texts[cand][file]}) lsh.insert(idx, mh) clean_data [ rec for i, rec in enumerate(texts) if i not in duplicate_flags ] # ---------- 输出 ---------- df pd.DataFrame(clean_data) df.to_json(OUTPUT_DIR / clean_zh.jsonl, orientrecords, linesTrue, force_asciiFalse) print(f最终保留 {len(clean_data)} 条输出至 {OUTPUT_DIR / clean_zh.jsonl})几点提醒第 5 步为了简化演示用了字符级 shingle也就是按汉字逐字切。字符级切分不会引入分词误差也更容易命中改写重复代价是签名计算时输入片段的语义边界不清晰。对要求更高的长文本场景建议先分词再 shingle。threshold0.8不是固定的科技博客类内容如果重复率很高可以调到 0.85 以上减少误杀。脚本里输出了 “真实 jaccard 二次确认”实际生产级最好多做一步把候选对重新放到正则化后的文本里计算一次精确相似度避免同一模板、不同正文的文章被误判为重复。4.3 接入OpenClaw技能和维护工作流的注意点如果你只是手动跑一次 Python 脚本那没必要把 OpenClaw 拖进来。但如果你想把它沉淀成每次数据更新都自动执行的流程就要考虑做成 skill。OpenClaw 的一大特点是通过 skill 扩展 Agent 能力。部署时经常遇到.openclaw目录下有一堆文件里面有skills目录只要你把一个满足规范的新技能文件夹放进去Agent 就能在下一个会话里识别到。清洗数据的 skill 可以这样设计输入一个文件夹路径自动执行 HTML 清洗、语种过滤、PII 脱敏、去重最后输出结构化向量库需要的 jsonl同时在结尾给出本次清洗的统计摘要比如丢弃了多少条、重复了多少条、输出文件位置。我自己在实际接入时踩过一个小坑OpenClaw 对可执行脚本有审批机制exec-approvals.json 会把允许执行的命令写进白名单。第一次调用清洗脚本时Agent 通常需要请求审批如果脚本改了路径或者改了执行参数审批位置会变化容易导致“skill 没反应”。这不是 skill 写错了而是执行权限没配置好。遇到这类问题去查看执行审批文件里记录的路径把可信的脚本路径加入白名单即可。另外如果输出文件比较大建议不要直接写到主工作日志目录而是放一个独立的数据目录并在 skill 描述里写明“仅读取/输出指定文件夹”。这样既能避免 OpenClaw 每次启动后无谓地扫描大文件也能降低误操作概率。5. 踩坑实录与参数调整经验5.1 相似度阈值选错会出现什么问题去重阈值的取舍非常容易走极端。阈值设得太低比如 0.5很多正常文章会因为引用了相同标准话术、都包含技术名词列表而被误判为重复损失大量有效数据。阈值设得太高比如 0.95那么“几乎只改几个字的重写文章”会被漏掉。这个区间的重复往往是最伤模型训练的它不会让模型完全学到错误内容但会放大某一类句式和表达造成同义重复的过拟合。我测试过不同阈值对一个小型中文语料的影响0.7 时去重率约 38%但人工抽查发现有接近 15% 的内容被误杀0.85 时去重率约 24%误杀率降到 3% 以内。所以我更倾向在文章类长文本中把阈值设置在 0.8 到 0.85 之间。如果处理的是商品标题、短信模板这类短文本阈值整体要调低因为短文本本身信息量少相似度容易被高估。5.2 Shingle长度、num_perm和中文的分词纠缠很多人第一次写 MinHash 时拿英文教程直接套中文看到效果不好就怀疑算法。其实问题往往出在分词策略上。英文是天然按空格切词所以直接用词级 shingle 没问题。中文如果不分词一整个句子可能只有两三个 Token信息量完全不够。先用 jieba 做粗分词再生成 shingle效果通常会好不少但代价是清洗脚本会慢一些而且如果 jieba 词典不包含领域术语会把一些正确的专业词切成碎片反而让相似文本看起来差异变大。如果你做的是“科技博客去重”这一类通用内容我的建议是先分词再取 3 到 5 个词作为一个 shingle。如果你做的是代码片段、命令日志这种偏符号化的数据那直接用字符级 shingle 更稳。混合型数据可以拆成两条管线分别处理不要在一个函数里两头兼顾。num_perm 这个参数容易被随手填成 32 或 64。在小数据上区别不大但在几十万条样本上num_perm 太低会造成 LSH 分桶时碰撞概率下降重复文档被漏检。至少在百万级以内的语料我都建议用 128。如果你发现输出结果里很多重复对没被查出来先不要怀疑算法有病先提高 num_perm再重新跑。5.3 三个真实踩坑故事第一个坑是正则脱敏误伤 URL。我当时把邮箱正则直接放到全文里跑结果把mailto:userexample.com这类链接里的邮箱替换成[EMAIL]后URL 前缀mailto:残留下来又是一层新的脏数据。后面改用“先抓出完整 URL 占位符再对剩余文本脱敏”的顺序问题才消失。第二个坑是 MinHash 查询出来的候选对很多但人工比对后发现它们只是共享了页头和页脚。某些技术博客有个固定的免责声明和作者介绍占全文比例不小。MinHash 只看 shingle 重合度不关心这些 shingle 是不是正文。解决办法是清洗阶段先把页头页脚和声明文字剥掉或者对相似文本对再做一次“去除公共首尾模板后再计算相似度”的二次确认。第三个坑和 OpenClaw 的 workspace 有关。我的清洗脚本一开始直接输出到/root/.openclaw/workspace目录结果 Agent 每次启动都把生成的几千万级临时文件当成上下文扫描对象导致任务执行卡顿。后来我把所有中间产物放到workspace/clean_jobs/子目录并通过 skill 描述文件告诉 Agent 不要自动读取整个目录只在需要时读取输出目录的 jsonl性能问题立刻缓解。6. 复制粘贴前先看的快查表6.1 常见问题原因与排查方向我把实际操作里比较高频的问题整理成了下面的速查表方便你在现场排查。现象大概率原因排查方向清洗后文本大量消失语种识别误删短文本或 HTML 正文提取失败抽样检查被过滤文本确认是空文本还是误删去重率异常高minhash threshold 太低或页头页脚模板未被剥离提高 threshold先做模板片段清洗minhash 漏掉明显重复num_perm 太小或分词粒度不合理将 num_perm 提高到 128 以上换分词策略中文文档被判为英文fastText 模型对简繁体混合文本识别不稳先用规则把汉字的比例算出来强设中文条件Agent 执行清洗 skill 没反应执行审批白名单未覆盖新脚本路径到 exec 审批配置文件里检查路径授权记忆库检索结果混乱塞入的数据未做 PII 脱敏或未去重重新跑清洗再重建记忆索引输出文件被 OpenClaw 自动扫描卡顿中间产物放在 workspace 根目录改到独立子目录并在 skill 描述里声明这个表里最后两条在 OpenClaw 场景下尤其容易被忽略。很多人只顾着把数据文件放进工作空间却忘了 Agent 的上下文扫描机制会对文件做索引。数据一多就会拖慢会话。这也是我坚持在 OpenClaw 内部把“数据清洗”做成独立 skill、而不是简单丢到任意目录的原因。6.2 一些值得提前留意的信号如果你的数据不是爬虫抓的而是自己积累的工作文档清洗思路要做一点调整。工作文档更常见的问题是模板套话和表格内容比如“请查收附件”“谢谢配合”这类句子会大量重复出现在不同文档里。这类数据从“文本相似度”角度看不一定是重复文档但放到训练数据里就会成为明显的模板噪声。建议先按文档类型分类每类单独做一次高频短句统计把 top 高频客套语去掉或转成带变量占位符的形式。清洗和去重做得好不好不能只看最终 Loss 曲线也要人工看样本。我每次跑完整条管线后都会随机抽 20 条清理后的数据放出来一眼扫过去。不要求每一条都完美但如果有明显乱码、明显重复、明显偏题就先别急着进入预训练环节把管线参数再调一轮。OpenClaw 相关的项目也一样。部署完成后不要急着让它干重活先丢一批规模不大但包含重复、脱敏、格式错乱的数据进去观察它在记忆检索和上下文调用上的表现。数据管线跑得顺不顺往往直接决定那些记忆类能力是真的可用还是只能成为演示 Demo。我自己现在的一个做法是把清洗脚本、脱敏规则、去重阈值全部参数化成配置文件放进 OpenClaw 的 workspace每次换场景只改配置文件不碰代码。这样即使 Agent 版本升级、工作目录变化我只需要把 skills 里的执行路径重新授权一次整套数据准备流程可以继续复用。最后一个真正受用的技巧所有清洗规则在上线前先拿一万条样本跑一遍并输出中间样本再决定阈值而不是把网上推荐的数值直接套到自己的数据上。数据场景千差万别能救你的不是某个万能参数而是一套可以快速回退、方便人工抽查的清洗流程。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门