114 lines
4.0 KiB
Bash
Executable File
114 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 验证 zenmux 两个端点 + prompt cache 是否可用
|
||
# 用法:bash scripts/verify-zenmux.sh
|
||
|
||
set -euo pipefail
|
||
|
||
# 加载密钥
|
||
if [[ -f secrets.env ]]; then
|
||
set -a; source secrets.env; set +a
|
||
fi
|
||
|
||
if [[ -z "${ZENMUX_API_KEY:-}" ]]; then
|
||
echo "❌ ZENMUX_API_KEY 未设置。请 cp secrets.env.example secrets.env 并填入 key"
|
||
exit 1
|
||
fi
|
||
|
||
echo "============================================"
|
||
echo " zenmux 端点与 prompt cache 自检"
|
||
echo "============================================"
|
||
|
||
# -------- 测试 1:OpenAI 兼容端点(Gemini) --------
|
||
echo ""
|
||
echo "[1/3] 测试 OpenAI 兼容端点(google/gemini-2.5-pro,隐式缓存)..."
|
||
RESP1=$(curl -sS -w "\n---HTTP:%{http_code}---\n" -X POST "https://zenmux.ai/api/v1/chat/completions" \
|
||
-H "Authorization: Bearer $ZENMUX_API_KEY" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"model": "google/gemini-2.5-pro",
|
||
"messages": [{"role": "user", "content": "用一句话回答:PubMed 是什么?"}],
|
||
"max_tokens": 100
|
||
}')
|
||
echo "$RESP1" | tail -5
|
||
echo ""
|
||
|
||
# -------- 测试 2:Anthropic 兼容端点(Claude Haiku) --------
|
||
echo "[2/3] 测试 Anthropic 兼容端点(claude-haiku-4.5)..."
|
||
RESP2=$(curl -sS -w "\n---HTTP:%{http_code}---\n" -X POST "https://zenmux.ai/api/anthropic/v1/messages" \
|
||
-H "x-api-key: $ZENMUX_API_KEY" \
|
||
-H "anthropic-version: 2023-06-01" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"model": "claude-haiku-4.5",
|
||
"max_tokens": 100,
|
||
"messages": [{"role": "user", "content": "用一句话回答:PubMed 是什么?"}]
|
||
}')
|
||
echo "$RESP2" | tail -5
|
||
echo ""
|
||
|
||
# -------- 测试 3:Claude + prompt cache(Sonnet) --------
|
||
echo "[3/3] 测试 Claude prompt cache(连续 2 次请求,第 2 次应命中 cache)..."
|
||
|
||
# 构造一个至少 1024 tokens 的 system prompt(约 3000 字符中文足够)
|
||
LONG_PROMPT=$(printf 'You are a biomedical research assistant. ' && \
|
||
for i in $(seq 1 80); do
|
||
printf 'This is test content line %d to build cacheable prefix context. ' "$i"
|
||
done)
|
||
|
||
PAYLOAD=$(cat <<EOF
|
||
{
|
||
"model": "claude-haiku-4.5",
|
||
"max_tokens": 50,
|
||
"system": [
|
||
{
|
||
"type": "text",
|
||
"text": "${LONG_PROMPT}",
|
||
"cache_control": {"type": "ephemeral"}
|
||
}
|
||
],
|
||
"messages": [{"role": "user", "content": "Say OK."}]
|
||
}
|
||
EOF
|
||
)
|
||
|
||
echo " 第 1 次调用(建 cache)..."
|
||
R1=$(curl -sS -X POST "https://zenmux.ai/api/anthropic/v1/messages" \
|
||
-H "x-api-key: $ZENMUX_API_KEY" \
|
||
-H "anthropic-version: 2023-06-01" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$PAYLOAD")
|
||
CACHE_CREATE=$(echo "$R1" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('usage',{}).get('cache_creation_input_tokens', 0))" 2>/dev/null || echo "?")
|
||
echo " cache_creation_input_tokens = $CACHE_CREATE"
|
||
|
||
sleep 2
|
||
|
||
echo " 第 2 次调用(应命中 cache)..."
|
||
R2=$(curl -sS -X POST "https://zenmux.ai/api/anthropic/v1/messages" \
|
||
-H "x-api-key: $ZENMUX_API_KEY" \
|
||
-H "anthropic-version: 2023-06-01" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$PAYLOAD")
|
||
CACHE_READ=$(echo "$R2" | python3 -c "import sys, json; d=json.load(sys.stdin); print(d.get('usage',{}).get('cache_read_input_tokens', 0))" 2>/dev/null || echo "?")
|
||
echo " cache_read_input_tokens = $CACHE_READ"
|
||
|
||
echo ""
|
||
echo "============================================"
|
||
echo " 结果"
|
||
echo "============================================"
|
||
|
||
if [[ "$CACHE_CREATE" != "0" && "$CACHE_CREATE" != "?" ]]; then
|
||
echo "✅ Cache 写入成功($CACHE_CREATE tokens)"
|
||
else
|
||
echo "⚠️ Cache 未写入(可能是 prompt 太短或端点不支持)"
|
||
fi
|
||
|
||
if [[ "$CACHE_READ" != "0" && "$CACHE_READ" != "?" ]]; then
|
||
echo "✅ Cache 命中成功($CACHE_READ tokens)— 成本大幅降低"
|
||
else
|
||
echo "⚠️ Cache 未命中(检查 AGENTS.md §6.5 诊断步骤)"
|
||
fi
|
||
|
||
echo ""
|
||
echo "完整 usage 字段(第 2 次):"
|
||
echo "$R2" | python3 -m json.tool 2>/dev/null | grep -A 10 '"usage"' || echo "$R2"
|