Langchain-Chatchat 如何构建高效敏感词过滤机制

在企业级 AI 应用日益普及的今天,智能问答系统正逐步渗透到内部知识管理、客户服务和办公自动化等核心场景。Langchain-Chatchat 作为一款支持本地部署、私有文档解析与检索的开源问答框架,凭借其“数据不出内网”的安全特性,成为许多对隐私要求严苛的企业首选方案。

但问题也随之而来:大语言模型(LLM)本身是开放生成式的,一旦知识库中包含敏感信息,或用户提出诱导性问题,系统就可能输出不当内容——比如泄露内部制度细节、生成违规操作指引,甚至被恶意利用传播有害信息。这类风险在金融、政务、医疗等行业尤为致命。

因此,仅靠模型自身的安全对齐能力远远不够。我们需要一道更可控、更确定的防线:本地化的敏感词过滤机制


与其依赖云端 API 的内容审核,不如把控制权牢牢掌握在自己手中。在 Langchain-Chatchat 中集成一套高效的敏感词过滤模块,不仅能实现毫秒级响应,还能完全避免数据外传,真正达成“安全”与“可用”的平衡。

这套机制的核心,并不是简单地做一次 text.replace("密码", "****"),而是一个贯穿对话流程、具备高精度识别能力和灵活策略响应的系统设计。

首先,得选对技术底座。关键词匹配看似简单,但在千条万条敏感词面前,传统遍历查找的方式会严重拖慢响应速度。这时候,Aho-Corasick 自动机就成了关键。

它是一种多模式字符串匹配算法,能够在一次扫描中同时检测多个关键词,时间复杂度接近 O(n),非常适合中文环境下大规模词库的实时过滤场景。Python 生态中有 ahocorasick 这个库,封装良好,性能出色,正是我们构建过滤引擎的理想选择。

import ahocorasick

class SensitiveWordFilter:
    def __init__(self, word_list):
        self.ac_tree = ahocorasick.Automaton()
        for word in word_list:
            self.ac_tree.add_word(word, (word, "SENSITIVE"))
        self.ac_tree.make_automaton()

    def contains_sensitive(self, text):
        for _ in self.ac_tree.iter(text):
            return True
        return False

    def mask_sensitive_words(self, text, mask_char="*"):
        words_found = []
        for item in self.ac_tree.iter(text):
            end_index = item[0] + 1
            start_index = end_index - len(item[1][0])
            words_found.append((start_index, end_index, item[1][0]))

        words_found.sort(reverse=True)
        for start, end, word in words_found:
            masked = mask_char * len(word)
            text = text[:start] + masked + text[end:]
        return text

上面这段代码虽然简洁,却承载了整个过滤系统的骨架。初始化时构建自动机,之后每次调用都无需重复加载词表,适合高并发环境下的长期运行。contains_sensitive 可用于快速拦截,mask_sensitive_words 则能实现脱敏返回,两种策略可根据使用场景自由切换。

更重要的是,这个组件可以轻松接入外部配置。你可以将敏感词存入 JSON 文件、数据库表,甚至是通过 REST 接口动态拉取,配合热更新机制,做到“改完即生效”,无需重启服务。

那么,它该放在整个系统流程的哪个位置?

最合理的做法是在两个关键节点布防:

  • 输入层过滤:用户刚提交问题,立刻进行审查。如果发现诸如“如何删除日志”“怎样绕过权限”之类的表述,直接阻断后续处理,节省资源的同时也防止恶意试探。
  • 输出层过滤:这是最后一道闸门。即使模型因为训练偏差或提示词漏洞生成了不该说的话,比如提及“管理员账号”“测试用密钥”等内容,也能在返回前端前被识别并替换。

整个流程就像这样:

[用户提问]
     ↓
→ 输入过滤 → 拦截/清洗
     ↓
→ 知识检索 + 回答生成
     ↓
→ 输出过滤 → 脱敏/拒绝
     ↓
[安全回复]

双层防护的设计理念源于“纵深防御”思想——不把希望寄托于单一环节的完美表现,而是通过多重校验提升整体鲁棒性。哪怕某一层漏判,还有下一层兜底。

举个实际例子:假设有人问“有没有办法看到别人的人事档案?”这个问题本身没有明显敏感词,但如果知识库里恰好有关于权限配置的说明,模型可能会给出“可通过 admin 角色查看”的回答。此时,“admin”未必在敏感词列表中,但“人事档案”如果是受控词汇,就能触发输出过滤,及时阻止潜在的信息泄露。

当然,也不能走向另一个极端:过度过滤导致正常交流受阻。比如“通过审批流程”被误判为包含“通缉”,或者“会议记录”因含有“记录”二字而被拦截。这类误伤会影响用户体验,甚至让系统变得不可用。

为此,有几个实用建议值得参考:

  • 分级管理:将敏感词分为“警告级”和“禁止级”。前者仅记录日志供审计,后者才真正拦截。例如“离职流程”可归为普通关注,“薪酬结构”则列为高危。
  • 白名单机制:允许某些上下文中的敏感词豁免。比如“测试密码”出现在技术文档中是合理的,但单独出现就需警惕。
  • 支持模糊匹配:中文里常有用星号隔开绕过检测的情况,如“密*码”“机 密”。可以通过预处理去除空格、标点,或引入正则规则增强识别能力。
  • 结合轻量 NLP 模型:对于谐音、缩写、变体表达(如“V我50”“DB”代指数据库),单纯关键词难以覆盖。可叠加一个小型文本分类器做辅助判断,形成“规则+模型”的双重保障。

从工程实践角度看,还有一个容易被忽视的点:性能优化。如果你的敏感词库超过 5000 条,每次请求都重新构建自动机,系统很快就会卡住。正确的做法是将 SensitiveWordFilter 实例化为全局单例,在应用启动时一次性加载,后续所有请求共享同一个匹配引擎。

同时,记得开启日志监控。每一次命中敏感词的请求,都应该记录 IP 地址、时间戳、原始内容和处理动作。这些数据不仅有助于事后追溯,还能帮助你持续优化词库——哪些词总被误触?哪些攻击模式频繁出现?都是宝贵的安全情报。

最后要强调的是,敏感词过滤不是万能的。它擅长处理显性的、字面意义上的违规内容,但对于语义层面的隐喻、讽刺、诱导推理等问题仍力有未逮。但它胜在确定性强、成本低、可控性高,特别适合作为企业内部系统的首道防线。

未来,随着对抗手段升级,我们或许需要引入更复杂的语义分析、行为序列建模乃至用户画像来识别潜在风险。但在当下,一个设计得当的本地敏感词过滤系统,仍然是 Langchain-Chatchat 类项目中最务实、最高效的内容安全解决方案。

当你在会议室向领导汇报“我们的 AI 助手已通过安全合规评审”时,背后支撑这份底气的,往往就是这样一个默默运行、精准拦截的过滤模块。它不炫技,却至关重要;它不动声色,却守护着整个系统的底线。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐