Files
group_fqcd_jr/docs/evidence/20260909-environment-facts.md
T
张胜宇 e239eb778b docs: 品牌全量口径统一为「南方基金」+ 作废文档清理
1) 客服 Agent 四份交付文档 + 构建脚手架:品牌由包装占位 XX科技 / 旧名 南方财富
   统一为南方基金(热线 400-889-8899 / 官网 nffund.com),系统名改为「智能服务系统」;
   同步追加 §0.4 修订记录行,工程记录行保留原占位字面以支撑硬编码扫描验收。
2) 开发文档:清理 28 份已作废/残留文档(14 份移出归档 + 14 份仓库副本),
   新增《文档规整方案与开发前待决事项-2026-09-17》。
3) 客服agent 四份交付文档首次纳入本分支。
2026-09-17 15:15:22 +08:00

94 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 运行环境事实与前置条件(2026-09-09 实测)
本文件汇总**在本机实测确认**的运行约束,供接入方与运维在部署前核对。每条都注明是实测还是推断;
没有实测支撑的内容不写。
## 一、结论速览
| 事实 | 影响 | 处置 |
|---|---|---|
| `model_endpoint_config` 表 0 行 | `IntentClassifier` 在端点为空时按设计失败关闭(抛 `RecoverableAgentError`),run 永远进不了 `complete_run` | **接入前必须配置至少一个模型端点与一个受控备用端点** |
| 无 embedding 端点 | 记忆语义(向量)召回降级为 `embedding_failed`,结构化召回仍可用 | 需要语义召回时配置 embedding 端点;代码已就绪,无需改动 |
| Worker 未常驻运行 | Outbox 事件持续堆积(实测 262 条 pending) | 部署常驻 Worker:`python -m app.worker` |
| `dispatch_one` 每轮只领取一条事件 | 清空 262 条积压约需 262 轮(默认轮询 1 秒) | 积压深度纳入运维观测;见「五」 |
| 记忆召回有 Redis 热缓存(TTL 300 秒) | 缓存命中会短路数据库查询 | 写入路径需失效缓存;见「四」 |
## 二、数据库
- 业务表 **51 张**(另加 `alembic_version`),`head = 20260909_memory_active_key`。
- 本机库名 `jr`,连接与凭据来自 `.env` 的 `MYSQL_DSN`(`tools/` 下脚本已不再硬编码口令)。
- 三件审计工具(提交前建议全跑):
```powershell
python tools/audit_schema.py # 表与列存在性
python tools/audit_constraints.py # 文档唯一键 ↔ 库唯一索引 ↔ ORM 列名
python tools/schema_fingerprint.py # 字段+索引+外键结构指纹
```
- **由脚本或人工建起的库(有表但没有 `alembic_version` 记录)不能直接 `upgrade`**,会重建已有表而失败。
先跑 `python tools/migration_state_check.py`,按提示 `alembic stamp <版本>` 再 `upgrade head`。
## 三、模型与向量化
- 文本生成入口:`ModelGenerationService`(经 `ModelDispatchService` 受控降级),端点来自
`model_endpoint_config`(`status=active`),密钥必须是 `env:` 引用。
- 文本向量化入口:`ModelEmbeddingService`,调用 OpenAI-compatible `/embeddings`(与文本生成同族)。
- **端点缺失一律失败关闭**:意图分类、记忆抽取、向量化都不会"猜"或返回默认值——这是设计意图,
不是缺陷。它会表现为 run 失败(`AGENT_INTERNAL_ERROR`)或召回带 `embedding_failed` 降级标记。
- 记忆抽取失败时**不写入任何记忆**(宁可不记,也不落用户原文)。
## 四、中间件(实测状态)
- **Milvus**:可达。`VectorMemoryAdapter` 构造成功(实测 `type(adapter).__name__ == "VectorMemoryAdapter"`),
语义通道已接入召回链路。
- **Redis**:可达。召回缓存的读写与失效均生效(实测缓存命中 `from_cache=True`、客户级失效返回删除键数)。
Redis 不可用时缓存读写失败不阻塞召回。
- **Neo4j**:可达(连通性检查通过);关系投影由 `GraphProjectionWorker` 承担。
- 记忆召回的缓存键前缀为 `mem:recall`(`MemoryRecallService.CACHE_KEY_PREFIX`)。**任何失效逻辑都必须
复用 `MemoryRecallService.cache_keys()`**,历史上出现过清理 `mem:mid:hot:` 这种不存在的键、导致失效空转的问题。
## 五、Worker 与事件队列
- Worker 是**独立进程**:`python -m app.worker`(`--once` 只消费一次后退出)。
- `WorkerRuntime` 注册的 handler:`agent.run_requested`、`memory.extraction_requested`、
`agent.run_completed`、`config.cache_invalidate_requested`、`memory.deletion_requested`。
**未注册 handler 的事件类型会永久滞留 pending** —— 新增事件类型时必须同时注册消费者。
- 实测 `jr` 库:`agent.run_requested` pending 262 / failed 1 / dead 1;无任何记忆事件(因为当时没有
run 能成功进入 `complete_run`)。
- episode 聚合是低频批处理(每 30 轮触发一次),幂等键为 `episodes.content_hash`。
- **常驻能力**:`serve()` 内层已加单轮异常兜底(记录堆栈 → 退避 → 继续),因此数据库抖动、
迁移锁表、外部依赖瞬断不会让常驻进程整体退出;`--once` 模式保持抛出,便于诊断。
- **⚠️ 跑验收前必须先停 Worker**:`tools/acceptance_check.py` 与常驻 Worker **共享同一条
`agent_run` 队列**。Worker 会抢先领取验收创建的 run,用**生产工厂**(未注册探针 Agent)执行,
于是 run 以 `AgentTypeNotFoundError` 失败、验收出现 4 项 FAIL——这是共享队列的固有竞争,
不是缺陷。停掉 Worker 后同一命令即 7 PASS。
- **本会话启动的 Worker 是后台任务,不保证跨会话存活**。要真正常驻请在自己终端拉起
`D:\conda\envs\jr_py313\python.exe -m app.worker`,或注册为系统服务/计划任务。
- **同一开发库不要并发跑 Worker 与验收**:多进程同时消费会互相抢 run(实测出现过一次)。
## 六、认证与权限
- 鉴权链:`Authorization: Bearer <JWT>` → `JwtAuthenticator`(RS256,校验 iss/aud/nbf/exp/jti)→
`IdentityService.resolve` 实时重载角色/权限/客户归属。
- JWT 公钥在**进程内首次请求时加载一次**(`lru_cache` 单例):**轮换密钥需重启进程或清缓存**。
- `tools/seed_test_rbac.py` 用于造测试账号(实测存在客户 `9001`、风控 `9002`)。
注意权限码必须与实际工具声明一致:`check_suitability` 需要 `suitability:read`、
`query_fund_quote` 需要 `fund:quote:read`、运行受理需要 `agent:run`。
## 七、本地开发环境
- Python 解释器必须用项目专用环境:`D:\conda\envs\jr_py313\python.exe`
(系统默认 `python` 是 conda base,缺少 `asyncmy` 等依赖,直接跑 pytest 会在 `conftest` 导入处失败)。
- 质量门禁命令:
```powershell
D:\conda\envs\jr_py313\python.exe -m pytest -q tests/unit tests/contract -p no:cacheprovider
D:\conda\envs\jr_py313\python.exe -m pytest -q tests/integration -p no:cacheprovider # 需真实 MySQL
D:\conda\envs\jr_py313\python.exe -m ruff check app tests tools alembic
D:\conda\envs\jr_py313\python.exe -m mypy app # strict
```
- 集成测试真连本地 MySQL `jr`,写数据必须自行清理;`tests/integration` 下所有文件均已打
`integration` marker(此前 5 个文件漏打,按 marker 过滤会静默漏测)。
- 端到端链路验收用 `python tools/memory_chain_probe.py`(自带清理,可重复运行)。