Skip to content

Commit 09687de

Browse files
authored
Merge pull request #70 from ghost-in-moss/feat/deepseek-reasoning
version:0.2.0
2 parents 459ebc5 + e9e11bf commit 09687de

File tree

27 files changed

+500
-163
lines changed

27 files changed

+500
-163
lines changed

RELEASES.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Releases
22

3+
# v0.2.0
4+
5+
support deepseek-r1.
6+
7+
* support deepseek-r1
8+
* consider deepseek api protocol is different from openai, add deepseek api adapter.
9+
* implement message stage.
10+
* thread history message to prompt filter by stages `[""]` as default.
11+
* streamlit chat with ghost support staging message stream.
12+
* openai o1 do not support system/developer message now, add new compatible option to the model.
13+
* now llm model and service both have attribute `compatible` to set universe compatible options.
14+
* prompt object add first_token attribute for debugging.
15+
* fix bugs
16+
* fix shell does not close conversation correctly
17+
* fix sequence pipeline handle multiple complete message wrong.
18+
319
# v0.1.0
420

521
first release version.

ghostos/app/configs/llms_conf.yml

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
# from class: ghostos.framework.llms.providers:LLMsYamlConfig
2+
services:
3+
- base_url: https://api.moonshot.cn/v1
4+
driver: openai_driver
5+
name: moonshot
6+
token: $MOONSHOT_API_KEY
7+
- base_url: https://api.openai.com/v1
8+
driver: openai_driver
9+
name: openai
10+
proxy: $OPENAI_PROXY
11+
token: $OPENAI_API_KEY
12+
compatible:
13+
use_developer_role: true
14+
- base_url: https://api.anthropic.com/v1
15+
driver: lite_llm_driver
16+
name: anthropic
17+
proxy: $ANTHROPIC_PROXY
18+
token: $ANTHROPIC_API_KEY
19+
- base_url: https://api.deepseek.com/beta
20+
driver: deepseek_driver
21+
name: deepseek
22+
token: $DEEPSEEK_API_KEY
23+
- base_url: $AZURE_ENDPOINT
24+
name: azure
25+
driver: openai_driver
26+
azure:
27+
api_key: $AZURE_API_KEY
28+
api_version: 2023-07-01-preview
229
default: gpt-4o
330
models:
431
gpt-4o-2024-08-06:
@@ -45,17 +72,11 @@ models:
4572
temperature: 0.7
4673
timeout: 30
4774
use_tools: true
48-
deepseek-coder:
49-
kwargs: { }
50-
max_tokens: 2000
51-
message_types: null
52-
model: deepseek/deepseek-coder
53-
n: 1
54-
request_timeout: 40
75+
deepseek-reasoner:
76+
max_tokens: 3400
77+
model: deepseek-reasoner
5578
service: deepseek
56-
temperature: 0.7
57-
timeout: 30
58-
use_tools: true
79+
reasoning: {}
5980
gpt-3.5-turbo:
6081
kwargs: { }
6182
max_tokens: 2000
@@ -93,10 +114,14 @@ models:
93114
model: o1-mini
94115
service: openai
95116
reasoning: { }
117+
compatible:
118+
allow_system_message: false
96119
gpt-o1:
97120
model: o1
98121
service: openai
99122
reasoning: { }
123+
compatible:
124+
allow_system_message: false
100125
gpt-4o:
101126
kwargs: { }
102127
max_tokens: 2000
@@ -141,30 +166,3 @@ models:
141166
temperature: 0.7
142167
timeout: 30
143168
use_tools: true
144-
services:
145-
- base_url: https://api.moonshot.cn/v1
146-
driver: openai_driver
147-
name: moonshot
148-
token: $MOONSHOT_API_KEY
149-
- base_url: https://api.openai.com/v1
150-
driver: openai_driver
151-
name: openai
152-
proxy: $OPENAI_PROXY
153-
token: $OPENAI_API_KEY
154-
compatible:
155-
use_developer_role: true
156-
- base_url: https://api.anthropic.com/v1
157-
driver: lite_llm_driver
158-
name: anthropic
159-
proxy: $ANTHROPIC_PROXY
160-
token: $ANTHROPIC_API_KEY
161-
- base_url: https://api.deepseek.com/beta
162-
driver: openai_driver
163-
name: deepseek
164-
token: $DEEPSEEK_API_KEY
165-
- base_url: $AZURE_ENDPOINT
166-
name: azure
167-
driver: openai_driver
168-
azure:
169-
api_key: $AZURE_API_KEY
170-
api_version: 2023-07-01-preview

ghostos/core/llms/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from ghostos.core.llms.configs import (
22
ModelConf, ServiceConf, LLMsConfig,
3-
OPENAI_DRIVER_NAME, LITELLM_DRIVER_NAME,
3+
OPENAI_DRIVER_NAME, LITELLM_DRIVER_NAME, DEEPSEEK_DRIVER_NAME,
44
)
55
from ghostos.core.llms.abcd import LLMs, LLMDriver, LLMApi
66
from ghostos.core.llms.prompt import (

ghostos/core/llms/abcd.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ class LLMApi(ABC):
1717
"""
1818

1919
service: ServiceConf
20+
"""service of the api"""
21+
2022
model: ModelConf
23+
"""model of the api"""
2124

2225
@property
2326
@abstractmethod
@@ -28,13 +31,15 @@ def name(self) -> str:
2831
def get_service(self) -> ServiceConf:
2932
"""
3033
get the service configuration of this API
34+
Deprecated.
3135
"""
3236
pass
3337

3438
@abstractmethod
3539
def get_model(self) -> ModelConf:
3640
"""
3741
get new api with the given api_conf and return new LLMAPI
42+
Deprecated.
3843
"""
3944
pass
4045

@@ -65,21 +70,34 @@ def chat_completion_chunks(self, prompt: Prompt) -> Iterable[Message]:
6570
pass
6671

6772
@abstractmethod
68-
def reasoning_completion(self, prompt: Prompt, stream: bool) -> Iterable[Message]:
73+
def reasoning_completion(self, prompt: Prompt) -> Iterable[Message]:
74+
"""
75+
reasoning completion is not compatible to chat completion.
76+
so we need another api.
77+
:param prompt:
78+
:return:
79+
"""
80+
pass
81+
82+
@abstractmethod
83+
def reasoning_completion_stream(self, prompt: Prompt) -> Iterable[Message]:
6984
pass
7085

7186
def deliver_chat_completion(self, prompt: Prompt, stream: bool) -> Iterable[Message]:
7287
"""
7388
逐个发送消息的包.
7489
"""
75-
if self.model.reasoning is not None:
76-
yield from self.reasoning_completion(prompt, stream)
77-
78-
elif not stream or not self.model.allow_streaming:
79-
message = self.chat_completion(prompt)
80-
return [message]
90+
if self.model.reasoning:
91+
if not stream or not self.model.allow_streaming:
92+
yield from self.reasoning_completion(prompt)
93+
else:
94+
yield from self.reasoning_completion_stream(prompt)
8195
else:
82-
yield from self.chat_completion_chunks(prompt)
96+
if not stream or not self.model.allow_streaming:
97+
message = self.chat_completion(prompt)
98+
return [message]
99+
else:
100+
yield from self.chat_completion_chunks(prompt)
83101

84102

85103
class LLMDriver(ABC):

ghostos/core/llms/configs.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111

1212
__all__ = [
1313
'ModelConf', 'ServiceConf', 'LLMsConfig',
14-
'OPENAI_DRIVER_NAME', 'LITELLM_DRIVER_NAME',
14+
'OPENAI_DRIVER_NAME', 'LITELLM_DRIVER_NAME', 'DEEPSEEK_DRIVER_NAME',
1515
]
1616

1717
OPENAI_DRIVER_NAME = "openai_driver"
1818
"""default llm driver name for OpenAI llm message protocol """
1919

2020
LITELLM_DRIVER_NAME = "lite_llm_driver"
2121

22+
DEEPSEEK_DRIVER_NAME = "deepseek_driver"
23+
2224

2325
class Reasonable(BaseModel):
2426
"""
@@ -28,6 +30,10 @@ class Reasonable(BaseModel):
2830
"medium",
2931
description="reasoning effort level",
3032
)
33+
max_completion_tokens: Optional[int] = Field(
34+
None,
35+
description="max completion tokens",
36+
)
3137

3238

3339
class ModelConf(Payload):
@@ -46,17 +52,19 @@ class ModelConf(Payload):
4652
request_timeout: float = Field(default=40, description="request timeout")
4753
kwargs: Dict[str, Any] = Field(default_factory=dict, description="kwargs")
4854
use_tools: bool = Field(default=True, description="use tools")
49-
max_completion_tokens: Optional[int] = Field(
50-
None,
51-
description="max completion tokens",
52-
)
55+
5356
message_types: Optional[List[str]] = Field(None, description="model allow message types")
5457
allow_streaming: bool = Field(True, description="if the current model allow streaming")
5558
reasoning: Optional[Reasonable] = Field(
5659
default=None,
5760
description="reasoning configuration",
5861
)
5962

63+
compatible: Optional[Compatible] = Field(
64+
default=None,
65+
description="the model api compatible configuration",
66+
)
67+
6068
payloads: Dict[str, Dict] = Field(
6169
default_factory=dict,
6270
description="custom payload objects. save strong typed but optional dict."
@@ -67,6 +75,7 @@ class ModelConf(Payload):
6775
class Compatible(BaseModel):
6876
use_developer_role: bool = Field(default=False, description="use developer role instead of system")
6977
allow_system_in_messages: bool = Field(default=True, description="allow system messages in history")
78+
allow_system_message: bool = Field(default=True, description="support system message or not")
7079

7180

7281
class Azure(BaseModel):
@@ -93,8 +102,8 @@ class ServiceConf(BaseModel):
93102
description="the adapter driver name of this service. change it only if you know what you are doing",
94103
)
95104

96-
compatible: Compatible = Field(
97-
default_factory=Compatible,
105+
compatible: Optional[Compatible] = Field(
106+
default=None,
98107
description="the model api compatible configuration",
99108
)
100109

ghostos/core/llms/prompt.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ class Prompt(BaseModel):
4949
error: Optional[str] = Field(default=None, description="error message")
5050
created: int = Field(default_factory=timestamp)
5151
model: Optional[ModelConf] = Field(default=None, description="model conf")
52-
run_start: int = Field(default=0, description="start time")
53-
run_end: int = Field(default=0, description="end time")
52+
run_start: float = Field(default=0.0, description="start time")
53+
first_token: float = Field(default=0.0, description="first token")
54+
run_end: float = Field(default=0.0, description="end time")
5455

5556
def system_prompt(self) -> str:
5657
contents = []

ghostos/core/messages/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
FunctionCaller, FunctionOutput,
44
MessageClass, MessageKind,
55
MessageClassesParser,
6+
MessageStage,
67
)
78
from ghostos.core.messages.message_classes import (
89
MessageKindParser,

ghostos/core/messages/message.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
__all__ = [
1515
"Message", "Role", "MessageType",
16+
"MessageStage",
1617
"MessageClass", "MessageClassesParser",
1718
"MessageKind",
1819
"FunctionCaller", "FunctionOutput",
@@ -187,6 +188,12 @@ def is_protocol_type(cls, value: str) -> bool:
187188
# todo: 1. 传输协议和存储协议分开.
188189
# todo: 2. 传输用弱类型.
189190
# todo: 3. delta 用于流式传输, content part 用来解决富文本, item 解决消息体.
191+
192+
class MessageStage(str, enum.Enum):
193+
DEFAULT = ""
194+
REASONING = "reasoning"
195+
196+
190197
class Message(BaseModel):
191198
""" message protocol """
192199

@@ -242,6 +249,7 @@ def new_head(
242249
name: Optional[str] = None,
243250
msg_id: Optional[str] = None,
244251
call_id: Optional[str] = None,
252+
stage: str = "",
245253
):
246254
"""
247255
create a head chunk message
@@ -252,6 +260,7 @@ def new_head(
252260
:param name:
253261
:param msg_id:
254262
:param call_id:
263+
:param stage:
255264
# :param created:
256265
:return:
257266
"""
@@ -271,6 +280,7 @@ def new_head(
271280
type=typ_,
272281
call_id=call_id,
273282
msg_id=msg_id,
283+
stage=stage,
274284
created=created,
275285
)
276286

@@ -286,6 +296,7 @@ def new_tail(
286296
# todo: change to call id
287297
call_id: Optional[str] = None,
288298
attrs: Optional[Dict[str, Any]] = None,
299+
stage: str = "",
289300
):
290301
"""
291302
create a tail message, is the complete message of chunks.
@@ -297,6 +308,7 @@ def new_tail(
297308
:param msg_id:
298309
:param call_id:
299310
:param attrs:
311+
:param stage:
300312
:return:
301313
"""
302314
msg = cls.new_head(
@@ -307,6 +319,7 @@ def new_tail(
307319
typ_=type_,
308320
msg_id=msg_id,
309321
call_id=call_id,
322+
stage=stage,
310323
)
311324
msg.seq = "complete"
312325
msg.attrs = attrs
@@ -322,6 +335,7 @@ def new_chunk(
322335
name: Optional[str] = None,
323336
call_id: Optional[str] = None,
324337
msg_id: Optional[str] = None,
338+
stage: str = "",
325339
):
326340
"""
327341
create a chunk message.
@@ -333,6 +347,7 @@ def new_chunk(
333347
call_id=call_id,
334348
msg_id=msg_id or "",
335349
seq="chunk",
350+
stage=stage,
336351
)
337352

338353
def get_content(self) -> str:
@@ -406,6 +421,8 @@ def update(self, pack: "Message") -> None:
406421
if not self.type:
407422
# only update when self type is empty (default)
408423
self.type = pack.type
424+
if pack.stage:
425+
self.stage = pack.stage
409426

410427
if not self.role:
411428
self.role = pack.role

0 commit comments

Comments
 (0)