Jean's Blog

一个专注软件测试开发技术的个人博客

0%

DeepAgents的Profiles

Profiles 功能的核心解读

核心痛点:频繁换模型 = 代码地狱

开发者在使用不同大模型(如 OpenAI、Anthropic Claude 等)时,会遇到一个普遍问题:

每次更换模型,都要修改 create_deep_agent 核心调用代码,调整参数、提示词格式等,过程麻烦且容易出错,导致代码冗余、维护成本高。

Profiles:模型的 “万能适配卡”

Profiles 就是为了解决上面的问题而设计的。它的核心思想是:

  • 提前为某个模型供应商或具体模型写好一整套 “微调规则”
  • Deep Agents 运行时会自动识别并匹配对应的模型,自动应用这些规则
  • 优势:完全不影响智能体的核心业务逻辑,让代码更清爽、配置更集中。

两种 Profile 的分工(核心差异)

框架提供了两种 Profile,它们的作用完全不同,面向的开发者场景也不一样:

类型 定位 作用范围 适用场景
Harness Profile 调整运行时行为 控制智能体的业务逻辑层面 绝大多数开发者的 “主战场”
Provider Profile 控制模型构建过程 控制模型的底层初始化与参数 封装第三方供应商集成时使用

🔧 Harness Profile:业务逻辑的 “调节器”

它主要用来控制智能体在运行时的行为,包括:

  • 系统提示词的拼接方式
  • 工具的可见性(哪些工具对模型开放)
  • 中间件的增删
  • 通用子智能体的表现规则

一句话总结:它是你用来 “调教” 智能体行为的地方,是日常开发中最常用的配置。

⚙️ Provider Profile:模型的 “幕后帮手”

它更偏向底层,用来管理 init_chat_model 过程中的细节:

  • 设置模型的默认参数(如温度、最大 token 数)
  • 初始化前的检查逻辑(比如验证 API 密钥)
  • 动态参数的获取(比如从配置中心读取模型地址)

一句话总结:它主要用于封装和适配不同的模型供应商,普通开发者很少直接用到。

对绝大多数使用者来说,Harness Profile 就是主战场,能满足你对智能体行为的各种微调需求。Provider Profile 通常只在封装第三方供应商集成时才会用到。

这个 Profiles 机制本质上是一种关注点分离的设计:

  • 业务逻辑(智能体行为) 由 Harness Profile 管理,和模型无关

  • 模型底层适配 由 Provider Profile 管理,和业务逻辑无关

    这样一来,你切换模型时,只需要新增 / 修改对应的 Provider Profile,业务代码完全不用动,实现了真正的解耦。

Harness Profile :智能体行为的“遥控器”

一个简单的例子:

你想给 openai:gpt-5.4 这个模型做几个定制化设置:

  1. 回答要尽量简短(不超过 100 字)
  2. 隐藏 / 禁用 execute 这个工具
  3. 移除 SummarizationMiddleware 这个摘要中间件
  4. 关闭通用子智能体功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from deepagents import (
GeneralPurposeSubagentProfile,
HarnessProfile,
register_harness_profile,
)

register_harness_profile(
"openai:gpt-5.4",
HarnessProfile(
system_prompt_suffix="Respond in under 100 words.",
excluded_tools={"execute"},
excluded_middleware={"SummarizationMiddleware"},
general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False),
),
)
  1. 导入模块

    • GeneralPurposeSubagentProfile:控制通用子智能体的配置

    • HarnessProfile:核心的 “行为配置类”,用来定义智能体的运行时规则

    • register_harness_profile:注册配置的函数,让框架知道哪个模型用这套规则

  2. register_harness_profile 函数

    • 第一个参数 "openai:gpt-5.4":指定这套规则只对这个模型生效

    • 第二个参数是 HarnessProfile 对象,里面包含了所有定制规则:

参数 作用 效果
system_prompt_suffix 给系统提示词追加内容 强制模型回答不超过 100 字
excluded_tools={"execute"} 把指定工具从模型可用列表中移除 模型再也看不到、也无法调用 execute工具
excluded_middleware={"SummarizationMiddleware"} 禁用指定的中间件 去掉自动摘要功能
general_purpose_subagent=...(enabled=False) 配置通用子智能体 完全关闭子智能体功能

这段代码一注册,Deep Agents 就会自动执行所有配置,而你的核心业务代码 create_deep_agent(...) 可以完全不改动。

这就是 Profiles 设计的核心优势:

  • 关注点分离:业务逻辑和模型行为配置完全解耦
  • 可复用性:同一套规则可以在多个地方复用,不用重复写配置
  • 易维护:要改模型行为,只需要修改 Profile 配置,不用动业务代码,大幅降低出错风险

HarnessProfile 可配置的字段和关键规则

字段 作用通俗解释 典型用法示例
base_system_prompt 直接替换框架内置的基础系统提示词,相当于重写智能体的 “初始人格” 把默认的通用助手人格,改成 “资深 Python 代码审查员”
system_prompt_suffix 在所有提示词的最后面追加文本,主智能体和子智能体都会生效 强制模型全程用中文回答、只返回 JSON 格式
tool_description_overrides 用字典形式,覆盖单个工具的描述文本 把默认英文的工具说明改成中文,方便模型理解
excluded_tools 从模型的可用工具列表中,移除指定的工具(发生在工具列表组装的最后一步) 禁用敏感工具(如文件删除、系统执行),防止误操作
excluded_middleware 从默认中间件栈中删除指定中间件(支持类名、字符串或导入引用) 去掉自动摘要、日志记录等非必要中间件
extra_middleware 给中间件栈追加自定义中间件(支持静态列表或动态生成的可调用对象) 接入自定义的权限校验、日志上报中间件
general_purpose_subagent 接收一个 GeneralPurposeSubagentProfile 对象,控制内置通用子智能体的开关、名字和系统提示词 关闭子智能体功能、修改子智能体的默认行为

1. 提示词的执行顺序是 “铁律”

调用方传入的 system_prompt 永远排在最前面,而 system_prompt_suffix 永远在最后面。不管模型怎么切换、Profile 怎么覆盖,这个顺序都不会变。

  • 提示词的完整拼接顺序:

      flowchart LR
        A["调用方传入的 system_prompt
    (最外层,最先拼接)"] --> B["base_system_prompt
    (替换/覆盖框架内置人格)"] B --> C["其他框架内置内容
    (如工具说明、中间件注入的上下文)"] C --> D["system_prompt_suffix
    (全局指令,最后拼接,强制生效)"]
  • 影响:如果你想强制模型遵守某个规则(比如 “必须用中文回答”),放在 system_prompt_suffix 里是最稳妥的,因为它永远是最后生效的,不会被前面的内容覆盖。

2. 彻底禁用子智能体的正确方式

只设置 general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False) 还不够!

你还必须在调用 create_deep_agent 时,确保 subagents= 参数为空,否则 task 这类工具还是会出现。

  • 错误做法:只关 Profile 里的子智能体开关
  • 正确做法:Profile 里禁用 + create_deep_agent 不传任何子智能体配置

3. 骨架级中间件不能被排除

FilesystemMiddlewareSubAgentMiddleware 以及内部的权限中间件,是框架的核心骨架,不能放进 excluded_middleware,否则会直接抛出 ValueError

  • 正确做法:如果不想让模型使用这些中间件的功能,应该用 excluded_tools 隐藏对应的工具,而不是直接删除中间件本身。

excluded_middleware排除中间件的三种写法

1. 直接传类

  • 写法示例SummarizationMiddleware
  • 原理:系统通过精确的类型匹配来排除中间件。
  • 优点:最直接、类型安全,IDE 可以自动补全,写错会直接报错。
  • 缺点:只能在代码中使用,不适合写在配置文件里。
  • 适用场景:Python 代码中直接配置,开发调试阶段首选。
1
2
3
4
5
6
# 示例
from some.module import SummarizationMiddleware

HarnessProfile(
excluded_middleware={SummarizationMiddleware},
)

2. 传字符串名称

  • 写法示例"SummarizationMiddleware"
  • 原理:匹配中间件类的 name 属性,只要 name 对上就会被排除。
  • 优点:写法简单,不用导入模块,适合快速配置。
  • 缺点:如果有重名的中间件,可能会误删;IDE 无法自动校验。
  • 适用场景:快速排除已知名称的中间件,或者简单配置场景。
1
2
3
4
# 示例
HarnessProfile(
excluded_middleware={"SummarizationMiddleware"},
)

3. 传导入引用(模块:类名)

  • 写法示例"my_pkg.middleware:TelemetryMiddleware"
  • 原理:用 模块路径:类名 的格式,动态导入并匹配中间件。
  • 优点:可以精确指定任意模块的中间件,支持在 YAML/JSON 等配置文件中写配置,不用提前导入。
  • 缺点:写法稍长,IDE 无法直接校验,写错会在运行时才报错。
  • 适用场景:配置文件(如 YAML)中动态配置,或者需要排除自定义模块中的中间件。
1
2
3
4
5
# 示例 YAML 配置
harness_profile:
excluded_middleware:
- "some.module:SummarizationMiddleware"
- "my_pkg.middleware:TelemetryMiddleware"

三种方式对比表

方式 格式 优点 缺点 最佳场景
直接传类 SummarizationMiddleware 类型安全、IDE 友好 只能在代码中使用 Python 代码内配置、开发阶段
传字符串名称 "中间件类名" 写法简单、无需导入 可能重名误删、无类型校验 快速排除已知中间件
传导入引用 "模块:类名" 精确匹配、支持配置文件 运行时才校验、IDE 不友好 YAML/JSON 配置、自定义中间件

💡 关键补充说明

  1. 优先级:这三种方式的排除效果是一样的,框架会同时支持三种匹配逻辑,选你觉得方便的就行。
  2. 避坑提醒:像 FilesystemMiddleware 这类骨架级中间件是不能被排除的,强行排除会直接抛 ValueError,正确的做法是用 excluded_tools 隐藏它对应的工具。

Deep Agents 中 Profile 的注册键层级与配置合并逻辑

核心是 “通用配置打底,专用配置叠加覆盖”。

注册键的两种层级

Profile 的注册键分为两个层级,作用范围不同:

层级 写法示例 生效范围
供应商级别 openai 配置对该供应商下所有模型生效,相当于 “全局默认配置”
模型级别 openai:gpt-5.4 配置仅对特定模型生效,相当于 “模型专属定制配置”

核心合并逻辑(优先级规则)

当你同时注册了供应商级和模型级的 Profile 时,框架会按以下顺序自动合并配置:

1️⃣ 供应商级打底

先用供应商级别的配置作为基础模板,比如给 openai 配置了 “默认用中文回答”“禁用 execute 工具”,所有 OpenAI 模型都会先继承这一套配置。

2️⃣ 模型级覆盖

模型级配置会和供应商级配置合并,规则是:

  • 模型级未设置的字段:继承供应商级配置
  • 模型级已设置的字段:直接覆盖供应商级配置
  • 例:供应商级配置了 system_prompt_suffix="用中文回答",模型级配置了 system_prompt_suffix="用中文回答,且只返回JSON",最终会使用模型级的版本。

3️⃣ 重复注册继续合并

即使对同一个键(比如 openai:gpt-5.4)多次注册 Profile,框架也不会直接替换旧配置,而是继续叠加合并。

  • 例:第一次注册配置了 “禁用 execute 工具”,第二次注册配置了 “禁用 search 工具”,最终两个工具都会被禁用。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from deepagents import HarnessProfile, register_harness_profile

# 1. 供应商级配置(所有 openai 模型生效)
register_harness_profile(
"openai",
HarnessProfile(
system_prompt_suffix="用中文回答。",
excluded_tools={"execute"},
)
)

# 2. 模型级配置(仅 openai:gpt-5.4 生效)
register_harness_profile(
"openai:gpt-5.4",
HarnessProfile(
system_prompt_suffix="用中文回答,且只返回JSON格式。",
excluded_middleware={"SummarizationMiddleware"},
)
)

# 3. 对同一个模型再次注册配置(叠加生效)
register_harness_profile(
"openai:gpt-5.4",
HarnessProfile(
excluded_tools={"search"},
)
)

最终合并后的配置效果

字段 最终值 来源说明
system_prompt_suffix "用中文回答,且只返回JSON格式。" 模型级覆盖了供应商级
excluded_tools {"execute", "search"} 供应商级的 execute + 第二次注册的 search,叠加生效
excluded_middleware {"SummarizationMiddleware"} 模型级新增,供应商级未设置,所以直接保留

这种分层 + 合并的设计,让你可以:

  • 供应商级配置统一管控同品牌模型的通用规则(比如语言、工具限制)
  • 模型级配置给特定模型做个性化微调,不影响其他模型
  • 多次注册实现模块化配置(比如按功能拆分不同的 Profile,最后合并生效)

各字段合并方式

字段 所属 Profile 类型 合并方式 通俗理解
base_system_prompt Harness 新值一旦设置就直接覆盖旧值;未设置则保持原样 非黑即白,要么完全继承,要么完全替换
system_prompt_suffix Harness 新值一旦设置就直接覆盖旧值;未设置则保持原样 优先级最高的指令,写了就会直接替换
tool_description_overrides Harness 按工具名合并字典,同一工具名的新描述覆盖旧描述 增量更新工具说明,只改指定工具
excluded_tools Harness 并集,新旧排除项叠加 越配置禁用的工具越多,不会被覆盖
excluded_middleware Harness 并集,新旧排除项叠加 越配置禁用的中间件越多,不会被覆盖
extra_middleware Harness 按中间件类合并:同类型在原位置替换,新类型追加到末尾 重复的替换,新的往后排
general_purpose_subagent Harness 逐字段合并,未设置的字段沿用原值 只更新你指定的子智能体配置,其他不变
init_kwargs Provider 按字典键合并,同一键的新值覆盖旧值 增量更新模型初始化参数
pre_init Provider 按顺序串联执行:原有先执行,新的接在后面 初始化钩子按注册顺序依次执行
init_kwargs_factory Provider 工厂函数按顺序串联,解析模型时合并所有工厂的输出 多个参数工厂的输出会合并为最终配置

1. base_system_prompt / system_prompt_suffix

  • 合并规则:新值一旦设置就直接覆盖旧值;没设置的话保持原样。

  • 通俗理解:非黑即白,要么完全继承旧值,要么完全替换。

  • 示例

    1
    2
    3
    4
    5
    # 供应商级
    HarnessProfile(system_prompt_suffix="用中文回答。")
    # 模型级
    HarnessProfile(system_prompt_suffix="用中文回答,只返回JSON。")
    # 最终结果:"用中文回答,只返回JSON。"(模型级直接覆盖)

2. tool_description_overrides

  • 合并规则:按工具名合并字典,同一个工具名上新描述覆盖旧描述。

  • 通俗理解:工具描述的 “增量更新”,只改你指定的工具,其他不变。

  • 示例

    1
    2
    3
    # 旧配置:{"search": "搜索工具", "execute": "执行工具"}
    # 新配置:{"search": "全网搜索工具"}
    # 最终结果:{"search": "全网搜索工具", "execute": "执行工具"}

3. excluded_tools / excluded_middleware

  • 合并规则:取并集,新旧排除项叠加,不会漏掉。

  • 通俗理解:越配置,禁用的东西越多,不会被覆盖。

  • 示例

    1
    2
    3
    # 旧配置:{"execute"}
    # 新配置:{"search"}
    # 最终结果:{"execute", "search"}(两个都被排除)

4. extra_middleware

  • 合并规则:按中间件具体类合并:

    • 同类型则在原位置替换
    • 全新类则追加到末尾
  • 通俗理解:重复的替换,新的往后排。

  • 示例

    1
    2
    3
    4
    # 旧配置:[LoggingMiddleware, AuthMiddleware]
    # 新配置:[LoggingMiddleware, TelemetryMiddleware]
    # 最终结果:[LoggingMiddleware, AuthMiddleware, TelemetryMiddleware]
    # (LoggingMiddleware被替换,TelemetryMiddleware追加到末尾)

5. general_purpose_subagent

  • 合并规则:逐字段合并,未设置的字段沿用原来的值。

  • 通俗理解:子智能体配置的 “部分更新”,只改你指定的字段。

  • 示例

    1
    2
    3
    # 旧配置:enabled=True, name="助手", system_prompt="你是助手"
    # 新配置:system_prompt="你是代码助手"
    # 最终结果:enabled=True, name="助手", system_prompt="你是代码助手"

6. init_kwargs(Provider 专用)

  • 合并规则:按字典键合并,同一个键上新值覆盖旧值。

  • 通俗理解:模型初始化参数的 “增量更新”,类似 tool_description_overrides

  • 示例

    1
    2
    3
    # 旧配置:{"temperature": 0.7, "max_tokens": 1000}
    # 新配置:{"temperature": 0.2}
    # 最终结果:{"temperature": 0.2, "max_tokens": 1000}

7. pre_init(Provider 专用)

  • 合并规则:按顺序串联执行:原有的先执行,新的接在后面。

  • 通俗理解:初始化前的钩子函数会按注册顺序依次执行,不会被覆盖。

  • 示例

    1
    2
    3
    # 旧pre_init:检查API密钥
    # 新pre_init:记录初始化日志
    # 执行顺序:检查API密钥 → 记录初始化日志

8. init_kwargs_factory(Provider 专用)

  • 合并规则:工厂函数按顺序串联,每次解析模型时合并所有工厂的输出。

  • 通俗理解:多个参数工厂的输出会合并成最终的 init_kwargs

  • 示例

    1
    2
    3
    # 工厂1输出:{"temperature": 0.7}
    # 工厂2输出:{"max_tokens": 1000}
    # 最终init_kwargs:{"temperature": 0.7, "max_tokens": 1000}

💡 核心避坑指南

  1. 覆盖型 vs 叠加型
    • 覆盖型base_system_prompt / system_prompt_suffixinit_kwargstool_description_overrides → 新值会替换旧值,只保留你最后设置的内容。
    • 叠加型excluded_tools / excluded_middlewareextra_middlewarepre_init → 配置会越来越多,不会被替换。
  2. 子智能体配置是 “部分更新”general_purpose_subagent 只会修改你指定的字段,其他字段会继承旧值,不会重置。
  3. Provider 钩子的顺序性pre_initinit_kwargs_factory 都是按注册顺序执行的,顺序会影响最终效果。

预配置模型实例的 Profile 查找顺序

预配置模型实例的 Profile 查找顺序

当你把一个已经构造好的聊天模型实例传给 create_deep_agent 时,Deep Agents 会按下面的优先级顺序匹配 Profile:

  1. 精确匹配(最高优先级)

    • 匹配方式:用完整的 provider:identifier 键进行匹配,比如 openai:gpt-5.4

    • 效果:只有完全匹配这个键的 Profile 才会被选中,优先级最高

  2. Identifier 匹配(次优先级)

    • 匹配方式:仅用 identifier 部分匹配(前提是 identifier 本身包含 :,比如模型标识是 gpt-5:4

    • 效果:当完整键匹配不到时,会尝试用模型的标识符部分单独匹配 Profile

  3. Provider 降级匹配(最低优先级)

    • 匹配方式:降级到仅用 provider(供应商)匹配,比如 openai

    • 效果:如果前面两种都匹配不到,就会用供应商级别的 Profile 作为兜底配置

为什么没有 “一键全选” 的通配键?

Profiles 的设计初衷是与特定模型绑定,因此不存在类似 * 的通配符键。

  • 如果你需要 “无论用什么模型都生效” 的全局调整,不能靠 Profiles
  • 正确做法:直接写在 create_deep_agent 的调用参数里(比如直接传 system_promptexcluded_tools 等参数),而不是通过 Profiles 配置

💡 核心逻辑总结

  1. 匹配优先级:完整模型键 > 模型标识符 > 供应商键,框架会从最具体到最通用依次尝试匹配。
  2. Profiles 是模型绑定的:Profiles 只能针对特定供应商或模型生效,不能实现真正的 “全局所有模型生效”,全局配置要写在调用参数里。

Provider Profile:决定模型怎么“出生“

ProviderProfile 是什么?

ProviderProfile 是 Deep Agents 中专门负责模型初始化过程的配置,和 HarnessProfile 不同:

  • HarnessProfile 管的是模型运行时的行为(提示词、工具、中间件等)
  • ProviderProfile 只影响模型被创建的那一瞬间,也就是 init_chat_model 的过程

⚠️ 关键前提:它只有在你用字符串 "供应商:模型" 的方式让框架自己初始化模型时才会生效;如果你直接传入一个已经构造好的模型实例,它是不起作用的。

示例代码

1
2
3
4
5
6
from deepagents import ProviderProfile, register_provider_profile

register_provider_profile(
"openai",
ProviderProfile(init_kwargs={"temperature": 0}),
)
  • 这段代码的效果:所有 OpenAI 模型在被框架初始化时,都会默认把 temperature 设置为 0(即模型输出更确定、少随机)。

  • 后续你调用 create_deep_agent(model="openai:gpt-4o") 时,框架会自动把这个参数带上。

核心字段详解

字段 作用 通俗理解 典型场景
init_kwargs 静态参数字典,原封不动传给 init_chat_model 给模型设置固定的默认参数 设置 temperaturemax_tokenstop_p等固定超参数
pre_init 可调用对象,在模型初始化之前执行 模型创建前的 “钩子”,用来做检查和准备 检查 API 密钥是否存在、验证环境变量、打印初始化日志
init_kwargs_factory 无参数可调用对象,返回参数字典,每次解析模型时重新调用 动态生成初始化参数 从配置中心动态获取模型地址、从上下文读取用户自定义参数

合并逻辑规则

三个字段的合并方式:

  1. init_kwargs:按字典键合并,同一个键上新值覆盖旧值(类似普通字典更新)。
    • 例:供应商级设置 {"temperature": 0.7},模型级设置 {"temperature": 0.2},最终 temperature0.2
  2. pre_init:按顺序链式执行,所有注册的 pre_init 函数都会依次执行,不会被覆盖。
    • 例:第一个 pre_init 检查密钥,第二个 pre_init 打印日志,两个都会按顺序运行。
  3. init_kwargs_factory:按顺序链式执行,每次解析模型时,所有工厂函数的输出都会合并成最终的 init_kwargs
    • 例:工厂 1 返回 {"temperature": 0.7},工厂 2 返回 {"max_tokens": 1000},最终合并为 {"temperature": 0.7, "max_tokens": 1000}

ProviderProfile 的核心价值,是把模型初始化的细节从业务代码中抽离出来:

  • 你可以集中管理不同供应商 / 模型的默认参数
  • 可以统一做初始化前的校验和准备工作
  • 支持动态参数注入,而不用修改核心业务代码

完整的示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from deepagents import (
ProviderProfile,
register_provider_profile,
create_deep_agent,
)

# ------------------------------
# 1. 定义 pre_init 钩子:模型初始化前的检查和日志
# ------------------------------
def check_openai_api_key():
"""检查 OpenAI API Key 是否设置"""
import os
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise ValueError("❌ 初始化失败:OPENAI_API_KEY 环境变量未设置!")
print("✅ 已验证 OpenAI API Key")

def log_model_init():
"""打印模型初始化日志"""
print("🚀 正在初始化 OpenAI 模型...")


# ------------------------------
# 2. 定义 init_kwargs_factory:动态获取运行时参数
# ------------------------------
def get_dynamic_openai_params():
"""从环境变量动态获取模型参数"""
import os
return {
"temperature": float(os.getenv("OPENAI_TEMPERATURE", "0.3")),
"max_tokens": int(os.getenv("OPENAI_MAX_TOKENS", "2048")),
}


# ------------------------------
# 3. 注册供应商级别的 ProviderProfile(所有 OpenAI 模型生效)
# ------------------------------
register_provider_profile(
"openai",
ProviderProfile(
# 静态默认参数
init_kwargs={
"model": "gpt-3.5-turbo", # 全局默认模型
"timeout": 30, # 全局超时设置
},
# 初始化前钩子(会按顺序执行)
pre_init=[check_openai_api_key, log_model_init],
# 动态参数工厂(每次解析模型时重新调用)
init_kwargs_factory=get_dynamic_openai_params,
),
)

# ------------------------------
# 4. 注册模型级别的 ProviderProfile(仅对 gpt-4 生效)
# ------------------------------
register_provider_profile(
"openai:gpt-4",
ProviderProfile(
# 覆盖供应商级的静态参数
init_kwargs={
"model": "gpt-4",
"temperature": 0.1, # 会覆盖环境变量的默认值
"max_tokens": 4096, # 会覆盖环境变量的默认值
},
),
)

# ------------------------------
# 5. 使用示例:创建智能体
# ------------------------------
if __name__ == "__main__":
# 方式1:使用供应商默认配置(会匹配 "openai" 级别的 Profile)
agent_gpt35 = create_deep_agent(model="openai:gpt-3.5-turbo")
print("✅ gpt-3.5-turbo 智能体创建完成")

# 方式2:使用模型级定制配置(会匹配 "openai:gpt-4" 级别的 Profile)
agent_gpt4 = create_deep_agent(model="openai:gpt-4")
print("✅ gpt-4 智能体创建完成")

用配置文件管理:告别硬编码

背景:为什么需要 YAML/JSON 配置?

在开发阶段,直接把 HarnessProfile 写在 Python 代码里很方便,但到了生产环境会有几个问题:

  • 配置和业务代码耦合,改配置要重新发布、部署
  • 多环境(开发 / 测试 / 生产)的配置差异不好管理
  • 非开发人员(比如运维、产品)无法直接修改配置

HarnessProfileConfig 就是为了解决这个问题,它把 HarnessProfile 里的纯数据部分提取出来,支持用 YAML/JSON 文件配置,而运行时的 Python 对象逻辑仍然留在 HarnessProfile 中。

YAML配置示例

openai.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 替换基础系统提示词,相当于给智能体重写初始人格
base_system_prompt: You are helpful.

# 在所有提示词末尾追加指令,强制模型回答简洁
system_prompt_suffix: Respond briefly.

# 排除工具:execute 和 grep 工具会被移除,模型无法调用
excluded_tools:
- execute
- grep

# 排除中间件:
# 1. SummarizationMiddleware:按名称排除
# 2. my_pkg.middleware:TelemetryMiddleware:按模块路径排除(支持自定义中间件)
excluded_middleware:
- SummarizationMiddleware
- my_pkg.middleware:TelemetryMiddleware

# 配置通用子智能体:直接禁用
general_purpose_subagent:
enabled: false

核心优势与用法

  1. 数据与逻辑分离
  • YAML/JSON 文件:只存纯数据配置(字符串、列表、字典等),任何人都能看懂和修改
  • Python 代码:保留运行时逻辑(比如中间件类、函数钩子),不暴露给配置文件
  1. 如何在代码中加载 YAML 配置?

下面是对应的 Python 加载示例,你可以直接用:

1
2
3
4
5
6
7
8
import yaml
from deepagents import HarnessProfileConfig, register_harness_profile

with open("openai.yaml") as f:
register_harness_profile(
"openai",
HarnessProfileConfig.from_dict(yaml.safe_load(f)),
)
  1. 导入依赖

    • import yaml:用于解析 YAML 配置文件

    • HarnessProfileConfig:专门用来加载纯数据配置的类

    • register_harness_profile:注册配置的核心函数

  2. 加载并注册配置

    • with open("openai.yaml") as f:打开 YAML 配置文件

    • yaml.safe_load(f):安全解析 YAML 文件,得到 Python 字典

    • HarnessProfileConfig.from_dict(...):把字典转换成框架可识别的配置对象

    • register_harness_profile("openai", ...):把配置注册给 openai 供应商级别的所有模型

配置文件只能承载纯声明式的数据。如果 Profile 里包含了用代码写的中间件实例、工厂函数,或者是类形式的 excluded_middleware 条目,那还是得回到 Python 里用 HarnessProfile 注册。

关键说明

  1. 支持的字段:YAML/JSON 中只能配置 HarnessProfile 里的纯数据字段,比如:

    • base_system_prompt / system_prompt_suffix

    • excluded_tools / excluded_middleware

    • tool_description_overrides

    • general_purpose_subagent 的基础配置

      extra_middleware这类需要 Python 对象的字段,还是要在代码中配置。

  2. 合并逻辑不变:通过 HarnessProfileConfig 注册的配置,和直接在代码中写的 HarnessProfile 遵循完全一样的合并规则(供应商级→模型级叠加覆盖)。