test_text2mem.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import pytest
  2. import app.adapters.text2mem as module
  3. from app.adapters.text2mem import Text2MemAgent
  4. from app.db import MemoryRepository
  5. from app.llm import LLMUnavailable
  6. class OfflineLLM:
  7. async def chat(self, *_args, **_kwargs):
  8. raise LLMUnavailable("test offline")
  9. class DisabledEmbedding:
  10. configured = False
  11. class FailingLLM:
  12. async def chat(self, *_args, **_kwargs):
  13. raise RuntimeError("temporary provider failure")
  14. def build_agent(monkeypatch, tmp_path) -> tuple[Text2MemAgent, MemoryRepository]:
  15. repo = MemoryRepository()
  16. repo.path = tmp_path / "memory.json"
  17. monkeypatch.setattr(module, "embedding_client", DisabledEmbedding())
  18. agent = Text2MemAgent()
  19. agent.repo = repo
  20. agent.llm = OfflineLLM()
  21. return agent, repo
  22. @pytest.mark.asyncio
  23. async def test_text2mem_explicit_write(monkeypatch, tmp_path):
  24. agent, repo = build_agent(monkeypatch, tmp_path)
  25. response = await agent.chat("记住:我偏好使用 Python 和 FastAPI")
  26. assert response.system == "text2mem"
  27. assert response.memory_events[0]["status"] == "created"
  28. memories = await repo.list_memories("text2mem")
  29. assert memories[0].content.startswith("记住")
  30. assert memories[0].memory_type == "semantic"
  31. @pytest.mark.asyncio
  32. async def test_text2mem_writes_all_four_memory_types_and_does_not_store_question(
  33. monkeypatch,
  34. tmp_path,
  35. ):
  36. agent, repo = build_agent(monkeypatch, tmp_path)
  37. statements = [
  38. "记住:我偏好使用 Python 和 FastAPI,代码要求严格类型注解。",
  39. "我正在开发一个企业内部智能知识库问答项目,使用通义千问和 RAG。",
  40. "更新一下:检索重排功能已经完成 75%,下一步补充效果评测集。",
  41. "上次部署测试环境时遇到向量索引构建超时,最后通过分批导入文档解决。",
  42. "以后修复代码时按这个流程:先复现问题,再定位原因,修改后运行测试。",
  43. ]
  44. for statement in statements:
  45. await agent.chat(statement)
  46. memories = await repo.list_memories("text2mem")
  47. assert len(memories) == 5
  48. assert [item.memory_type for item in memories].count("semantic") == 2
  49. assert {item.memory_type for item in memories} == {
  50. "semantic",
  51. "episodic",
  52. "procedural",
  53. "task-state",
  54. }
  55. response = await agent.chat("上次部署遇到了什么问题?")
  56. assert len(await repo.list_memories("text2mem")) == 5
  57. assert response.memory_events == []
  58. assert any("向量索引构建超时" in item.content for item in response.memory_context)
  59. assert all(item.memory_type == "episodic" for item in response.memory_context)
  60. def test_text2mem_write_classifier_rejects_normal_questions():
  61. assert Text2MemAgent._should_encode("我的项目使用什么数据库?") is False
  62. assert Text2MemAgent._should_encode("上次部署遇到了什么问题?") is False
  63. assert Text2MemAgent._should_encode("记住:项目数据库使用 PostgreSQL。") is True
  64. @pytest.mark.asyncio
  65. async def test_text2mem_falls_back_when_configured_model_call_fails(monkeypatch, tmp_path):
  66. agent, _ = build_agent(monkeypatch, tmp_path)
  67. agent.llm = FailingLLM()
  68. response = await agent.chat("记住:我偏好使用 Python 和 FastAPI。")
  69. assert response.mode == "local-fallback"
  70. assert "模型调用失败" in response.answer
  71. assert response.memory_events[0]["status"] == "created"