// Package context - chinese_bundle.go 定义中文系统提示词 Bundle. // // NewChineseBundle 返回一个全中文静态段落的 PromptBundle, // 动态段落(env_info,tool_descs,instructions,append_prompt 等)继承自 DefaultBundle. // // 适用场景: // - 接入中文语言模型(Qwen,Deepseek,Baidu ERNIE 等) // - 用户语言偏好为中文的部署环境 // - 需要验证"中文指令 vs 英文指令"效果差异的 A/B 实验 // // 注册示例: // // eng.RegisterPromptBundle( // engine.BundleKeyFor("qwen", "programming"), // context.NewChineseBundle(), // ) // // // 或通过 RunOption per-request 切换: // eng.Run(ctx, prompt, engine.WithBundleKey(engine.BundleKeyFor("qwen", "programming"))) // // 设计决策: // // - 静态段落全部替换为中文版本(prompts_zh.go),语义与英文版一字不差. // - 动态段落(env_info 读取 cwd/platform,instructions 读取 FLYTO.md, // tool_descs 从注册表生成)继承 DefaultBundle--这些段落的内容由运行时 // 注入值决定,与语言无关. // - 不修改 DefaultBundle--中文 Bundle 是独立注册的新 Bundle, // 不影响已验证的英文 claude+programming Bundle 的稳定性. package context // chineseProgrammingBundle 是全中文静态段落的 PromptBundle 实现. // // 升华改进(ELEVATED): 早期实现 只有英文提示词,无法适配中文语言模型. // 我们通过 BundleRegistry 机制注册中文 Bundle, // 无需修改任何现有代码即可让引擎在中文模型上使用中文提示词. // CLI/SDK/API 三种模式都能通过 BundleKey 选择此 Bundle, // 且与英文 Bundle 完全隔离--中文 Bundle 的修改不影响英文 Bundle. // 替代方案:<在 DefaultBundle 中添加语言切换逻辑(if lang == "zh")> // - 否决原因:将两种语言的逻辑耦合在同一个 Bundle 中, // 任何修改都要同时维护两个语言版本,且测试边界不清晰. type chineseProgrammingBundle struct{} // NewChineseBundle 创建中文版 PromptBundle 实例. // // 静态段落(角色定义,任务准则,操作安全,工具指南,Git 协议等) // 全部使用 prompts_zh.go 中的中文常量. // 动态段落继承 DefaultBundle 的实现(env_info,tool_descs,instructions 等). func NewChineseBundle() PromptBundle { return &chineseProgrammingBundle{} } // StaticSections 返回 8 个中文静态提示词段落. // // 精妙之处(CLEVER): 段落 Name 与 DefaultBundle 完全一致("intro","doing_tasks" 等)-- // SectionRegistry 以 Name 为缓存 key,相同 Name 在同一 registry 中共享缓存条目. // 这意味着:如果同一个引擎实例先使用了英文 Bundle(填充了缓存), // 再切换到中文 Bundle,因为内容不同,中文 Bundle 的 Compute 调用会写入新值, // 覆盖英文版缓存--这是预期行为,不是 Bug. // 若要避免缓存污染(多租户场景下两种 Bundle 并存), // 应为中文 Bundle 的 section 使用带前缀的 Name(如 "zh.intro"). // 当前实现假设同一 Engine 实例只使用一种语言 Bundle,满足大多数部署场景. func (b *chineseProgrammingBundle) StaticSections() []*Section { return []*Section{ StaticSection("intro", sectionIntroZH), StaticSection("system", sectionSystemZH), StaticSection("doing_tasks", sectionDoingTasksZH), StaticSection("actions", sectionActionsZH), StaticSection("using_tools", sectionUsingToolsZH), StaticSection("search_code", sectionSearchCodeZH), StaticSection("tone_and_style", sectionToneAndStyleZH), StaticSection("output_efficiency", sectionOutputEfficiencyZH), StaticSection("git_protocol", sectionGitProtocolZH), } } // DynamicSections 返回动态提示词段落(与 DefaultBundle 完全相同). // // 历史包袱(LEGACY): 动态段落的计算函数(computeInstructionsSection, // computeToolDescsSection,computeEnvInfoSection 等)直接复用 DefaultBundle 的实现. // 理想情况下,动态段落也应该支持中文化(如用中文写 env_info 头部文字). // 当前保持不变是因为:env_info 中大部分是变量值(路径,模型 ID), // 少量固定文字("# Environment")用中文对模型行为影响极小, // 且 computeEnvInfoSection 是独立函数,不易通过 Bundle 覆盖. // 未来改进:考虑将 computeEnvInfoSection 的头部文字提取为可配置参数. func (b *chineseProgrammingBundle) DynamicSections() []*Section { // 直接复用 DefaultBundle 的动态 sections // 精妙之处(CLEVER): 不持有 DefaultBundle 实例--直接调用其动态 section 函数. // 若持有实例则引入不必要的间接层;直接复用函数引用更简洁, // 且与 defaultClaudeProgrammingBundle.DynamicSections() 保持结构一致. return NewDefaultBundle().DynamicSections() } // --------------------------------------------------------------------------- // 便捷注册函数 // --------------------------------------------------------------------------- // ChineseBundleKeys 返回中文 Bundle 推荐注册的 BundleKey 列表. // // 当前包含主流中文语言模型的模型族标识符. // 调用方可以用此列表批量注册,也可以自行选择注册子集. // // 用法: // // for _, key := range context.ChineseBundleKeys() { // eng.RegisterPromptBundle(key, context.NewChineseBundle()) // } func ChineseBundleKeys() []BundleKey { return []BundleKey{ {ModelFamily: "qwen", Scenario: "programming"}, {ModelFamily: "deepseek", Scenario: "programming"}, {ModelFamily: "ernie", Scenario: "programming"}, {ModelFamily: "glm", Scenario: "programming"}, {ModelFamily: "hunyuan", Scenario: "programming"}, } } // RegisterChineseBundle 将中文 Bundle 批量注册到指定的 BundleRegistry. // // 升华改进(ELEVATED): 提供一键注册函数,降低 SDK 用户的接入成本-- // 不需要了解 ChineseBundleKeys() 列表,也不需要手动循环注册. // 与 NewDefaultBundleRegistry 的设计一致(工厂函数 vs 手动注册). // 替代方案:<要求调用方手动循环注册> // - 否决原因:样板代码重复,且当支持的模型族列表变化时, // 每个调用方都要手动更新,维护成本分散. func RegisterChineseBundle(r *BundleRegistry) { bundle := NewChineseBundle() for _, key := range ChineseBundleKeys() { r.Register(key, bundle) } }