[控场AI]
· 8 分钟阅读· 4,083 字

用1B小模型打造黄金时刻散步规划器:让AI只负责语言,代码负责计算

用1B小模型打造黄金时刻散步规划器:让AI只负责语言,代码负责计算

用1B本地模型做语言解析、确定性代码做路径计算,输出可打印散步路线卡,让屏幕退出户外体验。

这个散步规划器的核心工程思路是严格划分职责边界:本地1B-3B小模型只负责解析用户自然语言请求和撰写路线卡文案,所有数值计算(日落时间、路网下载、环线评分)全部交给`astral`、`osmnx`、`networkx`等确定性工具完成。系统通过JSON Schema强制结构化输出防止格式错误,通过"双括号地名校验"机制在事后比对OSM真实地名以拦截幻觉。模型对比测试显示三款模型内存均低于0.5GB,qwen2.5:3b在配速理解和卡片精准度上表现最佳。最终交付物是一张大字号单页路线卡和一个GPX文件,产品哲学是"让屏幕输掉"——用最短的屏幕时间换取最快的出门速度。

一个运行在本地1B模型上的散步规划器,核心设计理念出人意料地克制:让屏幕成为整个体验中最短的一环。开发者的目标很明确——花几分钟敲键盘,最终得到一张可打印的单页路线卡和一个GPX文件,然后把手机揣进口袋出门,赶在日落前走进被低角度阳光穿透的树林。

黄金时刻散步规划器

这个项目最值得关注的地方,不在于它用了多强的模型,而在于它如何用一个只有1B参数的小模型,稳定产出不会"胡编乱造"的结果。答案是一条清晰的职责边界:模型只做语言,确定性代码做所有数值计算。

要解决的真实痛点

大多数"我该去哪散步"的工具都要求你盯着屏幕。你打开地图应用、拖来拖去、查看日照、挑一条环线——等你终于出门,光线早已移动。开发者想要的恰恰相反:键盘前几分钟的操作,换来一张大字号、带小地图的单页路线卡,外加一个可导入 Organic Maps 或 OsmAnd 的 GPX 文件。

作者在实测中给出了具体场景:17:27 打印出单页卡片出门,日落在 18:07,路线把他引向附近的绿地,低角度阳光恰好在卡片预言的位置穿过树木。这种"离屏"的产品哲学,是整个项目的出发点。

让系统成立的铁律:模型永远不负责路径规划

这是整篇文章最核心的工程洞见。一个1B到3B的模型根本无法在真实街道网络中规划环线——它会凭空发明一条路、漏掉一个死胡同,或者交给你一条横穿河流的路线。因此作者做了明确切分:

  • 模型负责语言。 它把你的请求("天黑前45分钟,要有树、要安静")解析成结构化参数,并负责撰写最终卡片。
  • 确定性代码负责所有数值。 astral 计算日落与黄金时刻窗口,osmnx 下载步行路网与绿地数据,networkx 构建并对环线打分。

整个流程是一个小型 LangGraph 管线:intake → sun → weather → map_fetch → route_builder → critic → card_writer → render。其中 critic 节点可以把路线退回重试,如果达不到目标长度就适当放宽约束。这种设计把LLM的不确定性关进了一个很小的笼子里。

这里提到的几个工具值得简要说明。osmnx 是一个 Python 库,专门用于从 OpenStreetMap(OSM)下载和分析街道网络数据,它可以把真实城市的路网转化为可计算的图结构。networkx 则是 Python 生态中最主流的图计算库,负责在路网图上执行最短路径、环线搜索等算法。astral 专门处理天文计算,输入地理坐标和日期就能精确返回日出、日落、黄金时刻(golden hour)的时间——黄金时刻通常指日落前后约一小时,此时太阳角度极低,光线呈橙红色且方向性强,是摄影和户外散步的理想时段。LangGraph 是 LangChain 生态提供的一个有向图工作流框架,允许开发者把多个 LLM 调用和工具调用串联成可带分支、可回退的管线,critic 节点能把路线退回重试正是利用了这种有状态的循环能力。

用JSON Schema读取用户请求

intake 节点通过本地 Ollama 模型请求结构化输出,确保即使是小模型也能返回合法JSON:

resp = llm.chat_structured(
    model=state["model_name"],
    system="Extract walk parameters. Return JSON only.",
    user=state["user_input"],
    schema=IntakeParams.model_json_schema(),
    temperature=0.0,
    keep_alive="10m",   # 保持模型热态直到卡片写完
)
intake = IntakeParams.model_validate_json(resp)

一个关键的健壮性设计:如果模型无法访问或返回垃圾数据,节点会回退到默认值并记录一条警告。应用永远能产出一张卡片——这是面向最终体验而非技术炫技的典型思路。

JSON Schema 是一种描述 JSON 数据结构的规范,通过定义字段名称、类型和约束来限定合法的输出格式。在 LLM 调用中,将 Schema 附加到提示词并设置 temperature=0.0(即完全确定性输出),可以显著降低模型返回格式错误或字段缺失的概率。Ollama 在本地运行开源模型时支持"结构化输出"模式(structured output),底层通过语法约束(grammar-constrained decoding)强制模型的 token 采样始终符合指定 Schema,而非依赖模型自觉遵守指令——这是小模型能在 intake 环节稳定返回合法 JSON 的技术基础,而非单纯靠提示词工程。keep_alive="10m" 则告诉 Ollama 在本次请求结束后继续将模型权重保留在内存中十分钟,避免后续 card_writer 节点调用时重新加载模型带来的延迟。

只用事实写卡片,并逐一核验地名

card_writer 的提示词被刻意收紧:模型只能使用已验证的事实,而且每个地名都必须用 [[双括号]] 包裹,以便事后核查。

Use ONLY these facts. Do not invent places, landmarks, or plants.
Wrap every place name in [[double brackets]].
Start: ... | Distance: 3.4 km (~45 min) | Sunset: 2026-10-11 18:08
Golden light comes from the 271° . Weather: 29 C, 20% rain
Green spaces on the route: Allah Rakha Park, Bagh-e-Lyari

随后一段校验代码把所有 [[name]] 抽出来,与 OSM 的真实地名列表比对:

unknown = unknown_names(card_text, state["place_names"])
if unknown:
    warnings.append(f"unknown place names: {', '.join(unknown)}")

用作者的话说,这段校验正是"模型写了一张漂亮卡片"和"模型写了一张漂亮卡片、却把你送往一个根本不存在的公园"之间的分水岭。这其实是一套对抗幻觉的轻量级护栏,而非依赖模型本身的可靠性。

这套"双括号校验"机制在 LLM 应用工程中属于一种轻量级的"可审计输出"模式(auditable output)。核心思路是:与其在生成阶段阻止幻觉(极难),不如在生成后对高风险字段做事实核对。地名是典型的高风险字段——模型容易把相似的真实地名混淆,或基于训练数据中的模式凭空补全一个听起来合理的名字。通过要求模型用特殊符号标记所有地名,校验逻辑得以用正则表达式自动提取并与 OSM 数据做精确比对,整个过程不需要再调用一次 LLM 做二次判断,成本极低。这种"标记-提取-比对"的范式可以推广到任何需要验证模型输出中特定实体的场景,例如药品名称、法律条款编号或产品型号。

踩过的坑

真实工程记录往往比成功案例更有价值。作者坦诚列出了几个问题:

  • 1B模型确实发明了地名。 在某一次运行中,llama3.2:1b 写出了一个 OSM 数据里不存在的名字。双括号校验捕捉到了它,记录警告而非直接交付——并非每次都发生,诚实的数字见下方表格。
  • OSMnx 保存投影图时会丢失经纬度。 GPX 导出一度全是空坐标,直到加载器把节点的 x/y 属性反投影回 WGS84 才解决。
  • weasyprint 无法在 Windows 上安装。 作者改用 Edge 无头模式打印 HTML,把 PDF 当作尽力而为的输出。

模型对比:小模型到底够不够用

同样的请求、同样的起点、同样的地图,只换模型。由于路由器不含LLM,路线质量完全一致——真正有看点的是幻觉次数和卡片长度。

模型配速理解字数幻觉地名长度误差峰值内存耗时
qwen2.5:3b正常3600.3%259 MB106 s
qwen2.5:1.5b偏快6904.4%260 MB16 s
llama3.2:1b偏慢5609.5%274 MB76 s
模板(无模型)正常5500.3%273 MB65 s

三个模型都把模型内存控制在 0.5 GB 以下。3B 模型正确理解了配速,产出最短、最贴合目标的卡片;更小的模型会误读配速,从而影响目标长度和长度误差。这组数据说明:对于语言改写这类任务,小模型配合严格的事实约束完全可用,关键在于不要把它放在它不擅长的位置上。

整个项目的要义可以用作者的一句话概括:屏幕应该输掉这场比赛。 技术的终点不是更多的交互,而是让你更快地走进那片恰到好处的夕阳里。

#1B小模型#本地LLM#Ollama结构化输出#LangGraph#AI幻觉#散步规划器#边缘AI应用
分享:

相关推荐