一个基于 AI 对话的知识节点系统。用户可以在对话过程中逐步生成 question / answer 树,并在前端以可交互的知识图形式查看、拖动、调整尺寸和重组语义层级。
当前项目已经具备以下能力:
- 基于 Flask + SQLite 的对话与知识树后端
- 基于 React + TypeScript + React Flow 的可视化前端
- 每条对话持久化为一棵 question -> answer -> child question 的树
- 节点拖拽、卡片尺寸调整
- 前端本地布局持久化
- 语义关系编辑
- 普通 re-parent
- 直接父子节点交换
- 两步点击式关系编辑
- 拖拽到目标卡片上的关系编辑
- 历史对话加载、删除、重命名、搜索
- Markdown / 代码高亮 / LaTeX 渲染
- 模型超时与重试配置
后端:
- Python 3.13+
- Flask
- Flask-CORS
- SQLite
- LangChain / langchain-openai
前端:
- React 19
- TypeScript
- Vite
@xyflow/reactmarkedhighlight.jskatex
Knode/
├── main.py
├── pyproject.toml
├── uv.lock
├── .env.example
├── backend/
│ ├── app.py
│ └── Agents/
│ ├── __init__.py
│ ├── langgraph_utils.py
│ └── utils.py
├── database/
│ ├── database.py
│ ├── optimized_database.py
│ └── migration_to_optimized.py
├── frontend/
│ ├── package.json
│ ├── vite.config.ts
│ └── src/
│ ├── components/
│ ├── services/
│ ├── styles/
│ ├── types/
│ └── utils/
├── static/
├── tests/
│ ├── test_api_contract.py
│ ├── test_model_timeout_config.py
│ └── test_reparent_api.py
└── README.md
- Python
>=3.13 - Node.js
>=18 - npm
uv
复制模板:
cp .env.example .env最少需要配置智谱:
ZHIPU_API_KEY=your_zhipu_api_key_here可选配置:
ZHIPU_BASE_URLOPENAI_API_KEYOPENAI_BASE_URLAPI_TIMEOUTMODEL_REQUEST_TIMEOUTMODEL_MAX_RETRIES
说明:
- 当前前端默认提供的模型选项是 GLM 系列
backend/Agents/utils.py中其它 provider 的模型映射大多仍处于注释状态- 若要启用 OpenAI 等 provider,需要同时打开模型映射并配置对应环境变量
后端依赖:
uv sync前端依赖:
cd frontend
npm install
cd ..直接启动 Flask 服务:
uv run python main.py默认访问地址:
http://localhost:8000
说明:
main.py当前以debug=True启动 Flask- 前端生产构建产物位于
static/ - Flask 根路由会直接返回
static/index.html
前端 dev server:
cd frontend
npm run dev默认端口:
http://localhost:3001
Vite 会把 /api 代理到:
http://localhost:8000
开发时推荐两个终端:
- 终端 A
uv run python main.py- 终端 B
cd frontend
npm run dev前端发布构建:
cd frontend
npm run build
cd ..- 初始化一个 conversation
- 每次提问都会写入一个
question节点 - 模型回答会写入对应的
answer节点 - 跟进提问会挂到父
answer节点下面 - 后端返回的树结构会被前端转换为 QA 卡片视图
当前前端不是静态 SVG,而是动态节点画布:
- 节点支持拖动
- 节点支持 resize
- 布局保存在浏览器
localStorage - 布局按
conversationId隔离 - 边使用自定义 SVG overlay 渲染
当前已经支持语义层级调整,不再只按用户追问顺序组织树。
关系编辑模式下可用两种方式:
-
两步点击式
- 先点击要移动的节点
- 再点击目标父节点
-
拖拽式
- 将节点拖到目标卡片上
后端支持的规则:
- 允许普通 re-parent
- 允许直接父子 question 节点交换
- 禁止挂到更深层 descendant,避免真实环路
- 目标节点必须存在 answer child
- Markdown 渲染
- 代码块高亮
- LaTeX 数学公式
- 节点详情查看
- 基于节点内容继续追问
前端可选模型见 constants.ts 对应实现,当前默认提供:
glm-4.6vglm-4.6glm-4.5glm-4.5-airglm-4
后端默认模型:
glm-4.6v
核心接口:
POST /api/initPOST /api/chatPOST /api/resetGET /api/conversationsGET /api/conversations/<conversation_id>POST /api/conversations/<conversation_id>/loadDELETE /api/conversations/<conversation_id>PUT /api/conversations/<conversation_id>/titlePUT /api/conversations/<conversation_id>/nodes/<node_id>/reparentGET /api/conversations/search?q=...GET /api/conversations/paginated?page=1&limit=20
reparent 请求体:
{
"target_node_id": "target-question-node-id"
}当前仓库里已经有以下测试:
- API contract 测试
- 模型 timeout / retry 配置测试
- 语义 re-parent 测试
运行方式:
uv run pytest tests/test_api_contract.py tests/test_model_timeout_config.py tests/test_reparent_api.py -q前端构建验证:
cd frontend
npm run build数据库里的结构是交替树:
question
└── answer
└── question
└── answer
因此前端看到的一张 QA 卡片,本质上映射的是:
- 卡片
id-> question node id - 卡片
answerId-> answer node id
项目优先使用:
database/optimized_database.py
若导入失败,则回退到:
database/database.py
两个实现都维护了:
- conversation CRUD
- 树构建
- search
reparent_question_node
模型超时与重试由环境变量控制:
API_TIMEOUTMODEL_REQUEST_TIMEOUTMODEL_MAX_RETRIES
默认值定义在:
backend/Agents/langgraph_utils.py
当前默认:
request_timeout = 300max_retries = 2
- 节点布局目前只保存在前端
localStorage,还没有写回数据库 - README 中提到的多 provider 能力,当前代码里实际默认启用的是 GLM 系列
main.py中端口写死为8000,.env.example里的PORT说明尚未接入运行逻辑- 前端生产包体较大,
vite build会给出 chunk size warning
如果你要继续演进这个项目,当前比较自然的方向是:
- 把布局持久化到后端和数据库
- 给关系编辑增加更强的提示与撤销
- 引入“语义关系类型”,而不只是树形父子
- 把当前 provider 配置从代码注释迁移到正式配置层
- 增加前端交互测试和后端数据库级测试
最近已验证通过:
cd frontend && npm run build
uv run pytest tests/test_api_contract.py tests/test_model_timeout_config.py tests/test_reparent_api.py -q