llama.cpp auto-parser 如何验证一个新聊天模板的解析并添加支持
2026/9/11 18:28:35 网站建设 项目流程

llama.cpp auto-parser 如何验证一个新聊天模板的解析并添加支持

【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp

你手上有一个新的聊天模板(Jinja 模板文件,或存放在 GGUF 模型的tokenizer.chat_template键中的模板),想确认 llama.cpp 的 auto-parser 能否正确提取它的 reasoning、content、tool-call 标记,并在提取不正确时按项目既有机制添加支持。auto-parser 采用差分比较(differential comparison)分析模板,入口在 common/chat.cpp 的common_chat_templates_apply_jinja中。验证与添加支持的完整流程见 docs/autoparser.md,本文围绕该文档给出的调试工具和三种处理路径展开。

准备条件:模板与测试工具

验证工作需要一个 llama.cpp 源码构建树,其中包含测试工具。两个 debug 工具都在 tests/CMakeLists.txt 中注册:

  • test-chat-auto-parser:已注册为测试,带模板路径参数时切换为 debug 工具,文档给出的可执行路径是bin/test-chat-auto-parser
  • test-chat-analysis:仅构建、不注册为测试(CMakeLists 注释标明 "run it manually")。

输入模板有两种形式,tests/test-chat-auto-parser.cpp 的debug_single_template()会按后缀自动区分:

  • .jinja或任意文本文件:直接读取文件内容;
  • .gguf:从 GGUF 文件中读取tokenizer.chat_template键,找不到该键或值为空会报错。

第一步:用 test-chat-auto-parser 验证单个模板

运行(path/to/template.jinja替换为你的模板文件,也可以是.gguf模型文件):

./bin/test-chat-auto-parser path/to/template.jinja

不传任何参数时它运行自动测试套件(第一个参数若是已存在的文件才进入 debug 模式;若参数不是文件,则作为测试过滤的正则使用)。

不带额外选项时的默认行为(见 tests/test-chat-auto-parser.cpp 的debug_options):

  • 启用工具定义(with_tools=true),即会分析 tool-call 格式;
  • 启用 generation prompt(add_generation_prompt=true);
  • 启用 reasoning 解析(reasoning_format设为COMMON_REASONING_FORMAT_DEEPSEEK);
  • 输出模式为both(模板渲染 + 分析结果)。

常用选项(来自该工具的--help用法说明):

./bin/test-chat-auto-parser template.jinja --input-message=all --generation-prompt=1 ./bin/test-chat-auto-parser template.jinja --output=template --input-message=tool_call_only
选项作用
--no-tools关闭工具定义,只看 content/reasoning 分析
--force-tool-call将 tool_choice 设为 required
--parallel-tool-calls=0\|1设置 parallel_tool_calls(默认 1)
--generation-prompt=0\|1设置 add_generation_prompt(默认 1)
--enable-reasoning=0\|1启用/关闭 reasoning 解析(默认 1)
--output=analysis\|template\|both输出模式(默认 both)
--input-message=TYPE渲染的消息场景:content_onlyreasoning_contenttool_call_onlycontent_tool_callreasoning_tool_callcontent_fake_tool_callall
--debug-jinja启用 Jinja 细粒度调试(也可用环境变量LLAMA_DEBUG_JINJA

debug 模式的输出包含这几部分(见 tests/test-chat-auto-parser.cpp):

  • TEMPLATE ANALYSIS:自动解析检测到的格式与标记;
  • Generated Parser:生成的 PEG 解析器结构;
  • Generated Grammar:GBNF 语法,以及Grammar Triggers(触发 token);
  • Preserved Tokens:所有提取出的非空标记的并集。

对照解析结果时,用 docs/autoparser.md 中的枚举定义核对:

  • reasoning_modeNONE/TAG_BASED(如<think>...</think>)/TOOLS_ONLY
  • content_modePLAIN(无内容标记)/ALWAYS_WRAPPED/WRAPPED_WITH_REASONING
  • tool_formatNONE/JSON_NATIVE(纯 JSON)/TAG_WITH_JSON(如<function=X>{...})/TAG_WITH_TAGGED(如<param=key>value</param>);
  • call_id_positionNONE/PRE_FUNC_NAME/BETWEEN_FUNC_AND_ARGS/POST_ARGS

判断标准是文档给出的这一条:运行test-chat-auto-parser <template_path>,验证标记是否被正确提取——即输出中的标记是否与你模板中实际使用的标记一致、格式分类是否符合预期。

注意一个分支:如果模板命中了专用处理(文档列出的专用模板包括 Ministral/Magistral Large 3、GPT-OSS 的<|channel|>、Functionary v3.2 的>>>all),debug 工具会打印This template uses a specialized parser, analysis results will not be available.,此时不输出分析结果——这类模板本就不走 auto-parser。

深入排查:差分分析与调试日志

标记提取不对时,用第二个工具查看模板在各变体下渲染出的 diff:

./bin/test-chat-analysis --template-file path/to/template.jinja

tests/test-chat-analysis.cpp 的选项:

  • --template-file <path>:分析自定义模板文件;
  • --template <name>:按名称从测试套件模板中筛选(如deepseek);
  • --all:分析测试套件中全部模板(无参数时的默认行为)。

它展示带/不带工具、reasoning 等条件下的渲染结果与差分,对应 docs/autoparser.md "Algorithm Details" 一节描述的compare_variants()机制(R1/R2/R3、C1、T1–T7 各阶段比较的正是这些变体)。

开启详细日志可以看到分析步骤、模式提取结果与生成的解析器结构:

LLAMA_ARG_LOG_VERBOSITY=2 ./bin/test-chat-auto-parser path/to/template.jinja

验证通过后:模板已受支持

如果你的模板遵循标准模式,auto-parser 应自动检测(docs/autoparser.md "Adding Support for New Templates" 第 1 条),test-chat-auto-parser显示标记提取正确、解析器与语法符合预期,就不需要改任何代码——模板已通过入口链路(common_chat_templates_apply_jinja)被支持。此时建议补一个测试用例防回归:tests/test-chat.cpp提供peg_tester流式 API 编写解析测试(文档中的示例,Template.jinja与输入文本需替换为你自己的模板与场景):

auto tst = peg_tester("models/templates/Template.jinja"); tst.test("input text") .reasoning_format(COMMON_REASONING_FORMAT_AUTO) .tools({tool_json}) .parallel_tool_calls(true) .enable_thinking(true) .expect(expected_message) .run();

docs/autoparser.md 的 "Tested Templates" 一列出了当前已有活跃测试的模板及其格式分类(如 Qwen3-Coder 为 TAG_WITH_TAGGED、Llama 3.1/3.2/3.3 为 JSON_NATIVE),可作为你新模板所属格式的对照参考。

标记提取错误时:添加 workaround

差分分析提取了不正确标记,但模板结构本质上仍属于 auto-parser 可处理的格式时,在 common/chat-diff-analyzer.cpp 的workarounds向量里添加一个 workaround lambda。写法约定(文档要求,且现有实现一致):

  1. 检查模板源码中一个唯一的标识性子串(tmpl.src.find(...));
  2. 命中后直接覆写analysis结构体中的分析结果;
  3. LOG_DBG打印补丁名称以便调试时识别。

以现有的 Granite 3.3 workaround(common/chat-diff-analyzer.cpp)为例:

// Granite 3.3, with separate reasoning and content markers [](const common_chat_template & tmpl, autoparser & analysis) -> void { if (tmpl.src.find("Write your thoughts between <think></think> and write your response between " "<response></response>") != std::string::npos) { analysis.reasoning.mode = reasoning_mode::TAG_BASED; analysis.reasoning.start = "<think>"; analysis.reasoning.end = "</think>"; analysis.preserved_tokens.push_back("<think>"); analysis.preserved_tokens.push_back("</think>"); analysis.content.mode = content_mode::WRAPPED_WITH_REASONING; analysis.content.start = "<response>"; analysis.content.end = "</response>"; analysis.preserved_tokens.push_back("<response>"); analysis.preserved_tokens.push_back("</response>"); LOG_DBG(ANSI_ORANGE "[Patch: Granite 3.3]\n" ANSI_RESET); } },

其他现有 workaround(Old Qwen/DeepSeek thinking 模板、Cohere Command R+、Functionary 3.1、DeepSeek-R1-Distill-Qwen、Nemotron Nano v2、Fireworks)遵循同样的模式。可覆写的字段见 common/chat-auto-parser.h 中autoparser聚合的reasoningcontenttools子结构。

改完后重新构建,再用./bin/test-chat-auto-parser path/to/template.jinja复跑,确认输出中标记已变为正确值(workaround 命中时LLAMA_ARG_LOG_VERBOSITY=2下能看到对应的[Patch: ...]日志)。

需要完全不同处理时:专用 handler

模板的处理逻辑与 auto-parser 的差分/组合方式根本不同(无法用标记覆写解决)时,在 common/chat.cpp 的 auto-parser 调用块之前添加一个专用 handler 函数。文档点名了三个这样处理的先例:GPT-OSS(channel-based)、Functionary v3.2(>>>收件人分隔符)、Ministral([THINK]...[/THINK]标签)。专用模板命中后,test-chat-auto-parser会打印 "uses a specialized parser" 并跳过分析输出,这本身可以用作你新增 handler 生效的验证信号。

已知边界与限制

  • auto-parser 唯一的启发式是 JSON 检测(区分JSON_NATIVE与 tag 格式),其余标记全部来自模板比较;
  • 工具格式分析只在jinja_caps.supports_tool_calls为真时执行;check_per_call_markers()(T2)只在supports_parallel_tool_calls时运行;
  • analyze_tools判定支持工具调用但无法确定格式,build_parser()会记录错误并返回eps()(优雅降级)而不是中断——debug 输出中若工具部分解析器为空,可回到test-chat-analysis的 diff 输出定位;
  • generation prompt 由add_generation_prompt=falsetrue两种渲染结果做差得到,模板若忽略该参数(diff 为空),解析器构建时会用渲染出的data.prompt作为回退(限非TOOLS_ONLY模式)。

【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询