docs: 品牌全量口径统一为「南方基金」+ 作废文档清理

1) 客服 Agent 四份交付文档 + 构建脚手架:品牌由包装占位 XX科技 / 旧名 南方财富
   统一为南方基金(热线 400-889-8899 / 官网 nffund.com),系统名改为「智能服务系统」;
   同步追加 §0.4 修订记录行,工程记录行保留原占位字面以支撑硬编码扫描验收。
2) 开发文档:清理 28 份已作废/残留文档(14 份移出归档 + 14 份仓库副本),
   新增《文档规整方案与开发前待决事项-2026-09-17》。
3) 客服agent 四份交付文档首次纳入本分支。
This commit is contained in:
张胜宇
2026-09-17 15:15:22 +08:00
commit e239eb778b
874 changed files with 188418 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
"""Neo4j 图驱动:把 neo4j 异步驱动封装成 `RelationshipService` 期望的 `GraphDriver` 协议。
为什么单独一层:`RelationshipService` 只依赖 `execute_query(query, **params)` 这个窄协议,
不关心底层是哪个驱动。有这一层,读服务、投影 worker、删除客户端就能共用同一套连接管理,
也便于测试注入替身。
**这层此前是空的** —— `app/service/relationship_service.py` 里的 `GraphDriver` 只有一个
Protocol 声明,没有任何具体实现,组装层也没有装配它,所以读服务在运行期必然降级
(`neo4j_unavailable`),这正是"Neo4j 连读适配器都没有"的根因。
降级语义与 Milvus 侧保持一致:本层**不吞异常**(由调用方决定降级方式),但**构造失败返回 None**
——图库不可用不该让应用起不来,也不该阻塞主链路。
"""
import logging
from collections.abc import Sequence
from typing import Any
from app.core.config import get_settings
logger = logging.getLogger(__name__)
class Neo4jGraphDriver:
"""`GraphDriver` 协议的 neo4j 实现。"""
def __init__(self, driver: Any, database: str) -> None:
self._driver = driver
self._database = database
async def execute_query(self, query: str, **parameters: Any) -> Sequence[Any]:
"""执行一条 Cypher 并返回记录列表。
查询文本由调用方提供(`RelationshipService` 与投影 worker 各自持有白名单:
前者限制关系类型,后者只接受 `ALLOWED_RELATIONSHIPS` 中的关系),本层不做校验,
只负责执行与结果整形——把校验放在拥有业务语义的地方,避免两处规则漂移。
"""
async with self._driver.session(database=self._database) as session:
result = await session.run(query, **parameters)
return list(await result.data())
async def close(self) -> None:
await self._driver.close()
def build_graph_driver() -> Neo4jGraphDriver | None:
"""按配置构造图驱动;依赖缺失或配置不全时返回 None(图能力关闭)。
与 `get_vector_memory_adapter` 同一取向:外部依赖不可用只关闭对应能力,
不让整个应用起不来。
"""
settings = get_settings()
if not settings.neo4j_uri or not settings.neo4j_password:
logger.warning("neo4j config incomplete; graph capability disabled")
return None
try:
from neo4j import AsyncGraphDatabase
except ImportError:
logger.warning("neo4j driver not installed; graph capability disabled")
return None
driver = AsyncGraphDatabase.driver(
settings.neo4j_uri, auth=(settings.neo4j_username, settings.neo4j_password)
)
return Neo4jGraphDriver(driver, settings.neo4j_database)