7.5 KiB
提示词:Python 智能体 / Worker 端
你负责与现网询价智能体 功能等价 的运行时。代码全新组织,不要做成单文件上帝模块。每个模块、Handler、Graph 节点、队列/槽代码必须有详细中文注释(文件头 + 函数职责/副作用/线程;见 05 注释节)。无注释不验收。
必须提供的进程
只允许下面这些自研进程(详见 01 目标进程):
- 一个 HTTP:合并现 8810/8809/8811。询价入口、H5、主账唤醒、企微应用回调。请求线程只验签、入 inbox/任务表、返回;禁止同步 LibreOffice / 等完整 LLM。
- 一个 Worker:消费 LLM、识别、报价(Excel→PDF)、微盛存档。队列 + 按任务认领(处理中/超时回收)+ 重试。并发:LibreOffice 1 槽,其余 HTTP 类 2~3 槽。Windows 服务只起一份;禁止 Redis 全局 Worker 单例锁(现网
wecom:worker:singleton)。 - AIBOT 客户端:连本机 8813 桥;桥进程可仍是 Node
.cjs。 - 企微 inbox 消费与 outbox 外发:放在 HTTP 进程的快循环,或 Worker 里与 soffice 隔离的槽,不得和转 PDF 串行互堵。
不要:独立 bridge_api / wecom_robot 端口;五个 NSSM Worker。群机器人 8812 默认不做。
禁止卡顿(必须多线程 / 多槽)
实现验收:企微回调与 H5 在慢活进行时仍能秒回;一份 PDF 不能拖死收消息、查价、出站。
- 请求线程只做短事:验签、去重、入 inbox/任务表、202/明文成功码、返回。禁止在回调 / H5 / 唤醒 HTTP 里同步
invoke完整 Graph、等 LLM、跑 soffice。 - 尽量用多线程:HTTP 用线程池(uvicorn workers 或等价);Worker 进程内用线程槽并行——HTTP 类(模型、识别、主账、存档、outbox)至少 2~3 槽;inbox 消费与 outbox 外发独立线程,不得和转 PDF 排成一条队列。
- 唯一例外:LibreOffice 1 个槽(本机两台 soffice 会互抢卡死)。这不是「整进程单线程」。
- I/O 等待要让出:调企微、主账、TMS 经主账、对象存储、模型 HTTP 用超时 + 线程池;禁止无限阻塞、禁止热循环
sleep轮询把槽占满。Graphresume放在 Worker 槽里跑,不要占回调线程。 - 禁止用一把进程大锁串行所有工单。防重入只锁「同一条任务 / 同一个 thread_id 的写冲突」,不同工单必须能同时跑。
- 共享状态要线程安全:checkpoint、认领、outbox 用 DB 事务或按条锁,不要无锁改全局 dict。
- Windows 上线程优先于再开多个 Python 进程(已规定只有一个 Worker 进程)。需要并行就加槽/线程,不要再拆 NSSM。
卡住整机的写法一律视为缺陷,不是「先跑通再优化」。
模块边界
NormalizedInbound
→ 冻结只读状态快照
→ 允许的意图集合
→ DeepSeek A 唯一 route_decision
→ 确定性 RouteDecision
→ 唯一 handler
→ 执行到下一个 wait 边界
→ 持久化 version + 幂等键
模块划分(源码,不是进程)
进程可以只有 HTTP + Worker;包必须按功能切开。现网把编排、企微业务、识别堆进超大文件,新项目禁止复现。
建议包(名称可改,边界不能混):
| 包 | 只做什么 | 不准塞什么 |
|---|---|---|
channel/wecom |
验签、XML/JSON 解析、sender_id、inbox 写入 |
Graph、LLM、建单 |
channel/h5 |
表单上传、clarification 页 | 六态、TMS |
channel/outbox |
企微发送、限流、重试 | 抽字段 |
routing |
DeepSeek A、RouteDecision | 副作用(建单/发消息) |
handlers/ |
每类意图一个模块:会话、补问、建单、TMS 展示、协同、采用/调价、成交、异常 | 一个文件处理全部卡片 |
graph/ |
图定义、节点各文件、pause/resume、wake | 企微 HTTP、soffice |
llm/ |
网关、队列、各 mode schema | 业务六态 |
jobs/ |
认领循环、识别槽、LibreOffice 槽、Archive 槽 | 回调路由 |
ledger/ |
主账 HTTP 客户端 | 直连 TMS、直连 MySQL |
storage/ |
对象存储 | 工单状态 |
config/ |
只读环境变量 | 业务 if/else |
规则:
- 新功能先归包再写代码。入口(
main、FastAPIapp、Worker 启动)只组装依赖,不写业务分支。 - Graph 节点分文件(或按阶段分子包),禁止单文件堆全部节点。
- Handler 一类卡片/一类意图一个文件;公共校验放
schema/或policy/,不要复制粘贴进每个 handler。 - 跨包只通过明确接口(函数/协议/事件),禁止互相 import 私有内部函数绕过边界。
- 单文件超过约 400~600 行且已含两类职责:拆,不要继续往下加。
堆在一起的上帝模块一律视为缺陷,与卡顿同样不可验收。缺详细中文注释同样不可验收。
身份
入站已带企微 userid(sender_id)。禁止在收到聊天后再请求企微换 ID。无 sender_id 不进 Graph。工单 owner、会话、卡片权限、outbox touser 只用该字段。角色查主账,不查企微。H5 不从 URL 读 userid。细则见 09。
状态
| 状态 | 存储 |
|---|---|
| 活动工单、打断栈 | conversation session |
| 图节点、业务上下文 | Graph checkpoint |
| 等待点 waitVersion | suspend 账 |
| 补问/卡片绑定 | clarification,TTL(H5 30 分钟) |
| 正式六态 | 只调用主账 API |
| LLM/识别/报价任务 | 各自任务表 + 认领状态(谁在做、超时释放),不是进程级单例 |
运行账 PostgreSQL:PG_HOST/PG_DATABASE/PG_DSN 走环境变量(测试 ytd_test_runtime,正式 ytd_runtime,见 13)。开发期间 inbox/outbox/checkpoint/任务表缺结构:直接加迁移并执行到当前 PG_DATABASE,不要问能不能加表。禁止动现网 ytd_runtime。
LangGraph / Redis 何时用、怎么用:见 14-LangGraph与Redis.md。 图:一单一个 thread_id,checkpoint 在 PG,停点中断,Worker 结构化 wake。Redis:REDIS_URL(测试 /1 + ytd:test:),只做 Stream 或限流/token;checkpoint 与六态不准进 Redis。
LLM
实现队列(Redis Stream 或 DB 任务表)、按条认领、重试、熔断、审计。不要全局 SET NX 单例。模式至少:
ordered_actions(DeepSeek A,strict tool)- 文本字段抽取(DeepSeek B)
- 附件文本 / 图片读取(千问)
- 群报价抽取
- 报价工作表映射
环境变量名与 03-配置与密钥清单.md 对齐;测试/正式取值见 13(YTD_ENV、域名、端口、库)。禁止把 ai.ytd-scm.com 写死在代码里。
字段
实现与 inquiry-required-fields-v1.json 等价的条件激活(JSON 放在新仓库)。SEA 箱型箱量保持单原始字段 + B 模型投影 containerItems。协同点击用不可变询价原话重跑 B,去重补问。
出站
- 主账:登录或 Token,所有写操作要幂等键(message_id / request_id / quoteVersion)。
- 企微:只通过 outbox;失败重试;过期出站丢弃不计业务成功。询价与正式同一 Agent
1000010;运维1000014,测试告警正文加[test]。 - 对象存储:S3 兼容;生成文件后登记主账附件再发企微。
测试
每个业务线:完整字段不补问;缺一项只补该项;TMS 有价/无价/1003/技术失败;重复回调不建第二单。禁止依赖真实密钥才能跑单测(TMS 用 fixture 模式)。不要按企微 userid 在 Redis 里伪造 TMS。