langchain-deepseek 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.3
2
+ Name: langchain-deepseek
3
+ Version: 0.0.1
4
+ Summary:
5
+ Author: SyJarvis
6
+ Author-email: 1755115828@qq.com
7
+ Requires-Python: >=3.9,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Dist: langchain (>=0.2.6)
15
+ Description-Content-Type: text/markdown
16
+
17
+ <center><h2>🚀 Langchain-Deepseek: Using the deepseek model in langchain</h2></center>
18
+ ## Install
19
+
20
+ * Install from source (Recommend)
21
+
22
+ ```bash
23
+ cd langchain-deepseek
24
+ pip install -e .
25
+ ```
26
+ * Install from PyPI
27
+ ```bash
28
+ pip install langchain-deepseek
29
+ ```
30
+
31
+ ## Quick Start
32
+ * All the code can be found in the `examples`
33
+ * Set DeepSeek API key in environment if using DeepSeek models: `export DEEPSEEK_API_KEY="sk-...".`
34
+ * Maybe you can try loading environment variables like this. Create a new `.env` file
35
+ ```
36
+ DEEPSEEK_API_KEY="sk-..."
37
+ ```
38
+ ```python
39
+ from dotenv import load_dotenv, find_dotenv
40
+ load_dotenv(find_dotenv(), override=True)
41
+ ```
42
+ ##### It works with the Langchain library
43
+
44
+ ```python
45
+ from langchain_deepseek import ChatDeepSeekAI
46
+ from langchain_core.output_parsers import StrOutputParser
47
+
48
+ llm = ChatDeepSeekAI(
49
+ model="deepseek-chat",
50
+ api_key="sk-...",
51
+ )
52
+
53
+ output_parser = StrOutputParser()
54
+ chain = llm | output_parser
55
+ response = chain.invoke("太阳系有几大行星?")
56
+ print(response)
57
+ ```
58
+
59
+
60
+
61
+ ## 🌟Citation
62
+
63
+ ```python
64
+ @article{guo2025langchain-deepseek,
65
+ title={langchain-deepseek: Using the deepseek model in langchain},
66
+ author={Runke Zhong},
67
+ year={2025}
68
+ }
69
+ ```
70
+ **保持热爱,奔赴星海!**
71
+
72
+ *这个世界上唯有两样东西能让我们的心灵感到深深的震撼:一是我们头上灿烂的星空,一是我们内心崇高的道德法则*
73
+
@@ -0,0 +1,56 @@
1
+ <center><h2>🚀 Langchain-Deepseek: Using the deepseek model in langchain</h2></center>
2
+ ## Install
3
+
4
+ * Install from source (Recommend)
5
+
6
+ ```bash
7
+ cd langchain-deepseek
8
+ pip install -e .
9
+ ```
10
+ * Install from PyPI
11
+ ```bash
12
+ pip install langchain-deepseek
13
+ ```
14
+
15
+ ## Quick Start
16
+ * All the code can be found in the `examples`
17
+ * Set DeepSeek API key in environment if using DeepSeek models: `export DEEPSEEK_API_KEY="sk-...".`
18
+ * Maybe you can try loading environment variables like this. Create a new `.env` file
19
+ ```
20
+ DEEPSEEK_API_KEY="sk-..."
21
+ ```
22
+ ```python
23
+ from dotenv import load_dotenv, find_dotenv
24
+ load_dotenv(find_dotenv(), override=True)
25
+ ```
26
+ ##### It works with the Langchain library
27
+
28
+ ```python
29
+ from langchain_deepseek import ChatDeepSeekAI
30
+ from langchain_core.output_parsers import StrOutputParser
31
+
32
+ llm = ChatDeepSeekAI(
33
+ model="deepseek-chat",
34
+ api_key="sk-...",
35
+ )
36
+
37
+ output_parser = StrOutputParser()
38
+ chain = llm | output_parser
39
+ response = chain.invoke("太阳系有几大行星?")
40
+ print(response)
41
+ ```
42
+
43
+
44
+
45
+ ## 🌟Citation
46
+
47
+ ```python
48
+ @article{guo2025langchain-deepseek,
49
+ title={langchain-deepseek: Using the deepseek model in langchain},
50
+ author={Runke Zhong},
51
+ year={2025}
52
+ }
53
+ ```
54
+ **保持热爱,奔赴星海!**
55
+
56
+ *这个世界上唯有两样东西能让我们的心灵感到深深的震撼:一是我们头上灿烂的星空,一是我们内心崇高的道德法则*
@@ -0,0 +1,6 @@
1
+
2
+ from .base import ChatDeepSeekAI
3
+
4
+ __version__ = "0.0.1"
5
+ __author__ = "Runke Zhong"
6
+ __url__ = "https://github.com/SyJarvis/langchain-deepseek"
@@ -0,0 +1,77 @@
1
+ from pydantic import BaseModel, Field
2
+ import os
3
+ import requests
4
+ import json
5
+ from .const import DEFAULT_BASE_URL
6
+ from .exceptions import AuthenticationError, BadRequestError, APITimeoutError
7
+
8
+
9
+ class RestAPI:
10
+ """
11
+ 访问大模型的REST API
12
+ """
13
+ def __init__(
14
+ self,
15
+ base_url: str = None,
16
+ api_key: str = None
17
+ ):
18
+ env_base_url = os.getenv("DEEPSEEK_BASE_URL")
19
+ env_api_key = os.getenv("DEEPSEEK_API_KEY")
20
+ if base_url is None:
21
+ base_url = env_base_url if env_base_url else DEFAULT_BASE_URL
22
+ if api_key is None:
23
+ if env_api_key is None:
24
+ raise ValueError("`DEEPSEEK_API_KEY` is required")
25
+ else:
26
+ api_key = env_api_key
27
+ self.base_url = base_url
28
+ self.api_key = api_key
29
+ self.session = requests.Session()
30
+
31
+ def action_post(self, request_path: str, datas: str=None, **kwargs):
32
+ """POST"""
33
+ url = self.base_url + "/" + request_path
34
+ headers = self._generate_headers()
35
+ payload = datas if datas else json.dumps(kwargs)
36
+ for _ in range(3):
37
+ try:
38
+ response = self.session.post(url, headers=headers, data=payload)
39
+ except Exception as e:
40
+ print("Retry for HTTP Error ...")
41
+ continue
42
+ else:
43
+ if response.status_code == 401:
44
+ raise AuthenticationError(
45
+ "认证失败:无效的API密钥或未授权访问",
46
+ response=response,
47
+ body=response.text
48
+ )
49
+ elif response.status_code == 400:
50
+ raise BadRequestError(
51
+ "请求参数错误",
52
+ response=response,
53
+ body=response.text
54
+ )
55
+ elif response.status_code == 200:
56
+ break
57
+ else:
58
+ raise APITimeoutError("连接超时")
59
+
60
+ if response.text:
61
+ resp = response.json()
62
+ return resp
63
+ else:
64
+ return {}
65
+
66
+ def close(self):
67
+ """关闭会话"""
68
+ self.session.close()
69
+
70
+ def _generate_headers(self, token=None) -> dict:
71
+ if token is None:
72
+ token = self.api_key
73
+ return {
74
+ "Content-Type": 'application/json',
75
+ 'Accept': 'application/json',
76
+ 'Authorization': f'Bearer {token}'
77
+ }
@@ -0,0 +1,199 @@
1
+ import inspect
2
+ from typing import (
3
+ Dict,
4
+ List,
5
+ Any,
6
+ Optional,
7
+ Mapping,
8
+ Tuple
9
+ )
10
+
11
+ from langchain_core.language_models.chat_models import (
12
+ BaseChatModel,
13
+ generate_from_stream
14
+ )
15
+
16
+ from langchain_core.messages import (
17
+ BaseMessage
18
+ )
19
+
20
+ from langchain_core.outputs import (
21
+ ChatResult,
22
+ ChatGeneration
23
+ )
24
+
25
+ from langchain_core.callbacks import (
26
+ CallbackManagerForLLMRun
27
+ )
28
+
29
+ from langchain_community.adapters.openai import (
30
+ convert_message_to_dict,
31
+ convert_dict_to_message
32
+ )
33
+
34
+ from langchain_core.pydantic_v1 import BaseModel, Field, root_validator
35
+
36
+ from .api import RestAPI
37
+
38
+
39
+ class ChatDeepSeekAI(BaseChatModel):
40
+ """`DeepSeek` Chat large language models API.
41
+
42
+ """
43
+
44
+ @property
45
+ def lc_secrets(self) -> Dict[str, str]:
46
+ return {"deepseek_api_key": "DEEPSEEK_API_KEY"}
47
+
48
+ @classmethod
49
+ def get_lc_namespace(cls) -> List[str]:
50
+ """Return"""
51
+ return ["langchain", "chat_models", "DeepSeek"]
52
+
53
+ @property
54
+ def lc_attributes(self) -> Dict[str, Any]:
55
+ attributes: Dict[str, Any] = {}
56
+ return attributes
57
+
58
+ @property
59
+ def _llm_type(self) -> str:
60
+ """Return the type of chat model."""
61
+ return "DeepSeekAI"
62
+
63
+ @property
64
+ def _identifying_params(self) -> Mapping[str, Any]:
65
+ return {**{"model_name": self.model}, **self._default_params}
66
+
67
+ @property
68
+ def _default_params(self) -> Dict[str, Any]:
69
+ params = {
70
+ "model": self.model,
71
+ "stream": self.streaming,
72
+ "n": self.n,
73
+ "temperature": self.temperature,
74
+ # **self.model_kwargs
75
+ }
76
+ if self.max_tokens is not None:
77
+ params["max_tokens"] = self.max_tokens
78
+ return params
79
+
80
+ """deepseek client"""
81
+ client: Any = Field(default=None, exclude=True)
82
+ """model name use"""
83
+ model: str = Field(default="deepseek-chat")
84
+ api_key: Optional[str] = Field(default=None, exclude=True)
85
+ base_url: Optional[str] = Field(default=None)
86
+ temperature: Optional[float] = Field(default=1)
87
+ top_p: Optional[float] = Field(default=1)
88
+ request_id: Optional[str] = Field(default=None)
89
+ max_tokens: Optional[int] = Field(default=2048)
90
+ streaming: Optional[bool] = Field(default=False)
91
+ n: Optional[int] = Field(default=1)
92
+ response_format: Dict[str, str] = Field(default={"type": "text"})
93
+ frequency_penalty: Optional[int] = Field(default=0)
94
+ presence_penalty: Optional[int] = Field(default=0)
95
+ tools: Any = Field(default=None)
96
+ tool_choice: Optional[str] = Field(default="none")
97
+ logprobs: Optional[bool] = Field(default=False)
98
+ top_logprobs: Optional[int] = Field(default=None)
99
+
100
+ @classmethod
101
+ def filter_model_kwargs(cls):
102
+ """
103
+ """
104
+ return [
105
+ "model",
106
+ "frequency_penalty",
107
+ "max_tokens",
108
+ "presence_penalty",
109
+ "response_format",
110
+ "stop",
111
+ "stream",
112
+ "temperature",
113
+ "top_p",
114
+ "tools",
115
+ "tool_choice",
116
+ "logprobs",
117
+ "top_logprobs",
118
+ "request_id"
119
+ ]
120
+
121
+ def _generate(
122
+ self,
123
+ messages: List[BaseMessage],
124
+ stop: Optional[List[str]] = None,
125
+ run_manager: Optional[CallbackManagerForLLMRun] = None,
126
+ stream: Optional[bool] = None,
127
+ **kwargs: Any
128
+ ) -> ChatResult:
129
+ should_stream = stream if stream is not None else self.streaming
130
+ if should_stream:
131
+ stream_iter = self._stream(
132
+ messages, stop=stop, run_manager=run_manager, **kwargs
133
+ )
134
+ return generate_from_stream(stream_iter)
135
+ message_dict, params = self._create_message_dicts(messages, stop)
136
+ response = self.completion_with_retry(
137
+ message_dict=message_dict,
138
+ run_manager=run_manager,
139
+ params=params
140
+ )
141
+ return self._create_chat_result(response)
142
+
143
+ def completion_with_retry(
144
+ self, message_dict=None, run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs
145
+ ):
146
+ params = kwargs["params"]
147
+ params.update({"messages": message_dict})
148
+ try:
149
+ self.client = RestAPI(base_url=self.base_url, api_key=self.api_key)
150
+ reply = self.client.action_post(request_path=f"chat/completions", **params)
151
+ except Exception as e:
152
+ raise e
153
+ return reply
154
+
155
+ def _create_chat_result(self, response):
156
+ generations = []
157
+ id = response.get("id")
158
+ if not isinstance(response, dict):
159
+ response = response.dict()
160
+ for res in response["choices"]:
161
+ message_dict = res["message"]
162
+ message = convert_dict_to_message(message_dict)
163
+ generation_info = dict(finish_reason=res.get("finish_reason"))
164
+ gen = ChatGeneration(
165
+ message=message,
166
+ generation_info=generation_info,
167
+ )
168
+ generations.append(gen)
169
+ token_usage = response.get("usage", {})
170
+ llm_output = {
171
+ "id": id,
172
+ "created": response.get("created"),
173
+ "token_usage": token_usage,
174
+ "model_name": self.model,
175
+ }
176
+ return ChatResult(generations=generations, llm_output=llm_output)
177
+
178
+ def _create_message_dicts(
179
+ self, messages: List[BaseMessage], stop: Optional[List[str]]
180
+ ) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]:
181
+ params = self.get_model_kwargs()
182
+ params.update({"stream": False})
183
+ if stop is not None:
184
+ if "stop" in params:
185
+ raise ValueError("`stop` found in both the input and default params.")
186
+ params.update({"stop": stop})
187
+ message_dicts = [convert_message_to_dict(message) for message in messages]
188
+ # 传递prompt
189
+ params.update({"messages": message_dicts})
190
+ return message_dicts, params
191
+
192
+ def get_model_kwargs(self):
193
+ attrs = {}
194
+ for cls in inspect.getmro(self.__class__):
195
+ attrs.update(vars(cls))
196
+ attrs.update((vars(self)))
197
+ return {
198
+ attr: value for attr, value in attrs.items() if attr in self.__class__.filter_model_kwargs() and value is not None
199
+ }
@@ -0,0 +1,3 @@
1
+ # -*- coding: utf-8 -*-
2
+ DEFAULT_BASE_URL = "https://api.deepseek.com"
3
+ ERROR_MESSAGE = "use llm model faild"
@@ -0,0 +1,62 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from __future__ import annotations
4
+
5
+ import httpx
6
+ import requests
7
+ from typing import Any, Optional, Literal
8
+
9
+ __all__ = [
10
+ "AuthenticationError",
11
+ "BadRequestError",
12
+ ]
13
+
14
+
15
+ class DeepSeekError(Exception):
16
+ pass
17
+
18
+
19
+ class APIError(DeepSeekError):
20
+ message: str = None
21
+ request: Optional[httpx.Request] = None
22
+ body: Any = None
23
+ code: Optional[str] = None
24
+ param: Optional[str] = None
25
+ type: Optional[str]
26
+
27
+ def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None:
28
+ self.message = message
29
+ self.request = request
30
+ self.body = body
31
+
32
+
33
+ class APIStatusError(APIError):
34
+ """Raised when an API response has a status code of 4xx or 5xx."""
35
+
36
+ response: httpx.Response
37
+ status_code: int
38
+ request_id: str | None
39
+
40
+ def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None:
41
+ super().__init__(message, response.request, body=body)
42
+ self.response = response
43
+ self.status_code = response.status_code
44
+ self.request_id = response.headers.get("x-request-id")
45
+
46
+
47
+ class APIConnectionError(APIError):
48
+ def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None:
49
+ super().__init__(message, request, body=None)
50
+
51
+
52
+ class APITimeoutError(APIConnectionError):
53
+ def __init__(self, request: httpx.Request) -> None:
54
+ super().__init__(message="Request timed out.", request=request)
55
+
56
+
57
+ class AuthenticationError(APIStatusError):
58
+ status_code: Literal[401] = 401
59
+
60
+
61
+ class BadRequestError(APIStatusError):
62
+ status_code: Literal[400] = 400
@@ -0,0 +1 @@
1
+ # -*- coding: utf-8 -*-
@@ -0,0 +1,20 @@
1
+ [project]
2
+ name = "langchain-deepseek"
3
+ version = "0.0.1"
4
+ description = ""
5
+ authors = [
6
+ {name = "SyJarvis",email = "1755115828@qq.com"}
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.9,<4.0"
10
+ dependencies = [
11
+ "langchain (>=0.2.6)"
12
+ ]
13
+
14
+ [[tool.poetry.source]]
15
+ name = "aliyun"
16
+ url = "https://mirrors.aliyun.com/pypi/simple/"
17
+
18
+ [build-system]
19
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
20
+ build-backend = "poetry.core.masonry.api"