跳转至

架构与数据流

CG_RAG 是独立的法规检索、受约束生成与视觉隐患识别服务。稳定入口是 src.live_retriever_service,HTTP 与 MCP 共用同一个 CgRagService 实例,避免两套接口产生不同检索结果或缓存状态。

模块边界

模块 当前责任
src.live_retriever_service 读取启动参数、建立 FastAPI/MCP lifespan、装配配置和服务
src.retrieval.live_retriever_config 定义 fullusualusual_plus_law profile 与检索模型配置
src.retrieval.live_retriever_manager 按 scope 延迟加载、驻留复用、warmup、lease 与安全释放 retriever
src.retrieval.retrieve_service scope 归一化、fingerprint、cache、召回、rerank、hydration 和 timing
src.retrieval.hydration_service 构建/读取 SQLite sidecar,补全文档元数据
src.generation.constrained_generation_service 生成 prompt、调用 provider、解析候选索引并格式化条文回答
src.retrieval.cg_rag_stream 完整 RAG 与 SSE 事件编排
src.retrieval.cg_rag_vision 图片解码、直接 VQA、agent 运行时装配与进程内检索回调
src.agentic.vision_agentic_runtime 连续视觉 agent:观察、工具调用、证据整理、最终回答校验
src.retrieval.cg_rag_health health/profile 摘要与敏感信息脱敏
src.retrieval.cg_rag_service 对 HTTP/MCP 保持稳定的 facade
src.retrieval.cg_rag_http 参数校验、request ID、线程桥接、SSE、取消与 HTTP 错误映射
src.retrieval.cg_rag_mcp Streamable HTTP MCP 工具与统一 envelope

Retrieve-Rerank 数据流

request
  → Pydantic 校验与 scope 归一化
  → 计算当前 profile fingerprint
  → 查询内存 TTL/LRU cache
  → RetrieverManager.acquire(scope)
  → hybrid retrieve
  → 本地或远端 rerank
  → hydration sidecar 补全 law_name/article/contents/source
  → 复制公开结果并释放 lease
  → 写入 cache
  → response

manager 的 lease 很重要:scope 切换或服务释放时,不会关闭仍被并发请求使用的 retriever。响应只携带复制后的公开字段,不在 lease 外继续访问底层检索对象。

Constrained Generation 数据流

query + retrieval_docs
  → 文档数量与字段归一化
  → 服务端受约束 prompt
  → provider adapter 组装 thinking / stream / response_format
  → OpenAI-compatible Chat Completions
  → 收集 content 与可选 reasoning
  → 解析 JSON 候选索引
  → 校验索引范围、去重、max_items 截断
  → 由服务器使用原始 retrieval_docs 格式化 answer_text

模型只选择候选索引,不能自己写入新的法规条文。最终条文名称、编号和正文来自服务器持有的检索结果,因此生成失败不会污染 retrieval 数据。

完整 RAG 与 SSE

rag 依次执行 retrieve-rerank 和 constrained generation。rag/stream 使用同一业务步骤,但把阶段状态、检索结果和答案 token 转为 SSE。当前 answer token 是对已经校验完成的 answer_text 做分块发送,不代表把未经校验的上游模型 token 直接透传给客户端。

视觉隐患识别数据流

自由生成只有一次模型调用:

images(base64) + question
  → Pydantic 校验、张数与体积上限
  → base64 解码为内存字节,不落盘
  → 注入判定标准条款清单的 system prompt
  → OpenAI-compatible 多模态 Chat Completions
  → 去除 think 块并返回隐患报告

智能生成把上面的单次调用换成 agent 循环,并让模型自己决定检索问题:

images + question
  → 观察,模型决定是否调用 cg_retrieve_rerank
  → 进程内执行 retrieve-rerank(不经过 MCP 或 HTTP)
  → 证据编号、去重、截断
  → 重新观察,必要时继续检索,最多 max_search_rounds 轮
  → 生成最终回答
  → 校验公开协议与 [cite^n] 引用契约,不通过则重试
  → 返回带引用的隐患报告

关键差异在检索这一跳。Question App 的视觉 agent 通过 MCP 调用 CG_RAG,每轮检索都要一次网络往返;agent 运行在 CG_RAG 内部时,检索回调直接调用同一实例的 retrieve_rerank,共享同一份缓存、容量限制器和 profile fingerprint。

引用编号只能来自本轮工具返回的证据,判定标准条款清单属于 system prompt 而非检索证据,因此不能充当引用。回答未携带有效引用时会被判为协议失败并重试。

缓存一致性

retrieve cache key 包含:

  • normalized scope;
  • 去首尾空白的 query;
  • topk;
  • profile fingerprint。

fingerprint 摘要覆盖当前 profile、语料/索引文件、embedding 与 rerank 配置。索引文件或模型配置变化后会形成新 key,旧条目只能等待 TTL/LRU 淘汰,不会被新请求误用。LLM generation 不进入该缓存。

并发和取消

检索与生成各自使用容量限制器,默认并发均为 16,默认最多等待 5 秒。SSE 客户端断开时,HTTP 层取消 CancellationContext;检索、生成和上游 streaming 调用在安全检查点停止。若工作线程中的 generator 尚未退出,HTTP 层最多协作等待 1 秒,不会从另一个线程强制关闭正在运行的 generator。

边界

仓库内所有 VLM 调用都在 CG_RAG。 Question App 通过 HTTP 调用本服务的 vision/* 接口,自己不再组装多模态请求,也不再持有第二套判定标准或 agent 循环——同一份实现同时服务内部产品与外部调用方。

CG_RAG 负责法规检索、受约束生成和图片隐患识别,不负责网页会话、模型选择 UI、附件存储、聊天历史或用户权限。视觉接口接收调用方传入的图片字节并在内存中处理,不做上传管理、不落盘、不保留任何会话状态;这些产品逻辑属于调用方,不在本站点的公开边界内。