主流模型对于抽象问题的解答对比

52 阅读12分钟

背景描述

刚才突发奇想,目前在测试模型的时候流行问鹈鹕骑自行车,这个问题看似幽默,其实有几个点值得注意:

  1. 模型对于鹈鹕的理解,不然就画成鸭子了;
  2. 模型对于“骑”的理解,骑是要脚在脚踏板上的。

至于为什么是鹈鹕骑自行车,这个完全是由于某位老哥喜欢鹈鹕而已…… 然后我正上着班,看到DeepSeekV4.1可以用了,本来也想试试这个问题,简单测试一下。

但是转头一想这个问题烂大街了,模型会不会有专门的优化,所以干脆问个大概率没人问过的奇葩问题——“人马穿着三角裤骑马”。这个问题看似抽象,但是同样有两点值得注意:

  1. 人马应该怎么骑马?他应该是跨坐在马上的,而不是简单的叠加
  2. 人马的内裤该怎么穿?穿前面还是穿后面还是包住整个下面?

实践

基本工具:

  1. Pi Agent
  2. OpenCode Go套餐

首先让Pi Agent写一个批量测试的脚本,脚本如下:

# -*- coding: utf-8 -*-
"""
pi-multi-model-bench.py
用同一个提示词真·并发(asyncio)驱动 pi agent 测试多个国产大模型。

特性
- 输出目录直接以模型 id 命名: results/<时间戳>/glm-5.3/ ...
- 每个模型请求其支持的最高思考强度(pi 会按模型目录自动收敛,
  若 provider 明确报错不支持则自动降级重试)
- 真·并发: asyncio tasks 同时 spawn 子进程,每个模型记录
  start/end 绝对时间戳,写进报告可验证重叠执行
- 每模型导出: 原始事件流 / 最终消息 / 工具调用 / 思考 / 回答 / 指标
- 汇总 report.md

用法:
    python pi_multi_model_bench.py "你的提示词"
    python pi_multi_model_bench.py
    python pi_multi_model_bench.py --jobs 8 --timeout 900 --out results/run1
"""

import argparse
import asyncio
import json
import sys
import time
from datetime import datetime, timezone
from pathlib import Path

# ---------------------------------------------------------------------------
# 模型清单: opencode-go provider 下每家厂商最新最强(2026-09 时点)
# 更新方法: pi update && pi --list-models opencode-go 后修改本表
# ---------------------------------------------------------------------------
MODELS = [
    "deepseek-v4.1-flash",  # DeepSeek(最新,按用户要求)
    "glm-5.3",              # 智谱 GLM
    "kimi-k3",              # 月之暗面 Kimi
    "qwen3.8-max",          # 阿里 Qwen
    "minimax-m3",           # MiniMax
    "hy4-preview",          # 腾讯混元
    "mimo-v2.5-pro",        # 小米 MiMo
    "longcat-2.0",          # 美团 LongCat
]

# 请求思考强度: 从高到低尝试。pi 内部会按每个模型的 thinkingLevelMap
# 自动收敛到该模型支持的档位;仅当 provider 端明确报错时才走降级重试。
THINKING_ORDER = ["max", "xhigh", "high", "medium"]

PROVIDER = "opencode-go"

DEFAULT_PROMPT = (
    "请阅读当前目录结构,写一个 Python 脚本统计当前目录下所有 .txt 文件的总行数和总字节数,"
    "并将结果保存到 stats.txt 中。写完后实际运行验证一遍。"
)

# stderr 中出现这些关键词且进程很快退出时,视为思考档位不被支持
THINKING_ERR_HINTS = (
    "thinking", "reasoning", "reasoning_effort", "unsupported",
    "invalid_request", "invalid request", "400",
)


def now_iso():
    return datetime.now(timezone.utc).isoformat(timespec="milliseconds")


# ---------------------------------------------------------------------------
async def run_attempt(model_id: str, level: str, prompt: str, timeout: int, cwd: Path):
    cmd = [
        "pi", "--mode", "json", "-p", "--no-session", "--no-approve",
        "--provider", PROVIDER,
        "--model", model_id,
        "--thinking", level,
        "--", prompt,
    ]
    t0 = time.time()
    started = now_iso()
    proc = await asyncio.create_subprocess_exec(
        *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
        cwd=str(cwd))
    try:
        out, err = await asyncio.wait_for(proc.communicate(), timeout=timeout)
    except asyncio.TimeoutError:
        proc.kill()
        return {"ok": False, "error": f"timeout after {timeout}s",
                "started": started, "ended": now_iso(), "wall": round(time.time() - t0, 2)}
    return {
        "ok": proc.returncode == 0,
        "returncode": proc.returncode,
        "stdout": (out or b"").decode("utf-8", errors="replace"),
        "stderr": (err or b"").decode("utf-8", errors="replace"),
        "started": started, "ended": now_iso(),
        "wall": round(time.time() - t0, 2),
        "level": level,
    }


async def run_model(model_id: str, prompt: str, timeout: int, out_dir: Path):
    out_dir.mkdir(parents=True, exist_ok=True)
    info = None
    # 从最高思考强度开始尝试,失败且疑似档位不支持时降级重试
    for i, level in enumerate(THINKING_ORDER):
        info = await run_attempt(model_id, level, prompt, timeout, out_dir)
        if info["ok"]:
            break
        err_l = info.get("stderr", "").lower()
        if i < len(THINKING_ORDER) - 1 and any(h in err_l for h in THINKING_ERR_HINTS):
            info["retried_from"] = level
            continue
        break

    (out_dir / "raw_stream.jsonl").write_text(info.get("stdout", ""), encoding="utf-8")
    (out_dir / "stderr.txt").write_text(info.get("stderr", ""), encoding="utf-8")
    if not info["ok"]:
        return {"model": model_id, "ok": False,
                "error": info.get("error") or f"exit {info.get('returncode')}",
                "exit_code": info.get("returncode"),
                "wall": info.get("wall"), "level": info.get("level", THINKING_ORDER[0])}

    events = []
    for line in info["stdout"].splitlines():
        if line.startswith("{"):
            try:
                events.append(json.loads(line))
            except json.JSONDecodeError:
                pass

    parsed = parse_events(events)
    parsed.update(
        model=model_id, ok=True, exit_code=info.get("returncode"),
        wall_seconds=info["wall"],
        started=info["started"], ended=info["ended"],
        thinking_level=info["level"],
        retried_from=info.get("retried_from"),
    )
    write_per_model(parsed, out_dir, prompt)
    return parsed


def parse_events(events):
    usage, final_msg, tool_calls, tool_results = {}, None, [], []

    def collect_usage(u):
        if not isinstance(u, dict):
            return
        for k in ("input", "output", "reasoning", "cacheRead", "cacheWrite", "totalTokens"):
            if k in u:
                usage[k] = u.get(k, 0)
        c = u.get("cost") or {}
        if c:
            usage["cost"] = {k: c.get(k, 0)
                             for k in ("input", "output", "cacheRead", "cacheWrite", "total")}

    def handle_message(msg):
        nonlocal final_msg
        if not isinstance(msg, dict):
            return
        if msg.get("role") == "assistant":
            final_msg = msg
            collect_usage(msg.get("usage") or {})
            for block in msg.get("content", []):
                if block.get("type") == "toolCall":
                    tool_calls.append({
                        "name": block.get("name") or (block.get("toolCall") or {}).get("name", "?"),
                        "args": block.get("arguments") or block.get("args") or {},
                    })
        elif msg.get("role") == "toolResult":
            tool_results.append({"toolName": msg.get("toolName", "?"),
                                 "isError": bool(msg.get("isError") or msg.get("error"))})

    for e in events:
        t = e.get("type")
        if t == "message_end":
            handle_message(e.get("message"))
        elif t == "turn_end":
            handle_message(e.get("message"))
            for r in e.get("toolResults") or []:
                tool_results.append({"toolName": r.get("toolName", "?"),
                                     "isError": bool(r.get("isError"))})
        elif t in ("tool_execution_start", "toolcall_start"):
            if e.get("toolName"):
                tool_calls.append({"name": e["toolName"], "args": e.get("args") or {}})
        elif t == "agent_end":
            collect_usage(e.get("usage") or {})
            for m in e.get("messages") or []:
                if isinstance(m, dict) and m.get("role") == "assistant":
                    final_msg = m

    if final_msg and not usage:
        collect_usage(final_msg.get("usage") or {})
    return {"usage": usage, "final": final_msg or {},
            "tool_calls": tool_calls, "tool_results": tool_results}


def write_per_model(info, out_dir: Path, prompt: str):
    content = info["final"].get("content") or []
    thinking_text = "\n\n".join(b.get("thinking", "") for b in content
                                if b.get("type") == "thinking" and b.get("thinking"))
    answer_text = "\n\n".join(b.get("text", "") for b in content
                              if b.get("type") == "text" and b.get("text"))

    (out_dir / "thinking.md").write_text(thinking_text or "(无思考内容)", encoding="utf-8")
    (out_dir / "answer.md").write_text(answer_text or "(无回答)", encoding="utf-8")
    (out_dir / "final_message.json").write_text(
        json.dumps(info["final"], ensure_ascii=False, indent=2), encoding="utf-8")
    (out_dir / "tool_calls.json").write_text(
        json.dumps({"calls": info["tool_calls"], "results": info["tool_results"]},
                   ensure_ascii=False, indent=2), encoding="utf-8")

    u = info["usage"]
    cost = u.get("cost") or {}
    md = [
        f"# {info['model']}",
        "",
        f"- Provider: `{PROVIDER}`",
        f"- 请求思考强度: `{info['thinking_level']}`"
        + (f"(从 `{info['retried_from']}` 降级重试成功)" if info.get("retried_from") else ""),
        f"- 起始时间 (UTC): `{info['started']}`",
        f"- 结束时间 (UTC): `{info['ended']}`",
        f"- 耗时: `{info['wall_seconds']}s`",
        f"- Exit code: `{info['exit_code']}`",
        "",
        "## Token 用量",
        "",
        "| input | output | reasoning | cacheRead | cacheWrite | total |",
        "|---|---|---|---|---|---|",
        f"| {u.get('input', 0)} | {u.get('output', 0)} | {u.get('reasoning', 0)} "
        f"| {u.get('cacheRead', 0)} | {u.get('cacheWrite', 0)} | {u.get('totalTokens', 0)} |",
        "",
        "## 成本 (USD, 按模型目录单价估算)",
        "",
        "| input | output | cacheRead | cacheWrite | total |",
        "|---|---|---|---|---|",
        f"| {cost.get('input', 0)} | {cost.get('output', 0)} | {cost.get('cacheRead', 0)} "
        f"| {cost.get('cacheWrite', 0)} | {cost.get('total', 0)} |",
        "",
        f"## 工具调用 ({len(info['tool_calls'])} 次)",
        "",
        "```json",
        json.dumps(info["tool_calls"], ensure_ascii=False, indent=2),
        "```",
        "",
        "## 思考过程",
        "",
        thinking_text or "(该模型未输出思考内容, 或思考未开启)",
        "",
        "## 回答",
        "",
        answer_text or "(无回答)",
    ]
    (out_dir / "summary.md").write_text("\n".join(md), encoding="utf-8")


def write_summary(results, base_dir: Path, prompt: str, requested_level: str, started: str):
    window_start = min(r.get("started", "") for r in results if r.get("started")) if results else ""
    window_end = max(r.get("ended", "") for r in results if r.get("ended")) if results else ""
    lines = [
        "# pi 多模型评测报告",
        "",
        f"- 汇总时间: {started}",
        f"- Provider: `{PROVIDER}`",
        f"- 请求思考强度: `{requested_level}`(按各模型支持程度自动收敛)",
        f"- 整批最早开始 (UTC): `{window_start}`",
        f"- 整批最晚结束 (UTC): `{window_end}`",
        "- 执行方式: asyncio 真·并发, 每个模型的起止时间已在单模型 summary.md 中记录, "
        "可与上面的整批窗口比对验证并行执行",
        "",
        "## 提示词",
        "",
        "```", prompt, "```",
        "",
        "## 汇总对比(按耗时升序)",
        "",
        "| 模型 | 状态 | 起始(UTC) | 耗时(s) | 思考强度 | input tok | output tok "
        "| reasoning tok | total tok | 成本($) | 工具调用 |",
        "|---|---|---|---|---|---|---|---|---|---|---|",
    ]
    ok = [r for r in results if r.get("ok")]
    for info in sorted(ok, key=lambda r: r.get("wall_seconds", 0)):
        u = info["usage"]
        c = u.get("cost") or {}
        lvl = info["thinking_level"] + (f"←{info['retried_from']}" if info.get("retried_from") else "")
        lines.append(
            f"| {info['model']} | ✅ | {info['started'][11:19]} | {info['wall_seconds']} "
            f"| {lvl} | {u.get('input',0)} | {u.get('output',0)} | {u.get('reasoning',0)} "
            f"| {u.get('totalTokens',0)} | {c.get('total',0):.4f} "
            f"| {len(info['tool_calls'])} |")
    for r in results:
        if not r.get("ok"):
            lines.append(f"| {r['model']} | ❌ {r.get('error','')} "
                         f"| - | {r.get('wall','-')} | - | - | - | - | - | - | - |")
    lines += ["", "## 各模型最终回答节选", ""]
    for info in sorted(ok, key=lambda r: r["model"]):
        content = info["final"].get("content") or []
        text = "\n".join(b.get("text", "") for b in content if b.get("type") == "text")
        snippet = text.strip()[:800] or "(无)"
        lines += [f"### {info['model']}", "", "```", snippet, "```",
                  f"详见 `{info['model']}/answer.md`", ""]
    (base_dir / "report.md").write_text("\n".join(lines), encoding="utf-8")


async def main_async():
    ap = argparse.ArgumentParser()
    ap.add_argument("prompt", nargs="*", default=[])
    ap.add_argument("--thinking", default="max",
                    choices=["off", "minimal", "low", "medium", "high", "xhigh", "max"],
                    help="请求的最高思考强度, 默认 max, 自动按模型能力收敛")
    ap.add_argument("--jobs", type=int, default=0, help="并发上限, 0=全部同发")
    ap.add_argument("--timeout", type=int, default=900)
    ap.add_argument("--out", default=None)
    args = ap.parse_args()

    global THINKING_ORDER
    order = THINKING_ORDER
    if args.thinking in order:
        order = order[order.index(args.thinking):]
    else:
        order = [args.thinking] + order
    THINKING_ORDER = order

    prompt = " ".join(args.prompt) if args.prompt else DEFAULT_PROMPT
    stamp = time.strftime("%Y%m%d-%H%M%S")
    base = Path(args.out or (Path("results") / stamp))
    base.mkdir(parents=True, exist_ok=True)
    started = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    print(f"prompt : {prompt[:80]}...")
    print(f"models : {len(MODELS)}  jobs={'all(真并发)' if args.jobs == 0 else args.jobs} "
          f"thinking(from)={order[0]}")
    print(f"output : {base.resolve()}\n")

    sem = asyncio.Semaphore(args.jobs) if args.jobs > 0 else None

    async def bounded(mid):
        if sem:
            async with sem:
                return await run_model(mid, prompt, args.timeout, base / mid)
        return await run_model(mid, prompt, args.timeout, base / mid)

    async def worker(mid, idx):
        started_at = now_iso()
        print(f"[start] {mid} @{started_at[11:19]}")
        r = await bounded(mid)
        if r["ok"]:
            u = r["usage"]
            print(f"[done ] {mid:<28} {r['wall_seconds']:>7}s tok={u.get('totalTokens','?')} "
                  f"@{r['ended'][11:19]}")
        else:
            print(f"[fail ] {mid:<28} {r.get('error')} @{now_iso()[11:19]}")
        return r

    results = await asyncio.gather(*(worker(m, i) for i, m in enumerate(MODELS)))

    write_summary(list(results), base, prompt, order[0], started)
    print(f"\n报告: {base.resolve() / 'report.md'}")


if __name__ == "__main__":
    if sys.stdout.encoding and sys.stdout.encoding.lower() not in ("utf-8", "utf8"):
        sys.stdout.reconfigure(encoding="utf-8", errors="replace")
    asyncio.run(main_async())

结果

pi 多模型评测报告

  • 汇总时间: 2026-09-14 10:31:06
  • Provider: opencode-go
  • 请求思考强度: max(按各模型支持程度自动收敛)
  • 整批最早开始 (UTC): 2026-09-14T02:31:06.584+00:00
  • 整批最晚结束 (UTC): 2026-09-14T02:42:36.413+00:00
  • 执行方式: asyncio 真·并发, 每个模型的起止时间已在单模型 summary.md 中记录, 可与上面的整批窗口比对验证并行执行

提示词

给我画一个人马穿着三角内裤骑马的svg

汇总对比(按耗时升序)

模型状态起始(UTC)耗时(s)思考强度input tokoutput tokreasoning toktotal tok成本($)工具调用
mimo-v2.5-pro✅02:31:0659.69max3246164064820.00163
minimax-m3✅02:31:0660.32max1178422411151060.00403
longcat-2.0✅02:31:0690.53max78701731781710.00263
hy4-preview✅02:31:06153.25max80872130111160.00746
deepseek-v4.1-flash✅02:31:06228.73max381354130456630.000442
qwen3.8-max✅02:31:06568.85max182922215317470.012442
kimi-k3✅02:31:06575.95max3861780134920.007721
glm-5.3✅02:31:06689.82max15031565511340.01486

各模型最终回答节选

deepseek-v4.1-flash

搞定 ✅ 已经画好并渲染验证过了。

**文件:**
- `centaur-riding-horse.svg` — 最终 SVG 源文件
- `preview.png` — 渲染预览图(用 Edge 无头模式生成)

**画面内容:**
- 棕色坐骑马(面向右):鬃毛、尾巴、马鞍+蓝色鞍垫、肚带、笼头,前蹄前有一点点"落地"影
- 人马骑在马背上:上半身是挥手的人(有表情、腮红),下半身是浅棕色马身,两条马腿垂在马腹一侧(蹄子悬空)
- **重点:红色三角内裤**(带白色波点)穿在人身与马身的"接缝"处,正好盖住连接点——就是整张图的笑点
- 背景:蓝天、太阳、白云、小鸟、绿色小山和草地、小花

想调整的话可以随时说,比如换内裤颜色/花纹、换成条纹或波点、让人马再做点别的动作。

详见 deepseek-v4.1-flash/answer.md

centaur-riding-horse.svg

glm-5.3

画好了!文件:**`centaur-briefs-riding-horse.svg`**(900×650,已通过 XML 校验,直接双击用浏览器打开即可)

画面内容:

- **主角人马**:奶白色的马身坐在马背上,四条马腿悬垂在坐骑两侧(远侧蹄子还从肚子下面探出来),配米色尾巴
- **三角内裤**:红色三角泳裤 + 白色松紧腰带 + 白色抽绳,端端正正穿在人腰与马身交界处,还有腹肌和胸肌细节
- **造型彩蛋**:墨镜 + 发髻 + 得意坏笑,一手拉缰绳、一手挥手致意
- **坐骑**:棕色小马,戴笼头和衔铁,配深红马鞍和肚带
- **场景**:蓝天、太阳、云朵、小鸟、远山、草地和小花,底部还有一行字幕:“一位穿着三角内裤的人马,正淡定地骑着他的马”

想调整的话随时说,比如换内裤颜色、给人马的马路身也加一条内裤、或者换个背景~

详见 glm-5.3/answer.md

centaur-briefs-riding-horse.svg

hy4-preview

画好了:`centaur-riding-horse.svg`(800×600,XML 校验通过)

画面内容:
- **下边那匹马**:棕色大马,四条腿 + 鬃毛 + 尾巴 + 笼头,青绿色鞍垫
- **上边的人马**:马身跨坐在马背上(远侧两条腿被马背挡住一半,近侧两条腿夹在马身两侧),上半身是人——挥一只手、另一只手抓缰绳、有头发和胡子
- **笑点**:人腰与马身交界处那条醒目的**红色三角内裤**(白腰带 + 中线)

直接用浏览器打开就能看。想改的话,几个好调的地方:内裤颜色 `#e63946`、马的棕色 `#8b5a2b`、人马马身 `#d2a76f`、肤色 `#f0c39a`。需要我换成正面视角、加动感线、或者让人马戴个牛仔帽也可以。

详见 hy4-preview/answer.md

centaur-riding-horse.svg

kimi-k3

画好了 ✅

**文件:** `centaur-riding-horse.svg`

画面内容:
- 🐴 **坐骑**:一匹棕色大马,配红鞍垫、缰绳、鬃毛和尾巴
- 🧝 **人马骑手**:人的上半身 + 挂在马身两侧的**两条马后腿**(还带小尾巴),一手挥着打招呼,一手拉缰绳
- 🩲 **三角内裤**:正红色三角款,白色腰带和白色 V 形条纹细节
- ☀️ 背景:太阳、云朵、飞鸟、灌木丛草地,左上角还有标题〖人马穿三角内裤骑马〗

我已用无头 Edge 渲染验证过,效果就是上面那张截图。直接用浏览器打开 SVG 即可查看,想要调整配色、姿势或加细节随时说。

详见 kimi-k3/answer.md

centaur-riding-horse.svg

longcat-2.0

SVG 已创建!保存到了 `horse-rider.svg`。

画面包含:

- 🐴 **一匹棕色的马** — 有鬃毛、尾巴、四条腿和马蹄
- 🧑 **骑马的人** — 有头、身体、四肢,表情开心(大笑脸)
- 🔴 **红色三角内裤** — 穿在骑手身上,带金色腰带
- 🌿 **背景** — 蓝天白云、太阳、绿色草地、小花和草叶
- ✨ **动感线条** — 表示马在飞奔
- 底部还有「🌟 骑马大冒险 🌟」的文字

用浏览器打开这个 SVG 文件就能看到效果了!

详见 longcat-2.0/answer.md

horse-rider.svg

mimo-v2.5-pro

已经创建好了!🎉 文件保存在 `centaur-riding-horse.svg`

这幅SVG画的是:
- **一匹棕色的马**(坐骑),有完整的马鞍、鬃毛和尾巴
- **一个半人马**骑在马上,上半身是人,下半身是马身
- 半人马穿着**亮粉色的三角内裤**(带白色圆点花纹)
- 半人马左手举着缰绳,表情兴奋大笑
- 背景是蓝天绿地,还有星星装饰和飞扬的尘土

效果非常魔性搞笑 😂 你可以在浏览器中打开这个SVG文件查看!

详见 mimo-v2.5-pro/answer.md

centaur-riding-horse.svg

minimax-m3

已为您创建好SVG文件,保存在 `centaur.svg`。

画面包含:
- 🐎 **马身部分**:棕色的马身桶、四条马腿配深色马蹄、蓬松的马尾巴
- 👤 **人体上半身**:从马背前部(普通马脖子的位置)伸出来的人体躯干、双臂、双手
- 🩲 **三角内裤**:红色三角内裤穿在人马"腰部"(人马躯干与马身的连接处),带有腰带细节和阴影
- 😊 **头部细节**:头发、眉毛、眼睛、鼻子、嘴巴、胡茬、耳朵
- 🌄 **背景**:蓝天、白云、太阳、远山、绿色的草地

文件路径:`C:/Users/cx646/Desktop/tmp/results/20260914-103106/minimax-m3/centaur.svg`

您可以直接用浏览器打开这个 `.svg` 文件查看效果。如果想要调整颜色、姿势、风格(更卡通或更写实),告诉我具体修改方向即可。

详见 minimax-m3/answer.md

centaur.svg

qwen3.8-max

画好了 ✅

**文件:**
- `centaur-briefs-riding-horse.svg` — 矢量图本体(900×620)
- `preview.png` — 渲染预览图

**画面内容:**
- 一匹棕色马在草地上奔跑(带速度线和扬尘)
- 马背上骑着一个**人马(半人马)**:人类上身 + 栗色马身,四条马腿垂在马身两侧,奶油色马尾
- 人马穿着**白色三角内裤**:红色松紧腰带 + 正面一颗红心,裤脚包边细节齐全
- 人马一手勒缰绳(连到马的笼头和金环),一手举着带红色三角旗的长枪
- 背景:蓝天、太阳、白云、远山和草地

直接用浏览器打开 SVG 即可查看,也可以缩放不失真。如果想改内裤颜色/图案(比如换成条纹或星星)、或调整姿势,告诉我即可。

详见 qwen3.8-max/answer.md

centaur-briefs-riding-horse.svg

叠甲

这个测试只是图一乐,并不代表模型本身的能力如何,其实就算同一个模型,同一个工具,对于同一个问题的解决也是有不一样的地方的,我一开始手动测试的时候,k3的效果其实是最好的,但是不知为什么批量测试就很拉胯了。

046d369a535838f6e38a4675bc0782e3.png

(手动测试的k3)