agent01 / regression.ts
Auto Deployer
Deploy compliance agent services
f39c319
import fs from 'fs';
import path from 'path';
import app from './src/index';
const PORT = 3000;
const BASE_URL = `http://localhost:${PORT}`;
// 定义 12 个测试用例的数据
const testCases = [
{
case_id: 'TC-01',
sample_type: '明显漏洞',
materials: {
current_policy_text: '我们收集您的姓名和手机号。我们会申请设备权限。我们会共享数据给第三方。',
prd_text: '包含人脸识别功能,需要获取身份证正反面,并在开户流程中使用相机进行活体检测。',
permission_items: [
{ name: '相机权限', purpose: '活体检测与身份证识别', trigger_page: '开户流程', required: true }
],
sdk_items: [
{ name: '极光推送SDK', vendor: '极光', purpose: '消息推送', data_items: ['设备标识符', '网络状态'], privacy_url: 'https://jiguang.cn/privacy' }
]
},
peer_updates: ['同业A细化了权限说明'],
regulatory_updates: ['监管强调最小必要原则']
},
{
case_id: 'TC-02',
sample_type: '仅缺权限用途',
materials: {
current_policy_text: '我们收集您的姓名和手机号。我们在开户时申请相机权限。接入了极光推送SDK用于消息推送。',
prd_text: '开户流程中使用相机进行活体检测。',
permission_items: [
{ name: '相机权限', purpose: '活体检测与身份证识别', trigger_page: '开户流程', required: true }
],
sdk_items: [
{ name: '极光推送SDK', vendor: '极光', purpose: '消息推送', data_items: ['设备标识符'], privacy_url: 'https://jiguang.cn/privacy' }
]
},
peer_updates: [],
regulatory_updates: []
},
{
case_id: 'TC-03',
sample_type: 'SDK缺失',
materials: {
current_policy_text: '我们在开户时申请相机权限用于活体检测。我们绝不与第三方共享数据。',
prd_text: '接入了极光推送SDK用于消息推送。',
permission_items: [
{ name: '相机权限', purpose: '活体检测', trigger_page: '开户流程', required: true }
],
sdk_items: [
{ name: '极光推送SDK', vendor: '极光', purpose: '消息推送', data_items: ['设备标识符'], privacy_url: 'https://jiguang.cn/privacy' }
]
},
peer_updates: [],
regulatory_updates: []
},
{
case_id: 'TC-04',
sample_type: '基本合规',
materials: {
current_policy_text: '我们在开户流程申请相机权限,用于身份证识别与活体检测。我们接入极光推送SDK(收集设备标识符)用于消息推送。',
prd_text: '开户活体检测,极光消息推送。',
permission_items: [
{ name: '相机权限', purpose: '活体检测与身份证识别', trigger_page: '开户流程', required: true }
],
sdk_items: [
{ name: '极光推送SDK', vendor: '极光', purpose: '消息推送', data_items: ['设备标识符'], privacy_url: 'https://jiguang.cn/privacy' }
]
},
peer_updates: [],
regulatory_updates: []
},
{
case_id: 'TC-05',
sample_type: '缺 PRD',
materials: {
current_policy_text: '基本条款...',
prd_text: '', // 故意置空触发 4001
permission_items: [],
sdk_items: []
},
peer_updates: [],
regulatory_updates: []
},
{
case_id: 'TC-06',
sample_type: '缺 权限清单',
materials: {
current_policy_text: '基本条款...',
prd_text: '基本说明...',
permission_items: null, // 故意置空触发 4001
sdk_items: []
},
peer_updates: [],
regulatory_updates: []
},
{
case_id: 'TC-07',
sample_type: '缺 SDK清单',
materials: {
current_policy_text: '基本条款...',
prd_text: '基本说明...',
permission_items: [],
sdk_items: null // 故意置空触发 4001
},
peer_updates: [],
regulatory_updates: []
},
{
case_id: 'TC-08',
sample_type: '权限超范围收集',
materials: {
current_policy_text: '我们申请相机权限用于活体检测。我们还会申请通讯录权限用于推荐好友。',
prd_text: '仅开户需要相机,无推荐好友功能。',
permission_items: [
{ name: '相机权限', purpose: '活体检测', trigger_page: '开户流程', required: true }
],
sdk_items: []
},
peer_updates: [],
regulatory_updates: ['严禁超范围收集无关权限']
},
{
case_id: 'TC-09',
sample_type: 'SDK超范围收集',
materials: {
current_policy_text: '极光SDK用于推送,仅收集设备标识。',
prd_text: '极光SDK实际还偷偷收集了用户地理位置。',
permission_items: [],
sdk_items: [
{ name: '极光推送SDK', vendor: '极光', purpose: '消息推送', data_items: ['设备标识符', '精准地理位置'], privacy_url: 'https://jiguang.cn/privacy' }
]
},
peer_updates: [],
regulatory_updates: []
},
{
case_id: 'TC-10',
sample_type: '缺少注销账号条款',
materials: {
current_policy_text: '欢迎使用。收集信息... 完毕。',
prd_text: 'APP包含用户注册和注销功能。',
permission_items: [],
sdk_items: []
},
peer_updates: [],
regulatory_updates: ['工信部要求必须提供便捷的账号注销方式并在协议中说明']
},
{
case_id: 'TC-11',
sample_type: '缺少未成年人保护条款',
materials: {
current_policy_text: '我们面向所有用户提供服务。',
prd_text: 'APP可能有不满14周岁用户注册。',
permission_items: [],
sdk_items: []
},
peer_updates: [],
regulatory_updates: ['必须设立专门的未成年人个人信息保护规则']
},
{
case_id: 'TC-12',
sample_type: '个性化推荐未提供关闭选项',
materials: {
current_policy_text: '我们会根据您的浏览记录进行千人千面的内容推荐。',
prd_text: '首页包含基于用户画像的个性化推荐信息流。',
permission_items: [],
sdk_items: []
},
peer_updates: [],
regulatory_updates: ['算法推荐必须提供便捷的关闭选项']
}
];
// 辅助请求函数
async function post(url: string, data: any) {
const start = Date.now();
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const latency = Date.now() - start;
const json = await res.json();
if (!res.ok) {
throw { status: res.status, latency, error: json };
}
return { data: json, latency };
}
// 主执行循环
async function runRegression() {
console.log('Starting Agent Services for Regression Test...');
const server = app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
const report: any[] = [];
const logStream = fs.createWriteStream(path.join(__dirname, 'regression_report.log'), { flags: 'w' });
for (const tc of testCases) {
console.log(`\n====================================`);
console.log(`Executing ${tc.case_id}: ${tc.sample_type}`);
logStream.write(`\n====================================\n`);
logStream.write(`Executing ${tc.case_id}: ${tc.sample_type}\n`);
const result = {
case_id: tc.case_id,
sample_type: tc.sample_type,
e2e_latency_ms: 0,
each_agent_latency_ms: {
agent1: 0,
agent2: 0,
agent3: 0,
agent4: 0
},
actual_recommendation: '',
error: null as any
};
const startE2E = Date.now();
try {
// 构建基础上下文
const baseContext = {
case_id: tc.case_id,
customer_id: 'CUST-TEST',
customer_name: '测试银行',
app_name: '测试银行APP',
business_line: 'retail',
language: 'zh-CN',
materials: tc.materials,
external_context: {
peer_updates: tc.peer_updates,
regulatory_updates: tc.regulatory_updates
},
metadata: {
submitted_at: new Date().toISOString(),
source: 'regression-test'
}
};
// Agent 1: 同业/监管变化摘要
console.log(` -> [Agent 1] Peer Reg Summary...`);
const a1Res = await post(`${BASE_URL}/api/agents/peer-reg-summary`, {
peer_updates: tc.peer_updates,
regulatory_updates: tc.regulatory_updates,
business_line: 'retail',
app_name: '测试银行APP'
});
result.each_agent_latency_ms.agent1 = a1Res.latency;
// Agent 2: 协议重构
console.log(` -> [Agent 2] Policy Rewrite...`);
const a2Res = await post(`${BASE_URL}/api/agents/policy-rewrite`, {
case_context: baseContext,
peer_reg_summary: a1Res.data
});
result.each_agent_latency_ms.agent2 = a2Res.latency;
// Agent 3: 合规校验
console.log(` -> [Agent 3] Compliance Check...`);
const a3Res = await post(`${BASE_URL}/api/agents/compliance-check`, {
case_context: baseContext,
gap_analysis: a2Res.data
});
result.each_agent_latency_ms.agent3 = a3Res.latency;
// Agent 4: 法务审核包生成
console.log(` -> [Agent 4] Legal Pack...`);
const a4Res = await post(`${BASE_URL}/api/agents/legal-pack`, {
case_context: baseContext,
peer_reg_summary: a1Res.data,
gap_analysis: a2Res.data,
compliance_check: a3Res.data
});
result.each_agent_latency_ms.agent4 = a4Res.latency;
result.actual_recommendation = a4Res.data.review_recommendation || 'unknown';
console.log(` => Recommendation: ${result.actual_recommendation}`);
} catch (err: any) {
console.log(` => Error caught:`, err.status || err.message || err);
result.error = err.error || err.message || err;
if (err.error && (err.error.error_code === 'need_more_material' || (err.error.error && err.error.error.code === 4001))) {
result.actual_recommendation = 'need_more_material (4001)';
} else if (err.error && err.error.error && err.error.error.code === 5001) {
result.actual_recommendation = 'LLM_ERROR (5001)';
} else {
result.actual_recommendation = 'ERROR';
}
}
result.e2e_latency_ms = Date.now() - startE2E;
// 写入 Log
logStream.write(JSON.stringify(result, null, 2) + '\n');
report.push(result);
}
// 输出总报告
console.log(`\n\n====== Regression Test Report ======`);
console.table(report.map(r => ({
CaseID: r.case_id,
Type: r.sample_type,
E2E_ms: r.e2e_latency_ms,
A1_ms: r.each_agent_latency_ms.agent1,
A2_ms: r.each_agent_latency_ms.agent2,
A3_ms: r.each_agent_latency_ms.agent3,
A4_ms: r.each_agent_latency_ms.agent4,
Recommendation: r.actual_recommendation
})));
logStream.write(`\n\n====== Summary ======\n`);
logStream.write(JSON.stringify(report, null, 2));
logStream.end();
console.log(`\nRegression test complete. Report saved to regression_report.log`);
server.close();
process.exit(0);
}
runRegression().catch(console.error);