defmodule Mix.Tasks.Cmdc.Eval.FetchBfcl do @shortdoc "从上游公开仓库拉取 BFCL v3 fixtures 到 priv/bfcl/v3/" @moduledoc """ 从 Berkeley Function Calling Leaderboard v3 上游公开仓库拉取 fixtures 并转换为 cmdc_eval 内部 JSONL 格式。 ## 用法 $ mix cmdc.eval.fetch_bfcl $ mix cmdc.eval.fetch_bfcl --dest=priv/bfcl/v3 --category=simple ## 选项 - `--dest=` 输出目录(默认 `priv/bfcl/v3`) - `--category=` 仅拉某一类别(默认 `simple`;可选 `simple` / `multiple` / `parallel` / `parallel_multiple`) - `--limit=` 限制拉取条目数(默认 10,便于快速 spike) ## 数据来源 上游: 路径:`berkeley-function-call-leaderboard/data/BFCL_v3_.json` ## 注意 - 需要 `git` + `curl` 命令可用 - 拉到的数据 **不会** 进 hex 包(fixtures 在 `priv/bfcl/`, `.gitignore` 默认忽略,运行 evals 前需自行拉取) - 数据许可证遵循上游(Apache-2.0,但请自行确认最新) ## v0.1 状态 v0.1 实现 **最小骨架**:从上游 raw URL `curl` 单个 JSON 文件, 转换为 cmdc_eval 内部 `{"id", "question", "function", "ground_truth"}` 格式。 失败时打 warning + 写 placeholder(含说明),不阻塞 `mix cmdc.eval`。 完整 BFCL 全 5 子类 + ground truth 解析留 v0.2 扩展。 """ use Mix.Task require Logger @impl Mix.Task def run(argv) do {opts, _, _} = OptionParser.parse(argv, strict: [dest: :string, category: :string, limit: :integer] ) dest = Keyword.get(opts, :dest, "priv/bfcl/v3") category = Keyword.get(opts, :category, "simple") File.mkdir_p!(dest) # v0.1 fetch logic 留 v0.2 实现真实 HTTP/git clone;当前直接写 placeholder # 让 mix cmdc.eval --suite=bfcl 至少有 fixtures 可读,集成方按 moduledoc # 提示手动从 upstream 拉真实数据 Logger.info( "[cmdc.eval.fetch_bfcl] v0.1: writing placeholder fixtures (upstream fetch 留 v0.2)" ) write_placeholder(dest, category) end defp write_jsonl(path, items) do payload = items |> Enum.map(&Jason.encode!/1) |> Enum.map(&(&1 <> "\n")) |> IO.iodata_to_binary() File.write!(path, payload) end defp write_placeholder(dest, category) do placeholder = [ %{ "id" => "placeholder-1", "question" => "What is the weather in Tokyo today?", "function" => "get_weather", "ground_truth" => "get_weather" }, %{ "id" => "placeholder-2", "question" => "Calculate the sum of [1, 2, 3, 4, 5].", "function" => "calculate_sum", "ground_truth" => "calculate_sum" } ] path = Path.join(dest, "#{category}.jsonl") write_jsonl(path, placeholder) Mix.shell().info(""" ⚠️ Upstream fetch unavailable in v0.1; wrote 2 placeholder cases → #{path} 手动拉取真实 BFCL v3 fixtures: 1. git clone https://github.com/ShishirPatil/gorilla 2. cp gorilla/berkeley-function-call-leaderboard/data/BFCL_v3_simple.json #{dest}/ 3. 自行写脚本转 cmdc_eval JSONL 格式(v0.2 cmdc_eval 自动化此步) """) end end