Install
openclaw skills install @po-et/reduce-ai-toneopenclaw skills install @po-et/reduce-ai-tone定位一句话:AI 味多半不出在某个词上,出在文字里没有具体的人、具体的事、具体的判断。 删套话只是第一步,还要换上作者自己的细节和立场,读者才会觉得是一个人在跟他说话。
何时用:一段中文读起来空、顺、平,像在哪儿都见过;用户说「AI味太重」「去AI腔」「改得像我写的」。本技能管写作质量。如果目的是让作业或投稿躲过学校、期刊、单位对 AI 使用的规定,不接,理由见最后一节。
动笔前先弄清四件事,答不上来就问用户,别猜:
检查点:能用一句话说出「写给谁、读完要他做什么、作者平时怎么说话」,再往下走。
判断标准只有两条:删掉它,意思少没少;换一个题目,它还成不成立。 意思没少、换题照样成立,就是套话。清单里的词不是禁词,全文用一次「总之」没问题,问题在密度和空转。示例里「后」的细节都假定来自作者本人,实际改写时没有素材就写【待补:……】,不许编。
开始前先和用户定改写强度。轻:只删套话、拆冒号标题,结构和措辞基本不动,适合正式文件和已定稿的材料。中:再加上换细节、调句长,段落顺序不动,多数情况用这一档。重:按作者口吻重写,可以调结构,只在作者给了足够素材时做。
向作者要细节的五个问题:
1 这件事最近一次发生是什么时候?当时具体是什么情形?
2 能给一个数吗?多少人、多长时间、多少钱、比以前多了多少?
3 有没有谁说过的原话,或者一个你记得很清楚的场景?
4 如果只能选一边,你站哪边?为什么?
5 读者读完这段,你希望他做什么?
整段示例,属于「重」档。作者提供了自己的情况(三个月没读完书、通勤四十分钟、试过飞行模式),所以能改成第一人称的叙述。两段分别存成 draft.txt 和 revised.txt,可以拿来试脚本。
改写前(draft.txt):
在当今信息爆炸的时代,阅读习惯正在发生深刻的变化。随着短视频的普及,越来越多的人习惯了碎片化的信息获取方式。值得注意的是,这种变化既带来了机遇,也带来了挑战。
一方面,碎片化阅读让知识获取更加便捷、高效、灵活;另一方面,它也在一定程度上削弱了人们深度思考的能力。研究表明,长期碎片化阅读会导致注意力下降。
**核心观点:** 阅读不是一种消遣,而是一种能力。我们要以更开放的心态、更坚定的信念、更务实的行动,重建深度阅读的习惯。
总而言之,深度阅读至关重要。让我们携手并进,共同开创全民阅读的美好未来!
改写后(revised.txt):
我已经三个月没读完一本书了。每天通勤有四十分钟,全刷了短视频。
上周想重读一本以前很喜欢的小说,翻了二十页就去看手机,前后看了六次。我开始怀疑自己是不是读不进长东西了。
后来试了个笨办法:上地铁就把手机调成飞行模式,只带纸书。第一天读了八页,第四天读了三十多页。
能坚持多久我不知道。但这周,我读完了一本。
只用 python3 标准库。统计六类套话的命中次数和每千字密度、句长分布(平均、中位、变异系数、相邻两句长度接近的比例)、破折号、冒号小标题、顿号三连和排比候选。它量的是表面信号,不是 AI 检测器:人写的文字也可能命中很多,数字低也证明不了任何事。提示里的阈值(变异系数低于 0.35、破折号每千字超过 3 处、冒号小标题 3 行以上)是经验值,只供参考。词表按自己的领域增删,PATTERNS 里一类一行,写的是正则。
# 保存为 ai_tone_check.py;只用标准库。统计的是表面信号,不是「AI 检测器」
import re
import statistics
import sys
PATTERNS = {
"空泛开头": r"在当今[^,。]{0,8}|随着[^,。]{1,15}的(?:发展|普及|进步|到来)|在[^,。]{1,15}的(?:大)?背景下|众所周知",
"过渡套话": r"值得注意的是|需要指出的是|不难看出|由此可见|与此同时|事实上|首先|其次|此外",
"总结升华": r"总而言之|总的来说|综上所述|总之|让我们|携手|共同(?:开创|创造|书写|迎接)|未来可期|美好未来",
"无源引用": r"研究(?:表明|显示|发现)|数据(?:表明|显示)|专家(?:指出|认为)|有调查显示",
"空洞大词": r"赋能|抓手|闭环|打造|全方位|多维度|深度融合|至关重要|不可或缺|举足轻重",
"对举保险": r"不是[^。!?]{1,20}而是|不仅[^。!?]{1,20}(?:而且|更|还)|在一定程度上|某种意义上|一方面",
}
# 冒号小标题:加粗标签、列表项标签、行首 6 字以内的标签
HEAD = (r"(?m)^\s*(?:[-*+]\s+)?\*\*[^*\n]{1,12}(?:[::]\*\*|\*\*[::])"
r"|^\s*(?:[-*+]|\d+[.、])\s*[^\s::,。*]{1,8}[::]|^[^\s::,。*#]{1,6}[::]")
def main():
text = open(sys.argv[1], encoding="utf-8").read() if len(sys.argv) > 1 else sys.stdin.read()
size = len(re.sub(r"\s", "", text))
per_k = lambda n: n * 1000 / max(size, 1)
print(f"正文 {size} 字(不含空白)\n\n[套话] 次数 每千字 命中")
found = False
for name, pat in PATTERNS.items():
hits = re.findall(pat, text)
if hits:
detail = "、".join(f"{h}×{hits.count(h)}" for h in dict.fromkeys(hits))
print(f" {name} {len(hits):>4} {per_k(len(hits)):>6.1f} {detail[:50]}")
found = True
if not found:
print(" (无)")
sents = [s for s in (re.sub(r"\s", "", x) for x in re.split(r"[。!?!?;;…\n]+", text)) if len(s) >= 2]
lens = [len(s) for s in sents]
cv = 0.0
if len(lens) >= 2:
mean = statistics.mean(lens)
cv = statistics.pstdev(lens) / mean
near = sum(abs(a - b) <= 3 for a, b in zip(lens, lens[1:])) / (len(lens) - 1)
print(f"\n[句长] {len(lens)} 句 平均 {mean:.1f} 中位 {statistics.median(lens):.0f} "
f"最短 {min(lens)} 最长 {max(lens)} 变异系数 {cv:.2f} 相邻两句长度差≤3字 {near:.0%}")
for lo, hi in ((1, 10), (11, 20), (21, 30), (31, 45), (46, 999)):
n = sum(lo <= x <= hi for x in lens)
print(f" {lo:>2}-{hi if hi < 999 else '':<3}字 {'█' * n} {n}")
dash = text.count("——")
heads = len(re.findall(HEAD, text))
stacks = re.findall(r"(?:[^\s,。、;:!?]{1,4}、){2,}[^\s,。、;:!?]{1,4}", text)
print(f"\n[其他] 破折号 {dash} 处({per_k(dash):.1f}/千字) 冒号小标题 {heads} 行 "
f"加粗 {text.count('**') // 2} 处 顿号三连 {len(stacks)} 处 {' / '.join(stacks[:3])}".rstrip())
rows = []
for s in re.split(r"[。!?!?\n]+", text):
parts = [p.strip() for p in re.split(r"[,、;,;]", s) if p.strip()]
for a, b, c in zip(parts, parts[1:], parts[2:]):
if len(b) == len(c) >= 3 and any(x == y == z for x, y, z in zip(a[-len(b):], b, c)):
rows.append(f"{a},{b},{c}")
break
if rows:
print("\n[排比候选](三个并列小句,逐条人工判断)")
for r in rows[:5]:
print(" ·", r)
tips = []
if len(lens) >= 5 and cv < 0.35:
tips.append("句长偏整齐:拆一两个长句,把几个短句并成一句")
if per_k(dash) > 3:
tips.append("破折号偏多:多数可以换成逗号或句号")
if heads >= 3:
tips.append("冒号小标题多:想想哪些可以写成完整句子")
if tips:
print("\n[提示](经验阈值,只供参考)\n " + "\n ".join(tips))
if __name__ == "__main__":
main()
python3 ai_tone_check.py draft.txt
python3 ai_tone_check.py revised.txt
本机实测上面两段:改写前套话 14 处(空泛开头 2、过渡 1、总结升华 5、无源引用 1、大词 1、对举保险 4),10 句,变异系数 0.22,另有排比候选 1 条、顿号三连 1 处;改写后套话 0 处,8 句,变异系数 0.44。按行断开的诗歌、歌词、对话记录不适合看句长统计。