[杂谈]使用 Delphi 12.2+ 的 SmartInsight AI 支持一些体会

Delphi 12.2 开始引入了 SmartInsight 对 AI 编程模型的支持,最近简单的试用了一下,总体下自己的一点体会。先说一下结论:有比没有强,吃配置和耐心。

【补充测试】

  1. 使用亲戚家的 AMD 7800X3D+AMD 7800XT 16G + Windows 10 48G 平台,LMStudio 测试速度为 <40 tokens
  2. 传说中,LMStudio 比 Ollama 快 20%,在我个人机器上测试并不是,反而 ollama 比 LM Studio 快得多,实际应用环境,大家可以都安装测试下。
  3. 另外,LM Studio 中的 deepseek-coder-v2:16b 要比 ollama 的模型库中同一模型大 1GB+,这也可能是速度没有快 20% 的原因之一吧,但效率没有测试什么区别。
  1. 开启 AI 编程:
    • 我们选择 ollama 来部署本地模型,在安装完成后,我们要选择一些合适的模型,保证我们的系统能够跑起来(以我系统 10700+32GB RAM 为基准),经过测试:
      • deepseek-coder-v2:16b 速度 17.68 tokens/s,在 7950X+64G DDR5 6200+1050 ti 跑出了接近 40tokens/s 的速度(Deepin v23+ollama 0.6.2)
      • qwen2.5-coder:7b 速度 7.26 tokens/s
      • codegemma:7b 速度 6.08 tokens/s
      • starcoder2:7b 速度 13.70 tokens/s,但我问什么他直接原文回复我是什么鬼?
      • stable:3b 速度 14.94 tokens/s,不过 3b 参数太少
    • 所以综上,deepseek-coder-v2:16b 在我目前的机器上应该是比较好的一个选择
  2. 实际体验:
    • 响应速度: 感觉没有采用SSE模式,所以需要等待全部返回才能得到结果,会给人感觉比较慢。
    • 功能可用性:不要指望 CodeSight AI 的实时提示及分析,这个功能对算力的要求太高。目前可以主要可能完成:
      – 代码的阅读理解:让 AI 解释代码的执行流程,方便读别人的代码
      – 查找问题及解决方案:让 AI 检查你的函数是否有问题,做到 AI 辅助审查代码
      – 为代码添加注释:可以省下你的很大一部分写注释的精力
      – 优化代码:可以用来帮你调整优化代码
      – 其它功能:可以用,看需要和耐心,简单的代码等他出来,你可能早写完了。
    • 结果反馈:默认情况下,由于发起请求都是英文,所以回答都是英文。如果我们要让 AI 回复中文,需要在内容中包含“中文”这个关键词即可,比如下面就可以让回复中文,不过最安全是的写”使用中文回复”一类的字样:
//中文
procedure Test();
var
  p,pd: PInteger;
begin
  GetMem(p, 100);
  try
    pd:=p;
    for var I := 0 to 25 do
    begin
      pd^ := 0;
      Inc(pd);
    end;
  finally
    FreeMem(p);
  end;

end;

上面的代码选中,然后选择 SmartCodeInsight->Explain the Code,结果如下:

(************* Explanation
***************
这段代码是一个Delphi或Pascal语言的程序,用于分配内存并初始化这块内存。下面是对代码的详细解释:

```delphi
//中文
procedure
Test();
var
  p, pd: PInteger;
begin
  GetMem(p, 100); //
分配一块大小为100字节的内存,返回一个指向该内存的指针,赋值给变量p
  try
    pd := p; //
将指针p赋值给pd,此时pd也指向同一块内存
    for var I := 0 to 25 do // 使用for循环从0到25进行迭代

begin
      pd^ := 0; // 将当前pd所指向的内存单元设置为0
      Inc(pd); // 将pd指向下一个内存单元

end;
  finally
    FreeMem(p); // 释放分配的内存,无论之前是否发生异常都会执行这一步

end;
end;
```

### 代码解释:

1. **分配内存**:
   ```delphi
   GetMem(p, 100);

```
   这行代码调用`GetMem`函数,分配一块大小为100字节的内存,并返回一个指向这块内存的指针。这个指针被赋值给变量`p`。

2.
**初始化内存**:
   ```delphi
   pd := p;
   for var I := 0 to 25 do
   begin

pd^ := 0;
     Inc(pd);
   end;
   ```

这里,首先将指针`p`赋值给`pd`,使得它们指向同一块内存。然后使用一个`for`循环从0到25进行迭代,每次迭代都将当前`pd`所指向的内存单元设置为0,并将`pd`指向下一个内存单元。

3.
**释放内存**:
   ```delphi
   finally
     FreeMem(p);
   end;
   ```

无论在循环中是否发生异常,最后都会执行`FreeMem(p)`来释放之前分配的内存。

###
总结:
这段代码的主要功能是分配一块大小为100字节的内存,然后通过一个循环将这块内存的前26个整数(每个4字节)初始化为0。最后,无论循环过程中是否发生异常,都会确保释放分配的内存。
*)

如果我们不选中中文这行注释, 它返回的结果是:

(************* Explanation ***************
The code you've provided is a
Pascal procedure named `Test()`. This procedure uses dynamic memory allocation
and manipulation in Pascal. Here's a step-by-step breakdown of what the code
does:

1. **Variable Declarations**:
   ```pascal
   var p, pd: PInteger;

```
   - `p` is declared as a pointer to an integer.
   - `pd` is also
declared as a pointer to an integer, but it will be used to iterate over the
memory block allocated for `p`.

2. **Memory Allocation**:
   ```pascal

GetMem(p, 100);
   ```
   - This line allocates a block of memory with a size
of 100 bytes and assigns the pointer to this block to `p`. The allocated memory
is uninitialized and can be used to store integers.

3. **Memory
Initialization**:
   ```pascal
   try
     pd := p;
     for var I := 0 to
25 do
     begin
       pd^ := 0;
       Inc(pd);
     end;
   finally

FreeMem(p);
   end;
   ```
   - The `try` block is used to ensure that the
allocated memory is properly freed in case an exception occurs during its use.

- `pd := p;` initializes `pd` to point to the same memory location as `p`.
   -
The `for` loop iterates 26 times (from 0 to 25), setting each integer value in
the allocated block to 0:
     ```pascal
     for var I := 0 to 25 do

begin
       pd^ := 0;
       Inc(pd);
     end;
     ```
     - `pd^ :=
0;` sets the current integer value at the address pointed to by `pd` to 0.

- `Inc(pd);` increments the pointer `pd` to point to the next integer in the
memory block.
   - The finally clause ensures that the allocated memory is
freed using `FreeMem(p);` even if an exception occurs during the execution of
the procedure.

4. **Memory Deallocation**:
   ```pascal
   FreeMem(p);

```
   - This line frees the dynamically allocated memory block pointed to by
`p`.

### Summary
The `Test()` procedure allocates a block of memory for 100
integers, initializes the first 26 integers to zero, and then deallocates the
memory. The use of `try...finally` ensures that the memory is always freed, even
if an error occurs during the initialization process.
*)

下面是接入 DeepSeek API 做的代码完成测试的返回结果,先中前面的注释,然后右键选择 SmartInsight -> Complete the Code:

// 当前界面上 Memo1 存的是一个 JSON 字符串,帮我完成解析并获取其中名为 url 的成员的值,然后将其赋给 Edit1.Text
(************* Complete Code ***************
要完成这个任务,你可以使用 Delphi 的
`System.JSON` 单元来解析 JSON 字符串。以下是一个完整的代码示例,展示了如何从 `Memo1` 中获取 JSON 字符串,解析它,并提取名为
`url` 的成员的值,然后将其赋值给 `Edit1.Text`。

```delphi
uses

System.JSON;

procedure TForm1.Button1Click(Sender: TObject);
var

JSONString: string;
  JSONValue: TJSONValue;
  JSONObject: TJSONObject;

URLValue: string;
begin
  // 获取 Memo1 中的 JSON 字符串
  JSONString :=
Memo1.Text;

  try
    // 解析 JSON 字符串
    JSONValue :=
TJSONObject.ParseJSONValue(JSONString);
    if JSONValue is TJSONObject then

begin
      JSONObject := JSONValue as TJSONObject;

      // 获取名为 "url"
的成员的值
      if JSONObject.TryGetValue<string>('url', URLValue) then

begin
        // 将获取到的值赋给 Edit1.Text
        Edit1.Text := URLValue;

end
      else
      begin
        ShowMessage('JSON 中未找到 "url" 成员');

end;
    end
    else
    begin
      ShowMessage('JSON 字符串格式不正确');

end;
  finally
    // 释放 JSONValue
    JSONValue.Free;

end;
end;
```

### 代码说明:
1. **获取 JSON 字符串**:从 `Memo1` 中获取 JSON 字符串。
2.
**解析 JSON 字符串**:使用 `TJSONObject.ParseJSONValue` 方法解析 JSON 字符串。
3. **检查 JSON
类型**:确保解析后的 JSON 是一个对象(`TJSONObject`)。
4. **获取 `url` 成员的值**:使用 `TryGetValue`
方法尝试获取名为 `url` 的成员的值。
5. **赋值给 `Edit1.Text`**:如果成功获取到 `url` 的值,将其赋值给
`Edit1.Text`。
6. **错误处理**:如果 JSON 格式不正确或未找到 `url` 成员,显示相应的错误消息。
7.
**释放资源**:最后释放 `JSONValue` 对象,避免内存泄漏。

### 注意事项:
- 确保 `System.JSON` 单元已经被添加到
`uses` 子句中。
- 如果 JSON 字符串格式不正确或 `url` 成员不存在,代码会显示相应的错误消息。
- 这个代码假设 `Button1`
是一个按钮,点击按钮时执行解析操作。你可以根据需要调整触发事件。

希望这个代码对你有帮助!
*)
滚动至顶部