尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
输入全国任意一个地址(中国大陆),自动检索周边 1 km 的设施,由大模型撰写学术风格的场地分析简报,并由代码逐个校验简报中的数字。 面向建筑与城市设计专业的学生:做课程作业前,先快速获得一份带数据来源的场地概况。 ▶ 在线体验版(可输入全国任意地址,实时生成): https://www.dzs-agent.com ▶ 静态演示(预先生成的真实结果,点开即看,网络不佳时使用): https://dengzishuo19.github.io/site-analysis-agent/ 在线体验版部署在 Vercel(香港节点),并绑定了自己的域名。vercel.app 默认域名在国内被屏蔽,绑定自有域名(DNS 的 A 记录直接指向 Vercel 的服务器 IP)后,国内实测可正常打开、响应快;两个链接在国内网络下都实测可用。为保护接口额度,设有访问频率限制。 大模型擅长写作,但不擅长数数,也可能编造数字。所以这个项目把职责拆开: 校验器核对三类断言:「设施名」必须存在于数据;名称后的距离必须属于这个设施;“某类别 N 处”的 N 必须等于该类别的数量;其余数字至少要出现在统计表里。为了让校验器认得出断言,提示词要求模型使用固定句式。校验不通过时,会带着具体的纠错信息让模型重写一次;仍不通过则在页面上标红警告,不会悄悄放行。檢視完整 README ↗
输入全国任意一个地址(中国大陆),自动检索周边 1 km 的设施,由大模型撰写学术风格的场地分析简报,并由代码逐个校验简报中的数字。
面向建筑与城市设计专业的学生:做课程作业前,先快速获得一份带数据来源的场地概况。
▶ 在线体验版(可输入全国任意地址,实时生成): https://www.dzs-agent.com
▶ 静态演示(预先生成的真实结果,点开即看,网络不佳时使用): https://dengzishuo19.github.io/site-analysis-agent/
在线体验版部署在 Vercel(香港节点),并绑定了自己的域名。
vercel.app默认域名在国内被屏蔽,绑定自有域名(DNS 的 A 记录直接指向 Vercel 的服务器 IP)后,国内实测可正常打开、响应快;两个链接在国内网络下都实测可用。为保护接口额度,设有访问频率限制。
大模型擅长写作,但不擅长数数,也可能编造数字。所以这个项目把职责拆开:
| 环节 | 谁来做 | 原因 |
|---|---|---|
| 地址转坐标、周边设施检索 | 高德 Web 服务 API | 国内数据全 |
| 计数、按距离排序、取最近设施 | 代码 | 大模型数数不可靠 |
| 把统计数据写成书面简报 | 大模型(DeepSeek) | 擅长写作 |
| 逐条核对简报里的断言 | 代码 | 事实由代码裁决,不交给模型 |
校验器核对三类断言:「设施名」必须存在于数据;名称后的距离必须属于这个设施;“某类别 N 处”的 N 必须等于该类别的数量;其余数字至少要出现在统计表里。为了让校验器认得出断言,提示词要求模型使用固定句式。校验不通过时,会带着具体的纠错信息让模型重写一次;仍不通过则在页面上标红警告,不会悄悄放行。
杂志/刊物风格,黑白灰:用字号层级和图片排布表达信息主次,不用彩色;只有地图底图保留彩色(水系、绿地是场地分析的重要信息)。设施类别用简笔画图标区分(lib/icons.ts),不靠颜色。只用系统字体(谷歌字体在国内打不开):黑体标题与正文、宋体简报、等宽数字。
在线版首页(尚未分析时)有一句话说明、三个卖点,以及一个内置示例:7 个事先生成好的案例可切换(北京 5 个:国贸、首钢园、亦庄、北京建筑大学西城校区、八达岭;外地 2 个:上海陆家嘴、成都太古里),显示 7 类设施数量、简报节选和“已由代码校验”标记;点“用这个地址实际分析”才跑真实分析,点案例切换不请求任何接口。示例数据来自 app/components/examples.json(由 scripts/export-demo-data.mjs 与静态演示数据同时导出,只含数量、最近设施和简报节选,不含坐标),生成日期显示在页面上,不会随高德数据实时更新。分析等待时显示分步说明(定位、检索、过滤),这是按经验估计的,不是实时进度。
结果页顶部有一条可信度信息条,只展示后端已有的事实:统计经服务器签名;简报中的数字已全部核对、其中多少个与具体设施或类别逐一配对(来自校验器的覆盖率);已过滤多少个噪点(链接到 docs/testset/review.md 的规则与度量)。页面底部注明作者(邓子硕)与 GitHub 仓库;页面带分享标签与预览图(public/og.png),微信等平台是否采用以实测为准。
布局手机优先:单列、可点击元素不小于 44 px;宽屏放宽到约 960 px,地图与条形图并排。已用 375 px 与 1280 px 宽度实测,无横向滚动。
配色按 dataviz 技能 的方法计算:该色板最多只有 4 种颜色能同时通过“全配对”检查,而设施有 7 类,所以采用复合编码——颜色表示类型族(交通、生活服务、公园绿地、工业),标记里的单字表示具体类别(地、公、教、医、商、园、工),不靠颜色硬分。
| 地图(深色) | 图表(浅色) | 图表(深色) |
|---|---|---|
教育、医疗、工业三类可展开子类型(教育:大学、中学、小学、幼儿园、职业学校、其他;医疗:综合医院、社区卫生服务、口腔、医疗美容、眼科、其他专科;工业:产业园区、工厂、其他),使用者勾选后,数量、最近设施、地图、条形图随之更新。噪点过滤始终开启,不是选项;子类型是“分解 + 勾选”,默认全选,数字与大类一致。
数字仍然由服务端算并签名:/api/site 返回的签名数据里带有过滤后的点位池(每类最多 75 条,含子类型);勾选时浏览器把签名数据和勾选交给 POST /api/site/refine,服务端先验签,只用签名数据里的点位池重算,再重新签名,不访问高德、不信任浏览器提交的数字。改变口径后已生成的简报作废,需要按当前口径重新生成;简报会写明统计口径。
局限:高德的“学校”泛类分不出小学还是中学,按名称再划分,会有误分;点位池最多 75 条,设施很多的类别子类型数量是下限;子类型准确率只在自建的小测试集上核对过(教育 47 个、工业 26 个保留点位全部判对,但核对者与规则作者是同一方),医疗的子类型完全取决于高德类型。静态演示页只读显示子类型分解,不能勾选。
地铁出入口全部标出后,市中心的标记会大量重叠(国贸默认视野下 86 个标记有 72 个被压住)。现在相距很近的标记会合并为一个簇:同一类显示为该类标记加数量角标,多类显示为写着总数的圆点、下方小色点表示含有哪几类;点击簇放大拆开,18 级以上全部单独显示;图例隐藏的类别不参与聚合。聚合只改变显示,不改变标出的设施集合与任何统计数字。5 个演示案例默认视野下被压住的符号降到 0–2 个(lib/map-cluster.test.ts 回归测试)。
高德的地理编码在无法确定具体地点时,会静默返回一个行政区划中心点:例如输入“北京建筑大学”(有西城、大兴两个校区),它返回“北京市(level=省)”,坐标是市中心。如果直接照单全收,后面的统计、地图、简报都会建立在错误的位置上,而且看起来完全正常,所以这一步必须先校验定位精度:
| 情况 | 例子 | 处理 |
|---|---|---|
| 输入本身只是行政区名 | 北京、朝阳区 | 拒绝,提示输入更具体的地点 |
| 高德没认出具体地点,退回了行政中心 / 只定位到道路、村庄、开发区 | 北京建筑大学、长安街、中关村 | 用关键字搜索给出候选,让用户选 |
| 定位精确但有多个相距超过 300 m 的候选 | 北京大学(4 个校区) | 让用户选 |
| 定位精确 | 国贸地铁站、首钢园、清华大学 | 直接分析 |
候选去掉上级也在结果里的子点位(如校区在列表中时去掉校内的系;上级不在结果里的保留,例如挂在上级片区下的“成都太古里”。原规则为只保留 parent 为空的顶层点位,即校区本身,而不是校内的系、食堂、停车场)。用户选中候选时,服务器只接受自己签发的令牌(HMAC 签名、30 分钟有效、坐标必须在北京范围内),不接受浏览器提交的任意坐标。判断逻辑是纯函数并有单元测试。
parent 字段把校内院系、院内科室、园区楼栋折叠到所属机构,并按类型与名称剔除培训机构、党校、药店、写字楼里标成“工厂”的公司等类别归错的点位(附属学校、异地分部保留为独立设施);折叠后若没取完全部结果,数量按“至少”标注。过滤规则用一份人工标注的测试集度量(5 个场地、389 个点位,npm run eval:poi):误杀 1/184,漏网 16/205;用没参与调规则的 4 个场地抽查未见误杀,但测试集很小,这些数字不能外推到所有场地。需要 Node.js 20+,以及高德开放平台的 Web 服务 Key、Web 端(JS API)Key 和 DeepSeek API Key。
npm install
cp .env.example .env.local # 然后在 .env.local 中填入你自己的 Key
npm run dev # 打开 http://127.0.0.1:3000(不要用 localhost,见下)
npm test # 运行单元测试
本地必须用 127.0.0.1 访问:高德的域名白名单不接受 localhost,而地图会按访问域名校验 Key。
关于地图 Key:Web 端(JS API)Key 会出现在浏览器里,这是它的工作方式,无法像其他 Key 那样藏在服务器里。它是一个独立的 Key(与 Web 服务 Key 分开),靠高德控制台里的域名白名单保护(127.0.0.1、GitHub Pages 域名、在线版域名);白名单可以被非浏览器工具伪造,最坏的后果是有人消耗它的每日额度,不会产生费用。高德的服务条款规定:未购买技术服务许可时,所提供的 Key 与额度仅供短期、少量的测试使用——本项目是技术演示,请勿大量访问。
**排错:**若地图区域提示“脚本已加载但不可用”或“Key 格式不正确”,多半是环境变量里的 Key 带了多余字符(空格、换行、引号、变量名前缀)。高德在这种情况下不会报错,只会返回一个不定义 AMap 的脚本,页面上就是“脚本已加载但不可用”。代码会自动去掉首尾空白与引号,并要求 Key 是 32 位字母数字;重新填写环境变量并重新部署即可。
.env.local 已被 .gitignore 忽略,Key 只在服务端使用,不会出现在前端代码或返回结果中。生产环境还需要配置 SIGNING_SECRET(随机字符串,生成方法见 .env.example),缺少时所有页面和接口都会返回 500(安全失败,不会放行未签名的数据)。
在线版对所有人开放,背后消耗的是作者的接口额度,所以做了这些防护:
/api/site 返回的数据带 HMAC-SHA256 签名(30 分钟有效),/api/report 只接受验签通过的数据。别人无法伪造统计数据来滥用大模型,也无法借设施名称做提示词注入。/api/health 在生产环境返回 404;基础安全响应头。**这套防护的边界:**限流数据存在进程内存里,在多实例的无服务器环境下每个实例各自计数,只是“尽力而为”,防不住有意的攻击。兜底靠 DeepSeek 预充值制(最坏情况是余额用完)和高德的每日额度;如果被滥用,下一步是把计数迁移到共享存储(如 Redis)。
lib/amap.ts 高德接口封装(地理编码、周边搜索)
lib/stats.ts 设施统计(类别与分类编码在此配置)
lib/llm.ts 大模型调用封装(OpenAI 兼容格式,换模型只改环境变量)
lib/report.ts 简报生成 + 校验重试
lib/verify.ts 数字校验(纯函数) ← 含 verify.test.ts
app/api/ site(统计)、site/refine(自选子类型口径)、report(简报)、health(连通性检查)
docs/index.html 静态演示页(由 scripts/build-demo.mjs 生成)
docs/tasks/ 每个开发阶段的派工单与验收记录
项目借助 AI 编程 Agent 完成:我提出需求、审阅设计并逐条验收。每个阶段先写派工单(背景、输入输出、不许改的文件、验收标准),完成后按验收标准核对并留下证据,记录保存在 docs/tasks/。开发中真实发现并修复的问题包括:
sortrule=distance 返回顺序并不严格按距离,导致统计表“最近设施”出错,改为多取并在代码中排序。设施数据来自高德开放平台,简报由 DeepSeek 生成。本项目仅作技术演示与学习,简报仅基于统计表,不构成任何规划或投资建议。