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=<path>` 输出目录(默认 `priv/bfcl/v3`)
- `--category=<name>` 仅拉某一类别(默认 `simple`;可选 `simple` /
`multiple` / `parallel` / `parallel_multiple`)
- `--limit=<n>` 限制拉取条目数(默认 10,便于快速 spike)
## 数据来源
上游:<https://github.com/ShishirPatil/gorilla>
路径:`berkeley-function-call-leaderboard/data/BFCL_v3_<category>.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