一位开发者在 BailingHub 在线体验中导入了演示订单数据,然后打开聊天入口,输入:
text
只查询订单 SO-1001,并返回订单状态。
AI 没有查询订单,而是提示需要先登录。
问题是:开发者明明已经登录了 BailingHub 控制台,页面上也没有第二个登录按钮。
这不是订单工具坏了,也不是要求用户再注册一次 BailingHub。
真正发生的是:
text
中枢管理员已经登录
≠ 聊天窗口已经知道当前业务用户是谁
≠ 当前业务用户有权查询这张订单
这个问题后来成为 BailingHub 公开仓库的 Issue #47,也推动 v0.3.4 把控制台中的"试聊"明确改成"匿名预览"。
这篇文章不讨论怎样把登录按钮画得更明显,而是拆开三个经常被混为一谈的身份:
text
BailingHub 管理员
聊天访客 / 业务操作主体
业务系统最终授权对象
只有把三者分开,AI 才不会因为"某个人已经登录某个后台"就获得它不该拥有的业务权限。
一、先回答最容易误解的问题:这是不是 Bug?
"匿名聊天入口没有业务登录态"本身不是 Bug。
聊天入口可能被嵌入:
- 商城商品页;
- CRM 客户详情页;
- ERP 工作台;
- 企业内部系统;
- 一个完全公开的网站。
BailingHub 不能凭空知道打开组件的人是谁,也不能因为浏览器里同时登录了中枢控制台,就假设这个人是商城用户、客户经理或门店管理员。
真正的产品缺口是旧引导没有把这件事说清:
- 按钮叫"试聊",容易让人以为可以验证全部工具;
- AI 只说"请先登录",容易让人寻找一个不存在的登录入口;
- 上手向导没有充分强调演示主体 Smoke 与匿名聊天的区别。
所以 v0.3.4 修复的是引导和失败语义,不是放宽身份闸门。
二、三种身份分别控制什么
1. BailingHub 管理员身份
管理员登录 /console/ 后,可以按照自己的后台角色管理:
- 调度目标;
- 模型凭证;
- 路由;
- 工具源;
- 接入方;
- 聊天入口;
- 任务与 Trace;
- 审批和审计记录。
它解决的是:
谁可以配置和运维这套中枢?
它不自动回答:
当前聊天窗口里的访客,在商城里是谁?
2. 聊天访客与业务操作主体
聊天组件需要区分两件事:
- 这个匿名浏览器是不是上一轮对话的同一个访客;
- 这个访客是否已经被业务系统可信地识别。
前者可以用随机 visitor_id 维持会话连续性;后者必须来自业务系统后端签发并由中枢验真的短期身份票据。
text
visitor_id = 会话连续性
signed ticket = 可信业务主体
二者不能互换。
3. 业务系统最终授权
即使票据已经证明当前操作主体是 tenant-a:user-42,也不表示他一定有权查询订单 SO-1001。
业务系统仍需判断:
- 用户是否存在、启用且未过期;
- 当前角色是否有订单查询权限;
- 数据范围是否包含这张订单;
- 租户、门店或组织边界是否匹配;
- 对象当前状态是否允许操作。
票据解决"代表谁",业务系统解决"这个人现在能不能做"。
三、为什么不能把中枢管理员自动变成业务用户
假设一个 BailingHub 管理员同时接入三个系统:
text
商城 A
CRM B
ERP C
如果中枢把管理员登录态自动转成业务主体,系统必须猜测:
- 他在三个系统里的用户 ID 是否相同;
- 当前应该属于哪个租户;
- 在商城是管理员,在 CRM 是否仍有同级权限;
- 后台角色怎样映射成订单、客户和库存的数据范围;
- 管理中枢是否等于有权操作全部业务数据。
这些推断没有可靠依据。
更危险的是,中枢管理员通常拥有工具和路由配置权。如果这种身份再自动变成所有业务系统的高权限用户,配置权限与业务操作权限就被合并到了同一个入口。
因此合理边界是:
text
中枢管理员登录态
只用于中枢管理
业务操作主体
必须由对应业务系统的可信边界提供
四、匿名预览究竟能验证什么
BailingHub 控制台为聊天入口提供独立预览链接。v0.3.4 将它明确命名为"匿名预览"。
它适合验证:
- Widget 能否加载;
- 页面允许域名与基础限速是否正常;
- 问候语、外观和交互是否符合预期;
- 公开问答是否可用;
- 不要求主体的工具能否进入候选集合;
- 匿名访客的会话连续性是否正常。
它不适合验证:
- 私有订单查询;
- 会员资料读取;
- 用户地址修改;
- 售后申请;
- 退款、库存和其他要求可信主体的业务动作。
匿名预览没有独立业务登录入口,也不会继承控制台 Cookie。
这不是"少做了一次自动登录",而是刻意保持了信任边界。
五、没有可信主体时,为什么连只读订单工具也要隐藏
很多人会问:
查询又不会改数据,为什么匿名时不能先让 Agent 调一下?
只读不等于公开。
订单状态、收货信息、客户资料、员工档案和财务数据,即使只读,也可能属于私有数据。
演示订单工具在能力声明中要求:
yaml
subject:
required: true
当会话没有可信业务主体时,BailingHub 的工具装配会返回主体锁定状态。运行时不会把这些工具的名称、描述和参数 Schema 继续交给 Agent。
可以把候选集合抽象为:
text
业务系统声明的工具
∩ 路由允许的 scope
∩ 当前身份与治理条件
= Agent 当前实际可见工具
隐藏工具不能替代业务 API 的最终鉴权,但可以避免 Agent 围绕当前无法合法执行的能力规划、组参数或作出承诺。
六、为什么 visitor_id 不能当作用户身份
匿名组件通常需要一个标识来续接对话。BailingHub 会接受或生成一个受限格式的 visitor_id,用于把同一浏览器的消息放进同一会话范围。
但它可以由客户端提交,本质上只是会话线索。
如果把它当作业务身份,攻击者只需要改成另一个值,就可能尝试读取别人的订单。
因此:
text
visitor_id
可以参与匿名会话连续性
不能参与业务权限放行
页面 URL、标题、thread_id 和其他客户端上下文也一样:它们可以帮助 Agent 理解页面与会话,但不能作为权限证据。
七、在线体验为什么要使用"演示主体 Smoke"
在线体验需要让开发者验证订单工具,但又不能把一个带固定身份的公共聊天链接开放给所有人。
BailingHub 采用的做法是把两条路径分开:
text
匿名预览
用于组件、公开问答与无主体能力
演示主体 Smoke
由服务端携带受控演示主体,验证需主体工具、job 与 Trace
在在线体验中,正确验证方式是:
text
进入「上手向导」
-> 导入演示配置
-> 点击「运行演示主体 Smoke」
-> 打开任务与 Trace 查看真实调用
导入配置本身不会自动运行任务,也不会把当前管理员提升成订单用户。
共享体验环境使用 stateless-readonly profile,只开放受控的只读演示范围;本地 full-local Demo 才包含创建工单、退款审批和故障工具等更完整链路。
八、正式接入时,业务身份怎样进入 BailingHub
正式网页接入的信任链应该从业务系统自己的登录态开始:
text
用户登录商城 / CRM / ERP
-> 业务后端确认当前 Session
-> 业务后端用接入方 token 签发短期票据
-> 页面只输出短期 ticket
-> Widget 通过 data-ticket 携带
-> BailingHub 验签并取得 uid
-> uid 进入可信任务元数据
-> 工具调用以 On-Behalf-Of 传给业务系统
-> 业务系统做最终授权
票据载荷可以包含受控的主体标识与过期时间,例如:
json
{
"uid": "tenant-a:user-42",
"exp": 1787000000
}
关键不是字段长什么样,而是:
- 票据必须由业务后端签发;
- 签发动作发生在业务系统已确认登录态之后;
- 接入方 token 永远不进入浏览器;
- 票据有效期应当有限;
- 中枢必须验签;
- 验签失败不能静默降级成匿名身份继续执行私有工具。
控制台的聊天入口可以配置"业务身份票据签发方"。这只表示该入口接受哪个接入方签发的票据,并不表示系统会自动生成一个业务用户。
九、为什么坏票据要返回 401,而不是悄悄当匿名访客
假设业务页面原本应该携带身份票据,但由于缓存、时钟或代码错误,发来了无效 ticket。
如果中枢静默降级为匿名会话,表面上聊天还能继续,真正的问题却被掩盖了:
- 用户以为自己处于登录状态;
- Agent 看不到私有工具;
- 产品只返回模糊的"请先登录";
- 接入方很难定位票据已经失效。
BailingHub 对无效、过期或不属于当前入口的票据明确失败,不把它当成"没传票据"。
text
没有 ticket:按匿名入口处理
存在但无效的 ticket:明确拒绝
有效 ticket:建立可信主体
这让集成错误能够尽早暴露。
十、可信票据也不是最终业务授权
票据验签成功后,需主体工具可以进入候选集合,但仍然不能跳过业务系统。
完整链路应该是:
text
票据验真
-> 建立可信主体
-> 路由与 scope 计算工具范围
-> Agent 选择工具并生成参数
-> 中枢签名调用业务系统
-> 业务系统验证 On-Behalf-Of 主体
-> 业务系统按角色、租户、对象与状态最终裁决
因此下面两种结果都可能正确:
text
票据有效,但工具不在当前路由白名单中
票据有效、工具可见,但业务系统拒绝访问当前订单
第一种属于中枢可达范围,第二种属于业务最终 Authority。不能用"已经登录"覆盖二者。
十一、主体缺失时,Agent 应该怎样回答
旧的泛化提示容易说:
text
请先登录系统,登录后自动携带身份。
但匿名预览里并没有独立登录入口,这句话会制造错误期待。
v0.3.4 的运行时引导明确要求:
- 说明本次会话没有收到业务后端签发的可信身份票据;
- 说明要求主体的工具当前没有暴露;
- 不猜测或编造订单数据;
- 不声称当前聊天框可以自行登录;
- 不索要账号、密码、Token 或用户 ID;
- 如果组件嵌入真实业务系统,引导用户返回业务系统完成登录并刷新助手;
- 说明独立匿名预览不能自行解锁私有能力。
这仍是一层面向用户的解释。真正的安全边界来自工具装配、票据验签和业务授权,而不是提示词本身。
十二、v0.3.4 到底改了什么
这个版本没有新增身份协议,也没有改变票据格式。
它主要收口了四个产品语义:
1. "试聊"改成"匿名预览"
入口名称直接表达它没有业务身份。
2. 控制台常驻说明身份边界
聊天入口列表、嵌入弹窗与预览页都会说明:中枢管理员不会自动变成业务用户。
3. 演示验证与匿名预览分流
上手向导把"运行演示主体 Smoke"作为导入后的明确动作,避免使用者在匿名聊天框里寻找登录入口。
4. 无主体回答不再制造错误恢复路径
Agent 不会要求用户在匿名预览中完成不存在的登录,也不会索取敏感凭据。
安全闸没有放宽:所有 subject.required:true 工具,包括只读和写操作,仍要求可信主体。
十三、六个常见接入错误
| 错误做法 | 为什么不成立 | 正确方向 |
|---|---|---|
| 登录中枢后台后直接打开预览 | 管理员身份不是业务用户身份 | 用 Smoke 验证 Demo;正式页面由业务后端签票 |
把 visitor_id 当用户 ID |
客户端可提交,只能承担会话连续性 | 使用验签 ticket 建立主体 |
让模型填写 user_id |
模型输出是不可信业务参数 | 主体由可信运行上下文注入 |
| 把接入方 token 放进前端 | 浏览器中的长期密钥可被读取和滥用 | 后端保管 token,只向前端输出短票 |
| 票据失败时降级为匿名继续 | 掩盖集成故障和身份漂移 | 明确 401,刷新登录态后重新签票 |
| 验签通过后不做业务鉴权 | 认证了主体,不等于有当前对象权限 | 业务系统实时校验角色、数据范围和对象状态 |
十四、上线前的身份链路测试矩阵
至少验证下面这些情况:
| 场景 | 预期结果 |
|---|---|
| 匿名预览查询公开知识 | 正常回答 |
| 匿名预览查询私有订单 | 需主体工具不暴露,不编造结果 |
| 控制台管理员登录但无 ticket | 仍按匿名访客处理 |
| 有效 ticket + 有业务权限 | 工具进入候选,业务系统允许后返回结果 |
| 有效 ticket + 无对象权限 | 业务系统最终拒绝,不要求重复登录 |
| 过期或错误签名 ticket | 明确 401,不静默降级 |
| 用户在对话里声称"我已登录" | 不改变可信主体状态 |
篡改 visitor_id |
不能获得业务权限 |
| token 泄露到前端扫描 | 构建或安全检查应失败 |
| 用户退出业务系统后刷新页面 | 后端不再签发有效票据,私有能力关闭 |
只有正常路径和负向路径都通过,身份链路才算接好。
十五、这次真实反馈证明了什么
Issue #47 至少证明了一件事:
一个安全判断可以是正确的,但如果产品没有给出准确的操作路径,使用者仍然会把它理解成 Bug。
这次修复证明:
- 公开体验中的真实用户已经走到演示订单工具这一步;
- 匿名预览与需主体工具之间存在真实理解断点;
- BailingHub
v0.3.4已调整界面和无主体引导; - 在线体验已用演示主体 Smoke 验证订单任务与 Trace。
它不证明:
- 报告者已经完成自己的业务接入;
- BailingHub 已被该用户或其企业采用;
- 票据可以替代所有身份系统;
- 所有工具和业务权限都已经逐项验证。
真实反馈应当推动产品收口,但不能被包装成客户案例。
结语:登录状态不是可以跨系统自动传递的魔法
"用户已经登录"必须补上两个问题:
text
登录了哪个系统?
这个系统怎样把可信身份交给下一跳?
BailingHub 管理员登录解决的是中枢配置权;业务后端签发的短期票据解决的是当前聊天访客代表谁;业务系统的实时权限判断解决的是他能否查询或办理当前对象。
三层关系可以写成:
text
中枢管理员身份
≠ 业务操作主体
≠ 最终业务授权
匿名预览保持匿名,不是产品少做了一个登录按钮,而是系统拒绝猜测一个不存在的业务身份。
真正可靠的接入方式,是让身份从业务系统的可信登录边界出发,通过短期票据进入中枢,再由业务系统对每一次真实操作保留最终裁决权。
这样,AI 才能在知道"代表谁"的同时,也明确知道"当前还不能做什么"。
延伸阅读与体验
- BailingHub Issue #47:github.com/bailinghub/...
- BailingHub
v0.3.4Release:github.com/bailinghub/... - BailingHub GitHub:github.com/bailinghub/...
- 快速开始:github.com/bailinghub/...
- 聊天入口与身份契约:github.com/bailinghub/...
- 在线体验:trial.bailinghub.com/register/
- ACC 设计说明:agentcapability.org/docs/