脚下:隐秘场所的聊天室(以及我为什么不参加黑客马拉松)
这是由 n8n 和 Bright Data 支持的 AI Agents Challenge的参赛作品。
**已更新**
我刚刚发现我的n8n试用期正式结束了😢 所以我把聊天功能关掉了,这样它就不会再运行了。不过我对这个角色还有更大的计划,敬请期待。未来的我会陆续更新。🫶
另外,几天后我还写了一篇“前传”。如果你对“禁止黑客马拉松”这条规则感到好奇,想了解完整的故事,请点击这里。
🦄补充说明:事后我更新了内容——我的确计划了整整两周,精确到分钟——但我没料到数据会丢失,也没料到数据丢失时没有可靠的备份。另外,我还浪费了半天时间在 Figma 的装饰界面上。我匆忙粘贴的蜂鸣器声音听起来不像我,所以这是我能接受的版本(而且你们也可以读一读,图个乐子)。🪄
我建造的
Underfoot(我那固执的小聊天机器人)是一个聊天机器人,它能找到只有当地人才知道的、地图上找不到的地方,这些地方在 Yelp 或 TripAdvisor 上都找不到。你只需告诉它地点和搜索意图(音乐、咖啡、徒步旅行、蜘蛛农场……),它就会返回带有Stonewalker评分的独特搜索结果。每次查询还会将匿名留言添加到缓存中,因此随着用户使用,数据集也会不断增长。🎯
Underfoot——仅限本地人的寻宝猎人🎒
我没想着把这事儿硬塞进一个周末;我像制定飞行计划一样,把两周的时间都安排好了。最先出问题的,是我太信任的那部分:纸面上“准备就绪”的数据预加载,实际上却根本不存在。我精心制定的计划,原本的测试窗口被撕成了个大坑,之后就只剩下我、代理、缓存,以及无数句对自己野心勃勃的咒骂。🧭
耳语网络:项目背景📼
九十年代末/两千年代初的佐治亚州,手机只在紧急情况下使用,电池电量也像欠钱一样省着用。我和哥哥靠着口口相传,四处寻觅那些稀奇古怪的地方:后院举办的小型节日,密码藏在免费杂志的封底;还有那些奇奇怪怪的博物馆,以及要么假得滑稽可笑,要么逼真到让你在回家的路上都重新审视自己宇宙观的“鬼魂之旅”。太公开的话警察会来;太隐秘的话场地又会空无一人。我们喜欢这种微妙的平衡。
Underfoot能捕捉到那种能量。你给常驻的Stonewalker赋予一个你真正想要的意图(比如“现场音乐”、“奇特的博物馆”、“怪异的花园”、“蜘蛛农场”),再加上一个地点。它会先抓取那些不太显眼的地方,规范化混乱的 HTML,然后返回一个排名列表,告诉你:“这大概就是你喜欢的那种怪异——现在就去吧。” 🕵️♀️
但有个“陷阱”:有时候这些事件还没被发现——事情就是这样。而且,聊天机器人不可能乖乖地等着抓取数据,所以每对{intent, location}组合都会发出单独的消息,以此来构建该组合的缓存。下一个人的列表会比上一个更响亮、更疯狂一些。🔁
我做不了简单的事情(我也不再假装自己能做到)🧶
我承诺会提供“小型演示”,结果五分钟后,我得到了:一个修改了两次的 ADR 文件、一个 Leonardo 调色板、三个缓存,以及一个看起来像被人泼了咖啡的地铁线路图的“未来改进”页面。这不是范围蔓延,而是范围预先规划。我需要看到完整的产品才能交付一部分。
即兴编码大概只持续了两分钟。Copilot 帮我草拟了用户界面,我(其实没必要)在 Figma 里闲逛了一番,试用了 Stitch,然后冲到n8n上,因为托管聊天看起来速度很快,结果又想念起我的用户界面,把它拖了回来。就在这期间,我写出了我真正想要的智能体——它能像产品一样做出决策,而不是像科学展览会上的三折页那样。🧪
我为什么不参加黑客马拉松(以及我为什么这次还是参加了)⏱️
黑客马拉松想要的是快照;我构建的是生态系统。他们想要的是“周五午夜前完成”;而我想要的是给各个站点贴上标签,今天运行一条线路,下周运行其他线路。尽管如此,我还是参加了,因为这正是我几个月来一直想做的智能体。这很有趣——也让我明白,信任一个你无法控制的绿色复选框就像掷骰子一样。🟩
它看起来是这样的——用真实名词进行的冲刺🧵
两张嘴,一个脑子:
- n8n Hosted Chat(发现较晚,但一直在使用)
- 等我把这个基于 Copilot 的 React UI 框架部署好,并且它能像我设想的那样运行之后,我会把它做成一个简洁的用户界面。我也会更新这个链接。
两者都将自由格式的请求导入到{ intent, location }……
然后:
- 首先从非主流渠道获取信息(例如 Facebook 上的行为事件、Reddit 上与地点或弹出窗口相关的帖子、以及 Obsidian 中不断增长的“怪异网络”列表)。
- 解析时尽量减少标记假设(HTML 会随眨眼而改变)。
- 使用 URL + 模糊地理位置进行去重(并去除跟踪垃圾)。
- 使用十进制Stonewalker混合评分:独特性 • 地域性 • 近期性 • 意图契合度。
- 缓存到Supabase(两次抓取同一个星球是罪过)。
就在我完成第一次端到端运行的时候,n8n 的内存就达到上限了。本能反应:向量 + RAG + 整理 GCP 阁楼。现实:时间紧迫。我做了件枯燥但正确的事——少拉取数据,早点修剪,早点缓存。两个缓存解锁了;第三个是个小 Boss,等我不用熬夜的时候再去打吧。🧱
AI代理:周一是圣人,周二是妖精👾
系统中的代理人和帮助构建系统的代理人——这两个事实可以在同一小时内同时成立:
- ChatGPT把我从困境中解救出来,十分钟后又引用了来自邻近宇宙的文档。
- Copilot在冲刺阶段中途突然失去授权——正值冲刺初期高峰期。
- 当管道系统出现严重问题时,莱昂纳多让我看到了他的品牌,从而保持了良好的发展势头。
- 各种聊天框(n8n、Bright Data、Supabase)在出现语法幻觉之前都是很棒的橡皮鸭。
救了我一命的规则:任何代理都不能直接写入存储。规范化器是铁律。草稿可能易燃,但数据不会。🧯
缓存:Sheets vs Supabase(要做数据库,而不是氛围)🗄️
我一开始想把原型放在 Google Sheets 里,因为它就在那里,而且感觉简单。但简单只是个幌子。一旦你开始在意去重、TTL(生存时间)、命中/未命中追踪,以及“千万别搞砸任何人的业余网站”,你就需要更专业的存储方案了。我转而使用Supabase,遇到了行级安全 (RLS)和权限管理,感觉就像在新地牢里遇到一个小 Boss(v17 版本感觉更刺激了),学到了足够多的知识,不再被新的 schema 绊倒underfoot,最终成功创建了两个运行正常的缓存——第三个缓存现在甚至能听懂我的脚步声了。🪪
脚下的东西应该装在你的口袋里(笔记本电脑是试验场)📱
它运行在电脑上,因为工具都在那里,但Underfoot 的设计初衷是用于你的手机——一个“你已经出门了,附近有什么奇怪的东西吗?”的贴心助手。一键定位,红灯时可以(负责任地)刷卡查看信息,保存/分享功能流畅无阻,还有一个安静的开关:“当五英里范围内出现奇怪的东西时提醒我”。
路径: 先使用 PWA(可安装、离线查看最新结果、分享目标)→稍后推送(已保存的意图 → “您附近的新奇事物”)→使用Expo 封装,并添加触觉反馈和深度链接,使underfoot://place/:id地图体验更原生。🧭
我做错了什么(大声说出来)🧨
- 信任外部预加载却没有备选方案。精心挑选的 230 万行数据始终未能加载;我的测试窗口也随之消失;我重写了代码以实现“fetch + cache”功能,并为此付出了代价。🔌
- 花了半天时间在 Figma 上,而我根本没有空闲时间。我对用户体验设计表示敬意;但对我来说,它就像装饰性的流沙。🎨
- 别让“Cloudflare 很简单”这种说法白白流传下去。事实并非如此。保持用户界面简洁;仅在需要时添加小型 Worker 代理。☁️
- 离开副驾驶,工作缠身。冲刺途中积分耗尽,感觉就像戴着烤箱手套织毛衣一样难受。🧤
- 低估了 n8n 内存。解决方法是像管理资金一样管理数据:减少数据拉取,尽早进行内存精简,提前缓存。🧮
- 结构化产出乐观主义。代理人可以做到,但规范化者必须从一开始就起到把关作用。📇
🦄 我仍然玩得很开心,学到了很多东西,甚至可能还会再做一次——前提是先睡个午觉,再从权限对话框里解放出来。🌙
未来计划(也在代码库中)🧱
接下来的高影响力步骤:我控制的数据集预加载(种子批次),在流程变得枯燥后通过 pgvector 进行向量搜索,通过相同的归一化器处理 Google Places(文本/附近 + 详情),以及一个精心挑选的“奇特网页”种子列表(40-50 个你谷歌搜索不到的网址,定时抓取,质量评分以剔除噪声数据)。🧰
缓存优先响应: Whisper Network 在后台运行,但代理应首先访问缓存。更新提示/流程以强制使用缓存工具 → 实时工具。
缓存管理规划:我花了很多精力设计缓存结构,以便将来能够支持 RAG 类型的导航,以及更简单的嵌入方式来实现直接的矢量搜索。然而,除了“以后得考虑一下”之外,我完全没有考虑过数据存储后如何实际管理缓存。目前,所有缓存管理都依赖于 URL 唯一的合并操作。
- 这个“唯一”URL不太可靠,需要一个更好的“智能”去重系统。
- 我花了大概一个小时研究了一下 Google Sheets 里的 TTL(顺便说一句,完全不推荐这么做),结果发现无论我怎么尝试,结果都一样糟糕——真是个馊主意。于是我才开始用 Supabase,结果它带来的问题比解决的问题还严重。我当时真不该碰它。
本地化:目前为了提高速度,它返回第一个地理编码器结果。需要完善此功能,使结果与用户的预期相符,而不仅仅是地理编码器的猜测。
体验:透明的 Stonewalker 评分系统,方便查看和调整;更丰富的卡片(图片、标签、地图截图、保存/分享列表、快速筛选);更安静的 Discord 机器人,只提供价值,不制造噪音;移动端体验更佳,即使在光线不足的情况下也能流畅使用。✨
可靠性:规范化 2.0 是基本原则;仅在验证失败时才启用小型“修复”代理;改进跨源实体链接,使“老磨坊”成为一个地方,而不是十四个地方。🔐
技术方面
- 系统说明:石行者角色——以地图和旅行为重点的自然/科技混合型向导。
- 型号: GPT-4.1-mini(完整型号作为备用)。
- 内存/缓存:规范化结果以供重用(v2.0);原型最初在 Google Sheets 中开发。
- 节点: HTTP 请求、函数(规范化/去重)、Discord 通知器。Bright Data Verified节点在适用情况下非常好用;对于不常见的数据流,我经常切换到普通的 HTTP 请求。
- 中央人工智能代理: 石行者。
- 我之前用过一个单独的纯数据代理,但耗时太长,效果却不尽如人意。等缓存可靠性提升并整合地图数据后,我会再重新考虑。
- 触发器: Webhook(自定义 UI)+ n8n Chat(便捷)。
- 来源:内部缓存(进行中)、谷歌地图搜索结果(备用)、谷歌搜索结果、Reddit、Facebook 活动、预先批准的二级来源(未来)。
- 输出:结构化解析器 + 二级规范化器。
- 我一直在纠结是否要使用结构化输出;文档警告不要在代理中使用严格的模式。规范化器仍然是最终的权威。
- 错误处理: Discord 通知器——实用、响亮;需要改进格式和路由。
- 计划: Bright Data Google Maps 数据集(已于 2025 年 9 月 1 日 03:43 PDT 交付 — 谢谢团队)。
屏幕截图🖼️
快速链接🔗
代码库: https ://github.com/CheckMarKDevTools/underfoot-underground-travel-planner
在线链接: https://checkmarkdevtools.app.n8n.cloud/webhook/d92bc454-8f78-4471-ae25-ffa0c9bb87b3/chat
🛡️ RAI — 负责任的人工智能(如何有意识地保持良好状态)
- 透明度:模型生成的文本在上下文中清晰易懂;排名结果会注明来源;Stonewalker 评分具有可解释性(独特性、地域性、时效性、意图契合度),并且即将推出可调参数。🔍
- 隐私保护:无需提供个人身份信息;仅匿名访问意图和粗略位置信息;一键“忘记我”即可清除本地缓存和与您的会话关联的服务器痕迹。🫥
- 尊重:遵守版权
robots.txt、速率限制和网站服务条款;优先使用官方 API;请链接回源,不要直接抄袭;禁止设置付费墙和大规模转载。🧑⚖️ - 安全:默认过滤明显有害/非法内容和成人场所;对更敏感的类别设置准入门槛;降低连锁店排名;重点推荐真正本地化的商家。🧯
- 幻觉守卫:代理不会写入存储;确定性规范化器会在任何数据落地之前进行验证/修复/拒绝;不确定性会在用户界面中显示。🧪
- 安全措施:密钥保存在服务器端;采用最小权限密钥;日志经过脱敏处理;定期轮换。🛡️
- 爬虫要讲究礼仪:错峰爬虫、延迟退避、礼貌地并行运行,以免任何人的个人网站被挤垮。🐢
🦄坦白:没错,我作弊了——我让ChatGPT写了最初的提交稿,说实话,我根本没时间看。谁知道里面写了什么,反正我知道那不是我写的,看得我快疯了。🤪所以,请不要把这篇稿子作为项目评分的依据。它是在截止日期之后才完成的。
最后更新:2025年9月1日。如果我遗漏了任何信息,请提交问题,我会进行修正。✅
尾声📝
我尝试的事情有一半都是馊主意——所以我故意把另一半搁置了——但不知怎的,我依然玩得非常开心。我累了,但这种累是令人满足的。我想打个盹,想在某个陌生的城市打开手机,听到Stonewalker轻声说“左转”。我知道我还没结束——只是暂时停顿,好跟你讲讲到底发生了什么。🌆
🧠💥 气场全开(麦克风掉落)
时间已尽,好奇心却未减。Underfoot / Stonewalker已经找到了那些让小镇充满活力的奇特小角落,而书桌只不过是个试验场,因为你的口袋才是关键——轻轻一点,一个意图,几张卡片就像朋友凑近耳边轻声说:“嘘,去这儿。” 🌙
文章来源:https://dev.to/anchildress1/underfoot-the-chatpot-for-hidden-places-and-why-i-dont-do-hackathons-2684







