Files
inquiry_robot/prompt/14-LangGraph与Redis.md
T

128 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LangGraph 与 Redis:何时用、怎么用
给新项目实现用。可以换等价库,语义必须对齐。环境变量与 db/前缀见 `03`、`13`。
---
## 一、LangGraph 什么情况下用
**用:** 一条询价要多次停下来等人、等卡片、等主账、等 Worker 文件,然后从精确断点继续。
典型停点:补问字段、等建单结果、等 TMS 分类后的销售选择、等协同/群报价、等采用/调价、等 Excel/PDF、等成交/未成交。
**不用:**
| 事情 | 谁做 |
|---|---|
| 企微验签、inbox、解析 `sender_id` | 通道 HTTP / inbox |
| 意图(新询价 / 点卡 / 继续本单) | DeepSeek A |
| 抽字段、读图、读表 | DeepSeek B / 千问(经 LLM 队列) |
| 工单六态、报价版本真相 | 主账 MySQL |
| TMS HTTP | 主账适配器 |
| 转 PDF、写对象存储 | Worker LibreOffice 槽 |
自然语言进模型;图节点只编排和调用。节点里不准正则猜字段、不准用图状态假装主账已成功。
没有「等人/等文件」的一次性工具调用,不要硬套 Graph。
---
## 二、LangGraph 怎么用
1. **一张状态图**
节点对应业务步(解析/补问 → 建单 → 查价 → 协同 → 报价 → 采用/调价 → 成交)。停靠点(补问、等卡、等文件、等群)设为中断(现网 `interrupt_before` 一组 `pause_*`)。
2. **一条询价一个 `thread_id`**
绑会话/工单。新开询价新 thread;旧单 `resume` 精确断点。禁止拿新消息重放已提交的建单/查价。
3. **Checkpointer 在 PostgreSQL**
现网运行账:`ytd_runtime`(新进程禁止写)。新系统:`inquiry_robot_runtime`。进程重启后按 `thread_id` 捞图。不要把 checkpoint 放 Redis。
4. **谁启动图**
- 入站 → DeepSeek A →「继续本单」→ `invoke` / `resume`。无 `sender_id` 不进图。
- Worker 做完识别或 PDF → **结构化 wake**(工单号、quoteVersion、waitVersion)。用户聊天文字不能冒充「文件已生成」。
5. **waitVersion + 卡片**
补问卡、采用卡绑 `thread_id + waitVersion + 允许动作`。过期或错版本点击丢弃。H5 TTL 30 分钟。
6. **与主账边界**
图可记「准备建单、TMS 结果分类」;六态成功只认主账 API。图成功、主账失败 → 未报价。
7. **会话与图分工**
活动工单、打断栈 → conversation session;节点与业务上下文 → checkpoint;等待点 → suspend 账。不要在图里再做第二套六态机。
现网参考形态:`StateGraph` + Postgres checkpointer + `thread_id` + 中断停靠。新项目可用 LangGraph 或等价状态机,但必须有:停点、checkpoint、按版本唤醒、禁止用户文字假冒 Worker。
---
## 三、Redis 什么情况下用
**用:** 短命、可丢、可重建的协调。重启丢几秒可以接受。
| 用途 | 说明 |
|---|---|
| LLM / 识别任务队列 | Stream(或 DB 任务表二选一,见下);入口只入队,Worker 认领执行 |
| 短幂等 | 同一 `idempotency_key` 短 TTL 内不重复入队 |
| 企微 access_token 缓存 | 避免每次打企微;挂了可回内存再拉 |
| 出站 / API 限流 | 窗口计数;超限拒绝或排队,不改工单态 |
| 热缓存 | 只读加速;没有也能从 PG/MySQL 算出 |
**不用 Redis 当:**
- 工单六态、报价版本、权限(主账)
- Graph checkpoint、suspend、waitVersion、inbox/outbox 持久账(PostgreSQL)
- 附件字节(对象存储)
- Worker 进程全局单例锁(现网 `wecom:worker:singleton` / `SET NX`,新系统禁止)
- 按企微 userid 伪造 TMS 无价/异常(现网测试开关,新系统禁止)
真相在库里。Redis 挂了:队列可积压、限流失效、token 重拉;**已建单、已报价、已成交不得丢。**
---
## 四、Redis 怎么用
1. **连接**
只用 `REDIS_URL` + `REDIS_KEY_PREFIX`(或代码里统一前缀函数)。
现网:db0,前缀 `ytd:prod:…`。新系统:db1,前缀 `inquiry_robot:`。禁止新进程写现网前缀。
2. **键必须带环境前缀**
所有 key:`{REDIS_KEY_PREFIX}:…`。LLM 队列 namespace 也要能随环境错开,避免测服抢走现网任务。
3. **队列(若用 Stream)**
- `XADD` 入队,消费者组 `XREADGROUP`。
- **按条认领**:PEL + 租约心跳;Worker 挂了超时回收,别的槽再做。
- 结果短 TTL(现网约任务 300s / 结果 900s 量级,新项目可配)。
- HTTP 回调线程禁止同步等到完整 LLM(禁止 `wait_result` 堵在请求线程);只入队或写 PG 任务表后返回,由 **其它线程槽** 消费。不同任务并行认领,不要一个线程串行全部 Stream。
- 同一条消息防重入靠任务认领,不靠「全机只有一个 Worker」的 Redis 锁。
4. **也可以不用 Stream**
LLM/识别/报价任务可以全部落 PG 任务表 + 认领字段。Redis 则只留 token 缓存和限流。二选一写进设计;不要 Stream 和表双写两套真相。
5. **限流**
按 scope(全局 / 用户 / 出站)滑动或固定窗口。超限返回可重试,不写主账失败。
6. **Token 缓存**
GET 未命中再调企微;SET 带过期。失败回退再请求,不要把业务打成「未认证工单」。
7. **TTL**
队列结果、幂等、限流、token 都要过期。没有 TTL 的业务事实不要进 Redis。
8. **同机并存**
与现网共用 `10.206.0.14:6379`,**必须换 db 和前缀**。不要 `FLUSHDB`/`FLUSHALL`。
---
## 五、对照(实现时贴在旁边)
| 问题 | 放哪 |
|---|---|
| 这条询价跑到哪一节点 | Graph checkpoint(PG) |
| 能不能点这张卡 | waitVersion + clarification(PG) |
| 工单是不是已报价 | 主账六态(MySQL) |
| 下一个 LLM 任务谁做 | Redis Stream 或 PG 任务表认领 |
| 会不会把企微打爆 | Redis 限流 |
| 会不会两个进程抢同一条 inbox | 任务认领 + 超时回收;服务只起一份 |
| Worker 能不能双开 | Windows 服务一份 + 发布先停再起;**禁止** Redis 全局单例 |
LangGraph = 剧本和书签。Redis = 传话和限速。企微 = 舞台。主账 = 账本。模型 = 台词。