智能体工作流
TensorSharp.AgentHost 把本地模型的一次回复变成有界的生成 → 检查 → 运行 → 修复 → 回答循环。它只在需要时加载 Agent Skills(智能体技能),通过五个内置代码工具处理文件,在操作系统沙箱中运行检查,并向普通 CLI、Web UI、Ollama 或 OpenAI 客户端返回完成的产物。
一轮请求里发生什么
低成本公布能力
TensorSharp 在提示词里只放入每个可达技能的名称与描述。选中技能只表示优先使用并允许访问,不会加载其说明正文。
按需加载说明
支持工具往返的模型判断某项技能适用时,会调用
skills_read(skill, "SKILL.md")。TensorSharp 在进程内应答这个内置调用,把结果加入同一段对话,再次生成。完成实际工作
若运维方启用了
--code-exec,模型便可在请求或聊天工作区中检查、编辑、新建、打补丁并测试文件。技能脚本也能参与,但必须单独选择允许执行。返回普通答案
客户端收到最终完成结果,而不是 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 而不是页面:手机上是它自己的页面,按拇指而不是鼠标与宽窗口来排布,但绑定同一套 WebUiChatService 与 SkillsService 路由。
模型支持断点续传与 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_list 与 skills_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 会记录这一限制,而不是假装代码执行可用。