- reject K-0019 (Baidu Baike, expired), K-0022 (Xinhua, expired), K-0025 (aid report, off-topic) - add K-0040 (red culture), K-0041 (tourism), K-0042 (homestay) as replacements - verify K-0038~K-0042; all four categories now meet targets (8/10/7/6) Co-Authored-By: Claude Code <noreply@anthropic.com>
那拉提文旅智能问答
Vue 3 + TypeScript + Vite 前端;FastAPI + Pydantic + SQLAlchemy 后端;PostgreSQL + pgvector。当前后端提供知识管理、来源、文档、人工审核、关键词/向量/RRF 检索、文本与向量发布、历史记录及认证/角色权限,/api/chat 提供条目级关键词证据检索,不生成模型答案。
启动数据库
需要可用的 Docker Engine(Windows 可使用 Docker Desktop),在项目根目录运行:
docker compose up -d db
开发数据库默认仅绑定 127.0.0.1:5432。请在正式使用前修改默认密码。
启动后端(Windows PowerShell)
cd backend
py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
if (!(Test-Path .env)) { Copy-Item .env.example .env }
alembic upgrade head
uvicorn app.main:app --reload
API 文档:http://127.0.0.1:8000/docs
Linux / macOS 可使用以下等价命令(需要 Python 3.11+;.env 已存在时不要覆盖):
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
test -f .env || cp .env.example .env
alembic upgrade head
uvicorn app.main:app --reload --host 127.0.0.1
配置始终从 backend/.env 读取,环境变量优先。必须先迁移再启动;应用启动只检查数据库版本,不再执行 create_all。旧版 knowledge_items 会被非破坏性接管;首次迁移前仍须备份。迁移会保留原条目及导入快照,不推测缺失的采集时间。旧版 verified 条目因缺少完整审核记录,会转为 pending,原状态保存在导入日志中。
认证迁移为 0004_auth_sessions。知识管理、来源、文档及检索历史现要求管理员登录;迁移不创建默认账号。运行 python -m app.manage create-admin --username local_admin,通过隐藏输入设置独立密码。默认 Cookie 要求 HTTPS;本机 HTTP 联调须在未入库的 .env 显式设置 AUTH_COOKIE_SECURE=false(仅 development/test 允许)。完整来源、CSRF、字段和权限说明见 认证接口契约。当前数据库最新迁移为 0007_rag_contexts;文本构建/发布见 INDEX_API.md,本地模型及向量发布见 VECTOR_API.md,证据与 OpenAI 兼容请求准备见 RAG_CONTEXT_API.md。
启动前端(另开终端)
cd frontend
npm install
npm run dev
Vite 通常使用 http://localhost:5173。
已有接口
- 注册/登录/退出、当前会话、资料修改、改密与管理员用户列表,详见 认证接口契约
- GET
/api/health - GET
/api/ready:检查数据库连接 - POST
/api/chat:已核验条目关键词检索,问题1–500字符;返回 retrieval_only/no_evidence 和来源,详见 CHAT_API.md - GET
/api/knowledge - POST
/api/knowledge - GET
/api/knowledge/page、GET/PATCH/DELETE/api/knowledge/{id} - POST
/api/knowledge/{id}/review、GET/api/knowledge/{id}/history - GET/POST
/api/sources、GET/PATCH/DELETE/api/sources/{id}、GET/api/sources/{id}/history - GET/POST
/api/documents、GET/PATCH/DELETE/api/documents/{id}、GET/api/documents/{id}/history - POST
/api/retrieval:已核验知识的关键词检索 - GET
/api/retrieval/runs、GET/api/retrieval/runs/{run_id}:检索历史和原始结果 - POST
/api/retrieval/exports:管理员按编号导出 JSONL 历史与可选准备上下文,见 导出契约 /api/indexes:管理员构建/查询切分快照、发布/查询当前版本、查询 chunks 和发布历史,详见 接口契约
阶段 2 接口约定
- 所有日期均为带时区的 ISO 8601。输入拒绝未知字段,标题/正文不能全为空白,网址只接受 HTTP(S);可选网址空字符串按未填写处理。
GET /api/knowledge保留数组响应,支持q、category、verification_status、limit(默认 100,最大 200)和offset。新页面应使用/api/knowledge/page,避免把首批条目数量当作总数。- 分页响应为
{items, total, page, page_size};page从 1 开始,page_size默认 20、最大 100。来源、文档、知识分页和各类历史接口均支持分页。 - 来源分页支持
q;文档分页支持q、source_id、category;知识分页支持q、category、verification_status、source_id、document_id。q为字面文本子串搜索,尚非论文中的关键词检索基线。 - 创建知识沿用
title/category/content/source_url,新增可选source_id/document_id/collected_at;状态固定为pending。关联文档时自动解析其来源,填写的来源或网址若冲突会报错。直接来源链接的旧调用仍受支持。 - 来源创建字段:
name、可选source_url、notes。文档创建字段:source_id/title/content/collected_at,可选category/notes。文档来源归属固定,换来源需新建文档。 - 知识修改时省略
collected_at表示保留原值,明确传null表示清空;清空后回到待审核,补全真实采集时间前不能核验通过。文档的采集时间仍是必填字段,不接受null。 - PATCH 请求必须携带读取时获得的
expected_version,并至少提交一个修改字段;DELETE 使用查询参数expected_version。版本过期返回 409,防止覆盖他人修改。 - 审核请求字段见下方示例。
verification_status只允许pending/verified/rejected;核验人和说明必填。通过审核前必须有来源网址及真实采集时间。这里只记录人工结论,不会自动核实网页。 - 修改条目、关联来源或关联文档都会将相关知识转为
pending,清除当前审核字段并记录失效原因。历史快照保留当时的条目、来源和文档。 - 删除采用软删除;被有效文档或知识引用的来源、被有效知识引用的文档不能删除(409)。已删除记录不出现在列表,但历史仍可查看。
- 错误响应使用
detail:参数错误 422、记录不存在 404、版本/引用冲突 409、数据库暂不可用 503。
审核请求示例(仅为占位测试数据):
{
"expected_version": 1,
"verification_status": "verified",
"reviewer": "test-reviewer",
"verification_notes": "示例审核说明,实际使用须填写真实核验依据"
}
响应新增 version/updated_at/is_deleted 及关联、采集、审核字段;完整类型以 /openapi.json 和 /docs 为准。前端已接入登录/注册、Cookie 会话恢复、个人中心、账户设置、角色路由守卫、角色菜单、知识录入和来源登记/查询;来源和文档管理均已接入创建、编辑、软删除、分页搜索及历史快照的真实接口。知识审核与浏览器端 PostgreSQL 联调仍需按接口验收。
关键词检索基线
先安装更新后的依赖并执行 alembic upgrade head,再启动后端。检索请求示例:
{"query": "那拉提旅游资源", "mode": "keyword", "top_k": 5, "category": "旅游资源"}
query 为 1–500 字符;top_k 默认 5、最大 20;category 可省略。当前只接受 keyword 模式。纯标点、空白或仅含停用词的查询返回 422。
- 仅使用
verified且未删除、采集/审核字段齐全的知识。关联来源/文档须仍有效,来源网址须与登记来源一致;pending/rejected不参与分词、IDF 统计或结果排名。 - 使用固定
jieba==0.42.1搜索分词,关闭 HMM,加入项目词“那拉提”,采用字符级 NFKC 和大小写折叠、小型固定停用词表。标题词频权重 2,正文权重 1;BM25 参数k1=1.2/b=0.75,IDF 为ln(1+(N-df+0.5)/(df+0.5))。重复查询词计一次,同分按知识 ID 升序。 - 返回
run_id/status/query_terms/corpus_size/corpus_fingerprint/total_hits/results/elapsed_ms/config等字段。命中包含知识及关联文档/来源的 ID 与版本、标题、来源网址、分数、命中词和最长 240 字符的原文片段;snippet_start/end是原文字符偏移,结束位置不包含在片段内。分数仅用于排序,不是事实正确率或置信度。独立网址的旧条目可没有文档 ID 或来源名称。 - 关键词基线的检索单元仍是已审核知识条目;该接口的显示片段独立于新增的持久化 chunks,尚无向量索引。没有匹配证据时返回
status=no_evidence和空结果,当前不会调用模型生成答案。 - 每次成功检索(含零命中)保存不可变结果快照、实际检索耗时、语料指纹和算法参数。
elapsed_ms包含读取、分词、排序和片段生成,不包含记录写入和网络时间。历史记录用于复核,不能当作仍然有效的当前知识;依据变更后的新检索会重新应用审核条件。 GET /api/retrieval/runs使用标准分页参数;GET /api/retrieval/runs/{run_id}读取当时结果。当前知识修改、失效或删除不会改写历史结果。检索记录保存在数据库,运行日志和实际查询不要提交到 Git。- 本基线按请求计算语料词频,面向小规模资料集:筛选后的语料最多 5000 条、标题与正文合计最多 200 万字符。超过容量明确返回 503,不截断语料或伪造空结果;可缩小类别范围,大规模索引留到后续实现。
前端 src/api.ts 已提供带类型的检索及历史调用;混合检索证据展示已接入问答页。chunk 关键词、精确向量与 RRF 的独立调用及比较口径见 混合检索契约。已增加 RAG 证据与兼容请求准备,新准备采用 Responses 请求体与解析,兼容保留旧 Chat Completions 历史,可保存上下文和引用;实际 LLM 调用和领域评测仍待后续阶段。
前端包括问答、知识库管理、来源与更新、实验评估四个页面。实验评估页面没有虚构数据;所有页面明确标记当前功能状态。
注意:当前已实现本地 Embedding、文本/向量快照、精确向量及 RRF 混合检索;/api/chat 已接入独立关键词检索,生成模型实际调用暂缓,网络搜索、后台更新任务和真实领域评测尚未实现。管理接口由服务端认证与角色校验;审核表单的核验人仍是人工输入字段。已完成隔离环境的浏览器 Cookie/CSRF、角色与真实检索核心流程验收,见 浏览器验收记录 与 导出/采集时间复核;完整生产部署、Docker 数据库与 HTTPS 验收仍待完成。.env 不要提交到 Git。
后端测试和迁移回滚
在 backend 目录安装 requirements-dev.txt 后执行:
ruff check .
ruff format --check .
pytest -q
测试需要真实 PostgreSQL + pgvector:设置 TEST_DATABASE_URL(postgresql+psycopg://...),或另行 pip install pgserver 使用可选的本机临时实例。pgserver 仅用于测试,不是应用运行依赖;外部测试数据库账号需有建 Schema 权限且已启用 vector 扩展。每个测试使用独立 Schema,不会清空业务表。测试使用的占位正文和审核人不代表真实资料。
迁移命令为 alembic upgrade head,可重复执行。仅撤回请求准备快照时,备份后配合旧后端执行 alembic downgrade 0006_vectors;保留全部目录、文本/向量和检索历史。继续撤回向量快照时,备份后配合旧后端执行 alembic downgrade 0005_chunk_indexes,保留文本、账号、知识及检索历史;新模式历史的旧代码兼容边界见 HYBRID_API.md。继续撤回切分/索引版本时,备份后执行 alembic downgrade 0004_auth_sessions,保留账号、会话、知识和检索记录。继续撤回认证时,备份后执行 alembic downgrade 0003_retrieval_runs,删除用户/会话/预算表,保留知识和检索历史。继续执行 alembic downgrade 0002_catalog 还会删除检索历史。需要撤回阶段 2 时,先备份,再执行 alembic downgrade 0001_baseline;它保留基础知识字段,但会删除新增来源、文档、审核字段与所有历史记录,软删除的基础条目也会重新可见。降级须配合对应旧版后端,当前应用会拒绝旧 Schema。恢复完整数据应使用备份。不要在有业务数据的数据库执行 downgrade base。
团队协作文档
目标 Gitea 仓库:https://gitea.kronecker.cc/saint/border-red-post-nalati。