跳转至

架构

供修改代码的人员参考。调用方请查阅 HTTP 参考。

CG_RAG 是独立的法规检索、受约束生成与视觉隐患识别服务。HTTP 与 MCP 共用同一份服务状态,保证两套接口的检索结果与缓存一致。进程入口见 源码参考。

模块职责

环节 职责
启动 读取 YAML/环境变量,挂载 HTTP 和 MCP
检索范围 三个固定 scope:usual / usual_plus_law / full;同时只驻留一个
检索 归一化 scope、计算 fingerprint、查询缓存、召回、rerank、补全文
受约束生成 模型仅选择候选序号,服务按序号拼接条文
SSE 使用相同业务流程,将阶段状态与答案切分为事件流
视觉 图片在内存中解码;自由生成不执行检索,智能生成在进程内检索
对外 HTTP 层负责校验与错误映射;MCP 暴露相同工具集

各模块文件名见 源码参考,此处不逐一列举。

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、附件存储、聊天历史或用户权限。视觉接口接收调用方传入的图片字节并在内存中处理,不承担上传管理、不落盘、不保留任何会话状态;上述产品逻辑属于调用方职责,不在本站点的公开边界之内。