chore: 清理违反底座规则的死代码并修正接口文档编号

- 删除生产死代码 app/service/knowledge_tool_service.py 与
  app/infrastructure/milvus_knowledge_adapter.py:后者硬编码 Milvus 字段名,
  违反 AGENTS.md §E,且仅被前者引用;生产检索链路实际走
  knowledge_search_tool -> KnowledgeSearchService -> knowledge_schema 运行时探测。
- 删除上述两模块的单测,以及依赖 legacy 位置参数构造的
  tests/unit/service/test_knowledge_retrieval.py。
- app/service/knowledge_retrieval_service.py 整文件回退底座版本,
  移除 legacy 双构造与重复检索实现。
- docs/05-接口文档.md:客服画像候选改登记为 §8.5,恢复 §8.2 解析知识引用;
  既有 §8.1-§8.4 编号全部保持,修复此前出现两个 8.3 的问题。
- app/model/profile.py:current_customer_id 改为普通可空列映射,与
  alembic/baseline_generated.sql 及真实库一致;原 Computed 声明会让 ORM 把该列
  从 INSERT 中排除,与「必须显式写入」的实际 schema 不符。
- 新增 docs/客服Agent接入底座扩展说明_v1.md,供集成分支评审逐项确认。

验证:pytest tests/unit tests/contract -> 1275 passed, 2 skipped, 0 failed;
ruff check app tests tools alembic 通过;mypy app 通过(244 个源文件)。
This commit is contained in:
张胜宇
2026-09-12 11:15:24 +08:00
parent e85989b344
commit 9aaacc242f
9 changed files with 189 additions and 483 deletions
@@ -1,47 +0,0 @@
import pytest
from app.core.errors import ForbiddenAgentError
from app.infrastructure.milvus_knowledge_adapter import MilvusKnowledgeClient
class FakeMilvus:
def __init__(self) -> None:
self.kwargs = None
async def search(self, **kwargs):
self.kwargs = kwargs
return [[{
"distance": 0.91,
"entity": {
"knowledge_id": "101",
"snippet": "开户说明",
"title": "基金开户",
"tags": ["开户"],
"version": "v1",
},
}]]
@pytest.mark.asyncio
async def test_knowledge_adapter_uses_cosine_and_minimal_public_projection() -> None:
client = MilvusKnowledgeClient("http://unused")
fake = FakeMilvus()
client._client = fake
hits = await client.search("fin_faq_collection", [0.1] * 1024, 3)
assert hits[0]["knowledge_id"] == "101"
assert hits[0]["snippet"] == "开户说明"
assert hits[0]["score"] == 0.91
assert fake.kwargs["collection_name"] == "fin_faq_collection"
assert fake.kwargs["limit"] == 3
assert fake.kwargs["search_params"] == {"metric_type": "COSINE"}
assert fake.kwargs["output_fields"] == ["knowledge_id", "title", "snippet", "tags", "version"]
@pytest.mark.asyncio
async def test_knowledge_adapter_rejects_non_public_collection() -> None:
client = MilvusKnowledgeClient("http://unused")
with pytest.raises(ForbiddenAgentError):
await client.search("customer_vectors", [0.1] * 1024, 3)