365 lines
8.1 KiB
Markdown
365 lines
8.1 KiB
Markdown
# AI 服务统一说明
|
||
|
||
**更新时间**: 2025-12-27
|
||
|
||
---
|
||
|
||
## 统一后的 AI 服务架构
|
||
|
||
系统已完成 AI 服务的统一整理,现在只保留一个标准的 AI 服务实现。
|
||
|
||
---
|
||
|
||
## 文件位置
|
||
|
||
### ✅ 保留的文件(唯一 AI 服务实现)
|
||
|
||
**核心服务:**
|
||
- **`api/services/ai_service.js`** - AI 服务主文件(基于阿里云 Qwen 2.5)
|
||
- **`api/services/ai_call_recorder.js`** - AI 调用记录服务
|
||
|
||
**导出管理:**
|
||
- **`api/services/index.js`** - 服务统一导出
|
||
|
||
**数据库层:**
|
||
- **`api/model/ai_call_records.js`** - AI 调用记录模型
|
||
|
||
**后台管理:**
|
||
- **`api/controller_admin/ai_call_records.js`** - 后台管理 API
|
||
|
||
**前端界面:**
|
||
- **`admin/src/views/system/ai_call_records.vue`** - 管理界面
|
||
- **`admin/src/api/system/ai_call_records_server.js`** - API 服务
|
||
|
||
### ❌ 已删除的文件
|
||
|
||
- ~~`api/middleware/job/aiService.js`~~ - 已删除(内容已迁移到 `services/ai_service.js`)
|
||
|
||
---
|
||
|
||
## 使用方式
|
||
|
||
### 1. 直接引用(推荐)
|
||
|
||
```javascript
|
||
const aiService = require('./services/ai_service');
|
||
|
||
// 使用 AI 服务
|
||
const result = await aiService.analyzeJob(jobInfo, resumeInfo);
|
||
```
|
||
|
||
### 2. 通过服务管理器
|
||
|
||
```javascript
|
||
const { AIService } = require('./services');
|
||
|
||
// 使用 AI 服务
|
||
const result = await AIService.analyzeJob(jobInfo, resumeInfo);
|
||
```
|
||
|
||
---
|
||
|
||
## AI 服务功能列表
|
||
|
||
### 核心方法
|
||
|
||
| 方法 | 说明 | 业务类型 |
|
||
|------|------|---------|
|
||
| `callAPI(prompt, options)` | 基础 API 调用 | 自定义 |
|
||
| `analyzeJob(jobInfo, resumeInfo)` | 岗位智能筛选 | `job_analysis` |
|
||
| `generateChatContent(jobInfo, resumeInfo, chatType)` | 生成个性化聊天 | `chat_generation` |
|
||
| `analyzeResume(resumeText)` | 简历分析 | `resume_analysis` |
|
||
| `generateInterviewInvitation(jobInfo, chatHistory)` | 生成面试邀约 | `interview_invitation` |
|
||
| `identifyOutsourcingJob(jobInfo)` | 识别外包岗位 | `outsourcing_detection` |
|
||
|
||
### 辅助方法
|
||
|
||
| 方法 | 说明 |
|
||
|------|------|
|
||
| `recordAiCall(params)` | 记录 AI 调用 |
|
||
| `calculateCost(totalTokens)` | 计算调用费用 |
|
||
|
||
---
|
||
|
||
## Token 自动记录
|
||
|
||
所有通过 `callAPI()` 方法的调用都会自动记录以下信息:
|
||
|
||
- **Token 使用量**:prompt_tokens, completion_tokens, total_tokens
|
||
- **成本信息**:基于模型计算的费用
|
||
- **性能指标**:响应时间(毫秒)
|
||
- **状态跟踪**:成功/失败状态
|
||
- **业务关联**:business_type, reference_id
|
||
- **请求追踪**:完整的请求和响应内容
|
||
|
||
记录过程是异步非阻塞的,不会影响 AI 调用的主流程。
|
||
|
||
---
|
||
|
||
## 配置说明
|
||
|
||
### 环境变量
|
||
|
||
在 `.env` 文件中配置:
|
||
|
||
```bash
|
||
# 阿里云 DashScope API Key
|
||
AI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxx
|
||
|
||
# 模型选择(可选)
|
||
AI_MODEL=qwen-turbo # qwen-turbo, qwen-plus, qwen-max, qwen-long
|
||
```
|
||
|
||
### 代码配置
|
||
|
||
```javascript
|
||
// 在 config/config.js 中
|
||
module.exports = {
|
||
ai: {
|
||
apiKey: process.env.AI_API_KEY,
|
||
model: process.env.AI_MODEL || 'qwen-turbo'
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 模型选择
|
||
|
||
| 模型 | 速度 | 质量 | 成本 | 价格(元/1000 tokens)|
|
||
|------|------|------|------|---------------------|
|
||
| qwen-turbo | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ¥0.003 |
|
||
| qwen-plus | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ¥0.004 |
|
||
| qwen-max | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ¥0.12 |
|
||
| qwen-long | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | - |
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### 示例 1:岗位分析
|
||
|
||
```javascript
|
||
const aiService = require('./services/ai_service');
|
||
|
||
const jobInfo = {
|
||
companyName: '阿里巴巴',
|
||
jobTitle: 'Node.js 高级工程师',
|
||
salary: '30-50K',
|
||
location: '杭州',
|
||
description: '负责后端服务开发...',
|
||
skills: 'Node.js, MySQL, Redis'
|
||
};
|
||
|
||
const resumeInfo = {
|
||
skills: 'Node.js, JavaScript, MySQL',
|
||
experience: '5年后端开发经验',
|
||
education: '本科',
|
||
expectedSalary: '35K'
|
||
};
|
||
|
||
const result = await aiService.analyzeJob(jobInfo, resumeInfo);
|
||
console.log(result.analysis);
|
||
```
|
||
|
||
### 示例 2:生成聊天内容
|
||
|
||
```javascript
|
||
const result = await aiService.generateChatContent(
|
||
jobInfo,
|
||
resumeInfo,
|
||
'greeting' // greeting, interview, followup
|
||
);
|
||
|
||
console.log(result.content);
|
||
```
|
||
|
||
### 示例 3:简历分析
|
||
|
||
```javascript
|
||
const resumeText = `
|
||
姓名:张三
|
||
技能:Node.js, React, MySQL
|
||
工作经验:3年全栈开发
|
||
...
|
||
`;
|
||
|
||
const result = await aiService.analyzeResume(resumeText);
|
||
console.log(result.analysis);
|
||
// {
|
||
// skillTags: ['Node.js', 'React', 'MySQL'],
|
||
// strengths: '...',
|
||
// weaknesses: '...',
|
||
// careerSuggestion: '...',
|
||
// competitiveness: 75
|
||
// }
|
||
```
|
||
|
||
### 示例 4:自定义 AI 调用
|
||
|
||
```javascript
|
||
const result = await aiService.callAPI(
|
||
'请帮我分析这个岗位的发展前景...',
|
||
{
|
||
systemPrompt: '你是一个职业规划专家...',
|
||
temperature: 0.7,
|
||
maxTokens: 2000,
|
||
user_id: 123,
|
||
business_type: 'career_analysis'
|
||
}
|
||
);
|
||
|
||
console.log(result.content);
|
||
```
|
||
|
||
---
|
||
|
||
## 错误处理
|
||
|
||
AI 服务内置了重试机制(最多 3 次)和错误处理:
|
||
|
||
```javascript
|
||
try {
|
||
const result = await aiService.analyzeJob(jobInfo, resumeInfo);
|
||
} catch (error) {
|
||
console.error('AI 调用失败:', error.message);
|
||
// 错误会自动记录到 ai_call_records 表
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 监控与统计
|
||
|
||
### 查看调用记录
|
||
|
||
登录后台管理系统:**系统设置** → **AI调用记录**
|
||
|
||
### 统计信息
|
||
|
||
- 总调用次数
|
||
- Token 总使用量
|
||
- 总费用统计
|
||
- 平均响应时间
|
||
- 成功率
|
||
|
||
### 编程方式获取统计
|
||
|
||
```javascript
|
||
const AiCallRecorder = require('./services/ai_call_recorder');
|
||
|
||
// 获取用户统计
|
||
const userStats = await AiCallRecorder.getUserTokenStats(userId, {
|
||
startDate: new Date('2025-01-01'),
|
||
endDate: new Date('2025-12-31')
|
||
});
|
||
|
||
console.log(userStats);
|
||
// {
|
||
// total_calls: 100,
|
||
// total_prompt_tokens: 5000,
|
||
// total_completion_tokens: 3000,
|
||
// total_tokens: 8000,
|
||
// total_cost: 24.00,
|
||
// avg_response_time: 1500
|
||
// }
|
||
```
|
||
|
||
---
|
||
|
||
## 注意事项
|
||
|
||
### 1. API Key 安全
|
||
|
||
- ❌ 不要将 API Key 硬编码在代码中
|
||
- ❌ 不要将 `.env` 文件提交到版本控制
|
||
- ✅ 使用环境变量管理 API Key
|
||
- ✅ 生产环境使用独立的 API Key
|
||
|
||
### 2. 成本控制
|
||
|
||
- 选择合适的模型(开发用 turbo,生产用 plus)
|
||
- 设置合理的 `maxTokens` 限制
|
||
- 监控 Token 使用量
|
||
- 定期查看费用统计
|
||
|
||
### 3. 性能优化
|
||
|
||
- 重试机制已内置(3 次)
|
||
- 超时设置为 30 秒
|
||
- Token 记录是异步的,不阻塞主流程
|
||
|
||
### 4. 数据隐私
|
||
|
||
- 请求和响应内容会完整记录到数据库
|
||
- 注意敏感信息的处理
|
||
- 定期清理历史记录
|
||
|
||
---
|
||
|
||
## 迁移指南
|
||
|
||
如果你的代码之前引用了 `middleware/job/aiService.js`,请修改为:
|
||
|
||
```javascript
|
||
// ❌ 旧代码
|
||
const aiService = require('../middleware/job/aiService');
|
||
|
||
// ✅ 新代码
|
||
const aiService = require('../services/ai_service');
|
||
```
|
||
|
||
功能保持完全一致,只是路径发生了变化。
|
||
|
||
---
|
||
|
||
## 故障排查
|
||
|
||
### 问题 1:模型未加载
|
||
|
||
**错误信息:** `Cannot read property 'findAll' of undefined`
|
||
|
||
**解决方法:**
|
||
1. 确认已执行建表 SQL:`_sql/create_ai_call_records_table.sql`
|
||
2. 重启 Node.js 服务
|
||
3. 检查 `api/model/ai_call_records.js` 是否存在
|
||
|
||
### 问题 2:认证失败
|
||
|
||
**错误信息:** `auth header format should be Bearer sk-...`
|
||
|
||
**解决方法:**
|
||
1. 检查 `.env` 文件中的 `AI_API_KEY`
|
||
2. 确认 API Key 格式正确(以 `sk-` 开头)
|
||
3. 验证 API Key 有效性
|
||
|
||
### 问题 3:记录失败
|
||
|
||
**警告信息:** `记录AI调用失败(不影响主流程)`
|
||
|
||
**解决方法:**
|
||
1. 检查数据库连接
|
||
2. 确认 `ai_call_records` 表存在
|
||
3. 查看详细错误日志
|
||
|
||
### 问题 4:费用计算不准确
|
||
|
||
**解决方法:**
|
||
1. 检查 `calculateCost()` 方法中的价格配置
|
||
2. 根据实际使用的模型调整价格
|
||
3. 定期对账单进行核对
|
||
|
||
---
|
||
|
||
## 相关文档
|
||
|
||
- [AI 服务配置说明](ai_service_config.md) - 详细的环境配置指南
|
||
- [功能实施总结](implementation_summary.md) - 完整的功能实施文档
|
||
- [API 文档](../api/controller_admin/ai_call_records.js) - 后台 API 接口说明
|
||
|
||
---
|
||
|
||
**文档版本**: 1.0
|
||
**最后更新**: 2025-12-27
|
||
**维护者**: 开发团队
|