乐于分享
好东西不私藏

【用DeepWiki学源码】Serena模板模块实现机制

【用DeepWiki学源码】Serena模板模块实现机制

直接读源码会导致抓不住重点,通过如上类图,结合源码,可以迅速建立对模块的理解。

底层:基础模板类

1. JinjaTemplate

目的: 封装 Jinja2 模板引擎,提供模板渲染和参数提取功能。 

关键方法:

  • render(**params): 使用提供的参数渲染模板,返回字符串

  • get_parameters(): 提取模板中的变量参数列表(从 {{ }} 中推断)

2. PromptTemplate

目的: 表示单个提示模板,为 JinjaTemplate 添加名称标识。 

功能:

  • 实现 ParameterizedTemplateInterface 接口 

  • 存储模板名称和 Jinja 模板字符串

  • 在初始化时自动去除模板字符串的首尾空白

关键方法:

  • __init__(name, jinja_template_string): 创建模板实例,初始化 _jinja_template

  • render(**params): 委托给内部 _jinja_template.render()

  • get_parameters(): 返回模板参数列表 

3. PromptList

目的: 表示提示列表,将字符串列表格式化为可读的项目符号格式。 

功能:

  • 存储字符串列表,自动去除每项的首尾空白

  • 提供格式化输出功能

关键方法:

  • __init__(items): 初始化列表,对每项执行 strip()

  • to_string(): 格式化为带缩进的项目符号列表,处理多行项目的缩进对齐

中层:多语言容器

4. LanguageFallbackMode (枚举)

目的: 定义当请求的语言不存在时的回退策略。 

三种模式:

  • ANY: 返回任意语言(第一个找到的)

  • EXCEPTION: 抛出 KeyError 异常

  • USE_DEFAULT_LANG: 回退到默认语言

5. _MultiLangContainer[T]

目的: 泛型容器基类,管理同一语义实体的多语言版本。 

数据结构:

  • _lang2item: dict[str, T]: 语言代码到项目的映射 

关键方法:

  • add_item(item, lang_code, allow_overwrite): 添加特定语言的项目,默认不允许覆盖 

  • has_item(lang_code): 检查是否存在指定语言的项目 

  • get_item(lang, fallback_mode): 获取项目,支持回退策略。实现逻辑:先尝试直接获取,失败后根据 fallback_mode 决定是抛异常、返回任意语言或使用默认语言 

6. MultiLangPromptTemplate

目的: 管理单个提示模板的多语言版本,确保所有语言版本参数一致。 

功能:

  • 实现 ParameterizedTemplateInterface 接口

  • 内部使用 _MultiLangContainer[PromptTemplate] 存储不同语言版本

  • 参数一致性验证

关键方法:

  • add_prompt_template(prompt_template, lang_code, allow_overwrite): 添加新语言版本。如果已有其他语言版本,会验证参数是否一致,不一致则抛出 ValueError 

  • get_prompt_template(lang_code, fallback_mode): 获取指定语言的 PromptTemplate

  • get_parameters(): 返回模板参数列表(从第一个语言版本获取,因为所有版本参数相同) 

  • render(params, lang_code, fallback_mode): 渲染指定语言的模板 

7. MultiLangPromptList

目的: 管理提示列表的多语言版本。 

实现: 直接继承 _MultiLangContainer[PromptList],无额外逻辑。

上层:集合管理

8. MultiLangPromptCollection

目的: 主要管理类,从 YAML 文件加载并管理所有提示模板和列表。 

数据结构:

  • _multi_lang_prompt_templates: dict[str, MultiLangPromptTemplate]: 模板名称到多语言模板的映射 

  • _multi_lang_prompt_lists: dict[str, MultiLangPromptList]: 列表名称到多语言列表的映射 

关键方法:

初始化和加载:

  • __init__(prompts_dir, fallback_mode): 支持单个或多个目录,实现优先级加载机制。第一个目录优先级最高,后续目录的同名提示被忽略 

  • _load_from_disc(prompts_dir, on_name_collision): 从目录加载所有 .yml/.yaml 文件,解析 YAML 并根据值类型(字符串或列表)调用 _add_prompt_template 或 _add_prompt_list

添加方法:

  • _add_prompt_template(name, template_str, lang_code, on_name_collision): 创建 

    PromptTemplate,添加到对应的 MultiLangPromptTemplate。如果模板名称不存在,先创建 MultiLangPromptTemplate

  • _add_prompt_list(name, prompt_list, lang_code, on_name_collision): 类似逻辑,处理提示列表

查询方法:

  • get_prompt_template_names(): 返回所有模板名称列表

  • get_prompt_list_names(): 返回所有列表名称 

  • get_prompt_template(prompt_name, lang_code): 获取指定模板的 PromptTemplate 对象 

  • get_prompt_template_parameters(prompt_name): 获取模板参数列表 

  • get_prompt_list(prompt_name, lang_code): 获取指定列表的 PromptList 对象 

渲染方法:

  • render_prompt_template(prompt_name, params, lang_code): 直接渲染模板并返回字符串,是最常用的方法

工厂层

9. PromptFactoryBase

目的: 提示工厂基类,为子类提供模板渲染和列表获取的统一接口。 

数据结构:

  • lang_code: 存储的语言代码

  • _prompt_collectionMultiLangPromptCollection 实例 

关键方法:

  • __init__(prompts_dir, lang_code, fallback_mode): 创建 MultiLangPromptCollection 实例 

  • _render_prompt(prompt_name, params): 受保护方法,删除 params 中的 self 键(避免将实例传递给模板),然后委托给 _prompt_collection.render_prompt_template()

  • _get_prompt_list(prompt_name): 受保护方法,委托给 _prompt_collection.get_prompt_list()

10. autogenerate_prompt_factory_module (函数)

目的: 代码生成函数,扫描提示目录并生成 PromptFactory 类。 

实现流程:

  1. 创建临时 MultiLangPromptCollection 扫描提示 

  2. 为每个模板生成 create_<name> 方法,包含参数签名 

  3. 为每个列表生成 get_list_<name> 方法 

  4. 写入生成的 Python 代码到目标文件 

11. PromptFactory (自动生成)

目的: 自动生成的类,为每个提示模板和列表提供类型安全的方法。 

示例方法:

  • create_onboarding_prompt(*, system): 调用 _render_prompt('onboarding_prompt', locals())

  • create_system_prompt(*, available_markers, available_tools, ...): 带多个参数的模板渲染<cite repo=”oraios/serena

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 【用DeepWiki学源码】Serena模板模块实现机制

评论 抢沙发

8 + 2 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮