返回 AICAP-180
B18 · Day 171OSS 收口 + 英文 + 全局 SOTA 复核

smolagents v1.26.0 入口扫描

B17(Day 161-170)把 outcome 指标仪表盘 + 配对 A/B 收口——我们手里已经有了「用独立金标 + 真实成本/时延 + 配对 A/B」打出来的真值(V4-Pro 89.7% vs V4-Flash 79.3%、Δ+10.3pp、cost $0.0139/run)。

阶段: B18 · OSS 收口 + 英文 + 全局 SOTA 复核(Day 171-180) 标签: #smolagents #code-agent #tool-calling #mcp

今日导引(由浅入深)

B17(Day 161-170)把 outcome 指标仪表盘 + 配对 A/B 收口——我们手里已经有了「用独立金标 + 真实成本/时延 + 配对 A/B」打出来的真值(V4-Pro 89.7% vs V4-Flash 79.3%、Δ+10.3pp、cost $0.0139/run)。

B18 是整条 B1→B18 能力曲线的最后一段:把内功对外——读主流 OSS agent 框架的真源码、做全局 SOTA 复核、写英文 writeup、走真实 OSS 贡献流程。

今天是 B18 开篇,先扫 Hugging Face smolagents v1.26.0 的入口,搞清楚它的两类 agent 范式(CodeAgent vs ToolCallingAgent),并和本仓刻意做成「零模型回合、纯 TS、可重放」的 src/agent/mcp/toolRegistry.ts 做对照。紧接昨天「内部 eval 收口」,通向明天的「外部评测框架(DeepEval/Inspect AI)」。

最小可判定产出:一份对照 transcript.md(smolagents 真模型回合的 tool-call 轮数 vs 本仓 mock 的零回合执行),其中本仓侧对照物已就绪、smolagents 侧标「待跑(需 key)」。

一句话锚点:今天不是「学会用 smolagents」,而是「读懂主流 agent 框架的工具编排范式,并能说清本仓为什么选确定性 mock 换 CI 可重放」——这是 B18「内功对外」的第一块砖。

1. 机理精读

两类 agent 范式的定义。 smolagents(Hugging Face 维护的轻量 agent 库,本日扫的版本号为 v1.26.0)把 agent 主循环分成两条路线:

  • CodeAgent:LLM 不输出结构化的工具调用 JSON,而是直接生成一段 Python 代码作为 action,这段代码在受限沙箱里执行,代码里可以调用注册进来的 tool(如 web_search(...))。
  • ToolCallingAgent:走传统的结构化 JSON tool-call 协议,每一步模型产出一个 {name, arguments} 形态的调用,更贴近 OpenAI / Anthropic 原生 function-calling 的报文形状。

为什么 CodeAgent 这样设计:用代码当 action 减少往返轮数。 ToolCallingAgent 每调一个工具就是一个「模型生成 → 执行 → 把结果喂回模型」的回合;要串三个工具就是三个回合。

CodeAgent 让模型把多个 tool 调用组合进一段代码——results = web_search(q); top = results[0]; detail = visit(top.url)——一次生成就能编排多步,理论上把 N 个回合压成 1 个。这正是 smolagents 文档主推 CodeAgent 的核心论据:代码是比 JSON 更自然的「组合多步动作」的载体。依据:Hugging Face smolagents docs (2026-01)。

关键权衡:表达力 vs 安全/可控。 CodeAgent 的代码即 action 带来表达力,代价是必须有沙箱——LLM 生成的任意 Python 要在隔离环境跑(smolagents 提供本地受限执行 + E2B/Docker 远程沙箱选项),否则就是远程代码执行风险。ToolCallingAgent 没有「执行任意代码」这层风险面,但牺牲了组合性、回合更多。这是一对正面权衡:谁拿走表达力,谁就接过沙箱的安全债

把这对权衡再拆细,有三条次级取舍值得记住:

  • 可调试性:CodeAgent 的中间状态是 Python 变量,出错时 traceback 直接指向哪一步炸了;ToolCallingAgent 的中间状态散在多个回合的 JSON 里,串联调试更绕。
  • token 成本:ToolCallingAgent 每回合都要把「历史 + 上一步结果」重新塞进 context,多回合 ⇒ 重复前缀膨胀;CodeAgent 单段代码省掉了这部分往返重发,但代码本身可能更长。
  • 可观测埋点:ToolCallingAgent 的每个 {name, arguments} 是天然的 span 边界,OTel GenAI 埋点对得很齐;CodeAgent 一段代码里串多个 tool,要在沙箱里逐 call 打点才能拿到同等粒度。

与本仓 toolRegistry 的边界。 本仓 src/agent/mcp/toolRegistry.ts 走的是第三条路:它既不是 CodeAgent 也不是真的 ToolCallingAgent,而是把「工具暴露给 LLM 的契约层」(MCP 2026-07-28 stateless 语义的协议形状:tools/list + tools/call + JSON-Schema 校验)抽出来,做成进程内、确定性、纯 TS 的 mock——刻意避开真模型回合,让 CI 可重放。

换句话说:smolagents 是「真模型驱动的 agent 运行时」,本仓 toolRegistry 是「不依赖模型的协议骨架」。两者不是竞品,是同一条链上的不同切片——smolagents 演示「模型怎么编排工具」,toolRegistry 演示「工具契约层长什么样、怎么单测」。

这条边界很重要:明天起的 OSS 复核都建立在「我能读懂真框架,但本仓选择用确定性 mock 换 CI 可重放」这个自洽叙事上。

入口扫描要看的三个面(读 repo 时的 checklist)。 扫一个 agent 框架入口,不是只看 README 跑通 demo,而是带着三个问题读源码:

  • action 表示:模型的 action 是代码还是结构化 tool-call?(决定沙箱需求与回合数)
  • 工具契约:工具怎么声明(name/description/schema)、怎么发现、入参怎么校验?(这正是本仓 toolRegistry 抽出来的层)
  • 停机与错误:主循环何时停(达成目标 / 步数上限),工具抛错怎么回灌给模型?

smolagents 的 CodeAgent/ToolCallingAgent 在这三面给的答案,本仓 toolRegistry.ts 都有对应物(schema 校验 + JSON-RPC error 折叠),区别只在「跑不跑真模型」。

2. 推导 / 手算 / 代码走读

今天是代码对照日。已用 Read 打开 src/agent/mcp/toolRegistry.ts,走读其真实符号与零回合行为(这是 transcript.md 里「本仓侧」的对照物):

  1. McpToolRegistry.register(spec, handler)(line 151):把一个内部 TS 函数注册成 MCP 工具。它做三道防线——工具名必须匹配 /^[a-zA-Z][\w.-]*$/、重名直接抛错(避免静默覆盖)、inputSchema.type 必须是 'object'。注册是纯内存 Map,无网络。
  2. list()(line 169):对应 MCP tools/list 工具发现,返回按 name 稳定排序的 spec 列表,注释明确标「stateless:不依赖任何会话,结果可被客户端按 ttl 缓存」——这正是 MCP 2026 stateless core 的形状。
  3. call(name, args)(line 183):对应 tools/call。关键行为顺序——先 validate(t.spec.inputSchema, args) 按声明 schema 校验,校验失败抛 McpCallError(RPC.INVALID_PARAMS, ...);通过后才 t.handler(args);handler 自身抛错被包成 McpCallError(RPC.INTERNAL_ERROR, ...)整个调用没有任何模型回合——给定 args,输出由 handler 纯函数式决定,这就是「零回合执行」。
  4. handle(req)(line 199):JSON-RPC 2.0 信封版 dispatch,注释标「永不抛错:所有失败折成 response.error」,符合 JSON-RPC 语义。tools/list / tools/call / 未知 method 三分支齐全,未知 method 返回 RPC.METHOD_NOT_FOUND
  5. validate(schema, value, path)(line 112):教学用 JSON-Schema 子集校验器,覆盖 type / enum / minLength / minimum / maximum / array.items 递归 / object.required + properties 递归。type 不符则早返回不再深入(line 117 注释)。这是 smolagents tool 入参校验在本仓的对应物——只是本仓把它做成确定性可单测。

轮数对照(手算): 一个「搜索 → 取首条 → 取详情」的任务:

  • smolagents CodeAgent:理论 1 段代码即可串完三步 ≈ 1 回合(但实测含纠错重试,seed 预期 3-5 turns);
  • smolagents ToolCallingAgent:三步三回合 ≈ 3 回合
  • 本仓 toolRegistry.call:给定 args 直接 handler,0 模型回合(执行是纯函数)。

对照的洞察:本仓不是「更快的 agent」,而是「把 agent 协议层从模型不确定性里解耦出来,换 CI 可重放」——这是写进 transcript.md 的论点。

为什么本仓选「零回合协议骨架」而非真跑 agent(再推一层): CI 的第一性原理是可重放。真模型回合每次输出都可能不同(温度、版本漂移、限流),把它放进 CI 会让测试时绿时红、无法定位是代码退化还是模型抖动。

本仓把「工具契约层」从「模型推理层」切开——契约层(注册/发现/校验/调用)用纯 TS 做成确定性可单测,推理层(真模型回合)留给 scripts 下的接线脚本、需 key 时才跑。这条切法和 dsdb-lab 浏览器内确定性教学装置同理:把可确定的部分锁死进 CI,把不可确定的部分隔到 key-gated 边界外

3. 今日实战

按 seed 落地(指向真实路径与命令):

  1. git clone https://github.com/huggingface/smolagents,按官方 quickstart 起一个 CodeAgent,挂 DuckDuckGo 搜索 tool,模型用 model=LiteLLMModel("deepseek/deepseek-v4-flash")(key 已配,走 LiteLLM 适配 DeepSeek)。
  2. 跑几个多步任务,记录每个任务的 tool-call 轮数(CodeAgent 预期 3-5 turns)。
  3. 在本仓侧用 src/agent/mcp/toolRegistry.tsregister + call 起一组等价工具(确定性 handler),记录其零模型回合执行路径。
  4. 把两侧轮数与执行语义写进 transcript.md,committed。
  5. 本仓对照物的可信度由测试套件背书:toolRegistry.ts 在本仓 423 测试套件中绿。

4. 今日实测 / 产出

  • smolagents 真模型回合 → 待跑(需 key 跑 smolagents 真模型回合);将产出 transcript.md + 轮数(预期 3-5 turns,非已测真值)committed。
  • 本仓侧对照物已就绪toolRegistry.ts423 测试套件中绿
  • 不臆造 smolagents 实测轮数——seed 标「预期」即写「预期」,不写「实测得到」。

5. 常见误区 / 陷阱

  1. 把 CodeAgent 当「更智能」而非「不同权衡」:CodeAgent 省回合的代价是必须有沙箱,把它当无脑首选会忽略 RCE 风险面。
  2. 把本仓 toolRegistry 当 agent 运行时:它是协议契约层 mock,不跑模型;不要在 transcript 里声称它「执行了 agent 推理」。
  3. 把 mock 的零回合当「比 smolagents 快」:零回合是因为没跑模型,不是更快的 agent;混淆两者会让对照叙事失真。
  4. 版本号不复验:smolagents v1.26.0 是本日扫到的号,当周必须在 PyPI 复验(agent 库迭代快)。
  5. 拿 LiteLLM 模型 id 当真值数字:seed 的 3-5 turns 是预期区间,不是测出来的;混入 transcript 当实测会破坏诚信底线。
  6. 沙箱当摆设:跑 CodeAgent 不开沙箱(直接本地 exec LLM 生成的 Python)等于自挖 RCE 坑——本地试也应走受限执行或容器隔离。
  7. 把「省回合」当唯一指标:回合数只是一个维度,可调试性 / token 成本 / 埋点粒度同样影响生产选型,不能只看 turns。

6. 学习资源(每条带 YYYY-MM)

  • Hugging Face, smolagents documentation(CodeAgent vs ToolCallingAgent 范式)— 2026-01
  • Hugging Face, smolagents GitHub repo(v1.26.0,PyPI 版本号当周复验)— 2026
  • Anthropic, Model Context Protocol — stateless core / tools 语义(2026-07-28 最终规范,RC 2026-05-21 锁定)— 2026-05
  • MCPTox benchmark(工具投毒攻击成功率最高 72%)/ NIST CAISI AI Agent 标准(2026-02 启动)— 2026-02(本仓 toolRegistry.ts 头注引用)
  • LiteLLM, provider 适配文档(统一 OpenAI-compatible 接口接 DeepSeek,供 smolagents LiteLLMModel 用)— 2026
  • 本仓 src/agent/mcp/toolRegistry.ts(进程内 MCP stateless 协议形状 mock,零回合对照物)— 2026

SOTA检查 (2026-06 更新)

  • 当前主流:smolagents 仍是 Hugging Face 主推的轻量 agent 框架,CodeAgent 范式与 2026 context-engineering 主线一致,非过时。本仓 toolRegistry 复刻的 MCP stateless 协议形状对齐 2026-07-28 规范方向。
  • 是否仍 SOTA:是(轻量 agent 框架赛道)。但 v1.26.0 版本号当周需在 PyPI 复验——agent 库半衰期约 6 个月,版本漂移快。
  • 过时黑名单:避免引用已停更的 transformers-agents(旧 Agent API,已被 smolagents 取代);避免把 AutoGen/SK 当主线(维护模式)。
  • 安全前沿:MCPTox(2026)测得工具投毒攻击成功率最高 72%,NIST CAISI AI Agent 标准 2026-02 启动——真实 MCP server 必须零信任校验工具描述/参数,本仓 schema 校验只是该防线最小演示。
  • 下次复查点:2026-07-28 MCP 最终规范定稿日(server 构建须排其后);每周一 WebSearch 复刷 smolagents PyPI 版本号。

衔接

  • 昨天:Day 170 — Block 收口 + SOTA 检查(B17 用独立金标 + 真实成本/时延 + 配对 A/B 收口,留下 V4-Pro 89.7% / V4-Flash 79.3% / Δ+10.3pp not-sig@N=29 真值)
  • 今天:扫 smolagents v1.26.0 入口,理清 CodeAgent vs ToolCallingAgent 两范式,与本仓零回合 toolRegistry 做对照
  • 明天:Day 172 — DeepEval + Inspect AI 评测框架(从「框架的 agent 主循环」转到「框架的评测口径」,对照本仓 cohensKappa/agentEval)