rootengine-core 0.5.0__py3-none-any.whl
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.
- rootengine_core/__init__.py +5 -0
- rootengine_core/constants/__init__.py +0 -0
- rootengine_core/constants/conversation.py +5 -0
- rootengine_core/constants/framework.py +17 -0
- rootengine_core/constants/tool.py +0 -0
- rootengine_core/conversation/__init__.py +1 -0
- rootengine_core/conversation/no_tool_conversation.py +106 -0
- rootengine_core/llm/__init__.py +2 -0
- rootengine_core/llm/llm.py +37 -0
- rootengine_core/llm/openai_adapter.py +235 -0
- rootengine_core/schema/source/conversation/no_tool_conversation.json +40 -0
- rootengine_core/schema/source/llm/llm_message.json +96 -0
- rootengine_core/schema/source/llm/llm_output.json +50 -0
- rootengine_core/schema/source/llm/tool_choice.json +39 -0
- rootengine_core/schema/source/reif_entry.json +70 -0
- rootengine_core/schema/source/tool/tool_call.json +55 -0
- rootengine_core/schema/source/tool/tool_func_map.json +15 -0
- rootengine_core/schema/source/tool/tool_registry.json +37 -0
- rootengine_core/schema/source/tool/tool_result.json +68 -0
- rootengine_core/schema_runtime/reif_schema.py +338 -0
- rootengine_core/tool/__init__.py +1 -0
- rootengine_core/tool/adapter.py +19 -0
- rootengine_core/tool/tool.py +141 -0
- rootengine_core/utils/__init__.py +0 -0
- rootengine_core/utils/generate_json_dict.py +291 -0
- rootengine_core/utils/helpers.py +43 -0
- rootengine_core/utils/path.py +20 -0
- rootengine_core/utils/registrar.py +55 -0
- rootengine_core/utils/reif_adapter.py +9 -0
- rootengine_core/utils/reif_func.py +149 -0
- rootengine_core/utils/time.py +9 -0
- rootengine_core-0.5.0.dist-info/METADATA +152 -0
- rootengine_core-0.5.0.dist-info/RECORD +36 -0
- rootengine_core-0.5.0.dist-info/WHEEL +5 -0
- rootengine_core-0.5.0.dist-info/licenses/LICENSE +21 -0
- rootengine_core-0.5.0.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
VERSION = {
|
|
2
|
+
"reif_version":"1.0",
|
|
3
|
+
"conversation":"0.1.0",
|
|
4
|
+
"tool_registry":"0.1.0",
|
|
5
|
+
"tool_call":"0.1.0",
|
|
6
|
+
"tool_results":"0.1.0",
|
|
7
|
+
"tool_record":"0.1.0",
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
REIF_CATEGORY = [
|
|
12
|
+
"agent_card",
|
|
13
|
+
"conversation",
|
|
14
|
+
"tool_registry",
|
|
15
|
+
"tool_record"
|
|
16
|
+
|
|
17
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .no_tool_conversation import NoToolConversation
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
from ..constants.conversation import CONVERSATION_ROLE
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from ..utils.reif_func import reif_create,reif_validate
|
|
5
|
+
from ..utils.time import get_iso_timestamp
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
from jsonschema import validate
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from ..schema_runtime.reif_schema import get_json
|
|
12
|
+
SCHEMA = get_json("conversation.no_tool_conversation")
|
|
13
|
+
|
|
14
|
+
class NoToolConversation:
|
|
15
|
+
def __init__(self, conversation_entry: dict = None):
|
|
16
|
+
# 如果未传自动创建新的
|
|
17
|
+
if conversation_entry is None:
|
|
18
|
+
self.create()
|
|
19
|
+
else:
|
|
20
|
+
self.entry = conversation_entry
|
|
21
|
+
|
|
22
|
+
self.messages = self.entry["reif_content"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create(self) -> NoToolConversation:
|
|
26
|
+
"""创建新会话"""
|
|
27
|
+
self.entry = reif_create({"category": "conversation"})
|
|
28
|
+
# 确保 reif_content 存在且为空列表
|
|
29
|
+
self.entry["reif_content"] = []
|
|
30
|
+
# 链接
|
|
31
|
+
self.messages = self.entry["reif_content"]
|
|
32
|
+
|
|
33
|
+
return self
|
|
34
|
+
|
|
35
|
+
def add(
|
|
36
|
+
self ,
|
|
37
|
+
role: str,
|
|
38
|
+
content: str = None,
|
|
39
|
+
created_at: str = None,
|
|
40
|
+
extra: dict = None,
|
|
41
|
+
) -> NoToolConversation :
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
向会话添加一条消息。
|
|
45
|
+
|
|
46
|
+
:param role: 消息角色,必须为 system/user/assistant/tool 之一。
|
|
47
|
+
:param content: 文本内容(对 system/user/assistant 必填,对 tool 可选)。
|
|
48
|
+
|
|
49
|
+
:param extra: 可选的扩展字典,任意附加信息。
|
|
50
|
+
:param created_at: 可选时间戳,若不提供则自动生成。
|
|
51
|
+
:return: self,支持链式调用。
|
|
52
|
+
"""
|
|
53
|
+
#检验角色
|
|
54
|
+
if role not in CONVERSATION_ROLE:
|
|
55
|
+
raise ValueError(f"未知角色: {role}")
|
|
56
|
+
|
|
57
|
+
# 生成时间戳
|
|
58
|
+
if created_at is None:
|
|
59
|
+
created_at = get_iso_timestamp()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# 构造消息字典
|
|
63
|
+
item = {
|
|
64
|
+
"role": role,
|
|
65
|
+
"content": content,
|
|
66
|
+
"created_at": created_at
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if extra:
|
|
70
|
+
item["extra"] = extra
|
|
71
|
+
|
|
72
|
+
self.messages.append(item)
|
|
73
|
+
return self
|
|
74
|
+
|
|
75
|
+
def delete(self, index: int = None):
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
:param index: 索引,若不填默认删除最后一个
|
|
79
|
+
:return:
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
if index is None:
|
|
83
|
+
self.messages.pop()
|
|
84
|
+
else:
|
|
85
|
+
self.messages.pop(index)
|
|
86
|
+
return self
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def load_entry(self,entry: dict) -> NoToolConversation :
|
|
91
|
+
"""加载整个 conversation 条目"""
|
|
92
|
+
self.entry = entry
|
|
93
|
+
self.messages = self.entry["reif_content"]
|
|
94
|
+
return self
|
|
95
|
+
def load_messages(self,messages: list) -> NoToolConversation :
|
|
96
|
+
self.messages = messages
|
|
97
|
+
self.entry["reif_content"] = self.messages
|
|
98
|
+
return self
|
|
99
|
+
|
|
100
|
+
def validate_schema(self) -> bool:
|
|
101
|
+
if self.reif_entry is None:
|
|
102
|
+
raise RuntimeError("无会话可校验")
|
|
103
|
+
reif_validate(self.entry)
|
|
104
|
+
validate(instance=self.messages, schema = SCHEMA)
|
|
105
|
+
return True
|
|
106
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Optional,Dict,List,Any
|
|
2
|
+
|
|
3
|
+
from abc import ABC,abstractmethod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseLLM(ABC):
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
|
|
11
|
+
def call(self,
|
|
12
|
+
messages:List[dict[str,Any]],
|
|
13
|
+
tool_registry:Optional[List[Dict[str, Any]]],
|
|
14
|
+
tool_choice: Optional[str],
|
|
15
|
+
**kwargs)\
|
|
16
|
+
-> Dict[str, Any]:
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
:param messages: 消息列表 参考 ../schema/source/llm/llm_message.json
|
|
20
|
+
:param tool_registry: 工具注册表 参考 ../schema/source/tool/tool_registry.json
|
|
21
|
+
:param tool_choice: 工具选择策略 参考 ../schema/source/llm/tool_choice.json
|
|
22
|
+
:param kwargs: 拓展任意字段
|
|
23
|
+
:return: 参考 ../schema/source/llm/llm_output.json
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Provider 适配器:框架格式 ↔ 各 Provider 格式
|
|
3
|
+
|
|
4
|
+
用法:
|
|
5
|
+
adapter = OpenAIAdapter(model="gpt-4", api_key="...")
|
|
6
|
+
openai_params = adapter.to_provider(messages, tool_registry, tool_choice)
|
|
7
|
+
# 调用 OpenAI API...
|
|
8
|
+
llm_output = adapter.from_provider(openai_response)
|
|
9
|
+
"""
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import Any, Dict, List, Optional, Union
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
+
# 基类
|
|
16
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
class BaseLLMAdapter(ABC):
|
|
19
|
+
"""LLM 适配器基类,所有 Provider 适配器需继承此类"""
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def to_provider(
|
|
23
|
+
self,
|
|
24
|
+
messages: List[Dict[str, Any]],
|
|
25
|
+
tool_registry: Optional[Dict[str, Any]] = None,
|
|
26
|
+
tool_choice: Optional[Union[str, Dict]] = None,
|
|
27
|
+
**kwargs
|
|
28
|
+
) -> Dict[str, Any]:
|
|
29
|
+
"""
|
|
30
|
+
框架格式 → Provider 格式
|
|
31
|
+
|
|
32
|
+
:param messages: 框架消息列表 (llm_message[])
|
|
33
|
+
:param tool_registry: 框架工具注册表
|
|
34
|
+
:param tool_choice: 工具选择策略
|
|
35
|
+
:return: Provider API 调用参数
|
|
36
|
+
"""
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def from_provider(self, response: Dict[str, Any]) -> Dict[str, Any]:
|
|
41
|
+
"""
|
|
42
|
+
Provider 响应格式 → 框架格式 (llm_output)
|
|
43
|
+
|
|
44
|
+
:param response: Provider API 返回的原始响应
|
|
45
|
+
:return: 框架 llm_output 格式
|
|
46
|
+
"""
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def message_to_frame(self, message: Dict[str, Any]) -> Dict[str, Any]:
|
|
51
|
+
"""
|
|
52
|
+
单条 Provider 消息 → 框架格式 (llm_message)
|
|
53
|
+
|
|
54
|
+
用于把 Provider 返回的消息转成框架格式后再存入 messages 列表
|
|
55
|
+
|
|
56
|
+
:param message: Provider 格式的单条消息
|
|
57
|
+
:return: 框架 llm_message 格式
|
|
58
|
+
"""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
63
|
+
# OpenAI 适配器
|
|
64
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
class OpenAIAdapter(BaseLLMAdapter):
|
|
67
|
+
"""OpenAI 兼容 API 适配器"""
|
|
68
|
+
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
model: str = "gpt-4",
|
|
72
|
+
**config
|
|
73
|
+
):
|
|
74
|
+
"""
|
|
75
|
+
:param model: 模型名称
|
|
76
|
+
:param config: 其他 OpenAI API 配置(temperature, timeout 等)
|
|
77
|
+
"""
|
|
78
|
+
self.model = model
|
|
79
|
+
self.config = config
|
|
80
|
+
|
|
81
|
+
def to_provider(
|
|
82
|
+
self,
|
|
83
|
+
messages: List[Dict[str, Any]],
|
|
84
|
+
tool_registry: Optional[Dict[str, Any]] = None,
|
|
85
|
+
tool_choice: Optional[Union[str, Dict]] = None,
|
|
86
|
+
**kwargs
|
|
87
|
+
) -> Dict[str, Any]:
|
|
88
|
+
result = {
|
|
89
|
+
"model": self.model,
|
|
90
|
+
"messages": self._convert_messages(messages),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if tool_registry:
|
|
94
|
+
result["tools"] = self._convert_tool_registry(tool_registry)
|
|
95
|
+
|
|
96
|
+
if tool_choice is not None:
|
|
97
|
+
result["tool_choice"] = self._convert_tool_choice(tool_choice)
|
|
98
|
+
|
|
99
|
+
result.update(self.config)
|
|
100
|
+
result.update(kwargs)
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
def from_provider(self, response: Dict[str, Any]) -> Dict[str, Any]:
|
|
104
|
+
content = response.get("content")
|
|
105
|
+
tool_calls = response.get("tool_calls")
|
|
106
|
+
|
|
107
|
+
if content is None and not tool_calls:
|
|
108
|
+
llm_content = None
|
|
109
|
+
else:
|
|
110
|
+
llm_content = content
|
|
111
|
+
|
|
112
|
+
llm_tool_calls = None
|
|
113
|
+
if tool_calls:
|
|
114
|
+
llm_tool_calls = self._convert_tool_calls_from_openai(tool_calls)
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
"content": llm_content,
|
|
118
|
+
"tool_calls": llm_tool_calls,
|
|
119
|
+
"usage": self._normalize_usage(response.get("usage")),
|
|
120
|
+
"created_at": response.get("created") or response.get("created_at"),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
def message_to_frame(self, message: Dict[str, Any]) -> Dict[str, Any]:
|
|
124
|
+
role = message["role"]
|
|
125
|
+
frame_msg = {
|
|
126
|
+
"role": role,
|
|
127
|
+
"created_at": message.get("created_at") or message.get("created"),
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if role == "tool":
|
|
131
|
+
frame_msg["tool_call_id"] = message["tool_call_id"]
|
|
132
|
+
frame_msg["content"] = {
|
|
133
|
+
"call_id": message["tool_call_id"],
|
|
134
|
+
"type": "function",
|
|
135
|
+
"function": {
|
|
136
|
+
"result_content": message["content"],
|
|
137
|
+
"status": "success",
|
|
138
|
+
},
|
|
139
|
+
"created_at": frame_msg["created_at"],
|
|
140
|
+
}
|
|
141
|
+
else:
|
|
142
|
+
frame_msg["content"] = message.get("content")
|
|
143
|
+
|
|
144
|
+
if role == "assistant" and message.get("tool_calls"):
|
|
145
|
+
frame_msg["tool_calls"] = self._convert_tool_calls_from_openai(message["tool_calls"])
|
|
146
|
+
|
|
147
|
+
return frame_msg
|
|
148
|
+
|
|
149
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
150
|
+
# 内部转换方法
|
|
151
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
def _convert_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
154
|
+
"""框架消息列表 → OpenAI 消息列表"""
|
|
155
|
+
openai_messages = []
|
|
156
|
+
for msg in messages:
|
|
157
|
+
role = msg["role"]
|
|
158
|
+
openai_msg = {"role": role}
|
|
159
|
+
|
|
160
|
+
content = msg.get("content")
|
|
161
|
+
if role == "tool":
|
|
162
|
+
if isinstance(content, dict):
|
|
163
|
+
openai_msg["content"] = content.get("result_content", "")
|
|
164
|
+
else:
|
|
165
|
+
openai_msg["content"] = content or ""
|
|
166
|
+
else:
|
|
167
|
+
openai_msg["content"] = content
|
|
168
|
+
|
|
169
|
+
if role == "assistant" and msg.get("tool_calls"):
|
|
170
|
+
openai_msg["tool_calls"] = self._convert_tool_calls_to_openai(msg["tool_calls"])
|
|
171
|
+
|
|
172
|
+
openai_messages.append(openai_msg)
|
|
173
|
+
return openai_messages
|
|
174
|
+
|
|
175
|
+
def _convert_tool_calls_to_openai(self, tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
176
|
+
"""框架 tool_calls → OpenAI tool_calls"""
|
|
177
|
+
return [
|
|
178
|
+
{
|
|
179
|
+
"id": call["id"],
|
|
180
|
+
"type": call["type"],
|
|
181
|
+
"function": {
|
|
182
|
+
"name": call["function"]["registry_id"],
|
|
183
|
+
"arguments": call["function"]["arguments"],
|
|
184
|
+
},
|
|
185
|
+
}
|
|
186
|
+
for call in tool_calls
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
def _convert_tool_calls_from_openai(self, tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
190
|
+
"""OpenAI tool_calls → 框架 tool_calls"""
|
|
191
|
+
from ..utils.time import get_iso_timestamp
|
|
192
|
+
created_at = get_iso_timestamp()
|
|
193
|
+
return [
|
|
194
|
+
{
|
|
195
|
+
"id": call["id"],
|
|
196
|
+
"type": call["type"],
|
|
197
|
+
"function": {
|
|
198
|
+
"registry_id": call["function"]["name"],
|
|
199
|
+
"arguments": call["function"]["arguments"],
|
|
200
|
+
},
|
|
201
|
+
"created_at": created_at,
|
|
202
|
+
}
|
|
203
|
+
for call in tool_calls
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
def _convert_tool_registry(self, tool_registry: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
207
|
+
"""框架工具注册表 → OpenAI tools"""
|
|
208
|
+
openai_tools = []
|
|
209
|
+
for registry_id, tool_info in tool_registry.items():
|
|
210
|
+
func_info = tool_info.get("function", {})
|
|
211
|
+
openai_tools.append({
|
|
212
|
+
"type": "function",
|
|
213
|
+
"function": {
|
|
214
|
+
"name": registry_id,
|
|
215
|
+
"description": func_info.get("description", ""),
|
|
216
|
+
"parameters": func_info.get("parameters", {"type": "object", "properties": {}}),
|
|
217
|
+
},
|
|
218
|
+
})
|
|
219
|
+
return openai_tools
|
|
220
|
+
|
|
221
|
+
def _convert_tool_choice(self, tool_choice: Union[str, Dict]) -> Union[str, Dict]:
|
|
222
|
+
"""工具选择策略转换"""
|
|
223
|
+
if isinstance(tool_choice, str):
|
|
224
|
+
return tool_choice
|
|
225
|
+
return tool_choice
|
|
226
|
+
|
|
227
|
+
def _normalize_usage(self, usage: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
|
|
228
|
+
"""标准化 usage"""
|
|
229
|
+
if usage is None:
|
|
230
|
+
return None
|
|
231
|
+
return {
|
|
232
|
+
"prompt_tokens": usage.get("prompt_tokens", 0),
|
|
233
|
+
"completion_tokens": usage.get("completion_tokens", 0),
|
|
234
|
+
"total_tokens": usage.get("total_tokens", 0),
|
|
235
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "reif_content_base_conversation",
|
|
4
|
+
"description": "基础对话消息列表(无工具字段)",
|
|
5
|
+
"type": "array",
|
|
6
|
+
"items": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"role": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"enum": [
|
|
12
|
+
"system",
|
|
13
|
+
"user",
|
|
14
|
+
"assistant"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"content": {
|
|
18
|
+
"type": [
|
|
19
|
+
"string",
|
|
20
|
+
"null"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"created_at": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"format": "date-time"
|
|
26
|
+
},
|
|
27
|
+
"extra": {
|
|
28
|
+
"type": [
|
|
29
|
+
"object",
|
|
30
|
+
"null"
|
|
31
|
+
],
|
|
32
|
+
"additionalProperties": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"required": [
|
|
36
|
+
"role",
|
|
37
|
+
"created_at"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "llm_message",
|
|
4
|
+
"description": "LLM 对话消息单条格式,与 OpenAI 格式解耦",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"role": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"enum": ["system", "user", "assistant", "tool"],
|
|
10
|
+
"description": "消息角色"
|
|
11
|
+
},
|
|
12
|
+
"content": {
|
|
13
|
+
"description": "消息内容",
|
|
14
|
+
"oneOf": [
|
|
15
|
+
{
|
|
16
|
+
"type": "null",
|
|
17
|
+
"description": "assistant 无文字内容时(如纯工具调用)"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "system/user/assistant 普通文字内容"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "object",
|
|
25
|
+
"description": "tool 角色时为 tool_result 对象"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"tool_calls": {
|
|
30
|
+
"type": "array",
|
|
31
|
+
"description": "LLM 工具调用列表,仅 assistant 消息可能包含",
|
|
32
|
+
"items": {
|
|
33
|
+
"$ref": "../tool/tool_call.json"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"tool_call_id": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"pattern": "^[0-9a-fA-F]{32}$",
|
|
39
|
+
"description": "tool 角色必填,关联到 assistant 消息 tool_calls 中对应 call 的 id"
|
|
40
|
+
},
|
|
41
|
+
"created_at": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"format": "date-time",
|
|
44
|
+
"description": "创建时间 ISO 8601"
|
|
45
|
+
},
|
|
46
|
+
"extra": {
|
|
47
|
+
"type": ["object", "null"],
|
|
48
|
+
"additionalProperties": true,
|
|
49
|
+
"description": "扩展数据"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"required": ["role", "created_at"],
|
|
53
|
+
"allOf": [
|
|
54
|
+
{
|
|
55
|
+
"if": {
|
|
56
|
+
"properties": {
|
|
57
|
+
"role": {
|
|
58
|
+
"const": "tool"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"then": {
|
|
63
|
+
"properties": {
|
|
64
|
+
"content": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"description": "tool 角色的 content 必须为 tool_result 对象"
|
|
67
|
+
},
|
|
68
|
+
"tool_call_id": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"pattern": "^[0-9a-fA-F]{32}$"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"required": ["tool_call_id"]
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"if": {
|
|
78
|
+
"properties": {
|
|
79
|
+
"role": {
|
|
80
|
+
"const": "assistant"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"then": {
|
|
85
|
+
"properties": {
|
|
86
|
+
"tool_calls": {
|
|
87
|
+
"type": "array",
|
|
88
|
+
"items": {
|
|
89
|
+
"$ref": "tool/tool_call.json"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "llm_output",
|
|
4
|
+
"description": "LLM 单次调用的返回格式",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"content": {
|
|
8
|
+
"description": "LLM 回复的文字内容,无文字时为 null(纯工具调用场景)",
|
|
9
|
+
"oneOf": [
|
|
10
|
+
{ "type": "null" },
|
|
11
|
+
{ "type": "string" }
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"tool_calls": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"description": "LLM 发起的工具调用列表,无工具调用时为 null",
|
|
17
|
+
"items": {
|
|
18
|
+
"$ref": "../tool/tool_call.json"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"usage": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"description": "Token 用量统计",
|
|
24
|
+
"properties": {
|
|
25
|
+
"prompt_tokens": {
|
|
26
|
+
"type": "integer",
|
|
27
|
+
"description": "输入 prompt 消耗的 token 数"
|
|
28
|
+
},
|
|
29
|
+
"completion_tokens": {
|
|
30
|
+
"type": "integer",
|
|
31
|
+
"description": "生成回复消耗的 token 数"
|
|
32
|
+
},
|
|
33
|
+
"total_tokens": {
|
|
34
|
+
"type": "integer",
|
|
35
|
+
"description": "总 token 数"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"created_at": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"format": "date-time",
|
|
42
|
+
"description": "LLM 返回时间,ISO 8601 格式"
|
|
43
|
+
},
|
|
44
|
+
"extra": {
|
|
45
|
+
"type": ["object", "null"],
|
|
46
|
+
"additionalProperties": true,
|
|
47
|
+
"description": "扩展数据"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": " Tool Choice Schema(仿openai,其中function.name 改成了 func.registry_id)",
|
|
4
|
+
"description": "Controls how the model uses tools. Can be a simple string mode or an object specifying a forced function call.",
|
|
5
|
+
"type": ["string", "object"],
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"title": "Simple Mode",
|
|
9
|
+
"type": "string",
|
|
10
|
+
"enum": ["auto", "none", "required"],
|
|
11
|
+
"description": "Auto: model decides; None: no tool call; Required: model must call at least one tool."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"title": "Specific Function Call",
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"type": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"const": "function",
|
|
20
|
+
"description": "Must be 'function'."
|
|
21
|
+
},
|
|
22
|
+
"function": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"properties": {
|
|
25
|
+
"registry_id": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"format": "uuid",
|
|
28
|
+
"description": "tool 在注册表的 registry_id "
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"required": ["registry_id"],
|
|
32
|
+
"additionalProperties": false
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"required": ["type", "function"],
|
|
36
|
+
"additionalProperties": false
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|