深度研究 Agent 训练项目 — 测试题答案

⚠️ 请先独立作答,再查看答案!

对应题目见 [[深度研究Agent训练项目_笔记]]


基础概念题

A1:labels-100 的含义

-100 是 PyTorch CrossEntropyLoss 的忽略索引(ignore_index)。 在训练时,我们只希望模型学习"如何生成 assistant 的回复",而不需要学习 system prompt、用户问题、或工具返回结果。 因此对于非 assistant 角色的 token,将 labels 设为 -100,损失函数会跳过这些位置,不计算、不反向传播


A2:LoRA 的核心思想与优势

核心思想:假设模型权重的"更新量"ΔW 是低秩的。将 ΔW 分解为两个小矩阵 B × A(B: [d × r],A: [r × d],r « d)的乘积,只训练这两个小矩阵,原始权重冻结。

与全量微调的对比

维度全量微调LoRA
可训练参数量100%(数十亿)约 0.1-1%(数百万)
显存需求极高大幅降低
训练速度
存储(checkpoint)完整模型大小只存 LoRA 权重(几十 MB)
灾难性遗忘风险较高较低(原权重冻结)

A3:最多调用次数及限制原因

最多调用 4 次(最多 3 个功能性工具 + 1 个 finish)。

限制原因

  1. 效率:SME 咨询场景需要快速响应,无限循环会拖慢速度
  2. 成本控制:每次工具调用都消耗 API 费用(搜索、读取)
  3. 防止幻觉循环:限制步数迫使模型学会在有限信息内整合答案,而不是无休止搜索
  4. 训练数据一致性:固定最大步数使训练数据格式统一,易于学习

A4:<think><tool_call> 的含义

  • <think>...</think>:模型的内部推理过程,用于分析当前状态、决定下一步行动。不直接对用户可见,是"思维链"(Chain of Thought)的载体。
  • <tool_call>...</tool_call>:包裹工具调用指令,内容是 JSON 格式的工具名和参数,由系统解析并执行。

缺少 <think> 标签:会导致格式验证失败(quick_eval 评分为 0),因为系统设计强制要求先思考再行动。训练数据 build_format_boost.py 正是用于过滤这类缺少 <think> 的低质量样本。


A5:4 行业 × 6 问题类型示例

类型financecateringstartupsmart_transport
policy“小微企业贷款利率上限是多少?”“餐饮店办理食品经营许可证需要哪些条件?”“高新技术企业认定有哪些优惠政策?”“网约车平台需要申请哪些资质?”
market“2024年消费金融市场规模?”“奶茶行业年增长率如何?”“AI 创业赛道融资情况如何?”“智慧停车市场空间有多大?”
competitor“招商银行与建设银行小微贷款对比”“喜茶与奈雪的茶商业模式差异”“字节跳动与腾讯在 AI 投资上的区别”“滴滴与高德打车的竞争优势”
calculation“贷款 50 万、利率 4.5%、3年期,月供多少?”“开一家 100㎡奶茶店,预计回本周期?”“天使轮稀释 20%,估值如何计算?”“日均 500 单货运,月营收预估”
risk“小微贷款逾期有什么后果?”“食品安全事故的法律风险”“创业融资协议中的反稀释条款风险”“网约车驾驶员事故责任归属”
expansion“小贷公司如何拓展下沉市场?”“餐饮品牌如何进行城市扩张?”“SaaS 产品如何从 ToB 扩展到 ToC?”“城市物流如何拓展同城配送”

项目结构题

A6:tool_executor.py vs tool_definitions.py 的分工

  • tool_definitions.py:只包含工具的 JSON Schema 定义(工具名、参数名、参数类型、描述),用于告诉模型"有哪些工具、每个工具的参数是什么",即放入 system prompt 的工具文档。
  • tool_executor.py:负责真实调用工具——接收解析好的工具名和参数,调用博查搜索 API、Jina Reader API,或执行数学表达式,返回结果字符串。

为什么分开? 遵循单一职责原则:Schema 定义可以被 LLM Prompt 构建和数据合成复用,执行逻辑只在推理时使用。如果需要更换搜索 API,只改 tool_executor.py 即可,不影响 Schema 定义。


A7:quick_eval.py vs full_eval.py 的区别

维度quick_eval.pyfull_eval.py
评测内容只检查格式(<think> + <tool_call> 是否正确)格式 + 工具选择准确率 + 答案质量
速度快(不执行工具,不调用 judge LLM)慢(需要执行真实工具调用和 LLM 打分)
API 消耗高(搜索 API + judge LLM)
使用场景训练过程中快速验证模型是否"学会格式"最终评测,需要全面了解模型能力时

建议:每次训练完先跑 quick_eval,确认格式无误后再跑 full_eval,节省资源。


A8:build_format_boost.py 的作用

该脚本从训练数据中筛选出格式最严格规范的样本(必须同时包含正确的 <think> 标签和合法的 JSON <tool_call>),生成一个格式增强子集。

使用场景:当 quick_eval 显示格式得分很低时(如基础模型的 4/20),可以用这个格式增强数据集单独训练一轮,让模型先"学会格式",再用完整数据集训练工具调用和推理能力。相当于先教格式规范,再教内容。


代码理解题

A9:Loss Masking 代码解释

1
2
3
4
if msg["role"] == "assistant":
    labels.extend(tokens)        # 这些 token 参与 loss 计算
else:
    labels.extend([-100] * len(tokens))  # 这些 token 被忽略

完整解释

  • 遍历对话中每条消息
  • 如果是 assistant 说的话(思考过程 + 工具调用),将其 token id 加入 labels,训练时模型需要学会生成这些内容
  • 如果是其他角色(system、user、tool_response),用 -100 填充 labels,PyTorch 不对这些位置计算交叉熵损失
  • 效果:模型只学习"在什么情境下应该说什么",而不是死记硬背系统提示词或用户问题

A10:工具调用格式判断

1
2
我需要先搜索相关信息。
<tool_call>{"name": "search", "arguments": {"query": "2024年餐饮行业政策"}}</tool_call>

判断:不符合规范

原因

  1. 缺少 <think>...</think> 标签——推理过程"我需要先搜索相关信息"应该放在 <think> 标签内
  2. 正确格式应为:
1
2
3
4
<think>
我需要先搜索2024年餐饮行业政策的相关信息。
</think>
<tool_call>{"name": "search", "arguments": {"query": "2024年餐饮行业政策"}}</tool_call>

分析与优化题

A11:格式提升比工具调用提升更容易的原因

本质差异:格式学习是模式匹配任务,工具调用是推理决策任务

  • 格式(4→20):模型只需学会"每次回复都要先输出 <think>...</think>,再输出 <tool_call>...</tool_call>"——这是纯粹的序列模式,1140 条样本已经足够强化这个规律。
  • 工具调用(0→2):模型需要理解"什么时候用哪个工具"、“何时停止搜索直接回答”——这需要深层语义理解和多步推理能力,1140 条样本对于 0.6B-1.7B 的小模型来说还不够。

结论:小模型学习浅层格式比深层推理容易,这也是为什么先用 quick_eval 验证格式的原因——格式是基础,推理是上层建筑。


A12:排查 calculator 工具不被调用的问题

按优先级排查:

  1. 数据分布:检查训练数据中 calculation 类型问题占比是否太低(用 validate_data_v2.py 查看统计),占比过低会导致模型很少见到 calculator 的调用示例。

    • 解决:用 expand_seeds_with_llm.py 专门扩充 calculation 类型的种子问题
  2. 问题类型:检查测试问题是否真的需要计算(如果问题是"政策是什么",模型正确选择不调用 calculator)

  3. 工具定义:检查 tool_definitions.pycalculator 的描述是否清晰,参数 expression 的格式说明是否明确

  4. 格式问题:检查训练数据中 calculator 调用的格式是否一致(expression 是否用标准数学表达式)

  5. 模型容量:0.6B 模型可能不够大,升级到 1.7B 或 4B 尝试


A13:数据分布不均的问题与解决方案

问题

  • 模型会过度偏向金融行业的回答风格,在其他行业表现差
  • 对餐饮/创业/智慧交通的专业术语和场景理解不足
  • 评测时可能看起来还好(因为 finance 问题多),但实际应用中遇到非金融问题会失败

解决方案

  1. 过采样:复制少数类样本(餐饮/创业/交通各随机复制到与金融同等数量)
  2. 欠采样:从金融数据中随机抽样,使各类均衡
  3. 数据增强:用 expand_seeds_with_llm.py 专门为餐饮/创业/交通生成更多种子问题变体
  4. 加权损失:在 data_loader_v2.py 中为少数类样本设置更高的 loss weight

最佳实践:目标是 4 个行业各 25%,6 种问题类型各约 16-17%,做到双维度均衡。


A14:DPO 及其解决的问题

DPO(Direct Preference Optimization):一种基于人类(或 AI)偏好的对齐方法。不需要独立的奖励模型,直接用"选择的答案 vs 拒绝的答案"的对比数据来优化模型,使模型更倾向于生成被偏好的回答。

数据格式

1
2
3
4
5
{
  "prompt": "问题",
  "chosen": "高质量回答(有准确引用、逻辑清晰)",
  "rejected": "低质量回答(引用错误、逻辑混乱)"
}

在本项目中解决的问题

SFT(监督微调)只能让模型学习"如何模仿训练数据中的答案",但无法区分答案好坏。如果训练数据本身有噪声,模型会同样学习低质量答案。

DPO 可以解决:

  1. 答案准确性:训练模型偏好"引用来源正确的答案"而非"捏造来源的答案"
  2. 回答完整性:偏好"涵盖多角度分析的答案"而非"片面的答案"
  3. 格式一致性:在 SFT 已建立格式基础上,进一步强化高质量格式

在本项目的应用:可以用 build_before_after_judged_set.py 生成的"模型A错误、模型B正确"数据作为 DPO 的 rejected/chosen 对,进一步提升答案质量(从 2/10 向更高分数逼近)。