openheron
第 4 章

配置怎么写

4.1 Agent(agents/<name>.md)

一个 Agent 是一个 markdown 文件:frontmatter + 正文。正文就是给模型看的提示词。

---
description: "task: the concrete executor. Writes files per the task order."
model: deepseek/deepseek-flash
max_iterations: 50
reasoning: low
disabled_tools: [kb_index]
summarize_at: 80%
---

你是执行 Agent。收到任务后:
1. 先读相关文件
2. 按任务单逐项修改
3. 改完跑一遍测试,把失败项原样贴出来

frontmatter 可用键:

键 说明
description 这个 Agent 干什么用的(父 Agent 靠它决定委派给谁)
model <vendor>/<model>,必填,不继承也不回退
max_iterations 工具循环的轮数上限
summarize_at 这个 Agent 的上下文什么时候被压缩成摘要:模型窗口的 80%(默认)、绝对 token 数(104858)、或 0 表示永不
subagents 它能委派给谁(见 §5)
disabled_tools 对这个 Agent 生效的工具禁用表
skills 这个 Agent 能用的技能 —— skills/ 下文件夹的白名单(不写就是全部,写空列表就是一个都没有)
temperature / max_tokens 采样参数
reasoning 思考档位:off / low / high / max(名字由厂商档案定义)

★ frontmatter 写错一个键就是启动错误,不会被忽略 —— 这是故意的: 一份静默失效的配置比一份报错的配置难查得多。

★ model 不继承。父 Agent 用了哪个模型,子 Agent 不会跟着用 —— 每个 Agent 都得自己写。 这正是「专家配专模」的落点。

★ reasoning 档位必须在模型档案里声明过才有效。没声明的档位会被静默忽略: Agent 写着 reasoning: high,而端点没有 high,实际效果是「完全不思考」,且没有任何报错。 详见 §4.2。

★ summarize_at 是长对话活下来的原因。越过这个点,对话会被一段摘要取代,从那以后 agent 带着摘要往前走。它有三种写法:

写法 含义
summarize_at: 80% 该 Agent 实际所用模型 context_window 的 80%
summarize_at: 104858 绝对 token 数
summarize_at: 0 永不压缩 —— 上下文一直长到端点拒绝请求

不写这个键,Agent 拿到的是窗口的 80% —— 自动压缩默认开着。常用区间是 80–90%: 正好填满窗口的请求就是会被拒绝的请求,剩下的那点余量正是摘要自己需要的。

★ 百分比需要窗口。模型没声明 context_window,就没什么可取 80%:那个 Agent 永远不压缩, 而 openheron 加载配置时会说出来。在 llm/<vendor>.yaml 里声明 context_window, 或者在 Agent 上写一个绝对的 summarize_at。

4.2 模型档案(llm/<vendor>.yaml)

type: openai_compat
base_url: https://api.deepseek.com
api_key: ${DEEPSEEK_API_KEY}
timeout: 5m

models:
  - id: deepseek-flash
    context_window: 131072
    reasoning:
      off:  { reasoning_effort: none, thinking: { type: disabled } }
      low:  { reasoning_effort: low,  thinking: { type: enabled } }
      high: { reasoning_effort: high, thinking: { type: enabled } }
      max:  { reasoning_effort: max,  thinking: { type: enabled } }
    reasoning_default: off
字段 说明
type 协议类型,目前是 openai_compat
base_url 端点,含路径,从厂商文档抄
api_key 环境变量名,写成 ${NAME} —— 不能写字面量
timeout 超时,带单位(5m / 30m)
models[].id 模型名
models[].context_window 上下文窗口 —— 压缩阈值就是拿它量的
models[].reasoning 档位表:档位名 → 这个端点实际发什么字段
models[].reasoning_default Agent 没写 reasoning 时用哪档
models[].timeout 覆盖厂商级超时(思考模型通常要调大)
hint_keys 端点的字段名,用于请求被拒时给出准确提示
extra 厂商级方言,透传给所有请求

★ api_key 只能写环境变量名(${OPENAI_API_KEY})或文件引用(@file:/path)。 在配置里写字面量密钥,配置编辑器会直接拒绝保存 —— 密钥不该进仓库。

★ 压缩阈值属于 Agent,不属于模型。 context_window 是模型的;summarize_at 是 Agent 的 —— 这个 Agent 把自己的上下文填到多少才压缩,是它自己的策略。同一个模型可以服务多个策略不同的 Agent。模型档案里留着的 summarize_at 不再被读,openheron 加载配置时会说出来。

压缩缩短的是上下文,不是记录。被压缩掉的消息仍留在记录里、仍读得到;摘要就写在它们 旁边。你自己的话不会在切口处丢失 —— 摘要把它们留住了。

★ reasoning 档位表不是可选的。它是「Agent 写 reasoning: high」与 「这个端点怎么表达 high」之间的翻译层。表里没有的档位会被静默忽略, 于是「开了 high 档却不思考」这个坑会以最隐蔽的方式出现。

4.3 审批策略(policy/permissions.yaml)

ask:
  - write_file
  - edit_file
  - execute
  - kb_index
deny: []

只有两列,语义很直接:

  • 在 ask 里:每次调用都要你点头。
  • 在 deny 里:谁都不能用。
  • 不在任何一列里:默认 allow(直接放行)。

★ deny 是全局的。agents/*.md 里的 disabled_tools 只影响那一个 Agent, 放松不了外层的 deny。这是子 Agent 唯一放松不了的保证。

4.4 外部工具(tools/)

文件存在即启用,不用改代码。当前支持四个文件名:

文件 提供
http.yaml 通用 HTTP 请求工具
web_search.yaml 网页搜索
wikipedia.yaml 百科查询
kb.yaml 知识库(见 §7)

★ tools/ 下只认这四个文件名,写别的名字会启动报错,不会被静默忽略。

★ openheron init 默认不写 tools/ 下的任何文件 —— 这一整个目录要你自己写;加 --tools 才会把上面那四个文件写出来。没写就是没启用:对应的工具不会出现在 agent 的 工具表里,模型也看不见它。

4.5 进程参数(server/config.yaml)

字段 默认 说明
listen_addr :8080 监听地址
data_dir state 会话与 checkpoint 的存放目录
static_dir web/dist 前端产物目录(frontend_mode: dir 时用)
frontend_mode embed embed 用嵌进二进制的界面,dir 读磁盘
start_timeout 60s 启动超时
lease_ttl 10m 一轮在没有进展的情况下能持有多久的租约——必须长于 provider 自己的超时
agent.max_depth 1 委派深度上限

★ server/ 不热重载 —— 改了要重启才生效。所以配置编辑器里它是只读的, 提交会报 section "server" is not editable。

以下环境变量可以覆盖进程参数,优先级高于配置文件: LISTEN_ADDR、DATA_DIR、PROJECT_ROOT、FRONTEND_MODE、STATIC_DIR。

4.6 技能(skills/)

skills/<name>/SKILL.md,按 eino 原生的 skill 约定。

★ skills 的查找是另一套规则:先看 $EINO_EXT_SKILLS_DIR, 没有才从当前目录向上找 .openheron/skills。这跟配置根「不向上找」不一样 —— skills 是目录树,向上找是为了能用你家目录里的技能。

★ 一个 Agent 能用哪些技能,由它自己声明。agents/<name>.md 的 skills 键是 白名单,名字就是 skills/ 下的文件夹名:

skills: [refactor, review]

不写这个键就是目录里的全部技能;写空列表就是一个都没有。不在名单里的技能 不会出现在给模型看的技能清单里,点名去调也会失败 —— 看不见的东西调不到。 名单里写了目录里没有的名字,Agent 装配时日志会报出来,不会被忽略。