微信小程序页面迁移校验之前 P5任务处理之前
This commit is contained in:
296
scripts/ops/test_bailian_apps.py
Normal file
296
scripts/ops/test_bailian_apps.py
Normal file
@@ -0,0 +1,296 @@
|
||||
"""
|
||||
测试 8 个百炼 AI 应用的连通性。
|
||||
|
||||
通过 DashScope Application API 对每个应用发送一轮符合 P5 spec
|
||||
首条 Prompt 结构的示例数据,验证百炼应用能正常返回。
|
||||
|
||||
调用方式:POST https://dashscope.aliyuncs.com/api/v1/apps/{APP_ID}/completion
|
||||
参考文档:docs/reference/bailian-dashscope-api.md
|
||||
|
||||
用法:
|
||||
cd C:\\NeoZQYY && python scripts/ops/test_bailian_apps.py
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from http import HTTPStatus
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 加载根 .env
|
||||
load_dotenv(Path(__file__).resolve().parents[2] / ".env")
|
||||
|
||||
BAILIAN_API_KEY = os.environ.get("BAILIAN_API_KEY", "")
|
||||
if not BAILIAN_API_KEY:
|
||||
raise RuntimeError("BAILIAN_API_KEY 未设置,请检查 .env 文件")
|
||||
|
||||
# 8 个应用 ID 映射
|
||||
APP_CONFIGS = [
|
||||
("BAILIAN_APP_ID_1_CHAT", "应用1-通用对话"),
|
||||
("BAILIAN_APP_ID_2_FINANCE", "应用2-财务洞察"),
|
||||
("BAILIAN_APP_ID_3_CLUE", "应用3-客户数据维客线索分析"),
|
||||
("BAILIAN_APP_ID_4_ANALYSIS", "应用4-关系分析/任务建议"),
|
||||
("BAILIAN_APP_ID_5_TACTICS", "应用5-话术参考"),
|
||||
("BAILIAN_APP_ID_6_NOTE", "应用6-备注分析"),
|
||||
("BAILIAN_APP_ID_7_CUSTOMER", "应用7-客户分析"),
|
||||
("BAILIAN_APP_ID_8_CONSOLIDATE", "应用8-维客线索整理"),
|
||||
]
|
||||
|
||||
# ── 首条 Prompt 示例数据(符合 P5 spec 定义的 JSON 结构) ──────────────────────
|
||||
|
||||
FIRST_PROMPTS: dict[str, str] = {
|
||||
# 应用 1:通用对话 — 前端发起,首条消息为页面上下文
|
||||
"BAILIAN_APP_ID_1_CHAT": json.dumps({
|
||||
"source_page": "board-finance",
|
||||
"page_context": "当前在财务看板页面,本月收入 12,580 元,环比上月增长 8.3%",
|
||||
"screen_content": "财务看板:本月收入 12,580 元 | 台费 6,200 | 陪打 2,100 | 超休 1,000 | 商品 1,800 | 充值 1,480"
|
||||
}, ensure_ascii=False),
|
||||
|
||||
# 应用 2:财务洞察
|
||||
"BAILIAN_APP_ID_2_FINANCE": json.dumps({
|
||||
"site_id": 1,
|
||||
"time_dimension": "本月",
|
||||
"date_range": {"start": "2026-03-01 08:00:00", "end": "2026-04-01 08:00:00"},
|
||||
"current_period": {
|
||||
"income_structure": {"table_fee": 6200, "assistant_pd": 2100, "assistant_cx": 1000, "goods": 1800, "recharge": 1480},
|
||||
"prepaid_assets": {"total_balance": 28500, "recharge_amount": 1480, "consumption_deduction": 2100},
|
||||
"expense_summary": {"rent": 3000, "utilities": 800, "supplies": 500, "salary": 4200, "other": 300},
|
||||
"platform_settlement": {"groupbuy_income": 1200, "platform_fee": 120, "net_income": 1080}
|
||||
},
|
||||
"previous_period": {
|
||||
"time_dimension": "上月",
|
||||
"date_range": {"start": "2026-02-01 08:00:00", "end": "2026-03-01 08:00:00"},
|
||||
"income_structure": {"table_fee": 5800, "assistant_pd": 1950, "assistant_cx": 950, "goods": 1600, "recharge": 1300},
|
||||
"prepaid_assets": {"total_balance": 29120, "recharge_amount": 1300, "consumption_deduction": 1950},
|
||||
"expense_summary": {"rent": 3000, "utilities": 750, "supplies": 450, "salary": 4200, "other": 250},
|
||||
"platform_settlement": {"groupbuy_income": 1000, "platform_fee": 100, "net_income": 900}
|
||||
}
|
||||
}, ensure_ascii=False),
|
||||
|
||||
# 应用 3:客户数据维客线索分析
|
||||
"BAILIAN_APP_ID_3_CLUE": json.dumps({
|
||||
"member_nickname": "张三",
|
||||
"main_data": {
|
||||
"consumption_records": "近3个月消费12次,总消费2,860元。台费占比55%,助教费占比30%(陪打20%+超休10%),商品占比15%。偏好周末晚间时段,平均客单价238元。最近一次消费:2026-02-20,消费280元(台费+1小时助教)。",
|
||||
"member_cards": "持有银卡会员,2025-06-15注册",
|
||||
"card_balance_total": 580,
|
||||
"stored_value_balance_total": 580,
|
||||
"expected_visit_date": "2026-03-08",
|
||||
"days_since_last_visit": 13
|
||||
},
|
||||
"reference": {"app6_clues": None, "app8_history": []}
|
||||
}, ensure_ascii=False),
|
||||
|
||||
# 应用 4:关系分析 / 任务建议
|
||||
"BAILIAN_APP_ID_4_ANALYSIS": json.dumps({
|
||||
"assistant_info": "花名:小李,级别:中级助教,工龄:1年3个月,擅长中式台球教学",
|
||||
"service_history": "累计服务张三8次,最近一次2026-02-20,平均每次服务1.5小时,客户评价良好",
|
||||
"task_assignment_basis": "优先召回:距上次到店13天,超过客户平均到店间隔(10天)",
|
||||
"customer_data": {
|
||||
"system_data": "近3个月消费12次,总消费2,860元,客单价238元,储值余额580元",
|
||||
"notes": [
|
||||
{"recorded_by": "小李", "content": "张三喜欢打中式台球,经常带朋友来,上次提到想学斯诺克", "created_at": "2026-02-20 21:30:00"},
|
||||
{"recorded_by": "小王", "content": "张三对充值活动比较感兴趣,上次充了500", "created_at": "2026-02-10 20:00:00"}
|
||||
]
|
||||
},
|
||||
"reference": {"app8_current": None, "app8_history": []}
|
||||
}, ensure_ascii=False),
|
||||
|
||||
# 应用 5:话术参考
|
||||
"BAILIAN_APP_ID_5_TACTICS": json.dumps({
|
||||
"assistant_info": "花名:小李,级别:中级助教,工龄:1年3个月",
|
||||
"service_history": "累计服务张三8次,最近一次2026-02-20",
|
||||
"task_assignment_basis": "优先召回:距上次到店13天",
|
||||
"customer_data": {
|
||||
"system_data": "近3个月消费12次,总消费2,860元,储值余额580元",
|
||||
"notes": [{"recorded_by": "小李", "content": "张三喜欢打中式台球,经常带朋友来", "created_at": "2026-02-20 21:30:00"}]
|
||||
},
|
||||
"task_suggestion": "{\"relationship_summary\":\"主要服务助教,累计服务8次,关系紧密\",\"task_description\":\"客户张三距上次到店已13天,超过其平均到店间隔10天,存在轻度流失风险。\",\"actions\":[{\"suggestion\":\"本周内通过微信联系张三,以斯诺克体验课为切入点邀请回店\"}],\"summary\":\"以斯诺克体验为切入点,本周内微信召回\"}",
|
||||
"reference": {"app8_history": []}
|
||||
}, ensure_ascii=False),
|
||||
|
||||
# 应用 6:备注分析
|
||||
"BAILIAN_APP_ID_6_NOTE": json.dumps({
|
||||
"current_note": {
|
||||
"content": "张三今天带了两个朋友来,说是公司同事,三个人打了两个小时中式,走的时候说下周还想来,问有没有团建套餐",
|
||||
"recorded_by": "小李",
|
||||
"created_at": "2026-03-05 21:30:00"
|
||||
},
|
||||
"reference": {
|
||||
"member_nickname": "张三",
|
||||
"consumption_data": "近3个月消费12次,总消费2,860元,客单价238元",
|
||||
"all_notes": [
|
||||
{"recorded_by": "小李", "content": "张三喜欢打中式台球,经常带朋友来,上次提到想学斯诺克", "created_at": "2026-02-20 21:30:00"},
|
||||
{"recorded_by": "小王", "content": "张三对充值活动比较感兴趣,上次充了500", "created_at": "2026-02-10 20:00:00"}
|
||||
],
|
||||
"app3_clues": None,
|
||||
"app8_history": []
|
||||
}
|
||||
}, ensure_ascii=False),
|
||||
|
||||
# 应用 7:客户分析
|
||||
"BAILIAN_APP_ID_7_CUSTOMER": json.dumps({
|
||||
"member_id": 10086,
|
||||
"member_nickname": "张三",
|
||||
"objective_data": "近3个月消费12次,总消费2,860元,客单价238元。台费占比55%,助教费30%(陪打+超休),商品15%。偏好周末晚间,储值余额580元,银卡会员。距上次到店13天,平均到店间隔10天。",
|
||||
"subjective_data": {
|
||||
"notes": [
|
||||
{"recorded_by": "小李", "content": "张三喜欢打中式台球,经常带朋友来,上次提到想学斯诺克", "created_at": "2026-02-20 21:30:00"},
|
||||
{"recorded_by": "小王", "content": "张三对充值活动比较感兴趣,上次充了500", "created_at": "2026-02-10 20:00:00"},
|
||||
{"recorded_by": "小李", "content": "张三今天带了两个朋友来,说是公司同事,问有没有团建套餐", "created_at": "2026-03-05 21:30:00"}
|
||||
]
|
||||
},
|
||||
"reference": {"app8_current": None, "app8_history": []}
|
||||
}, ensure_ascii=False),
|
||||
|
||||
# 应用 8:维客线索整理
|
||||
"BAILIAN_APP_ID_8_CONSOLIDATE": json.dumps({
|
||||
"app3_clues": {
|
||||
"generated_at": "2026-03-05 14:30:00",
|
||||
"clues": [
|
||||
{"detail": "客户近3个月消费12次,平均10天到店一次,当前已13天未到店,超过平均间隔30%,存在轻度流失风险。建议本周内联系召回。", "category": "消费习惯", "summary": "到店间隔异常,轻度流失风险", "emoji": "⏰"},
|
||||
{"detail": "客户台费占比55%,助教费占比30%(陪打+超休),偏好周末晚间时段(18:00-22:00),中式台球为主。客单价238元,属于中等消费水平。", "category": "玩法偏好", "summary": "周末晚间中式台球爱好者", "emoji": "🎱"}
|
||||
]
|
||||
},
|
||||
"app6_clues": {
|
||||
"generated_at": "2026-03-05 14:25:00",
|
||||
"clues": [
|
||||
{"category": "社交关系", "emoji": "👥", "detail": "客户经常带朋友来店,最近一次带了两位公司同事,主动询问团建套餐,具有社交裂变潜力和团建需求。", "summary": "常带朋友,有团建需求"},
|
||||
{"category": "促销接受", "emoji": "💰", "detail": "客户对充值活动感兴趣,曾主动充值500元,储值余额580元。可在余额接近用完时推荐充值优惠。", "summary": "充值意愿强,关注优惠活动"}
|
||||
]
|
||||
}
|
||||
}, ensure_ascii=False),
|
||||
}
|
||||
|
||||
|
||||
# ── 通过 HTTP 调用百炼应用 API ─────────────────────────────────────────────────
|
||||
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
API_BASE = "https://dashscope.aliyuncs.com/api/v1/apps"
|
||||
|
||||
|
||||
def call_app(env_key: str, label: str) -> dict:
|
||||
"""通过 HTTP POST 调用单个百炼应用,返回结果摘要。"""
|
||||
app_id = os.environ.get(env_key, "")
|
||||
if not app_id:
|
||||
return {"app": label, "status": "SKIP", "reason": f"环境变量 {env_key} 未设置"}
|
||||
|
||||
prompt = FIRST_PROMPTS.get(env_key, "你好")
|
||||
url = f"{API_BASE}/{app_id}/completion"
|
||||
|
||||
body = json.dumps({
|
||||
"input": {"prompt": prompt},
|
||||
"parameters": {"has_thoughts": False}
|
||||
}).encode("utf-8")
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {BAILIAN_API_KEY}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
t0 = time.time()
|
||||
try:
|
||||
req = urllib.request.Request(url, data=body, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=60) as resp:
|
||||
data = json.loads(resp.read().decode("utf-8"))
|
||||
elapsed = round(time.time() - t0, 2)
|
||||
|
||||
output = data.get("output", {})
|
||||
usage = data.get("usage", {})
|
||||
text = output.get("text", "")
|
||||
finish = output.get("finish_reason", "?")
|
||||
models = usage.get("models", [])
|
||||
tokens_info = {}
|
||||
if models:
|
||||
m = models[0]
|
||||
tokens_info = {
|
||||
"model": m.get("model_id", "?"),
|
||||
"input": m.get("input_tokens", "?"),
|
||||
"output": m.get("output_tokens", "?"),
|
||||
}
|
||||
|
||||
return {
|
||||
"app": label,
|
||||
"app_id": app_id[:8] + "...",
|
||||
"status": "OK",
|
||||
"elapsed_s": elapsed,
|
||||
"finish_reason": finish,
|
||||
"tokens": tokens_info,
|
||||
"response_preview": text[:300] + ("..." if len(text) > 300 else ""),
|
||||
}
|
||||
except urllib.error.HTTPError as e:
|
||||
elapsed = round(time.time() - t0, 2)
|
||||
err_body = ""
|
||||
try:
|
||||
err_body = e.read().decode("utf-8")[:300]
|
||||
except Exception:
|
||||
pass
|
||||
return {
|
||||
"app": label,
|
||||
"app_id": app_id[:8] + "...",
|
||||
"status": "ERROR",
|
||||
"elapsed_s": elapsed,
|
||||
"error": f"HTTP {e.code}: {err_body}",
|
||||
}
|
||||
except Exception as e:
|
||||
elapsed = round(time.time() - t0, 2)
|
||||
return {
|
||||
"app": label,
|
||||
"app_id": app_id[:8] + "...",
|
||||
"status": "ERROR",
|
||||
"elapsed_s": elapsed,
|
||||
"error": str(e)[:300],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 70)
|
||||
print("百炼 AI 应用连通性测试(DashScope Application API)")
|
||||
print(f"API Key: {BAILIAN_API_KEY[:8]}...{BAILIAN_API_KEY[-4:]}")
|
||||
print(f"API Base: {API_BASE}")
|
||||
print("=" * 70)
|
||||
|
||||
results = []
|
||||
for env_key, label in APP_CONFIGS:
|
||||
print(f"\n▶ 测试 {label} ...")
|
||||
result = call_app(env_key, label)
|
||||
results.append(result)
|
||||
|
||||
icon = "✅" if result["status"] == "OK" else "⏭️" if result["status"] == "SKIP" else "❌"
|
||||
print(f" {icon} {result['status']}", end="")
|
||||
if "elapsed_s" in result:
|
||||
print(f" ({result['elapsed_s']}s)", end="")
|
||||
if "tokens" in result:
|
||||
t = result["tokens"]
|
||||
print(f" | model={t.get('model','?')} in={t.get('input','?')} out={t.get('output','?')}", end="")
|
||||
if "finish_reason" in result:
|
||||
print(f" | finish={result['finish_reason']}", end="")
|
||||
if "error" in result:
|
||||
print(f"\n ⚠️ {result['error'][:150]}", end="")
|
||||
if "reason" in result:
|
||||
print(f" | {result['reason']}", end="")
|
||||
print()
|
||||
|
||||
if "response_preview" in result:
|
||||
preview = result["response_preview"][:200]
|
||||
print(f" 📝 {preview}")
|
||||
|
||||
# 汇总
|
||||
print("\n" + "=" * 70)
|
||||
ok = sum(1 for r in results if r["status"] == "OK")
|
||||
err = sum(1 for r in results if r["status"] == "ERROR")
|
||||
skip = sum(1 for r in results if r["status"] == "SKIP")
|
||||
print(f"汇总: ✅ {ok} 成功 | ❌ {err} 失败 | ⏭️ {skip} 跳过 | 共 {len(results)} 个应用")
|
||||
print("=" * 70)
|
||||
|
||||
if err > 0:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user