This commit is contained in:
zhangquan 2026-03-31 15:41:21 +08:00
parent 3368188dd2
commit f9a356669f
6 changed files with 731 additions and 70 deletions

114
.env
View File

@ -1,56 +1,88 @@
# ============================================ # 环境变量配置示例
# 初中物理作业批改工作流 - 环境变量配置示例 # 复制此文件为 .env 并填入实际值
# ============================================
# 复制此文件为 .env 并填写实际值
# cp .env.example .env
# ============================================ # ==================== Coze API 配置 ====================
# 必需配置 - 大语言模型 API
# ============================================
# LLM API 密钥从火山引擎或OpenAI获取 # Coze API 访问密钥(必需)
LLM_API_KEY=eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbInRVaHJod1VDMmFHRmVSRjZBU01NNGxITjhoT01jOVA2Il0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjcwMTM1LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIxMzY5Mjg5OTI4MzQzNTY3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMTUwMTkzNTI1NjIwNzYyIn0.qIgzvuMGj976ekcmxZHIWlATn58PyPmFrsoYPeqTfSX4kdvkgeIXMEGR1NAX-OcOmBY_T8tvjcY2sxNDqRhLSQi-6teONHIYkTyXSrA_T5eJqaqrylFmzWPWzqX41LBsav5cyR0n4ffYzqLSd0-iAf8HdUyMEhVuTZuv-nGSpaQ-al98TqcrPtLqte71J1VbbAsjzFMrawTaSOe6WSiIQNe1qNDmsoyQpu_qdw5Sh_nMbPN8V5tjNFlX04pNV6O60M_Bqr1hDxAqY_fsUeECBhE5uG29cYawxc5oEb-xZF0vM_a0gvU5cw2jV1OktNXGJ6A2S9btRfyqoAc3fFqxmw # 获取方式https://www.coze.cn/
COZE_WORKLOAD_IDENTITY_API_KEY=eyJhbGciOiJSUzI1NiIsImtpZCI6ImRmZmU2NmYxLTg0MDMtNDc5Ni05ZmRhLTViMmJjZWExM2ViOCJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbInRVaHJod1VDMmFHRmVSRjZBU01NNGxITjhoT01jOVA2Il0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0NjcwMTM1LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIxMzY5Mjg5OTI4MzQzNTY3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIyMTUwMTkzNTI1NjIwNzYyIn0.qIgzvuMGj976ekcmxZHIWlATn58PyPmFrsoYPeqTfSX4kdvkgeIXMEGR1NAX-OcOmBY_T8tvjcY2sxNDqRhLSQi-6teONHIYkTyXSrA_T5eJqaqrylFmzWPWzqX41LBsav5cyR0n4ffYzqLSd0-iAf8HdUyMEhVuTZuv-nGSpaQ-al98TqcrPtLqte71J1VbbAsjzFMrawTaSOe6WSiIQNe1qNDmsoyQpu_qdw5Sh_nMbPN8V5tjNFlX04pNV6O60M_Bqr1hDxAqY_fsUeECBhE5uG29cYawxc5oEb-xZF0vM_a0gvU5cw2jV1OktNXGJ6A2S9btRfyqoAc3fFqxmw COZE_API_KEY=Bearer pat_N0naC1MsQ5cLAQjtNB8pfzzyT0kZWXBSaOOLLsN03TYgChkDgnCXDyfUvc1A68I2
# LLM API 基础URL # 大语言模型 API 密钥(必需)
# 火山引擎: https://ark.cn-beijing.volces.com/api/v3 LLM_API_KEY=Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjhiNmUwZWIwLTU2MGItNDFjMi1hODY4LTlmMzI4Y2FhZjAzNSJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0OTQyMTE5LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIzMzE4MzU0OTE2Mjc4MzA2In0.UHvct0nIH6hnKaHT2z3bfvLeNcyrgrnqYE3itr9ddl1mGHS0bAtGQ7lDCZwObCPrA_TqnaaAS8dW20ctpTd8Fwyr0nl-eKylKH40BvJ8DbsZdKbqKQgl3yxM14Bmy1VjfNyKRyVhE11RfOIAk_xgRS0k2lj9tyJNv0NFSNUPSFVA8ApNUXTALy8YdqnIbcfhWroCQTR9RkqsRuJ7GpMrODHxZcdYCXj2XF1nyeK68HCUB_2XcGFqccWkLQxMa9Y7mezkatT1txzQcP7gdN01Y2KwFkjxnpIv8qVVyB3UzgNDsEqqZWEh8ft-qMgPDcNc-YCB8r7-zxmMolcCp6fhlA
# OpenAI: https://api.openai.com/v1
LLM_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
# 模型名称 # 工作负载身份认证密钥(必需)
# 火山引擎推荐: doubao-seed-2-0-pro-260215 COZE_WORKLOAD_IDENTITY_API_KEY=Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjhiNmUwZWIwLTU2MGItNDFjMi1hODY4LTlmMzI4Y2FhZjAzNSJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0OTQyMTE5LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIzMzE4MzU0OTE2Mjc4MzA2In0.UHvct0nIH6hnKaHT2z3bfvLeNcyrgrnqYE3itr9ddl1mGHS0bAtGQ7lDCZwObCPrA_TqnaaAS8dW20ctpTd8Fwyr0nl-eKylKH40BvJ8DbsZdKbqKQgl3yxM14Bmy1VjfNyKRyVhE11RfOIAk_xgRS0k2lj9tyJNv0NFSNUPSFVA8ApNUXTALy8YdqnIbcfhWroCQTR9RkqsRuJ7GpMrODHxZcdYCXj2XF1nyeK68HCUB_2XcGFqccWkLQxMa9Y7mezkatT1txzQcP7gdN01Y2KwFkjxnpIv8qVVyB3UzgNDsEqqZWEh8ft-qMgPDcNc-YCB8r7-zxmMolcCp6fhlA
# OpenAI推荐: gpt-4o
LLM_MODEL_NAME=doubao-seed-2-0-pro-260215
# 注意不需要配置对象存储S3/TOS/OSS等 # 集成 API 密钥(必需)
# 图片直接使用原始URL不上传存储 COZE_INTEGRATION_API_KEY=Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjhiNmUwZWIwLTU2MGItNDFjMi1hODY4LTlmMzI4Y2FhZjAzNSJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb3plLmNuIiwiYXVkIjpbIkZVS1kzOVR0dFlSdmlNaldGVmNjaUg0NWFPblp2TGxpIl0sImV4cCI6ODIxMDI2Njg3Njc5OSwiaWF0IjoxNzc0OTQyMTE5LCJzdWIiOiJzcGlmZmU6Ly9hcGkuY296ZS5jbi93b3JrbG9hZF9pZGVudGl0eS9pZDo3NjIyMjM4NzUyNjQyOTU3MzQ3Iiwic3JjIjoiaW5ib3VuZF9hdXRoX2FjY2Vzc190b2tlbl9pZDo3NjIzMzE4MzU0OTE2Mjc4MzA2In0.UHvct0nIH6hnKaHT2z3bfvLeNcyrgrnqYE3itr9ddl1mGHS0bAtGQ7lDCZwObCPrA_TqnaaAS8dW20ctpTd8Fwyr0nl-eKylKH40BvJ8DbsZdKbqKQgl3yxM14Bmy1VjfNyKRyVhE11RfOIAk_xgRS0k2lj9tyJNv0NFSNUPSFVA8ApNUXTALy8YdqnIbcfhWroCQTR9RkqsRuJ7GpMrODHxZcdYCXj2XF1nyeK68HCUB_2XcGFqccWkLQxMa9Y7mezkatT1txzQcP7gdN01Y2KwFkjxnpIv8qVVyB3UzgNDsEqqZWEh8ft-qMgPDcNc-YCB8r7-zxmMolcCp6fhlA
# 工作空间 ID必需
COZE_WORKSPACE_ID=7622233047848583202
# ============================================ # ==================== Coze API 基础 URL ====================
# 可选配置 - 日志与缓存
# ============================================
# 日志级别: DEBUG, INFO, WARNING, ERROR # Coze 集成基础 URL
COZE_INTEGRATION_BASE_URL=https://api.coze.cn/v1
# Coze 模型基础 URL
COZE_INTEGRATION_MODEL_BASE_URL=https://api.coze.cn/v1
# LLM 基础 URL
LLM_BASE_URL=https://api.coze.cn/v1
# ==================== 模型配置 ====================
# 默认文本模型
LLM_MODEL_NAME=doubao-seed-1-8-251228
# 默认视觉模型
VISION_MODEL_NAME=doubao-seed-1-6-vision-250815
# ==================== 服务配置 ====================
# 服务端口
PORT=8000
# 工作线程数
WORKERS=1
# 超时时间(秒)
TIMEOUT_SECONDS=600
# ==================== 缓存配置 ====================
# 缓存目录
CACHE_DIR=/tmp/homework_cache
# 答案文档缓存目录
ANSWER_DOC_CACHE_DIR=/tmp/homework_cache/math_answer_doc
# 评分标准缓存目录
GRADE_STANDARDS_CACHE_DIR=/tmp/homework_cache/grade_standards
# ==================== 并发配置 ====================
# 最大并发数1-50
MAX_CONCURRENT_TASKS=10
# ==================== 日志配置 ====================
# 日志级别
LOG_LEVEL=INFO LOG_LEVEL=INFO
# 缓存目录(默认: /tmp/cache # 日志文件路径
CACHE_DIR=/tmp/cache LOG_FILE=/tmp/work/logs/bypass/app.log
# 单张图片处理超时(秒,默认: 120 # 日志最大大小(字节
SINGLE_IMAGE_TIMEOUT=120 LOG_MAX_BYTES=104857600
# 日志备份数量
LOG_BACKUP_COUNT=5
# ============================================ # ==================== 其他配置 ====================
# 可选配置 - 并发控制
# ============================================
# 最大并发数(默认: 10 # Coze 项目环境DEV/PROD
MAX_CONCURRENT=10 COZE_PROJECT_ENV=PROD
# 启用调试模式
# ============================================ DEBUG=false
# 工作目录(系统自动设置,无需修改)
# ============================================
# 工作目录路径(由系统自动设置)
# COZE_WORKSPACE_PATH=/workspace/projects

88
.env.example Normal file
View File

@ -0,0 +1,88 @@
# 环境变量配置示例
# 复制此文件为 .env 并填入实际值
# ==================== Coze API 配置 ====================
# Coze API 访问密钥(必需)
# 获取方式https://www.coze.cn/
COZE_API_KEY=Bearer YOUR_COZE_API_KEY_HERE
# 大语言模型 API 密钥(必需)
LLM_API_KEY=Bearer YOUR_LLM_API_KEY_HERE
# 工作负载身份认证密钥(必需)
COZE_WORKLOAD_IDENTITY_API_KEY=Bearer YOUR_WORKLOAD_IDENTITY_KEY_HERE
# 集成 API 密钥(必需)
COZE_INTEGRATION_API_KEY=Bearer YOUR_INTEGRATION_API_KEY_HERE
# 工作空间 ID必需
COZE_WORKSPACE_ID=YOUR_WORKSPACE_ID_HERE
# ==================== Coze API 基础 URL ====================
# Coze 集成基础 URL
COZE_INTEGRATION_BASE_URL=https://api.coze.cn/v1
# Coze 模型基础 URL
COZE_INTEGRATION_MODEL_BASE_URL=https://api.coze.cn/v1
# LLM 基础 URL
LLM_BASE_URL=https://api.coze.cn/v1
# ==================== 模型配置 ====================
# 默认文本模型
LLM_MODEL_NAME=doubao-seed-1-8-251228
# 默认视觉模型
VISION_MODEL_NAME=doubao-seed-1-6-vision-250815
# ==================== 服务配置 ====================
# 服务端口
PORT=8000
# 工作线程数
WORKERS=1
# 超时时间(秒)
TIMEOUT_SECONDS=600
# ==================== 缓存配置 ====================
# 缓存目录
CACHE_DIR=/tmp/homework_cache
# 答案文档缓存目录
ANSWER_DOC_CACHE_DIR=/tmp/homework_cache/math_answer_doc
# 评分标准缓存目录
GRADE_STANDARDS_CACHE_DIR=/tmp/homework_cache/grade_standards
# ==================== 并发配置 ====================
# 最大并发数1-50
MAX_CONCURRENT_TASKS=10
# ==================== 日志配置 ====================
# 日志级别
LOG_LEVEL=INFO
# 日志文件路径
LOG_FILE=/tmp/work/logs/bypass/app.log
# 日志最大大小(字节)
LOG_MAX_BYTES=104857600
# 日志备份数量
LOG_BACKUP_COUNT=5
# ==================== 其他配置 ====================
# Coze 项目环境DEV/PROD
COZE_PROJECT_ENV=PROD
# 启用调试模式
DEBUG=false

369
DEPLOYMENT.md Normal file
View File

@ -0,0 +1,369 @@
# 数学作业批改系统 - 部署指南
## 📋 项目概述
这是一个基于 LangGraph 的初中数学作业批改工作流系统,支持:
- ✅ 图片上传识别
- ✅ 自动批改
- ✅ 坐标定位
- ✅ 多学生多图片并行处理
- ✅ Word 文档答案解析
- ✅ 流式响应
---
## 🔧 前置条件
### 1. **Docker 环境**
```bash
# 安装 Docker
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y docker.io docker-compose
# CentOS/RHEL
sudo yum install -y docker docker-compose
# macOS
brew install docker docker-compose
# 启动 Docker
sudo systemctl start docker
sudo systemctl enable docker
```
### 2. **API 密钥**(重要!)
项目依赖 Coze API需要以下密钥
| 环境变量 | 说明 | 获取方式 |
|---------|------|---------|
| `COZE_API_KEY` | Coze API 访问密钥 | [Coze 控制台](https://www.coze.cn/) |
| `LLM_API_KEY` | 大语言模型 API 密钥 | [Coze 控制台](https://www.coze.cn/) |
| `COZE_WORKLOAD_IDENTITY_API_KEY` | 工作负载身份认证密钥 | [Coze 控制台](https://www.coze.cn/) |
| `COZE_INTEGRATION_API_KEY` | 集成 API 密钥 | [Coze 控制台](https://www.coze.cn/) |
| `COZE_WORKSPACE_ID` | 工作空间 ID | [Coze 控制台](https://www.coze.cn/) |
**获取密钥步骤**
1. 注册/登录 [Coze 平台](https://www.coze.cn/)
2. 创建工作空间
3. 在 API 密钥管理中获取相关密钥
### 3. **网络要求**
- ✅ 可访问 `api.coze.cn`(中国区)
- ✅ 可访问阿里云 OSS用于存储图片/答案文档)
- ✅ 防火墙允许出站 HTTPS 连接443 端口)
### 4. **系统资源要求**
| 资源 | 最低配置 | 推荐配置 |
|------|---------|---------|
| CPU | 2 核 | 4 核+ |
| 内存 | 4 GB | 8 GB+ |
| 磁盘 | 10 GB | 20 GB+ |
| 网络 | 1 Mbps | 10 Mbps+ |
---
## 🚀 部署步骤
### 方式一:使用 Dockerfile推荐
#### 1. 克隆/下载项目
```bash
# 方式一:使用 git clone
git clone <your-repo-url>
cd <project-directory>
# 方式二:下载压缩包并解压
unzip <project-name>.zip
cd <project-name>
```
#### 2. 修改 API 密钥
编辑 `assets/Dockerfile`,替换第 47-51 行的环境变量:
```dockerfile
ENV COZE_WORKLOAD_IDENTITY_API_KEY="Bearer YOUR_KEY_HERE" \
LLM_API_KEY="Bearer YOUR_KEY_HERE" \
COZE_API_KEY="Bearer YOUR_KEY_HERE" \
COZE_INTEGRATION_API_KEY="Bearer YOUR_KEY_HERE" \
COZE_WORKSPACE_ID=YOUR_WORKSPACE_ID
```
⚠️ **注意**:请将 `YOUR_KEY_HERE``YOUR_WORKSPACE_ID` 替换为你的实际密钥。
#### 3. 构建 Docker 镜像
```bash
docker build -f assets/Dockerfile -t math-correction:latest .
```
**构建时间**:约 5-10 分钟(首次构建较慢)
#### 4. 运行容器
```bash
docker run -d \
--name math-correction \
-p 8000:8000 \
-v /path/to/data:/app/data \
math-correction:latest
```
**参数说明**
- `-d`:后台运行
- `--name`:容器名称
- `-p 8000:8000`:端口映射(主机:容器)
- `-v /path/to/data:/app/data`:数据卷挂载(可选)
#### 5. 验证运行
```bash
# 查看容器日志
docker logs -f math-correction
# 检查健康状态
curl http://localhost:8000/health
# 测试接口
curl -X POST http://localhost:8000/run \
-H "Content-Type: application/json" \
-d '{"student_homework": []}'
```
---
### 方式二:使用 Docker Compose更方便
#### 1. 创建 `docker-compose.yml`
```yaml
version: '3.8'
services:
math-correction:
build:
context: .
dockerfile: assets/Dockerfile
container_name: math-correction
ports:
- "8000:8000"
environment:
# 替换为你的实际密钥
- COZE_WORKLOAD_IDENTITY_API_KEY=Bearer YOUR_KEY_HERE
- LLM_API_KEY=Bearer YOUR_KEY_HERE
- COZE_API_KEY=Bearer YOUR_KEY_HERE
- COZE_INTEGRATION_API_KEY=Bearer YOUR_KEY_HERE
- COZE_WORKSPACE_ID=YOUR_WORKSPACE_ID
volumes:
- ./data:/app/data
restart: unless-stopped
```
#### 2. 启动服务
```bash
# 构建并启动
docker-compose up -d
# 查看日志
docker-compose logs -f
# 停止服务
docker-compose down
```
---
## 📝 API 接口说明
### 1. **HTTP 模式**(同步/异步)
```bash
# 端点
POST http://localhost:8000/run
POST http://localhost:8000/stream_run
# 请求头
Content-Type: application/json
# 请求体示例
{
"student_homework": [
{
"student_id": 1,
"student_name": "张三",
"homework_images": [
"https://example.com/homework1.jpg",
"https://example.com/homework2.jpg"
]
}
],
"answer_doc_url": "https://example.com/answers.docx"
}
```
### 2. **流式响应模式**
```bash
# 端点
POST http://localhost:8000/stream_run
# 响应格式SSE
data: {"event": "workflow_start", "data": {...}}
data: {"event": "ping", "data": {...}}
data: {"event": "workflow_end", "data": {...}}
```
---
## 🔍 常见问题排查
### 1. **构建失败**
```bash
# 清理 Docker 缓存后重新构建
docker system prune -a
docker build --no-cache -f assets/Dockerfile -t math-correction:latest .
```
### 2. **容器启动失败**
```bash
# 查看详细错误日志
docker logs math-correction
# 进入容器调试
docker exec -it math-correction bash
```
### 3. **API 调用 401/403 错误**
**原因**API 密钥无效或过期
**解决**
1. 检查 `Dockerfile` 中的密钥是否正确
2. 确认密钥是否有效且未过期
3. 重新构建镜像(`docker build ...`
### 4. **图片下载失败**
**原因**:图片 URL 不可访问
**解决**
1. 检查图片 URL 是否有效
2. 确认网络是否正常
3. 检查防火墙设置
### 5. **内存不足**
**现象**:容器频繁重启或 OOM
**解决**
```bash
# 增加 Docker 内存限制
docker run -d \
--name math-correction \
--memory="8g" \
-p 8000:8000 \
math-correction:latest
```
---
## 📊 监控与日志
### 查看实时日志
```bash
# 容器日志
docker logs -f math-correction
# 查看最近 100 行
docker logs --tail 100 math-correction
# 查看错误日志
docker logs math-correction | grep ERROR
```
### 性能监控
```bash
# 查看容器资源使用
docker stats math-correction
# 查看容器详情
docker inspect math-correction
```
---
## 🛠️ 本地开发模式
如果不想使用 Docker可以直接在本地运行
```bash
# 安装 Python 3.12
python3.12 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 安装依赖
pip install -r requirements.txt
# 设置环境变量(创建 .env 文件)
export COZE_API_KEY="Bearer YOUR_KEY_HERE"
export LLM_API_KEY="Bearer YOUR_KEY_HERE"
export COZE_WORKSPACE_ID=YOUR_WORKSPACE_ID
# 运行
python src/main.py -m http -p 8000
```
---
## 📚 相关文档
- [LangGraph 官方文档](https://langchain-ai.github.io/langgraph/)
- [Coze API 文档](https://www.coze.cn/docs/developer_guides)
- [项目结构说明](./AGENTS.md)
---
## ⚠️ 注意事项
1. **API 密钥安全**
- ❌ 不要将密钥提交到代码仓库
- ✅ 使用环境变量或密钥管理服务
2. **图片存储**
- 推荐使用对象存储(如阿里云 OSS
- 确保 URL 可公网访问
3. **并发限制**
- 单图片超时120 秒
- 建议并发数10-50根据服务器配置调整
4. **数据隔离**
- 不同学科的缓存目录独立
- 建议定期清理缓存
---
## 🆘 技术支持
如遇问题,请提供以下信息:
1. Docker 版本:`docker --version`
2. 容器日志:`docker logs math-correction`
3. 错误信息截图
4. 系统配置:`uname -a`
---
## 📄 许可证
请遵循相关项目的许可证条款。

128
quick-start.sh Normal file
View File

@ -0,0 +1,128 @@
#!/bin/bash
# 数学作业批改系统 - 快速部署脚本
set -e
echo "=========================================="
echo " 数学作业批改系统 - 快速部署"
echo "=========================================="
echo ""
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 检查 Docker
if ! command -v docker &> /dev/null; then
echo -e "${RED}✗ Docker 未安装${NC}"
echo "请先安装 Docker: https://docs.docker.com/get-docker/"
exit 1
fi
echo -e "${GREEN}✓ Docker 已安装${NC}"
echo ""
# 检查 API 密钥
check_env_vars() {
local missing_vars=()
# 从 Dockerfile 中提取环境变量
if grep -q "YOUR_KEY_HERE\|YOUR_WORKSPACE_ID" assets/Dockerfile; then
echo -e "${YELLOW}⚠ 警告:检测到未配置的 API 密钥${NC}"
echo ""
echo "请在 assets/Dockerfile 中配置以下环境变量:"
echo " 1. COZE_WORKLOAD_IDENTITY_API_KEY"
echo " 2. LLM_API_KEY"
echo " 3. COZE_API_KEY"
echo " 4. COZE_INTEGRATION_API_KEY"
echo " 5. COZE_WORKSPACE_ID"
echo ""
read -p "是否继续构建?(将无法正常使用 LLM 功能)[y/N] " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}部署已取消${NC}"
exit 1
fi
fi
}
check_env_vars
# 构建镜像
echo -e "${YELLOW}正在构建 Docker 镜像...${NC}"
echo "这可能需要 5-10 分钟,请耐心等待..."
echo ""
docker build -f assets/Dockerfile -t math-correction:latest .
if [ $? -eq 0 ]; then
echo ""
echo -e "${GREEN}✓ 镜像构建成功!${NC}"
echo ""
else
echo ""
echo -e "${RED}✗ 镜像构建失败${NC}"
echo "请检查错误信息并重试"
exit 1
fi
# 运行容器
echo -e "${YELLOW}正在启动容器...${NC}"
docker run -d \
--name math-correction \
-p 8000:8000 \
--restart unless-stopped \
math-correction:latest
if [ $? -eq 0 ]; then
echo ""
echo -e "${GREEN}✓ 容器启动成功!${NC}"
echo ""
else
echo ""
echo -e "${RED}✗ 容器启动失败${NC}"
echo "请检查端口 8000 是否被占用"
exit 1
fi
# 等待服务启动
echo -e "${YELLOW}等待服务启动...${NC}"
sleep 5
# 测试服务
echo ""
echo -e "${YELLOW}正在测试服务...${NC}"
if curl -s http://localhost:8000/health > /dev/null 2>&1; then
echo -e "${GREEN}✓ 服务运行正常${NC}"
else
echo -e "${YELLOW}⚠ 服务可能还在启动中,请稍后测试${NC}"
fi
# 显示容器信息
echo ""
echo "=========================================="
echo " 部署完成!"
echo "=========================================="
echo ""
echo "容器信息:"
echo " 名称: math-correction"
echo " 端口: 8000"
echo " 状态: $(docker inspect --format='{{.State.Status}}' math-correction)"
echo ""
echo "常用命令:"
echo " 查看日志: docker logs -f math-correction"
echo " 停止容器: docker stop math-correction"
echo " 启动容器: docker start math-correction"
echo " 重启容器: docker restart math-correction"
echo " 删除容器: docker rm -f math-correction"
echo ""
echo "测试接口:"
echo " curl http://localhost:8000/health"
echo ""
echo "API 文档:"
echo " 请参考 DEPLOYMENT.md"
echo ""
echo -e "${GREEN}✓ 部署成功!${NC}"

View File

@ -251,20 +251,42 @@ def parse_answer_doc_with_llm(answer_doc_url: str, ctx, config: RunnableConfig)
] ]
}}""" }}"""
client = LLMClient(ctx=ctx) # 3. 调用LLM解析带错误处理
response = client.invoke( try:
messages=[HumanMessage(content=user_prompt)], client = LLMClient(ctx=ctx)
model=llm_config.get("model", "doubao-seed-2-0-pro-260215"), response = client.invoke(
temperature=llm_config.get("temperature", 0.1), messages=[HumanMessage(content=user_prompt)],
max_completion_tokens=llm_config.get("max_completion_tokens", 8192) model=llm_config.get("model", "doubao-seed-1-8-251228"),
) temperature=llm_config.get("temperature", 0.1),
max_completion_tokens=llm_config.get("max_completion_tokens", 8192)
response_text = response.content if isinstance(response.content, str) else " ".join( )
item.get("text", "") if isinstance(item, dict) else str(item)
for item in response.content # 安全提取响应文本
).strip() if isinstance(response.content, str):
response_text = response.content.strip()
logger.info(f"Word extract LLM response: {response_text[:1500]}") elif isinstance(response.content, list):
# 处理列表格式响应
text_parts = []
for item in response.content:
if isinstance(item, str):
text_parts.append(item)
elif isinstance(item, dict) and item.get("type") == "text":
text_parts.append(item.get("text", ""))
response_text = " ".join(text_parts).strip()
else:
response_text = str(response.content).strip()
# 检查响应是否为HTML错误页面
if response_text.startswith("<!DOCTYPE HTML>") or response_text.startswith("<html>") or "404 Not Found" in response_text[:100]:
logger.error(f"LLM returned HTML error page instead of JSON: {response_text[:200]}")
raise ValueError(f"LLM API returned error: {response_text[:200]}")
logger.info(f"Word extract LLM response: {response_text[:1500]}")
except Exception as e:
logger.error(f"LLM parsing failed: {e}, will use teacher mode")
# 返回空列表,降级为老师批改模式
return []
# 清理markdown标记 # 清理markdown标记
for prefix in ["```json", "```JSON", "```"]: for prefix in ["```json", "```JSON", "```"]:

View File

@ -263,21 +263,43 @@ def recognize_and_correct_node(
]) ])
] ]
client = LLMClient(ctx=ctx) # 4. 调用LLM批改带错误处理
response = client.invoke( try:
messages=messages, client = LLMClient(ctx=ctx)
model=llm_config.get("model", "doubao-seed-2-0-pro-260215"), response = client.invoke(
temperature=llm_config.get("temperature", 0.0), messages=messages,
max_completion_tokens=llm_config.get("max_completion_tokens", 8192) model=llm_config.get("model", "doubao-seed-1-6-vision-250815"),
) temperature=llm_config.get("temperature", 0.0),
max_completion_tokens=llm_config.get("max_completion_tokens", 8192)
response_text = response.content if isinstance(response.content, str) else " ".join( )
item.get("text", "") if isinstance(item, dict) else str(item)
for item in response.content # 安全提取响应文本
).strip() if isinstance(response.content, str):
response_text = response.content.strip()
# 只记录前500字符避免日志过大 elif isinstance(response.content, list):
logger.info(f"LLM response (first 500 chars): {response_text[:500]}") # 处理列表格式响应
text_parts = []
for item in response.content:
if isinstance(item, str):
text_parts.append(item)
elif isinstance(item, dict) and item.get("type") == "text":
text_parts.append(item.get("text", ""))
response_text = " ".join(text_parts).strip()
else:
response_text = str(response.content).strip()
# 检查响应是否为HTML错误页面
if response_text.startswith("<!DOCTYPE HTML>") or response_text.startswith("<html>") or "404 Not Found" in response_text[:100]:
logger.error(f"LLM returned HTML error page instead of JSON: {response_text[:200]}")
raise ValueError(f"LLM API returned error: {response_text[:200]}")
# 只记录前500字符避免日志过大
logger.info(f"LLM response (first 500 chars): {response_text[:500]}")
except Exception as e:
logger.error(f"LLM correction failed for image {image_url[:50]}...: {e}")
# 返回空结果,不影响其他图片处理
return []
# 解析结果 # 解析结果
result_dict = extract_json_from_text(response_text, "results") result_dict = extract_json_from_text(response_text, "results")