智能体工作流

TensorSharp.AgentHost 把本地模型的一次回复变成有界的生成 → 检查 → 运行 → 修复 → 回答循环。它只在需要时加载 Agent Skills(智能体技能),通过五个内置代码工具处理文件,在操作系统沙箱中运行检查,并向普通 CLI、Web UI、Ollama 或 OpenAI 客户端返回完成的产物。

一轮请求里发生什么

  1. 低成本公布能力

    TensorSharp 在提示词里只放入每个可达技能的名称与描述。选中技能只表示优先使用并允许访问,不会加载其说明正文。

  2. 按需加载说明

    支持工具往返的模型判断某项技能适用时,会调用 skills_read(skill, "SKILL.md")。TensorSharp 在进程内应答这个内置调用,把结果加入同一段对话,再次生成。

  3. 完成实际工作

    若运维方启用了 --code-exec,模型便可在请求或聊天工作区中检查、编辑、新建、打补丁并测试文件。技能脚本也能参与,但必须单独选择允许执行。

  4. 返回普通答案

    客户端收到最终完成结果,而不是 TensorSharp 内部工具调用。调用方自带的工具绝不会由 TensorSharp 执行;这些调用仍会正常返回给调用方处理。

🎯

当前范围是单个模型与单条进程内工具循环。TensorSharp 不会生成多个智能体,也不会把任务委派给子智能体;每条命令执行前也没有交互式审批队列。运维方在 CLI 或服务器启动时授予或拒绝技能、脚本执行、代码执行、联网与安装能力;之后内置工具只能按该策略运行,否则拒绝。

iPhone 与 iPad 上的 TensorAgent

TensorAgent 将本地聊天与智能体体验打包为 .NET MAUI iOS/iPadOS 应用。引擎以 iOS .xcframework 静态链接,在真机上使用 ggml_metal。应用与 CLI、服务端共享与宿主无关的聊天流水线(TensorSharp.Chat);由于 iOS 没有 ASP.NET Core runtime pack,UI 通过进程内 loopback server 提供。共享的是 API 而不是页面:手机上是它自己的页面,按拇指而不是鼠标与宽窗口来排布,但绑定同一套 WebUiChatServiceSkillsService 路由。

模型支持断点续传与 SHA-256 校验并下载到设备;会话可跨应用重启保留;照片、相机、视频、文件和听写使用同一套聊天附件流程。由于 iOS 不能启动子进程,TensorAgent 的 shell、Python 与 JavaScript 集成由运行时提供,并明确报告能力边界。

手机相对桌面多出三条约束,以及应用对每一条的处理:

约束应用的处理
回答过程中屏幕被切走生成过程归宿主侧的管理器所有,而不属于 WebView——视图离开窗口后 WebKit 会挂起该页面。应用切到后台时这一轮继续生成,返回时页面重新挂接上去。
每次启动的第一条消息都要为整段共享前缀买单所有会话共享的那段提示词末尾的状态,会按模型持久化到磁盘,并在下次启动时于准入阶段恢复。在 iPhone 17 Pro Max 上以 Qwen3.5 9B 实测:原本 54 秒的冷启动首条消息,变成 1.2 秒预热加约 0.6 秒的首条消息。
iOS jetsam 杀进程时既无栈也无消息引擎的内存策略按 jetsam 实际计费的口径设定——被 wire 住的文件页算在设备头上而不是进程头上——因此缓存从小起步按需增长,单个请求只预留有界的回复长度,收到内存警告时释放那些只为下一次请求提速的部分。

构建、模拟器、真机与验证步骤见 TensorAgent README

Agent Skills 与渐进式披露

一个技能就是一个目录:必需的 SKILL.md,加上说明会用到的脚本、参考资料与素材。TensorSharp 遵循 Agent Skills 规范,可直接加载公开技能仓库,无需改写其目录布局。

pdf/
├── SKILL.md
├── scripts/
│   └── extract_tables.py
├── references/
│   └── forms.md
└── assets/
    └── template.pdf
层级模型会看到什么何时看到
元数据name + description选中技能与可发现技能都会预先给出;这就是正常路径的提示词成本。
说明完整的 SKILL.md 正文仅当模型通过 skills_read(skill, "SKILL.md") 激活该技能之后。
随包文件参考资料、脚本与素材只索引路径和大小;内容由 skills_read 按 48 KB 分页读取。

正常元数据块约使用上下文窗口的 2%,并限制在大约 1,024–10,000 token。旧版“把所有选中技能正文预先内联”的行为默认关闭。无法携带并解析工具声明的模型家族没有机会调用 skills_read,因此 TensorSharp 会在有界回退预算内直接内联所选技能正文,同时不再宣传根本无法加载的技能。

内置技能工具是 skills_listskills_read。只有传入 --skills-allow-exec 才会出现第三个工具 skills_run。技能脚本默认不允许运行,并且始终与模型生成代码的执行权限分开控制。

五个代码工具,默认关闭

--code-exec 会加入一套补丁优先的代码工作面。它不要求安装技能;仅安装或选中技能也不会自动开启它。

工具用途关键边界
read_file按行号读取工作区中的真实字节。输出有界;路径必须留在工作区内。
edit_file在一个文件中精确替换一段字符串。找不到或命中多处时拒绝执行,不做猜测。
write_file新建文件,或有意整体替换文件。限制在工作区内,并报告重写范围。
apply_patch通过带锚点的 hunk 新建、修改、重命名或删除多个文件。原子操作:全部 hunk 成功,否则一个也不落地。
shell运行测试、命令与生成的程序。有超时与输出上限;受支持主机上必须沙箱化,否则拒绝。

失败结果专门为后续修复而设计。若诊断定位到工作区内的常规源文件,结果会附上有界的源码片段,并要求先做最小精确修改再重新运行。语法检查、允许时自动补齐缺失依赖、以及从已安装库中探测真实 API,都能减少无意义的模型轮次。

工作区生命周期与产物

入口工作区生命周期结果
CLI / 交互聊天在进程或聊天会话期间持续存在。后续工具调用能检查或修复先前调用写下的文件。
内置 Web UI在该 Web 聊天会话期间持续存在。显示实时的编写 / 运行状态、有界输出与生成文件下载标签。
OpenAI 与 Ollama HTTP 聊天一次请求的所有内部工具轮次共享一个私有工作区;响应结束即删除。同一请求内可以反复修复,而不同请求保持无状态。
未开启代码执行时的 skills_run每次调用使用新的临时目录,返回后删除。脚本不会意外共享状态。

开启代码执行后,技能脚本会与五个代码工具共享同一个请求 / 聊天工作区。服务端会把生成的文件复制到有界产物存储中;Web UI 提供安全下载链接,产物响应始终作为附件发送并禁用内容嗅探。

“沙箱化,否则拒绝”的安全模型

是否允许执行由运维方决定,不是请求字段。在 macOS 与 Linux 上,模型生成命令和已获准的技能脚本默认具有工作区写入边界、不可读的用户主目录、清理后的环境变量,并且不可联网。进入操作系统沙箱之前,进程内还会再次检查路径。

平台模型生成代码技能脚本
macOS使用 sandbox-exec;无法提供隔离时拒绝运行。默认 --skills-sandbox required;要么沙箱运行,要么拒绝。
Linux要求 bwrap 0.12.0 或更高版本;否则拒绝。默认 required 模式下同样要求安全版本的 bwrap
Windows尚未实现文件系统 / 网络沙箱。必须显式传入 --code-exec-unconfined,这会有意授予该进程可及的文件与网络范围。作业对象只能约束进程树,不能限制文件和套接字。默认 required 会拒绝;--skills-sandbox preferred 是明确接受较弱隔离的选择。
⚠️

沙箱并不等于一次性虚拟机。macOS 为兼容性有意保留共享 /private/tmp 与部分本地 Unix IPC。Seatbelt 限制会传递给子进程,普通进程组也会被停止,但有意脱离的子进程可能活过本次请求;每次工具结果都会报告这一缺口。Linux 即使禁止 IP 网络,也仍共享宿主网络命名空间的某些部分。每项平台缺口都必须认真对待。不要在他人可访问的服务器上启用非受限执行。

网络与软件包安装是彼此独立的授权

选项默认授予什么
--code-exec-allow-network关闭让所有模型生成命令使用不受域名过滤的宿主 IP 网络,包括 LAN / loopback 服务。
--skills-allow-network关闭只为已经获准执行的技能脚本开放网络;不会影响 shell
--code-exec-allow-install关闭允许宿主代为执行可识别的 pip / npm 安装。宿主读取并校验包名,只用预构建 wheel / 禁用 npm 脚本,并从模型命令中移除安装部分。

--code-exec-packages--code-exec-install-index--code-exec-install-domains 约束的是宿主安装器。一旦开放模型命令的无限制网络,它们就不再是安全边界,因为生成代码可以直接下载产物。技能脚本与代码工具的网络开关有意彼此独立。

启动一个智能体会话

使用技能并不要求执行代码:

dotnet run --project TensorSharp.Cli -c Release -- \
  --model models/model.gguf --backend ggml_metal \
  --skills-dir ./skills --skill pdf -i

显式加入五个代码工具。下例仍然关闭命令网络与软件包安装:

dotnet run --project TensorSharp.Cli -c Release -- \
  --model models/model.gguf --backend ggml_metal \
  --skills-dir ./skills --skill pdf --code-exec -i

也可以为 Web UI 与兼容 API 托管同一套循环:

dotnet run --project TensorSharp.Server.Host -c Release -- \
  --model models/model.gguf --backend ggml_cuda \
  --skills-dir ./skills --code-exec

# 浏览器 UI:http://localhost:5000/
# 存活检查:  http://localhost:5000/health

Linux 请先安装 bwrap 0.12.0 或更高版本。在 Windows 上,除非运维方有意加入 --code-exec-unconfined,否则代码执行不可用。不要把这个 Windows 逃生开关复制到共享服务器上。

从普通 HTTP 客户端使用技能

服务器启动时必须配置技能注册表。客户端随后在普通聊天请求上选择技能;TensorSharp 在内部处理自己的技能 / 代码调用,并返回完成后的响应。

{
  "model": "local",
  "messages": [
    { "role": "user", "content": "提取表格并总结结论。" }
  ],
  "skills": ["pdf"],
  "skills_discovery": false,
  "stream": true
}

skills_discovery 默认为 true。代码执行没有按请求开启的字段:运维方要么以 --code-exec 启动宿主,要么五个工具根本不会出现。智能体循环默认最多 8 个内部轮次;开启代码执行后默认 24 个;--skills-max-rounds 可明确设置 1–64 的上限。

模型家族限制

进程内循环要求模型家族既能携带工具声明,也能解析工具调用。不支持这种往返的家族会以内联方式获得选中的技能说明作为回退,但不会得到五个代码工具。TensorSharp 会记录这一限制,而不是假装代码执行可用。