Skip to content

20 · RAG 与 Agent 的服务端落地 ​

RAG 和 Agent 在笔记本里跑通只是开始,做成生产 API 才是你的目标。本篇讲「离线索引 + 在线检索 + 生成 + Agent 编排」的服务端工程化:延迟、并发、权限、成本一个都不能少。

速览卡 ​

项内容
一句话定位把 RAG 与 Agent 从 Jupyter 原型变成稳定、可观测、可上线的后端服务
核心内容RAG 全链路(ingestion/retrieval/generation)、向量库与重排、Agent 状态与工具编排、多租户隔离、生产性能与评测
读完能回答RAG 和 Agent 在生产和服务端有什么区别?向量检索放在哪一层?Agent 的状态怎么管理?
相关板块C19 · AI 服务端集成 | C13 · 缓存与 Redis | C21 · AI 服务可靠性

前置:先读 G 域实操 把原型跑通,本篇专注「生产化」这一跳。


一、从笔记本到生产:差在哪里 ​

维度Jupyter 原型生产服务
数据手动灌几个文档持续接入、增量更新、清理
检索一次性查询稳定延迟、缓存、重排
并发单线程演示多用户并发、限流、隔离
权限无每个租户只能检索自己的数据
评测人工看评测集 + 回归
观测print延迟/成本/错误指标

结论:生产 RAG 的难点不在"调模型",而在数据管道、检索质量、权限隔离、性能与成本这四个工程问题。


二、RAG 全链路:两段式架构 ​

text
离线(ingestion 数据管道)
  文档 → 解析/清洗 → 切片 → 向量化(embedding) → 写入向量库

在线(retrieval + generation)
  用户问题 → 向量化 → 向量检索(+关键词混合) → 重排
  → 组装 Prompt(上下文+问题) → LLM 生成 → 返回(带引用)

2.1 离线管道:数据质量决定上限 ​

环节关键点常见坑
解析PDF/Word/网页转纯文本表格、扫描件丢失语义
清洗去页眉页脚、去噪声脏文本污染 embedding
切片按语义/标题切,兼顾长度切太碎丢失上下文
向量化统一 embedding 模型与维度新旧模型混用导致检索错乱
写入幂等、去重、版本重复灌库导致答案重复

切片是前端类比最直接的:把一篇长文档切成"组件"而不是"一坨 div"。好的切片像按区块划分的 React 组件,边界清晰、可独立复用。

2.2 在线查询:延迟预算 ​

一条 RAG 请求的典型耗时分布:

text
向量化(问题) ~10-50ms → 向量检索 ~10-100ms → 重排 ~20-200ms → LLM 生成 秒级

优化顺序:先压检索层(索引、缓存、混合检索),再压生成层(模型路由、Prompt 精简)。LLM 生成占大头,缓存命中是最大收益。


三、向量库选型与定位 ​

方案适合类比
PostgreSQL + pgvector中小数据量,已有 PG在现有库里加一张表
专用向量库(Milvus/Qdrant)千万级、高 QPS独立的搜索引擎
托管向量服务不想运维用云服务

默认推荐:个人全栈从 pgvector 起步(详见 DB11 · pgvector),数据量大了再考虑专用库。别一上来就上分布式向量库。

检索质量三板斧 ​

  1. 混合检索:向量(语义)+ 关键词(精确)合并,见 G08
  2. 重排(rerank):候选 Top-50 重排成 Top-5,能明显提升相关度
  3. 元数据过滤:按租户/文档类型/时间先过滤再检索,既提质量又保隔离

四、Agent 的服务端化:状态与工具 ​

Agent 比单次 RAG 多了"多轮推理 + 调用工具"的循环(原理见 G03)。服务端要解决四个新问题:

问题服务端做法
状态管理会话上下文存 Redis/DB,而不是内存变量
工具执行工具是受控函数,参数要校验、超时要限制(见 C19)
循环边界最大轮数、单步超时、人工审批点
隔离与审计每个租户/用户独立会话与权限,记录每次工具调用
text
请求 → 取会话上下文 → LLM 推理 → 需要工具?
  ├─ 否 → 更新上下文 → 返回
  └─ 是 → 校验参数 → 执行工具 → 结果喂回 →(回到 LLM,直到结束或超轮数)

关键心智:Agent 的"记忆"不在模型里,而在你的存储里。前端类比是:会话状态别放组件内存,要放 store + 持久化。

人工审批(Human-in-the-loop) ​

高风险工具(下单、发邮件、删数据)必须插一个审批点:

text
Agent 请求工具 → 标记 pending → 通知用户 → 用户确认 → 才执行

红线:任何写操作、对外副作用、花钱的动作,默认都要有人工确认或白名单限制。


五、多租户与权限隔离 ​

这是 RAG 服务端最容易翻车的地方:

层级隔离方式
数据层文档/切片带 tenant_id,检索 SQL 强制带租户过滤
接口层从认证信息取 tenant_id,禁止由客户端传
模型层同租户共享模型,但 Prompt/上下文只含本租户数据

铁律:租户 id 永远从服务端会话取,不能信任请求体。前端提交 tenantId 字段的做法在安全上是反面教材。


六、性能、缓存与降级 ​

6.1 缓存策略 ​

缓存层缓存什么失效策略
语义缓存相似问题的完整答案相似度阈值 + TTL(见 C21)
检索缓存查询 → 检索结果文档更新时清除
embedding 缓存相同文本的向量内容不变则永久

6.2 降级路径 ​

text
向量库挂了 → 退化为关键词检索 → 再退化为"无上下文直接回答"
模型超时   → 返回缓存答案 / 明确报错(不要静默编造)

没有降级的 AI 服务,上游一抖你就全挂。 降级路径要提前设计并在上线前演练。


自检清单 ​

  • [ ] 能画出离线管道 + 在线查询两段式架构,并说出每段的关键质量点
  • [ ] 能按数据量给向量库选型(pgvector vs 专用库)
  • [ ] 能给检索加元数据过滤,保证租户隔离
  • [ ] 能讲清 Agent 的状态存哪、工具怎么受控、审批点插在哪
  • [ ] 有缓存与降级路径,上游故障时服务仍可用

常见误区 ​

  • 误区:原型跑通 = 可以上线。 没做隔离、评测、降级就上线,事故是迟早的。
  • 误区:RAG 就是"文档切一切 + 调模型"。 数据管道和检索质量决定了 80% 的效果。
  • 误区:Agent 状态放内存变量。 重启即丢、无法多实例扩展,必须持久化。
  • 误区:租户 id 由前端传。 安全隔离必须服务端认证后自己取。

动手练习 ​

练习 A:生产化 RAG API ​

把 G 域的 RAG 原型改造成 FastAPI 服务:POST /query,输入问题返回答案 + 引用切片列表。

练习 B:加租户隔离 ​

给文档加 tenant_id,实现两个租户互不可见,并用测试断言越权查询返回空。

练习 C:Agent + 审批 ​

实现一个带 send_email 工具(参数校验 + 审批点)的 Agent,跑通"请求 → 等待确认 → 执行 → 返回"。


相关文档 ​

本区 ​

其他域 ​