issue-ticket-kb
README.md
# 问题工单经验知识库
面向 C 语言开发团队的内部经验库。开发者粘贴或上传已解决问题的工单、报错、代码和日志,AI 只负责整理为草稿;人工确认后才进入正式检索。系统使用 FastAPI、PostgreSQL 16 和无构建步骤的原生 HTML/JS。
这是基于公开技术栈与项目自建 synthetic 数据的个人可复现工程,不含公司、客户或真实工单数据,也不代表任何曾任职单位的官方产品。仓库中的第三方连接器仅展示接口边界与接入准备状态,不宣称已完成生产 OAuth、ACL 或真实平台联通。
## 核心不变量
- `error_raw` 入库后不可修改,API 与数据库触发器双重保护。
- AI 输出始终是 draft;正式搜索和 `/retrieval` 只返回 confirmed。
- 写入和查询共用 `app.normalize.signature()`;中文写入和查询共用 `app.segment.segment()` 的 bigram。
- dev 外部 LLM 不得接收 real 数据;mock 不联网,因此允许 real 数据完成本地演示。
- 条目没有 DELETE 接口,只能归档并恢复。
- 批量任务和进度保存在 PostgreSQL,429 暂停后可继续。
- 服务启动会把未调度的 queued 和中断的 running 任务都恢复为 paused,避免任务永久卡住或自动重复外发。
- 反馈按一次搜索记录覆盖,并从 `search_log` 聚合重算。
- MCP 只能读取 confirmed;代理提交只能生成 draft,不提供确认、归档或删除工具。
## 快速启动
要求 Python 3.11+、PostgreSQL 16,以及数据库中的 `pg_trgm` 扩展。`vector` 与 `zhparser` 都是可选项。
```bash
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
python -m pip install -r requirements.txt
cp .env.example .env # Windows: Copy-Item .env.example .env
```
编辑 `.env` 的数据库连接。无内网 AI 时使用下面的本地演示配置:
```ini
LLM_PROFILE=dev
LLM_MODE=mock
EMBEDDING_ENABLED=false
```
mock 模式没有网络请求,允许录入 real 数据;dev/openai 会在发送 real 数据前返回 403。
按顺序执行:
```bash
python scripts/check_env.py
python scripts/init_db.py
python scripts/seed.py
uvicorn app.main:app --host 127.0.0.1 --port 8000
```
打开:
- 工作台总览:`http://127.0.0.1:8000/dashboard`
- 知识检索:`http://127.0.0.1:8000/`
- 单条录入:`http://127.0.0.1:8000/submit`
- 批量导入:`http://127.0.0.1:8000/review`
- 条目维护与修订历史:`http://127.0.0.1:8000/entries`
- 分析与固定集评测:`http://127.0.0.1:8000/analytics`
- 监控日志与 AI 调用观测:`http://127.0.0.1:8000/monitor`
- MCP 与第三方连接状态:`http://127.0.0.1:8000/connectors`
- 界面偏好与运行配置:`http://127.0.0.1:8000/settings`
- 健康检查:`http://127.0.0.1:8000/healthz`
## 工程工作台
独立模式采用 Windows 设置式工程工作台:桌面端使用 180px 稳定侧栏,窄屏转换为可横向浏览并自动定位当前模块的顶部导航。顶栏持续显示服务、AI 引擎、模型、数据边界和检索降级状态;总览页集中显示待审核队列与最近更新,条目页支持 draft 确认、归档、恢复和修订历史查看。
记录人与搜索人支持团队成员快速选择(`GET /api/users` 目录 + 前端下拉),新名字保存条目时自动加入目录。条目编辑带乐观锁(`expected_version`):他人已修改时返回 409 并自动加载最新版本,避免覆盖。监控日志页(`/monitor`)每 5 秒展示最近事件流与 LLM/检索耗时统计,日志只含长度和哈希,不含密钥与原文。
设置页采用行式布局,可调整当前浏览器的主题、界面密度、默认记录人和默认搜索条数,并以脱敏方式显示 OpenCode Go 或内网 AI、PostgreSQL、扩展和 Dify Retrieval 的运行状态。连接器页独立展示 MCP 端点、鉴权状态、工具权限以及 Slack、Asana、Box 的真实接入准备状态。单条录入和批量导入同时展示当前调用边界、人工审核规则和恢复能力。AI 端点、模型与凭证只允许由服务端 `.env` 管理,修改后重启服务;v1 没有登录和权限体系,因此网页不提供 API key 输入或配置写回接口。
## MCP 与连接器
项目使用官方 MCP Python SDK 2.0,通过 `POST /mcp` 提供 Streamable HTTP。启用方式:
```ini
MCP_ENABLED=true
MCP_API_KEY=由密码管理器生成
```
迁移期如果 `MCP_API_KEY` 为空,会复用已配置的 `RETRIEVAL_API_KEY`;生产环境应拆分凭证。网页只显示是否配置,不读取或写回 Token。
| 工具 | 行为边界 |
|---|---|
| `search_knowledge` | 只检索 confirmed,返回结构化原因、方案、验证、命中来源和 `log_id`;不调用回答 LLM |
| `get_entry` | 只读取 confirmed;draft 和 archived 按不存在处理 |
| `submit_draft` | 复用抽取和数据出境守卫,固定写入 `draft`、`source=agent_session` |
| `record_feedback` | 按 `log_id` 覆盖并聚合重算,重复提交不增加计数 |
MCP 不提供 confirm、archive、DELETE 或外部服务写操作。Slack、Asana、Box 当前只有持久化目录、同步游标和来源关系基础,适配器与 OAuth/ACL 尚未接入,因此工作台明确显示“待生产接入”。完整配置与客户端说明见 [docs/mcp-setup.md](docs/mcp-setup.md)。
## Windows 桌面交付(便携包 + 安装器)
项目可打包为免安装的 Windows 桌面软件:内置便携 Python 3.12 运行时、便携
PostgreSQL 16 与 pywebview 桌面壳,双击启动、退出自动清理,数据保存在
`%LOCALAPPDATA%\IssueTicketKB`(升级/卸载不丢失)。
```powershell
python scripts/win/make_wheelhouse.py # 离线 wheel(构建机需联网一次)
python scripts/win/build_windows.py # 组装便携包 + zip + SHA256SUMS
python scripts/win/package_installer.py # Inno Setup 安装器(需装 Inno Setup 6)
powershell -ExecutionPolicy Bypass -File scripts/win/verify_windows.ps1 # 验收
```
交付说明、使用说明、验收手册见 `docs/windows/`。
## 验证
测试连接真实 PostgreSQL,不使用 mocked SQL。`pytest` 会使用
`TEST_DB_NAME` 指定的独立测试库(默认为 `<DB_NAME>_test`),首次运行会创建并
迁移该库。测试夹具只会清理带项目专用安全标记的测试库;如果
`TEST_DB_NAME` 与 `DB_NAME` 相同会立即拒绝运行。数据库角色需要 `CREATEDB`
权限,或由 DBA 预先创建一个空的测试库。
```bash
pytest -q
python -m app.eval
```
当前提交内置 28 条 confirmed synthetic 数据(含 8 条 SRS 下行权值场景)和 34 条评测用例。2026-08-31 在隔离的 PostgreSQL 16.15、Python 3.12.10、`EMBEDDING_ENABLED=false` 上实测:
| 指标 | 结果 |
|---|---:|
| pytest | 174 passed |
| Recall@5 | 1.0000 |
| MRR | 0.8978 |
| Negative pass rate | 1.0000 |
评测按 slug 引用条目,不依赖自增 id。`deepseek-v4-flash` 是移动别名,上游升级后应重新跑抽取回归和这组检索评测。真实端点验证用 `scripts/real_llm_probe.py`(只发 synthetic 数据)。
## 数据边界
| 配置 | real 数据 | 网络行为 |
|---|---|---|
| `dev/mock` | 允许 | 不发网络请求 |
| `dev/openai` | 拒绝 | synthetic 可发送到开发端点 |
| `local/mock` | 允许 | 不发网络请求 |
| `local/openai` | 允许(风险自担) | 个人本地开发档:real 会发送到配置端点,仅限负责人明示的本地使用 |
| `prod/mock` | 允许 | 不发网络请求 |
| `prod/openai` | 允许 | 端点必须是内网主机 |
`local` 档是负责人为「各自机器本地先跑先建立」明示增加的档位:与 dev 行为一致但放行 real 外发(仅个人本地开发,数据风险由使用人承担,见 [docs/OPEN-QUESTIONS.md](docs/OPEN-QUESTIONS.md));`dev` 档的 real 拒绝语义不变。启用 embedding 后执行相同的数据分类检查。prod 的 embedding 端点必须为内网;当前数据库向量列固定为 1024 维,更换模型维度前必须新增迁移。
所有密钥只放 `.env`。`.env.example` 只含占位符,应用日志只记录内容长度和 SHA-256,不记录粘贴原文。
## 许可证
代码以 [Apache License 2.0](LICENSE) 发布;示例条目和固定评测集均为项目自建 synthetic 资产,其来源字段保留在数据文件中。`requirements.txt` 中的第三方依赖未随源码 vendoring,仍分别受其 MIT、BSD、Apache、MPL、LGPL 或 PSF 等原许可证约束。
## 摄取流程
- `POST /api/ingest/preview` 接受 JSON 粘贴或 multipart 文件,预览不落库。
- 单次最多 20 个文件、单文件 10 MB;支持 UTF-8、GBK、GB18030。
- CSV/XLSX 一行一条,预览前 10 条并返回总行数;超过 500 条先提示配额风险。
- 批量页展示实际列映射。修改报错列、解决说明列或材料列后必须重新预览,任务保存最终确认的映射。
- 完整 `error_raw` 与送 AI 的截断副本分离。错误段最多发送前 4000 字,完整原文仍保存。
- `POST /api/ingest/batch` 创建持久化 job;每行独立事务,产物保持 draft。
- 批量审核必须逐条检查并 PATCH 为 confirmed 后才可搜索。
## 检索与分数
默认运行错误签名和 bigram FTS 两路;pgvector 可用且 embedding 开启时增加向量一路。三路按 `RRF_K=60` 融合,权重为 `sig=1.5`、`fts=1.0`、`vec=0.8`。
数据库还没有向量列时不会调用 embedding 服务。标题、现象、根因、方案或 aliases 被修改或合并后,旧向量会立即清空,避免语义召回使用过期内容;正式启用 embedding 前仍需补充管理员回填工具。
对外分数使用固定理论上限:
```text
score = min(1, rrf_score / (sum(weights) / (RRF_K + 1)))
```
因此同一输入的分数含义不会随候选集合变化。`matched_by` 会返回每一路的命中排名。
## 常用命令
```bash
python scripts/init_db.py # 幂等迁移,也会重试协调可选 pgvector
python scripts/seed.py # 确定性重放,不调用 AI
python scripts/gen_seed.py --only all # 从本地采集和人工审核蓝图重建 JSON,不联网
python scripts/gen_seed.py --only evals --resume
python scripts/backfill_embeddings.py # 启用 embedding 后回填被清空的向量(--dry-run 先看候选)
python scripts/real_llm_probe.py # 真实 LLM 抽取探测(dev 工具,只发 synthetic)
bash scripts/backup.sh /var/backups/kb
bash scripts/restore.sh BACKUP.dump kb_restore_drill
```
部署、systemd、logrotate 和真实恢复步骤见 [DEPLOY.md](DEPLOY.md)。MCP 配置见 [docs/mcp-setup.md](docs/mcp-setup.md),Dify 配置见 [docs/dify-setup.md](docs/dify-setup.md),上线前待确认项见 [docs/OPEN-QUESTIONS.md](docs/OPEN-QUESTIONS.md)。
## 运行限制
- v1 没有账号、权限与 SSO,必须部署在受控内网边界后。
- 批量 worker 使用 FastAPI 进程内后台任务,systemd 必须保持 `--workers 1`。状态在数据库中,服务重启会把处理中任务置为 paused,人工点击继续即可。
- `LLM_MODE=custom` 是明确保留但未实现的扩展点;当前可用模式为 mock 和 OpenAI 兼容接口。
- 不包含 Docker Compose、Kubernetes、CI、Redis、Celery、ORM 或前端构建链。
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing