Files
Neo-ZQYY/scripts/ops/test_bailian_apps.py

297 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
测试 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()