☰
企业技术支持Agent实战:RAG与Token体系协同提效
2026/10/5 5:39:16 网站建设 项目流程

把标题这句话拆开看,它其实浓缩了我去年搭企业技术支持 Agent 时的完整心路历程。基础版本把 RAG 接进去之后,问答已经能跑通,但每个用户问出来的答案高度雷同,敏感资料不敢放,多轮对话也经常断片。后来把 Token 体系接进来,Agent 才真正开始“变聪明”:它知道你是谁、能看什么、上次聊到哪,回答质量完全换了一个档位。

这篇文章我会把项目从零到一的完整过程拉一遍,重点拆解三件事:Token 体系怎么设计和排障、RAG 知识库怎么建设才能真正用起来、Agent 怎么在并发场景下扛住生产流量。适合正在做企业知识问答助手、内部技术支持机器人,或者想把自己手头“能跑的 Demo”升级成“能用的系统”的开发和运维同学参考。所有方案都来自真实落地经验,不是 PPT 架构。

1. 为什么企业技术支持场景需要 RAG + Token

1.1 技术支持场景的真实痛点

做企业技术支持 Agent,最难的不是模型选型,而是回答的“一致性”和“可用性”。真实场景里,员工或客户问得最多的是这几类问题:

  • 操作类:怎么提单、怎么重置密码、某个功能按钮在哪里
  • 排障类:登录报错、接口 5xx、数据对不上
  • 政策类:报销额度、假期规则、审批流程
  • 产品知识类:某版本支持哪些特性、某模块依赖什么服务

这些问题有一个共同特点:答案往往分散在多个系统里。产品手册在 Wiki,历史工单在客服系统,常见问题在 FAQ 页面,架构说明在内部文档库。用户问一个问题,需要翻好几个地方才能拼出完整答案。传统的搜索框和 FAQ 页面解决不了,因为语义表达太灵活了,同一件事可能有几十种问法。

另一个痛点是信息更新太快。技术支持的知识库不是静态的,每周都有新发版公告、新工单案例、新的坑。如果靠人工维护“标准答案”,维护成本高且永远滞后。RAG 的价值就在这:它把检索和生成解耦,文档更新后重新切块索引,模型不需要重新训练就能回答新问题。

但只做“检索 + 生成”还不够。技术支持的对话高度依赖上下文和身份。同一个问题,“普通员工”和“IT 管理员”应该得到不同的答案;同一个工单,“提单人”和“审批人”能查看的信息也不同。如果没有身份层,Agent 就只能做一个“没有记忆、没有边界”的百科全书,这在企业内网是不可接受的。

1.2 “没 Token 能用”和“有 Token 更聪明”到底指什么

标题这句话,其实触及了企业级 Agent 的两个层级。

“没 Token 能用”指的是最基础的 RAG 问答链路:用户发起提问 → 检索知识库 → 拼接 Prompt → 模型生成。这个链路确实能跑通,我一开始就是先做的这个版本。问题在于,它把每个请求都当成孤立的匿名请求,用户身份、历史会话、权限范围全部丢失。

“有 Token 更聪明”则是把身份令牌(Token)接入到 Agent 的每个环节里,让 Agent 具备四个能力:

  1. 身份识别:知道提问者是内部员工还是外部客户,属于哪个部门,什么角色
  2. 权限过滤:检索结果在进入 Prompt 之前,先按用户的权限范围过滤,没有权限的文档直接不召回
  3. 上下文连续:通过 Token 关联会话 ID,把多轮对话、历史工单、上一次的回答都带进当前请求
  4. 审计与用量:每一次提问都对应到具体用户,可以统计 Token 用量、做限流、留审计日志

需要说明的是,里外里其实有“两个 Token”需要区分。一个是身份令牌(JWT 这类鉴权凭证),另一个是大模型调用的 Token 用量。标题里“没 Token 能用”的 Token 主要指身份令牌,但“有 Token 更聪明”里的 Token 也可以理解成大模型上下文窗口的合理使用——把身份信息、权限信息、历史会话都打包进 Prompt,模型自然能给出更贴合场景的回答。

企业技术支持 Agent 的关键,就是把这两个 Token 体系打通,让鉴权身份直接决定上下文范围。

2. Token 体系设计与实现:从登录到续签

2.1 为什么选 JWT 而不是 Session

这个项目最开始有同事建议用 Session 方案,理由是简单。我的看法是:Session 在单体应用里确实简单,但技术支持 Agent 注定要独立部署、水平扩展、被多个客户端(Web 管理后台、IM 机器人、工单系统)同时调用,这时候 Session 的劣势会很突出。

我把两个方案的对比整理成一张表:

对比项SessionJWT
状态存储服务端内存或 Redis客户端持有,服务端无状态
横向扩容需要集中式 Session 存储任何实例都能直接校验
多客户端复用需要共享 Session 存储Token 天然自包含
过期处理服务端统一清理依赖 exp 声明和刷新机制
权限变更可实时失效需配合黑名单或版本号

最终选了 JWT,核心原因是无状态。Agent 服务可以随便扩缩容,不需要引入额外的 Session 同步机制。JWT 本身包含用户 ID、角色、租户、过期时间,网关解析后就能拿到足够信息,不用每次都查数据库。

要提醒的是,JWT 选型时的一个大坑是密钥管理。我在项目里专门搞了一个密钥管理方案,定期轮换 JWT 签名密钥,同时在网关层缓存了公钥,避免每次请求都去认证中心拉密钥导致性能下降。

2.2 access token + refresh token 双令牌方案

光有 JWT 还不够,生产环境必须用双令牌:短期 access token + 长期 refresh token。为什么?如果只有一个长期 Token,一旦泄露,攻击者可以用很久;如果只有一个短期 Token,用户体验极差,每十分钟就要重新登录一次。

我采用的是标准双令牌流程:

  1. 用户登录成功后,认证中心签发一对 Token:access token(有效期 15 分钟)和 refresh token(有效期 7 天)
  2. 客户端请求时在 Authorization 头携带 access token
  3. Agent 网关校验 access token 签名和过期时间,通过后放行
  4. access token 过期后,网关返回 401,客户端收到后用 refresh token 调用刷新接口
  5. 刷新接口校验 refresh token 合法后,签发新的 access token,同时轮换 refresh token(返回新的 refresh token,旧的立即失效)

这里有几个容易被忽略的细节:

  • refresh token 一定要做轮换,否则旧 token 可以无限期续命
  • 用户登出或修改密码后,要把对应的 refresh token 加入黑名单或做版本号自增
  • 刷新接口要做设备绑定,同一个令牌不能同时在两个设备上使用(具体看业务,安全性要求高可以做)

这套流程跑通之后,用户基本感受不到 Token 过期,Agent 还能拿到最新的用户权限信息(比如员工角色刚变了,下一次刷新后立刻生效)。

2.3 Token 过期、续签和常见参数配置

JWT 里最核心的三个时间参数是:

  • iat(签发时间)
  • exp(过期时间)
  • nbf(生效时间)

我们项目里踩过一个坑:网关服务器时间比认证中心快了半分钟,导致刚签发的 Token 被判定为过期。后来统一接了 NTP 时钟同步,并在校验时加了 30 秒的时钟偏移容忍,问题才解决。

另一个经验是不要只看exp字段。Token“失效”的原因很多:

失效原因排查方向
过期(exp 到达)走 refresh 流程
尚未生效(nbf 在未来)检查签发时间与服务器时钟
签名密钥轮换确认网关是否缓存了旧公钥
用户被登出/权限变更检查 refresh token 黑名单或版本号
租户或 scope 不匹配检查 JWT claims 中的租户 ID

为了排查方便,我每个 JWT 都带了jti(唯一 ID),并在网关日志里记录了每个请求的 jti、用户 ID、校验结果。这样用户投诉“我明明登录了怎么又失效”时,能把日志拉出来看一眼。

3. RAG 知识库建设:让 Agent 真正“有据可查”

3.1 知识底座选型:FAQ 库、文档库、结构化库、知识图谱的区别

RAG 不是银弹,也不是所有知识都适合丢进向量数据库。我在项目里花了很大精力做知识分类,总结下来四类底座各有用武之地:

知识类型适合场景实现方式成本
FAQ / 结构化问答高频、答案确定、变化少关键词匹配 + 规则兜底低
非结构化文档产品手册、公告、历史工单向量检索 + 关键词检索中
结构化数据库订单、库存、设备配置、人员信息Agent 调用 SQL/API 实时查询中高
知识图谱实体关系复杂、需要多跳推理本体建模 + 图查询高

初期最容易犯的错误是什么都想做 RAG。我有段时间把 SQL 数据直接灌进向量库,检索效果很差,因为“订单号 WO-2025-001”这种精确值不是靠语义能搜出来的,该让 Agent 去调 HTTP API 或查数据库。后来定了原则:明确的、格式化的数据走接口查询;非结构化的文本知识才走 RAG。

知识图谱我没铺开做,但技术调研发现,对于“产品 A 依赖模块 B,模块 B 升级会影响哪些客户”这类问题,纯向量检索完全招架不住,本体约束(ontology)能显著提升召回准确性。如果团队资源够,建议用 KG 处理核心的实体关系场景。

3.2 文档切分与向量化:整本手册不能直接扔进 Embedding

做过 RAG 的人都知道,切分策略几乎决定了检索效果的 70%。我最初直接把整本产品手册当一个 chunk 去向量化,结果检索回来的内容又长又杂,模型根本没法学到重点。

我们最终沉淀出一套切分规范:

  • 单块控制在 1000~2000 字左右,太短语义不完整,太长检索噪声太大
  • 相邻块设 100~200 字的重叠(overlap),防止关键信息被拦腰截断
  • 优先按照文档的标题层级切分,而不是按固定字数,保证每块是一个语义完整的小节
  • 每块保留元数据:来源、版本号、适用产品、目标用户、更新日期

元数据特别重要。技术支持场景里经常有版本差异,同一操作步骤在 V2.1 和 V3.0 里不一样。如果不按版本过滤,检索结果会混在一起,Agent 就会一本正经地给出错误答案。我做了两件事:第一,文档入库时强制填写版本元数据;第二,检索时先从用户 Token 或对话上下文中判断当前的产品版本,作为过滤条件传入。

3.3 混合检索与重排序:为什么单用向量检索会翻车

向量检索擅长理解“意图”,但对精确值无能为力。我测试时遇到过很典型的情况:用户问“帮我查一下工单 WO-2025-001 的处理进度”,向量检索会给出一堆工单相关的通用流程文档,而不是这张工单的具体信息。因为“WO-2025-001”这个字符串在向量空间里几乎没有语义特征。

解决方案是混合检索:向量检索 + 关键词(BM25)检索双路召回,再做融合排序。我用的融合策略是 RRF(Reciprocal Rank Fusion),简单有效,不用训练模型。

下面是我验证过的基础版混合检索流程:

# 伪代码:混合检索 + RRF 重排 def hybrid_search(query_text, top_k=10): vector_hits = vector_store.search(query_text, top_k) keyword_hits = bm25_index.search(query_text, top_k) scores = {} for rank, hit in enumerate(vector_hits): scores[hit.id] = scores.get(hit.id, 0) + 1 / (60 + rank) for rank, hit in enumerate(keyword_hits): scores[hit.id] = scores.get(hit.id, 0) + 1 / (60 + rank) return sorted(scores.items(), key=lambda x: x[1], reverse=True)[:top_k]

RRF 的好处是鲁棒,不依赖两路召回的顺序,但精度到不了顶尖水平。对检索排序要求更高的场景,可以直接上 cross-encoder 重排模型,效果明显更好,只是耗时和成本会涨。企业技术支持场景里,这条路值得走,因为交互式问答的检索量不大,重排的代价完全可以接受。

3.4 知识库能存图片吗:多模态资料的处理经验

很多人问“RAG 知识库能存图片吗”,真实答案是:不是把图片塞进向量库,而是把图片变成“可检索的信息”。

企业技术支持场景里,图片信息量极大。用户最喜欢发截图:蓝屏、报错弹窗、接口异常堆栈、配置页面。这些截图里的文字比用户复述的“我这边报错了”准确得多,不利用就太可惜了。

我分两种方式处理图片:

  • 图片作为知识库资料:上传到对象存储,用 OCR 把图片里的文字抽出来,连同图片地址一起进入元数据。检索时命中文字片段,回答时把原图返回给用户。用户看到“你看这张截图”比纯文字说明直观得多。
  • 用户上传图片作为输入:用多模态模型把截图转成结构化文本(识别报错信息、界面关键字),再拿这段文本去走 RAG 检索。实测下来,对“重装系统后登录失败”“某个按钮不存在”这类问题,准确率比单纯让用户描述高好几个档次。

如果团队暂时没有多模态模型,退而求其次可以用通用的 OCR 服务先顶上,核心是不要只存图不提取信息,否则知识库里的图片永远搜不到。

4. Agent 设计与并发实践:从“问答机”到“能干活的助手”

4.1 Agent 框架选型:别一上来就上重型编排

这个项目里我最想分享的教训是:Agent 框架不要迷信“越重越好”。

我们最开始调研了各种 Agent 编排框架,有的支持 ReAct 循环、工具调用、Plan-and-Execute,功能很全。但实际场景里,80% 的技术支持问题根本不需要复杂的工具调用链,只需要“检索知识 → 生成回答 → 附上来源”这个线性流程。

我最终采用了轻量方案:知识问答核心用 LangChain4j 的 Easy RAG 起步,快速验证效果,同时预留了工具调用接口,等真正需要查工单、重置密码时再接上 ReAct 循环。Spring 系的团队选 LangChain4j 很顺手,如果你用的是 Python 技术栈,LangChain 或 LlamaIndex 都行。

判断要不要上完整 Agent 编排有一个标准:看你的任务是不是“需要调用多个工具且工具间有依赖”。比如“先查用户权限 → 再查工单 → 根据结果生成操作建议”就属于这种,值得做 ReAct。反过来,“查一下说明书里怎么配置”这种,做一个 RAG 查询接口就够了,别自己给自己加复杂度。

4.2 让 Agent 感知 Token:把用户身份注入 Prompt 与工具权限

Token 在 Agent 里不只是用来做“登录校验”,更关键的是把身份信息变成模型可见的上下文。我在 Prompt 里放了一段固定的身份块:

你是企业内部技术支持助手,面向公司员工提供产品使用与故障排查帮助。 当前用户信息: - 用户名:{user_name} - 角色:{role} - 部门:{department} - 当前产品范围:{product_scope} - 上下文关联工单:{order_id} 请基于以上身份信息回答问题,不要返回超出用户权限范围的内容。

这段信息从哪里来?就是从 JWT 解析出的 claims,加上一次轻量用户服务查询拼出来的。效果非常明显:普通员工问“怎么申请权限”,Agent 会引导他走审批流程;管理员问同样的问题,Agent 会直接给他管理端配置步骤。

“有 Token 更聪明”的另一个落地点是工具权限。Agent 后续接入了“查询工单”工具,调用时会把当前用户的 user_id 透传给下游 API。这样即使有人故意构造 Prompt 让 Agent 查别人的工单,下游接口也会基于透传身份做校验,从权限模型上切断越权风险。总结一句话:Token 决定的不是“能不能回答问题”,而是“能回答到什么程度”。

4.3 并发高峰:AI Agent 怎么扛住突增流量

企业技术支持 Agent 的并发量不算高,但会突然爆发。典型场景是:早上 10 点全员登录遇到故障,几百人同时来问;或者月底报销政策更新,短时间内涌入大量咨询。扛不住的表现就是接口超时、模型调用排队、用户等很久没回复。

我做的几个关键优化:

  • 无状态化部署:Agent 服务本身不存任何会话状态,会话上下文放在 Redis,按会话 ID 读取。这样服务可以随便扩副本。
  • 热点问题缓存:高频问题(比如“怎么登录”“密码怎么改”)提前把完整回答缓存起来,命中后直接返回,不走 LLM,成本几乎为零。
  • 大模型调用池化:模型服务端有并发限制,客户端做了连接池和排队,避免突发流量全部打爆。
  • 限流与熔断:对单个用户限流(比如每分钟 5 次提问),超出后返回排队提示,保护下游模型服务和知识库。

另外一个容易被忽略的点是超时与重试。模型生成慢的时候,用户会反复点按钮,造成请求叠加。我的做法是:前端做了幂等标识,同一个问题 30 秒内重复提交直接返回上一次请求的结果或排队状态,杜绝重复消费。

5. Token 与 RAG 联动的常见问题排查实录

5.1 Token 报错速查表:从登录失败到 refresh_token 为空

项目上线后,我们接到最多的报错就是各种 Token 相关异常。我把遇到的问题整理成了一张速查表,基本覆盖了大部分现场:

报错信息含义排查方向
sign-in could not be completed token exchange failed: error sending request客户端向认证中心换 Token 时网络不通或上游不可用检查认证中心健康状态、网关路由、client 配置的 token_endpoint 地址
token exchange failed: token endpoint returned status 403 forbidden认证中心拒绝了换 Token 请求检查 client_id / scope / 租户配置,看认证中心风控日志,确认请求头是否带了完整参数
failed to refresh token: 400 bad request: invalid refresh_token: empty string刷新时 refresh token 为空查前端存储,refresh token 是否被清掉、请求体字段名是否传错
your access token could not be refreshed because you have since logged outrefresh token 已被登出操作撤销用户需要重新登录,前端要清理本地残留 token
your access token could not be refreshed. please log out and sign in again.refresh token 已失效或轮换过与上一条类似,按业务提示用户重新登录

这里面有一条值得单独说:refresh token 为空,看起来是后端报错,根因往往在前端。常见原因有两个,一是刷新 token 存在 localStorage 里但换了域名后被清空;二是刷新接口要求的参数名是refresh_token,前端传了refreshToken,后端拿到空值。把字段名对齐,再把前端 token 存储方案从 localStorage 改成 HttpOnly Cookie(或至少做持久化兜底),问题就能避免。

5.2 RAG 检索质量瓶颈与调优:回答不对别急着怪模型

项目上线后,用户反馈最多的问题是“回答不对、答非所问、说了一堆废话”。多数时候不是模型的问题,而是检索质量没做够。我总结了五类高频问题和对应策略:

现象常见原因调优策略
召回为空或极少切块过大导致语义稀释,或查询词太抽象缩小 chunk,增加 query 改写,补充同义词典
召回了但排序不对只用了向量检索,精确匹配能力弱上混合检索(BM25 + 向量)
答案看着对但出处可疑没有重排,模型被低质量 chunk 带偏加 reranker,或提高元数据过滤强度
版本/角色信息不对检索结果混入多个版本内容用 Token 身份信息做预过滤,强制版本字段
回答太长、没有重点Prompt 没做约束,模型自由发挥Prompt 中明确“先给结论,再给步骤,不超过 200 字”

最典型的优化案例是版本过滤。我们初期没做版本过滤,用户问“V2.1 怎么配置”,检索结果混进了 V3.0 的文档,答案完全不对。后来在元数据过滤条件里把版本设成必填,再配合 ask 改写(把“新版”映射到具体版本号),准确率直线上升。

5.3 我整理的一份“避坑经验清单”

最后把所有踩过的坑浓缩一下,给后来者直接参考:

  • 先做无 Token 的 RAG 基线,再往上加身份感知。不要第一天就搞权限过滤,否则系统会变得极难排错。
  • JWT 的密钥要独立管理,定期轮换,网关和认证中心的时钟必须用 NTP 对齐,否则“刚签发就过期”的奇事天天有。
  • 知识库一定保留元数据,来源、版本、适用对象缺一不可,这是检索过滤的基石。
  • 图片资料单独走 OCR 或多模态链路,不要直接放弃,也不要盲目把原图灌进向量库。
  • 并发控制要“限流 + 缓存 + 幂等”三件套一起上,单靠扩机器解决不了 LLM 调用侧的资源瓶颈。
  • 线上问题排查时,用请求 ID 串起全网日志:前端 request_id → 网关 jti → 模型调用 trace,没有这个链路,出问题只能靠猜。

写在最后

这个项目做到后面,我最深的体会是:企业级 Agent 的难点从来不在“跑通一个Demo”,而在“让系统在真实组织环境里长期稳定地运行”。我在实际调试中反复确认了一个观点——Token 体系不是锦上添花的安全组件,而是让 RAG 从“能用”变“更聪明”的杠杆。身份信息一旦注入检索过滤、Prompt 上下文、工具权限这三个关键环节,回答质量、合规边界、审计能力都会同步上一个台阶。

如果后面继续扩展,我认为第一个值得做的方向是完善多模态链路(截图识别 + 图片结果返回),第二个是给 Agent 接入会话记忆的自动压缩,让长对话不丢失关键上下文。工具调用和知识检索的组合可以做深度一点,但前提是先把基础链路做稳定,别一上来就铺太大。还是那句话:先把“没 Token 能用”的基线打到 80 分,再让 Token 帮它突破 90 分。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询