fix(bridge+ai): 商品工具超时放宽到 30s,助理强制短关键词且禁止编造价格
This commit is contained in:
@@ -187,6 +187,7 @@ services:
|
||||
INVENTORY_API_URL: ${INVENTORY_API_URL}
|
||||
MEMBER_RPC_URL: ${MEMBER_RPC_URL}
|
||||
RPC_TIMEOUT_MS: ${RPC_TIMEOUT_MS:-8000}
|
||||
PRODUCT_TIMEOUT_MS: ${PRODUCT_TIMEOUT_MS:-15000}
|
||||
SITE_SEARCH_URL: ${SITE_SEARCH_URL}
|
||||
TWENTY_BASE_URL: http://twenty-server:3000
|
||||
TWENTY_GRAPHQL_PATH: /graphql
|
||||
|
||||
@@ -50,6 +50,7 @@ grep '^TOOLS_SHARED_KEY=' .env # bridge 工具密钥
|
||||
| `INVENTORY_API_URL` | 测试服地址 | `jsonrpc://host.docker.internal:24509` | eta-service(24509 → 9509) |
|
||||
| `MEMBER_RPC_URL` | 测试服地址 | `jsonrpc://host.docker.internal:24506` | member-service(24506 → 9506) |
|
||||
| `IDENTITY_DEV_MODE` | `false` | `true` | dev 环境方便 widget 联调;**上生产前改回 `false`** |
|
||||
| `PRODUCT_TIMEOUT_MS` | 未透传(bridge 默认 15s) | `30000`(compose 增加透传) | 冷门长查询会偶发 >15s,超时会降级成无价格的站点地图结果,模型易编价 |
|
||||
| `public-gateway` / `cloudflared` | compose 里默认启动 | **未启动** | 已有宿主 nginx 直出 HTTPS,不需要 Cloudflare 临时隧道 |
|
||||
|
||||
`host.docker.internal` 由 compose 的 `extra_hosts` 注入,指向宿主;`24503-24509` 是本工作区的 RPC 宿主转发端口
|
||||
@@ -59,6 +60,9 @@ grep '^TOOLS_SHARED_KEY=' .env # bridge 工具密钥
|
||||
|
||||
### LibreDesk
|
||||
- `System` 账号可登录(浏览器实测落到 `/inboxes/assigned`)。
|
||||
- **AI Provider 已配置**:DashScope `qwen-plus-latest`(completion)+ `text-embedding-v4` 1024 维(embedding),
|
||||
`configure-ai.js` 的两项连通性测试均通过。密钥只存在 LibreDesk 库内与 `.env`(600),未写入文档。
|
||||
- 助理指令已加固(见第 9 节):`search_products` 必须用 2-5 个词的关键词、不得编造价格/商品,`price=null` 时明确说“暂不可用”。
|
||||
- `app.root_url = https://wangliang-crm.dev.gaia888.com`(`scripts/set-public-url.js`)。
|
||||
- 10 个 bridge 工具已注册(`scripts/register-tools.js`):`search_products / search_orders / search_inventory /
|
||||
search_kb / search_email_history / collect_info / send_verification_code / verify_email_code / handoff_to_human /
|
||||
@@ -142,7 +146,7 @@ docker run --rm -v /etc/nginx/conf.d:/c redis:7-alpine rm -f /c/zz-wangliang-crm
|
||||
|
||||
| 项 | 现状 | 补法 |
|
||||
|---|---|---|
|
||||
| **AI Provider(DashScope)** | `LLM_*` / `EMB_*` 为空,助理不会真正调模型 | `DASHSCOPE_API_KEY=sk-xxx node scripts/configure-ai.js`(需能访问 dashscope) |
|
||||
| ~~AI Provider(DashScope)~~ | ✅ **已配置**(qwen-plus-latest / text-embedding-v4),端到端已验证 | 换 key:`DASHSCOPE_API_KEY=sk-xxx node scripts/configure-ai.js` |
|
||||
| **SMTP / 163 邮件** | `SMTP_*` 为空,OTP 与邮件渠道不可用 | 填 `.env` 后 `node scripts/configure-email.js` + `node scripts/add-email-inbox.js` |
|
||||
| **知识库 RAG(search_kb)** | 无 `RAG_PG_URL`,工具返回 503 | 指向旧 KB 库后运行 `scripts/import-kb-helpcenter.js` / `rebuild-kb-index.sh` |
|
||||
| **WhatsApp 渠道** | 无 Meta 凭据 | 填 `WA_*` 后 `scripts/add-whatsapp-inbox.js`;需要公网回调(本栈已有 HTTPS,可不用 cloudflared) |
|
||||
@@ -162,6 +166,10 @@ $ curl -s -X POST http://127.0.0.1:4100/tools/search_products -H 'X-Tools-Key:
|
||||
{"ok":true,"products":[{"name":"Stainless Steel Y-Chain Necklace","price":"$6.73","product_id":11079}]}
|
||||
```
|
||||
|
||||
AI 端到端(`node scripts/e2e-widget.js "Show me 3 stainless steel necklaces with prices and stock."`):
|
||||
助手调用 `search_products`(612ms,source=catalog)并返回真实数据 —— Y-Chain `$6.73`/237、Necklace `$6.85`/186、
|
||||
Necklace Star `$5.70`/110,与 RPC 直查一致(首次调试时的编价问题见第 9 节)。
|
||||
|
||||
浏览器(Playwright 真 Chrome,1440×900):
|
||||
|
||||
- LibreDesk 登录成功 → `/inboxes/assigned`(截图 `docs/screenshots/wangliang-libredesk-inbox.png`)
|
||||
@@ -169,3 +177,24 @@ $ curl -s -X POST http://127.0.0.1:4100/tools/search_products -H 'X-Tools-Key:
|
||||
- 回归:`wangliang-www` 仍 200,`wangliang-agent` 仍 302(宿主 nginx 未被改坏)
|
||||
|
||||
资源占用:约 1.9 GB 内存(Twenty worker 约 1.0 GB + server 0.6 GB + PG/Redis/bridge/LibreDesk 约 0.3 GB)。
|
||||
|
||||
## 9. 上线当天修的一个 AI 质量问题(编造价格)
|
||||
|
||||
首次用 `e2e-widget.js` 问“3 条不锈钢项链的价格和库存”时,助手返回了三款**不存在的商品**和虚高价格。
|
||||
排查(临时把 LibreDesk `log_level` 调到 `debug`)定位到:
|
||||
|
||||
1. 模型把用户**整句**(含 "under 10 dollars" 等)直接当成 `search_products` 的 query;
|
||||
2. 这类长查询偶发 >15s(bridge 的 `PRODUCT_TIMEOUT_MS` 默认 15s),超时后走降级:只返回名字、`price=null`;
|
||||
3. 模型面对 `price=null` 时自行编了价格(LibreDesk 的 guardrails 只是提示词,不是硬拦截)。
|
||||
|
||||
修复(已落地并验证):
|
||||
|
||||
- `docker-compose.yml` 给 bridge 透传 `PRODUCT_TIMEOUT_MS`,`.env` 设为 `30000`;
|
||||
- 助理的 instructions 追加严格规则(`scripts/setup-defaults.js` 同步):短关键词查询、工具输出是唯一事实来源、
|
||||
`price=null`/`stock=null` 时必须说“暂不可用”并建议转人工,禁止估算/换算币种。
|
||||
- 复测:同一条问题,工具调用 612ms 返回真实商品,回复价格/库存与 RPC 完全一致。
|
||||
|
||||
⚠️ 仍存在的结构性问题:LibreDesk 内置 AI 的回复**不经过** bridge 的 `输出护栏`(output_guard)。
|
||||
若后续要硬性拦截虚假价格/链接,需要走 bridge 自己的 agent 路径,或在 LibreDesk 侧加后置校验。
|
||||
|
||||
验证完已把 `log_level` 恢复为 `info`。
|
||||
|
||||
@@ -81,7 +81,13 @@ const INSTRUCTIONS = `You are the Yehwang B2B customer assistant for stainless-s
|
||||
- For stock / pre-order questions, call search_inventory with the SKU digits.
|
||||
- When you know company + contact name + product/need, call create_opportunity once.
|
||||
- If you cannot help, or the customer asks for a human, hand off to a human agent.
|
||||
- Never reveal another customer's data.`;
|
||||
- Never reveal another customer's data.
|
||||
|
||||
Tool usage rules (strict):
|
||||
- When calling search_products, pass a SHORT keyword phrase of 2-5 words (e.g. "stainless steel necklace"). Never pass the customer's full sentence, price limits ("under $10"), quantities or filler words ("show me", "please"). This keeps catalog search fast and accurate.
|
||||
- The tool output is the ONLY source of product names, prices, stock and URLs. Never invent or "fill in" a product, price, SKU or link that is not in the tool output.
|
||||
- If a returned product has price=null or stock=null, tell the customer that price/stock is unavailable for now; do NOT estimate, convert currency or guess. Offer to connect a human for an exact quote.
|
||||
- If search_products returns note/catalog_error saying prices are unavailable, list only the returned names/links and explicitly say prices need confirmation.`;
|
||||
|
||||
const GUARDRAILS = `Never invent prices, discounts, stock or delivery dates.
|
||||
Never share another customer's order or personal data.
|
||||
|
||||
Reference in New Issue
Block a user