tketool.llm 1.3.4__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.
- tketool_llm-1.3.4/PKG-INFO +99 -0
- tketool_llm-1.3.4/README.md +71 -0
- tketool_llm-1.3.4/pyproject.toml +46 -0
- tketool_llm-1.3.4/setup.cfg +4 -0
- tketool_llm-1.3.4/src/tketool/llm/__init__.py +7 -0
- tketool_llm-1.3.4/src/tketool/lmc/__init__.py +5 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/__init__.py +5 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/__init__.py +4 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/demo_tools.py +35 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/function_handler.py +224 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/interfaces.py +91 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/registry.py +76 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/simple_code.py +73 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/mcp_tools/tool_types.py +122 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/__init__.py +2 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/interfaces.py +71 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/local_memory.py +160 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/memory_imps/__init__.py +49 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/memory_imps/hindsight_like.py +532 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/memory_imps/ml2_indexes.py +25 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/__init__.py +43 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_bank_storage.py +25 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_entity_index.py +61 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_sparse_index.py +32 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_temporal_index.py +28 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/in_memory_vector_index.py +34 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_bank_storage.py +90 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_entity_index.py +73 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_sparse_index.py +41 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_temporal_index.py +35 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/storage_extensions/ml2_vector_index.py +44 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/memory/types.py +239 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/__init__.py +13 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/observer.py +322 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/redactor.py +68 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/report.py +67 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/sink.py +57 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/observer/types.py +74 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/__init__.py +4 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/base.py +32 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/__init__.py +4 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/base.py +492 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/main.py +674 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/plan_main.py +368 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/chains/tool_call.py +461 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/graph.py +19 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/__init__.py +35 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/common.py +47 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/main_chain_memory.py +82 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/memory_kit/tool_call_memory.py +214 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/node_types.py +12 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/__init__.py +21 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/common.py +5 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/decision.py +25 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/info_summary.py +15 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/main_chain/__init__.py +3 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/main_chain/experience.py +87 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/main_chain/finalize.py +83 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/__init__.py +9 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_build.py +125 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_check.py +60 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_select.py +56 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_synthesize.py +101 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_types.py +60 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/plan_update.py +71 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/plan_main_chain/subtask_run.py +77 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/task_identify.py +133 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/__init__.py +5 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/parameter_generate.py +134 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_call.py +109 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_decision.py +128 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_experience_write.py +81 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/tool_call_chain/tool_result_verify.py +99 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/nodes/verify.py +135 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/prompting.py +126 -0
- tketool_llm-1.3.4/src/tketool/lmc/agent_framework/scheduler2/types.py +194 -0
- tketool_llm-1.3.4/src/tketool/lmc/embeddings.py +17 -0
- tketool_llm-1.3.4/src/tketool/lmc/llms/__init__.py +1 -0
- tketool_llm-1.3.4/src/tketool/lmc/llms/embeddings.py +215 -0
- tketool_llm-1.3.4/src/tketool/lmc/llms/openai.py +326 -0
- tketool_llm-1.3.4/src/tketool/lmc/lmc_linked.py +604 -0
- tketool_llm-1.3.4/src/tketool/lmc/lmc_linked_flow.py +7 -0
- tketool_llm-1.3.4/src/tketool/lmc/lmc_prompt_invoker.py +426 -0
- tketool_llm-1.3.4/src/tketool/lmc/models.py +97 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/__init__.py +0 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/prompt_controller.py +462 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/auto_repair.txt +38 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/context_compact.txt +41 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/context_resolve_reference.txt +42 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/decompose_task_plan.txt +71 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/plan_tool_use.txt +53 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/prepare_tool_call.txt +56 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/re_understand_task.txt +61 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/reason.txt +35 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/replan_task_plan.txt +66 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/summarize_user_need.txt +50 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/understand_task.txt +47 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/validate.txt +41 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agent_scheduler/validate_task_plan.txt +46 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_method_plan.txt +51 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_range.txt +34 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_recall.txt +25 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/memory_thinking_recall.txt +36 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/agents/rule_compress.txt +26 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/context_summary.txt +28 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/mcp_page_use.txt +33 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/mcp_step_summary.txt +39 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/mcps/mcp_summary.txt +41 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_decide.txt +55 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_experience_organize.txt +23 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_experience_summarize.txt +33 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_main_finalize.txt +33 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_plan_build.txt +42 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_plan_synthesize.txt +44 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_task_identify.txt +47 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_decision.txt +38 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_experience_write.txt +65 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_parameter_generate.txt +53 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_tool_result_verify.txt +48 -0
- tketool_llm-1.3.4/src/tketool/lmc/prompts/templates/scheduler2/scheduler2_verify.txt +41 -0
- tketool_llm-1.3.4/src/tketool/lmc_console_tool.py +24 -0
- tketool_llm-1.3.4/src/tketool.llm.egg-info/PKG-INFO +99 -0
- tketool_llm-1.3.4/src/tketool.llm.egg-info/SOURCES.txt +125 -0
- tketool_llm-1.3.4/src/tketool.llm.egg-info/dependency_links.txt +1 -0
- tketool_llm-1.3.4/src/tketool.llm.egg-info/entry_points.txt +2 -0
- tketool_llm-1.3.4/src/tketool.llm.egg-info/requires.txt +16 -0
- tketool_llm-1.3.4/src/tketool.llm.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tketool.llm
|
|
3
|
+
Version: 1.3.4
|
|
4
|
+
Summary: OpenAI-compatible LLM, structured prompt, scheduler, and memory APIs for tketool
|
|
5
|
+
Author-email: Ke <jiangke1207@icloud.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://pypi.org/project/tketool.llm/
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: tketool.core==1.3.4
|
|
16
|
+
Requires-Dist: tketool.ml==1.3.4
|
|
17
|
+
Requires-Dist: openai<4,>=3
|
|
18
|
+
Requires-Dist: httpx<1,>=0.27
|
|
19
|
+
Requires-Dist: langchain-core<1.7,>=1.6
|
|
20
|
+
Requires-Dist: pydantic<3,>=2.10
|
|
21
|
+
Provides-Extra: local-embeddings
|
|
22
|
+
Requires-Dist: torch<3,>=2.4; extra == "local-embeddings"
|
|
23
|
+
Requires-Dist: transformers<6,>=5; extra == "local-embeddings"
|
|
24
|
+
Provides-Extra: memory
|
|
25
|
+
Requires-Dist: hindsight-all<1,>=0.9; extra == "memory"
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest<9,>=8; extra == "test"
|
|
28
|
+
|
|
29
|
+
# tketool.llm
|
|
30
|
+
|
|
31
|
+
OpenAI-compatible large-model access, structured-output prompts, embeddings,
|
|
32
|
+
memory, tools, and the current scheduler.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install tketool.llm
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Chat Completions
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import os
|
|
42
|
+
|
|
43
|
+
from tketool.llm import OpenAI_Complete_Model
|
|
44
|
+
|
|
45
|
+
llm = OpenAI_Complete_Model(
|
|
46
|
+
model_name="gpt-4o-mini",
|
|
47
|
+
apitoken=os.environ["OPENAI_API_KEY"],
|
|
48
|
+
base_url="https://api.openai.com/v1",
|
|
49
|
+
call_dict={"temperature": 0.2},
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
text = llm("用三句话解释向量检索", return_detail=False)
|
|
53
|
+
print(text)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Responses API
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import os
|
|
60
|
+
|
|
61
|
+
from tketool.llm import OpenAI_Response_Model
|
|
62
|
+
|
|
63
|
+
llm = OpenAI_Response_Model(
|
|
64
|
+
model_name="gpt-5-mini",
|
|
65
|
+
apitoken=os.environ["OPENAI_API_KEY"],
|
|
66
|
+
base_url="https://api.openai.com/v1",
|
|
67
|
+
call_dict={"max_output_tokens": 300},
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
text, detail = llm("给出一个最小 RAG 流程", return_detail=True)
|
|
71
|
+
print(text)
|
|
72
|
+
print(detail)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Both transports accept a complete `messages` list and return the same detail
|
|
76
|
+
shape. OpenAI-compatible gateways are supported by changing `base_url` and
|
|
77
|
+
`model_name`.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
messages = [
|
|
81
|
+
{"role": "system", "content": "回答要简洁。"},
|
|
82
|
+
{"role": "user", "content": "什么是结构化输出?"},
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
answer = llm("", return_detail=False, messages=messages)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
New code should import from `tketool.llm`. The existing `tketool.lmc` path is
|
|
89
|
+
kept as a compatibility API during migration.
|
|
90
|
+
|
|
91
|
+
Local Hugging Face embeddings are optional:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install "tketool.llm[local-embeddings]"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The optional `memory` extra requires Python 3.11 or newer because its external
|
|
98
|
+
backend does. The legacy `agent`/`context` implementation was removed because
|
|
99
|
+
it depended on the retired scheduler; use `scheduler2` for current agent flows.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# tketool.llm
|
|
2
|
+
|
|
3
|
+
OpenAI-compatible large-model access, structured-output prompts, embeddings,
|
|
4
|
+
memory, tools, and the current scheduler.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install tketool.llm
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Chat Completions
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
import os
|
|
14
|
+
|
|
15
|
+
from tketool.llm import OpenAI_Complete_Model
|
|
16
|
+
|
|
17
|
+
llm = OpenAI_Complete_Model(
|
|
18
|
+
model_name="gpt-4o-mini",
|
|
19
|
+
apitoken=os.environ["OPENAI_API_KEY"],
|
|
20
|
+
base_url="https://api.openai.com/v1",
|
|
21
|
+
call_dict={"temperature": 0.2},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
text = llm("用三句话解释向量检索", return_detail=False)
|
|
25
|
+
print(text)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Responses API
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import os
|
|
32
|
+
|
|
33
|
+
from tketool.llm import OpenAI_Response_Model
|
|
34
|
+
|
|
35
|
+
llm = OpenAI_Response_Model(
|
|
36
|
+
model_name="gpt-5-mini",
|
|
37
|
+
apitoken=os.environ["OPENAI_API_KEY"],
|
|
38
|
+
base_url="https://api.openai.com/v1",
|
|
39
|
+
call_dict={"max_output_tokens": 300},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
text, detail = llm("给出一个最小 RAG 流程", return_detail=True)
|
|
43
|
+
print(text)
|
|
44
|
+
print(detail)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Both transports accept a complete `messages` list and return the same detail
|
|
48
|
+
shape. OpenAI-compatible gateways are supported by changing `base_url` and
|
|
49
|
+
`model_name`.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
messages = [
|
|
53
|
+
{"role": "system", "content": "回答要简洁。"},
|
|
54
|
+
{"role": "user", "content": "什么是结构化输出?"},
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
answer = llm("", return_detail=False, messages=messages)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
New code should import from `tketool.llm`. The existing `tketool.lmc` path is
|
|
61
|
+
kept as a compatibility API during migration.
|
|
62
|
+
|
|
63
|
+
Local Hugging Face embeddings are optional:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install "tketool.llm[local-embeddings]"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The optional `memory` extra requires Python 3.11 or newer because its external
|
|
70
|
+
backend does. The legacy `agent`/`context` implementation was removed because
|
|
71
|
+
it depended on the retired scheduler; use `scheduler2` for current agent flows.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tketool.llm"
|
|
7
|
+
version = "1.3.4"
|
|
8
|
+
description = "OpenAI-compatible LLM, structured prompt, scheduler, and memory APIs for tketool"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [{ name = "Ke", email = "jiangke1207@icloud.com" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"tketool.core==1.3.4",
|
|
15
|
+
"tketool.ml==1.3.4",
|
|
16
|
+
"openai>=3,<4",
|
|
17
|
+
"httpx>=0.27,<1",
|
|
18
|
+
"langchain-core>=1.6,<1.7",
|
|
19
|
+
"pydantic>=2.10,<3",
|
|
20
|
+
]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Operating System :: OS Independent",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
local-embeddings = ["torch>=2.4,<3", "transformers>=5,<6"]
|
|
31
|
+
memory = ["hindsight-all>=0.9,<1"]
|
|
32
|
+
test = ["pytest>=8,<9"]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
lmc = "tketool.lmc_console_tool:main"
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://pypi.org/project/tketool.llm/"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
where = ["src"]
|
|
42
|
+
include = ["tketool*"]
|
|
43
|
+
namespaces = true
|
|
44
|
+
|
|
45
|
+
[tool.setuptools.package-data]
|
|
46
|
+
"tketool.lmc.prompts" = ["templates/*/*.txt"]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tketool.lmc.agent_framework.mcp_tools import *
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@tool_definition(
|
|
7
|
+
name="calculate_revenue",
|
|
8
|
+
description="计算总收入:上午收入 + 下午收入。",
|
|
9
|
+
parameters=[
|
|
10
|
+
ToolParameter(name="morning_count", type="int", description="上午销售数量"),
|
|
11
|
+
ToolParameter(name="morning_price", type="float", description="上午单价"),
|
|
12
|
+
ToolParameter(name="afternoon_count", type="int", description="下午销售数量"),
|
|
13
|
+
ToolParameter(name="afternoon_price", type="float", description="下午单价"),
|
|
14
|
+
],
|
|
15
|
+
output_schema={"required": ["revenue", "formula"]},
|
|
16
|
+
)
|
|
17
|
+
def calculate_revenue(
|
|
18
|
+
morning_count: int,
|
|
19
|
+
morning_price: float,
|
|
20
|
+
afternoon_count: int,
|
|
21
|
+
afternoon_price: float,
|
|
22
|
+
) -> dict:
|
|
23
|
+
"""计算今日总收入。"""
|
|
24
|
+
revenue = morning_count * morning_price + afternoon_count * afternoon_price
|
|
25
|
+
formula = (
|
|
26
|
+
f"{morning_count} x {morning_price:g} + "
|
|
27
|
+
f"{afternoon_count} x {afternoon_price:g} = {revenue:g}"
|
|
28
|
+
)
|
|
29
|
+
return {"revenue": revenue, "formula": formula}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def build_demo_tool_registry() -> InMemoryToolRegistry:
|
|
33
|
+
tools = InMemoryToolRegistry()
|
|
34
|
+
tools.register(FunctionToolHandler(calculate_revenue))
|
|
35
|
+
return tools
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from inspect import Signature, signature
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from tketool.lmc.agent_framework.mcp_tools.interfaces import ToolHandler
|
|
8
|
+
from tketool.lmc.agent_framework.mcp_tools.tool_types import (
|
|
9
|
+
ToolCall,
|
|
10
|
+
ToolDefinition,
|
|
11
|
+
ToolParameter,
|
|
12
|
+
ToolResult,
|
|
13
|
+
ToolResultStatus,
|
|
14
|
+
)
|
|
15
|
+
from tketool.lmc.agent_framework.observer import FrameworkObserver
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class FunctionToolHandler(ToolHandler):
|
|
19
|
+
"""把普通 Python 函数适配为 ToolHandler。"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, func: Callable, definition: ToolDefinition | None = None):
|
|
22
|
+
self.func = func
|
|
23
|
+
self.definition = definition or self._definition_from_func(func)
|
|
24
|
+
|
|
25
|
+
def before(self, call: ToolCall) -> ToolCall:
|
|
26
|
+
"""执行前补齐默认参数并校验必填参数。"""
|
|
27
|
+
arguments = dict(call.arguments)
|
|
28
|
+
missing = []
|
|
29
|
+
for parameter in self.definition.parameters:
|
|
30
|
+
if parameter.name not in arguments:
|
|
31
|
+
if parameter.required:
|
|
32
|
+
missing.append(parameter.name)
|
|
33
|
+
else:
|
|
34
|
+
arguments[parameter.name] = parameter.default
|
|
35
|
+
if missing:
|
|
36
|
+
raise ValueError(f"缺少必填参数:{', '.join(missing)}")
|
|
37
|
+
call.arguments = arguments
|
|
38
|
+
return call
|
|
39
|
+
|
|
40
|
+
def execute(self, call: ToolCall) -> ToolResult:
|
|
41
|
+
"""执行函数并把异常转换为标准 ToolResult。"""
|
|
42
|
+
try:
|
|
43
|
+
content = self.func(**call.arguments)
|
|
44
|
+
except Exception as exc: # noqa: BLE001
|
|
45
|
+
return ToolResult(
|
|
46
|
+
status=ToolResultStatus.FATAL_ERROR,
|
|
47
|
+
error=str(exc),
|
|
48
|
+
retryable=False,
|
|
49
|
+
metadata={"tool_name": self.definition.name},
|
|
50
|
+
)
|
|
51
|
+
return ToolResult(
|
|
52
|
+
status=ToolResultStatus.SUCCESS,
|
|
53
|
+
content=content,
|
|
54
|
+
metadata={"tool_name": self.definition.name},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def after(self, call: ToolCall, result: ToolResult) -> ToolResult:
|
|
58
|
+
"""执行后补充调用信息。"""
|
|
59
|
+
result.metadata = {
|
|
60
|
+
**result.metadata,
|
|
61
|
+
"call_id": call.call_id,
|
|
62
|
+
"task_id": call.context.task_id,
|
|
63
|
+
"step_id": call.context.step_id,
|
|
64
|
+
}
|
|
65
|
+
return result
|
|
66
|
+
|
|
67
|
+
def validate(self, call: ToolCall, result: ToolResult) -> ToolResult:
|
|
68
|
+
"""校验输出是否满足 output_schema 中的 required 字段要求。"""
|
|
69
|
+
if result.status != ToolResultStatus.SUCCESS:
|
|
70
|
+
return result
|
|
71
|
+
required_fields = (self.definition.output_schema or {}).get("required", [])
|
|
72
|
+
if required_fields:
|
|
73
|
+
if not isinstance(result.content, dict):
|
|
74
|
+
return ToolResult(
|
|
75
|
+
status=ToolResultStatus.VALIDATION_ERROR,
|
|
76
|
+
content=result.content,
|
|
77
|
+
error="工具输出不是 dict,无法校验 required 字段。",
|
|
78
|
+
retryable=False,
|
|
79
|
+
metadata=result.metadata,
|
|
80
|
+
)
|
|
81
|
+
missing = [field for field in required_fields if field not in result.content]
|
|
82
|
+
if missing:
|
|
83
|
+
return ToolResult(
|
|
84
|
+
status=ToolResultStatus.VALIDATION_ERROR,
|
|
85
|
+
content=result.content,
|
|
86
|
+
error=f"工具输出缺少字段:{', '.join(missing)}",
|
|
87
|
+
retryable=False,
|
|
88
|
+
metadata=result.metadata,
|
|
89
|
+
)
|
|
90
|
+
return result
|
|
91
|
+
|
|
92
|
+
def run(self, call: ToolCall, observer_object: FrameworkObserver | None = None) -> ToolResult:
|
|
93
|
+
"""按 before -> execute -> after -> validate 顺序执行工具。"""
|
|
94
|
+
span_id = None
|
|
95
|
+
if observer_object is not None:
|
|
96
|
+
span_id = observer_object.event_start(
|
|
97
|
+
"mcp.tool_call",
|
|
98
|
+
source="mcp",
|
|
99
|
+
phase="tool",
|
|
100
|
+
task_id=call.context.task_id,
|
|
101
|
+
node_id=call.context.step_id,
|
|
102
|
+
subject={"kind": "tool", "id": self.definition.name},
|
|
103
|
+
payload={
|
|
104
|
+
"tool_name": self.definition.name,
|
|
105
|
+
"call_id": call.call_id,
|
|
106
|
+
"arguments": dict(call.arguments),
|
|
107
|
+
"context_metadata": dict(call.context.metadata),
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
try:
|
|
111
|
+
prepared_call = self.before(call)
|
|
112
|
+
except Exception as exc: # noqa: BLE001
|
|
113
|
+
if observer_object is not None:
|
|
114
|
+
observer_object.error(
|
|
115
|
+
"mcp.tool_call_error",
|
|
116
|
+
exc,
|
|
117
|
+
source="mcp",
|
|
118
|
+
phase="tool",
|
|
119
|
+
task_id=call.context.task_id,
|
|
120
|
+
node_id=call.context.step_id,
|
|
121
|
+
payload={"tool_name": self.definition.name, "call_id": call.call_id, "stage": "before"},
|
|
122
|
+
)
|
|
123
|
+
if span_id:
|
|
124
|
+
observer_object.event_end(
|
|
125
|
+
span_id,
|
|
126
|
+
level="error",
|
|
127
|
+
status="failed",
|
|
128
|
+
payload={"tool_name": self.definition.name, "call_id": call.call_id, "stage": "before", "error": str(exc)},
|
|
129
|
+
)
|
|
130
|
+
return ToolResult(
|
|
131
|
+
status=ToolResultStatus.FATAL_ERROR,
|
|
132
|
+
error=str(exc),
|
|
133
|
+
retryable=False,
|
|
134
|
+
metadata={"tool_name": self.definition.name},
|
|
135
|
+
)
|
|
136
|
+
attempts = max(1, self.definition.retry_policy.max_attempts)
|
|
137
|
+
last_result: ToolResult | None = None
|
|
138
|
+
for attempt in range(1, attempts + 1):
|
|
139
|
+
result = self.execute(prepared_call)
|
|
140
|
+
result.metadata = {**result.metadata, "attempt": attempt}
|
|
141
|
+
result = self.after(prepared_call, result)
|
|
142
|
+
result = self.validate(prepared_call, result)
|
|
143
|
+
last_result = result
|
|
144
|
+
if observer_object is not None:
|
|
145
|
+
observer_object.record(
|
|
146
|
+
"mcp.tool_call_attempt",
|
|
147
|
+
source="mcp",
|
|
148
|
+
phase="tool",
|
|
149
|
+
level="error" if result.status != ToolResultStatus.SUCCESS else "info",
|
|
150
|
+
task_id=prepared_call.context.task_id,
|
|
151
|
+
node_id=prepared_call.context.step_id,
|
|
152
|
+
message=result.error or "",
|
|
153
|
+
payload={
|
|
154
|
+
"tool_name": self.definition.name,
|
|
155
|
+
"call_id": prepared_call.call_id,
|
|
156
|
+
"attempt": attempt,
|
|
157
|
+
"status": result.status,
|
|
158
|
+
"retryable": result.retryable,
|
|
159
|
+
},
|
|
160
|
+
)
|
|
161
|
+
# 只有 retry_policy 明确允许的状态才进入下一次尝试。
|
|
162
|
+
if result.status not in self.definition.retry_policy.retry_on:
|
|
163
|
+
if observer_object is not None:
|
|
164
|
+
observer_object.event_end(
|
|
165
|
+
span_id,
|
|
166
|
+
level="error" if result.status != ToolResultStatus.SUCCESS else "info",
|
|
167
|
+
status=result.status,
|
|
168
|
+
message=result.error or "",
|
|
169
|
+
payload={
|
|
170
|
+
"tool_name": self.definition.name,
|
|
171
|
+
"call_id": prepared_call.call_id,
|
|
172
|
+
"status": result.status,
|
|
173
|
+
"attempts": attempt,
|
|
174
|
+
"has_content": result.content is not None,
|
|
175
|
+
},
|
|
176
|
+
)
|
|
177
|
+
return result
|
|
178
|
+
assert last_result is not None
|
|
179
|
+
if observer_object is not None:
|
|
180
|
+
observer_object.event_end(
|
|
181
|
+
span_id,
|
|
182
|
+
level="error" if last_result.status != ToolResultStatus.SUCCESS else "info",
|
|
183
|
+
status=last_result.status,
|
|
184
|
+
message=last_result.error or "",
|
|
185
|
+
payload={
|
|
186
|
+
"tool_name": self.definition.name,
|
|
187
|
+
"call_id": prepared_call.call_id,
|
|
188
|
+
"status": last_result.status,
|
|
189
|
+
"attempts": attempts,
|
|
190
|
+
"has_content": last_result.content is not None,
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
return last_result
|
|
194
|
+
|
|
195
|
+
def _definition_from_func(self, func: Callable) -> ToolDefinition:
|
|
196
|
+
"""从函数签名生成工具定义,优先使用装饰器附加的定义。"""
|
|
197
|
+
if hasattr(func, "_tool_definition"):
|
|
198
|
+
return func._tool_definition
|
|
199
|
+
parameters = [
|
|
200
|
+
ToolParameter(
|
|
201
|
+
name=name,
|
|
202
|
+
type=self._type_name(param.annotation),
|
|
203
|
+
description=f"函数参数 {name}",
|
|
204
|
+
required=param.default is param.empty,
|
|
205
|
+
default=None if param.default is param.empty else param.default,
|
|
206
|
+
)
|
|
207
|
+
for name, param in signature(func).parameters.items()
|
|
208
|
+
]
|
|
209
|
+
return ToolDefinition(
|
|
210
|
+
name=func.__name__,
|
|
211
|
+
description=func.__doc__ or f"函数工具:{func.__name__}",
|
|
212
|
+
parameters=parameters,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
def _type_name(self, annotation: Any) -> str:
|
|
216
|
+
"""把 Python 类型注解转为简短字符串。"""
|
|
217
|
+
if annotation is Signature.empty:
|
|
218
|
+
return "Any"
|
|
219
|
+
return getattr(annotation, "__name__", str(annotation))
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def build_function_tool_handler(func: Callable) -> FunctionToolHandler:
|
|
223
|
+
"""从普通函数构造 FunctionToolHandler。"""
|
|
224
|
+
return FunctionToolHandler(func)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
|
|
4
|
+
from tketool.lmc.agent_framework.observer import FrameworkObserver
|
|
5
|
+
from tketool.lmc.agent_framework.mcp_tools.tool_types import (
|
|
6
|
+
ToolCall,
|
|
7
|
+
ToolDefinition,
|
|
8
|
+
ToolResult,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ToolHandler(ABC):
|
|
13
|
+
"""工具处理器接口,定义一次工具调用的完整生命周期。"""
|
|
14
|
+
|
|
15
|
+
definition: ToolDefinition
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def before(self, call: ToolCall) -> ToolCall:
|
|
19
|
+
"""执行前处理,例如参数补全、权限检查或日志记录。"""
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def execute(self, call: ToolCall) -> ToolResult:
|
|
24
|
+
"""执行实际工具逻辑。"""
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def after(self, call: ToolCall, result: ToolResult) -> ToolResult:
|
|
29
|
+
"""执行后处理,例如格式整理、指标记录或结果裁剪。"""
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def validate(self, call: ToolCall, result: ToolResult) -> ToolResult:
|
|
34
|
+
"""校验工具结果是否满足调度步骤要求。"""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
def run(self, call: ToolCall, observer_object: FrameworkObserver | None = None) -> ToolResult:
|
|
38
|
+
"""执行完整工具生命周期。"""
|
|
39
|
+
prepared_call = self.before(call)
|
|
40
|
+
result = self.execute(prepared_call)
|
|
41
|
+
result = self.after(prepared_call, result)
|
|
42
|
+
return self.validate(prepared_call, result)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ToolRegistry(ABC):
|
|
46
|
+
"""工具注册表接口,供调度器按名称查找可用工具。"""
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def mcplibcode(self) -> str:
|
|
51
|
+
"""当前注册工具名集合的稳定短 ID。"""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def register(self, handler: ToolHandler) -> None:
|
|
56
|
+
"""注册一个工具处理器。"""
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def get(self, name: str) -> ToolHandler:
|
|
61
|
+
"""根据工具名称获取处理器。"""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def list_definitions(self) -> list[ToolDefinition]:
|
|
66
|
+
"""列出当前可用工具定义。"""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
def search_definitions(self, query: str, top_k: int = 8) -> list[ToolDefinition]:
|
|
70
|
+
"""按查询文本检索候选工具定义;默认实现回退到全量列表截断。"""
|
|
71
|
+
return self.list_definitions()[:top_k]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def tool_definition(
|
|
75
|
+
name: str,
|
|
76
|
+
description: str,
|
|
77
|
+
parameters: list | None = None,
|
|
78
|
+
**kwargs,
|
|
79
|
+
) -> Callable:
|
|
80
|
+
"""为普通函数附加工具定义元数据。"""
|
|
81
|
+
|
|
82
|
+
def decorator(func: Callable) -> Callable:
|
|
83
|
+
func._tool_definition = ToolDefinition(
|
|
84
|
+
name=name,
|
|
85
|
+
description=description,
|
|
86
|
+
parameters=parameters or [],
|
|
87
|
+
**kwargs,
|
|
88
|
+
)
|
|
89
|
+
return func
|
|
90
|
+
|
|
91
|
+
return decorator
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
from tketool.lmc.agent_framework.mcp_tools.interfaces import ToolHandler, ToolRegistry
|
|
7
|
+
from tketool.lmc.agent_framework.mcp_tools.tool_types import ToolDefinition
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ToolRegistrationError(ValueError):
|
|
11
|
+
"""工具注册错误。"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ToolNotFoundError(KeyError):
|
|
15
|
+
"""工具不存在错误。"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class InMemoryToolRegistry(ToolRegistry):
|
|
19
|
+
"""内存版工具注册表,用于本地运行和单元测试。"""
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self._handlers: dict[str, ToolHandler] = {}
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def mcplibcode(self) -> str:
|
|
26
|
+
"""当前工具名集合的稳定短 ID。"""
|
|
27
|
+
tool_names = sorted(self._handlers)
|
|
28
|
+
raw = "\n".join(tool_names)
|
|
29
|
+
return hashlib.sha1(raw.encode("utf-8")).hexdigest()[:12]
|
|
30
|
+
|
|
31
|
+
def register(self, handler: ToolHandler) -> None:
|
|
32
|
+
"""注册一个工具处理器;重名工具默认拒绝。"""
|
|
33
|
+
name = handler.definition.name
|
|
34
|
+
if name in self._handlers:
|
|
35
|
+
raise ToolRegistrationError(f"工具已注册:{name}")
|
|
36
|
+
self._handlers[name] = handler
|
|
37
|
+
|
|
38
|
+
def get(self, name: str) -> ToolHandler:
|
|
39
|
+
"""根据名称获取工具处理器;不存在时抛出明确异常。"""
|
|
40
|
+
if name not in self._handlers:
|
|
41
|
+
raise ToolNotFoundError(f"工具不存在:{name}")
|
|
42
|
+
return self._handlers[name]
|
|
43
|
+
|
|
44
|
+
def list_definitions(self) -> list[ToolDefinition]:
|
|
45
|
+
"""按工具名稳定列出工具定义。"""
|
|
46
|
+
return [
|
|
47
|
+
self._handlers[name].definition
|
|
48
|
+
for name in sorted(self._handlers)
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
def search_definitions(self, query: str, top_k: int = 8) -> list[ToolDefinition]:
|
|
52
|
+
"""用轻量关键词打分检索工具定义。"""
|
|
53
|
+
definitions = self.list_definitions()
|
|
54
|
+
query_terms = _tokenize_tool_text(query)
|
|
55
|
+
if not query_terms:
|
|
56
|
+
return definitions[:top_k]
|
|
57
|
+
scored = []
|
|
58
|
+
for definition in definitions:
|
|
59
|
+
text = " ".join(
|
|
60
|
+
[
|
|
61
|
+
definition.name,
|
|
62
|
+
definition.description,
|
|
63
|
+
" ".join(parameter.name for parameter in definition.parameters),
|
|
64
|
+
" ".join(parameter.description for parameter in definition.parameters),
|
|
65
|
+
" ".join(str(value) for value in definition.metadata.values()),
|
|
66
|
+
]
|
|
67
|
+
)
|
|
68
|
+
terms = set(_tokenize_tool_text(text))
|
|
69
|
+
score = sum(1 for term in query_terms if term in terms)
|
|
70
|
+
scored.append((score, definition.name, definition))
|
|
71
|
+
scored.sort(key=lambda item: (-item[0], item[1]))
|
|
72
|
+
return [definition for score, _, definition in scored[:top_k] if score > 0] or definitions[:top_k]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _tokenize_tool_text(text: str) -> list[str]:
|
|
76
|
+
return [token.lower() for token in re.findall(r"[A-Za-z0-9_/-]+|[\u4e00-\u9fff]{2,}", text)]
|