开源 AI-Eval:Prompt 评估系统,用单元测试跑

TLDR: ai-eval 是一套 Go 写的 Prompt 评估系统。把 Prompt 测试当单元测试跑——写 YAML 定义用例,配评估器(模式匹配、LLM Judge、RAG、Agent、安全检测),跑 pass@k 处理 LLM 的不确定性。带 Web API、Leaderboard、CI 集成,支持 MMLU/GSM8K/HumanEval 标准 Benchmark。

维度 能力
评估器 模式匹配、LLM Judge、语义相似度、RAG、Agent、安全性
Benchmark MMLU、GSM8K、HumanEval(Docker 沙箱)
Provider Claude (Anthropic)、OpenAI
接入方式 CLI、Web API、CI/CD
存储 SQLite + Leaderboard

问题

改 Prompt 是个玄学活。

加了一句"请用中文回答",准确率从 85% 掉到 60%。把"你是专家"换成"你是资深工程师",效果又回来了。这种事我遇到不止一次。

传统代码有单元测试兜底,改了跑一遍就知道有没有 break。但 Prompt 的输出是非确定性的——同一个输入跑三次,三次结果可能都不一样。靠人眼盯?Prompt 一多根本盯不过来。

ai-eval 就是来解决这个问题的:给 Prompt 写测试,像跑 go test 一样跑评估。

架构

系统分六层,CLI 和 Web API 都走同一个 Core Engine,评估器通过 Registry 模式挂载。

graph TB
    subgraph CLI["CLI (cmd/eval)"]
        RUN[eval run]
        BENCH[eval benchmark]
        CMP[eval compare]
        OPT[eval optimize]
        LB[eval leaderboard]
    end

    subgraph API["Web API (api/)"]
        REST[REST Endpoints]
        WEB[Web UI]
    end

    subgraph Core["Core Engine"]
        RUNNER[Runner]
        LOADER[Prompt Loader]
        TC[Test Case Loader]
    end

    subgraph LLM["LLM Providers (internal/llm)"]
        CLAUDE[Claude / Anthropic]
        OPENAI[OpenAI / Compatible]
    end

    subgraph Evaluators["Evaluators (internal/evaluator)"]
        direction LR
        BASIC["Basic\ncontains | exact | regex"]
        SEMANTIC["Semantic\nllm_judge | factuality | similarity"]
        SAFETY["Safety\ntoxicity | bias | hallucination"]
        AGENT["Agent\ntool_selection | efficiency"]
        RAG["RAG\nfaithfulness | relevancy | precision"]
    end

    subgraph Benchmark["Benchmarks (internal/benchmark)"]
        MMLU[MMLU]
        GSM8K[GSM8K]
        HUMANEVAL[HumanEval]
    end

    subgraph Storage["Storage"]
        SQLITE[(SQLite)]
    end

    CLI --> Core
    API --> Core
    Core --> LLM
    Core --> Evaluators
    BENCH --> Benchmark
    Benchmark --> LLM
    LB --> SQLITE
    BENCH --> SQLITE
    RUNNER --> LOADER
    RUNNER --> TC

    style CLI fill:#e1f5fe,stroke:#01579b
    style API fill:#e8f5e9,stroke:#1b5e20
    style Core fill:#fff3e0,stroke:#e65100
    style LLM fill:#f3e5f5,stroke:#4a148c
    style Evaluators fill:#fce4ec,stroke:#880e4f
    style Benchmark fill:#e0f2f1,stroke:#004d40
    style Storage fill:#f5f5f5,stroke:#616161

跑一次评估的流程长这样:

sequenceDiagram
    participant User
    participant CLI
    participant Runner
    participant LLM as LLM Provider
    participant Eval as Evaluators
    participant DB as SQLite

    User->>CLI: eval run --prompt example
    CLI->>Runner: Load prompt + test cases

    loop For each test case
        loop For each trial (1..N)
            Runner->>LLM: Send prompt + input
            LLM-->>Runner: Response
            Runner->>Eval: Evaluate response
            Eval-->>Runner: Score + Pass/Fail
        end
    end

    Runner->>DB: Store results
    Runner-->>CLI: Suite results
    CLI-->>User: Pass/Fail report

每个 test case 跑 N 次 trial,每次都过评估器打分,最后算 pass@k。结果存 SQLite,下次可以对比。

怎么用

思路很直接:一个 YAML 定义 Prompt,一个 YAML 定义测试用例。

Prompt 定义:

    
    
    
  name: code-review
version: "1.0"
is_system_prompt: true
template: |
  你是一个代码审查助手。
  请审查以下代码:{{.code}}
tools:
  - name: suggest_fix
    description: 建议修复方案
    input_schema: {...}

测试用例:

    
    
    
  prompt: code-review
suite: basic
cases:
  - id: null-check
    input:
      code: "if (user) { user.name }"
    evaluators:
      - type: contains
        expected: ["null", "undefined"]
      - type: llm_judge
        criteria: "应该指出潜在的空指针问题"

一个 case 可以挂多个评估器。contains 检查输出里有没有关键词,llm_judge 让另一个 LLM 当裁判打分。两个都过了才算通过。

评估器

评估器是这套系统的核心,用 Registry 模式实现,加新的评估器只要实现一个接口。目前有 5 类 16 个:

模式匹配 —— 最快,不调 LLM

  • exact: 精确匹配
  • contains: 包含检查
  • regex: 正则
  • json_schema: JSON Schema 校验

LLM 评估 —— 用 LLM 当裁判

  • llm_judge: 根据 criteria 打 1-10 分(Likert 量表),这个用得最多
  • similarity: 语义相似度
  • factuality: 事实准确性

RAG 专用

  • faithfulness: 回答是否忠于检索内容
  • relevancy: 检索相关性
  • precision: 检索精度

Agent 专用

  • task_completion: 任务完成度
  • tool_selection: 工具选择对不对
  • efficiency: 执行效率(调用次数、Token 消耗)

安全性

  • hallucination: 幻觉检测
  • toxicity: 毒性检测
  • bias: 偏见检测

每个评估器返回统一的四元组:Passed(布尔)、Score(0-1)、MessageDetails。写自定义评估器也是返回这个结构。

pass@k

LLM 输出不确定,跑一次不能说明问题。pass@k 处理这个:

pass@k = 1 - (1 - pass_rate)^k

就是跑 k 次至少有一次通过的概率。pass_rate 0.7 的情况下:

k pass@k
1 0.700
3 0.973
5 0.998

配置里指定 trials(跑几次)和 threshold(通过阈值)就行。我一般设 trials=3,threshold=0.8。

Benchmark

除了自定义测试,内置三个标准 Benchmark:

Benchmark 干什么 细节
MMLU 通用知识 57 个学科的多选题
GSM8K 数学推理 小学数学应用题
HumanEval 代码生成 默认跑在 Docker 沙箱里

HumanEval 需要执行生成的代码来验证正确性,所以有个安全开关:

    
    
    
  # 默认 Docker 沙箱(推荐)
AI_EVAL_ENABLE_CODE_EXEC=1 eval benchmark --dataset humaneval --sample-size 50

# 直接在宿主机跑(别在生产环境用)
AI_EVAL_ENABLE_CODE_EXEC=1 AI_EVAL_SANDBOX_MODE=host eval benchmark --dataset humaneval

跑完记录准确率、Token 用量、延迟,按类别细分。结果存 SQLite,eval leaderboard --dataset mmlu 看历史对比。

Benchmark 的流程和评估不太一样,走的是专门的 Benchmark Runner:

sequenceDiagram
    participant User
    participant CLI
    participant BM as Benchmark Runner
    participant DS as Dataset
    participant LLM as LLM Provider
    participant LB as Leaderboard

    User->>CLI: eval benchmark --dataset mmlu
    CLI->>DS: Load questions
    DS-->>BM: Questions[]

    loop For each question
        BM->>LLM: Question prompt
        LLM-->>BM: Answer
        BM->>DS: Evaluate answer
        DS-->>BM: Score
    end

    BM->>LB: Save result
    BM-->>User: Accuracy report

Agent 测试

Agent 场景有专门支持。测试用例可以配 Tool Mock,不用真的去调外部 API:

    
    
    
  cases:
  - id: search-task
    input:
      task: "搜索最新的 Go 1.23 特性"
    tool_mocks:
      search:
        - query: "Go 1.23 features"
          response: "Go 1.23 支持 range over func..."
    evaluators:
      - type: tool_selection
        expected_tools: ["search"]
      - type: task_completion
        criteria: "应该准确总结 Go 1.23 的新特性"

执行时自动处理 Tool-calling loop,用 mock 响应替代真实调用。这样测试是确定性的,不依赖外部服务。

Web API

ai-eval 不只是个 CLI 工具。cmd/server 起一个 Web API 服务,带 REST 接口和静态页面:

    
    
    
  api/
├── server.go          # HTTP server
├── routes.go          # 路由注册
├── handlers.go        # 评估相关 handler
├── leaderboard.go     # Leaderboard 查询接口
├── middleware.go       # 日志、CORS、认证
└── security_config_test.go

Leaderboard 接口可以查历史 Benchmark 结果,按模型、数据集筛选。web/static/ 下有个简单的前端页面。

说实话这个 Web UI 目前比较简陋,但 API 本身够用了,可以自己接 Grafana 或者写个 Dashboard。

Red Team 测试

internal/redteam/ 里有个对抗性测试生成器。给它一个 Prompt,它会自动生成试图绕过安全限制的输入,配合 safety 评估器(toxicity、bias、hallucination)跑一遍,看 Prompt 的防御能力。

这个功能我觉得挺有意思,但目前生成的攻击模式还比较基础。

CI 集成

eval ci --threshold 0.8 跑完评估,分数低于阈值直接返回非零退出码。

internal/ci/github.go 里有 GitHub 集成——可以在 PR 评论里贴评估结果。典型用法:Prompt 改动走 PR,CI 自动跑评估,不达标就 block merge。

    
    
    
  # CI 模式,阈值 0.8
eval ci --threshold 0.8

# 跑指定 Prompt 的测试
eval run --prompt code-review --suite basic --trials 3

# 对比两个版本
eval compare --prompt code-review --versions v1,v2

# 让 LLM 分析失败用例,建议怎么改 Prompt
eval optimize --prompt code-review --suite basic

optimize 命令会分析失败用例,用 LLM 生成改进建议,直接输出修改后的 Prompt。省了不少手动分析的功夫。

项目结构

    
    
    
  ai-eval/
├── cmd/
│   ├── eval/              # CLI 入口
│   └── server/            # Web API server
├── api/                   # HTTP handlers、路由、中间件
├── configs/
│   └── config.yaml.example
├── internal/
│   ├── app/               # 编排层(run orchestrator)
│   ├── benchmark/         # MMLU、GSM8K、HumanEval
│   ├── ci/                # GitHub CI 集成
│   ├── claude/            # Claude API client
│   ├── config/            # 配置加载
│   ├── evaluator/         # 评估器实现
│   │   ├── agent/         # Agent 评估器
│   │   ├── rag/           # RAG 评估器
│   │   └── safety/        # 安全评估器
│   ├── generator/         # 测试用例生成
│   ├── leaderboard/       # Leaderboard 存储
│   ├── llm/               # LLM Provider(Claude、OpenAI)
│   ├── optimizer/         # Prompt 优化(失败分析 + 改写)
│   ├── prompt/            # Prompt 加载 + 模板渲染
│   ├── redteam/           # Red Team 对抗测试
│   ├── runner/            # 测试执行引擎
│   ├── store/             # SQLite 存储层
│   └── testcase/          # 测试用例加载
├── prompts/               # Prompt 定义(YAML)
├── tests/                 # 测试用例(YAML)
└── web/static/            # Web UI 静态文件

适合什么场景

我觉得这几个场景用起来收益最大:

Prompt 迭代 —— 改之前先把现有行为写成测试。改完跑一遍,有没有 regression 一目了然。比手动对比强太多。

模型迁移 —— 从 Claude 切到 GPT,或者升级模型版本,同一套测试跑一遍就知道新模型在你的场景下行不行。我们从 Sonnet 4.5 切到 Opus 4.5 的时候就是这么验的。

CI 质量门禁 —— Prompt 改动走 PR,CI 自动跑评估,不达标 block merge。这个对团队协作帮助很大,不用每次 review Prompt 改动都靠人肉判断。

RAG 调优 —— faithfulness、relevancy、precision 三个评估器量化 RAG 效果。调了检索策略之后跑一遍,比人眼看靠谱。

最后

ai-eval 解决的问题很具体:怎么系统化地测试 Prompt,不靠感觉靠数据。

如果你在维护多个 Prompt,或者团队里有人改 Prompt 改出过事故,可以试试。Go 写的,go install 一行搞定。

项目地址:github.com/stellarlinkco/ai-eval

欢迎提 Issue 和 PR。特别缺的是:更多 Provider 支持(Gemini、Mistral、国产模型)、多模态评估、更好的 Web Dashboard。


License: AGPL-3.0,商用需要单独授权

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐