437 lines
22 KiB
Markdown
437 lines
22 KiB
Markdown
# AI 数字销售助手 — AI 开发者快速指南
|
||
|
||
> **本文档面向 AI 编程助手**,帮助你在最短时间内理解项目全貌并继续开发。
|
||
|
||
---
|
||
|
||
## 项目目标(务必理解)
|
||
|
||
**构建一个能完全模仿真人销售在微信上与客户对话的 AI 系统。**
|
||
|
||
核心差异:
|
||
1. **数字销售分身**:上传销售真实聊天记录,AI 提取其个人风格(方言/句式/语气/性格),构建"数字分身"
|
||
2. **四维画像驱动**:基于 **销售风格 / 项目资料 / 聊天技巧 / 客户画像** 综合理解场景后生成回复
|
||
3. **自主运营**:自动回复(按客户等级分策略)、主动触达(生日/活动)、画像自迭代、等级动态评估
|
||
4. **最终愿景**:销售只处理 AI 搞不定的关键对话,日常维护/跟进/促单全部由 AI 代劳
|
||
|
||
**你写的每一行代码都应服务于:让 AI 更像那个销售、更懂那个客户、更专业地推进销售进程。**
|
||
|
||
---
|
||
|
||
## 技术栈
|
||
|
||
```
|
||
Go 1.26 + Fiber v2 + GORM(MySQL) + MongoDB + Redis + Wire DI + 原生前端(零构建)
|
||
```
|
||
|
||
调用链:
|
||
```
|
||
HTTP → Fiber中间件(JWT) → Router → Service → Biz → Impl/Mongo → LLM
|
||
↓
|
||
registerCommon 统一包装 {code:0, message, data}
|
||
```
|
||
|
||
---
|
||
|
||
## 目录结构(★ 标注当前活跃开发区域)
|
||
|
||
```
|
||
ai_scheduler/
|
||
├── cmd/server/
|
||
│ ├── main.go # 启动入口
|
||
│ ├── wire.go # Wire DI 声明(//go:build wireinject)
|
||
│ └── wire_gen.go # Wire 自动生成(禁止手动编辑)
|
||
├── config/config.yaml # MySQL/Mongo/Redis/JWT/微信协议地址
|
||
├── internal/
|
||
│ ├── biz/ # ★ 业务逻辑层
|
||
│ │ ├── advice_wx.go # 微信回调处理 + 消息流水 + 会话聚合 + ★ 托管自动注册
|
||
│ │ ├── advice_wx_send.go # 微信消息发送(含模拟真人打字延迟)
|
||
│ │ ├── advice_strategy.go # 智能策略(四级回复/主动对话)
|
||
│ │ ├── advice_client.go # 客户管理 + 等级评估
|
||
│ │ ├── advice_customer_new.go # ★ 微信好友 CRUD + 差集同步(ai_advice_customer)
|
||
│ │ ├── advice_label.go # ★ 标签同步(与 DB 比对增删改)
|
||
│ │ ├── advice_chat.go # AI 对话(LLM 调用 + ChatWithSession 复用优化)
|
||
│ │ ├── advice_evaluate.go # 客户等级评估
|
||
│ │ ├── advice_proactive.go # 主动触达
|
||
│ │ ├── advice_iterate.go # 画像自迭代
|
||
│ │ ├── handle/、llm_service/ # ⚠️ 历史死代码,忽略
|
||
│ │ └── provider_set.go
|
||
│ ├── services/advice/ # ★ HTTP Handler 层
|
||
│ │ ├── wxhook.go # 回调 + 会话 Handler
|
||
│ │ ├── wx_proxy.go # 微信 API 代理(分发到 wxDispatchMap)
|
||
│ │ ├── wx_ws_hub.go # WebSocket Hub(实时推送)
|
||
│ │ ├── customer_new.go # ★ 好友 CRUD Handler(Diff 同时返回标签)
|
||
│ │ ├── label.go # ★ 标签 Handler(List/Sync)
|
||
│ │ └── provider_set.go
|
||
│ ├── server/
|
||
│ │ ├── router/router.go # 路由总装 + registerCommon 中间件
|
||
│ │ ├── router/advicer.go # 全部业务路由(~80 个接口)
|
||
│ │ └── http.go # NewHTTPServer 参数列表需同步
|
||
│ ├── entitys/advicer_data.go # ★ 核心 DTO(最频繁修改)
|
||
│ ├── data/
|
||
│ │ ├── model/ # MySQL GORM 模型(*.gen.go 禁止手动编辑)
|
||
│ │ │ ├── ai_advice_customer.gen.go # ★ 微信好友表
|
||
│ │ │ └── ai_advice_label.gen.go # ★ 标签表
|
||
│ │ ├── impl/ # MySQL 数据访问(继承 DataTempBase[T])
|
||
│ │ │ ├── advice_customer_impl.go
|
||
│ │ │ └── advice_label_impl.go
|
||
│ │ ├── mongo_model/ # MongoDB 集合模型
|
||
│ │ └── constants/ # Prompt 模板、模型映射
|
||
│ ├── middleware/ # JWT 认证
|
||
│ ├── jobs/advice_task.go # 定时任务(cron)
|
||
│ └── pkg/wx/ # 微信协议封装(100+ API 端点)
|
||
├── web/ # ★ 前端(零构建,静态托管)
|
||
│ ├── project.html # ★ 版本号管理(修改 JS 后必须更新 ?v=N)
|
||
│ └── assets/
|
||
│ ├── css/theme.css # 深色科技风设计系统
|
||
│ └── js/
|
||
│ ├── core.js # 核心库(Core.api / Core.wxApi / Toast / Modal)
|
||
│ ├── wx.js # ★ 微信工作台核心(state/通讯录/标签/WS/好友同步)
|
||
│ ├── wx_login.js # ★ 登录模块(二维码/在线检测/登出)
|
||
│ └── wx_chat.js # ★ 聊天模块(会话/消息/联系人详情气泡)
|
||
└── sql/ # 数据库 DDL
|
||
├── 04_ai_advice_customer.sql
|
||
└── 05_ai_advice_label.sql
|
||
```
|
||
|
||
---
|
||
|
||
## 数据模型
|
||
|
||
### MySQL 核心表
|
||
|
||
| 表名 | 说明 | 关键字段 |
|
||
|---|---|---|
|
||
| `ai_advice_customer` | ★ 微信好友(`self_wxid` + `user_name` 唯一键) | label_list, session_id(当前活跃会话) |
|
||
| `ai_advice_label` | ★ 微信标签(`self_wxid` + `label_id` 唯一键) | label_id, label_name |
|
||
| `ai_advice_advicer` | 销售基本信息 | wx_device_id(即 appId) |
|
||
| `ai_advice_project` | 项目信息 | wx_token |
|
||
| `ai_advice_admin` | 管理员账号 | |
|
||
| `ai_advice_session` | AI 对话会话 | advicer_id(托管场景动态取最新版本) |
|
||
|
||
### MongoDB 核心集合
|
||
|
||
| 集合名 | 说明 | 关键字段 |
|
||
|---|---|---|
|
||
| `advicer_wx_msg` | ★ 微信消息流水 | appId, selfWxid, wxid, direction, msgType, content, read |
|
||
| `advicer_version` | 销售画像 | dialectFeatures, sentencePatterns, toneTags, personalityTags |
|
||
| `advicer_client` | 客户画像 | clientLevel, personalInfo, purchasePurpose, coreDemands |
|
||
| `advicer_project` | 项目资料维度(结构化) | regionValue, competitionComparison, coreSellingPoints, supportingFacilities, developerBacking |
|
||
| `advicer_project_data` | ★ 项目资料(扁平栏目) | projectId + 动态栏目(key=栏目名, value=内容),与 advicer_project 是**两个独立的集合** |
|
||
| `advicer_talk_skill` | 聊天技巧维度 | needsMining, painPointResponse, closingTechniques, communicationRhythm, valueBuilding |
|
||
| `advicer_activity` | 产品活动 | name, content, startAt, endAt |
|
||
|
||
### 命名差异
|
||
- MySQL:蛇形(`user_name`)
|
||
- MongoDB:驼峰 bson(`userName`)
|
||
- 前端 JS:驼峰(`userName`)
|
||
- API 响应:snake_case(`user_name`),前端手动映射
|
||
|
||
---
|
||
|
||
## 前端架构
|
||
|
||
### 核心机制
|
||
- **零构建**:`<script>` 标签按序引入,无打包工具
|
||
- **IIFE 模式**:每个 JS 文件 `(function(global){...})(window)` 包裹
|
||
- **版本号**:`<script src="xxx.js?v=42">` — **修改 JS/CSS 后必须更新 `project.html` 中的版本号**
|
||
- **全局命名空间**:`Core`(核心库)、`WxN`(微信模块共享)、`Wx`(挂载点)
|
||
|
||
### 微信工作台模块(WxN 命名空间)
|
||
|
||
| 文件 | 职责 |
|
||
|---|---|
|
||
| `wx.js` | state 管理 / 生命周期 / 通讯录 / 标签 / WebSocket / 好友差集同步 |
|
||
| `wx_login.js` | 二维码登录 / 在线检测 / 登出 |
|
||
| `wx_chat.js` | 会话列表 / 消息渲染 / 发送 / 联系人详情悬浮气泡 |
|
||
|
||
**架构要点**:
|
||
- `wx.js` 创建 `WxN` 命名空间,通过 `Object.defineProperty` 暴露 `state` getter
|
||
- 子模块通过 `WxN.state` 访问最新状态(不在闭包中缓存 state 引用)
|
||
- 子模块通过 `WxN.xxx = fn` 导出函数
|
||
- 加载顺序:`wx.js` → `wx_login.js` → `wx_chat.js`
|
||
|
||
### Core.js 速查
|
||
|
||
```javascript
|
||
Core.api(path, params) // 管理后台 API(POST JSON,JWT,自动解包 data)
|
||
// 完整路径:/api/v1/admin/advice/admin/{path}
|
||
Core.wxApi(path, params) // 微信代理 API(自动注入 projectId)
|
||
// 完整路径:/api/v1/admin/advice/admin/wx/{path}
|
||
Core.toast(msg, type) // type: "ok"|"err"|"warn"|"info"
|
||
Core.modal({title, body}) // 模态框
|
||
Core.confirm(msg) // 确认对话框,返回 Promise<boolean>
|
||
Core.esc(str) // HTML 转义
|
||
```
|
||
|
||
---
|
||
|
||
## 关键流程
|
||
|
||
### 初始化流程
|
||
|
||
```
|
||
页面加载 → mount() → freshState()
|
||
→ 解析 URL hash (#wx-advicer=advicerId)
|
||
→ fetchDeviceAndCheck(advicerId)
|
||
→ Core.api("advicer/info", {advicerId}) 获取 wx_device_id
|
||
→ state.app = { appId: wx_device_id } ← 始终从 API 获取,不缓存
|
||
→ checkOnline()
|
||
→ 在线 → checkOnlineLoop()(内含 connectWs())
|
||
loadProfile().then(loadConversations()) ← 需要 wxid
|
||
loadContacts() → syncCustomerDiff() ← diff 同时返回标签
|
||
loadLabels() ← 与微信同步标签到 DB
|
||
→ 离线 → getQrCode() 显示二维码
|
||
```
|
||
|
||
### 好友 + 标签同步流程
|
||
|
||
```
|
||
loadContacts() → syncCustomerDiff()
|
||
→ POST advicer/customer/diff { selfWxid, userNames: friends }
|
||
→ 后端返回 { list: [已有好友], diff: [缺失userName], labels: [标签列表] }
|
||
→ 用 list 填充 state.brief(联系人简要)
|
||
→ 用 labels 填充 state.labels + state.labelMap
|
||
→ diff 不为空时:分批 getBriefInfo → batch_add 入库
|
||
|
||
loadLabels()(并行)
|
||
→ Core.wxApi("label/list") 获取微信标签
|
||
→ POST advicer/label/sync 同步到 DB(比对增删改)
|
||
→ loadLabelsFromDb() 重新加载
|
||
```
|
||
|
||
### 消息回调流程
|
||
|
||
```
|
||
上游协议服务 → POST /api/v1/advicer/wx/callback
|
||
→ advice_wx.go:解析 AddMsg → 过滤 gh_ 公众号/msgType=other
|
||
→ 去重(AppId + NewMsgId)→ 入库 MongoDB advicer_wx_msg
|
||
→ WebSocket 广播 new_message(按 appId 匹配推送)
|
||
→ 触发智能策略(客户文本消息异步 AI 决策)
|
||
→ 触发托管自动注册(文本私聊消息异步检查)
|
||
```
|
||
|
||
### 托管自动注册流程
|
||
|
||
```
|
||
消息回调 → 文本私聊 → goroutine tryHostingAutoRegis
|
||
→ (1) 查 advicer(FindByWxDeviceId)→ hosting_enabled=1?
|
||
→ (2) 查 projectInfo → 取项目级 wxToken
|
||
→ (3) 若 peerWxid == "filehelper" 且 advicer.reply_filehelper=1 → 跳过标签检查,直接进入回复流程
|
||
否则调微信 contacts/getDetailInfo 取好友 labelList("1,2,3" 形式)
|
||
labelList 为空 → 直接 return,不做回复
|
||
→ (4) 取 ai_advice_label 中该销售 hosting=1 的标签 ID 列表
|
||
→ (5) 判断好友 labelList 与托管标签是否有交集,无交集 → return
|
||
→ (6) 查 ai_advice_customer 取 session_id
|
||
→ (7) 无会话 → autoRegisSession 全量加载数据并注册:
|
||
- 加载版本数据(advicer_version)
|
||
- 加载销售技巧(advicer_talk_skill,有 HostingSkillId 按 ID 取,无则按 projectId 取最新)
|
||
- 加载客户画像(advicer_client,按 projectId+advicerId+wxid 查)
|
||
- 加载项目资料(advicer_project 结构化 + advicer_project_data 扁平栏目)
|
||
- 构建 ChatData → Regis 存入 Redis(key=chatdata:{sessionId})
|
||
→ (8) hostingChatAndSend:
|
||
- 从 Redis 取 ChatData → buildChatPromptResponse 全量注入提示词
|
||
- Chat 生成 AI 回复 → 拆段 → 模拟打字延迟 → 分段发送
|
||
```
|
||
|
||
**关键设计**:
|
||
- 标签判断改用微信实时返回的 labelList,不再依赖 customer 表缓存的标签
|
||
- projectInfo 提前到步骤 2 查询(后续 getDetailInfo 和 Chat 都需要 wxToken)
|
||
- 客户昵称优先使用微信备注名(Remark),回退到 NickName,最后才用 customer 表中的昵称
|
||
- customer 表仅用于存取 session_id,不再承担标签判断职责
|
||
- 文件传输助手(filehelper)特殊路径:销售开启 `reply_filehelper` 后,跳过标签检查,直接作为客户进行 AI 回复
|
||
|
||
### ChatData 与全量提示词注入
|
||
|
||
**ChatData 结构**(`entitys/advicer.go`):
|
||
```go
|
||
type ChatData struct {
|
||
ClientInfo *AdvicerClientMongoEntity // 客户画像(advicer_client)
|
||
TalkSkill *AdvicerTalkSkillMongoEntity // 销售技巧(advicer_talk_skill)
|
||
ProjectInfo *AdvicerProjectMongoEntity // 项目资料-结构化(advicer_project)
|
||
ProjectData map[string]interface{} // 项目资料-扁平栏目(advicer_project_data)
|
||
AdvicerInfo *AiAdviceAdvicerEntity // 销售信息(MySQL)
|
||
AdvicerVersion map[string]interface{} // 销售人设维度数据(advicer_version)
|
||
RuleDimension string // 项目风控红线
|
||
}
|
||
```
|
||
|
||
**提示词构建流程**(`buildChatPromptResponse`):
|
||
```
|
||
System Prompt = BasePrompt + Mission + RuleDimension + BasePrompt2
|
||
+ [项目信息] (advicer_project JSON)
|
||
+ [项目资料] (advicer_project_data JSON)
|
||
+ [销售信息] (advicer MySQL JSON)
|
||
+ [销售人设风格] (advicer_version JSON)
|
||
+ [客户信息] (advicer_client JSON)
|
||
+ [销售技巧] (advicer_talk_skill JSON)
|
||
+ [输出格式] (永远在最后)
|
||
---
|
||
System Prompt = 聊天记录(客户/我 对话格式)
|
||
---
|
||
User Message = 当前消息
|
||
```
|
||
|
||
**数据流**:
|
||
- Regis 时:`autoRegisSession` 全量加载所有数据 → 构建 ChatData → `json.Marshal` 存入 Redis(key=`chatdata:{sessionId}`,TTL 1h)
|
||
- Chat 时:从 Redis 取 ChatData → `compactJSON`(递归去空值省 token)→ 注入 system prompt
|
||
- `compactJSON`:序列化前递归去除空字符串、null、空数组、空对象,减少无效 token
|
||
|
||
**注意**:`advicer_project` 和 `advicer_project_data` 是**两个独立的 MongoDB 集合**,前者存结构化维度(区域价值/竞品对比等),后者存扁平栏目数据(key=栏目名)。两者都需要加载。
|
||
|
||
**模拟真人发送算法**:
|
||
- AI 回复拆分为多条短消息(每条 ≤80 字,按换行/句末标点拆分)
|
||
- 初始延迟 3~8 秒(模拟阅读 + 思考)
|
||
- 每条消息间延迟 = 思考时间(2~5s) + 打字时间(每字 300~500ms)
|
||
- 提示词约束:每条消息 10~30 字,用 `\n` 分隔
|
||
|
||
### WebSocket 实时通信
|
||
|
||
```
|
||
前端 connectWs() → /api/v1/advicer/ws?token=JWT
|
||
→ onopen 发送 {"action":"subscribe","appId": state.app.appId}
|
||
→ 后端 Broadcast(appId, event, data) → 匹配 client.appId → 推送
|
||
→ 前端 onmessage → handleWsEvent()
|
||
→ "new_message" → WxN.handleNewMessage(data)
|
||
→ "online_status" → WxN.handleOnlineStatus(data)
|
||
```
|
||
|
||
---
|
||
|
||
## 当前开发状态(截至 2026-09-27)
|
||
|
||
### 已完成
|
||
|
||
- [x] 微信工作台:登录(二维码/在线检测)、通讯录、会话、聊天、AI 建议
|
||
- [x] 好友差集同步:`ai_advice_customer` 表 + `customer/diff` + `batch_add/batch_update`
|
||
- [x] 标签同步:`ai_advice_label` 表 + `label/sync` + `label/list`
|
||
- [x] 标签在 diff 接口一并返回(进入工作台时一次请求拿到好友 + 标签)
|
||
- [x] 标签 tab:展开/折叠、好友计数、loading 状态
|
||
- [x] 好友/会话列表展示联系人标签小标签
|
||
- [x] 联系人详情悬浮气泡(hover popup,含视口边界检测)
|
||
- [x] WebSocket 实时推送新消息 + 在线状态
|
||
- [x] 去掉 localStorage 缓存(brief/labels 全部内存 state)
|
||
- [x] 托管标签自动会话注册:检查标签交集 → 自动注册 AI 会话 → 回写 session_id
|
||
- [x] 托管自动回复:注册会话 → Chat → 拆段 → 模拟真人打字延迟 → 分段发送
|
||
- [x] 项目级 wx_token 支持:SendTextWithToken 方法,托管场景使用项目级 token
|
||
- [x] 查询优化:消除重复查询(projectInfo/advicer/session),新注册路径从 ~16 次降至 ~10 次 DB
|
||
- [x] 文件传输助手自动回复:销售级开关 `reply_filehelper`,开启后跳过标签检查直接 AI 回复
|
||
- [x] filehelper 普通客户化改造:走标准 customer 流程复用 session_id
|
||
- [x] ChatData 全量数据注入:Regis 时加载全部数据(项目/销售/客户/技巧/人设),Chat 时从 Redis 取出全量注入提示词
|
||
- [x] 提示词 token 优化:`compactJSON` 递归去空值,减少无效 token
|
||
|
||
### 待开发(下一步)
|
||
|
||
#### 1. 聊天算法深度优化
|
||
|
||
**目标**:进一步提升 AI 回复的真实感,让对话更自然、更像真人销售。
|
||
|
||
**优化方向**:
|
||
- **回复节奏优化**:根据消息内容复杂度动态调整延迟(简单问候快一些,复杂问题慢一些)
|
||
- **上下文感知回复**:结合客户画像、历史对话、当前时间段等因素调整回复风格
|
||
- **多轮对话连贯性**:确保多轮对话中话题过渡自然,不重复、不突兀
|
||
- **情绪感知**:识别客户情绪(犹豫/急迫/不满),动态调整回复语气和节奏
|
||
- **回复长度自适应**:根据客户消息长度调整回复长度(客户发短句,AI 也回短句)
|
||
- **提示词迭代**:根据实际对话效果持续优化 BasePrompt,减少 AI 味、增强人味
|
||
|
||
**涉及文件**:
|
||
- `internal/data/constants/prompt.go`(提示词模板)
|
||
- `internal/biz/advice_wx.go`(splitReplyToChunks / hostingChatAndSend)
|
||
- `internal/biz/advice_wx_send.go`(typingDelay 算法)
|
||
- `internal/biz/advice_chat.go`(Chat / ChatWithSession)
|
||
- `internal/biz/advice_strategy.go`(智能策略回复)
|
||
|
||
#### 2. 标签标记为客户标签 → 客户管理联动
|
||
|
||
**目标**:给标签打上"客户标记",被标记标签下的好友自动识别为客户,在客户管理模块体现,并在销售托管(自动回复)开启时仅对这些客户生效。
|
||
|
||
**设计思路**:
|
||
- `ai_advice_label` 表新增 `is_customer_tag TINYINT(1) DEFAULT 0` 字段(1=客户标签)
|
||
- 新增 API:`advicer/label/mark_customer` { selfWxid, labelId, isCustomerTag: bool }
|
||
- 前端标签 tab:每个标签右侧增加"客户标签"开关/标记按钮
|
||
- 客户管理模块(`advice_client.go` / `client.go`):
|
||
- 查询客户时,筛选 `ai_advice_customer.label_list` 包含已标记标签 ID 的记录
|
||
- 客户列表展示来源标签名称
|
||
- 智能策略(`advice_strategy.go`):
|
||
- 自动回复/主动触达判断时,仅对"客户标签下的好友"生效(非客户标签的好友不触发 AI 自动回复)
|
||
- 读取 `ai_advice_label` 中 `is_customer_tag=1` 的标签 ID 集合,与消息发送者的 `label_list` 取交集
|
||
|
||
**涉及文件**:
|
||
- 后端:`ai_advice_label.gen.go`(加字段)、`advice_label_impl.go`(加 MarkCustomer 方法)、`advice_label.go`(加 MarkCustomer biz)、`label.go`(加 handler)、`advicer_data.go`(加 DTO)、`advice_strategy.go`(过滤逻辑)
|
||
- 前端:`wx.js`(标签 tab 渲染标记按钮)、`theme.css`(标记样式)
|
||
- SQL:`06_ai_advice_label_customer_tag.sql`(ALTER TABLE 或迁移脚本)
|
||
|
||
#### 3. 好友/会话列表 → 给好友打标签
|
||
|
||
**目标**:在好友列表和会话列表中,可以对好友(非 chatroom)添加到指定标签,类似微信原生标签管理。
|
||
|
||
**设计思路**:
|
||
- 利用微信协议 API `contacts/modifyFriendLabel`(或类似端点)修改好友的标签
|
||
- 前端:联系人详情悬浮气泡(popup)中增加"管理标签"入口,点击弹出标签选择弹窗
|
||
- 展示当前好友已有的标签(从 `state.brief[wxid].labelList` 解析)
|
||
- 展示所有可用标签(`state.labels`)
|
||
- 支持勾选/取消,确认后调用微信 API 修改,再更新 DB(`ai_advice_customer.label_list`)
|
||
- 修改后需同步更新 `state.brief[wxid].labelList` 并重新渲染
|
||
|
||
**涉及文件**:
|
||
- 后端:可能需要新增微信代理 API(`pkg/wx/qs_*.go` + `api.go` + `wx_proxy.go` wxDispatchMap)
|
||
- 前端:`wx_chat.js`(popup 中加"管理标签"按钮 + 标签选择弹窗)、`wx.js`(标签更新逻辑)
|
||
- DB:更新 `ai_advice_customer.label_list` 字段
|
||
|
||
---
|
||
|
||
## Wire 依赖注入须知
|
||
|
||
新增模块后必须:
|
||
1. 各层 `provider_set.go` 添加 Provider
|
||
2. `http.go` 的 `NewHTTPServer` 参数列表添加 Service
|
||
3. `router.go` 的 `SetupRoutes` 参数列表添加 Service
|
||
4. `router/advicer.go` 的 `AdvicerRouterRegist` 参数列表添加 Service
|
||
5. 执行 `cd cmd/server && wire` 重新生成 `wire_gen.go`
|
||
6. `go build ./cmd/server` 编译验证
|
||
|
||
---
|
||
|
||
## 避坑清单
|
||
|
||
1. **`*.gen.go` 和 `wire_gen.go` 禁止手动编辑**
|
||
2. **Mongo 全量更新是 `$set` 语义** — 必须"先读后合并再写",否则清空未提交字段
|
||
3. **微信代理响应必须设 `skip_response_wrap`** — 否则被 `registerCommon` 二次包装成 `{data:{code,data}}`
|
||
4. **前端修改必须更新版本号** — `project.html` 中 `?v=N`,不更新则浏览器用旧缓存
|
||
5. **`state.app.appId` 不缓存** — 每次 mount 从 `advicer/info` API 实时获取
|
||
6. **`checkOnlineLoop()` 已内含 `connectWs()`** — 不要额外调用,否则连接级联断开
|
||
7. **`loadProfile()` 返回 Promise** — 依赖 `state.app.wxid` 的操作必须在其 `.then()` 中执行
|
||
8. **子模块通过 `WxN.state` getter 访问状态** — 不要在闭包中缓存 state 引用
|
||
9. **`builder.Cond` 查询用指针** — DataTemp 方法接受 `*builder.Cond` 指针
|
||
10. **`dataTemp.ReqPageBo` 分页字段是 `Limit`** — 不是 `PageSize`
|
||
11. **新增 Service 后同步三个文件** — `http.go`、`router.go`、`advicer.go` 函数签名都要加参数
|
||
12. **会话/消息查询用 `selfWxid` 筛选** — 不用 `appId`(appId 会变)
|
||
13. **WebSocket 订阅 appId 必须与广播 appId 一致** — 前端用 `wx_device_id`,后端用回调的 `Appid` 字段
|
||
14. **历史遗留代码**(`internal/biz/handle`、`llm_service`)是死代码,可忽略
|
||
15. **`advicer_project` 和 `advicer_project_data` 是两个独立的 MongoDB 集合** — 前者存结构化维度(RegionValue/CompetitionComparison 等),后者存扁平栏目数据(key=栏目名, value=内容)。加载项目数据时两者都要查
|
||
16. **HostingSkillId 为空时取最新** — 用 `VersionList(projectId)` 取第一条,不是跳过
|
||
17. **PreviousResponseID 续写不继承 system prompt** — Chat 时必须从 Redis 取 ChatData 重新注入全部数据,不能依赖 context cache 续写
|
||
18. **修改 JS/CSS 后必须更新版本号** — 否则浏览器用旧缓存,看起来像没改
|
||
|
||
---
|
||
|
||
## 编译与部署
|
||
|
||
```bash
|
||
# 编译(仅验证业务代码)
|
||
go build ./internal/entitys/ ./internal/services/advice/ ./cmd/server/
|
||
|
||
# 本地运行
|
||
go run cmd/server/main.go
|
||
|
||
# Wire 重新生成
|
||
cd cmd/server && wire
|
||
|
||
# Docker 部署
|
||
docker-compose up -d
|
||
```
|
||
|
||
---
|
||
|
||
*最后更新:2026-09-27*
|