落地海运协同群:测服靠会话存档听群话,报价单能带上协同字段。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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 ""
|
||||
Reference in New Issue
Block a user