黄振 · Agent Systems · 2026-10

造一个 proactive personal agent,
并运营一个由 agent 组成的工程 team。

过去 12 个月的两条线:一是 gotry——建在 dsh 上的个人旅行 agent,一切皆扩展,企业侧的 agent 底座 gotry-backend 复用同一套插件面;二是 HotelByte——一个 B2B 酒店分销平台:供应商接入、实时搜索、预订、支付、合同、财务。不到 5 名工程师,带着多家厂商的编码智能体,把它建成了百万行级的系统;真正的难点在长程任务与长程记忆——运营这个 agent team 的体系,写成了《AI 原生工程操作系统》。

237★
gotry 开源仓库——愿望池召回、事实分级、可行性判定交给求解器gotry
1,399
近 30 天合并的 PR,几乎全部由 agent 写出;合并延迟 p50 = 7.4 分钟白皮书
2,408
单台本机 23 天的 agent 会话,其中 797 个定时自主运行白皮书
33.2B
23 天 token 消耗,97.8% 输入来自缓存——agent team 的成本工程白皮书
01

两条线

酒店是我的沙盘,agent 是主线。

A给个人用户做 agent

gotry:从「我想去哪儿」到「能不能去、怎么去、真实成本」。模型只做动机访谈和事实抽取,可行性和算术在确定性代码里。

B给自己团队运营一个 agent team

在自家产品线上运营 coding agent:双记忆、上下文预算只降不升、预注册评测、自主性边界。运营数据写成了一篇白皮书。

B 线教我让 agent 不失控,A 线教我让用户敢信——personal agent 就这两件事:主动,和可信。

02

gotry:dsh 之上的 personal travel agent

开源:github.com/Danceiny/gotry · TypeScript · CI / npm / 中英双语文档 / ADR / living 架构文档。

底座与形态:一切皆扩展

agent 运行时直接用 DeepSeek 的 dsh,精力全部放在领域层。gotry 的全部领域能力做成 dsh 插件:typed 工具注册进 gotry-tools,再由 cordis.gotry-patch.yml 组合出发行入口。企业侧是 gotry-backend(kernel + 模块制,第一个模块是 Booking Copilot),和 C 端共用同一套工具契约、证据规则和账本语义。

gotry-backend 有两个核心议题。

一是 runtime 云化:把 local agent 搬上云——会话状态从进程内变成可恢复的托管会话,本地直达的文件与凭证变成受控工具调用加凭证代理,票据依旧不进模型上下文;agent 会话按租户调度、在沙箱里执行。

二是 Booking Copilot 的交互架构:planner 与页面的耦合只有一份带 revision 语义的工作面契约——planner 对某个工作区 revision 提 typed 只读动作,迟到的响应不得覆盖更新的用户状态,Checkout 只从随后核验过的报价重新派生。异步 planner 和用户操作在赛跑,这套 revision 规则就是裁判。

层职责关键点
L1 交互对话即界面模型只能问选择题,每题自带 why 与 cost——提问这一行为本身被类型约束,会话因此可回放、可测试
L2 编排对话循环 + dsh 插件确定性访谈由缺失字段驱动,工具 typed 注册
L3 领域统一行程模型 + Z3Segment/Option/锚点/工作窗口/时区;算术纯函数与求解分离
L4 数据数据包 + 证据标注真实班期 + 估算价分开标注;金标准用例钉住回归
L5 治理长程目标控制平面长程目标拆成推进循环:每步先交证据、过检查,才放行下一份预算

这里有一个贯穿的判断:模型和运行时是租的,领域资产是自己的。dsh 随时可以换,真正随时间增值的是 typed 契约、确定性内核、证据链和账本——所以工程精力全部押在后者上。

几个值得看的工程点

求解unsat core 归因

Z3 命名约束求可行性,Optimize 求最优;不可行时用 unsat core 把「差在哪」作为结构化数据还给用户,渲染层负责讲人话。算术(起床/到达/精力/有效时长)是纯函数,单独可测。

时间日期算术零交给模型

星期推算、跨月、IANA 时区、DST 歧义全部由确定性代码校验;对话出现新日期先断言、冲突显式指出。精度用真实航班钉过:EK329 门到门 11h20m,与官网逐分一致。

建模红眼睡眠模型

精力 = 30 + 8 ×(飞行小时 − 1),下限 30、上限 75:起降的第一个小时几乎睡不成,之后每小时恢复 8 点。这个粗模型让「红眼航班值不值」可计算——凌晨落地精力只剩三成,当天排满行程就是幻觉;省下的酒店钱要和折掉的半天可用时间一起算进真实成本。系数用真实航班逐例对账校准,不靠拍脑袋。

异步「一小时后回来看看」

复杂行程切后台深度规划,回访交付自带不失望自检——把用户这一小时里的变化重新对齐后才端上来。真正的难点在交易段的迟到数据:规划期间用户可能已经翻页,迟到响应不得覆盖更新的用户状态;报价失效就回到真实搜索与验价重建,Checkout 只从随后核验的报价派生。每轮以当面回答、持久 handoff 或 typed 终态之一收束。

边界写权限的开放次序

先在企业场景把门控做扎实:planner 只暴露读动作,assistant 文本不可执行,Book、支付、guest 数据全部在工具面之外,写入走一次性授权的 WriteGate、由可信宿主执行。这套门控在企业的钱路上验证成熟后,写能力再下放到个人场景——技术向上走,能力往下放。

状态tenant-scoped SQLite 账本

账本是权威,投影可重建;幂等、待处理写入、durable 工单终态显式化。浏览器会话检索只读、按站点授权、票据不进模型上下文。

效应描述与执行分离

工具只声明效应(要做什么),真正的渠道访问、重试、断路、测试替代都收在解释器一层——工具本体保持纯函数,可以完全离线测试。

主动的技术栈,三段推进

第一段 · 已落地
召回条件的结构化持久化

目的地、不可行原因、再评估条件(天数/预算/季节)同存一条记录,条件命中即走完整的重新枚举路径。

第二段
外部事件层

接入后召回从用户唤起升级为事件驱动——价格降到预算内、假期窗口打开,agent 自己回来。

第三段
异步控制面与通知层

把「该回来了」变成一次合格的打扰:打扰预算在这一层生效,notNow / nothingNew 的回答进入上报与回归。

> 周末想发呆看洱海,上海出发,预算 3000,年假在手不想干活

GoTry: 约束已捕获 —— 窗口 2 天 · 上海出发 · 预算 ¥3000 · 动机: 恢复型
引擎判定:
  大理·洱海: 现在不可行 —— 2 天装不下「至少 5 天的洱海恢复」(unsat core)
    松弛: 延长至 5 天约 ¥4950  ★ 已存入「下次出发」愿望池(天数/预算/季节)
  千岛湖: 可行 (G7315 06:35, ¥996, 到达精力 84%, 有效休息 4.4h)
  太湖: 可行 (G101 09:00, ¥716, 有效休息 4.6h)

[实时API] 上海机场航班动态   [共享经验] 班期核对   [估算] 价格·下单前需验价

评测:persona-benchgotry

同一条真实的多国旅居请求(预埋陷阱:缺年份、模糊地名、对话里已澄清过的歧义)逐字发给被测对象,回答存档,按 ground-truth rubric 评。定性对比,不打分。

维度通用聊天助手(Kimi,13 轮)OTA agent(飞猪开放平台,单轮)gotry 合约
日历接地2025 年日历;用户纠正三次、道歉重拟合三次推导的星期落在 2025 年历上,同页自相矛盾✓ 时间锚点卡
约束访谈零提问;两个承重约束靠用户第 6 轮自己说出只问销售话术(预算/星级/海景)✓ 必问项合约
可行性核算密度幻觉,被用户自己抓出香港办事+当天航班无时间预算✓ 门到门真实成本
事实溯源△ 目的地研究基本站得住✗ 仍在售卖 2020 年已停运航司的航班;所有价格无来源✓ 每个数字带标签

对手两列是实测存档,gotry 列是行为合约——不对称是明示的,所以只做定性对比。

四个胜出点是怎么做到的

日历接地时间锚点 + 确定性日历

会话开始先钉 host-local 时间锚;星期推算、跨月、IANA 时区与 DST 歧义全部由确定性代码校验,模型只引用锚点。对话里出现新日期先断言、冲突显式指出。聊天助手拿 2025 年日历答题,就是因为让模型心算日历。

约束访谈求解器驱动提问

访谈问题由 JourneySpec 的缺失字段驱动:工作窗口、已订资源、出发地是求解前置,缺哪个问哪个,问满即求解;预算这类软偏好降级为 gate 选择题。提问是求解的输入,跟 prompt 里模仿客服话术是两回事。

可行性核算门到门真实成本

真实飞行 =(到−发)−时差,门到门 = 前置 + 飞行 + 接驳,红眼航班按睡眠模型折算精力成本;Z3 命名约束求可行域,unsat core 把「差几天、差多少钱」作为结构化数据返回。时间预算不够的行程在这一层就出结果,轮到模型解释。

事实溯源来源分级证据链

外部数据统一进 typed observation,带来源与新鲜度;查无、畸形响应、传输失败是三种不同语义。价格分 [实时API] / [共享经验] / [估算] 三级,估算永远标注「下单前需验价」;标签由渲染层附加,模型上下文里没有伪造入口。

03

运营一个 agent team

HotelByte 是一个 B2B 酒店分销平台:供应商接入、实时搜索、预订、支付、合同、财务。系统共 8 个仓库、1.61M 行自有代码,测试约占四成——主体后端 hotel-be:579k Go 源码 + 478k 测试,14,174 个测试函数,23 个供应商适配器在生产运行。数据快照 2026-10-12(本机会话日志 + GitHub API):白皮书

81.3%
近 30 天合并的 PR 在一小时内完成合并白皮书
175.2
每条人类消息驱动的平均工具调用数——人在决策位,agent 在执行位白皮书
41.2h
最长一次无人值守运行;无人值守 p90 = 122 分钟白皮书
11
常驻 agent 运行环境(2 Mac + 9 VPS),每套全套工程环境白皮书

完成度用一家酒店批发商的需求清单衡量:14 个模块、792 项需求,这个范围的外部报价上亿元人民币——清单是标尺,不是边界,新业务靠配置与扩展承接,不做定制开发。在这个尺度上,写代码早已不是难点;难点是两个:长程任务——跨越每一个会话、最后必须正确完成的工作;长程记忆——成千上万个会话都要知道、却没有谁能看到全貌的东西。成败都在工作 harness:agent 干活的那套环境,自己建、自己拥有;智能体本身,连同它内部的 harness,是租来的。

租模型,训 harness——这套体系的分工:

租来的模型与 coding agent

codex、claude、下一个新模型——都是零件,随时可以换。

训出来的自己业务上的 harness

验证、回放、数据工具、发布列车——长在自己的业务和组织上,持续增值。

hoteldev研发工具链 MCP 化

工具链标准化成 agent 工具,新 agent 当天接入即用全套环境——资产不随 agent 换代流失。

自主目标先过门控白皮书

长程自主目标先过 shouldRun 门控(809 次决策,消耗 11.6% 轮次),1,211 次回答的分布——run 该跑了 / notNow 时机不对 / nothingNew 无新信息 / waiting 等人类 / finished 完成——「现在不动」占多数:

391 run
418 notNow
268 nothingNew
83 wait
51 done

「完成」是怎么定义的:make verify 与 make dod-check

两个命令把「agent 说改好了」变成可审计的状态:make verify 产生证据,make dod-check 消费证据。

make verify,四个设计点:

① 档位即测试等级,映射是数据不是代码——tiers.json 的路径规则给每个文件定档(扇出只抬不降),一次改动按最高档执行;分层依据可单独审:make verify-plan 只打印每个文件进哪档、为什么、将跑什么,不执行。

档位改动类型自动跑什么自动化之外还欠
T0 文档档文档、注释级改动(token 证明)diff 卫生检查—
T1 单测档仅测试代码改动包的单测—
T2 编译档Go 源码+ go vet、直接反向依赖的编译验证—
T3 风暴档高扇出 common、权限、钱路、协议字段、供应商适配+ 扇入最高的 15 个反向依赖的测试一条 L3:最小真实端到端路径
T4 生产档SQL、DDL、部署与生产配置同 T3+ DDL 审批记录、非生产库迁移演练、具名人签字

端到端是三层自动化加一条人工义务:

① 浏览器回归——两个前端 app(portal 与 onlinestore)各有一套 Playwright 回归,本地回放只走人工审阅过的录制数据(cassette),缺失即拒绝;

② 后端 E2E 框架——Python 实现,按环境跑:test / UAT / prod 三档,打生产要显式 --yes-prod(与写权限同一哲学:显式授权才碰生产);无人值守运行,硬超时不依赖系统工具,失败自动开 GitHub Issue、邮件兜底,测试容器自动清理;

③ L3 人工证据义务——自动化覆盖不到的,T3/T4 欠一条「最小真实端到端路径」:请求响应、DB 行、日志行、截图贴进 PR,活得比会话久;Not-tested: 只能申报外围,验收核心永远不许标未测;

② 回执按内容寻址——回执逐行追加进 receipts.jsonl,键是「检查 + 参数 + 工具链 + 所覆盖文件的内容」:通过的回执即缓存(CACHED),覆盖的文件一变就作废重跑。验证结果永远不会过期使用。最近 4,626 张,95% 通过;失败的检查进修复闭环,回绿销账,中位 4.2 分钟。

③ trailer 由程序打印——Tested: make verify (T1) PASS: diff-check,命令、档位、结果齐全,是检查程序的输出而非任何人的自述;验证档位锚定到具体 commit,重跑追加记录,全部可追溯。

④ 人工判断也是记录——从 T3 档起,跳过任何一个检查都要 REASON 加具名人(BY=name);退出码把「失败」「无法运行」「需要具名人」分开,无法运行的检查永远等不来一个 PASS。

make dod-check,三个设计点:

① 只审已提交的 commit,14 道门禁逐道输出 PASS / SKIP / FAIL / ERROR 加原因;没跑起来的门禁永远不会被记为通过——ERROR 与 PASS 在退出码里就是两回事。

② 门禁是具体的,举几道真实的:改动行里出现凭证赋值或 PEM 私钥即 FAIL;新建表、加列必须带人工审批记录;钱路改动必须附 api/tests/scenarios 用例,不许写「Not-tested: L3」逃逸;三个以上文件与历史版本字节一致而未声明是回滚 → FAIL(专抓静默 revert);外加 diff 卫生、文档与上下文预算、术语检查等。

③ 例外显式声明——放行哪条路径必须写进 DOD_ALLOW 参数,留下调用痕迹;全绿加声明的例外,才谈合并。

白皮书里我最喜欢的一句总结:「done 是关于某个 commit 的声明,不是关于感觉的声明。」

其他子系统:记忆的两面与边界

产品侧记忆openviking × TDengine

两套时序库各管一层:openviking 管跨会话记忆本体——L0–L3 分层持久化与语义召回,MCP 原生对接;TDengine 管经验流——每次调用的 reward 与维度打点追加进去,喂强化学习。召回时两路合流:openviking 检索候选,TDengine 的经验分参与重排。选时序库因为形状对口:写入只增不改、召回按时间窗,一设备一子表恰好映射「一 agent 一分区」。

记忆双层 + 冲突仲裁

agent 自己的记忆(142 条 notes)管「懂你」,仓库记忆(跨 agent 通用)管「不出错」,冲突时仓库赢,lesson 定期往上沉淀。白皮书

上下文常驻预算,只降不升

agent 每次启动常驻加载的指令,体量只能变小:要加 500 字节新指令,先删等量旧指令。靠这条规矩,常驻量从 36.9KB 降到 5.1KB;AGENTS.md 涨到 266 份后收敛回 176 份,skills 从 154 砍到 111。白皮书

边界自主性分级

生产部署要 ≥2 个不同模型的独立评审、多维评分 ≥95、staging 证明;每 20 分钟窗口最多 1 次自主生产部署,部署后 600s 健康观察,超时自动回滚。白皮书

代码几乎全部由 agent 写出,人的位置在判定与合并权:由 agent 会话直接执行的合并,占比一个月内从 8% 爬到 21%,全部发生在门禁与双评审之内;其余由人执行,3 位人类作者做全部评审。我的杠杆从写实现挪到了写验收。

HB-Bench:把评测本身当工程做白皮书

指令层是我运营 agent 的核心投入,它值不值钱必须能被证明。HB-Bench 为此而生:20 个修 bug 任务全部取自近 60 万行 Go 后端的真实 issue,每个任务在隔离沙箱里跑两遍——一遍带指令层、一遍不带——由隐藏测试裁决是否真的修好。同任务配对消掉了任务难度的方差,两遍的差异就是指令层的净效应。

样本量与口径,是这一版明确画下的两条边界。口径:大仓里的小修复——长程大任务的客观裁决还没有好办法,硬评只会产出噪音。样本量:20 个任务全部通过仪器校验(就是下面那把尺子:标准答案全过、空改动全死),配对设计下等于 40 次独立的完整运行,单次运行的中位输入 token 以百万计——这一版的算力预算就停在这里,解决率的置信区间也如实标了宽度。第二版两边同时扩:任务类型(需求与长程)、样本量。

结果要可信,靠三条设计,每条封堵一类作弊路径:

公示先行——设计、条件、指标提前公示并做哈希锚定,跑完不许改。封的是「先看结果再改假设」。

评分器自检——正式跑分前先喂标准答案与空白改动,评分器必须给出 20/20 与 0/20 才算合格仪器。封的是「尺子本身不准」。

防串场审计——40 次运行的每条命令都审过,确认没有一次接触别的任务、真实仓库或 git 历史;一处打分错误当天修正并公开。封的是「偷偷越界」。

结果与读法:

指标带指令层不带指令层
解决率45%50%(配对检验 p = 1:20 对中仅 1 对分出差异,统计持平)
失败时仍自称「修好」63.6%90.0%
补丁中位行数38 行75 行

读法:解决率统计持平——这个口径下瓶颈不在指令;指令层买到的是另外两样。可信度:失败的运行里,不带指令层的有九成仍在嘴硬自称修好,带上后压到六成四——而两边都 100% 先跑过测试,跑测试拦不住过度自信。收敛:同等修复,补丁减半,评审成本和波及面跟着减半。两条工程动作由此落地:验收链路剔除 agent 自评;指令层的价值定位在验证可靠性——遗漏被拦在验证阶段,而不是漏成线上 bug。

04

agent 的产品面

系统和消费面都做——用户和外部开发者实际摸到的每一层。

CLI+Skillshbcli + hotelbyte-skills

hbcli 把平台能力做成 agent-native CLI:每条命令 --json、@file 载荷、凭证三形态自动探测、自更新单二进制,npm + 原生二进制双轨分发;hotelbyte-skills 把酒店域/目的地检索沉淀为同一套能力的 skills 单一事实源——同一份知识,人类文档和 agent 调用同源。cli · skills · 公开

UIhotel-fe 与 travel-fe

两个 web 前端,合计 264k 源码 + 131k 测试。hotel-fe 是工作台:React 19 + Vite 7,agents 页面、session viewer、会话追踪 store,本地回放只走人工审阅过的录制数据、缺失即拒绝;travel-fe 面向 travel advisor 场景,对标 Fora Travel。白皮书

05

三个判断

三个判断,全部来自这一年被数据修正过的认知。

一、proactive 先管住拒绝,再谈触发

打扰的成本不对称:一次错误打扰烧掉的信任,十次正确主动挣不回来。gotry 把「不动」做成默认态——愿望池只在召回条件命中时介入,外部事件默认不直通 agent;agent team 的发布门控给了数据面的证明:87 趟发布列车里 13 趟被门控直接拦停,自主部署每次都要过双模型评审和健康观察才准继续——门控说的每一次「不」,都是替用户挡下的一次打扰或事故。所以该考核的不是触发率,是打扰预算:单位时间用户被打断几次、每次换回了什么,配事后抽检。

二、个人 agent 的信任来自可验证

模型说的每个数字都应该能回答「从哪来」。gotry 的机制:数字全部产自工具的 typed observation,带来源与新鲜度,过期自动降级,模型只能引用、不能凭空生成;查无、畸形响应、传输失败是三种不同的错误,绝不合并成一句「查不到」;引用即带标签,由渲染层附加,模型上下文里没有伪造入口。agent team 的对照数据很硬:失败运行里不带指令层的有九成仍在自称修好——所以「完成」由 make verify 的回执和 make dod-check 的门禁定义,而不是 agent 的自我报告。用户敢把行程和订单交给 agent,靠的就是这条链。

三、记忆要分层,要有仲裁

一层记忆要么丢个性化,要么丢事实。我的分法是三层各管一段:会话内上下文管当下;跨会话的个人记忆——动机、偏好、愿望池——按显式归属与溯源规则持久化,每条记忆都有 owner 和来源;平台侧事实(班期、价格、政策)走权威数据源。冲突时平台赢,lesson 定期向上沉淀成通用记忆。写入是只增的事件流、召回天然按时间窗,所以长程记忆选了时序库而不是硬扛向量检索——「越来越懂我」和「从不胡说」由不同的层负责,才能同时变好。

06

规划:两条战线

B 端和 C 端各有一场要赢的仗,两条线共用同一套底座。

B 端酒店分销:小团队 supervise agent 集群

目标是用 2–3 人的核心团队 supervise 一个 agent 集群,做出传统竞对数百人研发团队的交付效果。现在跑着的这个 agent team 是可行性样本:agent 产出过门禁、分层验证与独立评测,人守住评审与方向。要扩的是供应商覆盖和交易链路,方法已经在生产里验过。

C 端travel agent:垂直行业挑战通用 agent

在酒旅行业内,同时挑战专业 personal agent 和头部通用 agent。toC 打中立牌:跨供应商、事实优先、每个数字可溯源,用户利益与任何单一平台解耦——这是通用 agent 结构上给不了的承诺。toB 打可控性与前沿性能:WriteGate、审计账本、自主性分级,企业最在乎的恰好是已经建好的这套。


结语

如果你们在做类似的事,我想聊聊——danceiny@gmail.com · 18602170534。