使用 Code-Graph-RAG 的 CypherGenerator:自然语言生成知识图谱查询的完整指南
【免费下载链接】code-graph-ragThe ultimate RAG for your monorepo. Query, understand, and edit multi-language codebases with the power of AI and knowledge graphs项目地址: https://gitcode.com/GitHub_Trending/co/code-graph-rag
Code-Graph-RAG 的核心价值在于把多语言代码库解析成可查询的知识图谱,而CypherGenerator正是这座图谱的"自然语言入口":它把"Find all classes that inherit from BaseModel"这类人类提问翻译成可直接执行的 Cypher 查询。本文将以 docs/sdk/cypher-generator.md 为骨架,结合仓库源码(如 codebase_rag/services/llm.py、codebase_rag/constants/security.py),完整讲解它的接入方式、多 Provider 配置、底层安全校验机制与典型查询模式,帮助你在自己的 Agent 或自动化流程中安全、稳定地使用它。
一、CypherGenerator 是什么
CypherGenerator是 Code-Graph-RAG 提供的 Python SDK 类,职责单一而明确:把自然语言问题转换为针对知识图谱的只读 Cypher 查询。它并不是在本地做关键字映射,而是基于当前配置的大模型(Provider)构建一个专门的翻译 Agent,通过强约束的系统提示词把输出限定为"干净、只读、可安全执行"的 Cypher。
在 SDK 层面,它由 cgr/init.py 直接导出,因此只需一行导入即可使用:
from cgr import CypherGenerator与它一同导出的还有GraphLoader、MemgraphIngestor、embed_code、settings等,完整的 SDK 入口总览见 docs/sdk/overview.md。
二、快速上手:最小可用示例
最简单的用法是在 async 环境中创建实例并调用generate():
import asyncio from cgr import CypherGenerator async def main(): gen = CypherGenerator() cypher = await gen.generate("Find all classes that inherit from BaseModel") print(cypher) asyncio.run(main())运行后控制台会输出类似这样的 Cypher(实际生成结果取决于底层模型与图谱 Schema):
MATCH (c:Class)-[:INHERITS]->(b:Class) WHERE b.name = 'BaseModel' RETURN c.name AS name, c.qualified_name AS qualified_name, labels(c) AS type LIMIT 10;generate()返回的是已清理并校验过的只读查询字符串,可以直接交给 MemgraphIngestor 或 Memgraph 客户端执行。需要注意:默认配置下若未设置任何模型,底层会回退到本地 Ollama 默认模型(见下文"配置与优先级"),所以正式使用前请先完成 Provider 配置。
三、配置 Cypher Provider 的三种方式
生成器本身不绑定某个厂商,它读取的是"当前激活的 Cypher 模型配置"。文档提供了三种等价配置路径。
3.1 环境变量方式(推荐用于部署)
在启动进程前导出环境变量即可,Google 与 Anthropic 示例如下:
# Google(Gemini) CYPHER_PROVIDER=google CYPHER_MODEL=gemini-3.5-flash-lite CYPHER_API_KEY=your-google-api-key # 或 Anthropic(Claude) CYPHER_PROVIDER=anthropic CYPHER_MODEL=claude-haiku-4-5 CYPHER_API_KEY=sk-ant-your-anthropic-key从源码看,这些变量定义在 codebase_rag/config.py 的Settings类中,并且不止文档列出的三个,还包括:
| 环境变量 | 作用 | 说明 |
|---|---|---|
CYPHER_PROVIDER | 选择模型供应商 | 见下方支持的 Provider 表 |
CYPHER_MODEL | 指定模型 ID | 例如claude-haiku-4-5 |
CYPHER_API_KEY | API 密钥 | Google/OpenAI 等云端厂商必填 |
CYPHER_ENDPOINT | 自定义 API 端点 | 兼容 OpenAI 协议的自建服务用 |
CYPHER_PROJECT_ID | 云厂商项目 ID | 部分 Google 认证场景需要 |
CYPHER_REGION | 区域 | 默认取DEFAULT_REGION |
CYPHER_PROVIDER_TYPE | Google 认证类型 | 见GoogleProviderType |
CYPHER_THINKING_BUDGET | 思考预算 | 支持思维链的模型用 |
CYPHER_SERVICE_ACCOUNT_FILE | 服务账号文件 | Google 服务账号认证用 |
完整的全局配置说明可参考 docs/getting-started/configuration.md。
3.2 编程方式(推荐用于单次会话覆盖)
通过cgr.settings在代码里临时切换,不污染环境:
from cgr import settings # Google settings.set_cypher("google", "gemini-3.5-flash-lite", api_key="your-google-api-key") # 或 Anthropic settings.set_cypher("anthropic", "claude-haiku-4-5", api_key="sk-ant-your-key")从实现看,set_cypher 会把参数组装成ModelConfig并存入_active_cypher;CypherGenerator构造时通过settings.active_cypher_config属性读取它(llm.py)。也就是说,先调用set_cypher再创建CypherGenerator即可生效;ModelConfig还接受endpoint、provider_type、thinking_budget等 kwargs,与上面的环境变量一一对应。
3.3 默认回退行为(未配置时)
若既没有环境变量也没有调用set_cypher,_get_default_config(config.py)会回退到本地Ollama的默认模型,并尝试连接本机 Ollama 端点。这意味着:
- 本地已有 Ollama 且装有默认模型时,开箱即可用;
- 无本地模型时
CypherGenerator()构造会抛出LLMGenerationError(初始化失败)。
四、支持的 Provider 与模型选型
文档给出的供应商与示例模型如下:
| Provider | 示例模型 |
|---|---|
| Anthropic | claude-opus-5、claude-sonnet-5、claude-haiku-4-5 |
gemini-3.6-flash、gemini-3.5-flash-lite | |
| OpenAI | gpt-5.6-terra、gpt-5.6-luna |
| Ollama | qwen2.5-coder、llama3.2 |
模型选型建议(结合源码提示词的差异):
- 云端强模型(Claude/Gemini/GPT):走 build_cypher_system_prompt,提示词包含完整的图谱 Schema 与查询规则,可产出较复杂的多模式查询;
- 本地弱模型(Ollama):走 build_local_cypher_system_prompt,提示词更严格,要求"只输出合法 Cypher、不要解释、不要 Markdown",并给出更多直白的示例对,适合
qwen2.5-coder、llama3.2这类小模型。
这一分支逻辑位于 llm.py:config.provider == cs.Provider.OLLAMA时选择本地提示词,否则用完整提示词。
五、生成链路:从提问到安全可执行的 Cypher
generate()(llm.py)的内部流水线值得拆解,便于理解它的行为边界:
- 构造 Agent:
CypherGenerator.__init__用当前active_cypher_config创建模型实例,包装成pydantic-ai的Agent,输出类型固定为str,并设置重试次数settings.AGENT_RETRIES(llm.py)。 - 运行 Agent:
await self.agent.run(natural_language_query)把用户问题交给模型。 - 基础校验:结果必须是字符串,且大写后必须包含
MATCH关键字,否则视为无效输出(LLM_INVALID_QUERY)。 - 响应清理(
_clean_cypher_response):剥掉 Markdown 代码围栏(cypher ...)、去除**加粗**包裹、去掉反引号与多余的cypher前缀,并确保以分号结尾(llm.py)。 - 安全校验(只读强制):依次执行三个校验函数,任一失败都抛出
LLMGenerationError:_validate_cypher_read_only:按危险关键字白名单/黑名单扫描,见下文;_validate_no_unbounded_paths:拒绝无上界的变长路径;_validate_call_procedures:只允许调用放行前缀内的存储过程。
- 返回:校验通过后返回可直接执行的 Cypher 字符串,同时写入结构化日志(
CYPHER_GENERATED)。
5.1 只读安全边界(重点)
Cypher 由 LLM 生成,天然存在被诱导产生写操作的风险。仓库在 codebase_rag/constants/security.py 定义了一组危险关键字,生成结果中出现任何一个即被拒绝:
DELETE、DETACH、DROP、CREATE INDEX、CREATE CONSTRAINT、REMOVE、 SET、MERGE、CREATE、LOAD CSV、FOREACH这些关键字覆盖了删除节点/关系、修改属性、创建索引约束、批量导入等全部写路径。配合_validate_no_unbounded_paths,变长路径必须给出显式上界(如[*1..3]),防止全图扫描;_validate_call_procedures则只放行算法/分析类过程,白名单前缀(security.py)包括pagerank.、algo.、node_similarity.、leiden_community_detection.、nxalg.、schema.、wcc.等图分析过程,其余一律拒绝。
在项目级(多仓库)场景,查询还会受到项目作用域约束——相关的只读强制与作用域判定逻辑见 codebase_rag/tests/test_cypher_project_scope.py 的测试覆盖。
5.2 异常与失败处理
- 初始化失败(模型不可用、密钥错误)→
LLM_INIT_CYPHER; - 输出不含
MATCH→LLM_INVALID_QUERY; - 命中危险关键字 →
LLM_DANGEROUS_QUERY(包含具体关键字与原文); - 无界路径 →
LLM_UNBOUNDED_PATH; - 非法过程调用 →
LLM_DISALLOWED_PROCEDURE; - 其余生成/校验失败 →
LLM_GENERATION_FAILED。
所有错误统一以LLMGenerationError抛出(定义见 codebase_rag/exceptions.py),调用方按需捕获即可,同时在日志中记录CYPHER_ERROR便于排查。
六、模型提示词中的查询范式(进阶)
想要得到稳定的生成结果,理解系统提示词内置的查询范式很有帮助。build_cypher_system_prompt与build_local_cypher_system_prompt内嵌了多条"自然语言 → Cypher"示例(常量定义在 codebase_rag/cypher_queries.py),它们同时也是你手工编写查询时的最佳实践模板:
1. 按短名查找类的方法(用ENDS WITH匹配 qualified_name)
类/函数的qualified_name是完整路径(如Project.folder.subfolder.ClassName),用户只提短名时必须用后缀匹配,不能用{name: '...'}等值匹配:
MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method) WHERE c.name = 'UserService' RETURN c.name AS className, m.name AS methodName, m.qualified_name AS qualified_name, labels(m) AS type LIMIT 102. 按路径前缀查目录内容(用STARTS WITH)
MATCH (n) WHERE n.path IS NOT NULL AND n.path STARTS WITH 'workflows' RETURN n.name AS name, n.path AS path, labels(n) AS type LIMIT 103. 查找调用者(匹配CALLS边并返回type(r))
调用者一端保持不标注(模块、函数、方法都可能是调用点),并按qualified_name后缀过滤被调者:
MATCH (caller)-[r:CALLS]->(callee:Function|Method) WHERE callee.qualified_name ENDS WITH '.process_payment' RETURN caller.qualified_name AS caller_qualified_name, caller.path AS path, labels(caller) AS type, type(r) AS call_type LIMIT 104. 多项目数据库内限定单项目作用域
MATCH (c:Class) WHERE c.qualified_name STARTS WITH 'myproject.' RETURN c.name AS name, c.qualified_name AS qualified_name, labels(c) AS type LIMIT 105. 装饰器/标注查询、关键字检索、找文件
装饰器用IN运算符匹配decorators列表属性;通用关键字检索用CONTAINS兜底;找文件同时匹配name与path。提示词中还明确要求:
- 始终返回带别名的具体属性,不要
RETURN n返回整节点; - 路径匹配一律
STARTS WITH,避免用=; - 生成的是只读查询,输出仅包含 Cypher 本身。
这些规则共同保证了生成结果与知识图谱 Schema(见 codebase_rag/schema_builder.py)对齐,可直接交由查询层执行。
七、常见问题与使用建议
Q1:没有配任何密钥,能不能直接用?可以,但前提是本机 Ollama 可用且装有默认模型;否则构造时抛LLMGenerationError。云端场景请先设置CYPHER_PROVIDER/CYPHER_MODEL/CYPHER_API_KEY或调用settings.set_cypher(...)。
Q2:生成的查询会被拒绝吗?会。任何包含DELETE/CREATE/MERGE/SET/DROP...的写操作、无上界变长路径、白名单外的CALL过程都会被拦截并抛异常。这是刻意设计:CypherGenerator只产出只读查询。
Q3:模型输出带 Markdown 怎么办?无需担心,_clean_cypher_response会自动剥离 ``` 代码块、**粗体、反引号和多余的cypher前缀,并补齐分号。
Q4:如何挑选模型?云端任务优先选择文档示例中的快速模型(如gemini-3.5-flash-lite、claude-haiku-4-5)以降本增效;本地离线场景选 Ollama 的代码类模型(qwen2.5-coder),系统会自动切换为更严格的本地提示词。
实践建议:将CypherGenerator与 MemgraphIngestor 组合使用——前者负责把自然语言转成查询,后者负责执行并把结果返回给上层 Agent,形成"提问 → 生成 → 执行 → 回答"的完整 RAG 闭环;多项目场景记得利用active_projects参数(CypherGenerator(active_projects=[...]))把生成范围收敛到指定仓库,减少跨项目误匹配。
八、小结
CypherGenerator是 Code-Graph-RAG 面向"人类/Agent 提问 → 图谱查询"的关键桥梁。它把模型选型收敛为一行set_cypher或几个环境变量,把安全收敛为生成后的三道强制校验(只读关键字、无界路径、过程白名单),把质量收敛为内嵌查询范式的系统提示词。对集成开发者而言,记住三个要点即可稳定使用:先配置再构造、只读输出可直接执行、失败统一捕获LLMGenerationError。相关实现与测试均可继续在 codebase_rag/services/llm.py、codebase_rag/constants/security.py、codebase_rag/cypher_queries.py 以及测试目录codebase_rag/tests/(如test_cypher_project_scope.py)中深入阅读。
【免费下载链接】code-graph-ragThe ultimate RAG for your monorepo. Query, understand, and edit multi-language codebases with the power of AI and knowledge graphs项目地址: https://gitcode.com/GitHub_Trending/co/code-graph-rag
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考