docs(agent): 添加防止幻觉的验证指南和使用警告
在多个agent文件中添加详细的防止幻觉验证指南,包括: 1. 必须验证文件存在性和代码匹配性 2. 禁止猜测文件路径和行号 3. 知识库示例与实际代码的区分警告 4. 添加语言检测功能以提醒语言不匹配情况
This commit is contained in:
parent
80704fdcb4
commit
b0f17d50db
|
|
@ -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 查看代码
|
||||||
|
|
|
||||||
|
|
@ -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 仅查看根目录
|
||||||
|
|
|
||||||
|
|
@ -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 进行动态验证
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
"""列出知识模块输入"""
|
"""列出知识模块输入"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue