落地海运协同群:测服靠会话存档听群话,报价单能带上协同字段。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-15 18:12:45 +08:00
co-authored by Cursor
parent 235ecd8c83
commit 12219cacb1
39 changed files with 4436 additions and 256 deletions
+17 -1
View File
@@ -68,12 +68,17 @@ def _wrap_card(message: InboundMessage) -> None:
from agent.policy import inquiry_copy as copy
action = copy.canonical_button(message.content or "") or (message.content or "").strip()
payload = dict(message.raw or {})
payload.setdefault("event_key", message.content or "")
if message.chat_id:
payload["chat_id"] = message.chat_id
payload["chat_type"] = message.chat_type
card_action.handle_card_action(
sender_id=message.sender_id,
thread_id="",
wait_version=0,
action=action or "unknown",
payload=dict(message.raw or {}),
payload=payload,
)
@@ -136,6 +141,17 @@ def dispatch_inbound(message: InboundMessage, decision: RouteDecision) -> str:
副作用:仅 handler 内产生;本函数不做业务。
"""
if (message.chat_type or "") == "group":
from agent.policy import inquiry_copy as copy
event = str((message.raw or {}).get("event") or "").lower()
action = copy.canonical_button(message.content or "")
if event in {"template_card_event", "click", "templatecardevent"} or action in {
copy.BTN_DEAL,
copy.BTN_LOST,
copy.BTN_NEGOTIATE,
}:
_wrap_card(message)
return "card_action"
phase = handle_group_collab(message)
logger.info("dispatch group_collab phase=%s chat=%s", phase, message.chat_id)
return "group_collab"
@@ -0,0 +1,91 @@
"""
海运协同群文字意图:DeepSeek A 判断补字段 / 产品报价 / 解散 / 其它。
本文件职责:只分类,不写主账、不发企微。
禁止:把「解散群」写成唯一口令;私聊按钮不走这里。
"""
from __future__ import annotations
import logging
from typing import Optional
from agent.llm.extract_text import extract_collab_fields
logger = logging.getLogger(__name__)
INTENT_FIELDS = "collab_fields"
INTENT_QUOTE = "product_quote"
INTENT_DISSOLVE = "dissolve"
INTENT_OTHER = "other"
_VALID = {INTENT_FIELDS, INTENT_QUOTE, INTENT_DISSOLVE, INTENT_OTHER}
def classify_group_text(
text: str,
*,
injected: str = "",
allow_network: Optional[bool] = None,
) -> str:
"""
群里一句文字的意图。单测可注入;正式走模型。
模型不可用时:只认带标签的协同字段(键:值是合同,不是口令),其余当其它。
"""
hint = (injected or "").strip()
if hint in _VALID:
return hint
raw = (text or "").strip()
if not raw:
return INTENT_OTHER
try:
from agent.config import get_settings
settings = get_settings()
use_net = (
allow_network
if allow_network is not None
else bool(getattr(settings, "llm_allow_network", False))
)
if use_net and getattr(settings, "llm_data_usage_confirmed", False):
got = _classify_with_model(raw, settings)
if got in _VALID:
return got
except Exception:
logger.exception("群意图模型失败,回退标签字段")
if extract_collab_fields(raw):
return INTENT_FIELDS
from agent.llm.extract_text import extract_product_quote
if extract_product_quote(raw):
return INTENT_QUOTE
return INTENT_OTHER
def _classify_with_model(text: str, settings) -> str:
"""DeepSeek 只回一个意图词。失败空串。"""
from agent.llm.http_client import LlmHttpClient
from agent.llm.modes import LlmMode
client = LlmHttpClient.from_settings(settings)
system = (
"你是海运协同群意图分类。只回复一个英文词,不要解释。"
"collab_fields=在补贸易条款/货好时间/商品海关编码/含油含电含磁;"
"product_quote=产品在报价格或费用;"
"dissolve=要把这个协同群解散;"
"other=闲聊、问候、对询价港口的随口更正(不当改单)。"
"一句话里既补字段又报价,回 product_quote。"
)
data = client.chat(
mode=LlmMode.ORDERED_ACTIONS,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": text[:2000]},
],
)
content = str(getattr(data, "content", "") or "").strip().lower()
for token in (INTENT_QUOTE, INTENT_DISSOLVE, INTENT_FIELDS, INTENT_OTHER):
if token in content:
return token
return ""