Skip to content

Commit 883ef11

Browse files
committed
feat: demo
1 parent 6eb07b0 commit 883ef11

8 files changed

Lines changed: 2880 additions & 179 deletions

File tree

‎demohouse/deepdoubao/README.md‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# DeepDoubao
2+
## 应用介绍
3+
这是一款结合DeepSeek R1模型的强大推理能力与Doubao模型的高效对话能力的应用,为用户提供智能问答服务。通过Deepseek R1模型的推理能力与Doubao自然流畅的对话相结合,为用户带来精准、专业且具有互动性的智能体验。
4+
5+
### 相关模型
6+
- 思考:DeepSeek-R1/250120
7+
8+
- 回答:不同场景可以选择不同的回答模型
9+
- 综合任务:Doubao-1.5-pro-32k/250115
10+
- 角色扮演:Doubao-pro-32k/character-241215
11+
12+
13+
## 环境准备
14+
15+
- Python 版本要求大于等于 3.8,小于 3.12
16+
- 已获取火山方舟 API Key [参考文档](https://www.volcengine.com/docs/82379/1298459#api-key-%E7%AD%BE%E5%90%8D%E9%89%B4%E6%9D%83)
17+
- 已创建 DeepSeek-R1 的 endpoint [参考文档](https://www.volcengine.com/docs/82379/1099522#594199f1)
18+
- 已创建 Douba 的endpoint [参考文档](https://www.volcengine.com/docs/82379/1099522#594199f1)
19+
20+
## 快速开始
21+
22+
1. 下载代码库
23+
24+
```bash
25+
git clone https://github.com/volcengine/ai-app-lab.git
26+
cd demohouse/deepdoubao
27+
```
28+
2. 修改配置
29+
30+
- 修改`backend/code/main.py` 中配置,填入
31+
```text
32+
| 配置变量名 | 说明 |
33+
| ------------------------ | -------------------------------|
34+
| DEEPSEEK_R1_ENDPOINT | DeepSeek-R1 endpoint id |
35+
| DOUBAO_ENDPOINT | Doubao 模型 endpoint id |
36+
```
37+
38+
- 修改 `backend/run.sh` 中配置,填入获取的API key
39+
```text
40+
| 配置变量名 | 说明 |
41+
| ----------- | --------------- |
42+
| ARK_API_KEY | 火山方舟 API Key |
43+
```
44+
45+
46+
47+
3. 安装后端依赖
48+
49+
```bash
50+
cd demohouse/deepdoubao/backend
51+
52+
python -m venv .venv
53+
source .venv/bin/activate
54+
pip install poetry==1.6.1
55+
56+
poetry install
57+
```
58+
4. 启动后端
59+
60+
```bash
61+
cd demohouse/deepdoubao/backend
62+
bash run.sh
63+
```
64+
65+
5. 测试
66+
67+
```bash
68+
curl --location 'http://localhost:8888/api/v3/bots/chat/completions' \
69+
--header 'Content-Type: application/json' \
70+
--data '{
71+
"model": "test",
72+
"stream": true,
73+
"messages": [
74+
{
75+
"role": "user",
76+
"content": "写一个适合3岁宝宝的睡前故事"
77+
}
78+
]
79+
}'
80+
```
81+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
2+
# Licensed under the 【火山方舟】原型应用软件自用许可协议
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# https://www.volcengine.com/docs/82379/1433703
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
2+
# Licensed under the 【火山方舟】原型应用软件自用许可协议
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# https://www.volcengine.com/docs/82379/1433703
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
11+
12+
"""
13+
DeepDoubao
14+
"""
15+
16+
import logging
17+
import os
18+
from typing import AsyncIterable, Union
19+
20+
from arkitect.core.component.llm import BaseChatLanguageModel
21+
from arkitect.core.component.llm.model import (
22+
ArkChatCompletionChunk,
23+
ArkChatParameters,
24+
ArkChatRequest,
25+
ArkChatResponse,
26+
Response,
27+
ArkMessage,
28+
BotUsage,
29+
)
30+
from arkitect.launcher.local.serve import launch_serve
31+
from arkitect.telemetry.trace import task
32+
from volcenginesdkarkruntime.types.completion_usage import (
33+
CompletionUsage,
34+
PromptTokensDetails,
35+
CompletionTokensDetails,
36+
)
37+
38+
logger = logging.getLogger(__name__)
39+
40+
DEEPSEEK_R1_ENDPOINT = "<ENDPOINT_ID_FOR_DEEPSEEK_R1>"
41+
DOUBAO_ENDPOINT = "<ENDPOINT_ID_FOR_DOUBAO>"
42+
43+
44+
def merge_usage(usage1: CompletionUsage, usage2: CompletionUsage) -> CompletionUsage:
45+
usage = CompletionUsage(
46+
prompt_tokens=usage1.prompt_tokens + usage2.prompt_tokens,
47+
completion_tokens=usage1.completion_tokens + usage2.completion_tokens,
48+
total_tokens=usage1.total_tokens + usage2.total_tokens,
49+
)
50+
if usage1.prompt_tokens_details or usage2.prompt_tokens_details:
51+
usage.prompt_tokens_details = PromptTokensDetails(
52+
cached_tokens=usage1.prompt_tokens_details.cached_tokens
53+
+ usage2.prompt_tokens_details.cached_tokens
54+
)
55+
if usage1.completion_tokens_details or usage2.completion_tokens_details:
56+
r1 = usage1.completion_tokens_details.reasoning_tokens
57+
r2 = usage2.completion_tokens_details.reasoning_tokens
58+
usage.completion_tokens_details = CompletionTokensDetails(
59+
reasoning_tokens=r1 if r2 is None else r2 if r1 is None else r1 + r2
60+
)
61+
return usage
62+
63+
64+
@task()
65+
async def default_model_calling(
66+
request: ArkChatRequest,
67+
) -> AsyncIterable[Union[ArkChatCompletionChunk, ArkChatResponse]]:
68+
parameters_r1 = ArkChatParameters(**request.__dict__)
69+
parameters_r1.max_tokens = (
70+
1 # Set max_tokens to 1, so R1 model will only output reasoning content.
71+
)
72+
deepseek = BaseChatLanguageModel(
73+
endpoint_id=DEEPSEEK_R1_ENDPOINT,
74+
messages=request.messages,
75+
parameters=parameters_r1,
76+
)
77+
reasoning_content = ""
78+
reasoning_usage = CompletionUsage(
79+
completion_tokens=0,
80+
total_tokens=0,
81+
prompt_tokens=0,
82+
)
83+
if request.stream:
84+
async for chunk in deepseek.astream():
85+
if chunk.usage:
86+
reasoning_usage = chunk.usage
87+
if len(chunk.choices) > 0 and chunk.choices[0].delta.reasoning_content:
88+
yield chunk
89+
reasoning_content += chunk.choices[0].delta.reasoning_content
90+
else:
91+
response = await deepseek.arun()
92+
reasoning_content = response.choices[0].message.reasoning_content
93+
if response.usage:
94+
reasoning_usage = response.usage
95+
96+
parameters_doubao = ArkChatParameters(**request.__dict__)
97+
doubao = BaseChatLanguageModel(
98+
endpoint_id=DOUBAO_ENDPOINT,
99+
messages=request.messages
100+
+ [
101+
ArkMessage(
102+
role="assistant",
103+
content="思考过程如下:\n"
104+
+ reasoning_content
105+
+ "\n请根据以上思考过程,给出完整的回答:\n",
106+
)
107+
],
108+
parameters=parameters_doubao,
109+
)
110+
if request.stream:
111+
async for chunk in doubao.astream():
112+
if chunk.usage:
113+
chunk.bot_usage = BotUsage(model_usage=[reasoning_usage, chunk.usage])
114+
chunk.usage = merge_usage(chunk.usage, reasoning_usage)
115+
yield chunk
116+
else:
117+
response = await doubao.arun()
118+
response.choices[0].message.reasoning_content = reasoning_content
119+
if response.usage:
120+
response.bot_usage = BotUsage(model_usage=[reasoning_usage, response.usage])
121+
response.usage = merge_usage(response.usage, reasoning_usage)
122+
yield response
123+
124+
125+
@task()
126+
async def main(request: ArkChatRequest) -> AsyncIterable[Response]:
127+
async for resp in default_model_calling(request):
128+
yield resp
129+
130+
131+
if __name__ == "__main__":
132+
port = os.getenv("_FAAS_RUNTIME_PORT")
133+
launch_serve(
134+
package_path="main",
135+
port=int(port) if port else 8888,
136+
health_check_path="/v1/ping",
137+
endpoint_path="/api/v3/bots/chat/completions",
138+
)

0 commit comments

Comments
 (0)