
最近在参与一个政务智能客服系统的开发这个项目挺有意思的也遇到了不少政务场景下特有的挑战。今天就来和大家分享一下我们基于AI辅助开发的实战经验特别是架构设计和性能优化方面的一些心得。政务场景的客服系统和普通的电商客服很不一样。首先政策文件更新非常频繁可能今天刚上线的问答明天因为新规发布就失效了。其次咨询量在特定时段比如新政策发布后会呈现爆发式增长对系统的并发能力是巨大考验。最后用户可能使用各种方言进行咨询这对语音识别和自然语言理解都提出了更高要求。这些痛点决定了我们的技术方案不能是简单的“拿来主义”。在技术选型上我们重点对比了模型服务化的方案。政务系统通常对稳定性和可控性要求极高。TensorFlow Serving生态成熟支持热更新模型监控完善。但其资源占用相对较高在国产化CPU环境如鲲鹏、飞腾上的优化程度有时不如X86平台且对于需要快速响应、轻量级部署的场景显得有些“重”。ONNX Runtime优势在于跨框架和性能。它支持将PyTorch、TensorFlow等框架训练的模型统一转换成ONNX格式进行推理在CPU尤其是通过Intel MKL-DNN或ARM Compute Library优化后上往往能获得更优的推理速度。对于需要适配多种国产硬件环境的政务项目ONNX Runtime的跨平台特性是一个加分项。考虑到我们后续可能面临国产化适配和极致性能的需求最终选择了BERT模型 ONNX Runtime推理 FastAPI提供HTTP服务的混合架构。下面聊聊核心实现。核心实现拆解整个系统可以分成几个关键模块我们逐一来看。政策问答核心基于BERT-wwm的语义匹配政策问答不能靠简单的关键词匹配必须理解意图。我们选用BERT-wwm-ext全词掩码中文预训练模型因为它对中文实体和词组的理解更好。流程是将用户问题和一个政策知识库由许多政策条款Q-A对组成同时输入模型计算问题与每个知识库条目的语义相似度取最相关的TOP N条作为候选答案再经过一个轻量级的规则校验层比如检查时效性输出最终答案。这里的关键是将庞大的政策知识库预先向量化并建立索引比如用FAISS避免实时计算海量相似度。高并发基石FastAPI异步接口与批处理为了应对高并发咨询我们用FastAPI搭建服务。它的异步支持async/await和非阻塞I/O特性非常适合IO密集型的AI服务。我们设计了异步批处理接口将短时间内收到的多个用户请求聚合成一个批次一次性送入模型进行推理极大地提升了GPU/CPU的利用率和整体吞吐量。合规生命线基于AC自动机的敏感词过滤政务回复必须严谨合规。我们实现了一个基于AC自动机Aho-Corasick算法的敏感词过滤模块。AC自动机的优势在于无论敏感词库多大它都能在O(n)的时间复杂度内完成对单条文本的多模式匹配速度极快。我们将政策法规中明令禁止的表述、涉密词汇等维护成词库所有生成或转写的文本在返回给用户前都必须经过这个过滤层一旦命中即触发审核或替换流程。代码示例与关键实现下面展示一些核心代码片段重点看服务化封装和异步批处理。首先是模型服务化的封装类我们使用ONNX Runtime进行推理import onnxruntime as ort import numpy as np from typing import List import asyncio from concurrent.futures import ThreadPoolExecutor class PolicyQAService: def __init__(self, onnx_model_path: str, vocab_path: str): 初始化政策问答服务。 :param onnx_model_path: 导出的BERT ONNX模型路径 :param vocab_path: 词表文件路径 # 创建ONNX Runtime会话优化推理配置 self.session ort.InferenceSession( onnx_model_path, providers[CPUExecutionProvider], # 政务环境常用CPU也可用CUDAProvider sess_optionsort.SessionOptions() ) self.tokenizer BertTokenizer.from_pretrained(vocab_path) self.executor ThreadPoolExecutor(max_workers4) # 用于CPU上的并行批处理 self._knowledge_vectors self._load_knowledge_base() # 预加载知识库向量 async def async_predict_batch(self, questions: List[str]) - List[str]: 异步批处理预测接口。 :param questions: 用户问题列表 :return: 答案列表 loop asyncio.get_event_loop() # 将编码和推理任务放到线程池执行避免阻塞事件循环 encoded_batch await loop.run_in_executor(self.executor, self._encode_batch, questions) # ONNX推理 inputs {self.session.get_inputs()[0].name: encoded_batch[input_ids], self.session.get_inputs()[1].name: encoded_batch][attention_mask]} outputs await loop.run_in_executor(self.executor, self.session.run, None, inputs) # 语义匹配与答案检索简化 answers await loop.run_in_executor(self.executor, self._match_and_retrieve, outputs[0]) return answers def _encode_batch(self, texts: List[str]) - dict: 批量编码文本 return self.tokenizer(texts, paddingTrue, truncationTrue, max_length128, return_tensorsnp) def _match_and_retrieve(self, question_vec: np.ndarray) - List[str]: 语义匹配与答案检索此处简化为最近邻搜索 # 实际使用中这里会对接FAISS等向量数据库进行近似最近邻搜索 # scores np.dot(question_vec, self._knowledge_vectors.T) # top_indices np.argsort(scores)[-3:] # 取最相关的3个 # return [self.knowledge_base[i][answer] for i in top_indices] return [根据相关政策规定...] * len(question_vec) # 示例返回然后是FastAPI的主应用和敏感词过滤模块的集成from fastapi import FastAPI, BackgroundTasks from pydantic import BaseModel from ac_automaton import ACAutomaton # 假设有一个AC自动机实现 app FastAPI(title政务智能客服API) # 初始化敏感词过滤机 with open(sensitive_words.txt, r, encodingutf-8) as f: sensitive_words [line.strip() for line in f if line.strip()] ac_filter ACAutomaton() for word in sensitive_words: ac_filter.add(word) ac_filter.build() class QueryRequest(BaseModel): question: str session_id: str # 用于幂等性设计和会话状态管理 app.post(/v1/policy_qa) async def policy_qa(query: QueryRequest, background_tasks: BackgroundTasks): 政策问答主接口。 1. 敏感词过滤 2. 异步调用模型服务 3. 记录日志后台任务 # 1. 输入内容敏感词检测 sensitive_hits ac_filter.search(query.question) if sensitive_hits: # 记录日志或触发告警此处直接返回提示 return {code: 403, msg: 提问内容包含敏感词汇请重新表述。} # 2. 异步调用模型服务实际项目中PolicyQAService可能以依赖注入形式引入 qa_service app.state.qa_service # 这里为了演示实际应做请求排队或批处理调度 answer (await qa_service.async_predict_batch([query.question]))[0] # 3. 将日志记录等非关键操作放入后台任务 background_tasks.add_task(log_interaction, query.session_id, query.question, answer) # 4. 对输出答案再进行一次敏感词过滤确保生成内容合规 if ac_filter.search(answer): answer 您好关于该问题的解答涉及内部管理细则建议您前往线下服务窗口咨询。 return {code: 200, data: {answer: answer, session_id: query.session_id}} def log_interaction(session_id: str, question: str, answer: str): 后台记录用户交互日志用于分析和优化 # 异步写入数据库或文件 pass性能测试与优化结果系统上线前我们进行了严格的压测。方言识别准确率我们接入了第三方方言语音转写服务并针对本地区主流方言如粤语、四川话的转写结果进行了微调。测试集显示对于带口音的普通话识别准确率从85%提升至92%对于纯方言我们通过补充特定词汇库将可理解率Intent Accuracy从70%提高到了82%。高并发性能在4核8G的云服务器上使用locust进行压测。在1000 QPS每秒查询率的压力下接口的P99延迟99%的请求响应时间控制在250毫秒以内平均响应时间在120毫秒左右满足政务高峰期的需求。这主要得益于异步批处理将多个请求的推理合并减少了模型加载和计算的重复开销。内存泄漏检测我们使用objgraph和tracemalloc在长期运行测试中监控内存。发现主要内存增长点在于缓存的政策向量和会话状态。通过为缓存设置TTL生存时间和LRU最近最少使用淘汰策略并将会话状态存储转移到外部Redis有效控制了内存的平稳增长。避坑指南这个项目踩了不少坑这里总结几个关键的政策术语向量化技巧BERT对专业术语的向量化可能不准。我们的经验是在微调BERT时将政策原文、官方解读、同义词、旧表述与新表述一起作为训练数据让模型学习到这些术语的关联性。也可以单独为术语构建一个小的Embedding表在检索时进行加权融合。会话状态管理的幂等设计用户可能因网络问题重复提交相同问题。我们为每个会话session_id和问题内容生成一个唯一请求ID如MD5在短时间内如5秒内对于相同的请求ID直接返回缓存的结果避免重复计算也保证了应答的一致性。国产化CPU适配经验在鲲鹏ARM服务器上部署时ONNX Runtime需要从源码编译开启ARM相关的优化选项如使用OpenBLAS。此外一些Python的科学计算库如NumPy也需要安装针对ARM架构优化的版本。内存对齐问题在ARM平台可能更敏感需要关注。结尾思考项目做下来一个始终萦绕的问题是如何平衡政策文本的严谨性与自然语言表达的灵活性我们的系统可以精确地匹配政策条款但用户常常用非常口语化、甚至不完整的方式提问。一味追求严谨可能导致系统变得“死板”答非所问而过度追求灵活理解又可能产生歧义甚至误导。目前我们采用“精准匹配为主意图泛化为辅”的策略并设置了人工审核通道处理置信度低的回答。未来或许需要更先进的模型能够真正理解政策精神并用更人性化的方式解释条款这不仅是技术问题也涉及到语言学和公共服务的理念。以上就是我们在政务智能客服系统开发中的一些实践。这条路还在继续探索希望这些经验对你有帮助。如果你有更好的想法或遇到过类似的挑战欢迎一起交流。