Skip to content

Agent 深入

群里发一句 ai: 查一下明天天气,几秒后 bot 回了带数据的回答——中间发生了什么?本篇沿着这条路径展开 AI 总览 的运行时:ZhinAgent 的回合流程、deferred tools、子代理与编排、会话持久化与 compaction、Assistant profile 与调度任务。

ZhinAgent 回合

触发命中后,Agent Host 调用 zhinAgent.process(text, commMessage, tools) 跑一个回合(turn):

几个值得记住的事实。ZhinAgent、子代理、后台 worker、AIService.runAgent 走的是同一条 agentLoop,行为可以一致地预期。同会话的消息按 ai.agent.inboundQueue 排队(groupMode: supersede | fifo),并发回合不会互相覆盖。首选模型失败时按候选链 fallback 到同 provider 的其他可用模型。maxIterations 默认 15(DEFAULT_CONFIG.maxIterations),可按 provider/model 经 model harness 覆盖(见下文)。超时有三层:触发侧单回合受 ai.trigger.timeout 约束(默认 60000ms),Agent 回合整体默认 120000ms(DEFAULT_CONFIG.timeout),工具预执行另有 15000ms 上限(preExecTimeout)。

回合产出的工具池 = 插件注册工具 + ai.mcpServers 连接工具 + 内置工具 + deferred meta 工具 + schedule_* + bash + Host 扩展工具(如 voice_stt / voice_tts)。

Deferred tools(discover / load_tool / load_skill)

工具数量大时,全量 schema 塞进 prompt 会挤占上下文。Zhin.js 的做法是延迟加载:回合只常驻少量元工具,模型按需检索、按名加载。

常驻工具(alwaysLoadedTools 默认值):ask_userspawn_taskdiscoverload_toolload_skill

元工具作用
discover按 query 检索工具/技能(`kind: tool
load_tool按名把工具 schema 载入本会话,之后可直接调用
load_skill载入技能说明文本与其声明的工具

调参(ai.agent.deferredTools):

yaml
ai:
  agent:
    deferredTools:
      maxLoadedPerSession: 12   # 单会话最多载入工具数(默认 12)
      discoverTopK: 5           # discover 返回条数(默认 5)
      alwaysLoadedTools: [ask_user, spawn_task, discover, load_tool, load_skill]
      mcpServers:
        icqq: { alwaysLoaded: [send_msg] }   # 指定 MCP server 的常驻工具

保留/内置工具名(bashread_filespawn_task 等)不可被插件覆盖;非保留工具同名时后注册覆盖前注册,冲突记 warn。

子代理与 spawn_task

主 Agent 通过 spawn_task 把复杂/耗时任务派给后台子代理,主对话不阻塞:

yaml
ai:
  agent:
    maxParallelSubagents: 5        # 并行子代理硬顶(默认 5)
    toolExecution: tiered          # parallel | sequential | tiered(默认)
    subagentAutoContinue: true     # 异步完成后唤醒主 Agent 续聊(默认 true)
    subagentDirectImDelivery: false # 额外直发子任务摘要到 IM(默认 false)
    subagentTools: []              # 追加子代理可用工具白名单

spawn_task 关键参数:

参数说明
task任务描述(目标、范围、期望产出)
agent子代理名(须在 ai.agentsagents/*.agent.md 预设中存在)
waittrue 时同步等待,结果经 tool result 回到当前回合
contextfork(注入父会话近期消息)/ fresh(空上下文)
tools / skills声明子任务需要的工具与技能

行为上有几条约束:同一回合可发起多个 spawn_task,独立子任务建议并行;tiered 模式下只读工具与 spawn 并行、写/bash 顺序执行。子代理默认使用受限工具集(read_file / write_file / edit_file / list_dir / glob / grep / web_search / web_fetch / bash + deferred meta),不自动继承主会话全部工具,要用 ai.agent.subagentTools 显式追加。主 Agent 可见的子代理类型受 ai.agents.<name>.permission.task(glob → allow/deny)约束。异步完成后结果先交还主 Agent(写入主会话并 auto-continue),用户可见回复由主 Agent 整理发出。另外,子代理预设可用 agents/<name>.agent.md(YAML frontmatter + 说明)文件化声明,启动时自动发现注册。

编排(Orchestration)

OrchestrationService(Kernel)维护 Run / Task 状态机:一个用户请求可拆成有依赖关系(dependsOn)的多任务,按 executor(local / remote)分派执行。内置编排工具:

工具作用
orchestration_start开启一个编排 Run
orchestration_add_task向 Run 添加任务(role / goal / dependsOn / priority)
orchestration_status查询 Run / Task 状态
orchestration_complete结束 Run
orchestration_retry_task / orchestration_skip_task失败任务重试 / 跳过

Run 状态:openrunning / waiting → 完成。配置 ai.remoteAgentsid + cardUrl + token)后可将任务派给远程 A2A agent 执行:

yaml
ai:
  remoteAgents:
    - id: local
      cardUrl: http://127.0.0.1:8069/a2a/zhin/.well-known/agent-card.json
      token: ${HTTP_TOKEN}

编排运行可在 Console 的 Orchestration 页查看(GET /api/agent/orchestration/runs),见 Console

会话持久化与会话树

数据库可用时,Agent Host 落三张表(缺库时自动降级为内存模式):

内容
agent_sessionsAgent 会话元数据(含会话树 parent_id / active_leaf
agent_messagesAgent 回合消息(上下文仓库)
im_transcriptsIM 进出站流水(chat_history 工具的数据源)

ai.sessions.useDatabase: false 可强制内存模式。

同一 IM 会话内还可以分叉(branch)成会话树,用 IM 命令管理:

命令作用
/compact手动压缩当前会话上下文
/tree / /tree N查看 / 切换会话分支
/reset重置会话
发送 clear / 清空 / 重置归档并清空本会话 AI 多轮上下文

其他管理命令(master / 有权限用户):/models/health/cmd/endpoints/bindings/tools/mcp

Compaction

上下文接近窗口上限时自动压缩,配置 ai.agent.compaction

yaml
ai:
  agent:
    compaction:
      enabled: true
      auto: true
      keepRecentTokens: 20000   # 保留最近消息的 token 预算(默认 20000)
      minKeepCount: 2           # 至少保留的消息条数(默认 2)

估算 token 超过 contextWindow × 0.6 触发压缩。压缩分两级:先做 micro-compact(裁剪冗余工具结果等),再由 LLM 生成 [Previous conversation summary] 摘要替换旧历史。连续自动压缩失败达到上限后停止自动压缩,避免反复消耗。

Model harness

按 provider / model 覆盖执行循环参数(当前消费 maxIterations),合并顺序:TS 默认表 → providerPatterns(支持 * 通配)→ models 精确键:

yaml
ai:
  agent:
    modelHarness:
      providerPatterns:
        "open*": { maxIterations: 7 }
      models:
        "gpt-4o": { maxIterations: 8 }
        "openai:gpt-4o": { maxIterations: 9 }

内置工具

类别工具
执行bashrun_deferred_task
文件read_filewrite_fileedit_filelist_dirglobgrep
网络web_searchweb_fetch
交互ask_user
任务spawn_tasktodo_readtodo_writeorchestration_*
记忆/检索memory_searchmemory_upsertknowledge_searchchat_history
媒体generate_imageanalyze_media
discoverload_toolload_skillinstall_skill
调度schedule_listschedule_addschedule_removeschedule_pauseschedule_resumeschedule_preview

Assistant profile 与调度任务

Assistant 运行时把「定时做事」产品化:持久化任务存 data/schedule-jobs.json,由 ScheduleJobEngine 到点执行并把结果推回 IM。

yaml
assistant:
  enabled: true
  profile:
    enabled: true
    file: assistant.profile.yml   # 相对项目根,默认即此名
  events:
    enabled: true                 # 开放 POST /api/assistant/events 外部事件入口
  defaults:
    notifyOnFailure: false

assistant.profile.yml 声明人设与例行任务(routines),启动时同步为调度任务:

yaml
version: 1
persona:
  soul: 你是贴心的生活助手。
routines:
  heartbeat:
    enabled: true
    everyMs: 1800000
    prompt: 检查待办并汇报。
  morningBrief:
    enabled: true
    scheduleKind: solar      # solar | lunar | workday | freeDay | holiday
    cron: "0 0 8 * * *"
    tz: Asia/Shanghai
    prompt: 生成今日早报。

内置 routine 有 heartbeat(间隔执行)、morningBrief(默认 08:00)、bedtimeCheck(默认 22:00)、weatherReport,也可自定义键。注意中国大陆「工作日」场景用 workday(含调休),不要用 solar 的 1-5

用户也可以在 IM 里让 Agent 用 schedule_add / schedule_list / schedule_preview 等工具直接管理任务;外部系统可经 POST /api/assistant/events 注入事件、GET /api/assistant/jobs 查询任务。

相关