112 lines
4.6 KiB
Markdown
112 lines
4.6 KiB
Markdown
# Simple Chat API
|
||
|
||
一个使用 FastAPI 和 DeepSeek API 的多轮 Agent 服务。每个会话的系统提示词、消息历史和工具调用过程保存在本地 JSON 文件中。
|
||
|
||
## 代码结构
|
||
|
||
采用 `src/` 布局,所有业务代码收纳在 `src/chat_api/` 包内,按职责分模块/子包,根目录只保留 `main.py` 入口。
|
||
|
||
```
|
||
src/chat_api/
|
||
├── app.py 应用工厂 + 生命周期(组装各层)
|
||
├── config.py Settings:从 .env 读取配置
|
||
├── auth.py API Key 鉴权依赖项(CurrentUser)
|
||
├── routes.py 所有 HTTP 路由
|
||
├── domain/ 持久化模型(不依赖任何其它层)
|
||
│ ├── messages.py UserMessage / AssistantMessage / ToolMessage / ToolCall
|
||
│ └── session.py Session(含旧数据兼容校验器)
|
||
├── schemas/ API 请求/响应模型(按接口分组)
|
||
│ ├── session.py 创建会话 / 历史查询
|
||
│ ├── message.py 发送消息 / TokenUsage
|
||
│ ├── auth.py 注册 / 登录
|
||
│ └── usage.py 用量查询
|
||
├── storage/ 持久化实现
|
||
│ ├── sessions.py JsonSessionStorage(会话 JSON)
|
||
│ └── users.py UserStore(SQLite 用户 + bcrypt + AuthenticatedUser)
|
||
├── service/
|
||
│ └── chat.py ChatService:Agent 循环与业务规则
|
||
└── tools/
|
||
├── registry.py ToolRegistry / ToolSpec 注册表基础设施
|
||
└── time_tools.py get_current_time 内置工具
|
||
```
|
||
|
||
分层依赖方向:`domain` ← `schemas`/`storage` ← `service`/`auth` ← `routes` ← `app`。各子包 `__init__.py` 做重导出,跨层引用形如 `from chat_api.storage import JsonSessionStorage, UserStore`。
|
||
|
||
## 启动
|
||
|
||
```bash
|
||
uv sync
|
||
cp .env.example .env
|
||
# 编辑 .env 并填写 DEEPSEEK_API_KEY
|
||
uv run python main.py # 或:uv run uvicorn main:app --reload --reload-dir src
|
||
```
|
||
|
||
服务默认运行在 `http://127.0.0.1:8000`,交互式 API 文档位于 `/docs`。
|
||
|
||
服务会自动加载项目根目录的 `.env`,已有系统环境变量优先级更高。可配置 `DEEPSEEK_BASE_URL`、`DEEPSEEK_MODEL`、`DEFAULT_SYSTEM_PROMPT`、`CHAT_DATA_DIR`、`USER_DB_PATH` 和工具调用限制,完整示例见 `.env.example`。第一版应只使用一个 Uvicorn worker。
|
||
|
||
用户名、密码哈希、UUID 及 API Key 保存在 SQLite 中(默认路径 `USER_DB_PATH=data/users.db`,随服务启动自动建表)。所有业务接口都必须通过 `X-API-Key` 请求头提供访问密钥,服务端从数据库中查找比对以识别当前用户。
|
||
|
||
## 注册与登录
|
||
|
||
注册用户(用户名已存在返回 `409`):
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8000/auth/register \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"username":"小明","password":"your-password"}'
|
||
```
|
||
|
||
用用户名、密码换取持久化的 API Key(凭据错误返回 `401`):
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8000/auth/login \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"username":"小明","password":"your-password"}'
|
||
# => {"user_id":"...","api_key":"YOUR_API_KEY"}
|
||
```
|
||
|
||
## 使用
|
||
|
||
创建会话:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8000/sessions \
|
||
-H 'X-API-Key: YOUR_API_KEY' \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"system_prompt":"你是一个简洁的中文助手。"}'
|
||
```
|
||
|
||
使用返回的 `session_id` 发送消息:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8000/sessions/SESSION_ID/messages \
|
||
-H 'X-API-Key: YOUR_API_KEY' \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"content":"你好,请记住我的名字是小明。"}'
|
||
```
|
||
|
||
API 返回及存储的每条消息都包含 UTC `created_at`。只有模型完整响应成功后,本轮消息才会写入会话历史。
|
||
|
||
模型可以按需调用服务端白名单工具:
|
||
|
||
- `get_current_time`:查询指定 IANA 时区的当前时间。
|
||
|
||
工具调用无需增加请求参数。服务端会执行工具并把结果返回模型,直到模型生成最终回答。发送消息接口通过 `tools_use` 返回本轮使用的工具名称,完整调用过程可通过历史接口查询;未调用工具时 `tools_use` 为空数组。
|
||
|
||
获取指定会话的完整历史:
|
||
|
||
```bash
|
||
curl http://127.0.0.1:8000/sessions/SESSION_ID/messages \
|
||
-H 'X-API-Key: YOUR_API_KEY'
|
||
```
|
||
|
||
查询当前用户的累计 API 调用次数和 token 用量:
|
||
|
||
```bash
|
||
curl http://127.0.0.1:8000/usage \
|
||
-H 'X-API-Key: YOUR_API_KEY'
|
||
```
|
||
|
||
每个会话 JSON 顶层保存所属 `user_id`、成功聊天次数及累计 token。`/usage` 会扫描并汇总当前用户的全部会话,不使用独立统计文件。创建会话、查询历史和查询用量不计入 `api_calls`。
|