自定义 Agent
系统提示词、技能、工具、风险上限和触发器的可保存组合,可通过 CLI、REPL、HTTP、Workflow 和 cron 运行
🟢 可配置:自定义 Agent 是一个配方,不是独立的运行时。 它运行在同一个 agent 循环、同一个技能注册表、同一个资金确认闸门上, 与 REPL 会话完全一致。
自定义 Agent (Custom Agent) 是一份保存好的组合:
- 一段
system_prompt(Agent 运行时的指令) - 一份
skill_ids子集(runner 激活哪些 DomainSkill) - 一份
tool_names+tool_sets子集(runner 暴露哪些工具) - 一个
risk_tier_max上限(1 只读 → 4 仅手动)。Web UI 向导把它呈现为三档 :: 只读、不动资金、可动资金 :: 其中"可动资金"再分 tier 3(确认制现货:swap、buy、sell)或 tier 4(全部资金操作,含永续、提现、autopilot)。定时和事件触发的 agent 无法动用资金,且每次资金操作仍需确认。 - 一个
discovery_mode(runner 自我扩展的激进程度) - 一组
triggers(manual、cron、event) - 自由形式的
metadata
这份组合持久化到 SQLite 的 agent_definitions 表。
你可以从 REPL /agents run、CLI minara agents run、HTTP
POST /v1/agents/:id/runs、Web UI 的 Run 抽屉、workflow 步骤
(agent_turn { agent_id }),或 cron / event 触发器运行它。
自定义 Agent 在概念上更接近 Claude Code subagents, 而不是 Anthropic 的 Managed Agents API。它们在与主 agent 相同的 进程内本地执行,共享同一份技能目录,继承同一组安全边界。 它们不是沙箱化的第三方运行时。
运维者为什么想要它
- 复用:把一个高频任务编码一次。"每日 ETH 早报"、 "每周组合复盘"、"链上流入监控",每一个都是命名 Agent, 一键启动。
- 限定工具面:研究型 Agent 只需要只读技能(不需要
swap_tokens)。 财库型 Agent 只需要 Hyperliquid 永续。 技能集越小,系统提示词越紧凑、无关工具调用越少、每轮 token 成本越低。 - 触发器:挂上
cron: "0 9 * * *"的 Agent 每天早晨自动运行, 无需运维干预。挂上event: { event_name: "price.alert" }的 Agent 在事件总线发布匹配事件时触发。 - 可被 Workflow 编排:多步 workflow 可以引用
agent_turn { agent_id: "research-bot" }, 不必把研究提示词内联进去。Workflow 作者拥有流程, Agent 拥有推理。 - 可分享:把一个 JSON 文件丢进
~/.minara/agents/, 下次启动时 loader 会拾起。把你的research-bot导出给队友, 对方实例加载后source: "file:..."。
三种 discovery 模式
discovery_mode 控制 runner 在执行时如何对待 skill_ids 和 tool_names。
新建 agent 默认 free_discovery:和主助手一样,agent 自行发现所需技能,
Web UI 向导无需你预先勾选。工具由所选技能加上 risk_tier_max 上限决定,
因此 tool_names、tool_sets、discovery_skill_pool 是高级字段,只能通过
JSON 文件加载或 HTTP API 设置,不在向导里暴露。
constrained
硬白名单。Runner 完全按照声明的 skill_ids 激活,
完全按照声明的 tool_names(与 tool_sets 的并集取交集)暴露工具。
activate_skills 元工具被禁用,LLM 无法在中途自我扩展。
生产可靠性场景请选这个。Agent 每次都按同样的形状运行。 易于审阅、易于测试、易于做预算。
scenario_aware
为向后兼容保留,当前行为与 constrained 完全一致。
原先按提示词预加载技能的场景分类器已下线,因此该模式只运行声明的
skill_ids,activate_skills 禁用。已有 agent 保留此值;新建 agent
请选 constrained。
free_discovery(默认)
从声明的种子集合起步,LLM 可以在中途调用 activate_skills 加技能。
受 discovery_skill_pool glob 模式(为空 / 缺失则全目录)约束,
受 risk_tier_max 钳制。
请节制使用。它把整个技能目录作为解空间交给 Agent, 对开放式研究很强,对窄而重复的任务却脆弱。
三种模式都遵守的安全不变量
risk_tier_max在 触发时 由 runner 强制执行, 不只是在 upsert 时。就算你直接在 DB 里UPDATE agent_definitions SET risk_tier_max = 4,cron / event / autopilot 触发依然会 把有效上限钳到 2。- 资金确认门会读取 Agent 运行的上下文。测试运行强制走两步确认,
哪怕环境里设置了
MINARA_SKIP_FUND_CONFIRM=1。 - 归档 Agent 走 fail-closed。任何在飞的
agent_turn步骤 若引用了已归档的 Agent,继续按已保存的 snapshot 运行; 而新提交的运行如果对应 Agent 已归档,立即失败。
触发器
每个 Agent 有一组 triggers。v1 支持四种类型。
| 类型 | 形状 | 何时触发 |
|---|---|---|
manual | { kind: "manual" } | 你在 UI 里点 Run / 输入 /agents run / POST /v1/agents/:id/runs |
cron | { kind: "cron", expr: "0 9 * * *", timezone?: "UTC" } | TriggerManager tick 跨过 cron 表达式 |
event | { kind: "event", filter: { event_name: "price.alert", payload_match?: {...} } } | 事件总线发布匹配事件 |
once | { kind: "once", fire_at: 1717430400000 } | 墙钟时间到达 fire_at(unix 毫秒)。只触发一次,随后 Agent 自动归档 |
安全规则:默认情况下,任何非 manual 的触发器在 upsert 时强制
risk_tier_max ≤ 2,因此定时 / 事件 agent 无法动用资金。agent 可以选择开启
自主资金操作(allow_autonomous_fund_moves: true,且同一次写入需带
confirm_autonomous_fund_moves: true),这会把非 manual 的上限抬到
≤ 3(确认制现货交易)。tier 4(永续、提现、autopilot)始终需要手动触发,
确保它们触发时人在环里。超出上限的写入会被 store 以清晰错误拒绝。
once Agent 就是提醒的实现方式。它只触发一次,然后归档,不再触发。恢复一个
已触发的提醒不会重放它。请重新排期(设置新的 fire_at)或手动运行。要做周期
提醒,改用 cron 触发器。
通知
一次运行结束后,Minara 有两种方式告诉你。
站内通知中心。 右上角的铃铛会显示未读数和最近的 Agent 运行列表,每条都 链接到对应的那次运行。它一直开着、实时更新,并保留一小段可标记已读或清空的 历史。
浏览器通知。 在 设置 → 通用 里(或铃铛上的快捷开关)打开「浏览器通知」, 当 Minara 标签页在后台或被最小化时,就能收到一条系统桌面通知。当你正看着 Minara 标签页时,提醒会改为以站内消息的形式出现。浏览器首次会询问权限。一旦 你关闭标签页或退出浏览器就收不到了,并且页面需要安全上下文(HTTPS),localhost 例外。
哪些运行会通知。 Agent 自己发起的运行会通知:定时(cron)、事件(event)、
一次性提醒、以及 workflow 步骤。你自己发起的运行不会通知(Run 按钮、
/agents run、聊天对话),因为你已经在看着它了。测试运行永远不通知。
按 Agent 控制。 每个 Agent 都有一个「站内通知」设置。可以为话痨 Agent 关掉, 或只在运行失败时通知。新建的 Agent 默认开启。
引用 Agent 的 Workflow
Workflow 的 agent_turn 步骤有两种形态:
// 推荐:按 id 引用已有的自定义 Agent
{ "kind": "agent_turn", "agent_id": "research-bot",
"input": { "ticker": "ETH" } }
// 旧式回退:inline goal,引擎临时拉起一个一次性 Agent,
// 不带任何 scoped 的技能 / 工具子集
{ "kind": "agent_turn", "goal": "summarize recent ETH news" }何时用 agent_turn { agent_id } 而非 tool_call
需要推理、多工具探索、自然语言输出时用 agent_turn:
研究、起草、分类、总结。
输入已知、动作确定的单步操作用 tool_call:
一次 swap、一次 transfer、一次余额查询、一次价格抓取。
工具调用更快、更便宜,且不必让一轮 LLM 重复 confirm 上下文,
继续沿用既有的资金确认闸门。
一个"先做空 ETH,再写策略复盘"的 workflow 拆成两步:
执行用 tool_call { tool: "open_perps_position" },
复盘用 agent_turn { agent_id: "strategy-note" }。
本地自动化技能会自动遵守这套矩阵。
它会暴露自定义 Agent 目录,把"起草"/"研究"/"总结"意图路由到
agent_turn,把资金动作意图路由到 tool_call。
CLI
minara agents 子命令暴露完整生命周期。
| 动作 | 形式 | 用途 |
|---|---|---|
list | minara agents list [--archived] | 列出每一个已注册的 Agent |
get | minara agents get <id> | 以 JSON 形式打印完整 definition |
create | minara agents create --from <file.json> | 从 JSON 文件插入 |
update | minara agents update <id> --from <patch.json> | PATCH;实质改动时递增 version |
archive | minara agents archive <id> | 软删除;卸载所挂的触发器 |
run | minara agents run <id> [--input "..."] [--test] | 启动一次 ad-hoc 运行;事件流到 stdout |
export | minara agents export <id> | 打印 JSON,方便管道写入文件 |
import | minara agents import [--from <file.json>] | export 的逆操作;缺 --from 时读 stdin |
run 同步打开一个事件流,直到 workflow 完成或失败,
然后打印最终的 __adhoc__ 输出 payload。可直接喂给 cron / shell 脚本。
minara agents export research-bot > research-bot.json
scp research-bot.json bob@host:~/.minara/agents/
ssh bob@host minara agents list # research-bot 出现,source=file:...REPL
/agents 斜杠命令是交互对应物。
| 形式 | 行为 |
|---|---|
/agents 或 /agents list | 列出每一个已注册的 Agent |
/agents create | 交互式 collectArgs 流程:名字 → 系统提示词 → 技能挑选 |
/agents run [<id>] [<input>...] | 运行一个 Agent;缺 <id> 时弹出实时选择器 |
/agents archive [<id>] | 归档;缺 <id> 时弹出实时选择器;y/N 确认 |
/agents create 流程走标准的
collectArgs
模式:必填字段一字段一字段地提示;校验失败时只重问坏字段;
连续三次空回答取消。
Web UI
Web UI 在 AUTOMATE 导航组下的 /agents 路由列出自定义 Agent
(和 Workflows、Autopilot 并列)。请打开 Web UI 的 /agents。
- 列表页:每个 Agent 一张卡,含名字、风险上限、discovery 模式、 触发器摘要,以及每卡的 Run / Edit / Archive 动作。 Import 按钮接收 JSON 文件上传,New 按钮打开向导。
- 向导(3 步):第 1 步挑模板(researcher / treasury sentinel / drafting)或"空白"。第 2 步起名、写系统提示词、挑技能(只有 硬白名单模式才显示选择器)。第 3 步选 discovery 模式、风险上限、触发器类型, 安全钳制规则就地显示。
- 详情页:Overview / Definition / History 三个 tab。
Definition tab 显示当前 JSON;PATCH 编辑会原子地递增
version。 - Run 抽屉:从列表卡或详情页打开。内嵌 SSE 事件流显示
workflow:started→workflow:step事件 → 终态workflow:completed/workflow:failed。Run as test (?test=1) 是 一个 checkbox;测试运行在环境变量配了 skip 的情况下,依然会弹出资金确认 modal。
REST 端点
HTTP gateway 为非 CLI 集成暴露同一组接口。
| 方法 | 路径 | 用途 |
|---|---|---|
GET | /v1/agents | 列出 definition(?archived=true 仅返回已归档) |
POST | /v1/agents | 创建:body 是一个 AgentDefinitionInput |
GET | /v1/agents/:id | 拿最新 definition |
PATCH | /v1/agents/:id | 更新;body 是部分 AgentUpdatePatch |
DELETE | /v1/agents/:id | 归档(软删除,可恢复) |
POST | /v1/agents/:id/restore | 恢复已归档的 agent(重新挂载触发器) |
DELETE | /v1/agents/:id/permanent | 永久删除(不可逆;运行历史保留) |
POST | /v1/agents/:id/runs | 启动 ad-hoc 运行;加 ?test=1 进入测试模式 |
GET | /v1/agents/:id/runs | 列出历史运行(workflow 实例历史) |
GET | /v1/workflows/:id/instances/:iid/events/stream | 运行中实例的 SSE 事件流 |
SSE 端点和 Web UI Run 抽屉用的是同一个。它会透明地把事件按
单一 instance_id 过滤。
示例:用 curl 创建
curl -X POST http://localhost:8080/v1/agents \
-H "Authorization: Bearer $GATEWAY_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d @research-bot.json
# 启动一次 ad-hoc 测试运行
curl -X POST "http://localhost:8080/v1/agents/research-bot/runs?test=1" \
-H "Authorization: Bearer $GATEWAY_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "input": "summarize recent ETH news" }'AgentDefinition JSON 示例
{
"id": "research-bot",
"name": "Daily Research Bot",
"description": "Morning brief: trending tokens, macro context, watchlist signals.",
"system_prompt": "You are a markets research assistant. Output a 5-bullet brief covering crypto majors, US equities open, and any flagged watchlist alerts. No advice; observation only.",
"skill_ids": [
"analysis.market_overview",
"research.knowledge_base",
"minara.core"
],
"tool_names": ["get_price", "get_trending", "search_tokens"],
"tool_sets": ["market_data"],
"risk_tier_max": 1,
"discovery_mode": "constrained",
"triggers": [
{ "kind": "cron", "expr": "0 9 * * *", "timezone": "UTC" }
],
"metadata": {
"tags": ["research", "daily"],
"owner": "[email protected]"
}
}要点:
- 只读市场数据的 cron 触发 Agent 适合用
risk_tier_max: 1(只读)。 定时 agent 默认上限为 tier 2,开启allow_autonomous_fund_moves后为 tier 3。超出该上限的写入会在 upsert 时被拒。 discovery_mode: "constrained"意味着 runner 不会在中途调用activate_skills。技能 / 工具面就是声明的样子。tool_sets: ["market_data"]把该集合里的每个工具叠加进tool_names白名单。Runner 取并集。
包含 agent_turn { agent_id } 的 Workflow JSON
{
"id": "morning-brief",
"name": "Morning Brief",
"version": 1,
"steps": [
{
"id": "step_1",
"kind": "tool_call",
"tool": "get_portfolio_snapshot",
"input": {}
},
{
"id": "step_2",
"kind": "agent_turn",
"agent_id": "research-bot",
"input": {
"portfolio_summary": "{{ steps.step_1.output }}"
}
},
{
"id": "step_3",
"kind": "tool_call",
"tool": "send_telegram",
"input": {
"text": "{{ steps.step_2.output }}"
}
}
]
}Workflow 作者编排流程;research-bot 拥有推理。
第 2 步首次执行时,engine 把 Agent definition 快照写入
workflow_instances.agent_def_snapshot。
之后对 research-bot 的 PATCH 不影响这个在飞实例。
新提交的运行才拿到新版本。
基于 JSON 文件的分享
Agent loader 在启动时扫描 ~/.minara/agents/
(或 $MINARA_DATA_DIR/agents/)。每一个能解析成 AgentDefinition
的 *.json 文件,都会落入 store,source: "file:<绝对路径>"。
文件来源行是 PATCH-locked 的:REST 和 CLI 的更新会被以清晰错误拒绝。 请在磁盘上改文件,然后重启 agent(或调用 loader 同步端点)以拾起改动。 这保证文件始终是来源真相,磁盘与 DB 之间不会悄悄漂移。
删除文件会在下一次同步时归档对应行,所以删文件不会破坏已经 为该 Agent 做过快照的 workflow。
安全姿态(汇总)
- Runtime 风险钳制:非 manual 触发器(cron、event、autopilot)
会把
effective_risk_tier_max钳到 2,开启allow_autonomous_fund_moves后钳到 3。钳制在 AgentRunner 里、LLM 一轮开始之前、触发源解析之后立即执行。 tier 4 工具在注册表门处对自主来源始终被拦截。 - 上下文感知的资金确认:每一次资金移动工具调用都路由经过资金确认门。
测试运行时,无论
MINARA_SKIP_FUND_CONFIRM怎么配, 确认门都强制走两步确认。测试运行不会悄悄动钱。 - 归档 Agent fail-closed:对已归档 Agent 的手动运行立即失败。
挂在已归档 Agent 上的 cron 触发器连续 skip 三次后,
自动停用触发器。在飞的
agent_turn步骤按已保存的 snapshot 继续。 归档只对未来生效。 - Snapshot 隔离:通过
agent_id引用 Agent 的 workflow 实例, 在首次执行时把完整 definition 做成 snapshot。 之后对源 Agent 的 PATCH 或 ARCHIVE,对任何在飞实例都没有影响。 - 审计日志:每一次运行都向审计日志写入请求的风险 tier、
生效(钳制后的)风险 tier、触发源,以及被丢掉的技能 / 工具列表。
Web UI 在 History tab 暴露这些;CLI 可以通过
minara agents get <id>加一次 instance 查询拿到。