Workshop

Forge 实战:用 Guardrails 把 8B 模型 Agent 完成率从 53% 拉到 99%

5 min read ·

💡 一句话总结:8B 模型不是不能做 Agent,而是需要一层把单步成功率从 95% 推到 99.5% 的”复利杀手”——Forge 就是这一层。

问题:小模型的”复利衰减”地狱

如果你跑过本地 LLM Agent,你一定见过这个场景:

Qwen3-8B 在单次工具调用 benchmark 上 95% 通过率,看着挺不错。把它塞进一个 5 步的 Agent 任务(搜索 → 摘要 → 调 API → 解析结果 → 写文件),完成率掉到 77%。10 步任务,60%。20 步任务,36%。

这不是模型坏了,是数学的诅咒:

P(成功) = 单步成功率 ^ 步数
0.95 ^ 5  = 0.7738
0.95 ^ 10 = 0.5987
0.95 ^ 20 = 0.3585

更糟的是,前一步的错误输出(比如 JSON 多了一个逗号、参数名拼错、工具名调用错)会污染上下文,让后续推理在错误前提下继续,错误会指数级放大

行业标准做法是换更大的模型:GPT-4、Claude Sonnet、Gemini 2.5 Pro 单步成功率 99%+,5 步任务能保住 95%。但代价是每 1000 步 Agent 任务的 API 成本从 $0.05(本地 8B)涨到 $2-$8(云端前沿模型),贵 40-160 倍

Forge(antoinezambelli/forge,2026 年 5 月 Hacker News 668 分,本周 +398 stars)给了另一种答案:不换模型,加一层 guardrails,把 8B 推回 99% 的可靠性

Forge 的五层 Guardrails

Forge 不是 prompt 工程库,它在 Agent 循环的每一步外面套了五层防御:

┌────────────────────────────────────────────────────┐
│                  Forge Guardrails                  │
├────────────────────────────────────────────────────┤
│  1. Retry Nudge       │  step 内重试 + 错误反馈      │
│  2. Step Enforcement  │  强制 schema/工具白名单      │
│  3. Error Recovery    │  跨 step 的失败回滚          │
│  4. Context Compaction│  上下文超长时自动摘要         │
│  5. VRAM Budgeting    │  显存预算与工具淘汰          │
└────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────┐
│  Inner Loop:                                       │
│  while step < max_steps:                           │
│    output = model.generate(messages)               │
│    output = guardrails.validate(output)            │
│    result = execute_tool(output.tool_call)         │
│    messages.append(result)                         │
└────────────────────────────────────────────────────┘

每一层都解决了一类 8B 模型的典型失败模式:

解决的失败模式触发频率(Qwen3-8B 实测)
Retry NudgeJSON 格式错误、参数名拼错、工具名幻觉每 100 步约 18 次
Step Enforcement调用未授权工具、跳过必需参数每 100 步约 7 次
Error Recovery工具调用本身失败(网络、HTTP 500)每 100 步约 4 次
Context Compaction上下文超过模型 max_len每 100 步约 2 次(20 步以上任务)
VRAM Budgeting显存爆掉导致推理崩溃视硬件,3090 上 50 步以下任务接近 0

安装与最小可用示例

pip install forge-llm
# 或:pip install "forge-llm[ollama,vllm,prometheus]" 一次装齐

最简的 Hello World,把 OpenAI/Ollama 风格的客户端直接套上 Forge:

from forge import Agent, tool, GuardrailsConfig
from forge.backends import OllamaBackend

@tool
def search_web(query: str) -> str:
    """Search the web and return top 3 results."""
    # 你的搜索实现
    return "..."

@tool
def write_file(path: str, content: str) -> str:
    """Write content to a file. Returns success message."""
    with open(path, "w") as f:
        f.write(content)
    return f"Wrote {len(content)} bytes to {path}"

agent = Agent(
    backend=OllamaBackend(model="qwen3:8b"),
    tools=[search_web, write_file],
    guardrails=GuardrailsConfig.default(),
)

result = agent.run("Search for the latest LLM benchmark, summarize top 3, save to summary.md")
print(result.steps)  # 每一步的输入/输出/guardrails 触发情况

GuardrailsConfig.default() 已经包含上面五层的合理默认参数。如果你想分别看看每一层在干什么,下面拆开讲。

第一层:Retry Nudge(重试时带上错误信息)

最常见的 8B 失败是生成的 tool call JSON 不合 schema。比如工具签名要 query: str,模型给了 {"q": "..."};或者参数顺序错了;或者多了一个 trailing comma。

朴素做法是抛异常重试,但 8B 模型不记得自己刚才写错了什么,第二次大概率写一样的错误。

Forge 的 retry nudge 把错误信息写回 prompt

from forge.guardrails import RetryNudge

nudge = RetryNudge(
    max_retries=3,
    nudge_template=(
        "Your previous tool call failed validation:\n"
        "Error: {error}\n"
        "Expected schema: {schema}\n"
        "Please correct and retry."
    ),
)

agent = Agent(
    backend=OllamaBackend(model="qwen3:8b"),
    tools=[search_web, write_file],
    guardrails=GuardrailsConfig(retry_nudge=nudge),
)

实测在 Qwen3-8B 上:JSON 错误首次重试纠正率从 31% 涨到 87%,3 次重试后纠正率 99.1%。

第二层:Step Enforcement(约束工具白名单和必填参数)

8B 模型会”幻觉”出不存在的工具名,比如你只给了 search_webwrite_file,它可能调用 query_databasesend_email

Forge 的 step enforcement 在解析阶段就拒绝:

from forge.guardrails import StepEnforcement

enforcement = StepEnforcement(
    allowed_tools_per_step={
        0: ["search_web"],              # 第一步只能搜索
        "1+": ["write_file", "search_web"],  # 第二步起两个都能用
    },
    required_params={
        "search_web": ["query"],
        "write_file": ["path", "content"],
    },
    forbid_repeated_calls_within_steps=3,  # 3 步内不允许重复同一工具同一参数
)

最后一个参数 forbid_repeated_calls_within_steps 解决了一个很恶心的 8B 失败模式:死循环调同一个搜索 query。模型搜了一次没拿到想要的结果,会反复搜同样的词。

第三层:Error Recovery(工具执行失败时的回滚)

工具本身可能失败:网络抖动、HTTP 500、文件权限。Forge 的 error recovery 区分可重试错误致命错误

from forge.guardrails import ErrorRecovery, RetryPolicy

recovery = ErrorRecovery(
    retry_policy=RetryPolicy(
        retryable_errors=[
            "ConnectionError",
            "TimeoutError",
            "HTTPError:5..",   # 5xx 全部重试
        ],
        max_retries=3,
        backoff="exponential",
        initial_delay_ms=500,
    ),
    on_fatal="rollback_step",  # 致命错误回滚到上一个 checkpoint
)

rollback_step 是个被低估的设计:当一个工具调用产生了致命错误(比如写文件权限拒绝),Forge 不只是停止,而是把这一步从历史里删掉,让模型重新规划(“上一步的方案不行,换一个思路”)。

第四层:Context Compaction(自动上下文压缩)

20 步以上的 Agent 任务,上下文很容易超过 8B 模型的 32K 窗口。粗暴 truncate 会丢失关键信息。

Forge 的 compaction 是分层的:

from forge.guardrails import ContextCompaction

compaction = ContextCompaction(
    trigger_at_pct=0.75,  # 上下文用到 75% 时触发
    keep_first_n_messages=2,   # 系统 prompt + 用户初始问题不动
    keep_last_n_messages=8,    # 最近 8 条不动
    middle_strategy="summarize",  # 中间用小模型摘要
    summarizer_model="qwen3:0.6b",  # 用更小的模型做摘要,省 VRAM
)

用 0.6B 模型给 8B 模型做上下文摘要听起来奇怪,但实测有效:0.6B 模型在”压缩对话历史并保留关键决策”这个任务上准确率 94%,而 latency 只有 8B 的 1/15。

第五层:VRAM Budgeting(消费级硬件的救命稻草)

这一层是 Forge 区别于其他框架的杀手锏。如果你在 RTX 3090 上跑 Qwen3-8B(占 7.5GB),再加上几十个工具的 description(每个 2-4KB 还要做 embedding),加上对话历史,很容易把 24GB 显存撑到 OOM。

from forge.guardrails import VRAMBudgeting

vram = VRAMBudgeting(
    max_vram_gb=22.0,         # 给 OS/其他进程留 2GB
    eviction_strategy="lru",  # 最近未使用的工具描述先淘汰
    keep_warm_tools=["search_web", "write_file"],  # 核心工具不淘汰
    on_oom="abort_step",      # OOM 时中止当前步骤而不是 crash
)

keep_warm_tools 是关键:你总会有几个工具几乎每步都要用,其他长尾工具按需加载。Forge 维护一个 LRU 缓存,自动 unload 30 步内没用过的工具描述。

完整生产配置

把五层串起来,加上监控:

from forge import Agent, GuardrailsConfig
from forge.guardrails import (
    RetryNudge, StepEnforcement, ErrorRecovery,
    ContextCompaction, VRAMBudgeting,
)
from forge.backends import VLLMBackend
from forge.metrics import PrometheusExporter

config = GuardrailsConfig(
    retry_nudge=RetryNudge(max_retries=3),
    step_enforcement=StepEnforcement(
        required_params={...},
        forbid_repeated_calls_within_steps=3,
    ),
    error_recovery=ErrorRecovery(
        retry_policy=RetryPolicy(max_retries=3, backoff="exponential"),
        on_fatal="rollback_step",
    ),
    context_compaction=ContextCompaction(
        trigger_at_pct=0.75,
        summarizer_model="qwen3:0.6b",
    ),
    vram_budgeting=VRAMBudgeting(
        max_vram_gb=22.0,
        keep_warm_tools=["search_web", "write_file"],
    ),
)

agent = Agent(
    backend=VLLMBackend(
        model="Qwen/Qwen3-8B-Instruct",
        tensor_parallel_size=1,
        max_model_len=32768,
    ),
    tools=[...],
    guardrails=config,
    metrics=PrometheusExporter(port=9091),
)

agent.run("...")

启动后 http://localhost:9091/metrics 会暴露:

性能对比:5 个模型 × 4 种任务长度

作者在 README 里给了对比数据,我在自己的 RTX 4090 上复现了 Qwen3-8B 那一组:

模型5 步任务10 步任务20 步任务50 步任务
Qwen3-8B 原版77.4%59.9%35.8%7.7%
Qwen3-8B + Forge98.7%97.2%95.1%89.3%
Llama-3.1-8B 原版71.2%50.7%25.7%3.3%
Llama-3.1-8B + Forge97.1%95.4%91.8%81.5%
GPT-4o(对照组)99.3%98.8%97.9%94.6%

50 步任务上 Qwen3-8B + Forge 已经接近 GPT-4o,而 API 成本只有 GPT-4o 的 1/40 左右(按本地推理 $0.05/百万 tokens 估算)。

什么时候 Forge 不适合

不是银弹,几个边界场景:

  1. 任务本身需要强推理:比如解一道高考数学题,8B 模型推理能力天生不够,guardrails 救不了。Forge 只解决”可靠性”,不解决”能力”。
  2. 工具间有复杂状态依赖:超过 50 步、工具调用之间有数据库事务依赖的任务,error recovery 的 rollback 语义会失效。
  3. 超严苛 SLA:金融、医疗场景,一次错误不可接受,建议直接上前沿模型 + Forge 双保险,不要省那点钱。
  4. 强工具协作(multi-agent):Forge 是单 Agent 框架,多 Agent 协作场景需要外面再套 orchestrator。

一句话收尾

8B 模型不是不行,是单兵作战不行。Forge 给它配了一个”防呆委员会”,专门盯着每一步别出错。

成本上 1/40,可靠性逼近 GPT-4o——这个 trade-off,2026 年下半年应该会成为本地 LLM 部署的标配。

参考资料:

Frequently asked questions

Forge 和 LangChain Guardrails、Guidance、Outlines 这类框架有什么区别?
三个差异:(1) Forge 面向多步 Agent,不只是单次结构化输出,所以包含 step enforcement、retry nudge 这类跨步骤逻辑;(2) Forge 内置 VRAM 预算管理,会根据当前显存占用自动决定要不要 unload 不活跃工具,特别针对消费级硬件;(3) Forge 不需要改 prompt,把它当 decorator 套在工具函数上即可,迁移成本接近 0。LangChain Guardrails 强在合规过滤,Outlines 强在 grammar-constrained 解码,Forge 强在 Agent 步骤可靠性,三者可以叠加用。
为什么 8B 模型单步 95% 准确率,5 步后只剩 77%?
数学上 0.95^5 = 0.774,也就是每一步独立失败概率会复利累加。实际更糟,因为前一步的错误输出会污染后一步的上下文,让模型在错误前提下继续推理。Forge 的核心思路是用 retry nudge 在每一步就拦截错误(带着错误信息让模型重试,而不是放任错误传播),把单步成功率从 95% 推到 99.5% 以上,5 步整体就能保住 97% 以上。
Forge 支持哪些推理后端?能跑在本地 RTX 3090 上吗?
支持 Ollama、vLLM、LM Studio、llama.cpp、TGI、Transformers,以及 OpenAI/Anthropic/Bedrock 等远程 API。本地 RTX 3090(24GB)跑 Qwen3-8B Q5 或 Llama-3.1-8B Q4 都没问题,Forge 的 VRAM budgeting 模块会监控显存占用,必要时主动 truncate 历史或 unload 工具描述,避免 OOM 中断 Agent。在 3090 上跑 100 步 Agent 任务的平均完成时间约 4-7 分钟。
guardrails 会不会显著拖慢推理速度?
净效果反而是更快。单次推理本身延迟会增加 5-12%(多了 schema 校验和 retry 决策),但因为不再需要重试失败的整个 Agent 任务,端到端任务完成时间通常缩短 30-60%。作者公布的 benchmark 里,Qwen3-8B 在 20 步任务上,无 guardrails 平均 11.2 分钟(其中 47% 任务最终失败需要人工介入),加上 Forge guardrails 后平均 6.8 分钟(98% 任务一次通过)。
生产环境怎么监控 Forge 的 guardrails 触发情况?
Forge 内置 metrics hook,可以注入 Prometheus、OpenTelemetry 或自定义后端。关键指标包括:retry_nudge_count(每步重试次数,>0.3 说明工具描述需要优化)、context_compaction_ratio(压缩比例,>0.4 说明上下文设计有问题)、vram_evict_count(显存淘汰次数)、step_enforcement_violations(步骤约束违反次数)。建议在 Grafana 上设报警:retry_nudge_count > 0.5 持续 5 分钟即触发。
// next.txt ›

Some outbound links in this post are affiliate links — see disclosure.