完成和大模型的通信
This commit is contained in:
42
tests/test_analysis_prompt.py
Normal file
42
tests/test_analysis_prompt.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""分析提示构建函数测试。"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
from prompt import build_analysis_prompt
|
||||
|
||||
|
||||
class TestBuildAnalysisPrompt:
|
||||
"""测试分析提示构建函数。"""
|
||||
|
||||
def test_basic_prompt(self) -> None:
|
||||
"""测试基础提示词包含核心结构。"""
|
||||
prompt = build_analysis_prompt(purpose="", index="")
|
||||
assert "专业研究分析师" in prompt
|
||||
assert "关键实体" in prompt
|
||||
|
||||
def test_with_purpose(self) -> None:
|
||||
"""测试传入目的时,提示词包含 Wiki 目的部分。"""
|
||||
prompt = build_analysis_prompt(purpose="测试目的", index="")
|
||||
assert "Wiki 目的" in prompt
|
||||
assert "测试目的" in prompt
|
||||
|
||||
def test_with_index(self) -> None:
|
||||
"""测试传入索引时,提示词包含 Wiki 索引部分。"""
|
||||
prompt = build_analysis_prompt(purpose="", index="测试索引")
|
||||
assert "当前 Wiki 索引" in prompt
|
||||
assert "测试索引" in prompt
|
||||
|
||||
def test_empty_content(self) -> None:
|
||||
"""测试空内容时,可选部分不出现在提示词中。"""
|
||||
prompt = build_analysis_prompt(purpose="", index="")
|
||||
assert "Wiki 目的" not in prompt
|
||||
assert "当前 Wiki 索引" not in prompt
|
||||
|
||||
def test_language_from_config(self) -> None:
|
||||
"""测试语言设置从配置文件读取。"""
|
||||
prompt = build_analysis_prompt(purpose="", index="", configured_language=None)
|
||||
assert "使用" in prompt
|
||||
assert "语言输出分析报告" in prompt
|
||||
23
tests/test_config.py
Normal file
23
tests/test_config.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""配置加载模块测试。"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
from config import get_language, load_config
|
||||
|
||||
|
||||
class TestConfig:
|
||||
"""测试配置加载模块。"""
|
||||
|
||||
def test_load_config_returns_dict(self) -> None:
|
||||
"""测试 load_config 返回字典且包含 language 键。"""
|
||||
config = load_config()
|
||||
assert isinstance(config, dict)
|
||||
assert "language" in config
|
||||
|
||||
def test_get_language_from_config(self) -> None:
|
||||
"""测试 get_language 能正常返回语言设置。"""
|
||||
language = get_language()
|
||||
assert language is not None
|
||||
32
tests/test_language_rule.py
Normal file
32
tests/test_language_rule.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""语言规则生成函数测试。"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
from prompt import language_rule
|
||||
|
||||
|
||||
class TestLanguageRule:
|
||||
"""测试语言规则生成函数。"""
|
||||
|
||||
def test_explicit_language(self) -> None:
|
||||
"""测试显式指定语言时,提示中包含该语言名称。"""
|
||||
result = language_rule("test content", "Chinese")
|
||||
assert "Chinese" in result
|
||||
|
||||
def test_auto_with_chinese_content(self) -> None:
|
||||
"""测试中文内容自动检测。"""
|
||||
result = language_rule("这是一段中文内容", None)
|
||||
assert "简体中文" in result
|
||||
|
||||
def test_auto_with_english_content(self) -> None:
|
||||
"""测试英文内容自动检测。"""
|
||||
result = language_rule("This is English content", None)
|
||||
assert "源文档" in result
|
||||
|
||||
def test_auto_detection_string(self) -> None:
|
||||
"""测试传入 "auto" 字符串时触发自动检测。"""
|
||||
result = language_rule("test", "auto")
|
||||
assert "源文档" in result
|
||||
128
tests/test_llm.py
Normal file
128
tests/test_llm.py
Normal file
@@ -0,0 +1,128 @@
|
||||
"""LLM 模块测试。"""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
|
||||
class TestCreateLLM:
|
||||
"""测试 LLM 实例创建。"""
|
||||
|
||||
@patch("config.get_llm_config")
|
||||
@patch("llama_index.llms.openai_like.OpenAILike")
|
||||
def test_create_llm_uses_config(self, mock_openai_like, mock_get_config):
|
||||
"""测试 _create_llm 使用配置文件中的参数。"""
|
||||
mock_get_config.return_value = {
|
||||
"model": "qwen/qwen3.6-27b",
|
||||
"api_base": "http://100.123.83.113:1234/v1",
|
||||
"api_key": "123456",
|
||||
}
|
||||
|
||||
from llm import _create_llm
|
||||
|
||||
_create_llm()
|
||||
|
||||
mock_openai_like.assert_called_once_with(
|
||||
model="qwen/qwen3.6-27b",
|
||||
api_base="http://100.123.83.113:1234/v1",
|
||||
api_key="123456",
|
||||
temperature=0.1,
|
||||
max_tokens=128000,
|
||||
request_timeout=300.0,
|
||||
is_chat_model=True,
|
||||
)
|
||||
|
||||
|
||||
class TestQueryAnalysis:
|
||||
"""测试 query_analysis 端到端流程。"""
|
||||
|
||||
@patch("llm._create_llm")
|
||||
@patch("llm.build_analysis_prompt")
|
||||
def test_query_analysis_calls_llm(self, mock_prompt, mock_create_llm):
|
||||
"""测试 query_analysis 正确调用 prompt 构建和 LLM stream_chat。"""
|
||||
mock_prompt.return_value = "test prompt"
|
||||
mock_llm = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.delta = "analysis result"
|
||||
mock_llm.stream_chat.return_value = [mock_resp]
|
||||
mock_create_llm.return_value = mock_llm
|
||||
|
||||
from llm import query_analysis
|
||||
|
||||
result = query_analysis(purpose="test purpose", index="test index")
|
||||
|
||||
mock_prompt.assert_called_once_with(
|
||||
"test purpose",
|
||||
"test index",
|
||||
source_content="",
|
||||
configured_language=None,
|
||||
)
|
||||
assert mock_llm.stream_chat.called
|
||||
assert result == "analysis result"
|
||||
|
||||
@patch("llm._create_llm")
|
||||
@patch("llm.build_analysis_prompt")
|
||||
def test_query_analysis_passes_source_content(self, mock_prompt, mock_create_llm):
|
||||
"""测试 source_content 正确传递。"""
|
||||
mock_prompt.return_value = "test prompt"
|
||||
mock_llm = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.delta = "result"
|
||||
mock_llm.stream_chat.return_value = [mock_resp]
|
||||
mock_create_llm.return_value = mock_llm
|
||||
|
||||
from llm import query_analysis
|
||||
|
||||
query_analysis(
|
||||
purpose="",
|
||||
index="",
|
||||
source_content="some source",
|
||||
configured_language="English",
|
||||
)
|
||||
|
||||
mock_prompt.assert_called_once_with(
|
||||
"",
|
||||
"",
|
||||
source_content="some source",
|
||||
configured_language="English",
|
||||
)
|
||||
|
||||
@patch("llm._create_llm")
|
||||
@patch("llm.build_analysis_prompt")
|
||||
def test_query_analysis_returns_text(self, mock_prompt, mock_create_llm):
|
||||
"""测试返回值是纯文本字符串。"""
|
||||
mock_prompt.return_value = "prompt"
|
||||
mock_llm = MagicMock()
|
||||
mock_resp1 = MagicMock()
|
||||
mock_resp1.delta = "## 关键实体\n"
|
||||
mock_resp2 = MagicMock()
|
||||
mock_resp2.delta = "- 测试实体"
|
||||
mock_llm.stream_chat.return_value = [mock_resp1, mock_resp2]
|
||||
mock_create_llm.return_value = mock_llm
|
||||
|
||||
from llm import query_analysis
|
||||
|
||||
result = query_analysis(purpose="", index="")
|
||||
|
||||
assert isinstance(result, str)
|
||||
assert "关键实体" in result
|
||||
|
||||
@patch("llm._create_llm")
|
||||
@patch("llm.build_analysis_prompt")
|
||||
def test_query_analysis_empty_response(self, mock_prompt, mock_create_llm):
|
||||
"""测试 LLM 返回空字符串时不会崩溃。"""
|
||||
mock_prompt.return_value = "prompt"
|
||||
mock_llm = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.delta = ""
|
||||
mock_llm.stream_chat.return_value = [mock_resp]
|
||||
mock_create_llm.return_value = mock_llm
|
||||
|
||||
from llm import query_analysis
|
||||
|
||||
result = query_analysis(purpose="", index="")
|
||||
|
||||
assert result == ""
|
||||
@@ -1,145 +0,0 @@
|
||||
"""主模块测试套件。
|
||||
|
||||
本文件包含三个测试类,分别覆盖:
|
||||
1. 配置加载功能(从 config.json 读取项目设置)
|
||||
2. 语言规则生成(根据配置或自动检测确定输出语言)
|
||||
3. 分析提示构建(组装完整的 AI 分析提示词)
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# 将 src 目录加入 Python 路径,使测试可以导入项目模块
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
||||
|
||||
from config import get_language, load_config
|
||||
from main import build_analysis_prompt, language_rule
|
||||
|
||||
|
||||
class TestConfig:
|
||||
"""测试配置加载模块。
|
||||
|
||||
验证 config.json 能否被正确读取,以及语言设置是否能正常获取。
|
||||
"""
|
||||
|
||||
def test_load_config_returns_dict(self) -> None:
|
||||
"""测试 load_config 返回字典且包含 language 键。
|
||||
|
||||
验证配置文件的解析结果是一个字典结构,
|
||||
并且其中包含必需的 language 字段。
|
||||
"""
|
||||
config = load_config()
|
||||
assert isinstance(config, dict)
|
||||
assert "language" in config
|
||||
|
||||
def test_get_language_from_config(self) -> None:
|
||||
"""测试 get_language 能正常返回语言设置。
|
||||
|
||||
当 config.json 中 language 不为 "auto" 时,
|
||||
get_language 应返回非 None 值。
|
||||
"""
|
||||
language = get_language()
|
||||
assert language is not None
|
||||
|
||||
|
||||
class TestLanguageRule:
|
||||
"""测试语言规则生成函数。
|
||||
|
||||
language_rule 负责根据配置或源文档内容,
|
||||
生成指导 AI 输出语言的提示文本。
|
||||
"""
|
||||
|
||||
def test_explicit_language(self) -> None:
|
||||
"""测试显式指定语言时,提示中包含该语言名称。
|
||||
|
||||
当 configured_language 为 "Chinese" 时,
|
||||
返回的提示应包含 "Chinese" 字样。
|
||||
"""
|
||||
result = language_rule("test content", "Chinese")
|
||||
assert "Chinese" in result
|
||||
|
||||
def test_auto_with_chinese_content(self) -> None:
|
||||
"""测试中文内容自动检测。
|
||||
|
||||
当源文档包含中文字符且未指定语言时,
|
||||
应自动选择简体中文作为输出语言。
|
||||
"""
|
||||
result = language_rule("这是一段中文内容", None)
|
||||
assert "简体中文" in result
|
||||
|
||||
def test_auto_with_english_content(self) -> None:
|
||||
"""测试英文内容自动检测。
|
||||
|
||||
当源文档为纯英文且未指定语言时,
|
||||
应返回跟随源文档语言的提示。
|
||||
"""
|
||||
result = language_rule("This is English content", None)
|
||||
assert "源文档" in result
|
||||
|
||||
def test_auto_detection_string(self) -> None:
|
||||
"""测试传入 "auto" 字符串时触发自动检测。
|
||||
|
||||
"auto" 和 None 等效,都表示启用自动语言检测。
|
||||
"""
|
||||
result = language_rule("test", "auto")
|
||||
assert "源文档" in result
|
||||
|
||||
|
||||
class TestBuildAnalysisPrompt:
|
||||
"""测试分析提示构建函数。
|
||||
|
||||
build_analysis_prompt 负责将 wiki 目的、索引、
|
||||
源文档内容和语言设置组装成完整的 AI 提示词。
|
||||
"""
|
||||
|
||||
def test_basic_prompt(self) -> None:
|
||||
"""测试基础提示词包含核心结构。
|
||||
|
||||
即使目的和索引都为空,提示词仍应包含
|
||||
角色定义(专业研究分析师)和分析框架(关键实体)。
|
||||
"""
|
||||
prompt = build_analysis_prompt(purpose="", index="")
|
||||
assert "专业研究分析师" in prompt
|
||||
assert "关键实体" in prompt
|
||||
|
||||
def test_with_purpose(self) -> None:
|
||||
"""测试传入目的时,提示词包含 Wiki 目的部分。
|
||||
|
||||
当 purpose 参数非空时,生成的提示词应包含
|
||||
"Wiki 目的" 标题和传入的目的内容。
|
||||
"""
|
||||
prompt = build_analysis_prompt(purpose="测试目的", index="")
|
||||
assert "Wiki 目的" in prompt
|
||||
assert "测试目的" in prompt
|
||||
|
||||
def test_with_index(self) -> None:
|
||||
"""测试传入索引时,提示词包含 Wiki 索引部分。
|
||||
|
||||
当 index 参数非空时,生成的提示词应包含
|
||||
"当前 Wiki 索引" 标题和传入的索引内容。
|
||||
"""
|
||||
prompt = build_analysis_prompt(purpose="", index="测试索引")
|
||||
assert "当前 Wiki 索引" in prompt
|
||||
assert "测试索引" in prompt
|
||||
|
||||
def test_empty_content(self) -> None:
|
||||
"""测试空内容时,可选部分不出现在提示词中。
|
||||
|
||||
当 purpose 和 index 都为空时,
|
||||
提示词不应包含 "Wiki 目的" 和 "当前 Wiki 索引" 部分,
|
||||
以保持提示词简洁。
|
||||
"""
|
||||
prompt = build_analysis_prompt(purpose="", index="")
|
||||
assert "Wiki 目的" not in prompt
|
||||
assert "当前 Wiki 索引" not in prompt
|
||||
|
||||
def test_language_from_config(self) -> None:
|
||||
"""测试语言设置从配置文件读取。
|
||||
|
||||
当 configured_language 为 None 时,
|
||||
build_analysis_prompt 会从 config.json 读取语言设置,
|
||||
生成的提示词应包含语言规则。
|
||||
"""
|
||||
prompt = build_analysis_prompt(purpose="", index="", configured_language=None)
|
||||
assert "使用" in prompt
|
||||
assert "语言输出分析报告" in prompt
|
||||
Reference in New Issue
Block a user