视觉隐患识别¶
本页面供调用方参考。三种模式的说明、图片传输格式及错误码均在本页。上游配置方式见 配置 和 CG 字段手册。
CG_RAG 内置施工现场图片安全隐患识别功能。调用方提交 base64 编码图片,即可获取结构化隐患报告,无需自行对接 VLM。
三种模式:
| 模式 | 接口 | 是否检索法规 | 回答是否带引用 | 典型耗时 |
|---|---|---|---|---|
| 自由生成 | /cg-rag/vision/answer |
否 | 否 | 单次模型调用 |
| 智能生成 | /cg-rag/vision/agentic |
是,模型自行决定检索问题 | 是,[cite^n] |
多轮观察 + 检索 |
| 垂域+RAG | /cg-rag/vision/hybrid |
是,DeepSeek 按千问描述检索 | 是,正文为 〔n〕 |
一次看图 + 文本检索 |
| 观察 | /cg-rag/vision/observe |
否 | 否 | 单次模型调用 |
自由生成适用于快速筛查与高并发场景;智能生成适用于需要条文依据、可审计结论的场景;观察返回经校验的隐患标签与展示文本,供调用方将图片转换为检索问题后自行编排检索流程。
与 Question App 的关系¶
仓库内所有 VLM 调用均发生在 CG_RAG。 Question App 不再自行组装多模态请求,而是通过本页的 HTTP 接口调用 CG_RAG,再将结果渲染为对话轮次:
该设计带来两项直接效果:
- 智能生成每轮检索无网络往返。agent 与检索同进程,共享同一份 retrieve cache、profile fingerprint 与容量限制器。
- 判定标准、prompt、引用校验仅有一份实现。Question App 与外部调用方获取到的是同一套行为,不会因两处实现漂移而产生不同结论。
调用方只需访问 CG_RAG,无需额外部署编排层。
前置配置¶
视觉功能需单独配置一个多模态上游,与文本生成使用不同的配置。YAML 写在 cg_rag.vision(endpoint / model,密钥 cg_rag.vision.api_key)。未配置时,检索与文本生成不受影响,仅 /cg-rag/vision/* 返回 vision_not_configured。
通过 /cg-rag/health 的 vision.configured 字段判断是否就绪。字段说明见 CG 字段手册。
图片输入¶
两个接口的 images 字段结构相同:
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
data |
string | 是 | 无 | base64 数据,或 data:<mime>;base64,<...> 形式的 data URL |
mime_type |
string | 否 | image/jpeg |
image/jpeg、image/png、image/webp 之一 |
source_turn_index |
integer/null | 否 | null |
图片来源轮次,从 0 开始;用于多轮上下文标记 |
约定:
- 单次请求最多
max_images张(默认 4),单张解码后最多max_image_bytes字节(默认 16 MiB)。 data为 data URL 时,以 data URL 自带的媒体类型为准,mime_type字段被忽略。调用方可直接使用浏览器产生的 data URL,不会造成类型错标。- 不接受 HEIC 格式。iPhone 原图需由调用方预先转换为 JPEG/PNG/WebP —— CG_RAG 接收的是已解码的字节,且上游 VLM 均不支持 HEIC。
- 图片仅在内存中流转,不落盘。
多图时,服务会在每张图前注入 图N: 标记,模型按图分块输出(## 图1、## 图2 …)。单图时不注入该标记。
多轮图片与文字¶
answer、observe 和 agentic 接受可选 history 数组,最多六轮,每项包含
query(用户文字)、answer(助手文字)、turn_index(从 0 开始的轮次)。历史文字按 user/assistant
顺序传给视觉模型;本次 images 必须同时提供需要继续观察的历史图片字节。CG_RAG 不为调用方保存会话或图片,
仅在文字中注明"见上图"不能替代图片内容。
history 非空时,成功响应返回 history_turn_count,调用方可据此确认对端是否接受了多轮协议。
Question API 仅在请求携带 vision_multi_turn=true 时合并当前会话的历史图片与本次上传、按图片 ID 去重,并校验此回执;默认关闭,本轮仅发送当前附件。
POST /cg-rag/vision/answer¶
自由生成。请求字段:
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
images |
array | 是 | 无 | 至少一张,见上文 |
question |
string | 否 | 请检测图中的安全隐患 |
观察重点;非隐患类问题会被直接回答,不套用固定格式 |
enable_thinking |
boolean/null | 否 | null |
单次覆盖服务级 CG_RAG_VISION_ENABLE_THINKING |
history |
array | 否 | [] |
最近六轮以内的用户问题和助手回答,见上文 |
请求:
curl --noproxy '*' -sS \
-X POST http://127.0.0.1:8864/cg-rag/vision/answer \
-H 'Content-Type: application/json' \
-H 'X-Request-ID: req-doc-vision' \
-d "{\"images\":[{\"data\":\"$(base64 -w0 site.jpg)\",\"mime_type\":\"image/jpeg\"}]}"
示例输出,已删减:
{
"ok": true,
"request_id": "req-doc-vision",
"mode": "free_form",
"question": "请检测图中的安全隐患",
"answer": "隐患等级:一般隐患\n\n隐患分类:扣件式钢管脚手架\n\n隐患描述:\n1. 脚手架基础区域存在明显积水,未采取有效排水措施。\n\n整改措施和建议:\n1. 立即排除积水并设置排水设施。",
"reasoning": "",
"image_count": 1,
"model": "<vlm-model>",
"thinking_enabled": false,
"citations": [],
"retrieval_docs": [],
"hazard_categories": ["扣件式钢管脚手架"],
"hazard_taxonomy_version": "construction-hazard-19-v1",
"usage": {"prompt_tokens": 1180, "completion_tokens": 96, "total_tokens": 1276},
"runtime_stats": {"total_time_ms": 6421.3}
}
citations 与 retrieval_docs 恒为空数组:该模式不执行检索,回答中不会出现 [cite^n]。需要条文依据时,请使用智能生成模式。服务会校验回答中的分类;首次格式不合法时自动纠正一次,仍不合法则返回 vision_response_invalid,不会返回或保存格式异常的报告。
POST /cg-rag/vision/agentic¶
智能生成。在自由生成字段的基础上追加:
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
scope |
string | 否 | full |
检索范围,full / usual / usual_plus_law |
max_search_rounds |
integer/null | 否 | null |
最多检索轮数,范围 1..3;null 用服务配置 |
topk |
integer/null | 否 | null |
每轮检索候选数,范围 1..200;null 用服务配置 |
请求:
curl --noproxy '*' -sS \
-X POST http://127.0.0.1:8864/cg-rag/vision/agentic \
-H 'Content-Type: application/json' \
-d "{\"images\":[{\"data\":\"$(base64 -w0 site.jpg)\"}],\"scope\":\"full\",\"topk\":12}"
示例输出,已删减:
{
"ok": true,
"request_id": "req_xxx",
"mode": "agentic",
"question": "请检测图中的安全隐患",
"answer": "## 隐患等级\n重大事故隐患\n\n## 隐患分类\n扣件式钢管脚手架\n\n## 隐患描述\n1. 脚手架立杆底部浸泡在积水中。\n\n## 隐患判定依据\n1. 《房屋市政工程生产安全重大事故隐患判定标准(2024版)》第七条第一款:脚手架工程基础承载力和变形不满足设计要求。\n2. 《施工脚手架通用规范》(GB 55023-2022)地基应坚实、平整,不应有积水 [cite^2]。\n\n## 整改措施及建议\n1. 立即排水并复核地基承载力。",
"reasoning_stages": [
{"label": "OBSERVATION", "content": "图中脚手架立杆底部处于积水中。"},
{"label": "SEARCH_PLAN", "content": "检索脚手架地基基础排水与承载力要求。"},
{"label": "EVIDENCE_REVIEW", "content": "检索到的条文支持地基不应积水。"},
{"label": "FINAL_REASONING", "content": "按 2024 版判定标准第七条第一款定级。"}
],
"citations": [2],
"retrieval_docs": [
{
"law_name": "GB55023-2022施工脚手架通用规范",
"article_number": "2.0.1",
"contents": "脚手架性能应符合下列规定……"
}
],
"pipeline_trace": [
{"name": "图片接收", "status": "done", "summary": "已接收并校验 1 张图片。"},
{"name": "第 1 轮法规检索", "status": "done", "summary": "执行 1 条检索问题,累计保留 12 条证据。"},
{"name": "证据化结论生成", "status": "done", "summary": "已生成最终回答,使用 1 条服务器引用。"}
],
"scene_status": "assessable",
"image_count": 1,
"model": "<vlm-model>",
"scope": "full",
"thinking_enabled": false,
"warnings": [],
"hazard_categories": ["扣件式钢管脚手架"],
"hazard_taxonomy_version": "construction-hazard-19-v1",
"usage": {"total_tokens": 8241},
"runtime_stats": {"total_time_ms": 41250.8}
}
字段说明:
citations为回答中实际使用的服务器证据序号,与retrieval_docs的下标一一对应(从 1 开始)。reasoning_stages为可公开的审计依据,非模型的原始 thinking。scene_status取值为assessable、unsupported_scene、insufficient_visual_evidence或not_assessed;后两者表示图片本身不足以判定,此时应按warnings提示补拍。pipeline_trace用于向用户展示进度,亦便于排查某一轮检索是否为空。
隐患等级取值为 无隐患 / 一般隐患 / 疑似重大事故隐患 / 重大事故隐患。每张图同时只有一个主隐患分类;hazard_categories 按图片顺序给出"19 类 + 无"的校验结果,hazard_taxonomy_version 标明分类版本。存在多项隐患时,优先选取等级最高者;同等级则优先画面证据最明确、最具体的设备或工程类别。非施工场景或证据不足时,不会以 无 代替实际情况。定级规则、分类清单和 2024 版判定标准条款清单均由服务端注入 system prompt,调用方无需自行实现。
POST /cg-rag/vision/hybrid¶
垂域+RAG。与上一节的智能生成不属于同一条处理链路。
智能生成由看图的模型自行决定检索内容,再输出带 [cite^n] 的报告。本接口的处理流程为:千问先按自由生成方式输出隐患描述,描述、等级和分类保持原样;DeepSeek 仅读取该段文字,调用检索工具查询法规,再撰写判定依据和整改措施。文本模型不接收图片。
存在可见隐患且检索到证据时,判定依据固定为 3 条,每条仅引用一条证据。整改措施根据描述和这 3 条依据撰写,条数不要求与依据条数一致。格式校验未通过时,模型先修正一次;仍未通过,服务端保留已输出的可见事实,不整篇重写。visual_qa 直接回答问题,不使用报告格式,亦不执行检索。
请求字段与 /cg-rag/vision/agentic 相同。topk 不生效,服务端固定为 12。未传入 max_search_rounds 时最多检索 2 轮;传入时限制在 1 到 3 轮,每轮最多 3 次工具调用。scope 按请求执行。正文中的引用已写成 〔n〕,citations 为对应的证据序号。agentic 返回的是原始 [cite^n],由调用方自行渲染,两种格式不可混用。
文本模型需单独配置,三项均为必填:
| 环境变量 | 含义 |
|---|---|
CG_RAG_HYBRID_GENERATION_ENDPOINT |
文本模型地址 |
CG_RAG_HYBRID_GENERATION_MODEL |
现网为 deepseek-flash |
CG_RAG_HYBRID_GENERATION_API_KEY |
文本模型密钥,不回退到 CG_RAG_API_KEY |
任一项缺失均返回 hybrid_generation_not_configured。不会改用受约束生成的 CG_RAG_GENERATION_MODEL(现网为另一个 deepseek-chat)。
Question App 中 qwen-deepseek-flash 的带图智能生成仅转发至本接口。页面上的模型名、反馈卡和文字复核不变。文字复核不经过本接口,仍由 Question App 使用修改后的描述执行文本检索。返回元数据中的 match_type 仍为 hybrid_vision_agentic,该字段为历史遗留字段名,与 /vision/agentic 无关。
流式路径为 POST /cg-rag/vision/hybrid/stream,事件类型与智能生成相同,并额外增加 retrieval 事件,用于更新检索预览。
POST /cg-rag/vision/observe¶
单次结构化观察。请求字段与自由生成相同(images、question),但返回的是经校验的观察结果,而非隐患报告:
curl --noproxy '*' -sS \
-X POST http://127.0.0.1:8864/cg-rag/vision/observe \
-H 'Content-Type: application/json' \
-d "{\"images\":[{\"data\":\"$(base64 -w0 site.jpg)\"}]}"
示例输出:
{
"ok": true,
"mode": "observe",
"text": "图片描述:图中可见施工区域地面存在积水。\n\n确定隐患描述:场地积水问题\n\n整改建议:\n1. 及时排除积水。",
"hazard_label": "场地积水问题",
"is_non_scene": false,
"parse_status": "succeeded",
"parse_error": "",
"profile_id": "construction-hazard-inspection-v1",
"system_prompt_sha256": "<PROFILE_PROMPT_SHA256>",
"image_count": 1,
"model": "<vlm-model>",
"usage": {"total_tokens": 812},
"elapsed_ms": 5120.4
}
hazard_label 取自服务端的 62 项标签词表,模型无法自行生成词表外的标签。parse_status 为 failed 时,hazard_label 为空,parse_error 说明原因,而 text 仍为可安全展示的原始观察内容——这是正常返回,而非错误:调用方应据此决定降级展示或中止,不应将其视为调用失败。观察接口无流式变体。
流式接口¶
/cg-rag/vision/answer/stream 与 /cg-rag/vision/agentic/stream 的请求字段与各自的非流式版本完全相同,响应类型为 text/event-stream:
curl --noproxy '*' -N \
-X POST http://127.0.0.1:8864/cg-rag/vision/agentic/stream \
-H 'Content-Type: application/json' \
-d "{\"images\":[{\"data\":\"$(base64 -w0 site.jpg)\"}]}"
事件序列示例,已删减:
event: progress
data: {"stage":"vision","label":"正在结合法规识别图片隐患","status":"running"}
event: trace
data: {"name":"第 1 轮法规检索","status":"done","summary":"执行 1 条检索问题,累计保留 12 条证据。"}
event: agent
data: {"event_id":"vision.final","kind":"final","status":"running","label":"正在生成最终回答"}
event: token
data: {"channel":"answer","text":"## 隐患等级\n重大事故隐患\n"}
event: final
data: {"ok":true,"mode":"agentic","answer":"...","citations":[2]}
事件说明:
| 事件 | 出现于 | 含义 |
|---|---|---|
progress |
两种模式 | 阶段进度 |
token |
两种模式 | 可追加到 UI 的片段,channel 为 answer 或 reasoning |
trace |
智能生成 | 流水线节点:图片接收、各轮检索、结论生成 |
agent |
智能生成 | agent 事件(观察、检索、重试、最终回答)的状态流转 |
answer_reset |
两种模式 | 作废此前已发送的全部 answer 文本,随后重发 |
error |
两种模式 | 业务或流式中断错误 |
final |
两种模式 | 与非流式响应结构一致的完整结果 |
answer_reset 必须处理。智能生成会校验公开协议、引用与分类契约;自由生成会校验分类契约并最多纠正一次。校验不通过时服务重试,重试成功后重发正确答案;客户端需先清空已渲染的 answer 缓冲,再追加后续 token。忽略该事件将导致页面出现两份拼接在一起的回答。
其余语义与 /cg-rag/rag/stream 一致,详见 HTTP 参考 · SSE。以 final 作为最终状态来源;final 的 payload 与非流式响应结构相同。
MCP 工具¶
两种模式同样以 MCP 工具形式暴露,见 MCP 工具:
cg_vision_answer(images, question, enable_thinking)cg_vision_agentic(images, question, scope, max_search_rounds, topk, enable_thinking)
MCP 返回完整 JSON envelope,不提供 token 流;如需逐字输出,请使用上述 HTTP 流式接口。
错误¶
| 错误码 | HTTP 状态 | 含义 |
|---|---|---|
vision_not_configured |
503 |
未设置 CG_RAG_VISION_ENDPOINT / CG_RAG_VISION_MODEL |
invalid_image |
400 |
图片数量超限、体积超限、base64 非法或媒体类型不受支持 |
invalid_request |
400 |
请求体字段类型或范围不合法 |
vision_upstream_error |
502 |
调用 VLM 失败 |
vision_response_invalid |
502 |
VLM 未返回可用内容 |
capacity.exceeded |
429 |
生成容量等待超时 |
示例:
{
"request_id": "req_xxx",
"error": {
"code": "invalid_image",
"message": "第 1 张图片为 20971520 字节,超过上限 16777216 字节。",
"details": {}
}
}
流式接口的响应头在生成开始前已发出,因此上述失败在流中表现为 event: error,HTTP 状态仍为 200。
集成建议¶
- 先通过
/cg-rag/health的vision.configured判断能力是否可用,再决定是否向用户开放入口。 - 批量筛查使用自由生成,需要出具依据时再对命中项调用智能生成,以避免对每张图均付出多轮检索的开销。
- 智能生成请显式传入
scope和topk,不应依赖默认值。 - 视觉与文本生成共用同一个 generation 容量限制器,批量调用前请确认
capacity.generation余量。 - 图片体积直接影响上传耗时和 token 成本,建议调用方预先将长边压缩至 2048 以内再提交。
视觉版本(profile)¶
配置键 cg_rag.vision.profile(环境变量 CG_RAG_VISION_PROFILE)。未设置时,兼容旧键 CG_RAG_VISION_AGENTIC_WORKFLOW:continuous 解析为 e10,controller 解析为 controller。
| profile | 含义 | 适用 | 已知自动评测(是/(是+否),未识别不进分母) |
|---|---|---|---|
e10(默认,当 workflow=continuous) |
continuous + 六分区观察清单 + publish/salvage + VLM 上游重试×4 | 生产;与线上 overlay 20260920T2235Z-e10-observe-inventory-cg 对齐 |
≈48.5%(9-19~9-21) |
continuous_base |
continuous 无观察清单;可关 strict_retrieval_failure |
回退对照(9/16 原版思路) | ≈43.5%(今日重跑) |
controller |
main controller 工作流(含引用对齐与检索失败加固) | 对照 / 非生产默认 | ≈41.7%(9/17) |
controller_wip |
实验:垫板词表、二次观察、覆盖检索等 | 实验,不建议生产 | d04 ≈45.4% |
切换方式:修改 YAML cg_rag.vision.profile 或环境变量后重启 CG-RAG。回滚生产版本:将其设回 e10(或仅保留 CG_RAG_VISION_AGENTIC_WORKFLOW=continuous 且不设 profile)后重启。
与线上 overlay 的有意差异¶
strict_retrieval_failure默认开启:检索传输全部失败时,在成文前拒绝请求(线上 e10 会先成文)。continuous_base可关闭该选项。- 观察清单 phase 名为
inventory(线上曾用observe,但当时 observe 无 JSON schema;现网 main 的 observe 会套 controller schema,故改名)。 - 流式 VLM 仅在首个 token 前重试(避免半途重放重复字)。
健康检查会报告当前 profile 名与提示词 SHA。启动时预检 SHA 钉子(CG_RAG_STRICT_PROMPT_PINS=1 时不一致则拒绝启动)。
整单预算与心跳(P5)¶
cg_rag.vision.total_budget_seconds/CG_RAG_VISION_TOTAL_BUDGET_SECONDS:整单墙钟预算。e10 默认 150 秒(现网均时约 67s;外层 CG/问答超时 180s)。各阶段(观察、六分区清单、检索、成文纠正、上游重试)启动前均检查预算;预算耗尽时优先发布已通过校验的报告,否则返回vision_budget_exceeded。cg_rag.vision.sse_heartbeat_seconds/CG_RAG_VISION_SSE_HEARTBEAT_SECONDS:默认 15;设为0时关闭。长等待期间发送 SSE: keepalive(前端忽略注释行)及携带heartbeat: true的 progress 事件。
检索全失败(G6)¶
cg_rag.vision.strict_retrieval_failure/CG_RAG_VISION_STRICT_RETRIEVAL_FAILURE:为真时,传输全部失败在成文之前拒绝请求(retrieval.failed),不会先流出半篇报告。e10 默认开启;continuous_base默认关闭,以回退至线上旧有的"先成文"行为。检索成功但返回 0 篇时继续成文,提示不得写条号,结果evidence_status=none,模型若仍写条号将被清洗。