释放重复工时,用 TRAE 打造个性化智能编程工作流

大模型向量数据库云通信

picture.image

本文作者:Ida,对移动端开发拥有深厚的技术积累。近年来,积极探索如何利用 AI 技术提升日常工作效率,并尝试将生成式 AI 应用于研发流程优化。曾参与多个复杂项目的开发与维护,擅长将创新技术融入实际场景,提升用户体验。热爱分享技术心得,致力于让更多人了解并掌握前沿科技。

当基础编码效率提升后,如何让 TRAE 成为真正懂你的 AI 工程师?本文将聚焦 Agent、Rules、图像理解等进阶能力,通过真实案例展示如何系统性提升开发效率,打造专属 AI 工作流。

picture.image

用 Agent 进一步提效

TRAE 目前支持自定义 Agent,用一段做特定任务的提示词就可以创建一个 Agent,也可以给 Agent 关联上 MCP Tools,并在提示词中编排如何去调用它们。

在过往的开发中,你可能已经发现,有一些提示词会反复用来做某一个特定事情,之前是把这些提示词记到小本本上,用的时候复制过来,现在就可以用它们来创建 Agent 啦,如果提示词具有普适性,还可以直接将 Agent 分享给别人去使用,下面列举一些例子供大家参考。

Case 1:为关键链路补充 ALog

ALog 是抖音里用来打印日志的,当线上用户发生问题时可以回捞这部分日志,用来分析当时用户的代码执行过程,所以通常我们会在关键代码逻辑处,和异常返回处加上 ALog。

现在我们来把诉求告知 AI,然后让它来生成一份更加完善的提示词,再用这份提示词创建一个“抖音 ALog 助手”:

picture.image

picture.image

找一份老代码,用这个助手为其加上 ALog,我们来看看效果:

picture.image

picture.image

picture.image

几秒钟的功夫,它就洋洋洒洒地给该文件加上了足够细致的 log,而且拼接出来的语句也都带上了关键的信息。这里不贴生成的提示词了,有需要的同学可以直接复制下面的链接添加到 TRAE 里:

我用 TRAE 做了一个有意思的 Agent 「抖音 ALog 助手」。 点击 https://share.bytedance.net/a/d86a16 立即复刻,一起来玩吧!

Case 2: 给老代码加上注释

同样地,我们也可以创建一个给老代码加注释的 Agent,提高代码阅读的效率。

picture.image

picture.image

picture.image

效果验证

同样分享一下这个 Agent,大家也可以基于这份提示词再继续加工优化:

我用 TRAE 做了一个有意思的 Agent 「代码注释精灵」。 点击 https://share.bytedance.net/a/4f4fbf 立即复刻,一起来玩吧!

Case 3: 生成 UI 代码

UI 代码的生成也可以通过 Agent 一步到位完成,预期它要做的事情:

  • 调用 Figma MCP 工具生成 UI 代码。

  • 如果是生成 Swift 代码,需要使用 SnapKit 布局。

  • 如果是生成 Objective-C 代码,需要使用 Masonry 布局。

在 TRAE 的官方 MCP 市场中可以找到 Figma,然后按照官方指引获取 FIGMA_API_KEY 配置上即可。

picture.image

picture.image

picture.image

再编写提示词,内容如下:

上下滑动查看完整内容

  
你是一个 UI 代码生成助手 Agent。  
  
你的主要任务是根据 Figma 设计稿生成高质量的 UI 代码。请遵循以下指示:  
  
1.  **调用 Figma MCP 工具**:使用 `Figma` 工具从设计稿中提取必要的布局信息和组件规范,并基于此生成初始的 UI 代码。  
    *   **ICON 处理**:如果设计稿中包含 ICON,请确保导出并使用 PNG 格式的 3x 分辨率图。  
  
2.  **Swift 代码生成规范**    *   如果目标语言是 Swift,你必须使用 SnapKit 框架进行布局。确保生成的约束代码简洁、易读,并符合 SnapKit 的最佳实践。  
  
3.  **Objective-C 代码生成规范**    *   如果目标语言是 Objective-C,你必须使用 Masonry 框架进行布局。  
  
4.  **代码质量与组件管理**    *   **变量定义**:默认情况下,所有生成的 UI 视图组件都应作为局部临时变量进行定义和使用。除非用户明确指示需要将某个组件定义为属性(例如,为了后续在其他方法中访问或修改),否则不要将其声明为类的属性。  
    *   **注释规范**:生成的代码中应避免过度注释。注释应保持简洁明了,只在必要时解释复杂逻辑或重要意图,而不是简单描述代码做了什么。  
    *   生成的代码应具有良好的可读性和可维护性。  
    *   遵循项目既有的代码风格和命名约定。  
    *   确保生成的代码没有明显的性能问题。  
  
请在开始生成代码前,确认目标语言(Swift 或 Objective-C)和相关的设计稿信息。

现在可以创建 Agent 了,命名为【UI 魔法师】,并关联上Figma这个工具。最后测试一下效果:

上下滑动查看完整内容

  
#import "MyCardView.h"  
#import <Masonry/Masonry.h>  
  
@implementation MyCardView  
  
- (instancetype)initWithFrame:(CGRect)frame {  
    self = [super initWithFrame:frame];  
    if (self) {  
        [self setupUI];  
    }  
    return self;  
}  
  
- (void)setupUI {  
    self.layer.cornerRadius = 16;  
    self.layer.masksToBounds = YES;  
    self.layer.borderWidth = 1.5;  
    self.layer.borderColor = [UIColor colorWithWhite:1.0 alpha:0.15].CGColor;  
  
    // Background Gradient  
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];  
    gradientLayer.colors = @[  
        (id)[UIColor blackColor].CGColor,  
        (id)[UIColor blackColor].CGColor,  
        (id)[UIColor colorWithRed:0 green:0.267 blue:0.208 alpha:1.0].CGColor  
    ];  
    gradientLayer.locations = @[@0, @0.6, @1.0];  
    gradientLayer.frame = self.bounds;  
    [self.layer insertSublayer:gradientLayer atIndex:0];  
  
    // Icon  
    UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon.png"]];  
    [self addSubview:iconView];  
  
    // Title Label  
    UILabel *titleLabel = [[UILabel alloc] init];  
    titleLabel.text = @"我是标题";  
    titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightMedium];  
    titleLabel.textColor = [UIColor whiteColor];  
    titleLabel.textAlignment = NSTextAlignmentCenter;  
    [self addSubview:titleLabel];  
  
    // Subtitle Label  
    UILabel *subtitleLabel = [[UILabel alloc] init];  
    subtitleLabel.text = @"我是副标题的介绍;  
    subtitleLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];  
    subtitleLabel.textColor = [UIColor colorWithWhite:0.6 alpha:1.0];  
    subtitleLabel.textAlignment = NSTextAlignmentCenter;  
    subtitleLabel.numberOfLines = 0;  
    [self addSubview:subtitleLabel];  
  
    // Button  
    UIButton *matchButton = [UIButton buttonWithType:UIButtonTypeSystem];  
    [matchButton setTitle:@"开始旅程" forState:UIControlStateNormal];  
    [matchButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];  
    matchButton.titleLabel.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium];  
    matchButton.layer.cornerRadius = 12;  
    matchButton.layer.masksToBounds = YES;  
    [self addSubview:matchButton];  
      
    // Button Gradient  
    CAGradientLayer *buttonGradient = [CAGradientLayer layer];  
    buttonGradient.colors = @[  
        (id)[UIColor colorWithRed:0.2 green:1.0 blue:0.867 alpha:1.0].CGColor,  
        (id)[UIColor colorWithRed:0.533 green:1.0 blue:0.337 alpha:1.0].CGColor  
    ];  
    buttonGradient.startPoint = CGPointMake(0, 0.75);  
    buttonGradient.endPoint = CGPointMake(1, 1.1);  
    // The button's frame is set by autolayout, so we need to update the gradient layer's frame in layoutSubviews  
    [matchButton.layer insertSublayer:buttonGradient atIndex:0];  
  
    // Layout  
    [iconView mas_makeConstraints:^(MASConstraintMaker *make) {  
        make.top.equalTo(self.mas_top).offset(64);  
        make.centerX.equalTo(self);  
        make.width.height.mas_equalTo(120);  
    }];  
  
    [titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {  
        make.top.equalTo(iconView.mas_bottom).offset(8);  
        make.centerX.equalTo(self);  
    }];  
  
    [subtitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {  
        make.top.equalTo(titleLabel.mas_bottom).offset(4);  
        make.left.equalTo(self.mas_left).offset(84);  
        make.right.equalTo(self.mas_right).offset(-84);  
    }];  
  
    [matchButton mas_makeConstraints:^(MASConstraintMaker *make) {  
        make.bottom.equalTo(self.mas_bottom).offset(-16);  
        make.left.equalTo(self.mas_left).offset(16);  
        make.right.equalTo(self.mas_right).offset(-16);  
        make.height.mas_equalTo(44);  
    }];  
}  
  
- (void)layoutSubviews {  
    [super layoutSubviews];  
    for (CALayer *layer in self.layer.sublayers) {  
        if ([layer isKindOfClass:[CAGradientLayer class]]) {  
            layer.frame = self.bounds;  
        }  
    }  
    for (CALayer *layer in [self.subviews.lastObject layer].sublayers) {  
        if ([layer isKindOfClass:[CAGradientLayer class]]) {  
            layer.frame = self.subviews.lastObject.bounds;  
        }  
    }  
}  
  
@end

picture.image

picture.image

用 Rules 规范生成的代码

经过一段时间对 TRAE 的使用,就会发现,有一些要求需要每次都写在提示词中,代码风格有时也不稳定,好在目前 TRAE 已经支持了 Rules,我们可以把一些对生成代码的通用要求配置在这里。对于这个配置的提示词,也可以让 TRAE 来生成。

picture.image

picture.image

picture.image

对这份生成的提示词还比较满意,有需要的同学可以直接抱走~

上下滑动查看完整内容

  
# 代码风格规范指南  
  
以下规则旨在指导代码生成和修改,以确保代码库的一致性和可读性。  
## 1. 注释规范  
### 1.1. Swift 注释  
- **注释风格**:对于 Swift 代码,在为函数、类、属性、结构体等添加注释时,请始终使用三斜线注释 (`///`)。  
  ```swift  
  /// 这是一个描述该函数功能的注释。  
  /// - Parameter name: 参数的描述。  
  /// - Returns: 返回值的描述。  
  func exampleFunction(name: String) -> String {  
      // ...  
  }  
  /// 这是一个描述该类功能的注释。  
  class ExampleClass {  
      /// 这是一个描述该属性功能的注释。  
      var exampleProperty: Int = 0  
  }  

1.2. Objective-C 注释

  • 注释风格:对于 Objective-C 代码,在添加注释时,请始终使用三斜线注释 (///)。
    /// 这是一个描述该方法功能的注释。  
    /// @param parameterName 参数的描述。  
    /// @return 返回值的描述。  
    - (NSString *)exampleMethodWithParameter:(NSString *)parameterName;  
    /// 这是一个描述该属性功能的注释。  
    @property (nonatomic, strong, nullable) NSString *exampleProperty;  
    

1.3. 通用注释要求

  • 注释语言:所有注释内容请始终使用中文编写。
  • 注释简洁性:注释应保持简洁明了,清晰地解释代码的意图、功能或复杂逻辑。避免过度注释,尤其不应添加描述代码修改过程的无意义注释(例如:“把XXX修改成XXX”、“修复BUG”等)。注释的目的是解释代码的“为什么”和“做什么”,而不是记录显而易见的修改历史。

2. Swift 代码风格

  • SwiftLint 遵循:Swift 代码的格式化应严格遵守 SwiftLint 的规范。
  • 参数垂直对齐:特别注意 vertical_parameter_alignment 规则:当函数或方法声明中的参数因过长而占据多行时,这些参数应当垂直对齐。 0
    • 非触发示例 (Good): 0
      func validateFunction(_ file: SwiftLintFile, kind: SwiftDeclarationKind,  
                            dictionary: SourceKittenDictionary) { }  
      func validateFunction(  
         _ file: SwiftLintFile, kind: SwiftDeclarationKind,  
         dictionary: SourceKittenDictionary  
      ) -> [StyleViolation]  
      
    • 触发示例 (Bad - 需要修正): 0
      // SwiftLint会在此处报错  
      func validateFunction(_ file: SwiftLintFile, kind: SwiftDeclarationKind,  
                        dictionary: SourceKittenDictionary) { } // 'dictionary' 未对齐  
      func validateFunction(_ file: SwiftLintFile,  
                        kind: SwiftDeclarationKind,         // 'kind' 未对齐  
                        dictionary: SourceKittenDictionary) { } // 'dictionary' 未对齐  
      
    具体细节请参考 。 0

3. Objective-C 代码风格

  • Nullability 修饰符:为 Objective-C 代码生成方法(包括返回类型)和属性时,如果它们是指针类型,请始终为其添加 nullable 修饰符,除非上下文文明确要求 nonnull 或已知其永不为空。
    // 示例:  
    @property (nonatomic, strong, nullable) NSString *name;  
    @property (nonatomic, copy, nullable) NSArray<NSString *> *items;  
    - (nullable UIView *)viewWithTag:(NSInteger)tag;  
    - (void)processData:(nullable NSData *)data completion:(nullable void (^)(NSError * _Nullable error))completion;  
    
  • 头文件 NS_ASSUME_NULLABLE: 创建新的 Objective-C 头文件 (.h) 时,其内容应始终被 NS_ASSUME_NULLABLE_BEGINNS_ASSUME_NULLABLE_END 宏包裹。这有助于管理区域性的 nullability 注解。参考示例:
    // SomeClass.h  
    #import <Foundation/Foundation.h> // 或其他必要的 imports  
    NS_ASSUME_NULLABLE_BEGIN  
    @interface SomeClassName : NSObject  
    // 属性和方法声明在此处  
    @end  
    NS_ASSUME_NULLABLE_END  
    

4. 单例命名规范

  • 命名统一性:单例模式的实例访问方法或属性命名应保持统一规范:
    • Swift:在 Swift 代码中,单例实例请统一命名为 shared
      class DataManager {  
          static let shared = DataManager()  
          private init() {}  
      }  
      // 使用: DataManager.shared  
      
    • Objective-C:在 Objective-C 代码中,单例实例的获取方法请统一命名为 sharedInstance
      // DataManager.h  
      @interface DataManager : NSObject  
      + (instancetype)sharedInstance;  
      @end  
      // DataManager.m  
      @implementation DataManager  
      + (instancetype)sharedInstance {  
          static DataManager *sharedInstance = nil;  
          staticdispatch_once_t onceToken;  
          dispatch_once(&onceToken, ^{  
              sharedInstance = [[self alloc] init];  
          });  
          return sharedInstance;  
      }  
      - (instancetype)init {  
          self = [super init];  
          if (self) {  
              // 初始化代码  
          }  
          return self;  
      }  
      @end  
      // 使用: [DataManager sharedInstance]  
      













  



找了个文件测试了一下效果,看起来还不错,nullable 加上了,注释也都是按要求来的。


  







![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/3fb9370b11b2477497bc7bf9107baf5d~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=pNtbAOfVLqCyuzoyNm3nSJj8Tiw%3D)






![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/ffbf8c72811244659d6ca9f68a5ed2f6~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=3cs7ZWqC4%2BpfHlBl8FhJtWY%2BuTs%3D)






![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/f344997a38114fdd8784cd5340d8698a~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=jYUBExae%2Fpj%2BH61qDQsiZSqBjNU%3D)




  





![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/e8ee412298ad486fa89b7c4c0fdc7254~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=%2FREXMytg9kzfKFwlrDJVz8qukn8%3D)




**把图作为上下文使用** 




  




现在 TRAE 已经集成了 Gemini-2.5-Pro-Preview(0506)(最新版本中已经是 Gemini-2.5-Pro),**该模型支持图片理解** ,可以有效利用这一能力来节省写提示词的时间。前面有直接用类图生成代码的演示,这里再列举一些 Case。


  








**Case 1: 用线框图生成 debug 页面** 






  



当我们想在 Debug 面板中加上某个功能的调试页面时,可以画好页面的线框图中,然后直接让 Gemini 根据图中样式去实现页面,这样基本可以一次性就把页面布局搞定。比如下面是给社交相机跳转的调试页面:


  




**上下滑动查看完整内容** 













#import "AFDSocialCameraDebugViewController.h"

@interface AFDSocialCameraDebugViewController()
@property(nonatomic, strong) UILabel *enterFromLabel;
@property (nonatomic, strong) UITextField *enterFromTextField;
@property (nonatomic, strong) UILabel *shootWayLabel;
@property (nonatomic, strong) UITextField *shootWayTextField;
@property (nonatomic, strong) UILabel *socialCameraTypeLabel;
@property (nonatomic, strong) UITextField *socialCameraTypeTextField;
@property (nonatomic, strong) UILabel *configLabel;
@property (nonatomic, strong) UITextView *configTextView;
@property (nonatomic, strong) UIButton *generateSchemaButton;
@property (nonatomic, strong) UITextView *schemaTextView;
@property (nonatomic, strong) UIButton *openCameraButton;
@end
@implementation AFDSocialCameraDebugViewController

  • (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    [self setupUI];
    }
  • (void)setupUI {
    self.enterFromLabel = [UILabel new];
    self.enterFromLabel.text = @"enter_from:";
    [self.view addSubview:self.enterFromLabel];
    self.enterFromTextField = [UITextField new];
    self.enterFromTextField.borderStyle = UITextBorderStyleRoundedRect;
    [self.view addSubview:self.enterFromTextField];
    self.shootWayLabel = [UILabel new];
    self.shootWayLabel.text = @"shoot_way:";
    [self.view addSubview:self.shootWayLabel];
    self.shootWayTextField = [UITextField new];
    self.shootWayTextField.borderStyle = UITextBorderStyleRoundedRect;
    [self.view addSubview:self.shootWayTextField];
    self.socialCameraTypeLabel = [UILabel new];
    self.socialCameraTypeLabel.text = @"social_camera_type:";
    [self.view addSubview:self.socialCameraTypeLabel];
    self.socialCameraTypeTextField = [UITextField new];
    self.socialCameraTypeTextField.borderStyle = UITextBorderStyleRoundedRect;
    [self.view addSubview:self.socialCameraTypeTextField];
    self.configLabel = [UILabel new];
    self.configLabel.text = @"config:";
    [self.view addSubview:self.configLabel];
    self.configTextView = [UITextView new];
    self.configTextView.layer.borderColor = [UIColor lightGrayColor].CGColor;
    self.configTextView.layer.borderWidth = 1.0;
    self.configTextView.layer.cornerRadius = 5.0;
    [self.view addSubview:self.configTextView];
    self.generateSchemaButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.generateSchemaButton setTitle:@"生成 Schema" forState:UIControlStateNormal];
    self.generateSchemaButton.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:1.0 alpha:1.0];
    self.generateSchemaButton.layer.cornerRadius = 10.0;
    [self.view addSubview:self.generateSchemaButton];
    self.schemaTextView = [UITextView new];
    self.schemaTextView.layer.borderColor = [UIColor lightGrayColor].CGColor;
    self.schemaTextView.layer.borderWidth = 1.0;
    self.schemaTextView.layer.cornerRadius = 5.0;
    [self.view addSubview:self.schemaTextView];
    self.openCameraButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.openCameraButton setTitle:@"点击打开相机" forState:UIControlStateNormal];
    self.openCameraButton.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:1.0 alpha:1.0];
    self.openCameraButton.layer.cornerRadius = 10.0;
    [self.view addSubview:self.openCameraButton];
    // Layout
    self.enterFromLabel.translatesAutoresizingMaskIntoConstraints = NO;
    self.enterFromTextField.translatesAutoresizingMaskIntoConstraints = NO;
    self.shootWayLabel.translatesAutoresizingMaskIntoConstraints = NO;
    self.shootWayTextField.translatesAutoresizingMaskIntoConstraints = NO;
    self.socialCameraTypeLabel.translatesAutoresizingMaskIntoConstraints = NO;
    self.socialCameraTypeTextField.translatesAutoresizingMaskIntoConstraints = NO;
    self.configLabel.translatesAutoresizingMaskIntoConstraints = NO;
    self.configTextView.translatesAutoresizingMaskIntoConstraints = NO;
    self.generateSchemaButton.translatesAutoresizingMaskIntoConstraints = NO;
    self.schemaTextView.translatesAutoresizingMaskIntoConstraints = NO;
    self.openCameraButton.translatesAutoresizingMaskIntoConstraints = NO;
    CGFloat padding = 20.0;
    CGFloat textFieldHeight = 40.0;
    CGFloat textViewHeight = 100.0;
    CGFloat buttonHeight = 44.0;
    [NSLayoutConstraint activateConstraints:@[
    [self.enterFromLabel.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:padding],
    [self.enterFromLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.enterFromTextField.topAnchor constraintEqualToAnchor:self.enterFromLabel.bottomAnchor constant:8],
    [self.enterFromTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.enterFromTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
    [self.enterFromTextField.heightAnchor constraintEqualToConstant:textFieldHeight],
    [self.shootWayLabel.topAnchor constraintEqualToAnchor:self.enterFromTextField.bottomAnchor constant:padding],
    [self.shootWayLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.shootWayTextField.topAnchor constraintEqualToAnchor:self.shootWayLabel.bottomAnchor constant:8],
    [self.shootWayTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.shootWayTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
    [self.shootWayTextField.heightAnchor constraintEqualToConstant:textFieldHeight],
    [self.socialCameraTypeLabel.topAnchor constraintEqualToAnchor:self.shootWayTextField.bottomAnchor constant:padding],
    [self.socialCameraTypeLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.socialCameraTypeTextField.topAnchor constraintEqualToAnchor:self.socialCameraTypeLabel.bottomAnchor constant:8],
    [self.socialCameraTypeTextField.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.socialCameraTypeTextField.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
    [self.socialCameraTypeTextField.heightAnchor constraintEqualToConstant:textFieldHeight],
    [self.configLabel.topAnchor constraintEqualToAnchor:self.socialCameraTypeTextField.bottomAnchor constant:padding],
    [self.configLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.configTextView.topAnchor constraintEqualToAnchor:self.configLabel.bottomAnchor constant:8],
    [self.configTextView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.configTextView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
    [self.configTextView.heightAnchor constraintEqualToConstant:textViewHeight],
    [self.generateSchemaButton.topAnchor constraintEqualToAnchor:self.configTextView.bottomAnchor constant:padding],
    [self.generateSchemaButton.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
    [self.generateSchemaButton.widthAnchor constraintEqualToConstant:200],
    [self.generateSchemaButton.heightAnchor constraintEqualToConstant:buttonHeight],
    [self.schemaTextView.topAnchor constraintEqualToAnchor:self.generateSchemaButton.bottomAnchor constant:padding],
    [self.schemaTextView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:padding],
    [self.schemaTextView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-padding],
    [self.schemaTextView.heightAnchor constraintEqualToConstant:textViewHeight],
    [self.openCameraButton.topAnchor constraintEqualToAnchor:self.schemaTextView.bottomAnchor constant:padding],
    [self.openCameraButton.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
    [self.openCameraButton.widthAnchor constraintEqualToConstant:200],
    [self.openCameraButton.heightAnchor constraintEqualToConstant:buttonHeight],
    ]];
    }

@end
















![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/11a72e9c2a7e4a7381f81f8147071713~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=KmHehYLLLoaXjMnc87af3haOtlA%3D)


  







**Case 2: 用表格生成 libra 中配置的 json** 






  



我一般习惯在技术方案中本次需求中涉及到的所有 AB 和 Settings 变量,有了这样的表格后,可以直接将其截图给 Gemini ,然后让它把其中的内容转换成 json 格式,省得自己去一点点拼接,几秒钟就完成了!


  







![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/98eb121f400a4530a786ccb79ee2297a~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=3Jcv%2FhoyMy5Y2Ln5BptlK7bxLzI%3D)






![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/1cbcfffa61b34f27803c6363696f6a3c~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=2pSPXqRi5gcVVPQ8xrQNfsjChvs%3D)




  





![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/95765fdac3b44ec3a3a92782ab371305~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=sTJ6nm0W1QdRLvOvsNmNxH%2Fl9Oo%3D)




**编写提效脚本工具** 




  




还可以用 TRAE 编写 Python 脚本,将需要手动重复操作的事情自动化处理,有想法就可以跟 LLM 去聊,让它先规划一下实现思路,觉得可行就开始让它继续往下写。


  



下面几个是我之前写的,完全是通过与 LLM 的对话来实现的,可供大家参考,打开思路。


  








**Case1: 快速创建 BugFix MR** 






  




在日常工作中经常遇到的一种情况是,我正在热火朝天地开发需求赶 Deadline 呢,QA 突然找过来一个集成问题,有时不得不跟 alpha 修,之前的做法是打开 MBox ,切换 workspace,创建分支,这个过程就要等一会,然后再把修复问题的 commit chery-pick 过来,push 代码,创建 MR。


  



于是我就把这一套提 MR 的流程打包成了脚本,然后创建了一个 workspace 专门用来提 BugFix MR,最后又丰富了一下脚本的功能。



  




**上下滑动查看完整内容** 













#!/usr/bin/env python3
import argparse
from datetime import datetime
import subprocess
import sys
import webbrowser
import os
import json
def run_git_command(command):
"""执行 git 命令并返回结果"""
# 定义允许的 git 命令白名单
allowed_commands = {
'git checkout', 'git pull', 'git checkout -b',
'git cherry-pick', 'git push', 'git fetch',
'git merge', 'git branch',
'git diff' # 新增允许的diff命令
}

# 验证命令是否在白名单中  
ifnotany(command.startswith(cmd) for cmd in allowed_commands):  
    print(f"不允许执行的命令: {command}")  
    sys.exit(1)  
      
try:  
    result = subprocess.run(command, shell=True, check=True,   
                          capture_output=True, text=True)  
    return result.stdout.strip()  
except subprocess.CalledProcessError as e:  
    print(f"Git 命令执行失败: {e}")  
    print(f"错误输出: {e.stderr}")  
    sys.exit(1)  

def create_bugfix_branch(base_branch):
"""基于给定分支创建 bugfix 分支"""
# 获取当前日期和时间(添加时分秒)
now = datetime.now()
timestamp = now.strftime('%Y%m%d_%H%M%S')
new_branch = f"feature/ida_{timestamp}"

# 确保环境清洁  
run_git_command("git branch -D temp_branch || true")  # 强制清理旧分支  
  
try:  
    run_git_command(f"git fetch origin {base_branch}")  
    run_git_command(f"git checkout -b temp_branch origin/{base_branch}")  
finally:  
    run_git_command("git branch -D temp_branch || true")  # 确保最终清理  
  
# 创建新分支  
run_git_command(f"git checkout -b {new_branch}")  
run_git_command("git branch -D temp_branch")  # 新增:删除临时分支  
print(f"成功创建分支: \033[92m{new_branch}\033[0m")  
return new_branch  

def cherry_pick_commits(commit_hashes):
"""Cherry-pick 指定的提交"""
print("正在获取远端最新提交...")
run_git_command("git fetch --all --prune")
print("获取完成。")
for commit in commit_hashes:
try:
# 使用 GIT_EDITOR=true 防止 git 打开编辑器导致进程挂起
# 我们不使用 run_git_command 因为我们想自定义错误处理
result = subprocess.run(f"GIT_EDITOR=true git cherry-pick {commit}",
shell=True,
capture_output=True,
text=True)
if result.returncode != 0:
# 抛出异常,由 except 块统一处理
raise subprocess.CalledProcessError(result.returncode, result.args, output=result.stdout, stderr=result.stderr)

        print(f"成功 cherry-pick 提交: {commit}")  
    except subprocess.CalledProcessError as e:  
        print(f"\nCherry-pick 失败,提交 hash: {commit}")  
          
        # 检查是否有冲突  
        conflict_files = run_git_command("git diff --name-only --diff-filter=U")  
        if conflict_files:  
            print("‼️ 检测到合并冲突。冲突文件列表:")  
            print(conflict_files)  
            print("\n请按以下步骤处理:")  
            print("1. 手动解决上述冲突文件")  
            print("2. 执行 git add 冲突文件")  
            print("3. 执行 git cherry-pick --continue 继续")  
            print("或使用 git cherry-pick --abort 中止操作")  
        else:  
            print("错误详情:")  
            print(e.stderr)  
        sys.exit(1)  

def push_branch(branch_name):
"""推送分支到远端"""
try:
run_git_command(f"git push -u origin {branch_name}")
print(f"成功推送分支 \033[92m{branch_name}\033[0m到远端")
except Exception as e:
print(f"推送分支失败: {e}")
sys.exit(1)
def open_create_mr_page():
"""打开创建 MR 的网页"""
url = "MR 网页的URL"
try:
webbrowser.open(url)
print("已打开创建 MR 的网页")
except Exception as e:
print(f"打开网页失败: {e}")
print(f"请手动访问: {url}")
def merge_develop(branch_name):
try:
print("正在合并 develop 分支...")
run_git_command("git fetch origin develop") # 简化的fetch命令
# 修改合并命令添加冲突检测
result = subprocess.run("git merge origin/develop", shell=True, capture_output=True, text=True) # 明确指定远端分支
if result.returncode != 0:
conflict_files = run_git_command("git diff --name-only --diff-filter=U")
print("\n‼️ 合并冲突文件列表:")
print(conflict_files)
raise subprocess.CalledProcessError(result.returncode, result.args)
print("成功合并 develop 分支")
except Exception as e:
print(f"\n合并 develop 分支失败: {e}")
print("请按以下步骤处理:")
print("1. 手动解决上述冲突文件")
print("2. 执行 git add 冲突文件")
print("3. 执行 git commit 完成合并")
sys.exit(1)
def set_working_directory():
"""设置工作目录"""
work_dir = "/Volumes/Ida/DevMbox-BugFix/Aweme" # 默认工作目录
try:
os.chdir(work_dir)
print(f"已切换工作目录到: {work_dir}")
except Exception as e:
print(f"切换工作目录失败: {e}")
sys.exit(1)
def main():
parser = argparse.ArgumentParser(description='Git 分支管理工具')
args = parser.parse_args()
set_working_directory()
# 获取并显示所有分支
branches = run_git_command("git branch").split('\n') # 修改为仅获取本地分支
current_branch = next((b.split()[-1] for b in branches if b.startswith('*')), 'unknown')

print("\n可用分支列表:")  
for branch in branches:  
    display = branch.replace('* ', '')  
    if branch.startswith('*'):  
        print(f"  \033[91m{display}\033[0m (当前分支)")  
    else:  
        print(f"  {display}")  
# 新增分支操作选项  
# 修改后的分支操作选项  
choice = None  
while choice not in ['a', 'b', 'c', 'd']:  # 新增选项d  
    print("\n请选择操作:")  
    print("a. 创建新分支")  
    print("b. 切换到现有分支")  
    print("c. 继续在当前分支操作")  
    print("d. 删除现有分支")  # 新增删除选项  
    choice = input("请输入选项 (a/b/c/d): ").strip().lower()  
# 修改后的分支操作逻辑  
if choice == 'd':  # 分支删除逻辑  
    branches_to_delete = input("请输入要删除的分支名称(多个用空格分隔): ").split()  
    for branch in branches_to_delete:  
        try:  
            run_git_command(f"git branch -D {branch}")  
            print(f"已删除分支: \033[91m{branch}\033[0m")  
        except Exception as e:  
            print(f"删除分支 {branch} 失败: {e}")  
    print(f"\n所有操作已完成!")  
    sys.exit(0)  
elif choice == 'a':  # 创建分支  
    base_branch = input("请输入要基于哪个分支创建(例如 develop): ").strip()  
    new_branch = create_bugfix_branch(base_branch)  
elif choice == 'b':  # 切换分支  
    target_branch = input("请输入要切换到的分支名称: ").strip()  
    run_git_command(f"git checkout {target_branch}")  
    new_branch = run_git_command("git branch --show-current")  
    print(f"已切换到分支: \033[92m{new_branch}\033[0m")  
else:  # 继续当前分支(选项c)  
    new_branch = current_branch  
    print(f"继续在当前分支操作: \033[92m{new_branch}\033[0m")  
# Cherry-pick 确认(原有代码保持不变)  
if input("是否要执行 cherry-pick?(Y/N): ").strip().upper() == 'Y':  
    commits = input("请输入要 cherry-pick 的提交 hash(多个用空格分隔): ").split()  
    if commits:  
        cherry_pick_commits(commits)  
# 合并 develop 确认  
if input("是否要合并 develop 分支?(Y/N): ").strip().upper() == 'Y':  
    merge_develop(new_branch)  
# 推送分支  
push_branch(new_branch)  
# 新增打开网页确认  
if input("是否要打开创建 MR 的网页?(Y/N): ").strip().upper() == 'Y':  
    open_create_mr_page()  
  
print(f"\n所有操作已完成!")  
  

if name == "main":
main()
















![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/7fde990e589a432a8cf94b4f1176c617~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=z6BhLmKXi8IaYpDq9xfRpa50TME%3D)


  







**Case2: 生成代码的脚手架** 






  



前段时间做了推人卡片接入异形卡框架的重构,重构之后再有新的卡片接入,按照一定的模式实现就行了,比如要创建哪些类,实现哪些接口。所以我直接把推人卡片代码改造成了模块化的代码,加了一些占位符,然后再通过脚本改成新卡片的代码。模板化改造这一部分也是用 TRAE 来完成的,主要是一些重命名,符号替换的工作。


  




**上下滑动查看完整内容** 













import os
import shutil
import argparse
import subprocess
from datetime import datetime

def replace_in_file(file_path, replacements):
"""Replaces multiple occurrences in a file based on a dictionary of replacements."""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()

    new_content = content  
    for old_str, new_str in replacements.items():  
        new_content = new_content.replace(old_str, new_str)  
      
    if new_content != content:  
        with open(file_path, 'w', encoding='utf-8') as f:  
            f.write(new_content)  
    else:  
        print(f"    - No content replacement needed in: {os.path.basename(file_path)}")  
          
except Exception as e:  
    print(f"    - Error processing file {file_path}: {e}")  

def get_git_username():
"""Gets the current git username."""
try:
result = subprocess.run(['git', 'config', 'user.name'], capture_output=True, text=True, check=True)
return result.stdout.strip()
except (subprocess.CalledProcessError, FileNotFoundError):
print("Warning: Could not get git username. Using 'Default Author'.")
return"Default Author"

def generate_card_module(module_name):
"""Generates a new card module based on the BusinessCard template."""
source_dir = os.path.join(os.getcwd(), "BusinessCard")
target_dir = os.path.join(os.getcwd(), module_name)
new_prefix = f"AWE{module_name}"
old_prefix = "BusinessCard"
git_author = get_git_username()
current_date = datetime.now().strftime("%Y/%-m/%-d") # Format YYYY/M/D

ifnot os.path.exists(source_dir):  
    print(f"Error: Source directory '{source_dir}' not found.")  
    return  

if os.path.exists(target_dir):  
    print(f"Error: Target directory '{target_dir}' already exists.")  
    return  

try:  
    # 1. Create target directory  
    os.makedirs(target_dir)  

    # 2. Copy files  
    copied_files = []  
    for item in os.listdir(source_dir):  
        # Skip .DS_Store files  
        if item == ".DS_Store":  
            continue  
        s_path = os.path.join(source_dir, item)  
        d_path = os.path.join(target_dir, item)  
        if os.path.isfile(s_path):  
            shutil.copy2(s_path, d_path)  
            copied_files.append(item)  
      
    # 3. Rename files and replace content  
    for filename in copied_files:  
        if filename.startswith(old_prefix):  
            # Rename file  
            new_filename = filename.replace(old_prefix, new_prefix, 1)  
            old_filepath = os.path.join(target_dir, filename)  
            new_filepath = os.path.join(target_dir, new_filename)  
            os.rename(old_filepath, new_filepath)  
              
            # Prepare replacements  
            replacements = {  
                old_prefix: new_prefix,  
                "__AUTHOR__": git_author,  
                "__DATE__": current_date  
            }  
            # Replace content in the renamed file  
            replace_in_file(new_filepath, replacements)  
        else:  
             # Also replace content in files that don't match the prefix pattern  
             filepath = os.path.join(target_dir, filename)  
             replacements = {  
                 old_prefix: new_prefix, # Keep prefix replacement if needed elsewhere  
                 "__AUTHOR__": git_author,  
                 "__DATE__": current_date  
             }  
             replace_in_file(filepath, replacements)  

    print(f"\033[92m\nSuccessfully generated module '{module_name}' in '{target_dir}'\033[0m")  

except Exception as e:  
    print(f"An error occurred: {e}")  
    # Clean up if error occurs during creation  
    if os.path.exists(target_dir):  
         shutil.rmtree(target_dir)  
         print(f"Cleaned up directory: {target_dir}")  

if name == "main":
parser = argparse.ArgumentParser(description="Generate a new card module framework.")
parser.add_argument("module_name", help="The name of the new card module (e.g., MateBigCard)")

args = parser.parse_args()  
  
generate_card_module(args.module_name)













模板代码:




![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/364c72d6022b4800bba836303395f4db~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=yLN%2BcpPP8HKvzVhS21KQ6JTYSfE%3D)


  



执行脚本:




![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/6e03732453884c60bef4fd232bbabc12~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=Bkd%2FSmtcbOb%2Fc0jRoBSq3K1o39Q%3D)






python3 generate_code.py 你的卡片模块名称(比如推人大卡就可以是MateBigCard)



  







**Case3: 快速构造 mock 数据** 






  



也是在做推人卡片重构时,发现手动去 mock 数据非常麻烦,而客户端的调试又依赖数据,所以琢磨能否用写个脚本来自动请求 user 数据,再拼接成符合要求的数据格式。


  







![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/4b82d7254fe7409aad2c19ee2a81ee57~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=c72WkfKsxw%2B7z9JkYA8myJM%2FbOc%3D)






![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/4e880d43b9b14822a046e7adfaa1c812~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=Jn2O2%2F9vxgVzvwi6OIjqEmaWqL8%3D)






![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/1898146860fa4f9e8c239430d09092e2~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=BaenPjZ3zlDaTn7ejZo2MlFYUPM%3D)




  





![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/251177648e0d453a9bbce65b4e0bfb5c~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=vRoNwdMNfi3HzFGc0DLNq5gymqo%3D)




**作为 Source Control 工具** 




  




TRAE IDE 里也集成了 Source Control 工具,同样推荐大家去试用:


  



* 这样就可以少开一个用来做 Source Control 的工具啦,并且可以随时查看代码变更。
* 可以自动生成 commit message。
* UI 交互区友好,基本零成本上手使用。



  







![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/bc158fec0bf949cd9cfc58dc56d09d48~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=H0ASvseQmecJq67nQuu0Q5BG43k%3D)






![picture.image](https://p6-volc-community-sign.byteimg.com/tos-cn-i-tlddhu82om/79cf5281ad014ddc8e28a2e8ab376aa8~tplv-tlddhu82om-image.image?=&rk3s=8031ce6d&x-expires=1752621415&x-signature=Xclok9aZmE1j7RW%2B3MXuLnlYZB4%3D)




  





最后,无论 AI 生成的代码如何精妙,工程师对质量的守护永不可替代,在上线前还是要仔细地去 Review 代码,保持对线上代码的敬畏心。


  



点击**阅读原文** ,让 TRAE 成为你的提效加速器,用 AI 释放创造力,以专业守护代码质量。




  












0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
DevOps 在字节移动研发中的探索和实践
在日益复杂的APP工程架构下,如何保证APP能高效开发,保障团队效能和工程质量?本次将结合字节内部应用的事件案例,介绍DevOps团队对移动研发效能建设的探索和思考。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论