def build_cg_rag_mcp(service: Any) -> FastMCP:
mcp = FastMCP("CG_RAG", json_response=True, streamable_http_path="/")
@mcp.tool()
async def cg_health() -> dict[str, Any]:
"""返回检索服务健康状态、active scope、可用 profile、rerank 和 LLM 配置状态。"""
return await _call_service(lambda _cancel_token: service.health())
@mcp.tool()
async def cg_list_profiles() -> dict[str, Any]:
"""列出检索服务可用检索范围 profile,例如 usual、usual_plus_law 和 full。"""
return await _call_service(lambda _cancel_token: {"profiles": service.profiles()})
@mcp.tool()
async def cg_retrieve_rerank(
query: TextInput = None, scope: TextInput = "usual", topk: IntInput = 78
) -> dict[str, Any]:
"""执行检索服务召回和重排,只返回候选条文,不调用 LLM 生成。"""
return await _call_service(
lambda cancel_token: _call_with_optional_cancel(
service.retrieve_rerank,
CgRetrieveRerankRequest(query=query, scope=scope, topk=topk),
cancel_token=cancel_token,
)
)
@mcp.tool()
async def cg_constrained_generate(
query: TextInput = None,
retrieval_docs: DocsInput = None,
max_items: IntInput = 10,
include_debug: BoolInput = False,
generation_enable_thinking: BoolInput = None,
) -> dict[str, Any]:
"""基于调用方传入的候选条文执行受约束生成,返回候选索引和格式化条文。"""
return await _call_service(
lambda cancel_token: _call_with_optional_cancel(
service.constrained_generate,
CgConstrainedGenerateRequest(
query=query,
retrieval_docs=retrieval_docs,
max_items=max_items,
include_debug=include_debug,
generation_enable_thinking=generation_enable_thinking,
),
cancel_token=cancel_token,
)
)
@mcp.tool()
async def cg_rag(
query: TextInput = None,
scope: TextInput = "usual",
topk: IntInput = 78,
max_items: IntInput = 10,
include_debug: BoolInput = False,
generation_enable_thinking: BoolInput = None,
) -> dict[str, Any]:
"""执行完整检索增强流程:召回、重排、受约束生成。该流程不包含 domain gate。"""
return await _call_service(
lambda cancel_token: _call_with_optional_cancel(
service.rag,
CgRagRequest(
query=query,
scope=scope,
topk=topk,
max_items=max_items,
include_debug=include_debug,
generation_enable_thinking=generation_enable_thinking,
),
cancel_token=cancel_token,
),
operation_ok_from_data=_cg_rag_operation_ok,
)
@mcp.tool()
async def cg_vision_answer(
images: ImagesInput = None,
question: TextInput = "请检测图中的安全隐患",
enable_thinking: BoolInput = None,
) -> dict[str, Any]:
"""自由生成:直接根据施工现场图片识别安全隐患并给出整改建议,不检索法规,回答不带引用。"""
return await _call_service(
lambda cancel_token: _call_with_optional_cancel(
service.vision_answer,
CgVisionAnswerRequest(
images=images,
question=question,
enable_thinking=enable_thinking,
),
cancel_token=cancel_token,
)
)
@mcp.tool()
async def cg_vision_observe(
images: ImagesInput = None,
question: TextInput = "请检测图中的安全隐患",
) -> dict[str, Any]:
"""结构化视觉观察:返回校验过的隐患标签与展示文本,供调用方据此构造检索问题。"""
return await _call_service(
lambda cancel_token: _call_with_optional_cancel(
service.vision_observe,
CgVisionAnswerRequest(images=images, question=question),
cancel_token=cancel_token,
)
)
@mcp.tool()
async def cg_vision_agentic(
images: ImagesInput = None,
question: TextInput = "请检测图中的安全隐患",
scope: TextInput = "full",
max_search_rounds: IntInput = None,
topk: IntInput = None,
enable_thinking: BoolInput = None,
) -> dict[str, Any]:
"""智能生成:模型先观察图片,再自行检索法规条文,最后输出带 [cite^n] 引用的隐患判定。"""
return await _call_service(
lambda cancel_token: _call_with_optional_cancel(
service.vision_agentic,
CgVisionAgenticRequest(
images=images,
question=question,
scope=scope,
max_search_rounds=max_search_rounds,
topk=topk,
enable_thinking=enable_thinking,
),
cancel_token=cancel_token,
)
)
return mcp