docs(agent): 添加防止幻觉的验证指南和使用警告

在多个agent文件中添加详细的防止幻觉验证指南,包括:
1. 必须验证文件存在性和代码匹配性
2. 禁止猜测文件路径和行号
3. 知识库示例与实际代码的区分警告
4. 添加语言检测功能以提醒语言不匹配情况
This commit is contained in:
lintsinghua 2025-12-19 19:14:23 +08:00
parent 80704fdcb4
commit b0f17d50db
4 changed files with 151 additions and 9 deletions

View File

@ -211,6 +211,31 @@ Action Input: {"target_path": ".", "rules": "auto"}
3. **上下文分析** - 看到可疑代码要读取上下文理解完整逻辑 3. **上下文分析** - 看到可疑代码要读取上下文理解完整逻辑
4. **自主判断** - 不要机械相信工具输出要用你的专业知识判断 4. **自主判断** - 不要机械相信工具输出要用你的专业知识判断
## 🚨 知识工具使用警告(防止幻觉!)
**知识库中的代码示例仅供概念参考不是实际代码**
当你使用 `get_vulnerability_knowledge` `query_security_knowledge`
1. **知识示例 项目代码** - 知识库的代码示例是通用示例不是目标项目的代码
2. **语言可能不匹配** - 知识库可能返回 Python 示例但项目可能是 PHP/Rust/Go
3. **必须在实际代码中验证** - 你只能报告你在 read_file **实际看到**的漏洞
4. **禁止推测** - 不要因为知识库说"这种模式常见"就假设项目中存在
错误做法幻觉来源
```
1. 查询 auth_bypass 知识 -> 看到 JWT 示例
2. 没有在项目中找到 JWT 代码
3. 仍然报告 "JWT 认证绕过漏洞" <- 这是幻觉
```
正确做法
```
1. 查询 auth_bypass 知识 -> 了解认证绕过的概念
2. 使用 read_file 读取项目的认证代码
3. 只有**实际看到**有问题的代码才报告漏洞
4. file_path 必须是你**实际读取过**的文件
```
## ⚠️ 关键约束 - 必须遵守! ## ⚠️ 关键约束 - 必须遵守!
1. **禁止直接输出 Final Answer** - 你必须先调用工具来分析代码 1. **禁止直接输出 Final Answer** - 你必须先调用工具来分析代码
2. **至少调用两个工具** - 使用 smart_scan/semgrep_scan 进行扫描然后用 read_file 查看代码 2. **至少调用两个工具** - 使用 smart_scan/semgrep_scan 进行扫描然后用 read_file 查看代码

View File

@ -154,6 +154,35 @@ Final Answer: {
- `line_start`: 行号 - `line_start`: 行号
- `description`: 详细描述 - `description`: 详细描述
## 🚨 防止幻觉(关键!)
**只报告你实际读取过的文件**
1. **file_path 必须来自实际工具调用结果**
- 只使用 list_files 返回的文件列表中的路径
- 只使用 read_file 成功读取的文件路径
- 不要"猜测"典型的项目结构 app.py, config.py
2. **行号必须来自实际代码**
- 只使用 read_file 返回内容中的真实行号
- 不要编造行号
3. **禁止套用模板**
- 不要因为是 "Python 项目" 就假设存在 requirements.txt
- 不要因为是 "Web 项目" 就假设存在 routes.py views.py
错误做法
```
list_files 返回: ["main.rs", "lib.rs", "Cargo.toml"]
high_risk_areas: ["app.py:36 - 存在安全问题"] <- 这是幻觉项目根本没有 app.py
```
正确做法
```
list_files 返回: ["main.rs", "lib.rs", "Cargo.toml"]
high_risk_areas: ["main.rs:xx - 可能存在问题"] <- 必须使用实际存在的文件
```
## ⚠️ 关键约束 - 必须遵守! ## ⚠️ 关键约束 - 必须遵守!
1. **禁止直接输出 Final Answer** - 你必须先调用工具来收集项目信息 1. **禁止直接输出 Final Answer** - 你必须先调用工具来收集项目信息
2. **至少调用三个工具** - 使用 rag_query 语义搜索关键入口read_file 读取文件list_files 仅查看根目录 2. **至少调用三个工具** - 使用 rag_query 语义搜索关键入口read_file 读取文件list_files 仅查看根目录

View File

@ -282,6 +282,33 @@ Action Input: {"file_path": "search.php"}
- **uncertain**: 需要更多信息才能判断 - **uncertain**: 需要更多信息才能判断
- **false_positive**: 确认是误报有明确理由 - **false_positive**: 确认是误报有明确理由
## 🚨 防止幻觉验证(关键!)
**Analysis Agent 可能报告不存在的文件** 你必须验证
1. **文件必须存在** - 使用 read_file 读取发现中指定的文件
- 如果 read_file 返回"文件不存在"该发现是 **false_positive**
- 不要尝试"猜测"正确的文件路径
2. **代码必须匹配** - 发现中的 code_snippet 必须在文件中真实存在
- 如果文件内容与描述不符该发现是 **false_positive**
3. **不要"填补"缺失信息** - 如果发现缺少关键信息如文件路径为空标记为 uncertain
错误做法
```
发现: "SQL注入在 api/database.py:45"
read_file 返回: "文件不存在"
判定: confirmed <- 这是错误的
```
正确做法
```
发现: "SQL注入在 api/database.py:45"
read_file 返回: "文件不存在"
判定: false_positive理由: "文件 api/database.py 不存在"
```
## ⚠️ 关键约束 ## ⚠️ 关键约束
1. **必须先调用工具验证** - 不允许仅凭已知信息直接判断 1. **必须先调用工具验证** - 不允许仅凭已知信息直接判断
2. **优先使用 run_code** - 编写 Harness 进行动态验证 2. **优先使用 run_code** - 编写 Harness 进行动态验证

View File

@ -126,6 +126,10 @@ class VulnerabilityKnowledgeInput(BaseModel):
..., ...,
description="漏洞类型,如: sql_injection, xss, command_injection, path_traversal, ssrf, deserialization, hardcoded_secrets, auth_bypass" description="漏洞类型,如: sql_injection, xss, command_injection, path_traversal, ssrf, deserialization, hardcoded_secrets, auth_bypass"
) )
project_language: Optional[str] = Field(
None,
description="目标项目的主要编程语言(如 python, php, javascript, rust, go用于过滤相关示例"
)
class GetVulnerabilityKnowledgeTool(AgentTool): class GetVulnerabilityKnowledgeTool(AgentTool):
@ -165,7 +169,7 @@ class GetVulnerabilityKnowledgeTool(AgentTool):
def args_schema(self) -> Type[BaseModel]: def args_schema(self) -> Type[BaseModel]:
return VulnerabilityKnowledgeInput return VulnerabilityKnowledgeInput
async def _execute(self, vulnerability_type: str) -> ToolResult: async def _execute(self, vulnerability_type: str, project_language: Optional[str] = None) -> ToolResult:
"""获取漏洞知识""" """获取漏洞知识"""
try: try:
knowledge = await security_knowledge_rag.get_vulnerability_knowledge( knowledge = await security_knowledge_rag.get_vulnerability_knowledge(
@ -191,13 +195,41 @@ class GetVulnerabilityKnowledgeTool(AgentTool):
if knowledge.get("owasp_ids"): if knowledge.get("owasp_ids"):
output_parts.append(f"OWASP: {', '.join(knowledge['owasp_ids'])}") output_parts.append(f"OWASP: {', '.join(knowledge['owasp_ids'])}")
# 🔥 v2.2: 添加语言不匹配警告
content = knowledge.get("content", "")
knowledge_lang = self._detect_code_language(content)
if project_language and knowledge_lang:
project_lang_lower = project_language.lower()
if knowledge_lang.lower() != project_lang_lower:
output_parts.append("")
output_parts.append("=" * 60)
output_parts.append(f"⚠️ **重要警告**: 以下示例代码是 {knowledge_lang.upper()} 语言")
output_parts.append(f" 你正在审计的项目是 {project_language.upper()} 项目")
output_parts.append(" **这些代码示例仅供概念参考,不要直接套用到目标项目!**")
output_parts.append(" 请在目标项目中查找该语言特有的等效漏洞模式。")
output_parts.append("=" * 60)
output_parts.append("") output_parts.append("")
output_parts.append(knowledge.get("content", "")) output_parts.append(content)
# 🔥 v2.2: 添加使用指南
output_parts.append("")
output_parts.append("---")
output_parts.append("📌 **使用指南**:")
output_parts.append("1. 以上知识仅供参考,你必须在实际代码中验证漏洞是否存在")
output_parts.append("2. 不要假设项目中存在示例中的代码模式")
output_parts.append("3. 只有在 read_file 读取到的代码中确实存在问题时才报告漏洞")
output_parts.append("4. 如果示例语言与项目语言不同,请查找该语言的等效漏洞模式")
return ToolResult( return ToolResult(
success=True, success=True,
data="\n".join(output_parts), data="\n".join(output_parts),
metadata=knowledge, metadata={
**knowledge,
"knowledge_language": knowledge_lang,
"project_language": project_language,
},
) )
except Exception as e: except Exception as e:
@ -207,6 +239,35 @@ class GetVulnerabilityKnowledgeTool(AgentTool):
error=f"获取漏洞知识失败: {str(e)}", error=f"获取漏洞知识失败: {str(e)}",
) )
def _detect_code_language(self, content: str) -> Optional[str]:
"""检测知识内容中的主要代码语言"""
# 检测代码块中的语言标记
import re
code_blocks = re.findall(r'```(\w+)', content)
if code_blocks:
# 统计最常见的语言
from collections import Counter
lang_counts = Counter(code_blocks)
most_common = lang_counts.most_common(1)
if most_common:
return most_common[0][0]
# 基于内容特征检测
if "def " in content or "import " in content or "@app.route" in content:
return "python"
if "<?php" in content or "$_GET" in content or "$_POST" in content:
return "php"
if "function " in content and ("const " in content or "let " in content):
return "javascript"
if "func " in content and "package " in content:
return "go"
if "fn " in content and "let mut" in content:
return "rust"
if "public class" in content or "private void" in content:
return "java"
return None
class ListKnowledgeModulesInput(BaseModel): class ListKnowledgeModulesInput(BaseModel):
"""列出知识模块输入""" """列出知识模块输入"""