文章

AI 辅助编程:VS Code + Cline + DeepSeek

通过 VS Code + Cline + DeepSeek 以一个实际项目为例,进行项目的通读理解以及新增功能,并能够解决代码的扩展性以及过程中的问题修复,最后可以正常运行和演示。

项目技术栈如下:

image-20250213下午81151105

项目的具体情况可以看下面 AI 总结的项目总体概览。

安装 Cline

需要先安装 VS Code(全称:Visual Studio Code)

https://code.visualstudio.com/

image-20250213下午25544258

配置 Cline

在VS Code中,通过 Ctrl/Command+Shift+P 打开命令工具,在新 tab 中打开 Cline 进行配置。或者通过左边的图标进入 cline。

image-20250213下午30354358

01、配置 DeepSeek

这里有很多 AI Provider 的选择,如下图:

image-20250213下午73623225

硅基流动:

image-20250213下午32900182

  1. API Provider:选择 “OpenAI Compatible”

  2. Base Url:https://api.siliconflow.cn/v1

  3. API Key:从 https://cloud.siliconflow.cn/account/ak 中获取

  4. Model ID:从 https://cloud.siliconflow.cn/models 中获取

阿里云百炼:

image-20250213下午33037493

  1. API Provider:选择 “OpenAI Compatible”

  2. Base Url:https://dashscope.aliyuncs.com/compatible-mode/v1

  3. API Key:从https://bailian.console.aliyun.com/?apiKey=1#/api-key 中获取

  4. Model ID:从 https://bailian.console.aliyun.com/#/model-market 中获取

以上两种方式都有一定的免费额度,都可以快速和免费地体验。但在使用硅基流动时,非常卡顿,后面切换到了阿里云百炼平台。

02、配置权限

image-20250213下午24246134

注意:如果你开通了 Auto-approve,cline将会自动移动、删除、修改你的文件。如果不勾选的话,每次修改之后需要人工介入同意或者拒绝这次修改。

Cline使用的几种方式:Problems、文件、文件夹 + 提问,当然也可以进行自由的组合。

image-20250213下午81842029

实战

01、通读整个项目

通过 README文件 让 cline 结合 DeepSeek 说明当前项目的情况和进度。

image-20250213下午33709740

image-20250213下午33838868

image-20250213下午33912382

02、新增功能:加入 DeepSeek V3 Chat 模型

该项目之前已经集成了openai llm。通过一个简单的 DeepSeek 的python 的demo例子,期望cline能够将其整合到当前的项目中。

Demo 代码:

from openai import OpenAI
import os
from dotenv import load_dotenv, find_dotenv

_ = load_dotenv(find_dotenv())

# 初始化OpenAI客户端
client = OpenAI(
    # 如果没有配置环境变量,请用百炼API Key替换:api_key="sk-xxx"
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

def main():
    reasoning_content = ""  # 定义完整思考过程
    answer_content = ""     # 定义完整回复
    is_answering = False   # 判断是否结束思考过程并开始回复

    # 创建聊天完成请求
    stream = client.chat.completions.create(
        model="deepseek-r1",  # 此处以 deepseek-v1 为例,可按需更换模型名称
        messages=[
            {"role": "user", "content": "9.9和9.11谁大"}
        ],
        stream=True
        # 解除以下注释会在最后一个chunk返回Token使用量
        # stream_options={
        #     "include_usage": True
        # }
    )

    print("\n" + "=" * 20 + "思考过程" + "=" * 20 + "\n")

    for chunk in stream:
        # 处理usage信息
        if not getattr(chunk, 'choices', None):
            print("\n" + "=" * 20 + "Token 使用情况" + "=" * 20 + "\n")
            print(chunk.usage)
            continue

        delta = chunk.choices[0].delta

        # 检查是否有reasoning_content属性
        if not hasattr(delta, 'reasoning_content'):
            continue

        # 处理空内容情况
        if not getattr(delta, 'reasoning_content', None) and not getattr(delta, 'content', None):
            continue

        # 处理开始回答的情况
        if not getattr(delta, 'reasoning_content', None) and not is_answering:
            print("\n" + "=" * 20 + "完整回复" + "=" * 20 + "\n")
            is_answering = True

        # 处理思考过程
        if getattr(delta, 'reasoning_content', None):
            print(delta.reasoning_content, end='', flush=True)
            reasoning_content += delta.reasoning_content
        # 处理回复内容
        elif getattr(delta, 'content', None):
            print(delta.content, end='', flush=True)
            answer_content += delta.content

    # 如果需要打印完整内容,解除以下的注释
    """
    print("=" * 20 + "完整思考过程" + "=" * 20 + "\n")
    print(reasoning_content)
    print("=" * 20 + "完整回复" + "=" * 20 + "\n")
    print(answer_content)
    """

if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print(f"发生错误:{e}")

通过Cline进行自动代码改造之后:

from typing import List, Dict, Optional, AsyncGenerator
from openai import AsyncOpenAI
from dotenv import load_dotenv, find_dotenv
import os
import time
from .base import BaseLLM
from app.models.chat import ChatMessage
from app.core.config import logger

_ = load_dotenv(find_dotenv())

class DeepSeekLLM(BaseLLM):
    # 定义模型的最大token限制
    MODEL_LIMITS = {
        'deepseek-v3': 4096
    }

    def __init__(self):
        super().__init__()
        self.client = AsyncOpenAI(
            api_key=os.getenv("DASHSCOPE_API_KEY"),
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
        )

    async def generate(
        self,
        messages: list[ChatMessage],
        **kwargs
    ) -> str:
        formatted_messages = [
            {"role": msg.role, "content": msg.content}
            for msg in messages
        ]

        response = await self.client.chat.completions.create(
            model="deepseek-v3",
            messages=formatted_messages,
            stream=False,
            **kwargs
        )

        return response.choices[0].message.content

    async def chat(
        self,
        messages: list[ChatMessage],
        **kwargs
    ) -> str:
        return await self.generate(messages, **kwargs)

    def _truncate_messages(self, messages: List[Dict[str, str]], model: str) -> List[Dict[str, str]]:
        """截断消息以适应模型的上下文长度限制"""
        max_tokens = self.MODEL_LIMITS.get(model, 4096)
        # 预留2000个token给响应
        max_message_tokens = max_tokens - 2000

        # 从最新的消息开始保留
        truncated_messages = []
        current_tokens = 0

        for message in reversed(messages):
            # 粗略估计token数(每4个字符约1个token)
            estimated_tokens = len(message['content']) // 4
            if current_tokens + estimated_tokens > max_message_tokens:
                break
            truncated_messages.insert(0, message)
            current_tokens += estimated_tokens

        return truncated_messages or [messages[-1]]  # 至少保留最后一条消息

    async def chat_stream(
        self,
        messages: List[Dict[str, str]],
        temperature: float = 0.7,
        max_tokens: int = 2000,
        model: str = "deepseek-v3",
        **kwargs
    ) -> AsyncGenerator[str, None]:
        """使用流式响应进行对话"""
        logger.info("Starting DeepSeek stream chat with %s model", model)
        start_time = time.time()
        try:
            # 截断消息
            truncated_messages = self._truncate_messages(messages, model)
            logger.info("Truncated messages: %s", truncated_messages)

            is_answering = False   # 判断是否结束思考过程并开始回复

            # 创建异步流式响应
            response = await self.client.chat.completions.create(
                model=model,
                messages=truncated_messages,
                stream=True
            )

            # yield "思考过程:\n"

            async for chunk in response:
                if not chunk.choices:
                    continue

                delta = chunk.choices[0].delta

                # 处理空内容情况
                if not getattr(delta, 'reasoning_content', None) and not getattr(delta, 'content', None):
                    continue

                # if not getattr(delta, 'reasoning_content', None) and not is_answering:
                #     is_answering = True
                #     yield "完整回复: \n"

                # # 处理思考过程
                # if getattr(delta, 'reasoning_content', None):
                #     yield delta.reasoning_content
                # # 处理回复内容
                # elif getattr(delta, 'content', None):
                #     yield delta.content

                if getattr(delta, 'content', None):
                    yield delta.content


        except Exception as e:
            error_msg = f"DeepSeek API 调用失败: {str(e)}"
            if hasattr(e, 'response'):
                error_msg += f"\nResponse: {e.response}"
            logger.error(error_msg)
            raise Exception(error_msg)
        finally:
            duration = time.time() - start_time
            logger.info("DeepSeek stream completed | duration=%.2fs", duration)

完成之后的项目结构如下,其中 deepseek_llm.py 为主要生成的代码。

image-20250213下午74704942

03、验证结果

提问:9.9 和 9.11 哪个大?

首页:

image-20250213下午72555950

gpt 3.5:

image-20250213下午73024291

gpt-4:

image-20250213下午73120858

DeepSeek-v3:

image-20250213下午73253218

最后

总体体验下来,Cline 有如下优点:

  • 支持多种API提供商,如:OpenAI、DeepSeek、Google Gemini、Anthropic Claude、Alibaba Qwen、Ollama等。

  • 类似于 Cursor,代码修改过程完全可视化,可以看到 AI 的每一步操作,甚至可以完全授权,代码不需要人工干预自动修改。

  • 可以处理复杂的开发任务,从项目创建到文件编辑,再到终端命令执行,几乎覆盖所有的开发流程。

  • 在生成错误的代码会自动修正,例如:生成的 TypeScript 语法错误,缺少依赖包等。

  • 完全可以先免费体验,同时加上 DeepSeek,推理能力真的上了一个台阶。

但也有一些缺点:

  • 处理复杂任务时,响应时间较长,这点尤其收到选择的 API 供应商,这点确实没法和 Cursor Fast 响应额度比。

  • Token 消耗速度太快了,简单任务会好很多。例如,百炼提供的免费 100 万额度不到两小时就消耗殆尽。

  • 当你知道问题出在哪个文件,直接指定文件说明问题进行修改的时,效率较高,但有时 Cline 也会通过上下文修改其他文件,这时查找效率会比较低,甚至会去比对代码,但是又没有进行任何修改,这时就感觉傻傻的......

如果响应速度再提升 10 倍,token 再便宜些,模型的推理能力再强一些,其实这也是一种趋势了,未来可期。


欢迎关注我的公众号“Eric技术圈”,原创技术文章第一时间推送。

License:  CC BY 4.0