Token导航 LogoToken导航

Agent Skill · 开发

deepseek-integration(DeepSeek 集成)

deepseek-integration 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

deepseek-integration 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证信息还不明确,第三方扫描有未通过项,按安装量在开发类的 21,746 个 Skill 里排第 20,391。

总安装 222周安装 9GitHub Stars 1下载 70核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:deepseek-integration(DeepSeek 集成)
来源仓库:https://github.com/cacr92/wereply
仓库路径:skills/deepseek-integration
安装命令:
npx skills add https://github.com/cacr92/wereply --skill deepseek-integration
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/cacr92/wereply --skill deepseek-integration

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

deepseek-integration 提供 DeepSeek API 与 reqwest HTTP 客户端的深度集成指南,支持流式响应与错误处理。适用于需要将 AI 生成能力嵌入到 Rust 应用中的开发者,强调连接池与令牌安全管理。

包含非流式 JSON 与 Server-Sent Events 两种返回格式的配置示例。使用前请准备好有效的 DeepSeek API 密钥,并确保运行环境支持 Rust 3.12+。涉及外部 API 调用时应注意配额限制与超时设置,避免阻塞主流程。

来源仓库内路径:skills/deepseek-integration

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/cacr92/wereply --skill deepseek-integration;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

deepseek-integration 怎么安装?

在终端执行 npx skills add https://github.com/cacr92/wereply --skill deepseek-integration。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

deepseek-integration 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

deepseek-integration 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

deepseek-integration 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

deepseek-integration 用的人多吗?

公开数据是累计安装 222 次,近一周安装 9 次,下载 70 次,GitHub 1 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

deepseek-integration 安全吗?

第三方扫描有未通过项,风险较高。除非你确认过源码,否则不建议直接安装到常用环境。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
deepseek-integration

DeepSeek 集成 · 本页

2221接触敏感数据未明确未通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

DeepSeek Integration Skill

Expert guidance for integrating DeepSeek API with reqwest HTTP client, streaming responses, and error handling.

Overview

WeReply uses DeepSeek API to generate reply suggestions:

  • HTTP Client: reqwest with connection pooling
  • API Endpoint: https://api.deepseek.com/v1/chat/completions
  • Authentication: API key via Bearer token
  • Response Format: JSON (non-streaming) or Server-Sent Events (streaming)
  • Configuration: API key stored in system keychain

HTTP Client Configuration

Reqwest Client Setup

use reqwest::{Client, ClientBuilder};
use std::time::Duration;
use std::sync::Arc;

pub struct DeepSeekClient {
    client: Arc<Client>,
    api_key: String,
    api_endpoint: String,
}

impl DeepSeekClient {
    pub fn new(api_key: String) -> anyhow::Result<Self> {
        let client = ClientBuilder::new()
            .pool_max_idle_per_host(10)  // 连接池最大空闲连接数
            .timeout(Duration::from_secs(30))  // 请求超时30秒
            .connect_timeout(Duration::from_secs(10))  // 连接超时10秒
            .build()?;

        Ok(Self {
            client: Arc::new(client),
            api_key,
            api_endpoint: "https://api.deepseek.com/v1/chat/completions".to_string(),
        })
    }

    pub fn with_custom_endpoint(mut self, endpoint: String) -> Self {
        self.api_endpoint = endpoint;
        self
    }
}

Connection Pooling Best Practices

// ✓ 共享 Client 实例(连接池复用)
pub struct AppState {
    deepseek_client: Arc<DeepSeekClient>,
}

// ✗ 每次创建新 Client(无连接池复用)
pub async fn bad_example() {
    let client = DeepSeekClient::new(api_key).unwrap();  // 不要这样做
}

API Request Pattern

Basic Request/Response

use serde::{Deserialize, Serialize};

#[derive(Serialize)]
pub struct ChatCompletionRequest {
    model: String,
    messages: Vec<ChatMessage>,
    #[serde(skip_serializing_if = "Option::is_none")]
    temperature: Option<f32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    max_tokens: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    stream: Option<bool>,
}

#[derive(Serialize, Deserialize)]
pub struct ChatMessage {
    role: String,  // "system", "user", "assistant"
    content: String,
}

#[derive(Deserialize)]
pub struct ChatCompletionResponse {
    id: String,
    model: String,
    choices: Vec<ChatChoice>,
    usage: Usage,
}

#[derive(Deserialize)]
pub struct ChatChoice {
    index: u32,
    message: ChatMessage,
    finish_reason: String,
}

#[derive(Deserialize)]
pub struct Usage {
    prompt_tokens: u32,
    completion_tokens: u32,
    total_tokens: u32,
}

Making API Requests

impl DeepSeekClient {
    pub async fn generate_completion(
        &self,
        messages: Vec<ChatMessage>,
    ) -> anyhow::Result<ChatCompletionResponse> {
        let request = ChatCompletionRequest {
            model: "deepseek-chat".to_string(),
            messages,
            temperature: Some(0.7),
            max_tokens: Some(1000),
            stream: Some(false),
        };

        let response = self.client
            .post(&self.api_endpoint)
            .header("Authorization", format!("Bearer {}", self.api_key))
            .header("Content-Type", "application/json")
            .json(&request)
            .send()
            .await?;

        // 检查 HTTP 状态码
        if !response.status().is_success() {
            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            return Err(anyhow!(
                "DeepSeek API 请求失败: {} - {}",
                status,
                error_text
            ));
        }

        // 解析响应
        let completion = response.json::<ChatCompletionResponse>().await?;

        Ok(completion)
    }
}

Streaming Response Pattern

Event Stream Processing

use futures::stream::StreamExt;
use serde_json;

impl DeepSeekClient {
    pub async fn generate_completion_stream(
        &self,
        messages: Vec<ChatMessage>,
        on_chunk: impl Fn(String) + Send + 'static,
    ) -> anyhow::Result<String> {
        let request = ChatCompletionRequest {
            model: "deepseek-chat".to_string(),
            messages,
            temperature: Some(0.7),
            max_tokens: Some(1000),
            stream: Some(true),  // 启用流式响应
        };

        let response = self.client
            .post(&self.api_endpoint)
            .header("Authorization", format!("Bearer {}", self.api_key))
            .header("Content-Type", "application/json")
            .json(&request)
            .send()
            .await?;

        if !response.status().is_success() {
            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            return Err(anyhow!(
                "DeepSeek API 请求失败: {} - {}",
                status,
                error_text
            ));
        }

        let mut stream = response.bytes_stream();
        let mut full_content = String::new();
        let mut buffer = String::new();

        while let Some(chunk_result) = stream.next().await {
            let chunk = chunk_result?;
            let chunk_str = String::from_utf8_lossy(&chunk);

            buffer.push_str(&chunk_str);

            // 处理 SSE 格式:data: {...}\n\ndata: {...}\n\n
            for line in buffer.lines() {
                if line.starts_with("data: ") {
                    let json_str = &line[6..];  // 去掉 "data: " 前缀

                    if json_str == "[DONE]" {
                        break;
                    }

                    if let Ok(chunk_data) = serde_json::from_str::<StreamChunk>(json_str) {
                        if let Some(choice) = chunk_data.choices.first() {
                            if let Some(content) = &choice.delta.content {
                                full_content.push_str(content);
                                on_chunk(content.clone());
                            }
                        }
                    }
                }
            }

            buffer.clear();
        }

        Ok(full_content)
    }
}

#[derive(Deserialize)]
struct StreamChunk {
    choices: Vec<StreamChoice>,
}

#[derive(Deserialize)]
struct StreamChoice {
    delta: Delta,
    finish_reason: Option<String>,
}

#[derive(Deserialize)]
struct Delta {
    #[serde(skip_serializing_if = "Option::is_none")]
    content: Option<String>,
}

Tauri Event Integration

use tauri::Manager;

#[tauri::command]
#[specta::specta]
pub async fn generate_suggestions_stream(
    context_messages: Vec<String>,
    style: String,
    state: State<'_, AppState>,
    app_handle: tauri::AppHandle,
) -> ApiResponse<String> {
    let client = state.deepseek_client.clone();

    // 构建消息
    let messages = build_chat_messages(context_messages, style);

    // 流式生成,实时发送到前端
    match client.generate_completion_stream(messages, move |chunk| {
        // 发送 chunk 到前端
        app_handle.emit_all("suggestion-chunk", chunk).ok();
    }).await {
        Ok(full_text) => api_ok(full_text),
        Err(e) => api_err(format!("生成建议失败: {}", e)),
    }
}

Error Handling and Retry

Exponential Backoff Retry

use tokio::time::{sleep, Duration};

impl DeepSeekClient {
    pub async fn generate_completion_with_retry(
        &self,
        messages: Vec<ChatMessage>,
        max_retries: u32,
    ) -> anyhow::Result<ChatCompletionResponse> {
        let mut retry_count = 0;
        let mut backoff_ms = 1000;  // 初始退避时间 1 秒

        loop {
            match self.generate_completion(messages.clone()).await {
                Ok(response) => return Ok(response),
                Err(e) => {
                    retry_count += 1;

                    if retry_count > max_retries {
                        return Err(anyhow!(
                            "DeepSeek API 调用失败,已重试 {} 次: {}",
                            max_retries,
                            e
                        ));
                    }

                    // 判断是否可重试的错误
                    if !is_retryable_error(&e) {
                        return Err(e);
                    }

                    tracing::warn!(
                        error = %e,
                        retry_count = retry_count,
                        backoff_ms = backoff_ms,
                        "DeepSeek API 调用失败,等待重试"
                    );

                    // 指数退避
                    sleep(Duration::from_millis(backoff_ms)).await;
                    backoff_ms = (backoff_ms * 2).min(30000);  // 最大退避 30 秒
                }
            }
        }
    }
}

fn is_retryable_error(error: &anyhow::Error) -> bool {
    let error_msg = error.to_string().to_lowercase();

    // 网络错误、超时、429 (Rate Limit)、5xx 服务器错误可重试
    error_msg.contains("timeout")
        || error_msg.contains("network")
        || error_msg.contains("429")
        || error_msg.contains("500")
        || error_msg.contains("502")
        || error_msg.contains("503")
        || error_msg.contains("504")
}

Error Classification

#[derive(Debug, thiserror::Error)]
pub enum DeepSeekError {
    #[error("API 密钥无效")]
    InvalidApiKey,

    #[error("请求超时")]
    Timeout,

    #[error("请求频率超限")]
    RateLimitExceeded,

    #[error("服务不可用")]
    ServiceUnavailable,

    #[error("网络错误: {0}")]
    NetworkError(String),

    #[error("响应解析错误: {0}")]
    ParseError(String),

    #[error("未知错误: {0}")]
    Unknown(String),
}

impl DeepSeekClient {
    fn classify_error(status_code: u16, body: &str) -> DeepSeekError {
        match status_code {
            401 => DeepSeekError::InvalidApiKey,
            408 | 504 => DeepSeekError::Timeout,
            429 => DeepSeekError::RateLimitExceeded,
            500 | 502 | 503 => DeepSeekError::ServiceUnavailable,
            _ => DeepSeekError::Unknown(body.to_string()),
        }
    }
}

Message Construction Pattern

Building Chat Messages

pub fn build_chat_messages(
    context_messages: Vec<String>,
    style: &str,
) -> Vec<ChatMessage> {
    let mut messages = Vec::new();

    // 系统提示词
    let system_prompt = format!(
        "你是一个微信回复建议助手。请根据聊天上下文,用{}风格生成3条简短的回复建议。\
        每条建议不超过50字,自然流畅,符合微信聊天习惯。",
        get_style_description(style)
    );

    messages.push(ChatMessage {
        role: "system".to_string(),
        content: system_prompt,
    });

    // 聊天上下文
    let context = context_messages.join("\n");
    messages.push(ChatMessage {
        role: "user".to_string(),
        content: format!("聊天记录:\n{}\n\n请生成3条回复建议:", context),
    });

    messages
}

fn get_style_description(style: &str) -> &str {
    match style {
        "formal" => "正式、礼貌",
        "friendly" => "亲切、友好",
        "humorous" => "幽默、轻松",
        _ => "自然、随和",
    }
}

Response Parsing

pub fn parse_suggestions(response_text: &str) -> Vec<String> {
    // DeepSeek 可能返回带编号的列表,如:
    // 1. 建议1
    // 2. 建议2
    // 3. 建议3

    let mut suggestions = Vec::new();

    for line in response_text.lines() {
        let trimmed = line.trim();

        // 匹配带编号的建议(如 "1. xxx" 或 "1) xxx")
        if let Some(content) = trimmed.strip_prefix(|c: char| c.is_numeric()) {
            if let Some(content) = content.strip_prefix(". ").or(content.strip_prefix(") ")) {
                suggestions.push(content.trim().to_string());
            }
        }
    }

    // 如果没找到带编号的建议,尝试按换行分割
    if suggestions.is_empty() {
        suggestions = response_text
            .lines()
            .map(|l| l.trim().to_string())
            .filter(|l| !l.is_empty())
            .collect();
    }

    suggestions
}

Configuration Management

API Key from System Keychain

use keyring::Entry;

pub fn get_deepseek_api_key() -> anyhow::Result<String> {
    let entry = Entry::new("wereply", "deepseek_api_key")?;
    entry.get_password()
        .context("未找到 DeepSeek API 密钥,请在设置中配置")
}

pub fn set_deepseek_api_key(api_key: &str) -> anyhow::Result<()> {
    let entry = Entry::new("wereply", "deepseek_api_key")?;
    entry.set_password(api_key)?;
    Ok(())
}

Environment Variable Fallback

use std::env;

pub fn get_api_endpoint() -> String {
    env::var("DEEPSEEK_API_ENDPOINT")
        .unwrap_or_else(|_| "https://api.deepseek.com/v1/chat/completions".to_string())
}

pub fn get_model_name() -> String {
    env::var("DEEPSEEK_MODEL")
        .unwrap_or_else(|_| "deepseek-chat".to_string())
}

Testing

Mock HTTP Client

#[cfg(test)]
mod tests {
    use super::*;
    use mockito::{mock, server_url};

    #[tokio::test]
    async fn test_generate_completion() {
        // 模拟 DeepSeek API 响应
        let _m = mock("POST", "/v1/chat/completions")
            .with_status(200)
            .with_header("content-type", "application/json")
            .with_body(r#"{
                "id": "chatcmpl-123",
                "model": "deepseek-chat",
                "choices": [{
                    "index": 0,
                    "message": {
                        "role": "assistant",
                        "content": "1. 好的,谢谢!\n2. 收到,马上处理。\n3. 了解,没问题。"
                    },
                    "finish_reason": "stop"
                }],
                "usage": {
                    "prompt_tokens": 20,
                    "completion_tokens": 30,
                    "total_tokens": 50
                }
            }"#)
            .create();

        let client = DeepSeekClient::new("test_api_key".to_string())
            .unwrap()
            .with_custom_endpoint(server_url());

        let messages = vec![
            ChatMessage {
                role: "user".to_string(),
                content: "测试消息".to_string(),
            },
        ];

        let response = client.generate_completion(messages).await.unwrap();

        assert_eq!(response.model, "deepseek-chat");
        assert_eq!(response.choices.len(), 1);
        assert!(response.choices[0].message.content.contains("好的"));
    }

    #[tokio::test]
    async fn test_retry_on_error() {
        // 模拟失败后成功的情况
        let _m1 = mock("POST", "/v1/chat/completions")
            .with_status(503)
            .with_body("Service Unavailable")
            .create();

        let _m2 = mock("POST", "/v1/chat/completions")
            .with_status(200)
            .with_body(r#"{"id": "test", "choices": []}"#)
            .create();

        let client = DeepSeekClient::new("test_key".to_string())
            .unwrap()
            .with_custom_endpoint(server_url());

        let messages = vec![];
        let result = client.generate_completion_with_retry(messages, 3).await;

        assert!(result.is_ok());
    }
}

Performance Optimization

Request Timeout Configuration

pub struct DeepSeekConfig {
    pub connect_timeout_secs: u64,
    pub request_timeout_secs: u64,
    pub max_retries: u32,
}

impl Default for DeepSeekConfig {
    fn default() -> Self {
        Self {
            connect_timeout_secs: 10,
            request_timeout_secs: 30,
            max_retries: 3,
        }
    }
}

Batch Request Processing

use futures::future::join_all;

pub async fn generate_multiple_suggestions(
    &self,
    requests: Vec<Vec<ChatMessage>>,
) -> Vec<anyhow::Result<ChatCompletionResponse>> {
    // 并发处理多个请求
    let futures = requests.into_iter().map(|messages| {
        let client = self.clone();
        async move {
            client.generate_completion(messages).await
        }
    });

    join_all(futures).await
}

Security Best Practices

API Key Validation

pub fn validate_api_key(api_key: &str) -> anyhow::Result<()> {
    if api_key.is_empty() {
        return Err(anyhow!("API 密钥不能为空"));
    }

    if !api_key.starts_with("sk-") {
        return Err(anyhow!("API 密钥格式错误"));
    }

    if api_key.len() < 20 {
        return Err(anyhow!("API 密钥长度不足"));
    }

    Ok(())
}

Logging Without Sensitive Data

use tracing::info;

pub async fn log_api_call(
    &self,
    message_count: usize,
    response_length: usize,
) {
    info!(
        message_count = message_count,
        response_length = response_length,
        "DeepSeek API 调用成功"
    );
    // ❌ 不要记录 API 密钥或消息内容
}

When to Use This Skill

Activate this skill when:

  • Integrating DeepSeek API
  • Implementing AI-powered features
  • Working with HTTP clients (reqwest)
  • Handling streaming responses
  • Implementing retry logic
  • Managing API keys securely
  • Optimizing API performance
  • Testing API integrations

平台分布

Codex

33.22%
按下载量换算23

Claude

31.61%
按下载量换算22

Cursor

18.72%
按下载量换算13

Gemini CLI

9.36%
按下载量换算7

安全审计

Gen Agent Trust Hub

通过

Socket

未通过

Snyk

可疑

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills