第 04 步:配置系统¶
这一节学什么¶
jianmu的常见配置入口有哪些- 环境变量、
jianmu.yaml、代码参数分别适合放什么 - 配置覆盖关系与最小验证方式
这一节放到这里的原因¶
到这一步,你已经至少见过:
- 最小聊天
- ReAct with tool
- prompt /
ContextBuilder
所以现在再回头理解配置系统,会更容易把抽象和实际运行链路对应起来。
最小心智模型¶
先记住这一条就够了:
- 环境变量:放密钥、Base URL、部署差异
jianmu.yaml:放项目默认值- 代码参数:放某个 Agent、某个节点、某次运行的局部覆盖
核心概念¶
最常见的启动前配置包括:
OPENAI_API_KEYBASE_URLMODELjianmu.yaml里的models.default
这里需要注意一件事:
MODEL现在不只是某些 examples 自己读取的约定值- 它已经并入了统一配置加载链路
也就是说,如果你没有在 jianmu.yaml 里显式写:
models.defaultmodels.reactmodels.plan_executemodels.evaluate
那么配置加载阶段会用 MODEL 去补这些常见模型默认值。
但如果 jianmu.yaml 已经显式写了某个模型字段,那么文件配置仍然优先。
jianmu.yaml 常用来放什么¶
新人最常先碰到的是这几类字段:
modelsdefaultreactprompt- 默认 prompt 片段和模板
- bootstrap 文件列表
pathsskills_dircheckpoints_dirstoreexecution- 本地 / Docker 执行默认值
limits- 默认轮次、历史条数、RAG 分块参数
也就是说,jianmu.yaml 更适合回答“这个项目通常怎么运行”,而不是“这次调用临时想改一下”。
jianmu.yaml 和 jianmu/config 是什么关系¶
这两个名字也很容易让人误以为是两套平行系统,但其实不是。
更准确地说:
jianmu/config是配置系统本身jianmu.yaml是这套配置系统最常见的项目级输入文件
可以按下面理解:
jianmu/config/project.py- 定义配置 schema,例如
JianmuConfig、ModelsConfig、PromptConfig jianmu/config/loader.py- 负责查找
jianmu.yaml、解析文件、处理路径、返回统一配置对象 jianmu.yaml- 只是这些 schema 的外部数据来源之一
所以不是:
- “
jianmu/config是一套配置” - “
jianmu.yaml又是另一套配置”
而是:
jianmu/config定义和加载配置jianmu.yaml提供项目默认值数据
配置是怎么真正生效的¶
这一层链路建议你记成一句话:
- 框架不是直接读取
jianmu.yaml在各处生效 - 框架消费的是
jianmu/config解析后的统一配置对象
也就是说,典型链路是:
get_config()/load_config()找到jianmu.yaml- 把它解析成
JianmuConfig - 各模块再从这个配置对象里取默认值
例如:
- model 层读取模型默认值
- prompt resolver 读取 prompt 默认模板
- execution 读取执行默认值
- memory / checkpoint 读取路径和运行时默认值
这也是为什么代码参数还能继续覆盖它:
jianmu.yaml提供的是项目默认值- 具体节点或具体 Agent 仍然可以在代码里做更窄范围的局部覆盖
代码参数通常用来做什么¶
如果你只想改某一个节点或某一个 Agent,不要先改全局配置。
更直接的做法通常是:
- 在
AgentLLMConfig/ReActConfig里显式传model - 在节点构造时显式传
system_prompt - 在需要时显式传
context_builder
这样做的好处是覆盖范围明确,不会意外影响整个项目里的其他节点。
什么适合放 jianmu.yaml,什么更适合写在代码里¶
如果你不知道该放哪,可以先按这个原则判断:
更适合放 jianmu.yaml¶
这些通常是项目级默认值:
- 默认模型名
- 默认 prompt 模板或 prompt 片段
skills_dir、checkpoints_dir、store这类路径- 默认 execution / runtime / limits 配置
它们的共同特点是:
- 会被很多地方复用
- 希望整个项目默认一致
- 不依赖某一次具体调用的上下文
更适合在代码里显式传¶
这些通常是某条运行链路的局部决策:
- 某个节点临时换一个
system_prompt - 某个 Agent 指定一组特殊 tools
- 某次运行显式指定
context_builder - 某个示例或 app 明确强制走
litellm
它们的共同特点是:
- 只影响某个节点、某个 Agent 或某次运行
- 你希望覆盖范围尽量窄
- 你希望调用点一眼就能看出实际行为
一个实用判断标准¶
如果你问自己:
- “这是项目默认策略吗?”
答案如果是“是”,优先放 jianmu.yaml。
如果你问自己:
- “这是这一条链路才需要的特殊行为吗?”
答案如果是“是”,优先放代码参数。
覆盖关系应该怎么理解¶
Getting Started 阶段可以先按下面理解:
- 环境变量提供外部依赖的运行环境
jianmu.yaml提供项目默认值- 代码构造参数在具体调用点做局部覆盖
这里最容易混淆的是:
.env不是所有配置的唯一来源jianmu.yaml也不是所有运行时临时决策都该放进去
一个实用判断标准是:
- 会随部署环境变化的,优先放环境变量
- 会作为项目默认策略长期存在的,优先放
jianmu.yaml - 只影响某条链路的,优先在代码里显式传参
对 MODEL 来说,可以更具体一点理解:
- 如果你只是想快速给当前环境设一个统一模型默认值,写
.env里的MODEL很方便 - 如果你想为项目长期固定不同链路的默认模型,还是更适合在
jianmu.yaml里显式写models.*
模型 Provider 是怎么自动选择的¶
这里有一个很容易误解的点:
- 环境变量不只是在“给模型提供密钥”
- 它也会影响默认选择哪个 model provider
按当前实现,ModelClient.resolve() 在你没有显式指定 provider 时,会先按下面顺序尝试:
openailitellm
也就是说,默认优先级不是“谁都一样”,而是先原生 openai,再 litellm。
OPENAI_API_KEY 会导致什么¶
如果你设置了:
OPENAI_API_KEY- 或
API_KEY
那默认最容易命中的就是 openai provider。
也就是说,下面这种配置:
通常表示的是:
- 走
openaiprovider - 但请求地址不是官方 OpenAI,而是你提供的 OpenAI-compatible
BASE_URL
这对 SiliconFlow、OpenRouter 的 OpenAI-compatible endpoint、内部代理网关等场景都很常见。
BASE_URL 决定什么,不决定什么¶
BASE_URL 或 OPENAI_BASE_URL:
- 会传给已经选中的 provider,作为请求地址
- 但它本身不决定先选
openai还是先选litellm
所以不要把它理解成:
- “我写了
BASE_URL,框架就会自动切去某个特定 provider”
更准确的理解是:
- “provider 先被选出来,再读取
BASE_URL去发请求”
如果我想强制走 litellm 怎么办¶
如果你希望明确使用 litellm,不要依赖默认自动选择。
更稳的做法是显式写:
或者在更上层装配里显式传入一个已经解析好的 ModelClient。
这样不会受到默认优先顺序影响。
LITELLM_CUSTOM_LLM_PROVIDER 影响什么¶
这个环境变量经常也会让人混淆。
它影响的不是:
- Jianmu 外层先选
openai还是litellm
它影响的是:
- 当你已经进入
LiteLLMProvider之后 - LiteLLM 该按哪个下游 provider 语义解释当前
model
也就是说,它是 LiteLLM 内层路由的一部分,不是 Jianmu 外层 provider 选择器的一部分。
例如:
这类配置的含义更接近于:
- “如果我已经走
litellm,那就按openrouter的规则理解这个 model”
而不是:
- “只要写了这个变量,Jianmu 就会自动切到
litellm”
所以如果你希望这个变量稳定生效,最好同时做到两件事:
- 外层显式使用
litellm - 再用
LITELLM_CUSTOM_LLM_PROVIDER指定 LiteLLM 的下游 provider
需要注意的一个现实细节¶
当前框架里,LiteLLMProvider 自己支持的环境变量范围,其实比默认自动探测逻辑更宽。
例如 LiteLLM 常见会读取:
OPENROUTER_API_KEYANTHROPIC_API_KEYGOOGLE_API_KEYGEMINI_API_KEYXAI_API_KEYDEEPSEEK_API_KEYGROQ_API_KEYOLLAMA_API_BASE
但默认自动选择逻辑目前并没有把这些情况全部对齐覆盖。
所以 Getting Started 阶段你可以先用一个简单原则:
- 想走最稳的 OpenAI-compatible 主路径:
OPENAI_API_KEY + BASE_URL - 想明确走
litellm:显式指定name="litellm"
怎么验证配置是否生效¶
最小验证方法有三种:
- 直接读取项目配置对象
from jianmu.config import get_config
config = get_config()
print(config.models.default)
print(config.prompt.bootstrap_files)
- 运行一个最小示例,看它是否使用了你设定的模型或 prompt
- 在某个节点显式传参,再和全局默认值做对照
如果你改了 jianmu.yaml 但结果没变化,优先检查:
- 当前工作目录下是否真的加载到了目标配置文件
- 你改的是项目默认值,还是某个节点已经在代码里显式覆盖了它
- 相关能力是不是其实走环境变量或 provider 自己的配置
这一节和前后步骤的关系¶
前面几步先让你看清:
- 一个最小 Agent 怎么跑
- ReAct 怎么工作
- prompt 和
ContextBuilder是怎么装配的
到这一步,你再回头看配置系统,才更容易知道:
- 哪些配置会影响哪些运行链路
- 为什么有些默认值应该放
jianmu.yaml - 为什么有些特殊行为更适合直接写在代码里