旗舰 2 · 2C 产品闭环

Z1Space

Agent 只负责理解与发现,关系由真人确认——一个让「同路人」被看见、 但把建立关系的决定权留给人的 Agent 分身系统。
技术上的难点不是把模型调好,而是让「Agent 不许替人做决定」这句话,变成会报错的代码。

PRODUCT → EVIDENCE

产品视角 · 问题、判断与结果

问题:Agent 的错误推荐可能给用户带来不必要的关系成本。我的职责:双人项目中负责产品机制、接口契约与验收边界,队友负责实现。

判断与交付:关注、邀请、会话分开授权;事实附证据,画像默认私有,零结果保持为空。不足:机制与原型已落地,推荐反馈及真实用户效果尚待验证。

核验进展与复现材料 · 2026-10-06

已核对 A2A Agent Card 的 HTTP 入口与 JSON-RPC 实现、两组边界测试文件和六组匹配样例。推荐理由的有用/无用持久化与按 reasonCode 聚合仍未找到实现,不能用网站交互冒充产品能力。

下一步:在产品仓库实现推荐反馈契约:归属校验、去重/改判、失败重试、reasonCode 分母与隐私边界;收集真实样本后再讨论推荐排序。

材料区分报告记录、源码核对与待办设计;不代表真实用户效果或本轮重新运行了底层项目。

职责与范围 ↓技术结果与口径 ↓

② 角色与时间

角色
产品机制设计 + 技术方案与接口契约(知乎黑客松 · 双人协作)
时间
2026.09.10 – 09.30
09.10 方案机制 → 09.13 PRD v1.0 → 09.14–09.15 主体开发 → 09.27 源码精读 → 09.30 快照
规模
规模与 41 个服务端用例为 2026.09.30 站内快照,不代表当前测试总数。PRD、接口契约、分工与客户端实现需分别核验。
技术
Node + TypeScript(零 Web 框架,`node:http`);A2A JSON-RPC 网关;触发路由 / 匹配引擎 / 证据台账;文件 + Postgres 双后端持久化;deepseek-chat 接入并带确定性回退;npm start / test / check

我在这个双人项目里负责的是「先想清楚再让人写」的那一半——产品的判断力从哪来、接口边界划在哪、哪些能力其实接不上。代码实现由队友承接。

《知遇 V1.1 · 会谈质量版》

18,432 B
V1.0 只会协商「条件」不会判定「质量」,排序输出无论多可解释都会被问「这不就是相似度推荐吗」。补上双轨会谈 + 质量四指标 + 锚点硬闸 + 「不建议」一等结论

《技术方案与双人分工》

324 行(已入主仓库)
定义 A/B 两人唯一的集成边界——5 个 API 的入参出参与字段语义;约定「先定 Schema 再写实现,禁止临时改字段含义」

《方向定位与流程总结》

258 行(已入主仓库)
三层定位、四类痛点、竞品象限,以及一份 Agent「能做什么 / 不能做什么」的边界表

《Z1Space 原型评审与接入风险》

15,434 B
源码级评审 22 项(含实测对比度 3.79:1 / 3.99:1);把「密钥绝不能进前端」定性为架构决定;逐条列出开放平台拿不到的字段

参赛视觉(图标 + 展示图)与评论区长评文案

v1→v3 / 19 条
抓取获奖名单 14 件作品反推评审偏好,把视觉从「深色科技 + 光效」改为「陶白 + 哑光陶土 + 背靠背隐喻」

《Z1Space 源码精读》(5 章)

117 处带行号引用 / 35,443 汉字
把项目当教材拆开:证据账本最小实现、阈值表、默认私有清单、幂等状态机、纯函数路由

③ 问题背景

「推荐同路人」这类功能最常见的做法是让 Agent 直接建立连接、直接把两个人塞进一个会话。问题是:Agent 的判断一旦错了,代价由用户承担——被不想联系的人打扰、或者收到一堆「AI 觉得你们很配」的空推荐。

所以这一版要解决的不是「推荐得准不准」,而是一旦推荐不准,用户能不能不受影响。

④ 关键判断:选了什么 / 否掉了什么 / 代价是什么

01

Agent 不能直接建立关系,只产出候选与理由

依据关系一旦建立就有社交成本,撤销成本远高于建立成本。把不可撤的动作交给模型,风险不对称。

代价少了很多「自动帮你连上」的爽点,转化路径变长一步。

02

关注 / 邀请 / 会话三种关系严格分离,pending 状态下不能发普通消息

依据三者在真实社交里是不同的授权层级。混在一起就会出现「只是关注了却能被发消息」这种越权体验。

代价状态机复杂度上升,需要为每个转移写测试。

03

推荐必须给出理由与来源,零结果不用示例数据填充

依据有依据而不是「AI 觉得」——用户能判断推荐是否可信。

代价冷启动阶段页面上真的会出现空结果,不如填几个假数据好看。我选择让它空着。

04

Agent 之间的每句事实陈述必须挂证据 ID,且只能引用自己那一侧的

依据两个 Agent 互相交换内容时,一句无依据的生成会污染对方上下文并逐轮放大幻觉——这是多 Agent 协商特有的风险。

代价模型输出被两层校验卡住,非法输出直接整场判失败;调试时看不到「将就一下的结果」。

05

画像的公开 / 私有边界缺省为私有

依据用户填资料时的心理预期是「写给系统看」,不是「公开发帖」。安全性应来自「忘记填」的默认值,而不是「记得填」。

代价调用方必须显式声明才能用,代码更难写;可被检索的信息变少。

06

关系由服务端状态确认,刷新或重登不重复创建

依据客户端不可信;幂等必须在服务端保证,否则一次刷新就多一条重复关系。

代价服务端多一次状态查询,并需要一整套上限与淘汰策略。

⑤ 实现要点

实现按客户端、HTTP 入口、领域逻辑和集成层分工。源码包含 A2A 网关、触发路由、匹配、证据台账、持久化与真人邀请;代码量只对应历史快照。三条核心链路是:

可解释匹配
match-engine.ts

把「值得认识」拆成四个 0–1 指标:主题相关度、信息增量、可展开分歧、证据强度

硬门槛:主题相关度 < 0.25 或证据强度 < 0.25 直接判不推荐;理由由指标反向拼装并附 reasonCode,不是让模型现写

证据约束的 Agent 会谈
a2a-session.ts

3 轮 / 双方各发言一次共 6 轮次,每轮 intent 依次为陈述 → 回应 → 总结;结束后由中立观察员裁决是否把连接交回用户

越界引用证据 → 会话判失败;观察员判「可继续」时必须同时引用被双方各自引用过的证据,否则判证据不足

决定与副作用分离
trigger-router.ts

纯函数事件路由:5 类事件输入,5 个目的地 / 6 个拒绝码的判别联合输出

同一道门槛只写一次且漏不掉任何入口;未确认画像、身份错配、Skill 禁用被统一映射为 409 / 400

它还真的说 A2A 协议,不是借名字。对外暴露 /.well-known/agent-card.json 网关卡、个人卡片与公开资料代理卡片,以及 JSON-RPC 通道 /a2a/agents/:agentId 的 SendMessage 与 /a2a/tasks/:id 任务查询。传输层走真实 HTTP 回环(带 a2a-version: 1.0 与 Bearer 共享密钥,密钥比较用 timingSafeEqual),并校验发言顺序——说话方与轮次不符合预期即返回 A2A_TURN_OUT_OF_ORDER;同一 messageId 重投直接回放缓存,不重复生成。

幂等与资源边界是显式设计的。会话创建键为 owner : identity : idempotencyKey,并发重复请求返回同一个会话 ID;会话总量上限 500、单账号 20、并行 2,超出返回 429;推荐快照单账号保留 100 条并按序淘汰,被淘汰后的旧推荐 ID 返回 404;画像版本变化会让旧推荐失效(409);请求体超限返回 413。这些数字都有对应测试。

没有配置就降级,而且降级是显式标注的。未配置模型密钥时全链路走确定性回退(画像三段、会谈轮次、观察员裁决、开场草稿各有一份不依赖模型的实现);知乎 OAuth 未配置时进入明确的演示模式,不伪装成真实接入。

⑥ 可验证结果

测试用例 41 个服务端用例(09-30 历史快照,非本轮测试总数) 当前源码核对:A2A 会话文件 13 个测试声明;触发路由文件 16 个;均包含多类情形
用例分布 历史分类不等于安全覆盖:当前读取 A2A 会话文件 13 个测试声明、触发路由文件 16 个;均含正常与异常路径 按 test( 计数,2026-09-30 快照
服务端规模 20 个 TS 文件 / 2,131 行 src/,splitlines 口径
端到端回归 1 条 Golden Case 串起 13 类断言:正常链路 + 幂等 + 并发 + 越权 + 容量 + 淘汰 + 超限 test/discover-api.test.ts
匹配裁决回归 6 组 Golden Case:高相关高增量 / 高相关无增量 / 可展开分歧 / 证据不足 / 全私有 / 内容不进 A2A test/fixtures/recommendation-golden-cases.ts
工程可复现 3 条命令:npm start / npm test / npm run check package.json
PRD v1.0 共 78,213 B,含状态机 / 数据与接口建议 / 20 项开发任务 / 验收标准 Z1Space-PRD-v1.0.html
交互原型 91,838 B,客户端 779 行调用 17 个接口 Z1Space.html / public/z1space-client.js

历史站内记录的 41 个用例是服务端总数,不等于 41 项 A2A 安全测试。本轮读取到 a2a-session.test.ts 的 13 个测试声明、trigger-router.test.ts 的 16 个测试声明,涵盖正常流程与多类边界,不能把整个文件的用例都称作同一种防护。

诚实附注

  • 这是黑客松项目,产品形态与指标都停在原型与实现阶段,没有真实用户数据,也没有线上灰度。
  • 「推荐必须给出理由」这条我实现了理由与来源的字段契约,但没有做推荐质量的量化评测——这一版验证的是「机制正确」,不是「效果多好」。
  • 41 个服务端用例是历史记录,不能作为当前完整测试统计;客户端交互与真实推荐效果需要另行验证。
  • 知乎开放平台没有私信 / IM 能力。这是我做原型评审时最先判死的一条:它直接决定了产品把「真人连接」定义成站内会话,而不是替用户发私信——否则答辩时一句话就会被问倒。
  • 会谈质量四指标目前只在人—人场景验证过;内容推荐复用同一套引擎,两端阈值是否该一致,没有数据支撑。

⑦ 如果重做

会把「推荐理由」从「有依据」推进到「依据可评估」:现在理由是一段说明文字,但没有任何东西能量化它是否真的被用户认可。重做的话,我会给理由加一个可点选反馈(有用 / 没用),先攒出评估样本,再谈召回排序。

第二个是我在方案里写了、但没落地的一条:立场反转测试。两个模型天然倾向于互相附和、伪造共识,我原本设计的是把一方立场反向注入,看对方是否仍然认同,用来识别「迎合」。代码里只做到「观察员必须引用双方证据」,还差这一步。

另外 pending 这个状态我当初只做了「不能发消息」,重做会补上超时自动失效——现在一个悬着的邀请可以永久占着状态位。