如果你关注过公共服务类系统的数字化改造,会发现一个正在发生的趋势:许多医疗预约、税务申报、社会福利申领系统,正在从传统的“表单 + 工作流”模式,慢慢变成“对话式问答 + AI 自动决策”模式。技术圈把这件事概括为一句话:AI 正在“打破”旧有的公共服务系统结构。我不打算从政治或体制角度去讨论这个标题,真正值得技术人关注的是工程层面的变化——当一个需要审计、稳定、可回滚的公共系统开始接入大模型和 Agent 之后,哪些旧架构假设失效了,哪些工程手段必须补上。
看到这个标题,我的第一反应是:AI 对公共服务系统的冲击,瓶颈并不在模型能力,而在传统软件工程范式跟不上。过去做政务或公共服务系统,强调流程固定、权限清晰、操作留痕;现在做 AI Agent 系统,模型输出有概率性,工具调用有不确定性,连“用户想问的问题到底是什么意图”都可能需要模型自己判断。两套思路碰撞时,最危险的不是算法效果不够好,而是边界没有想清楚就匆匆上线。
这篇文章从四个层面展开。先讲公共服务系统接入 AI 真正会遇到哪些卡点,再讲 AI Agent、RAG 和传统系统之间的关系;然后给出一套最小可运行的原型代码,覆盖问答服务、权限校验、审计日志和幻觉缓解;最后讲清楚验证方法、常见问题和最佳实践。读完你会明白,AI 改造公共服务系统这件事,难的不是选模型,而是怎么用工程手段,把“不确定的模型”装进“确定性要求极高的系统”里。
1. 公共服务系统接入 AI,真正的卡点在哪
很多人以为,公共服务系统接入 AI 的最大难点是模型能力不足。比如问答不准确、理解不细致、多轮对话容易跑偏。但从实际工程视角看,这些属于可以迭代的问题,真正让人头疼的是下面四个卡点。
第一个卡点是历史数据孤岛。公共服务系统往往由多个时期建设的子系统组成,有上世纪遗留的关系型数据库,有新上的微服务,还有大量Excel、PDF甚至纸质扫描件。AI 问答要给出准确答案,必须先做数据盘点、清洗、分级和向量化。这个过程通常要占整个项目 60% 以上的工作量,而不是像 demo 里那样,给模型接一个知识库就完事。
第二个卡点是权限边界与审计要求。公共系统涉及公民隐私和机构数据,必须做到“谁在什么条件下能看什么数据”。传统系统的权限模型是写死在接口里的,而 AI 问答是一个自然语言入口,用户不会每次都告诉你“我是哪个科室、要查哪类数据”。如果检索环节不做权限过滤,一个普通市民的提问,可能让模型从私有知识库里检索出内部政策依据。这个风险比模型答错别字严重得多。
第三个卡点是模型幻觉与决策责任。公共服务场景对准确性的要求远高于普通客服机器人。一个社保问答系统如果给出了错误的申请条件,用户可能白跑一趟;如果一个辅助审批的 Agent 给出错误建议并被人采纳,责任归属就会成为大问题。技术人必须接受一个现实:大模型给出的答案只是“候选内容”,不是“最终结论”。系统设计上必须留出人审、抽查和纠正路径。
第四个卡点是灰度发布与回滚机制。传统系统发版很明确:代码上线,验证新功能,出问题就回滚到上个版本。AI 系统的不确定性在于,模型本身是概率输出,同一套 Prompt 换一个模型版本,回答风格和正确率都会变化。更麻烦的是,RAG 里的知识库会持续更新,数据变化可能导致同样的问题给出不同答案。没有评估集、没有 A/B 对比、没有快速回滚能力,AI 系统一旦上线,出了问题很难定位是模型问题、数据问题还是 Prompt 问题。
所以,公共服务系统 AI 化的本质,不是“用大模型替代旧系统”,而是把 AI 能力嵌入一个已经存在了几十年的复杂系统。真正被“打破”的,是传统软件“输入确定、逻辑确定、输出确定”的确定性假设。
2. 核心概念与架构认知
在写代码之前,有必要把几个关键概念说清楚。因为公共服务类系统的开发者,很多人对微服务、事务、权限模型很熟,但对 Agent 和 RAG 的认知还停留在“会聊天的机器人”阶段。
2.1 AI Agent:从“回答一句话”到“完成一个任务”
AI Agent 可以理解为具备“任务拆解—工具调用—结果汇总”能力的大模型应用。它不只是生成一段回答,还会判断需要调用哪个接口、查哪张表、做哪一步操作。比如用户说“我想申请残疾人护理补贴”,Agent 可能要拆成“确认申请资格—列出材料清单—查找就近受理点—生成申请指引”几个步骤,每一步都可能调用不同的后端服务。
但在公共服务系统里,Agent 不能拥有过大的操作权限。它更适合做“信息检索、材料整理、流程引导”,而不是直接修改核心业务数据。把 Agent 定位成“有大脑的读多写少网关”,会比“让 Agent 自动办事”安全得多。
2.2 RAG:让模型既能回答问题,又能回答准确问题
RAG,即检索增强生成。核心思路是:不直接让大模型凭记忆回答,而是先从知识库检索出与用户问题相关的文档片段,再把“参考资料 + 用户问题”一起交给大模型生成答案。这么做有三个好处:一是答案可以溯源;二是知识可以随时更新;三是可以按用户权限控制检索范围,从而降低越权风险。
公共服务领域的知识库有一个特点:政策文本经常更新,不同层级的规则存在差异。如果只靠模型微调,每次政策变化都要重新训练,成本高且不及时。RAG 则可以在知识库文档更新后立刻影响回答结果,这也是它在公共系统中更受青睐的原因。
2.3 传统公共系统架构与 AI 架构的差异
传统公共系统一般是“界面 + 服务接口 + 数据库”的固定结构。用户录入表单,后端校验合法性,数据库执行事务,系统把结果写回并记录日志。这套架构成熟、安全、可审计,但不适合处理开放式自然语言问题。
AI 系统的典型链路是“用户输入 → 意图识别 → 权限校验 → 向量检索 → Prompt 拼装 → 模型生成 → 内容审核 → 结果返回”。这条链路多出了检索、生成、审核三个环节,任何一个环节出错,都会影响最终答案。
| 维度 | 传统公共服务系统 | 引入 AI 后的系统 |
|---|---|---|
| 输入 | 结构化表单 | 自然语言 + 表单 |
| 输出 | 固定结果 | 概率性文本 |
| 数据访问 | 接口写死权限 | 检索阶段动态过滤 |
| 故障排查 | 日志 + 堆栈 | 需要追踪检索、Prompt、模型响应 |
| 安全边界 | 数据库权限 | 检索范围 + 内容过滤 + 人审兜底 |
| 上线方式 | 版本发布 | 模型灰度 + Prompt 灰度 + 知识库灰度 |
把这张表理解透,你会发现 AI 公共系统并不是推倒重来,而是在传统系统前面加了一层“智能问答与决策辅助层”。传统系统仍然是事实来源和事务中枢,AI 层负责理解和生成。这个架构边界一旦明确,很多技术选型就清晰了。
3. 环境准备与前置条件
本文的示例代码以 Python 和 FastAPI 为主,适合快速搭建原型。虽然生产环境可能是 Java 技术栈,但核心设计和排查思路是通用的。下面列出最小环境要求,版本请以实际项目为准,这里重点演示工程思路。
3.1 基础运行环境
- 操作系统:Linux 或 macOS,Windows 建议使用 WSL。
- Python 3.9 及以上版本,需要支持
list[str]类型写法。 - FastAPI 和 Uvicorn,用于提供 HTTP 接口。
- PyYAML,用于加载 Prompt 模板配置。
- requests,用于调用模型网关接口。
- 向量数据库,用于知识库检索。生产环境常用 pgvector、Milvus、Elasticsearch 等,原型阶段用内存列表也可以。
3.2 目录结构规划
public-service-ai/ ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI 入口,注册中间件 │ ├── security.py # 权限校验与 Token 验证 │ ├── service.py # 问答主流程:检索 + 拼装 Prompt + 调用模型 │ ├── vector.py # 向量检索桩实现 │ └── llm.py # 模型调用桩实现 ├── config/ │ └── prompts.yaml # Prompt 模板配置 ├── requirements.txt └── docker-compose.yml这种分层思路适合公共服务类系统:接口层只负责接收请求和返回结果,安全层负责校验身份,服务层负责编排,检索和模型调用各自隔离。后续替换向量库或模型网关,不需要改接口层代码。
3.3 requirements.txt
fastapi uvicorn pyyaml requests原型阶段不要为了炫技引入太多重量级依赖。公共服务系统最大的敌人是依赖冲突和不可复现,依赖越少,问题越容易排查。
4. 核心流程拆解
从需求到上线,一个公共服务 AI 问答系统通常要走过六步。每一步都可以独立验证,避免把所有风险积压到最后。
4.1 需求冻结与场景裁剪
首先明确系统要回答哪些问题。不要一开始就追求“什么都能问”,而是圈定 20 到 50 个高频业务问题,比如申请条件、材料清单、办理时限、常见拒件原因。把这些问题的标准答案写成问答对,作为后续测试集的基础。没有测试集,AI 系统上线后基本无法判断改得好不好。
4.2 数据盘点与知识库构建
整理与这些高频问题相关的政策文档、办事指南、内部口径。每份文档需要标注来源、生效日期、适用范围。然后按业务域拆分片段,写入向量库。这个阶段最容易踩的坑是“把没有脱敏的内部文件直接向量化”,会在权限层面埋雷。
4.3 权限模型设计
在写业务代码之前,先定义数据分级。比如“公开政策”“登录用户可见”“内部处理口径”三级。向量检索时,必须根据用户身份传入允许访问的数据域,而不是让模型自行判断。检索阶段过滤权限,要比生成之后再审核更可靠。
4.4 Prompt 模板管理
Prompt 不要写在业务代码里,而是放在独立的配置文件中。这样产品、运营、业务专家可以直接调整模板,不需要改代码重新发版。同时给 Prompt 加上版本号,方便对比不同版本的效果。
4.5 接口与审计
所有 AI 问答接口都应该经过统一身份认证,并记录完整审计日志。日志至少要包含:用户标识、问题内容、检索到的文档来源、Prompt 版本、模型版本、生成结果、响应耗时。这样一旦出现争议,可以完整还原“用户问了什么、系统查了什么、模型答了什么”。
4.6 灰度发布
上线时先开放白名单用户,配置比例从 5% 慢慢提升到 100%。每次更新知识库或模型版本,先用离线测试集跑一遍准确率,再放到线上小流量观察。如果发现问题,可以快速关闭 AI 入口,回退到传统人工问答通道。
5. 最小原型代码实现
下面用 FastAPI 实现一个最小可运行的公共服务问答系统。这套代码包含了接口入口、权限校验、审计中间件、检索与生成流程,以及 Prompt 模板管理。代码只是工程骨架,不依赖具体向量库和模型厂商。
5.1 FastAPI 主入口
# app/main.py import time import uuid from fastapi import FastAPI, Request, HTTPException, Depends from pydantic import BaseModel from app.security import authorize from app.service import retrieve_and_generate app = FastAPI(title="Public Service Q&A Agent") class Question(BaseModel): question: str session_id: str class Answer(BaseModel): answer: str sources: list[str] request_id: str @app.middleware("http") async def audit_middleware(request: Request, call_next): start = time.time() response = await call_next(request) elapsed_ms = int((time.time() - start) * 1000) # 生产环境应写入独立审计库或消息队列 print({ "type": "AUDIT_LOG", "path": request.url.path, "method": request.method, "user": request.headers.get("X-User-Id", "anonymous"), "status": response.status_code, "elapsed_ms": elapsed_ms, }) return response @app.post("/api/v1/ask", response_model=Answer) def ask(question: Question, user: dict = Depends(authorize)): request_id = str(uuid.uuid4()) try: answer, sources = retrieve_and_generate(question.question, user["user_id"]) return Answer(answer=answer, sources=sources, request_id=request_id) except Exception: raise HTTPException(status_code=500, detail="service error")这里的审计中间件是全局的,它会记录每一次请求的用户、路径、状态和耗时。生产中应该把这段 JSON 写入独立的审计存储或消息队列,不能只打印到控制台。
5.2 权限校验与 Token 生成
# app/security.py import hashlib import hmac import os from fastapi import Header, HTTPException # 实际项目中应从配置中心读取密钥,并接入统一身份认证服务 API_SECRET = os.getenv("API_SECRET", "change-me") def validate_token(user_id: str, token: str) -> bool: expected = hmac.new( API_SECRET.encode("utf-8"), user_id.encode("utf-8"), hashlib.sha256, ).hexdigest() return hmac.compare_digest(expected, token) def authorize( x_user_id: str = Header(...), x_user_token: str = Header(...), ): if not validate_token(x_user_id, x_user_token): raise HTTPException(status_code=401, detail="unauthorized") return {"user_id": x_user_id}这个示例用 HMAC 模拟 token 校验。真实项目必须使用统一认证平台,并加入 token 有效期、刷新机制和用户角色。HMAC 只用于解释“每一个 AI 请求都要校验身份”这个工程原则。
5.3 问答服务主流程
# app/service.py import os import yaml from app.llm import call_llm from app.vector import vector_search _PROMPT_CACHE = None def _load_prompts(): global _PROMPT_CACHE if _PROMPT_CACHE is None: with open(os.path.join(os.path.dirname(__file__), "..", "config", "prompts.yaml"), "r", encoding="utf-8") as f: _PROMPT_CACHE = yaml.safe_load(f) return _PROMPT_CACHE def build_prompt(question: str, docs: list[dict]) -> str: prompts = _load_prompts() template = prompts["rag_question"]["template"] context = "\n---\n".join( f"文档{doc['source']}: {doc['content']}" for doc in docs ) return template.format(question=question, context=context) def retrieve_and_generate(question: str, user_id: str): docs = vector_search(question, top_k=3, allowed_domains=_get_domains(user_id)) prompt = build_prompt(question, docs) answer = call_llm(prompt) sources = [doc["source"] for doc in docs] return answer, sources def _get_domains(user_id: str) -> list[str]: # 真实系统应从权限中心获取用户可访问的数据域 return ["policy_public", "personal_service"]这里有一个容易被忽略的设计:_get_domains决定了用户能检索哪些数据域。即使前端隐藏了入口,只要接口允许传用户 ID,就必须在服务端重新计算权限,而不是信任前端传来的角色字段。
5.4 向量检索与模型调用桩
# app/vector.py def vector_search(query: str, top_k: int, allowed_domains: list[str]) -> list[dict]: # 实际项目:连接向量数据库,构造权限过滤条件后做相似度检索 return [ { "source": "policy_public_001", "content": "根据相关政策,申请残疾人护理补贴需要身份证、居住证和残疾证明。" }, { "source": "policy_public_002", "content": "低保家庭申请流程需先在社区服务站提交材料,审核周期通常为15个工作日。" }, ] def call_llm(prompt: str) -> str: # 实际项目:调用统一模型网关,网关负责限流、内容安全和模型路由 return ( "根据资料,申请残疾人护理补贴目前需要身份证、居住证和残疾证明。" "具体材料以当地窗口要求为准。" )这个桩实现的意义是让整个链路先跑通。你可以先不接真实的向量库和模型服务,用固定返回验证权限、审计和接口流程,然后再替换为真实实现。
5.5 Prompt 模板配置
# config/prompts.yaml rag_question: template: | 你是一个公共服务问答助手。请严格基于以下资料回答问题。 如果资料中没有相关答案,请直接回答“资料库中暂未收录,请联系人工窗口咨询”。 不要编造政策条款,不要使用资料库之外的信息。 用户问题: {question} 可参考资料: {context} 要求: 1. 只能引用资料中的内容。 2. 回答结束后,列出引用的资料编号。这份 Prompt 的关键不是“回答得多好”,而是“回答错了怎么办”。它明确要求模型在资料不充分时放弃回答,并给出兜底话术。公共服务场景里,承认不知道比乱编一个答案安全得多。
5.6 生成测试 Token 的命令
pip install fastapi uvicorn pyyaml requests export API_SECRET='change-me' python -c "import hmac,hashlib,os; secret=os.getenv('API_SECRET','change-me'); uid='user_123'; print(hmac.new(secret.encode(), uid.encode(), hashlib.sha256).hexdigest())" uvicorn app.main:app --host 0.0.0.0 --port 8080生成 Token 后,用下面的 curl 请求验证接口:
curl -X POST http://localhost:8080/api/v1/ask \ -H "Content-Type: application/json" \ -H "X-User-Id: user_123" \ -H "X-User-Token: <上一步生成的token>" \ -d '{"question": "残疾人护理补贴的申请条件是什么?", "session_id": "s_001"}'如果 Token 错误,接口会返回 401;如果正确,会返回带有答案、来源和请求 ID 的 JSON。这里最重要的验证点是:当用户身份变化时,服务端重新计算数据域并影响检索结果,而不是让用户自己决定能看什么。
6. 运行结果与效果验证
启动服务后,先不要急着接真实模型。建议按下面的顺序验证系统是否健康。
6.1 权限验证
用一个错误的 Token 请求接口,预期返回如下:
{ "detail": "unauthorized" }这一步确认没有 Token 就无法访问 AI 接口。公共系统最怕“接口公开,数据裸奔”,权限校验是第一道防线。
6.2 正常问答验证
用正确的 Token 请求,预期返回类似:
{ "answer": "根据资料,申请残疾人护理补贴目前需要身份证、居住证和残疾证明。具体材料以当地窗口要求为准。", "sources": [ "policy_public_001" ], "request_id": "xx-xx-xx" }需要确认两点:一是答案是否严格来自 source 列表中的文档;二是 request_id 是否与审计日志中的请求 ID 对应。这样后续追责才能有据可查。
6.3 幻觉回归测试
准备一组“知识库中没有答案”的问题,比如一个虚构政策名。预期模型回答“资料库中暂未收录,请联系人工窗口咨询”,而不是编造一个政策条文。如果模型开始自由发挥,说明 Prompt 约束失效,需要调整模板或增加内容审核。
6.4 可观测性验证
观察控制台输出的审计日志是否包含完整字段。真实项目还应该接入链路追踪和指标监控,重点指标包括:检索耗时、模型生成耗时、单次问答总耗时、来源命中率、拒答率。这些指标决定了你能否在用户投诉前发现问题。
6.5 失败时先看哪里
如果接口 500 报错,优先检查四个位置:一是权限模块是否异常导致用户身份拿不到;二是向量检索是否超时;三是模型网关是否限流;四是审计日志是否因为写入失败阻塞了主流程。公共服务系统里,审计链路故障宁可降级也不要影响业务接口。
7. 常见问题与排查思路
下面这些问题是公共服务 AI 项目中常见的高频故障,按表格整理,方便实际操作时快速定位。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 用户能看到其他辖区政策 | 检索阶段未按区域过滤 | 查看审计日志中的检索条件 | 在向量检索参数中加入区域权限过滤 |
| 模型回答中出现编造条款 | 知识库未覆盖该问题,Prompt约束不足 | 跑幻觉回归测试集 | 强化拒答指令,增加兜底话术 |
| 同一问题不同用户答案不同且都正确 | 权限不同导致检索范围不同 | 对比两个用户的数据域 | 属正常现象,但需在 UI 提示“按您的权限展示” |
| 接口响应越来越慢 | 检索或模型调用无超时控制 | 查看监控指标中的分位耗时 | 为检索和模型调用设置独立超时,启用缓存 |
| 更新知识库后答案变差 | 新文档清洗不完整,片段拆分不合理 | 对比新旧版本测试集准确率 | 上线前跑回归测试,做到可回滚 |
| Audit 日志缺失 | 审计写入异常被吞掉 | 检查消息队列或数据库写入失败率 | 引入降级策略,确保审计不阻塞主流程 |
| 模型被诱导输出内部口径 | 方法人审与内容安全检测 | 用红队问题集进行安全测试 | 增加内容安全网关,关键场景转为人工审核 |
这些问题的共同点,是不能只靠改模型解决。它们发生在数据、权限、流程和运维层,必须用工程手段处理。
8. 最佳实践与工程建议
如果要把这套原型做成生产级公共服务系统,下面几条建议值得提前考虑。
8.1 数据分级是 AI 权限的第一道锁
在知识库构建阶段就完成数据分级,比事后补救便宜得多。公开政策、登录用户可见、内部处理口径,必须分库或者打上清晰标签。向量检索时,把用户的数据域作为硬过滤条件,而不是把过滤希望寄托在模型理解上。
8.2 模型是易变的,Prompt 是易变的,接口必须是稳定的
公共服务系统会被大量第三方系统集成。对外接口的参数和返回结构一旦确定,就不要随模型升级而变。内部可以同时存在多个 Prompt 版本和模型版本,通过路由策略灰度切换,但接口契约要保持稳定。这样每次模型升级都只是内部实现变化,不会牵动整个外部系统改造。
8.3 所有答案必须可追溯
每个 AI 答案都应该携带 request_id、模型版本、Prompt 版本、检索来源列表。用户投诉时,运营人员能通过 request_id 还原完整现场。没有追溯能力的 AI 系统,不适合用于公共服务。
8.4 明确人工兜底边界
AI 只能做辅助,不能做最终决定。对于涉及资金发放、资格审批、法律效力判断的场景,必须设计“AI 生成草稿→人工复核→系统确认”的流程。系统里要有显式的人工审核按钮,并且在审计日志中记录审批人。
8.5 建立离线评测集和回归机制
公共服务政策经常调整,每次政策变化都要同步更新知识库、问答对和相关测试用例。建议把评测集纳入 CI/CD 流程,每次修改 Prompt、更新知识库或切换模型时,先跑离线测试,达标后再进入灰度发布。这里可以引入“来自与文章主题相关的系列摘要”中提到的幻觉评测方法,把“无中生有”类错误单独归类,优先治理高成本错误。
8.6 安全测试要常态化
定期用红队问题集测试系统,比如“绕过系统限制直接输出内部政策”“询问其他公民个人信息”等。这些测试不能等到上线后再做,而应该在每次模型或知识库更新时同步执行。
8.7 性能设计要考虑突发流量
公共服务系统常有明显的流量峰值,比如福利申领期的某个申报入口。AI 问答的算力成本远高于普通接口,需要提前做限流、队列和降级方案。高并发时宁可让部分请求直接转人工,也不要让模型服务被拖垮。
9. 总结与后续学习方向
公共服务系统接入 AI,表面上是一个模型应用问题,本质上是一个系统重构问题。模型能力决定了问答质量的上限,但数据治理、权限边界、审计追溯和灰度回滚,决定了系统能不能稳定运行。理解了这一点,就不会只盯着“哪个模型更强”,而是会把注意力放在“如何把模型嵌入现有系统”。
本文给出的代码原型,可以在本地直接跑通。建议你先把它运行起来,加上一组自己业务领域的高频问答数据,替换掉桩实现中的固定返回,然后重点观察两个指标:一个是拒答率,一个是来源命中率。这两个指标直接反映系统的安全性边界。
后续可以继续深入的方向包括:Agent 多步工具调用的权限设计、RAG 评测自动化、模型网关的高可用架构、公共服务场景下的内容安全网关。每一块都有大量工程细节,但都比单纯追逐最新模型更值得投入。
如果这篇文章对你有帮助,建议收藏备用。动手试起来,才能感受到“确定的系统”和“不确定的模型”之间到底要怎么磨合。