增加成本统计信息
This commit is contained in:
parent
4e8caf4c53
commit
3de7ef68ba
@ -35,6 +35,7 @@
|
|||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- [x] 完成最基本的各类基础设施
|
- [x] 完成最基本的各类基础设施
|
||||||
|
- [ ] chat 模式下支持进行成本分析
|
||||||
- [ ] 支持同时调试多个 MCP Server
|
- [ ] 支持同时调试多个 MCP Server
|
||||||
- [ ] 支持通过大模型进行在线验证
|
- [ ] 支持通过大模型进行在线验证
|
||||||
- [ ] 支持 completion/complete 协议字段
|
- [ ] 支持 completion/complete 协议字段
|
||||||
|
@ -29,7 +29,7 @@ bridge.addCommandListener('hello', data => {
|
|||||||
|
|
||||||
|
|
||||||
function initDebug() {
|
function initDebug() {
|
||||||
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
connectionArgs.commandString = 'uv run mcp run ../servers/main.py';
|
||||||
connectionMethods.current = 'STDIO';
|
connectionMethods.current = 'STDIO';
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
|
@ -1,12 +1,23 @@
|
|||||||
import { ToolItem } from "@/hook/type";
|
import { ToolItem } from "@/hook/type";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
import type { OpenAI } from 'openai';
|
||||||
|
type ChatCompletionChunk = OpenAI.Chat.Completions.ChatCompletionChunk;
|
||||||
|
|
||||||
|
export interface IExtraInfo {
|
||||||
|
created: number,
|
||||||
|
serverName: string,
|
||||||
|
usage?: ChatCompletionChunk['usage'];
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
export interface ChatMessage {
|
export interface ChatMessage {
|
||||||
role: 'user' | 'assistant' | 'system' | 'tool';
|
role: 'user' | 'assistant' | 'system' | 'tool';
|
||||||
content: string;
|
content: string;
|
||||||
tool_call_id?: string
|
tool_call_id?: string
|
||||||
name?: string // 工具名称,当 role 为 tool
|
name?: string // 工具名称,当 role 为 tool
|
||||||
tool_calls?: ToolCall[]
|
tool_calls?: ToolCall[],
|
||||||
|
extraInfo: IExtraInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增状态和工具数据
|
// 新增状态和工具数据
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<div class="message-text">
|
<div class="message-text">
|
||||||
<div v-if="message.content" v-html="markdownToHtml(message.content)"></div>
|
<div v-if="message.content" v-html="markdownToHtml(message.content)"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<MessageMeta :message="message" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 助手调用的工具部分 -->
|
<!-- 助手调用的工具部分 -->
|
||||||
@ -81,6 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<MessageMeta :message="message" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -129,12 +131,16 @@ import { ref, onMounted, defineComponent, defineProps, onUnmounted, computed, ne
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { ElMessage, ScrollbarInstance } from 'element-plus';
|
import { ElMessage, ScrollbarInstance } from 'element-plus';
|
||||||
import { tabs } from '../panel';
|
import { tabs } from '../panel';
|
||||||
import { ChatMessage, ChatStorage, getToolSchema, ToolCall } from './chat';
|
import { ChatMessage, ChatStorage, getToolSchema, IExtraInfo, ToolCall } from './chat';
|
||||||
|
|
||||||
|
|
||||||
import Setting from './setting.vue';
|
import Setting from './setting.vue';
|
||||||
|
import MessageMeta from './message-meta.vue';
|
||||||
|
|
||||||
// 引入 markdown.ts 中的函数
|
// 引入 markdown.ts 中的函数
|
||||||
import { markdownToHtml, copyToClipboard } from './markdown';
|
import { markdownToHtml, copyToClipboard } from './markdown';
|
||||||
import { TaskLoop } from './task-loop';
|
import { ChatCompletionChunk, TaskLoop } from './task-loop';
|
||||||
|
import { llmManager, llms } from '@/views/setting/llm';
|
||||||
|
|
||||||
defineComponent({ name: 'chat' });
|
defineComponent({ name: 'chat' });
|
||||||
|
|
||||||
@ -174,6 +180,7 @@ interface IRenderMessage {
|
|||||||
toolResult?: string;
|
toolResult?: string;
|
||||||
tool_calls?: ToolCall[];
|
tool_calls?: ToolCall[];
|
||||||
showJson?: Ref<boolean>;
|
showJson?: Ref<boolean>;
|
||||||
|
extraInfo: IExtraInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderMessages = computed(() => {
|
const renderMessages = computed(() => {
|
||||||
@ -182,7 +189,8 @@ const renderMessages = computed(() => {
|
|||||||
if (message.role === 'user') {
|
if (message.role === 'user') {
|
||||||
messages.push({
|
messages.push({
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: message.content
|
content: message.content,
|
||||||
|
extraInfo: message.extraInfo
|
||||||
});
|
});
|
||||||
} else if (message.role === 'assistant') {
|
} else if (message.role === 'assistant') {
|
||||||
if (message.tool_calls) {
|
if (message.tool_calls) {
|
||||||
@ -190,12 +198,14 @@ const renderMessages = computed(() => {
|
|||||||
role: 'assistant/tool_calls',
|
role: 'assistant/tool_calls',
|
||||||
content: message.content,
|
content: message.content,
|
||||||
tool_calls: message.tool_calls,
|
tool_calls: message.tool_calls,
|
||||||
showJson: ref(false)
|
showJson: ref(false),
|
||||||
|
extraInfo: message.extraInfo
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
messages.push({
|
messages.push({
|
||||||
role: 'assistant/content',
|
role: 'assistant/content',
|
||||||
content: message.content
|
content: message.content,
|
||||||
|
extraInfo: message.extraInfo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +312,11 @@ const handleSend = () => {
|
|||||||
|
|
||||||
tabStorage.messages.push({
|
tabStorage.messages.push({
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: `错误: ${msg}`
|
content: `错误: ${msg}`,
|
||||||
|
extraInfo: {
|
||||||
|
created: Date.now(),
|
||||||
|
serverName: llms[llmManager.currentModelIndex].id || 'unknown'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
@ -361,7 +375,6 @@ const jsonResultToHtml = (jsonString: string) => {
|
|||||||
return html;
|
return html;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 新增格式化工具参数的方法
|
|
||||||
const formatToolArguments = (args: string) => {
|
const formatToolArguments = (args: string) => {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(args);
|
const parsed = JSON.parse(args);
|
||||||
@ -510,9 +523,7 @@ const formatToolArguments = (args: string) => {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 原有样式保持不变 */
|
|
||||||
|
|
||||||
/* 新增工具调用样式 */
|
|
||||||
.tool-calls {
|
.tool-calls {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
76
renderer/src/components/main-panel/chat/message-meta.vue
Normal file
76
renderer/src/components/main-panel/chat/message-meta.vue
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<template>
|
||||||
|
<div class="message-meta" @mouseenter="showTime = true" @mouseleave="showTime = false">
|
||||||
|
<span v-if="usageStatistic" class="message-usage">
|
||||||
|
<span>
|
||||||
|
输入 {{ usageStatistic.input }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
输出 {{ usageStatistic.output }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
消耗的总 token {{ usageStatistic.total }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
缓存命中率 {{ usageStatistic.cacheHitRatio }}%
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-else class="message-usage">
|
||||||
|
<span>你使用的供应商暂时不支持统计信息</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-show="showTime" class="message-time">
|
||||||
|
{{ props.message.extraInfo.serverName }} 作答于
|
||||||
|
{{ new Date(message.extraInfo.created).toLocaleString() }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineComponent, defineProps, ref } from 'vue';
|
||||||
|
import { makeUsageStatistic } from './usage';
|
||||||
|
|
||||||
|
defineComponent({ name: 'message-meta' });
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
message: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const usageStatistic = makeUsageStatistic(props.message.extraInfo);
|
||||||
|
const showTime = ref(false);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.message-meta {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-time {
|
||||||
|
opacity: 0.7;
|
||||||
|
padding: 2px 6px 2px 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-usage {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-usage > span {
|
||||||
|
background-color: var(--el-fill-color-light);
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -6,8 +6,8 @@ import type { OpenAI } from 'openai';
|
|||||||
import { callTool } from "../tool/tools";
|
import { callTool } from "../tool/tools";
|
||||||
import { llmManager, llms } from "@/views/setting/llm";
|
import { llmManager, llms } from "@/views/setting/llm";
|
||||||
|
|
||||||
type ChatCompletionChunk = OpenAI.Chat.Completions.ChatCompletionChunk;
|
export type ChatCompletionChunk = OpenAI.Chat.Completions.ChatCompletionChunk;
|
||||||
type ChatCompletionCreateParamsBase = OpenAI.Chat.Completions.ChatCompletionCreateParams & { id?: string };
|
export type ChatCompletionCreateParamsBase = OpenAI.Chat.Completions.ChatCompletionCreateParams & { id?: string };
|
||||||
interface TaskLoopOptions {
|
interface TaskLoopOptions {
|
||||||
maxEpochs: number;
|
maxEpochs: number;
|
||||||
}
|
}
|
||||||
@ -18,6 +18,7 @@ interface TaskLoopOptions {
|
|||||||
export class TaskLoop {
|
export class TaskLoop {
|
||||||
private bridge = useMessageBridge();
|
private bridge = useMessageBridge();
|
||||||
private currentChatId = '';
|
private currentChatId = '';
|
||||||
|
private completionUsage: ChatCompletionChunk['usage'] | undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly streamingContent: Ref<string>,
|
private readonly streamingContent: Ref<string>,
|
||||||
@ -27,7 +28,9 @@ export class TaskLoop {
|
|||||||
private onDone: () => void = () => {},
|
private onDone: () => void = () => {},
|
||||||
private onEpoch: () => void = () => {},
|
private onEpoch: () => void = () => {},
|
||||||
private readonly taskOptions: TaskLoopOptions = { maxEpochs: 20 },
|
private readonly taskOptions: TaskLoopOptions = { maxEpochs: 20 },
|
||||||
) {}
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private async handleToolCalls(toolCalls: ToolCall[]) {
|
private async handleToolCalls(toolCalls: ToolCall[]) {
|
||||||
// TODO: 调用多个工具并返回调用结果?
|
// TODO: 调用多个工具并返回调用结果?
|
||||||
@ -89,6 +92,13 @@ export class TaskLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleChunkUsage(chunk: ChatCompletionChunk) {
|
||||||
|
const usage = chunk.usage;
|
||||||
|
if (usage) {
|
||||||
|
this.completionUsage = usage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private doConversation(chatData: ChatCompletionCreateParamsBase) {
|
private doConversation(chatData: ChatCompletionCreateParamsBase) {
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
@ -99,15 +109,16 @@ export class TaskLoop {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { chunk } = data.msg as { chunk: ChatCompletionChunk };
|
const { chunk } = data.msg as { chunk: ChatCompletionChunk };
|
||||||
|
|
||||||
// 处理增量的 content 和 tool_calls
|
// 处理增量的 content 和 tool_calls
|
||||||
this.handleChunkDeltaContent(chunk);
|
this.handleChunkDeltaContent(chunk);
|
||||||
this.handleChunkDeltaToolCalls(chunk);
|
this.handleChunkDeltaToolCalls(chunk);
|
||||||
|
this.handleChunkUsage(chunk);
|
||||||
|
|
||||||
this.onChunk(chunk);
|
this.onChunk(chunk);
|
||||||
}, { once: false });
|
}, { once: false });
|
||||||
|
|
||||||
this.bridge.addCommandListener('llm/chat/completions/done', data => {
|
this.bridge.addCommandListener('llm/chat/completions/done', data => {
|
||||||
this.onDone();
|
this.onDone();
|
||||||
chunkHandler();
|
chunkHandler();
|
||||||
|
|
||||||
@ -140,6 +151,7 @@ export class TaskLoop {
|
|||||||
// 如果超出了 tabStorage.settings.contextLength, 则删除最早的消息
|
// 如果超出了 tabStorage.settings.contextLength, 则删除最早的消息
|
||||||
const loadMessages = tabStorage.messages.slice(- tabStorage.settings.contextLength);
|
const loadMessages = tabStorage.messages.slice(- tabStorage.settings.contextLength);
|
||||||
userMessages.push(...loadMessages);
|
userMessages.push(...loadMessages);
|
||||||
|
|
||||||
// 增加一个id用于锁定状态
|
// 增加一个id用于锁定状态
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
|
|
||||||
@ -188,7 +200,14 @@ export class TaskLoop {
|
|||||||
*/
|
*/
|
||||||
public async start(tabStorage: ChatStorage, userMessage: string) {
|
public async start(tabStorage: ChatStorage, userMessage: string) {
|
||||||
// 添加目前的消息
|
// 添加目前的消息
|
||||||
tabStorage.messages.push({ role: 'user', content: userMessage });
|
tabStorage.messages.push({
|
||||||
|
role: 'user',
|
||||||
|
content: userMessage,
|
||||||
|
extraInfo: {
|
||||||
|
created: Date.now(),
|
||||||
|
serverName: llms[llmManager.currentModelIndex].id || 'unknown'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
for (let i = 0; i < this.taskOptions.maxEpochs; ++ i) {
|
for (let i = 0; i < this.taskOptions.maxEpochs; ++ i) {
|
||||||
|
|
||||||
@ -197,6 +216,7 @@ export class TaskLoop {
|
|||||||
// 初始累计清空
|
// 初始累计清空
|
||||||
this.streamingContent.value = '';
|
this.streamingContent.value = '';
|
||||||
this.streamingToolCalls.value = [];
|
this.streamingToolCalls.value = [];
|
||||||
|
this.completionUsage = undefined;
|
||||||
|
|
||||||
// 构造 chatData
|
// 构造 chatData
|
||||||
const chatData = this.makeChatData(tabStorage);
|
const chatData = this.makeChatData(tabStorage);
|
||||||
@ -212,7 +232,11 @@ export class TaskLoop {
|
|||||||
tabStorage.messages.push({
|
tabStorage.messages.push({
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: this.streamingContent.value || '',
|
content: this.streamingContent.value || '',
|
||||||
tool_calls: this.streamingToolCalls.value
|
tool_calls: this.streamingToolCalls.value,
|
||||||
|
extraInfo: {
|
||||||
|
created: Date.now(),
|
||||||
|
serverName: llms[llmManager.currentModelIndex].id || 'unknown'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const toolCallResult = await this.handleToolCalls(this.streamingToolCalls.value);
|
const toolCallResult = await this.handleToolCalls(this.streamingToolCalls.value);
|
||||||
@ -222,14 +246,24 @@ export class TaskLoop {
|
|||||||
tabStorage.messages.push({
|
tabStorage.messages.push({
|
||||||
role: 'tool',
|
role: 'tool',
|
||||||
tool_call_id: toolCall.id || toolCall.function.name,
|
tool_call_id: toolCall.id || toolCall.function.name,
|
||||||
content: toolCallResult
|
content: toolCallResult,
|
||||||
|
extraInfo: {
|
||||||
|
created: Date.now(),
|
||||||
|
serverName: llms[llmManager.currentModelIndex].id || 'unknown',
|
||||||
|
usage: this.completionUsage
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (this.streamingContent.value) {
|
} else if (this.streamingContent.value) {
|
||||||
tabStorage.messages.push({
|
tabStorage.messages.push({
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: this.streamingContent.value
|
content: this.streamingContent.value,
|
||||||
|
extraInfo: {
|
||||||
|
created: Date.now(),
|
||||||
|
serverName: llms[llmManager.currentModelIndex].id || 'unknown',
|
||||||
|
usage: this.completionUsage
|
||||||
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
37
renderer/src/components/main-panel/chat/usage.ts
Normal file
37
renderer/src/components/main-panel/chat/usage.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { IExtraInfo } from "./chat";
|
||||||
|
|
||||||
|
export interface UsageStatistic {
|
||||||
|
input: number;
|
||||||
|
output: number;
|
||||||
|
total: number;
|
||||||
|
cacheHitRatio: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function makeUsageStatistic(extraInfo: IExtraInfo): UsageStatistic | undefined {
|
||||||
|
if (extraInfo.serverName === 'unknown' || extraInfo.usage === undefined || extraInfo.usage === null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usage = extraInfo.usage;
|
||||||
|
|
||||||
|
switch (extraInfo.serverName) {
|
||||||
|
case 'deepseek':
|
||||||
|
return {
|
||||||
|
input: usage.prompt_tokens,
|
||||||
|
output: usage.completion_tokens,
|
||||||
|
total: usage.prompt_tokens + usage.completion_tokens,
|
||||||
|
cacheHitRatio: Math.ceil(usage.prompt_tokens_details?.cached_tokens || 0 / usage.prompt_tokens * 1000) / 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'openai':
|
||||||
|
return {
|
||||||
|
// TODO: 完成其他的数值统计
|
||||||
|
input: usage?.prompt_tokens,
|
||||||
|
output: usage?.completion_tokens,
|
||||||
|
total: usage.prompt_tokens + usage.completion_tokens,
|
||||||
|
cacheHitRatio: Math.ceil(usage.prompt_tokens_details?.cached_tokens || 0 / usage.prompt_tokens * 1000) / 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
@ -27,6 +27,8 @@ async function connectHandler(option: MCPOptions, webview: PostMessageble) {
|
|||||||
// 比如 error: Failed to spawn: `server.py`
|
// 比如 error: Failed to spawn: `server.py`
|
||||||
// Caused by: No such file or directory (os error 2)
|
// Caused by: No such file or directory (os error 2)
|
||||||
|
|
||||||
|
console.log('error', error);
|
||||||
|
|
||||||
const connectResult = {
|
const connectResult = {
|
||||||
code: 500,
|
code: 500,
|
||||||
msg: (error as any).toString()
|
msg: (error as any).toString()
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"tabs": [],
|
|
||||||
"currentIndex": -1
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"currentIndex": 1,
|
"currentIndex": 2,
|
||||||
"tabs": [
|
"tabs": [
|
||||||
{
|
{
|
||||||
"name": "资源",
|
"name": "资源",
|
||||||
@ -18,6 +18,87 @@
|
|||||||
"storage": {
|
"storage": {
|
||||||
"currentPromptName": "translate"
|
"currentPromptName": "translate"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "交互测试",
|
||||||
|
"icon": "icon-robot",
|
||||||
|
"type": "blank",
|
||||||
|
"componentIndex": 3,
|
||||||
|
"storage": {
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "你好,请问什么是",
|
||||||
|
"extraInfo": {
|
||||||
|
"created": 1744876735890,
|
||||||
|
"serverName": "deepseek"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "你好!请问你是想问什么呢?可以具体一点吗?比如:\n\n- 什么是人工智能?\n- 什么是区块链?\n- 什么是量子计算?\n- 或者其他任何你想了解的概念或问题?\n\n告诉我你的具体需求,我会尽力解答!",
|
||||||
|
"extraInfo": {
|
||||||
|
"created": 1744876742266,
|
||||||
|
"serverName": "deepseek",
|
||||||
|
"usage": {
|
||||||
|
"prompt_tokens": 453,
|
||||||
|
"completion_tokens": 49,
|
||||||
|
"total_tokens": 502,
|
||||||
|
"prompt_tokens_details": {
|
||||||
|
"cached_tokens": 448
|
||||||
|
},
|
||||||
|
"prompt_cache_hit_tokens": 448,
|
||||||
|
"prompt_cache_miss_tokens": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "你的名字是",
|
||||||
|
"extraInfo": {
|
||||||
|
"created": 1744878380791,
|
||||||
|
"serverName": "openai"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "错误: OpenAI API error: 404 404 page not found",
|
||||||
|
"extraInfo": {
|
||||||
|
"created": 1744878381940,
|
||||||
|
"serverName": "openai"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"modelIndex": 0,
|
||||||
|
"enableTools": [
|
||||||
|
{
|
||||||
|
"name": "add",
|
||||||
|
"description": "对两个数字进行实数域的加法",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "multiply",
|
||||||
|
"description": "对两个数字进行实数域的乘法运算",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "is_even",
|
||||||
|
"description": "判断一个整数是否为偶数",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "capitalize",
|
||||||
|
"description": "将字符串首字母大写",
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"enableWebSearch": false,
|
||||||
|
"temperature": 0.7,
|
||||||
|
"contextLength": 10,
|
||||||
|
"systemPrompt": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user