From 4e937cd2b1fa75c1e5b0869c63aa07d88f2444a5 Mon Sep 17 00:00:00 2001 From: wangzhihong Date: Tue, 7 Apr 2026 13:24:00 +0800 Subject: [PATCH 1/5] add claude support --- lazyllm/components/prompter/builtinPrompt.py | 45 +++++- lazyllm/docs/module.py | 58 ++++++++ .../onlinemodule/base/onlineChatModuleBase.py | 7 +- .../llms/onlinemodule/supplier/claude.py | 132 ++++++++++++++++++ tests/charge_tests/Models/test_chat.py | 5 + 5 files changed, 239 insertions(+), 8 deletions(-) create mode 100644 lazyllm/module/llms/onlinemodule/supplier/claude.py diff --git a/lazyllm/components/prompter/builtinPrompt.py b/lazyllm/components/prompter/builtinPrompt.py index 2d705ed34..66ac30ab2 100644 --- a/lazyllm/components/prompter/builtinPrompt.py +++ b/lazyllm/components/prompter/builtinPrompt.py @@ -183,6 +183,24 @@ def _generate_prompt_dict_impl(self, instruction, input, user, history, tools, l 'content': self._system + '\n' + instruction if instruction else self._system}) return dict(messages=history, tools=tools) if tools else dict(messages=history) + # Used for OnlineChatModule with Anthropic-format API + def _generate_prompt_anthropic_impl(self, instruction, input, user, history, tools, label): + result = self._generate_prompt_dict_impl(instruction, input, user, history, tools, label) + messages = result.get('messages', []) + system_text = None + non_system = [] + for msg in messages: + if msg.get('role') == 'system': + system_text = msg['content'] + else: + non_system.append(msg) + out = dict(messages=non_system) + if system_text is not None: + out['system'] = system_text + if tools: + out['tools'] = result['tools'] + return out + def pre_hook(self, func: Optional[Callable] = None): self._pre_hook = func return self @@ -203,17 +221,26 @@ def generate_prompt(self, input: Union[str, List, Dict[str, str], None] = None, history: List[Union[List[str], Dict[str, Any]]] = None, tools: Union[List[Dict[str, Any]], None] = None, label: Union[str, None] = None, - *, show: bool = False, return_dict: bool = False) -> Union[str, Dict]: + *, show: bool = False, return_dict: bool = False, + format: Optional[str] = None) -> Union[str, Dict]: + if return_dict and format is None: + LOG.log_once('return_dict is deprecated, use format="openai" instead.', level='warning') + format = 'openai' input = copy.deepcopy(input) if self._pre_hook: input, history, tools, label = self._pre_hook(input, history, tools, label) tools = tools or self._tools - instruction, input = self._get_instruction_and_input(input, return_dict=return_dict, tools=tools) - history = self._get_histories(history, return_dict=return_dict) - tools = self._get_tools(tools, return_dict=return_dict) + instruction, input = self._get_instruction_and_input(input, return_dict=bool(format), tools=tools) + history = self._get_histories(history, return_dict=bool(format)) + tools = self._get_tools(tools, return_dict=bool(format)) self._check_values(instruction, input, history, tools) instruction, user_instruction = self._split_instruction(instruction) - func = self._generate_prompt_dict_impl if return_dict else self._generate_prompt_impl + if format == 'anthropic': + func = self._generate_prompt_anthropic_impl + elif format == 'openai': + func = self._generate_prompt_dict_impl + else: + func = self._generate_prompt_impl result = func(instruction, input, user_instruction, history, tools, label) if self._show or show: LOG.info(result) return result @@ -225,8 +252,12 @@ def get_response(self, output: str, input: Union[str, None] = None) -> str: class EmptyPrompter(LazyLLMPrompterBase): - def generate_prompt(self, input, history=None, tools=None, label=None, show=False, return_dict=False): - if return_dict: + def generate_prompt(self, input, history=None, tools=None, label=None, show=False, + return_dict=False, format=None): + if return_dict and format is None: + LOG.log_once('return_dict is deprecated, use format="openai" instead.', level='warning') + format = 'openai' + if format: return {'messages': [{'role': 'user', 'content': input}]} if self._show or show: LOG.info(input) return input diff --git a/lazyllm/docs/module.py b/lazyllm/docs/module.py index a49099277..6dd654d80 100644 --- a/lazyllm/docs/module.py +++ b/lazyllm/docs/module.py @@ -1633,6 +1633,64 @@ >>> print(response) ''') +add_chinese_doc('llms.onlinemodule.supplier.claude.ClaudeChat', '''\ +Claude 在线聊天模块,继承自 OnlineChatModuleBase。 +封装了对 Anthropic Claude Messages API(/v1/messages)的调用,用于进行多轮问答交互。 +默认使用模型 `claude-opus-4-5`,支持流式输出、工具调用和调用链追踪。 + +与 OpenAI 兼容格式不同,该模块使用 Anthropic 原生 API 格式:请求头使用 `x-api-key` 和 +`anthropic-version`,`system` 消息作为顶层字段传递,工具定义使用 `input_schema` 字段。 +传入的 OpenAI 格式工具定义会自动转换为 Anthropic 格式。 + +Args: + model (str): 使用的模型名称,默认为 `claude-opus-4-5`。 + base_url (str): API 基础 URL,默认为 `https://api.anthropic.com/v1/`。 + api_key (Optional[str]): Anthropic API Key,若未提供,则从 `lazyllm.config['claude_api_key']` 读取。 + stream (bool): 是否启用流式输出,默认为 True。 + return_trace (bool): 是否返回调用链追踪信息,默认为 False。 + **kwargs: 其他传递给基类 OnlineChatModuleBase 的参数。 +''') + +add_english_doc('llms.onlinemodule.supplier.claude.ClaudeChat', '''\ +Claude online chat module, inheriting from OnlineChatModuleBase. +Wraps the Anthropic Claude Messages API (/v1/messages) for multi-turn Q&A interactions. +Defaults to model `claude-opus-4-5`, supporting streaming, tool calls, and optional trace return. + +Unlike OpenAI-compatible format, this module uses the native Anthropic API format: the request +header uses `x-api-key` and `anthropic-version`, the `system` message is passed as a top-level +field, and tools use the `input_schema` field. OpenAI-format tool definitions are automatically +converted to Anthropic format. + +Args: + model (str): The model name to use. Defaults to `claude-opus-4-5`. + base_url (str): Base URL of the API. Defaults to `https://api.anthropic.com/v1/`. + api_key (Optional[str]): Anthropic API key. If not provided, it is read from `lazyllm.config['claude_api_key']`. + stream (bool): Whether to enable streaming output. Defaults to True. + return_trace (bool): Whether to return trace information. Defaults to False. + **kwargs: Additional arguments passed to the base class OnlineChatModuleBase. +''') + +add_example('llms.onlinemodule.supplier.claude.ClaudeChat', '''\ +>>> import lazyllm +>>> # Set environment variable: export LAZYLLM_CLAUDE_API_KEY=your_api_key +>>> chat = lazyllm.OnlineChatModule(source='claude', model='claude-opus-4-5') +>>> response = chat('Hello, who are you?') +>>> print(response) + +>>> # Tool call example (requires FunctionCallFormatter to preserve tool_calls in output) +>>> from lazyllm.components.formatter import FunctionCallFormatter +>>> tools = [{'type': 'function', 'function': { +... 'name': 'get_weather', +... 'description': 'Get the current weather for a city', +... 'parameters': {'type': 'object', 'properties': {'city': {'type': 'string'}}, 'required': ['city']} +... }}] +>>> chat = lazyllm.OnlineChatModule(source='claude', model='claude-opus-4-5', stream=False) +>>> chat._formatter = FunctionCallFormatter() +>>> result = chat('Please call get_weather for Beijing', tools=tools) +>>> print(result) +''') + + add_chinese_doc('llms.onlinemodule.supplier.openai.OpenAIEmbed', '''\ OpenAI 在线嵌入模块。 该类封装了对 OpenAI 嵌入 API 的调用,默认使用模型 `text-embedding-ada-002`,用于将文本编码为向量表示。 diff --git a/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py b/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py index 26254242b..90c247f90 100644 --- a/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py +++ b/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py @@ -21,6 +21,7 @@ class LazyLLMOnlineChatModuleBase(LazyLLMOnlineBase, LLMBase): VLM_MODEL_PREFIX = [] NO_PROXY = True __lazyllm_registry_key__ = LLMType.CHAT + __format__ = 'openai' def __init__(self, api_key: Union[str, List[str]], base_url: str, model_name: str, stream: Union[bool, Dict[str, str]], return_trace: bool = False, skip_auth: bool = False, @@ -70,6 +71,9 @@ def _get_models_list(self): def _convert_msg_format(self, msg: Dict[str, Any]): return msg + def _prepare_request_data(self, data: Dict[str, Any]) -> Dict[str, Any]: + return data + def _str_to_json(self, msg: str, stream_output: bool): if isinstance(msg, bytes): pattern = re.compile(r'^data:\s*') @@ -131,7 +135,7 @@ def forward(self, __input: Union[Dict, str] = None, *, llm_chat_history: List[Li runtime_url = self._get_chat_url(url) if url else self._chat_url runtime_model = model or self._model_name - params = {'input': __input, 'history': llm_chat_history, 'return_dict': True} + params = {'input': __input, 'history': llm_chat_history, 'format': self.__format__} if tools: params['tools'] = tools data = self._prompt.generate_prompt(**params) data.update(self._static_params, **dict(model=runtime_model, stream=bool(stream_output))) @@ -146,6 +150,7 @@ def forward(self, __input: Union[Dict, str] = None, *, llm_chat_history: List[Li if msg.get('role') == 'user' and isinstance(msg.get('content'), str): msg['content'] = self._format_vl_chat_query(msg['content']) + data = self._prepare_request_data(data) proxies = {'http': None, 'https': None} if self.NO_PROXY else None with requests.post(runtime_url, json=data, headers=self._header, stream=stream_output, proxies=proxies) as r: diff --git a/lazyllm/module/llms/onlinemodule/supplier/claude.py b/lazyllm/module/llms/onlinemodule/supplier/claude.py new file mode 100644 index 000000000..d5825adfd --- /dev/null +++ b/lazyllm/module/llms/onlinemodule/supplier/claude.py @@ -0,0 +1,132 @@ +import json +import re +import requests +from typing import Any, Dict, List, Optional, Union +from urllib.parse import urljoin +from ..base import OnlineChatModuleBase + + +class ClaudeChat(OnlineChatModuleBase): + # Anthropic native Messages API (/v1/messages). + # Differs from OpenAI: x-api-key header, system as top-level field, + # max_tokens required, and SSE event types for streaming. + + _ANTHROPIC_VERSION = '2023-06-01' + _DEFAULT_MAX_TOKENS = 4096 + __format__ = 'anthropic' + + def __init__(self, base_url: Optional[str] = None, model: Optional[str] = None, + api_key: str = None, stream: bool = True, return_trace: bool = False, **kwargs): + base_url = base_url or 'https://api.anthropic.com/v1/' + model = model or 'claude-opus-4-5' + super().__init__(api_key=api_key or self._default_api_key(), + base_url=base_url, model_name=model, stream=stream, + return_trace=return_trace, **kwargs) + + def _get_system_prompt(self): + return 'You are Claude, an AI assistant made by Anthropic. You are helpful, harmless, and honest.' + + def _get_chat_url(self, url): + if url.rstrip('/').endswith('v1/messages'): + return url + base = url.rstrip('/') + if base.endswith('/v1'): + return base + '/messages' + return urljoin(url if url.endswith('/') else url + '/', 'v1/messages') + + @staticmethod + def _get_header(api_key: str) -> dict: + header = {'Content-Type': 'application/json', + 'anthropic-version': ClaudeChat._ANTHROPIC_VERSION} + if api_key: + header['x-api-key'] = api_key + return header + + @staticmethod + def _convert_tools(tools: List[Dict]) -> List[Dict]: + # Convert OpenAI-format tools to Anthropic format. + # OpenAI: [{"type": "function", "function": {"name": ..., "description": ..., "parameters": {...}}}] + # Anthropic: [{"name": ..., "description": ..., "input_schema": {...}}] + result = [] + for tool in tools: + fn = tool.get('function', tool) + result.append({ + 'name': fn['name'], + 'description': fn.get('description', ''), + 'input_schema': fn.get('parameters', fn.get('input_schema', {'type': 'object', 'properties': {}})), + }) + return result + + def _prepare_request_data(self, data: Dict[str, Any]) -> Dict[str, Any]: + data = dict(data) + data.setdefault('max_tokens', self._DEFAULT_MAX_TOKENS) + if data.get('tools'): + data['tools'] = self._convert_tools(data['tools']) + return data + + def _convert_msg_format(self, msg: Dict[str, Any]): + msg_type = msg.get('type', '') + if msg_type == 'message': # non-stream response + text = ''.join(b.get('text', '') for b in msg.get('content', []) if b.get('type') == 'text') + tool_calls = [ + {'id': b['id'], 'type': 'function', + 'function': {'name': b['name'], 'arguments': json.dumps(b.get('input', {}), ensure_ascii=False)}} + for b in msg.get('content', []) if b.get('type') == 'tool_use' + ] + message: Dict[str, Any] = {'role': 'assistant', 'content': text} + if tool_calls: + message['tool_calls'] = tool_calls + usage = msg.get('usage', {}) + return {'choices': [{'message': message}], + 'usage': {'prompt_tokens': usage.get('input_tokens', -1), + 'completion_tokens': usage.get('output_tokens', -1)}} + if msg_type == 'content_block_delta': + delta_obj = msg.get('delta', {}) + if delta_obj.get('type') == 'text_delta': + return {'choices': [{'delta': {'role': 'assistant', 'content': delta_obj.get('text', '')}}]} + if delta_obj.get('type') == 'input_json_delta': + # Partial tool input — carry as tool_calls delta with index + return {'choices': [{'index': msg.get('index', 0), + 'delta': {'tool_calls': [{'function': {'arguments': delta_obj.get('partial_json', '')}}]}}]} + if msg_type == 'content_block_start': + block = msg.get('content_block', {}) + if block.get('type') == 'tool_use': + # Emit the tool call header (id + name) as the first delta + return {'choices': [{'index': msg.get('index', 0), + 'delta': {'role': 'assistant', 'content': '', + 'tool_calls': [{'index': msg.get('index', 0), + 'id': block['id'], 'type': 'function', + 'function': {'name': block['name'], 'arguments': ''}}]}}]} + if msg_type == 'message_start': + usage = msg.get('message', {}).get('usage', {}) + return {'choices': [{'delta': {'role': 'assistant', 'content': ''}}], + 'usage': {'prompt_tokens': usage.get('input_tokens', -1), 'completion_tokens': -1}} + if msg_type == 'message_delta': + usage = msg.get('usage', {}) + return {'choices': [{'delta': {'role': 'assistant', 'content': ''}}], + 'usage': {'prompt_tokens': -1, 'completion_tokens': usage.get('output_tokens', -1)}} + return '' # ping / content_block_stop / message_stop → filtered out + + def _str_to_json(self, msg: Union[str, bytes], stream_output: bool): + if isinstance(msg, bytes): + msg = re.sub(r'^data:\s*', '', msg.decode('utf-8')) + try: + message = self._convert_msg_format(json.loads(msg)) + if not stream_output: + return message + color = stream_output.get('color') if isinstance(stream_output, dict) else None + for item in (message.get('choices', []) if isinstance(message, dict) else []): + delta = item.get('delta', {}) + if (content := delta.get('content', '')) and not delta.get('tool_calls'): + self._stream_output(content, color) + return message + except Exception: + return '' + + def _validate_api_key(self): + try: + models_url = urljoin(self._base_url, 'models') + response = requests.get(models_url, headers=self._header, timeout=10) + return response.status_code == 200 + except Exception: + return False diff --git a/tests/charge_tests/Models/test_chat.py b/tests/charge_tests/Models/test_chat.py index f5fc02373..9c7db3c7c 100644 --- a/tests/charge_tests/Models/test_chat.py +++ b/tests/charge_tests/Models/test_chat.py @@ -70,3 +70,8 @@ def test_aiping_chat(self): @pytest.mark.xfail def test_ppio_chat(self): self.common_chat(source='ppio') + + @pytest.mark.ignore_cache_on_change(get_path('claude')) + @pytest.mark.xfail + def test_claude_chat(self): + self.common_chat(source='claude') From 1b15e0d678cab6e909aaba0c3b36c7d9201347cc Mon Sep 17 00:00:00 2001 From: wangzhihong Date: Tue, 7 Apr 2026 13:40:12 +0800 Subject: [PATCH 2/5] add claude support --- .github/PULL_REQUEST_TEMPLATE.md | 223 +++++++++++++----- .../onlinemodule/base/onlineChatModuleBase.py | 4 +- .../llms/onlinemodule/supplier/claude.py | 13 +- 3 files changed, 179 insertions(+), 61 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9ccfa3bc5..e7aa484e9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,70 +1,185 @@ -## 📌 PR 内容 / PR Description - -- +# 📌 PR 内容 / PR Description -## 🔍 相关 Issue / Related Issue - - -## ✅ 变更类型 / Type of Change - -- [ ] 修复 Bug / Bug fix (non-breaking change that fixes an issue) -- [ ] 新功能 / New feature (non-breaking change that adds functionality) -- [ ] 重构 / Refactor (no functionality change, code structure optimized) -- [ ] 重大变更 / Breaking change (fix or feature that would cause existing functionality to change) -- [ ] 文档更新 / Documentation update (changes to docs only) -- [ ] 性能优化 / Performance optimization - -## 🧪 如何测试 / How Has This Been Tested? - -1. -2. -3. - -## 📷 截图 / Demo (Optional) - +--- + +# 🎯 问题背景 / Problem Context + + - -## ⚡ 更新后的用法示例 / Usage After Update - +# 🔍 相关 Issue / Related Issue + +* + +--- + +# ✅ 变更类型 / Type of Change + +* [ ] Bug fix +* [ ] New feature +* [ ] Refactor +* [ ] Breaking change +* [ ] Documentation +* [ ] Performance optimization + +--- + +# 🧪 如何测试 / How Has This Been Tested? + +1. +2. +3. + +--- + +# 📷 Demo (Optional) + +* + +--- + +# ⚡ 更新后的用法示例 / Usage After Update + ```python -# 示例 / Example ``` -## 🔄 重构前 / 重构后对比 (仅当 Type 为 Refactor) / Refactor Before & After (only for Refactor) - +--- -### 重构前 / Before: +# 🔄 重构对比(如适用) + +## Before + +```python +``` + +## After + +```python +``` + +# ⚠️ 注意事项 / Additional Notes + +* + +--- + + +# 🧠 AI 参与情况 / AI Involvement + + +- [ ] 未使用 AI +- [ ] 使用 AI 辅助(局部代码) +- [ ] 使用 AI 主导(大部分代码) + +**使用工具 / Tools Used:** +- [ ] Cursor +- [ ] CodeX +- [ ] ClaudeCode +- [ ] OpenCode +- [ ] 其他: + +# 🤖 AI 生成过程 / AI Generation Process + +## 初始 Prompt + +```text +``` +## AI 初始输出质量 -### 重构后 / After: +* [ ] 一次正确 +* [ ] 部分正确 +* [ ] 基本不可用 + +## **问题点:** + +--- + +## 🔧 人工干预过程 / Human Intervention + + + +### 第一次修正 + +**修改后的 Prompt / 操作:** + +```text +``` + +## **原因:** + +--- + +### 第二次修正(如有) + +**修改后的 Prompt / 操作:** + +```text +``` + +## **原因:** + +--- + +### 最终策略总结 + + + +* + +--- + +# 📊 AI vs 人工贡献占比 + + + +* AI 生成代码占比:`%` +* 人工修改占比:`%` + +**主要人工修改点:** + +* [ ] 逻辑修正 +* [ ] 边界处理 +* [ ] 性能优化 +* [ ] 代码风格 +* [ ] 架构调整 + +--- + +# ⚠️ AI 问题记录 / AI Failure Cases + + + +### ❌ 失败 Prompt 示例 + +```text +``` + +### ❌ 问题表现 + +* + +### ✅ 改进后 Prompt + +```text +``` +# 🧩 可复用经验 / Reusable Patterns -## ⚠️ 注意事项 / Additional Notes - +* Prompt 模板: +* 常见坑: +* 推荐做法: diff --git a/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py b/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py index 90c247f90..ba645268d 100644 --- a/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py +++ b/lazyllm/module/llms/onlinemodule/base/onlineChatModuleBase.py @@ -21,7 +21,7 @@ class LazyLLMOnlineChatModuleBase(LazyLLMOnlineBase, LLMBase): VLM_MODEL_PREFIX = [] NO_PROXY = True __lazyllm_registry_key__ = LLMType.CHAT - __format__ = 'openai' + _message_format = 'openai' def __init__(self, api_key: Union[str, List[str]], base_url: str, model_name: str, stream: Union[bool, Dict[str, str]], return_trace: bool = False, skip_auth: bool = False, @@ -135,7 +135,7 @@ def forward(self, __input: Union[Dict, str] = None, *, llm_chat_history: List[Li runtime_url = self._get_chat_url(url) if url else self._chat_url runtime_model = model or self._model_name - params = {'input': __input, 'history': llm_chat_history, 'format': self.__format__} + params = {'input': __input, 'history': llm_chat_history, 'format': self._message_format} if tools: params['tools'] = tools data = self._prompt.generate_prompt(**params) data.update(self._static_params, **dict(model=runtime_model, stream=bool(stream_output))) diff --git a/lazyllm/module/llms/onlinemodule/supplier/claude.py b/lazyllm/module/llms/onlinemodule/supplier/claude.py index d5825adfd..fd8902ba0 100644 --- a/lazyllm/module/llms/onlinemodule/supplier/claude.py +++ b/lazyllm/module/llms/onlinemodule/supplier/claude.py @@ -13,12 +13,12 @@ class ClaudeChat(OnlineChatModuleBase): _ANTHROPIC_VERSION = '2023-06-01' _DEFAULT_MAX_TOKENS = 4096 - __format__ = 'anthropic' + _message_format = 'anthropic' def __init__(self, base_url: Optional[str] = None, model: Optional[str] = None, api_key: str = None, stream: bool = True, return_trace: bool = False, **kwargs): base_url = base_url or 'https://api.anthropic.com/v1/' - model = model or 'claude-opus-4-5' + model = model or 'claude-3-5-sonnet-20241022' super().__init__(api_key=api_key or self._default_api_key(), base_url=base_url, model_name=model, stream=stream, return_trace=return_trace, **kwargs) @@ -86,8 +86,9 @@ def _convert_msg_format(self, msg: Dict[str, Any]): return {'choices': [{'delta': {'role': 'assistant', 'content': delta_obj.get('text', '')}}]} if delta_obj.get('type') == 'input_json_delta': # Partial tool input — carry as tool_calls delta with index + partial = delta_obj.get('partial_json', '') return {'choices': [{'index': msg.get('index', 0), - 'delta': {'tool_calls': [{'function': {'arguments': delta_obj.get('partial_json', '')}}]}}]} + 'delta': {'tool_calls': [{'function': {'arguments': partial}}]}}]} if msg_type == 'content_block_start': block = msg.get('content_block', {}) if block.get('type') == 'tool_use': @@ -124,9 +125,11 @@ def _str_to_json(self, msg: Union[str, bytes], stream_output: bool): return '' def _validate_api_key(self): + # Anthropic has no /v1/models endpoint; send a minimal request to verify the key. try: - models_url = urljoin(self._base_url, 'models') - response = requests.get(models_url, headers=self._header, timeout=10) + data = {'model': self._model_name, 'max_tokens': 1, + 'messages': [{'role': 'user', 'content': 'hi'}]} + response = requests.post(self._chat_url, json=data, headers=self._header, timeout=10) return response.status_code == 200 except Exception: return False From 932a32b7dd8afd67c965040b7e80d1c2a488c047 Mon Sep 17 00:00:00 2001 From: wangzhihong Date: Tue, 7 Apr 2026 13:44:29 +0800 Subject: [PATCH 3/5] add claude support --- .github/PULL_REQUEST_TEMPLATE.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e7aa484e9..4c186eddf 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -107,8 +107,6 @@ ## **问题点:** ---- - ## 🔧 人工干预过程 / Human Intervention @@ -120,9 +118,7 @@ ```text ``` -## **原因:** - ---- +### **原因:** ### 第二次修正(如有) @@ -131,9 +127,7 @@ ```text ``` -## **原因:** - ---- +### **原因:** ### 最终策略总结 From 069ef1cea9dd0e22c2b58a66f4d882fc627a2482 Mon Sep 17 00:00:00 2001 From: wangzhihong Date: Tue, 7 Apr 2026 13:50:29 +0800 Subject: [PATCH 4/5] add claude support --- .github/PULL_REQUEST_TEMPLATE.md | 93 ++++++++++++++++---------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4c186eddf..b7213e8f3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,13 +1,14 @@ # 📌 PR 内容 / PR Description @@ -18,7 +19,7 @@ # 🎯 问题背景 / Problem Context - + - # 🔍 相关 Issue / Related Issue @@ -59,7 +60,7 @@ --- -# 🔄 重构对比(如适用) +# 🔄 重构对比 / Refactor Comparison (如适用 / if applicable) ## Before @@ -80,100 +81,100 @@ # 🧠 AI 参与情况 / AI Involvement - -- [ ] 未使用 AI -- [ ] 使用 AI 辅助(局部代码) -- [ ] 使用 AI 主导(大部分代码) + +- [ ] 未使用 AI / No AI used +- [ ] 使用 AI 辅助(局部代码)/ AI-assisted (partial code) +- [ ] 使用 AI 主导(大部分代码)/ AI-led (majority of code) **使用工具 / Tools Used:** - [ ] Cursor - [ ] CodeX - [ ] ClaudeCode - [ ] OpenCode -- [ ] 其他: +- [ ] 其他 / Other: # 🤖 AI 生成过程 / AI Generation Process -## 初始 Prompt - +## 初始 Prompt / Initial Prompt + ```text ``` -## AI 初始输出质量 +## AI 初始输出质量 / Initial Output Quality -* [ ] 一次正确 -* [ ] 部分正确 -* [ ] 基本不可用 +* [ ] 一次正确 / Correct on first try +* [ ] 部分正确 / Partially correct +* [ ] 基本不可用 / Mostly unusable -## **问题点:** +## **问题点 / Issues:** ## 🔧 人工干预过程 / Human Intervention - + -### 第一次修正 +### 第一次修正 / First Correction -**修改后的 Prompt / 操作:** +**修改后的 Prompt / 操作 / Updated Prompt or Action:** ```text ``` -### **原因:** +### **原因 / Reason:** -### 第二次修正(如有) +### 第二次修正(如有)/ Second Correction (if any) -**修改后的 Prompt / 操作:** +**修改后的 Prompt / 操作 / Updated Prompt or Action:** ```text ``` -### **原因:** +### **原因 / Reason:** -### 最终策略总结 +### 最终策略总结 / Final Strategy Summary - + * --- -# 📊 AI vs 人工贡献占比 +# 📊 AI vs 人工贡献占比 / AI vs Human Contribution - + -* AI 生成代码占比:`%` -* 人工修改占比:`%` +* AI 生成代码占比 / AI-generated code:`%` +* 人工修改占比 / Human modifications:`%` -**主要人工修改点:** +**主要人工修改点 / Key Human Modifications:** -* [ ] 逻辑修正 -* [ ] 边界处理 -* [ ] 性能优化 -* [ ] 代码风格 -* [ ] 架构调整 +* [ ] 逻辑修正 / Logic fixes +* [ ] 边界处理 / Edge case handling +* [ ] 性能优化 / Performance optimization +* [ ] 代码风格 / Code style +* [ ] 架构调整 / Architecture adjustments --- # ⚠️ AI 问题记录 / AI Failure Cases - + -### ❌ 失败 Prompt 示例 +### ❌ 失败 Prompt 示例 / Failed Prompt Example ```text ``` -### ❌ 问题表现 +### ❌ 问题表现 / Issue Description * -### ✅ 改进后 Prompt +### ✅ 改进后 Prompt / Improved Prompt ```text ``` # 🧩 可复用经验 / Reusable Patterns -* Prompt 模板: -* 常见坑: -* 推荐做法: +* Prompt 模板 / Prompt template: +* 常见坑 / Common pitfalls: +* 推荐做法 / Recommended practices: From 842a99d0e9160819ec3bc4536b84a4b118fec18e Mon Sep 17 00:00:00 2001 From: wangzhihong Date: Tue, 7 Apr 2026 14:10:00 +0800 Subject: [PATCH 5/5] add claude support --- docs/en/Best Practice/prompt.md | 21 ++--- docs/en/Cookbook/decentralized.md | 2 +- docs/lazyllm-skill/assets/basic/prompter.md | 8 +- docs/zh/Best Practice/prompt.md | 21 ++--- docs/zh/Cookbook/decentralized.md | 2 +- lazyllm/components/prompter/builtinPrompt.py | 23 +++--- lazyllm/docs/components.py | 22 ++++-- .../basic_tests/Components/test_component.py | 78 +++++++++---------- 8 files changed, 93 insertions(+), 84 deletions(-) diff --git a/docs/en/Best Practice/prompt.md b/docs/en/Best Practice/prompt.md index 45185a1f2..86d326b55 100644 --- a/docs/en/Best Practice/prompt.md +++ b/docs/en/Best Practice/prompt.md @@ -31,14 +31,15 @@ import lazyllm prompter.generate_prompt(dict(context='背景', input='输入')) # {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\n你是一个由LazyLLM开发的知识问答助手,你的任务是根据提供的上下文信息来回答用户的问题。上下文信息是背景,用户的问题是输入,现在请你做出回答。\n\n'}, {'role': 'user', 'content': ''}]} -prompter.generate_prompt(dict(context='背景', input='输入'), return_dict=True) +prompter.generate_prompt(dict(context='背景', input='输入'), format='openai') ``` In the example above, the ``generate_prompt`` function accepts a ``dict`` as input, filling in the slots in the ``instruction`` template with the provided values. !!! Note - - In the code above, there's a parameter ``return_dict`` worth noting. When ``return_dict`` is set to True, it returns a dictionary in the OpenAI format for online models. + - In the code above, there's a parameter ``format`` worth noting. When ``format='openai'``, it returns a dictionary in the OpenAI Chat Completions format for online models. + - The legacy ``return_dict=True`` remains supported (equivalent to ``format='openai'``, with a deprecation warning); prefer ``format`` in new code. - Typically, you just need to assign the Prompter to a ``TrainableModule`` or ``OnlineChatModule`` without worrying about the ``generate_prompt`` function. ### Design Concept of LazyLLM Prompter @@ -221,7 +222,7 @@ The tool will be read after step 4 in [Prompt Generation Process Analysis](#anal >>> import lazyllm >>> tools=[dict(type='function', function=dict(name='example'))] >>> prompter = lazyllm.AlpacaPrompter('你是一个工具调用的Agent,我会给你提供一些工具,请根据用户输入,帮我选择最合适的工具并使用', extra_keys='input', tools=tools) - >>> prompter.generate_prompt('帮我查询一下今天的天气', return_dict=True) + >>> prompter.generate_prompt('帮我查询一下今天的天气', format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\n你是一个工具调用的Agent,我会给你提供一些工具,请根据用户输入,帮我选择最合适的工具并使用\\n\\nHere are some extra messages you can referred to:\\n\\n### input:\\n帮我查询一下今天的天气\\n\\n'}, {'role': 'user', 'content': ''}], 'tools': [{'type': 'function', 'function': {'name': 'example'}}]} @@ -234,9 +235,9 @@ If we want the model to have multi-turn conversation capabilities, we need to co >>> prompter = lazyllm.ChatPrompter('你是一个对话机器人,现在你要和用户进行友好的对话') >>> prompter.generate_prompt('我们聊会儿天吧', history=[['你好', '你好,我是一个对话机器人,有什么能为您服务的']]) '<|start_system|>You are an AI-Agent developed by LazyLLM.你是一个对话机器人,现在你要和用户进行友好的对话\\n\\n<|end_system|>\\n\\n<|Human|>:你好<|Assistant|>:你好,我是一个对话机器人,有什么能为您服务的\\n<|Human|>:\\n我们聊会儿天吧\\n<|Assistant|>:\\n' ->>> prompter.generate_prompt('我们聊会儿天吧', history=[['你好', '你好,我是一个对话机器人,有什么能为您服务的']], return_dict=True) +>>> prompter.generate_prompt('我们聊会儿天吧', history=[['你好', '你好,我是一个对话机器人,有什么能为您服务的']], format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\n你是一个对话机器人,现在你要和用户进行友好的对话\\n\\n'}, {'role': 'user', 'content': '你好'}, {'role': 'assistant', 'content': '你好,我是一个对话机器人,有什么能为您服务的'}, {'role': 'user', 'content': '我们聊会儿天吧'}]} ->>> prompter.generate_prompt('我们聊会儿天吧', history=[dict(role='user', content='你好'), dict(role='assistant', content='你好,我是一个对话机器人,有什么能为您服务的')], return_dict=True) +>>> prompter.generate_prompt('我们聊会儿天吧', history=[dict(role='user', content='你好'), dict(role='assistant', content='你好,我是一个对话机器人,有什么能为您服务的')], format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\n你是一个对话机器人,现在你要和用户进行友好的对话\\n\\n'}, {'role': 'user', 'content': '你好'}, {'role': 'assistant', 'content': '你好,我是一个对话机器人,有什么能为您服务的'}, {'role': 'user', 'content': '我们聊会儿天吧'}]} ``` @@ -245,12 +246,12 @@ The conversation history will be read in step 4 of [Prompt Generation Process An !!! Note - Only ``ChatPrompter`` supports passing in conversation history. - - When the input is in the format ``[[a, b], ...]``, both ``return_dict`` set to ``True`` or ``False`` are supported, whereas when the input is in the format ``[dict, dict]``, only ``return_dict`` set to ``True`` is supported. + - When the input is in the format ``[[a, b], ...]``, both ``format='openai'`` (or default ``None`` for string concatenation) are supported, whereas when the input is in the format ``[dict, dict]``, only API message formats such as ``format='openai'`` are supported. #### Used with OnlineChatModule -When the ``Prompter`` is used with the ``OnlineChatModule``, ``OnlineChatModule.__call__`` will call ``Prompter.generate_prompt`` and ``pass __input``, -``history``, and ``tools`` to ``generate_prompt``. At this time, the ``return_dict`` of ``generate_prompt`` will be set to ``True``. Below is an example: +When the ``Prompter`` is used with the ``OnlineChatModule``, ``OnlineChatModule.__call__`` will call ``Prompter.generate_prompt`` and pass ``__input``, +``history``, and ``tools`` to ``generate_prompt``. The module sets ``format`` to ``'openai'`` or ``'anthropic'`` as appropriate. Below is an example: ```python import lazyllm @@ -262,8 +263,8 @@ module(dict(context='背景', input='输入')) #### Used with TrainableModule -When the ``Prompter`` is used with the ``TrainableModule``, ``TrainableModule.__call__`` will call ``Prompter.generate_prompt`` and ``pass __input``, -``history``, and ``tools`` to ``generate_prompt``. At this time, the ``return_dict`` of ``generate_prompt`` will be set to ``True``. Below is an example: +When the ``Prompter`` is used with the ``TrainableModule``, ``TrainableModule.__call__`` will call ``Prompter.generate_prompt`` and pass ``__input``, +``history``, and ``tools`` to ``generate_prompt``. ``format`` stays at the default (``None``), producing the concatenated string for local inference. Below is an example: ```python import lazyllm diff --git a/docs/en/Cookbook/decentralized.md b/docs/en/Cookbook/decentralized.md index c6668613b..8d6ad34f1 100644 --- a/docs/en/Cookbook/decentralized.md +++ b/docs/en/Cookbook/decentralized.md @@ -523,7 +523,7 @@ def generate_character_description(character_name): that emphasizes their personalities. Speak directly to {character_name}. Do not add anything else.''', - return_dict=True) + format='openai') character_description = lazyllm.OnlineChatModule(model='Qwen3-32B', static_params=temp)(contents) return character_description diff --git a/docs/lazyllm-skill/assets/basic/prompter.md b/docs/lazyllm-skill/assets/basic/prompter.md index 523a17c3b..a9eab2c80 100644 --- a/docs/lazyllm-skill/assets/basic/prompter.md +++ b/docs/lazyllm-skill/assets/basic/prompter.md @@ -78,17 +78,17 @@ from lazyllm import AlpacaPrompter p = AlpacaPrompter('hello world {instruction}') p.generate_prompt('this is my input') 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world this is my input\n\n\n### Response:\n' -p.generate_prompt('this is my input', return_dict=True) +p.generate_prompt('this is my input', format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world this is my input\n\n'}, {'role': 'user', 'content': ''}]} p = AlpacaPrompter('hello world {instruction}, {input}', extra_keys=['knowledge']) p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm')) 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world hello world, my input\n\nHere are some extra messages you can referred to:\n\n### knowledge:\nlazyllm\n\n\n### Response:\n' -p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'), return_dict=True) +p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'), format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world hello world, my input\n\nHere are some extra messages you can referred to:\n\n### knowledge:\nlazyllm\n\n'}, {'role': 'user', 'content': ''}]} p = AlpacaPrompter(dict(system="hello world", user="this is user instruction {input}")) p.generate_prompt(dict(input="my input")) 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello word\n\n\n\nthis is user instruction my input### Response:\n' -p.generate_prompt(dict(input="my input"), return_dict=True) +p.generate_prompt(dict(input="my input"), format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input'}]} ``` @@ -127,7 +127,7 @@ p.generate_prompt({ p = ChatPrompter(dict(system="hello world", user="this is user instruction {input}")) p.generate_prompt({'input': "my input", 'query': "this is user query"}) 'You are an AI-Agent developed by LazyLLM.hello world\nthis is user instruction my input this is user query\n' -p.generate_prompt({'input': "my input", 'query': "this is user query"}, return_dict=True) +p.generate_prompt({'input': "my input", 'query': "this is user query"}, format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input this is user query'}]} ``` diff --git a/docs/zh/Best Practice/prompt.md b/docs/zh/Best Practice/prompt.md index fdef3224c..281b88ec4 100644 --- a/docs/zh/Best Practice/prompt.md +++ b/docs/zh/Best Practice/prompt.md @@ -31,14 +31,15 @@ import lazyllm prompter.generate_prompt(dict(context='背景', input='输入')) # {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\n你是一个由LazyLLM开发的知识问答助手,你的任务是根据提供的上下文信息来回答用户的问题。上下文信息是背景,用户的问题是输入,现在请你做出回答。\n\n'}, {'role': 'user', 'content': ''}]} -prompter.generate_prompt(dict(context='背景', input='输入'), return_dict=True) +prompter.generate_prompt(dict(context='背景', input='输入'), format='openai') ``` 在上面的例子中, ``generate_prompt`` 的输入是一个 ``dict`` ,他会把值依次填入 ``instruction`` 提供的槽位中。 !!! Note "注意" - - 上面代码中出现了一个值得您关注的参数 ``return_dict`` , 当 ``return_dict`` 为 True 时,会返回 OpenAI 格式的 dict 用于线上模型。 + - 上面代码中出现了一个值得您关注的参数 ``format`` ,当 ``format='openai'`` 时,会返回 OpenAI Chat Completions 风格的 dict 用于线上模型。 + - 旧版代码中的 ``return_dict=True`` 仍受支持(等价于 ``format='openai'``,并会提示弃用);新代码请优先使用 ``format``。 - 一般情况下,您只需要将Prompter设置给 ``TrainableModule`` 或 ``OnlineChatModule`` 即可,而无需关心 ``generate_prompt`` 这一函数。 ## LazyLLM Prompter 的设计思路 @@ -220,7 +221,7 @@ prompter.generate_prompt(dict(context='背景', input='输入'), return_dict=Tru >>> import lazyllm >>> tools=[dict(type='function', function=dict(name='example'))] >>> prompter = lazyllm.AlpacaPrompter('你是一个工具调用的Agent,我会给你提供一些工具,请根据用户输入,帮我选择最合适的工具并使用', extra_keys='input', tools=tools) - >>> prompter.generate_prompt('帮我查询一下今天的天气', return_dict=True) + >>> prompter.generate_prompt('帮我查询一下今天的天气', format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\n你是一个工具调用的Agent,我会给你提供一些工具,请根据用户输入,帮我选择最合适的工具并使用\\n\\nHere are some extra messages you can referred to:\\n\\n### input:\\n帮我查询一下今天的天气\\n\\n'}, {'role': 'user', 'content': ''}], 'tools': [{'type': 'function', 'function': {'name': 'example'}}]} @@ -234,9 +235,9 @@ prompter.generate_prompt(dict(context='背景', input='输入'), return_dict=Tru >>> prompter = lazyllm.ChatPrompter('你是一个对话机器人,现在你要和用户进行友好的对话') >>> prompter.generate_prompt('我们聊会儿天吧', history=[['你好', '你好,我是一个对话机器人,有什么能为您服务的']]) '<|start_system|>You are an AI-Agent developed by LazyLLM.你是一个对话机器人,现在你要和用户进行友好的对话\\n\\n<|end_system|>\\n\\n<|Human|>:你好<|Assistant|>:你好,我是一个对话机器人,有什么能为您服务的\\n<|Human|>:\\n我们聊会儿天吧\\n<|Assistant|>:\\n' ->>> prompter.generate_prompt('我们聊会儿天吧', history=[['你好', '你好,我是一个对话机器人,有什么能为您服务的']], return_dict=True) +>>> prompter.generate_prompt('我们聊会儿天吧', history=[['你好', '你好,我是一个对话机器人,有什么能为您服务的']], format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\n你是一个对话机器人,现在你要和用户进行友好的对话\\n\\n'}, {'role': 'user', 'content': '你好'}, {'role': 'assistant', 'content': '你好,我是一个对话机器人,有什么能为您服务的'}, {'role': 'user', 'content': '我们聊会儿天吧'}]} ->>> prompter.generate_prompt('我们聊会儿天吧', history=[dict(role='user', content='你好'), dict(role='assistant', content='你好,我是一个对话机器人,有什么能为您服务的')], return_dict=True) +>>> prompter.generate_prompt('我们聊会儿天吧', history=[dict(role='user', content='你好'), dict(role='assistant', content='你好,我是一个对话机器人,有什么能为您服务的')], format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\n你是一个对话机器人,现在你要和用户进行友好的对话\\n\\n'}, {'role': 'user', 'content': '你好'}, {'role': 'assistant', 'content': '你好,我是一个对话机器人,有什么能为您服务的'}, {'role': 'user', 'content': '我们聊会儿天吧'}]} ``` @@ -245,12 +246,12 @@ prompter.generate_prompt(dict(context='背景', input='输入'), return_dict=Tru !!! Note "注意" - 只有 ``ChatPrompter`` 支持传入历史对话 - - 当输入是 ``[[a, b], ...]`` 格式时,同时支持 ``return_dict`` 为 ``True`` 或 ``False`` , 而当输入为 ``[dict, dict]`` 格式时,仅支持 ``return_dict`` 为 ``True`` + - 当输入是 ``[[a, b], ...]`` 格式时,同时支持 ``format`` 为 ``'openai'``(或默认 ``None`` 走字符串拼接),而当输入为 ``[dict, dict]`` 格式时,仅支持 ``format='openai'`` 等 API 消息格式 ### 和 OnlineChatModule 一起使用 -当 ``Prompter`` 和 ``OnlineChatModule`` 一起使用时, ``OnlineChatModule.__call__`` 会调用 ``Prompter.generate_prompt`` ,并且将 ``__input``, -``history`` 和 ``tools`` 传给 ``generate_prompt`` ,此时 ``generate_prompt`` 的 ``return_dict`` 会被设置为 ``True``。下面给出一个例子: +当 ``Prompter`` 和 ``OnlineChatModule`` 一起使用时, ``OnlineChatModule.__call__`` 会调用 ``Prompter.generate_prompt`` ,并且将 ``__input``、 +``history`` 和 ``tools`` 传给 ``generate_prompt`` ,此时 ``generate_prompt`` 的 ``format`` 会由模块设为 ``'openai'`` 或 ``'anthropic'`` 等。下面给出一个例子: ```python import lazyllm @@ -262,8 +263,8 @@ module(dict(context='背景', input='输入')) ### 和 TrainableModule 一起使用 -当 ``Prompter`` 和 ``TrainableModule`` 一起使用时, ``TrainableModule.__call__`` 会调用 ``Prompter.generate_prompt`` ,并且将 ``__input``, -``history`` 和 ``tools`` 传给 ``generate_prompt`` ,此时 ``generate_prompt`` 的 ``return_dict`` 会被设置为 ``True``。下面给出一个例子: +当 ``Prompter`` 和 ``TrainableModule`` 一起使用时, ``TrainableModule.__call__`` 会调用 ``Prompter.generate_prompt`` ,并且将 ``__input``、 +``history`` 和 ``tools`` 传给 ``generate_prompt`` ,此时 ``format`` 为默认(``None``),得到用于本地推理的拼接字符串。下面给出一个例子: ```python import lazyllm diff --git a/docs/zh/Cookbook/decentralized.md b/docs/zh/Cookbook/decentralized.md index 001683bbd..b7211c63f 100644 --- a/docs/zh/Cookbook/decentralized.md +++ b/docs/zh/Cookbook/decentralized.md @@ -513,7 +513,7 @@ def generate_character_description(character_name): that emphasizes their personalities. Speak directly to {character_name}. Do not add anything else.''', - return_dict=True) + format='openai') character_description = lazyllm.OnlineChatModule(model='Qwen3-32B', static_params=temp)( contents ) diff --git a/lazyllm/components/prompter/builtinPrompt.py b/lazyllm/components/prompter/builtinPrompt.py index 66ac30ab2..37294e51a 100644 --- a/lazyllm/components/prompter/builtinPrompt.py +++ b/lazyllm/components/prompter/builtinPrompt.py @@ -65,16 +65,16 @@ def _set_model_configs(self, system: str = None, sos: Union[None, str] = None, s 'tool_end_token', 'tool_args_token']: if local[name] is not None: setattr(self, f'_{name}', local[name]) - def _get_tools(self, tools, *, return_dict): - return tools if return_dict else '### Function-call Tools. \n\n' +\ + def _get_tools(self, tools, *, for_chat_api: bool): + return tools if for_chat_api else '### Function-call Tools. \n\n' +\ f'{json.dumps(tools, ensure_ascii=False)}\n\n' if tools else '' def _get_tools_name(self, tools): return json.dumps([t['function']['name'] for t in tools], ensure_ascii=False) if tools else '' - def _get_histories(self, history, *, return_dict): # noqa: C901 + def _get_histories(self, history, *, for_chat_api: bool): # noqa: C901 if not self._history and not history: return '' - if return_dict: + if for_chat_api: content = [] for item in self._history + (history or []): if isinstance(item, list): @@ -119,9 +119,9 @@ def _get_histories(self, history, *, return_dict): # noqa: C901 else: raise NotImplementedError('Cannot transform json history to {type(history[0])} now') - def _get_instruction_and_input(self, input, *, return_dict=False, tools=None): + def _get_instruction_and_input(self, input, *, for_chat_api: bool = False, tools=None): instruction = self._instruction_template - fc_prompt = '' if return_dict or not tools else FC_PROMPT + fc_prompt = '' if for_chat_api or not tools else FC_PROMPT if fc_prompt and FC_PROMPT_PLACEHOLDER not in instruction: instruction = f'{instruction}\n\n{fc_prompt}' instruction = instruction.replace(FC_PROMPT_PLACEHOLDER, fc_prompt) @@ -230,9 +230,10 @@ def generate_prompt(self, input: Union[str, List, Dict[str, str], None] = None, if self._pre_hook: input, history, tools, label = self._pre_hook(input, history, tools, label) tools = tools or self._tools - instruction, input = self._get_instruction_and_input(input, return_dict=bool(format), tools=tools) - history = self._get_histories(history, return_dict=bool(format)) - tools = self._get_tools(tools, return_dict=bool(format)) + for_chat_api = bool(format) + instruction, input = self._get_instruction_and_input(input, for_chat_api=for_chat_api, tools=tools) + history = self._get_histories(history, for_chat_api=for_chat_api) + tools = self._get_tools(tools, for_chat_api=for_chat_api) self._check_values(instruction, input, history, tools) instruction, user_instruction = self._split_instruction(instruction) if format == 'anthropic': @@ -252,8 +253,8 @@ def get_response(self, output: str, input: Union[str, None] = None) -> str: class EmptyPrompter(LazyLLMPrompterBase): - def generate_prompt(self, input, history=None, tools=None, label=None, show=False, - return_dict=False, format=None): + def generate_prompt(self, input, history=None, tools=None, label=None, *, show=False, + return_dict: bool = False, format=None): if return_dict and format is None: LOG.log_once('return_dict is deprecated, use format="openai" instead.', level='warning') format = 'openai' diff --git a/lazyllm/docs/components.py b/lazyllm/docs/components.py index fa27fa667..c7d25ab62 100644 --- a/lazyllm/docs/components.py +++ b/lazyllm/docs/components.py @@ -3022,7 +3022,7 @@ def extract_result(output, inputs): >>> p = MyPrompter('ins {instruction}') >>> p.generate_prompt('hello') 'You are an AI-Agent developed by LazyLLM.\\\\nins hello\\\\n\\\\n\\\\n\\\\n, ## Response::' ->>> p.generate_prompt('hello world', return_dict=True) +>>> p.generate_prompt('hello world', format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\\\nins hello world\\\\n\\\\n'}, {'role': 'user', 'content': ''}]} ''') @@ -3055,7 +3055,8 @@ def extract_result(output, inputs): tools (Option[List[Dict]]: 可以使用的工具合集,大模型用作FunctionCall时使用,默认为None label (Option[str]): 标签,训练或微调时使用,默认为None show (bool): 标志是否打印生成的Prompt,默认为False - return_dict (bool): 标志是否返回dict,一般情况下使用 ``OnlineChatModule`` 时会设置为True。如果返回dict,则仅填充 ``instruction``。默认为False + return_dict (bool): 已弃用,请改用 ``format="openai"``。当 ``format`` 为 ``None`` 且该参数为 True 时,行为与 ``format="openai"`` 相同,并会记录一次弃用告警。默认为 False。 + format (Option[str]): 输出结构。``None`` 表示返回用于本地/微调的拼接字符串;``"openai"`` 表示返回 OpenAI Chat Completions 风格的 ``messages``(及可选 ``tools``);``"anthropic"`` 表示 Anthropic Messages API 所需的 ``system``/``messages`` 结构。使用 ``OnlineChatModule`` 时由模块传入相应格式。若同时传入 ``return_dict`` 与本参数,以本参数为准。默认为 ``None``。 ''') add_english_doc('prompter.PrompterBase.generate_prompt', '''\ @@ -3068,7 +3069,8 @@ def extract_result(output, inputs): tools (Option[List[Dict]]): A collection of tools that can be used, used when the large model performs FunctionCall, defaults to None. label (Option[str]): Label, used during fine-tuning or training, defaults to None. show (bool): Flag indicating whether to print the generated Prompt, defaults to False. - return_dict (bool): Flag indicating whether to return a dict, generally set to True when using ``OnlineChatModule``. If returning a dict, only the ``instruction`` will be filled. Defaults to False. + return_dict (bool): Deprecated; prefer ``format="openai"``. When ``format`` is ``None`` and this is True, behaves like ``format="openai"`` and emits a one-time deprecation warning. Defaults to False. + format (Option[str]): Output structure. ``None`` returns a concatenated string for local/finetuning use; ``"openai"`` returns OpenAI-style ``messages`` (and optional ``tools``); ``"anthropic"`` returns Anthropic-style ``system``/``messages``. ``OnlineChatModule`` passes the appropriate value. If both ``return_dict`` and ``format`` are provided, ``format`` takes precedence. Defaults to ``None``. ''') add_chinese_doc('prompter.PrompterBase.get_response', '''\ @@ -3124,6 +3126,8 @@ def extract_result(output, inputs): tools (Option[List[Dict]]): 工具参数,可忽略,默认None。 label (Option[str]): 标签,可忽略,默认None。 show (bool): 是否打印返回内容,默认为False。 + return_dict (bool): 已弃用,请改用 ``format="openai"``。当 ``format`` 为 ``None`` 且该参数为 True 时,与 ``format="openai"`` 行为一致并记录一次弃用告警。 + format (Option[str]): 若为非空(例如 ``"openai"``),则返回 ``{"messages": [{"role": "user", "content": input}]}``;否则直接返回 ``input``。若同时传入 ``return_dict`` 与本参数,以本参数为准。 ''') add_english_doc('prompter.EmptyPrompter.generate_prompt', '''\ @@ -3137,6 +3141,8 @@ def extract_result(output, inputs): tools (Option[List[Dict]]): Tool definitions, ignored. Defaults to None. label (Option[str]): Label, ignored. Defaults to None. show (bool): Whether to print the returned prompt. Defaults to False. + return_dict (bool): Deprecated; prefer ``format="openai"``. When ``format`` is ``None`` and this is True, behaves like ``format="openai"`` with a one-time deprecation warning. + format (Option[str]): If set (e.g. ``"openai"``), returns ``{"messages": [{"role": "user", "content": input}]}``; otherwise returns ``input`` unchanged. If both ``return_dict`` and ``format`` are provided, ``format`` takes precedence. ''') add_english_doc('prompter.builtinPrompt.LazyLLMPrompterBase', '''\ @@ -3209,19 +3215,19 @@ def extract_result(output, inputs): >>> p = AlpacaPrompter('hello world {instruction}') >>> p.generate_prompt('this is my input') 'You are an AI-Agent developed by LazyLLM.\\\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\\\n\\\\n ### Instruction:\\\\nhello world this is my input\\\\n\\\\n\\\\n### Response:\\\\n' ->>> p.generate_prompt('this is my input', return_dict=True) +>>> p.generate_prompt('this is my input', format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\\\n\\\\n ### Instruction:\\\\nhello world this is my input\\\\n\\\\n'}, {'role': 'user', 'content': ''}]} >>> >>> p = AlpacaPrompter('hello world {instruction}, {input}', extra_keys=['knowledge']) >>> p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm')) 'You are an AI-Agent developed by LazyLLM.\\\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\\\n\\\\n ### Instruction:\\\\nhello world hello world, my input\\\\n\\\\nHere are some extra messages you can referred to:\\\\n\\\\n### knowledge:\\\\nlazyllm\\\\n\\\\n\\\\n### Response:\\\\n' ->>> p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'), return_dict=True) +>>> p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'), format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\\\n\\\\n ### Instruction:\\\\nhello world hello world, my input\\\\n\\\\nHere are some extra messages you can referred to:\\\\n\\\\n### knowledge:\\\\nlazyllm\\\\n\\\\n'}, {'role': 'user', 'content': ''}]} >>> >>> p = AlpacaPrompter(dict(system="hello world", user="this is user instruction {input}")) >>> p.generate_prompt(dict(input="my input")) 'You are an AI-Agent developed by LazyLLM.\\\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\\\n\\\\n ### Instruction:\\\\nhello word\\\\n\\\\n\\\\n\\\\nthis is user instruction my input### Response:\\\\n' ->>> p.generate_prompt(dict(input="my input"), return_dict=True) +>>> p.generate_prompt(dict(input="my input"), format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\\\n\\\\n ### Instruction:\\\\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input'}]} ''') @@ -3259,7 +3265,7 @@ def extract_result(output, inputs): >>> p.generate_prompt('this is my input') 'You are an AI-Agent developed by LazyLLM.hello world\\\\nthis is my input\\\\n' ->>> p.generate_prompt('this is my input', return_dict=True) +>>> p.generate_prompt('this is my input', format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\\\nhello world'}, {'role': 'user', 'content': 'this is my input'}]} - Using extra_keys @@ -3284,7 +3290,7 @@ def extract_result(output, inputs): >>> p.generate_prompt({'input': "my input", 'query': "this is user query"}) 'You are an AI-Agent developed by LazyLLM.hello world\\\\nthis is user instruction my input this is user query\\\\n' ->>> p.generate_prompt({'input': "my input", 'query': "this is user query"}, return_dict=True) +>>> p.generate_prompt({'input': "my input", 'query': "this is user query"}, format='openai') {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\\\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input this is user query'}]} ''') diff --git a/tests/basic_tests/Components/test_component.py b/tests/basic_tests/Components/test_component.py index c6a5262fd..5bd5b1812 100644 --- a/tests/basic_tests/Components/test_component.py +++ b/tests/basic_tests/Components/test_component.py @@ -5,37 +5,36 @@ class TestPrompter(object): def test_prompter(self): p = lazyllm.Prompter(prompt='hello world2 <{input}>') - assert not p._is_empty(), "Prompter should not be empty" + assert not p._is_empty(), 'Prompter should not be empty' def test_generate_prompt(self): p = lazyllm.Prompter(prompt='hello world2 <{input}>') result = p.generate_prompt('123') - assert result == 'hello world2 <123>', f"Expected 'hello world2 <123>', but got '{result}'" + assert result == 'hello world2 <123>', 'unexpected: ' + repr(result) def test_generate_prompt_dict_input(self): p = lazyllm.Prompter(prompt='hello world2 <{input}>') result_dict_input = p.generate_prompt({'input': '123'}) - assert result_dict_input == 'hello world2 <123>', \ - f"Expected 'hello world2 <123>', but got '{result_dict_input}'" + assert result_dict_input == 'hello world2 <123>', 'unexpected: ' + repr(result_dict_input) def test_from_template(self): p = lazyllm.Prompter.from_template('alpaca') expected_prompt = ( - "Below is an instruction that describes a task, paired with an input that provides further context. " - "Write a response that appropriately completes the request.\n\n### Instruction:\n{instruction}\n\n### " - "Input:\n{input}\n\n### Response:\n" + 'Below is an instruction that describes a task, paired with an input that provides further context. ' + 'Write a response that appropriately completes the request.\n\n### Instruction:\n{instruction}\n\n### ' + 'Input:\n{input}\n\n### Response:\n' ) - assert p._prompt == expected_prompt, f"Expected prompt to be '{expected_prompt}', but got '{p._prompt}'" + assert p._prompt == expected_prompt, 'unexpected prompt: ' + repr(p._prompt) def test_generate_prompt_with_template(self): p = lazyllm.Prompter.from_template('alpaca') result = p.generate_prompt(dict(instruction='ins', input='inp')) expected_result = ( - "Below is an instruction that describes a task, paired with an input that provides further context. " - "Write a response that appropriately completes the request.\n\n### Instruction:\nins\n\n### " - "Input:\ninp\n\n### Response:\n" + 'Below is an instruction that describes a task, paired with an input that provides further context. ' + 'Write a response that appropriately completes the request.\n\n### Instruction:\nins\n\n### ' + 'Input:\ninp\n\n### Response:\n' ) - assert result == expected_result, f"Expected '{expected_result}', but got '{result}'" + assert result == expected_result, 'unexpected: ' + repr(result) class TestAlpacaPrompter(object): @@ -43,15 +42,16 @@ def test_basic_prompter(self): p = lazyllm.AlpacaPrompter('请完成加法运算, 输入为{instruction}') r = p.generate_prompt('a+b') assert r == 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n### Instruction:\n请完成加法运算, 输入为a+b\n\n\n\n### Response:\n' # noqa E501 - r = p.generate_prompt('a+b', return_dict=True) + r = p.generate_prompt('a+b', format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n### Instruction:\n请完成加法运算, 输入为a+b\n\n'}, # noqa E501 {'role': 'user', 'content': ''}]} + assert p.generate_prompt('a+b', return_dict=True) == r p = lazyllm.AlpacaPrompter('请完成加法运算', extra_keys='input') r = p.generate_prompt('a+b') assert r == 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n### Instruction:\n请完成加法运算\n\nHere are some extra messages you can referred to:\n\n### input:\na+b\n\n\n\n### Response:\n' # noqa E501 - r = p.generate_prompt('a+b', return_dict=True) + r = p.generate_prompt('a+b', format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n### Instruction:\n请完成加法运算\n\nHere are some extra messages you can referred to:\n\n### input:\na+b\n\n'}, # noqa E501 {'role': 'user', 'content': ''}]} @@ -59,7 +59,7 @@ def test_basic_prompter(self): p = lazyllm.AlpacaPrompter(dict(system='请完成加法运算', user='输入为{instruction}')) r = p.generate_prompt('a+b') assert r == 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n### Instruction:\n请完成加法运算\n\n输入为a+b### Response:\n' # noqa E501 - r = p.generate_prompt('a+b', return_dict=True) + r = p.generate_prompt('a+b', format='openai') assert r == {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n### Instruction:\n请完成加法运算'}, {'role': 'user', 'content': '输入为a+b'}]} # noqa E501 @@ -68,7 +68,7 @@ def test_basic_prompter(self): p = lazyllm.ChatPrompter('请完成加法运算, 输入为{instruction}') r = p.generate_prompt('a+b') assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算, 输入为a+b\n\n\n\n\n\n\n\n' - r = p.generate_prompt('a+b', return_dict=True) + r = p.generate_prompt('a+b', format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算, 输入为a+b\n\n'}, {'role': 'user', 'content': ''}]} @@ -76,7 +76,7 @@ def test_basic_prompter(self): p = lazyllm.ChatPrompter('请完成加法运算', extra_keys='input') r = p.generate_prompt('a+b') assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算\nHere are some extra messages you can referred to:\n\n### input:\na+b\n\n\n\n\n\n\n\n\n' # noqa E501 - r = p.generate_prompt('a+b', return_dict=True) + r = p.generate_prompt('a+b', format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算\nHere are some extra messages you can referred to:\n\n### input:\na+b\n\n\n'}, # noqa E501 {'role': 'user', 'content': ''}]} @@ -84,7 +84,7 @@ def test_basic_prompter(self): p = lazyllm.ChatPrompter(dict(system='请完成加法运算', user='输入为{instruction}')) r = p.generate_prompt('a+b') assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算\n\n\n\n输入为a+b\n\n' - r = p.generate_prompt('a+b', return_dict=True) + r = p.generate_prompt('a+b', format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算'}, {'role': 'user', 'content': '输入为a+b'}]} @@ -94,7 +94,7 @@ def test_history(self): history=[['输入为a+b', 'a+b'], ['输入为c+d', 'c+d']]) r = p.generate_prompt('e+f') assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算\n\n输入为a+ba+b输入为c+dc+d\n\n输入为e+f\n\n' - r = p.generate_prompt('e+f', return_dict=True) + r = p.generate_prompt('e+f', format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算'}, {'role': 'user', 'content': '输入为a+b'}, @@ -107,7 +107,7 @@ def test_history(self): r = p.generate_prompt('e+f', history=[['输入为a+b', 'a+b'], ['输入为c+d', 'c+d']]) assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算\n\n输入为a+ba+b输入为c+dc+d\n\n输入为e+f\n\n' - r = p.generate_prompt('e+f', history=[['输入为a+b', 'a+b'], ['输入为c+d', 'c+d']], return_dict=True) + r = p.generate_prompt('e+f', history=[['输入为a+b', 'a+b'], ['输入为c+d', 'c+d']], format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算'}, {'role': 'user', 'content': '输入为a+b'}, @@ -117,12 +117,12 @@ def test_history(self): {'role': 'user', 'content': '输入为e+f'}]} p = lazyllm.ChatPrompter(dict(system='请完成加法运算', user='输入为{instruction}'), history=[['输入为a+b', 'a+b']]) - r = p.generate_prompt('e+f', history=[{"role": "user", "content": '输入为c+d'}, - {"role": "assistant", "content": 'c+d'}]) + r = p.generate_prompt('e+f', history=[{'role': 'user', 'content': '输入为c+d'}, + {'role': 'assistant', 'content': 'c+d'}]) assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算\n\n输入为a+ba+b输入为c+dc+d\n\n输入为e+f\n\n' - r = p.generate_prompt('e+f', history=[{"role": "user", "content": '输入为c+d'}, - {"role": "assistant", "content": 'c+d'}], return_dict=True) + r = p.generate_prompt('e+f', history=[{'role': 'user', 'content': '输入为c+d'}, + {'role': 'assistant', 'content': 'c+d'}], format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算'}, {'role': 'user', 'content': '输入为a+b'}, @@ -134,11 +134,11 @@ def test_history(self): def test_empty_prompt_with_history(self): p = lazyllm.ChatPrompter('', history=[['输入为a+b', 'a+b']]) r11 = p.generate_prompt('c+d') - r12 = p.generate_prompt('c+d', return_dict=True) + r12 = p.generate_prompt('c+d', format='openai') p = lazyllm.ChatPrompter(None, history=[['输入为a+b', 'a+b']]) r21 = p.generate_prompt('c+d') - r22 = p.generate_prompt('c+d', return_dict=True) + r22 = p.generate_prompt('c+d', format='openai') assert r11 == r21 == 'You are an AI-Agent developed by LazyLLM.\n\n输入为a+ba+b\n\nc+d\n\n' assert r12 == r22 == {'messages': [ @@ -152,18 +152,18 @@ def test_configs(self): p._set_model_configs(sos='', eos='') r = p.generate_prompt('a+b') assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算\n\n\n\n输入为a+b\n\n' - r = p.generate_prompt('a+b', return_dict=True) + r = p.generate_prompt('a+b', format='openai') assert r == {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算'}, {'role': 'user', 'content': '输入为a+b'}]} # noqa E501 def test_config_with_history(self): p = lazyllm.ChatPrompter(dict(system='请完成加法运算', user='输入为{instruction}'), history=[['输入为a+b', 'a+b']]) p._set_model_configs(sos='', eos='', soh='', eoh='', soa='', eoa='') - r = p.generate_prompt('e+f', history=[{"role": "user", "content": '输入为c+d'}, - {"role": "assistant", "content": 'c+d'}]) + r = p.generate_prompt('e+f', history=[{'role': 'user', 'content': '输入为c+d'}, + {'role': 'assistant', 'content': 'c+d'}]) assert r == 'You are an AI-Agent developed by LazyLLM.请完成加法运算\n\n输入为a+ba+b输入为c+dc+d\n\n输入为e+f\n\n' # noqa E501 - r = p.generate_prompt('e+f', history=[{"role": "user", "content": '输入为c+d'}, - {"role": "assistant", "content": 'c+d'}], return_dict=True) + r = p.generate_prompt('e+f', history=[{'role': 'user', 'content': '输入为c+d'}, + {'role': 'assistant', 'content': 'c+d'}], format='openai') assert r == {'messages': [ {'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\n请完成加法运算'}, {'role': 'user', 'content': '输入为a+b'}, @@ -175,16 +175,16 @@ def test_config_with_history(self): class TestLLMType(object): def test_llm_type(self): - assert LLMType("llm") == LLMType.LLM - assert LLMType("LLM") == LLMType.LLM + assert LLMType('llm') == LLMType.LLM + assert LLMType('LLM') == LLMType.LLM assert LLMType(LLMType.LLM) == LLMType.LLM - assert LLMType.LLM == "llm" - assert "llm" == LLMType.LLM - assert LLMType.LLM == "LLM" - assert "LLM" == LLMType.LLM + assert LLMType.LLM == 'llm' + assert 'llm' == LLMType.LLM + assert LLMType.LLM == 'LLM' + assert 'LLM' == LLMType.LLM assert LLMType.LLM in ('LLM',) assert LLMType.LLM in (LLMType.LLM,) assert LLMType.LLM in ('llm',) assert 'llm' in (LLMType.LLM,) - assert LLMType("CROSS_modal_embed") == LLMType.CROSS_MODAL_EMBED - assert LLMType("CROSS_MODAL_EMBED") == LLMType.CROSS_MODAL_EMBED + assert LLMType('CROSS_modal_embed') == LLMType.CROSS_MODAL_EMBED + assert LLMType('CROSS_MODAL_EMBED') == LLMType.CROSS_MODAL_EMBED