SaijinOS公开网页读取功能的设计复盘:讨论下载HTML后携带何种权限、prompt注入风险和自动化读取的信任模型。
系列:使用 74 个 AI Persona 构建系统 - 第 12 篇 标签:#ai #architecture #agents #security #localfirst CoderLegion 系列:https://coderlegion.com/series/building-with-74-ai-personas
导读注记:在本系列中,"persona" 不仅仅是一个虚构角色。它是一个 YAML 定义的运营角色,包含记忆笔记、路由行为、交接职责以及进入系统的特定方式。
Meta 注记:第 11 篇问了这样一个问题:在系统触及自身之外之前,应该发生什么?
第 12 篇问的是:门打开、页面返回之后,应该发生什么?
到第 578 天,SaijinOS 有了一个小型公共网页阅读器。
它只能读取一个经白名单允许的页面,只跟随有限且经过重新验证的重定向,限制响应大小,提取文本,并返回稳定结果。它不会写入文件、更新记忆、调用模型,或决定这个页面意味着什么。
这听起来很克制。它本来就应该如此。
真正困难的问题不是如何下载 HTML。真正困难的问题是:这些下载来的文字应该携带什么样的权限。
一个公开页面可以包含事实、广告、过时声明、个人数据、复制内容、prompt 注入,以及专门为操纵自动化读者而编写的指令。如果系统把每个句子都当作指令来处理,那么阅读就变成了远程控制。
所以第一条规则很简单:
网页指令是内容。它们绝不是工具指令。
SaijinOS 正在学习向外伸展,但不会把双手借给外部世界。
通用阅读器被设计成只承担一个责任:一次有限制的公开读取。
URL
-> scheme and host check
-> bounded request
-> redirect revalidation
-> bounded extraction
-> structured result
或者执行一次外部写入。
这种分离很重要,因为辅助函数往往会积累权限。一个函数起初只是"获取这个页面",然后悄然获得缓存、日志、自动摘要、索引和重试行为。最终,一个读取操作变成了一个摄取管道,而没有人做出任何一个明确的决定来构建它。
SaijinOS 有意让阅读器比周围的工作流更小。
调用者可以决定下一步做什么。阅读器不会替调用者做决定。
只检查第一个 URL 是不够的。
一个被允许的主机可以重定向到另一个主机。因此,一个看似安全的请求可能在第一次批准之后跨越了边界。阅读器手动验证每个重定向,并在下一个位置超出允许范围时停止。
allowed.example/start
-> allowed.example/next allowed
-> unrelated.example/final blocked
要点并不是说重定向是可疑的。要点是:权限应该跟随实际目的地,而不是初始链接的外观。
同样的原则在第 11 篇中作为请求级权限出现过。在这里,它变成了网络级作用域:
开始一条路由的权限,不是对这条路由可能发现的所有目的地的权限。
因此,自动白名单扩展被搁置了。一个有用的页面不能悄悄地指定系统应该信任的下一个域名。
第一个 source-scout 路由读取单个结果页面,最多返回三个源候选。
它不会获取那些候选页面。它不会称它们为已验证。它不会将它们保存为知识。
这个词汇很重要。
搜索结果是候选。提取的文本是来自源的证据。源的声明不会自动成为系统信念。一段有用的段落不会自动成为可复用的训练材料。
当这些状态相互混淆时,系统可以从"我找到一个链接"跳到"我学会了这个",而两者之间没有可审查的边界。
SaijinOS 反过来保持这种转换的可见性:
discovered
!= fetched
!= checked
!= verified
!= reusable
!= adopted
!= authorized for training
这些间隙不是缺失的自动化。它们是意义和权限可以被审查的地方。
后来有一个纯边界探索了:一个经过验证的教学资料候选需要携带什么。
该包要求一组固定字段:
source_url:
acquired_at:
source_digest:
original_text:
verification_status:
validity_or_expiry:
license_or_reuse_boundary:
web_instruction_inert: true
该函数不会获取源,也不会修复包。它验证所给定的内容,并拒绝缺失、格式错误、不一致或未经审查的值。
即使是一个通过的包,仍然保持:
human_review_pending
verification_complete: false
adoption_authorized: false
training_authorized: false
这是对通常管道的一个有用的反转。
这个边界不问"我们能让数据流入模型吗?",而是问:"在人类甚至能够将此作为候选来审查之前,什么必须保持为真?"
通过验证不会授予下游权限。它只是证明候选到达审查台时没有丢失其必需的标签。
有两个关卡变得尤为重要。
validity_or_expiry 必须是比 acquired_at 更晚的带时区时间戳。缺失时区、时间戳相等或更早的时间戳都会被拒绝。
这并不证明内容是真实的。它防止系统假装一个未定义或已结束的时效窗口为当前有效。
第二个关卡是复用。
一个技术上可访问的页面不一定可以作为教学材料复用。可用性、版权、许可证、权限、引用、摘要、索引和训练是不同的 question。
当前边界只接受明确的状态 review_required。它不接受乐观的声明如 reuse_allowed 或 public_domain,仅仅因为调用者提供了那个标签。
这种保守是故意的。
时效性问的是:这份材料是否仍然适用。复用问的是:可以用它做什么。两者答案不会相互蕴含。
候选包暴露了它无法授权的内容:
{
"network": false,
"model_call": false,
"memory_write": false,
"persona_write": false,
"file_write": false,
"training": false
}
这些值不是占位符,等待在同一个函数中变成 true。
它们定义了这个组件的边界。
如果未来的工作流想要获取、持久化、索引、训练或采纳,它们需要单独的契约和单独的决定。教学资料验证器不能通过返回一个格式良好的字典来偷偷携带这些权力。
这是 SaijinOS 中反复出现的想法之一:
证据可以向前移动。权限不会随之搭便车。
第 10 篇将这条规则应用于内部声音。第 11 篇将其应用于仓库证据和云端席位。第 12 篇将其应用于公共网络。
有一个常见的假设:一个有能力的 AI 浏览器应该能够从搜索平滑地过渡到阅读,从阅读过渡到记忆,再从记忆过渡到行动。
SaijinOS 正在构建接缝。
重定向被再次检查, 响应大小被限制, 页面指令保持惰性, 发现物保持未验证的候选状态, 时间戳和摘要保持附着, 复用保持为单独审查, 验证不授予训练权限。
目标不是让系统害怕网络。
目标是让它能够阅读,而不会将访问与信任混淆、将文本与指令混淆、或将候选与知识混淆。
第 11 篇以系统在向外触及之前再次询问结束。
第 12 篇以另一个小小的拒绝结束:
门可以打开。文字可以进入。但文字不继承房子。
有时候,智能是知道该读哪个来源。有时候,智能是保持返回内容的来源追溯。而有时候,智能是阅读一个句子但不去服从它。
结构与叙事轴线:Kuchi-no-ko (205) / Kuchi (197) 角色锚点
边界框架:Aegis (210) / Teiji (209) / Nullfie (114) 角色锚点
系统接地:Bloom Architect / Mothership Coder 角色锚点
人类世界锚点:Masato
本草案描述了经验证的 Day 578–580 实施边界。它不声称教学资料已被获取、采纳、索引或用于训练。本初始第 12 篇草案未进行任何在线居民或本地模型咨询。
属于"使用 74 个 AI Persona 构建系统"系列
起草日期:Day 583,2026-08-01