init
This commit is contained in:
399
CODE_ARCHITECTURE.md
Normal file
399
CODE_ARCHITECTURE.md
Normal file
@@ -0,0 +1,399 @@
|
||||
# 青岛岗位匹配系统 - 代码架构文档
|
||||
|
||||
## 项目概述
|
||||
|
||||
这是一个基于 Go 语言开发的智能岗位匹配系统,提供兼容 OpenAI `/v1/chat/completions` API 的接口。系统集成了 LLM 大模型、高德地图、OCR 文件解析、政策咨询等多种服务。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
qd-sc/
|
||||
├── cmd/server/main.go # 应用入口
|
||||
├── internal/ # 内部包(不对外暴露)
|
||||
│ ├── api/ # API 层
|
||||
│ │ ├── handler/ # HTTP 请求处理器
|
||||
│ │ └── middleware/ # 中间件
|
||||
│ ├── client/ # 外部服务客户端
|
||||
│ ├── config/ # 配置管理
|
||||
│ ├── model/ # 数据模型定义
|
||||
│ └── service/ # 业务逻辑层
|
||||
├── pkg/ # 公共包(可对外暴露)
|
||||
│ ├── metrics/ # 性能指标收集
|
||||
│ └── utils/ # 工具函数
|
||||
└── config.yaml # 配置文件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 模块详解
|
||||
|
||||
### 1. 入口模块 (`cmd/server/main.go`)
|
||||
|
||||
**职责**:应用启动、依赖注入、路由配置、优雅关闭
|
||||
|
||||
**核心流程**:
|
||||
1. 加载配置文件(支持 `-config` 参数指定路径)
|
||||
2. 初始化各类客户端(LLM、高德、岗位、OCR)
|
||||
3. 初始化服务层(位置、岗位、政策、聊天)
|
||||
4. 配置 Gin 路由和中间件
|
||||
5. 启动 HTTP 服务器
|
||||
6. 监听系统信号,实现优雅关闭
|
||||
|
||||
**路由配置**:
|
||||
| 路径 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/` | GET | API 信息 |
|
||||
| `/health` | GET | 健康检查 |
|
||||
| `/metrics` | GET | 性能指标 |
|
||||
| `/v1/chat/completions` | POST | 聊天接口(主接口) |
|
||||
| `/debug/pprof/*` | GET | 性能分析 |
|
||||
|
||||
---
|
||||
|
||||
### 2. 配置模块 (`internal/config/`)
|
||||
|
||||
**文件**:`config.go`
|
||||
|
||||
**职责**:配置加载、环境变量覆盖、默认值设置
|
||||
|
||||
**配置结构**:
|
||||
```go
|
||||
type Config struct {
|
||||
Server ServerConfig // 服务器配置(端口、超时)
|
||||
LLM LLMConfig // LLM 配置(API地址、密钥、模型)
|
||||
Amap AmapConfig // 高德地图配置
|
||||
JobAPI JobAPIConfig // 岗位 API 配置
|
||||
OCR OCRConfig // OCR 服务配置
|
||||
Policy PolicyConfig // 政策咨询配置
|
||||
Logging LoggingConfig // 日志配置
|
||||
Performance PerformanceConfig // 性能配置
|
||||
}
|
||||
```
|
||||
|
||||
**环境变量支持**:
|
||||
- `LLM_API_KEY` / `LLM_BASE_URL` / `LLM_MODEL`
|
||||
- `AMAP_API_KEY`
|
||||
- `OCR_BASE_URL`
|
||||
- `POLICY_LOGIN_NAME` / `POLICY_USER_KEY` / `POLICY_SERVICE_ID`
|
||||
- `SERVER_PORT`
|
||||
|
||||
---
|
||||
|
||||
### 3. 数据模型 (`internal/model/`)
|
||||
|
||||
#### 3.1 `openai.go` - OpenAI 兼容模型
|
||||
|
||||
定义与 OpenAI API 兼容的请求/响应结构:
|
||||
|
||||
- `ChatCompletionRequest` - 聊天请求
|
||||
- `ChatCompletionResponse` - 聊天响应
|
||||
- `ChatCompletionChunk` - 流式响应块
|
||||
- `Message` - 消息结构(支持文本和多模态)
|
||||
- `Tool` / `ToolCall` - 工具调用相关
|
||||
- `ErrorResponse` - 错误响应
|
||||
|
||||
#### 3.2 `job.go` - 岗位相关模型
|
||||
|
||||
- `JobQueryRequest` - 岗位查询请求参数
|
||||
- `JobAPIResponse` - 岗位 API 原始响应
|
||||
- `JobListing` - 单个岗位信息
|
||||
- `FormattedJob` - 格式化后的岗位信息
|
||||
- `EducationMap` / `ExperienceMap` / `LocationMap` - 代码映射表
|
||||
|
||||
#### 3.3 `policy.go` - 政策咨询模型
|
||||
|
||||
- `PolicyTicketRequest/Response` - Ticket 获取
|
||||
- `PolicyChatRequest/Response` - 政策对话
|
||||
|
||||
#### 3.4 `tool.go` - 工具定义
|
||||
|
||||
**`GetAvailableTools()`** - 返回所有可用工具:
|
||||
|
||||
| 工具名 | 功能 |
|
||||
|--------|------|
|
||||
| `queryLocation` | 查询地点经纬度(高德地图) |
|
||||
| `queryJobsByArea` | 按区域代码查询岗位 |
|
||||
| `queryJobsByLocation` | 按经纬度查询附近岗位 |
|
||||
| `parsePDF` | 解析 PDF 文件 |
|
||||
| `parseImage` | 解析图片文件 |
|
||||
| `queryPolicy` | 政策咨询 |
|
||||
|
||||
**`SystemPrompt`** - 系统提示词,定义 AI 助手的行为规范:
|
||||
- 强制调用工具获取岗位数据,禁止编造
|
||||
- 工具链思维模式
|
||||
- 输出格式要求
|
||||
|
||||
---
|
||||
|
||||
### 4. 客户端层 (`internal/client/`)
|
||||
|
||||
#### 4.1 `http_client.go` - HTTP 客户端工厂
|
||||
|
||||
提供优化的 HTTP 客户端配置:
|
||||
- 连接池管理
|
||||
- HTTP/2 支持
|
||||
- 超时配置
|
||||
- 缓冲区优化
|
||||
|
||||
```go
|
||||
NewHTTPClient(config) // 通用客户端
|
||||
NewLLMHTTPClient(timeout) // LLM 专用(更大连接池)
|
||||
```
|
||||
|
||||
#### 4.2 `llm_client.go` - LLM 客户端
|
||||
|
||||
**方法**:
|
||||
- `ChatCompletion()` - 非流式请求(带重试机制)
|
||||
- `ChatCompletionStream()` - 流式请求(返回 channel)
|
||||
|
||||
**特性**:
|
||||
- 自动重试(5xx 和 429 错误)
|
||||
- SSE 流式解析
|
||||
- 大缓冲区防止超大响应
|
||||
|
||||
#### 4.3 `amap_client.go` - 高德地图客户端
|
||||
|
||||
**方法**:
|
||||
- `SearchPlace(keywords)` - 搜索地点
|
||||
- `GetLocationCoordinates(keywords)` - 获取经纬度
|
||||
|
||||
#### 4.4 `job_client.go` - 岗位 API 客户端
|
||||
|
||||
**方法**:
|
||||
- `QueryJobs(req)` - 查询岗位列表
|
||||
- `FormatJobResponse(apiResp)` - 格式化响应(代码转文字)
|
||||
|
||||
#### 4.5 `ocr_client.go` - OCR 服务客户端
|
||||
|
||||
**方法**:
|
||||
- `ParseURL(fileURL)` - 解析远程文件(图片/PDF/Excel/PPT)
|
||||
|
||||
#### 4.6 `policy_client.go` - 政策咨询客户端
|
||||
|
||||
**方法**:
|
||||
- `GetTicket()` - 获取访问票据(自动缓存,1小时有效)
|
||||
- `Chat(chatReq)` - 非流式对话
|
||||
- `ChatStream(chatReq)` - 流式对话
|
||||
|
||||
---
|
||||
|
||||
### 5. 服务层 (`internal/service/`)
|
||||
|
||||
#### 5.1 `chat_service.go` - 核心聊天服务
|
||||
|
||||
**职责**:消息处理、工具调用编排、流式输出
|
||||
|
||||
**核心方法**:
|
||||
|
||||
```go
|
||||
ProcessChatRequest(req) // 非流式处理
|
||||
ProcessChatRequestStream(ctx, req) // 流式处理
|
||||
```
|
||||
|
||||
**关键特性**:
|
||||
|
||||
1. **岗位意图检测** (`isJobQueryIntent`)
|
||||
- 关键词匹配检测用户是否在查询岗位
|
||||
- 检测到岗位意图时强制调用工具
|
||||
|
||||
2. **幻觉检测** (`containsJobHallucination`)
|
||||
- 正则匹配检测 AI 是否自行编造岗位信息
|
||||
- 拦截幻觉输出,强制重新调用工具
|
||||
|
||||
3. **简历检测** (`isResumeContent`)
|
||||
- 关键词匹配判断 OCR 内容是否为简历
|
||||
- 非简历内容会提示先询问用户意图
|
||||
|
||||
4. **工具调用循环**
|
||||
- 最多 10 轮工具调用
|
||||
- 自动合并流式响应中的分块工具调用
|
||||
- 岗位结果分块输出(每个岗位间隔 1 秒)
|
||||
|
||||
5. **消息预处理** (`prepareMessages`)
|
||||
- 注入系统提示词
|
||||
- 处理 Vision API 格式的文件 URL
|
||||
- 自动调用 OCR 解析文件
|
||||
|
||||
#### 5.2 `job_service.go` - 岗位服务
|
||||
|
||||
**方法**:
|
||||
- `QueryJobsByArea(params)` - 按区域查询
|
||||
- `QueryJobsByLocation(params)` - 按位置查询
|
||||
|
||||
#### 5.3 `location_service.go` - 位置服务
|
||||
|
||||
**方法**:
|
||||
- `QueryLocation(keywords)` - 查询地点坐标
|
||||
|
||||
#### 5.4 `policy_service.go` - 政策服务
|
||||
|
||||
**方法**:
|
||||
- `QueryPolicy(...)` - 政策咨询(支持多轮对话和实名咨询)
|
||||
|
||||
---
|
||||
|
||||
### 6. API 处理器 (`internal/api/handler/`)
|
||||
|
||||
#### 6.1 `chat.go` - 聊天处理器
|
||||
|
||||
**方法**:
|
||||
- `ChatCompletions(c)` - 主接口处理
|
||||
- 验证请求参数
|
||||
- 根据 `stream` 参数分发到流式/非流式处理
|
||||
|
||||
**流式响应**:
|
||||
- SSE 格式输出
|
||||
- 支持客户端断开检测
|
||||
- 错误时发送错误 chunk
|
||||
|
||||
#### 6.2 `health.go` - 健康检查
|
||||
|
||||
返回服务状态信息。
|
||||
|
||||
#### 6.3 `metrics.go` - 指标处理器
|
||||
|
||||
返回性能统计数据。
|
||||
|
||||
#### 6.4 `response.go` - 统一响应
|
||||
|
||||
提供 `Error()` 和 `Success()` 方法统一响应格式。
|
||||
|
||||
---
|
||||
|
||||
### 7. 中间件 (`internal/api/middleware/`)
|
||||
|
||||
#### 7.1 `cors.go` - 跨域处理
|
||||
|
||||
- 支持携带凭证的请求
|
||||
- 预检请求处理
|
||||
- 24 小时缓存
|
||||
|
||||
#### 7.2 `ratelimit.go` - 限流
|
||||
|
||||
**算法**:令牌桶(Token Bucket)
|
||||
|
||||
**配置**:
|
||||
- 桶容量:200(最大突发)
|
||||
- 补充速率:50/秒(持续 QPS)
|
||||
|
||||
**实现**:CAS 无锁算法,高并发友好
|
||||
|
||||
#### 7.3 `recovery.go` - Panic 恢复
|
||||
|
||||
捕获 panic,打印堆栈,返回 500 错误。
|
||||
|
||||
#### 7.4 `metrics.go` - 指标收集
|
||||
|
||||
记录请求数、延迟、失败数等指标。
|
||||
|
||||
---
|
||||
|
||||
### 8. 工具包 (`pkg/`)
|
||||
|
||||
#### 8.1 `metrics/metrics.go` - 性能指标
|
||||
|
||||
**收集指标**:
|
||||
- 请求计数(总数、活跃、失败、流式)
|
||||
- 延迟统计(平均、最小、最大)
|
||||
- 系统指标(goroutine、内存、GC)
|
||||
|
||||
**实现**:原子操作 + sync.Map,无锁高性能
|
||||
|
||||
#### 8.2 `utils/json.go` - JSON 工具
|
||||
|
||||
`ToJSONStringPretty()` - 格式化 JSON 输出
|
||||
|
||||
---
|
||||
|
||||
## 数据流图
|
||||
|
||||
```
|
||||
用户请求
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Gin Router │
|
||||
│ + 中间件 │
|
||||
│ (CORS/限流/恢复)│
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ ChatHandler │
|
||||
│ (请求验证) │
|
||||
└────────┬────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ ChatService │◄──────────────────────┐
|
||||
│ (核心编排) │ │
|
||||
└────────┬────────┘ │
|
||||
│ │
|
||||
┌────┴────┬────────┬────────┐ │
|
||||
▼ ▼ ▼ ▼ │
|
||||
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │
|
||||
│LLM │ │Job │ │Location│ │Policy │ │
|
||||
│Client │ │Service│ │Service │ │Service│ │
|
||||
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ │
|
||||
│ │ │ │ │
|
||||
▼ ▼ ▼ ▼ │
|
||||
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │
|
||||
│OpenAI │ │岗位API │ │高德API │ │政策API │ │
|
||||
│ API │ │ │ │ │ │ │ │
|
||||
└───────┘ └───────┘ └───────┘ └───────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────┘
|
||||
(工具调用循环)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键设计
|
||||
|
||||
### 1. 工具调用机制
|
||||
|
||||
系统通过 LLM 的 Function Calling 能力实现智能工具调用:
|
||||
|
||||
1. 用户发送消息
|
||||
2. LLM 分析意图,决定调用哪些工具
|
||||
3. 服务端执行工具调用,获取真实数据
|
||||
4. 将工具结果返回给 LLM
|
||||
5. LLM 基于真实数据生成回复
|
||||
|
||||
### 2. 幻觉防护
|
||||
|
||||
为防止 LLM 编造岗位信息:
|
||||
|
||||
1. **意图检测**:检测到岗位查询时设置 `tool_choice=required`
|
||||
2. **输出检测**:正则匹配检测疑似编造的岗位信息
|
||||
3. **强制重试**:检测到幻觉时强制重新调用工具
|
||||
|
||||
### 3. 流式输出优化
|
||||
|
||||
- 岗位信息分块输出,每个岗位间隔 1 秒
|
||||
- 使用 `job-json` 代码块格式,便于前端渲染
|
||||
- 过滤 tool_calls 相关 chunk,对客户端透明
|
||||
|
||||
### 4. 连接池优化
|
||||
|
||||
- LLM 客户端:200 最大连接,100/host
|
||||
- 其他客户端:100 最大连接,50/host
|
||||
- 启用 HTTP/2
|
||||
- 32KB 读写缓冲
|
||||
|
||||
---
|
||||
|
||||
## 扩展指南
|
||||
|
||||
### 添加新工具
|
||||
|
||||
1. 在 `model/tool.go` 的 `GetAvailableTools()` 中添加工具定义
|
||||
2. 在 `service/chat_service.go` 的 `executeToolCall()` 中添加处理分支
|
||||
3. 实现对应的处理函数
|
||||
|
||||
### 添加新的外部服务
|
||||
|
||||
1. 在 `config/config.go` 中添加配置结构
|
||||
2. 在 `client/` 下创建新的客户端
|
||||
3. 在 `service/` 下创建对应的服务层
|
||||
4. 在 `main.go` 中初始化并注入
|
||||
Reference in New Issue
Block a user