logo
0
0
WeChat Login

eval-server

Agent 评估框架后端服务(Go + PostgreSQL + Redis + Kafka)。

项目代码结构

eval-server/ ├── cmd/server/ # 程序入口:加载配置、初始化 DI 容器、注册路由、启动 Kafka Worker ├── internal/ │ ├── domain/ # 核心业务逻辑(DDD 聚合根 + 领域服务) │ │ ├── evaluation/ # 评测运行、任务、结果;LLM/规则/span 评估器 │ │ ├── execution/ # 执行运行、任务、Trace Session、Span │ │ ├── suite/ # 测试套件、用例、轮次、标签、Span 期望 │ │ ├── config/ # 评估配置、指标、打分标准、Judge Profile │ │ ├── aggregation/ # 通过率与分数聚合 │ │ ├── governance/ # Golden Set、漂移检测、仲裁 │ │ ├── manualscore/ # 人工打分任务 │ │ ├── sampling/ # 采样策略与规则 │ │ ├── script/ # 可复用评估脚本 │ │ └── shared/ # 基础实体、租户、值对象 │ ├── application/ # 应用层(命令/查询/服务编排) │ │ ├── service/ # 应用服务:ExecutionApp、EvaluationApp、DashboardApp 等 │ │ ├── command/ # 写侧命令结构体 │ │ ├── query/ # 读侧查询接口与类型 │ │ └── dto/generated/ # Thrift 生成的 DTO(`make gen` 产出,已提交) │ ├── interface/http/ # HTTP 层 │ │ ├── handler/ # Gin 请求处理、DTO 解析、响应封装 │ │ └── middleware/ # Auth、RequestID、Tenant 中间件 │ └── infrastructure/ # 基础设施 │ ├── config/ # 配置加载(Viper + 环境变量) │ ├── di/ # 依赖注入容器(Wire 风格手工组装) │ ├── persistence/ # GORM 模型与 Repository 实现 │ ├── kafka/ # Kafka Consumer/Producer、任务 Worker │ ├── llm/ # LiteLLM / Gemini 客户端 │ ├── langfuse/ # Langfuse Trace 拉取客户端 │ ├── cache/ # Redis 缓存 │ ├── observability/ # OpenTelemetry、Prometheus 指标 │ ├── migrations/ # 迁移运行器(在进程内执行) │ └── crypto/ # AES 加密工具 ├── pkg/ # 公共包 │ ├── errors/ # 业务错误类型封装 │ └── logger/ # 结构化日志(zapcore 封装) ├── migrations/ # SQL 迁移文件(golang-migrate,32 个版本) ├── idl/ # Thrift IDL 定义(idl.thrift) ├── deploy/k8s/ # Kubernetes 清单(Deployment、Service、HPA 等) ├── scripts/ # 工具脚本 │ ├── gen_thrift.sh # 生成 Thrift DTO │ ├── openapi/ # 生成 OpenAPI 文档 │ └── seed/ # 数据库 Seed 脚本(`make seed`) ├── tests/ # 测试 │ ├── e2e/ # 端到端测试 │ ├── integration/ # 集成测试 │ └── perf/ # 性能测试(k6 + vegeta) └── docs/ # OpenAPI 文档(openapi.yaml,`make openapi` 生成)

架构分层(从外到内):

interface/http/handler → application/service → domain/*/service → infrastructure/persistence

代码规范

不可变更新

Go 中禁止就地修改已有结构体,始终返回新结构体或副本:

// 错误:直接修改传入结构 func updateRun(r *EvalRun, status string) { r.Status = status // 禁止 } // 正确:返回新值 func withStatus(r EvalRun, status string) EvalRun { r.Status = status return r }

错误处理

  • 所有错误必须显式处理,不允许 _ = err
  • 使用 fmt.Errorf("...: %w", err) 包装上下文。
  • 使用 errors.Is / errors.As 做类型判断。
  • 禁止在中间层吞掉错误后继续执行。
result, err := repo.FindByID(ctx, id) if err != nil { return fmt.Errorf("findEvalRun %s: %w", id, err) }

输入校验

在 Handler 层对所有入参做显式校验(struct 字段校验或手工检查),不允许裸传至 Service 层:

if req.SuiteID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "suite_id is required"}) return }

文件与函数粒度

  • 单文件不超过 800 行,典型目标 200–400 行。
  • 单函数不超过 50 行;复杂逻辑拆分为私有辅助函数。
  • 按功能/领域组织文件,禁止把无关逻辑堆到一个大文件。

命名规范

场景规范
导出标识符PascalCase
未导出标识符camelCase
接口命名动词/能力名词,如 InvokerRepository
禁止 stutterevaluation 内不用 EvaluationService,用 Service

禁止硬编码密钥

所有密钥、URL、凭证必须通过环境变量注入,由 internal/infrastructure/config/config.go 统一加载:

// 禁止 const apiKey = "sk-xxxxx" // 正确 apiKey := cfg.LLM.APIKey

context.Context 规范

context.Context 必须作为第一个参数贯穿整个调用链,不允许存储在结构体中:

func (s *Service) CreateRun(ctx context.Context, cmd CreateRunCommand) (*EvalRun, error)

日志规范

  • 使用 pkg/logger 提供的结构化日志,禁止 fmt.Printlnlog.Printlnlog.Printf 出现在提交中。
  • 日志级别:调试信息用 Debug,正常流程用 Info,可恢复错误用 Warn,不可恢复错误用 Error

可用的 Make 命令

make build # 编译二进制到当前目录(输出文件名:server) make test # 运行全部单元测试 make lint # 运行 golangci-lint(启用 errcheck/govet/staticcheck/gofmt/goimports) make format # gofmt + goimports 格式化所有 .go 文件 make gen # 执行 go generate(重新生成 Thrift DTO) make openapi # 生成 docs/openapi.yaml make migrate-up # 执行数据库迁移(需要 DATABASE_URL 环境变量) make migrate-down # 回滚最近一次迁移 make seed # 运行 scripts/seed/main.go 填充测试数据

本地部署说明

前置依赖

依赖版本要求说明
Go1.23+go.mod
Docker Desktop最新版运行基础服务
make系统自带构建工具
migrate可选数据库迁移 CLI(go install github.com/golang-migrate/migrate/v4/cmd/migrate@latest
golangci-lint可选本地 lint(go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

1. 启动依赖服务

注意:eval-server 使用独立的 Docker stack(eval_backend),端口与 eval-invoke 的 stack 不同,请勿混淆。

# 在 eval-server 目录执行 docker compose up -d postgres redis zookeeper kafka

服务端口映射:

服务容器端口宿主机端口
PostgreSQL 1554325433
Redis 763796380
Zookeeper21812181
Kafka9092 / 290929092 / 29092 (推荐从宿主机连接用 29092)

2. 创建 Kafka DLQ Topic

eval-server 启动前必须预先创建以下 Dead Letter Queue topic,否则消费失败时 Worker 会无限阻塞:

docker exec eval_backend-kafka-1 kafka-topics --bootstrap-server localhost:9092 --create --topic eval.evaluation-tasks.dlq --partitions 1 --replication-factor 1 docker exec eval_backend-kafka-1 kafka-topics --bootstrap-server localhost:9092 --create --topic eval.execution-tasks.dlq --partitions 1 --replication-factor 1 docker exec eval_backend-kafka-1 kafka-topics --bootstrap-server localhost:9092 --create --topic eval.trace-fetch.dlq --partitions 1 --replication-factor 1

3. 配置环境变量

cp .env.example .env

编辑 .env,重点核查以下字段(其余保持默认即可):

DATABASE_URL=postgres://postgres:postgres@localhost:5433/eval_backend?sslmode=disable REDIS_ADDR=localhost:6380 KAFKA_BROKERS=localhost:29092

4. 数据库迁移

迁移在服务启动时会自动执行(通过 internal/infrastructure/migrations/runner.go)。

如需手动执行:

make migrate-up # 需要环境变量 DATABASE_URL,或直接传递: DATABASE_URL=postgres://postgres:postgres@localhost:5433/eval_backend?sslmode=disable make migrate-up

5. 生成 Thrift DTO(首次或 IDL 变更后)

make gen

6. 启动后端服务

go run ./cmd/server

或使用 Docker Compose 一体启动(含热重载):

docker compose up app

默认监听:

  • HTTP API::8080
  • Prometheus 指标::9090

7. eval-invoke 依赖说明

eval-server 在执行 exec-run 时通过 HTTP 调用 eval-invoke(路径 /api/eval/invoke)。调用目标地址来自数据库中存储的 agent_endpoints 记录(通过 /api/v1/agent-endpoints API 管理),而非固定配置项。

eval-invoke 使用独立的 Docker stack(agent_v1_3_2,端口 5432/6379),与 eval-server 的 stack 完全隔离。本地开发时默认 eval-invoke 监听 :8001

8. 健康检查 / 验证服务正常

curl http://127.0.0.1:8080/health # → {"status":"ok"} curl http://127.0.0.1:8080/ready # → {"status":"ok"}(含 DB/Redis 连通检查) curl http://127.0.0.1:8080/health/kafka # → {"status":"ok"}(Kafka broker 可达)

常见问题

现象原因解决方法
Kafka eval consumer 卡死,无法消费新消息DLQ topic 不存在,失败消息无法投递创建 DLQ topic(见第 2 步),重启 eval-server
GET /api/v1/scripts 返回 500GORM 期望表名 script_models,迁移创建的是 scripts检查迁移是否完整执行
Trace session 一直是 PENDINGTrace 拉取失败未重试手动触发 POST /api/v1/trace-sessions/<id>/retry-fetch
Kafka Zookeeper NodeExists 错误Stale broker session等待 Zookeeper 就绪后重启 Kafka 容器

English (legacy)

This repo follows the OpenSpec change plan in openspec/changes/implement-eval-backend/.

API Migration Notes

  • POST /api/v1/eval-runs no longer accepts eval_config_id or judge_profile_id.
  • Client migration guide: docs/migration-evaluation-start.md

About

No description, topics, or website provided.
Language
Go97.9%
Thrift2%
Dockerfile0.1%
Shell0%