From fd8c991393a3ac3ca87aa44becabd1bf1e95e88f Mon Sep 17 00:00:00 2001 From: ehhuang Date: Tue, 4 Mar 2025 13:08:16 -0800 Subject: [PATCH] fix: rag as attachment bug (#1392) Summary: Test Plan: added new test LLAMA_STACK_CONFIG=fireworks pytest -s -v tests/api/agents/test_agents.py --safety-shield meta-llama/Llama-Guard-3-8B --- .../agents/meta_reference/agent_instance.py | 5 +- tests/integration/agents/test_agents.py | 23 +- .../recorded_responses/chat_completion.json | 4156 +++++++++++++++-- .../recorded_responses/chat_completion.pickle | Bin 541735 -> 684331 bytes .../recorded_responses/invoke_tool.json | 49 +- .../recorded_responses/invoke_tool.pickle | Bin 52685 -> 53903 bytes 6 files changed, 3830 insertions(+), 403 deletions(-) diff --git a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py index 886a36024..921beac27 100644 --- a/llama_stack/providers/inline/agents/meta_reference/agent_instance.py +++ b/llama_stack/providers/inline/agents/meta_reference/agent_instance.py @@ -534,7 +534,10 @@ class ChatAgent(ShieldRunnerMixin): session_info = await self.storage.get_session_info(session_id) # if the session has a memory bank id, let the memory tool use it if session_info and session_info.vector_db_id: - toolgroup_args[RAG_TOOL_GROUP]["vector_db_ids"].append(session_info.vector_db_id) + if RAG_TOOL_GROUP not in toolgroup_args: + toolgroup_args[RAG_TOOL_GROUP] = {"vector_db_ids": [session_info.vector_db_id]} + else: + toolgroup_args[RAG_TOOL_GROUP]["vector_db_ids"].append(session_info.vector_db_id) output_attachments = [] diff --git a/tests/integration/agents/test_agents.py b/tests/integration/agents/test_agents.py index ca97eb692..f221582c8 100644 --- a/tests/integration/agents/test_agents.py +++ b/tests/integration/agents/test_agents.py @@ -401,7 +401,19 @@ def test_rag_agent(llama_stack_client_with_mocked_inference, agent_config, rag_t assert expected_kw in response.output_message.content.lower() -def test_rag_agent_with_attachments(llama_stack_client_with_mocked_inference, agent_config): +@pytest.mark.parametrize( + "toolgroup", + [ + dict( + name="builtin::rag/knowledge_search", + args={ + "vector_db_ids": [], + }, + ), + "builtin::rag/knowledge_search", + ], +) +def test_rag_agent_with_attachments(llama_stack_client_with_mocked_inference, agent_config, toolgroup): urls = ["chat.rst", "llama3.rst", "memory_optimizations.rst", "lora_finetune.rst"] documents = [ Document( @@ -414,14 +426,7 @@ def test_rag_agent_with_attachments(llama_stack_client_with_mocked_inference, ag ] agent_config = { **agent_config, - "toolgroups": [ - dict( - name="builtin::rag/knowledge_search", - args={ - "vector_db_ids": [], - }, - ) - ], + "toolgroups": [toolgroup], } rag_agent = Agent(llama_stack_client_with_mocked_inference, agent_config) session_id = rag_agent.create_session(f"test-session-{uuid4()}") diff --git a/tests/integration/fixtures/recorded_responses/chat_completion.json b/tests/integration/fixtures/recorded_responses/chat_completion.json index 8a4bae93d..021b6c936 100644 --- a/tests/integration/fixtures/recorded_responses/chat_completion.json +++ b/tests/integration/fixtures/recorded_responses/chat_completion.json @@ -102,22 +102,7 @@ { "event": { "delta": { - "text": " boiling point of polyjuice is -100 degrees", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " Fahrenheit.", + "text": " boiling point of polyjuice is -100 degrees Fahrenheit.", "type": "text" }, "event_type": { @@ -381,7 +366,7 @@ "celcius": "false", "liquid_name": "polyjuice" }, - "call_id": "f9d5523a-6d3a-4cfc-b02d-a1204b591a86", + "call_id": "b9ded2e6-bef1-40bc-8a5b-a8c1018d0ba2", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -624,7 +609,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "name\": \"get_boiling_point\", \"parameters\": {\"liquid_name", + "tool_call": "name\": \"get_boiling_point\",", "type": "tool_call" }, "event_type": { @@ -643,7 +628,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\": \"polyjuice\", \"celcius\": \"true", + "tool_call": " \"parameters\": {\"liquid_name\": \"polyju", "type": "tool_call" }, "event_type": { @@ -662,7 +647,26 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\"}}", + "tool_call": "ice\", \"celcius\":", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " \"true\"}}", "type": "tool_call" }, "event_type": { @@ -686,7 +690,7 @@ "celcius": "true", "liquid_name": "polyjuice" }, - "call_id": "874df3c4-bc63-4f21-9353-4d0e4ce9c347", + "call_id": "98c011b5-f5de-416e-9a06-c2e3d0fa5581", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -827,7 +831,22 @@ { "event": { "delta": { - "text": " boiling point of polyjuice is -100\u00b0C.", + "text": " boiling point of polyjuice is -100\u00b0C", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ".", "type": "text" }, "event_type": { @@ -1046,7 +1065,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "{\"type\": \"function\", \"name\":", + "tool_call": "{\"type\": \"function\", \"name", "type": "tool_call" }, "event_type": { @@ -1065,7 +1084,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " \"get_boiling_point\", \"parameters", + "tool_call": "\": \"get_boiling_point\", \"parameters", "type": "tool_call" }, "event_type": { @@ -1084,7 +1103,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\": {\"liquid_name\": \"polyjuice\", \"cel", + "tool_call": "\": {\"liquid_name\": \"polyjuice\", \"celci", "type": "tool_call" }, "event_type": { @@ -1103,7 +1122,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "cius\": \"true\"}}", + "tool_call": "us\": \"true\"}}", "type": "tool_call" }, "event_type": { @@ -1127,7 +1146,7 @@ "celcius": "true", "liquid_name": "polyjuice" }, - "call_id": "832c5abc-4369-4a2e-b85f-e7452f634e6c", + "call_id": "15326d2e-d284-4c7e-86b1-5bfbba74a914", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -1200,22 +1219,7 @@ { "event": { "delta": { - "text": " customer smiled and said \"hello\" to the friendly store", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " clerk.", + "text": " customer smiled and said \"hello\" to the friendly store clerk.", "type": "text" }, "event_type": { @@ -1634,6 +1638,269 @@ ], "type": "generator" }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv file, can you describe it?', context=None), ToolResponseMessage(role='tool', call_id='', tool_name=, content=[TextContentItem(type='text', text='# User provided a file accessible to you at \"\"\\nYou can use code_interpreter to load and inspect it.')]), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\ndf = pd.read_csv(\"\")\\nprint(df.head())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\"), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\ndf = pd.read_csv(\"\")\\nprint(df.head())\\nprint(df.info())\\nprint(df.describe())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)}), ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "The", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " error message indicates that the `bwrap.core` module is", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " not found. This is likely because the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " `bwrap` package is not installed. To fix this,", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " you can install the `bwrap` package", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " using pip:\n\n```\npip install bwrap", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "\n```\n\nHowever, if you don't", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " have permission to install packages, you can use", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the `knowledge_search` function to get information about", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the CSV file instead:\n\n```\n{\n ", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " \"type\": \"function\",\n \"name\": \"", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "knowledge_search\",\n \"parameters\": {\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " \"query\": \"describe a csv file\"\n }\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "}\n```\n\nThis will return a description of", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the CSV file.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv file, can you describe it?', context=None), ToolResponseMessage(role='tool', call_id='', tool_name=, content=[TextContentItem(type='text', text='# User provided a file accessible to you at \"\"\\nYou can use code_interpreter to load and inspect it.')]), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\ndf = pd.read_csv(\"\")\\nprint(df.head())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\"), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\ndf = pd.read_csv(\"\")\\nprint(df.head())\\nprint(df.info())\\nprint(df.describe())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)}), ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { "chunks": [ { @@ -1852,6 +2119,208 @@ ], "type": "generator" }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv file, can you describe it?', context=None), ToolResponseMessage(role='tool', call_id='', tool_name=, content=[TextContentItem(type='text', text='# User provided a file accessible to you at \"\"\\nYou can use code_interpreter to load and inspect it.')]), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\ndf = pd.read_csv(\"\")\\nprint(df.head())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)}), ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "started" + }, + "tool_call": "", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "import pandas as pd\ndf = pd.read", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "_csv(\"/var/folders/cz/vyh7y1d11", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "xg881lsxsshnc5c0000gn/T/tmpc_", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "ozqkdv/GwQ6oJB4inflation", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": ".csv\")\nprint(df.head())\nprint(df.info())\nprint(df.describe", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "())", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "succeeded" + }, + "tool_call": { + "arguments": { + "code": "import pandas as pd\ndf = pd.read_csv(\"/var/folders/cz/vyh7y1d11xg881lsxsshnc5c0000gn/T/tmpc_ozqkdv/GwQ6oJB4inflation.csv\")\nprint(df.head())\nprint(df.info())\nprint(df.describe())" + }, + "call_id": "551648f3-c903-44ef-84ae-0f1dcbaaa68f", + "tool_name": { + "__enum__": "BuiltinTool", + "value": "code_interpreter" + } + }, + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv file, can you describe it?', context=None), ToolResponseMessage(role='tool', call_id='', tool_name=, content=[TextContentItem(type='text', text='# User provided a file accessible to you at \"\"\\nYou can use code_interpreter to load and inspect it.')]), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\ndf = pd.read_csv(\"\")\\nprint(df.head())'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)}), ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { "chunks": [ { @@ -2097,7 +2566,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "import pandas as pd\ndf = pd.read_csv(\"/var", + "tool_call": "import pandas as pd\ndf = pd.read", "type": "tool_call" }, "event_type": { @@ -2116,7 +2585,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "/folders/cz/vyh7y1d11xg", + "tool_call": "_csv(\"/var/folders/cz/vyh", "type": "tool_call" }, "event_type": { @@ -2135,7 +2604,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "881lsxsshnc5c0000gn/T/tmpkbnyor", + "tool_call": "7y1d11xg881lsxsshnc5c", "type": "tool_call" }, "event_type": { @@ -2154,7 +2623,45 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "uj/fzDfYIPeinflation.csv\")\ndf.head()", + "tool_call": "0000gn/T/tmpc_ozqkdv/Gw", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "Q6oJB4inflation.csv\")\n", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "print(df.head())", "type": "tool_call" }, "event_type": { @@ -2175,9 +2682,9 @@ }, "tool_call": { "arguments": { - "code": "import pandas as pd\ndf = pd.read_csv(\"/var/folders/cz/vyh7y1d11xg881lsxsshnc5c0000gn/T/tmpkbnyoruj/fzDfYIPeinflation.csv\")\ndf.head()" + "code": "import pandas as pd\ndf = pd.read_csv(\"/var/folders/cz/vyh7y1d11xg881lsxsshnc5c0000gn/T/tmpc_ozqkdv/GwQ6oJB4inflation.csv\")\nprint(df.head())" }, - "call_id": "df6b121d-9ad2-4d15-9fae-26c31f4c13c5", + "call_id": "204b3ad9-ff20-4fab-a055-13da99874d88", "tool_name": { "__enum__": "BuiltinTool", "value": "code_interpreter" @@ -3698,6 +4205,1107 @@ ], "type": "generator" }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv, can you describe it?', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\n# Load data\\ndf = pd.read_csv(\"\")\\n# Rows\\nprint(\"Number of rows and columns in the data:\", df.shape)\\n# Columns\\nprint(\"Columns of the data are:\", len(df.columns))\\n# Column names\\nprint(\"Columns of the data are:\", df.columns)\\n# Column dtypes\\nprint(\"Datatype of the columns are:\", df.dtypes)'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\"), CompletionMessage(role='assistant', content='It seems that the file \"\" does not exist. \\n\\nTo describe the csv file, you need to provide the actual file path or the file itself. If you are using a remote server, you can use the `requests` library to download the file and then load it into a pandas dataframe. \\n\\nHere is an example of how you can do it:\\n\\n```\\nimport pandas as pd\\nimport requests\\n\\n# Download the csv file\\nurl = \"https://example.com/your_file.csv\"\\nresponse = requests.get(url)\\n\\n# Load the csv file into a pandas dataframe\\ndf = pd.read_csv(response.content)\\n\\n# Print the description of the dataframe\\nprint(df.describe())\\n```\\n\\nPlease replace the `url` variable with the actual URL of your csv file. \\n\\nIf you are using a local file, you can simply use the `pd.read_csv()` function with the file path:\\n\\n```\\nimport pandas as pd\\n\\n# Load the csv file into a pandas dataframe\\ndf = pd.read_csv(\\'your_file.csv\\')\\n\\n# Print the description of the dataframe\\nprint(df.describe())\\n```\\n\\nPlease replace `\\'your_file.csv\\'` with the actual path to your csv file.', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Plot average yearly inflation as a time series', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\nimport matplotlib.pyplot as plt\\n\\n# Load data\\ndf = pd.read_csv(\"\")\\n\\n# Convert \\'Year\\' column to datetime\\ndf[\\'Year\\'] = pd.to_datetime(df[\\'Year\\'])\\n\\n# Group by year and calculate average inflation\\naverage_inflation = df.groupby(\\'Year\\')[\\'Inflation\\'].mean().reset_index()\\n\\n# Plot average yearly inflation as a time series\\nplt.figure(figsize=(10,6))\\nplt.plot(average_inflation[\\'Year\\'], average_inflation[\\'Inflation\\'], marker=\\'o\\')\\nplt.title(\\'Average Yearly Inflation\\')\\nplt.xlabel(\\'Year\\')\\nplt.ylabel(\\'Inflation Rate\\')\\nplt.grid(True)\\nplt.show()'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "It", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " seems that the file \"/var/f", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "olders/cz/vyh7y", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "1d11xg881lsx", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "sshnc5c0000gn", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "/T/tmpc_ozqkdv/EzGU", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "QEnJinflation.csv\" does", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " not exist. \n\nTo plot the average yearly inflation as a", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " time series, you need to provide the actual file path or", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the file itself. If you are using a remote server,", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " you can use the `requests` library to download the file", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " and then load it into a pandas dataframe. \n\nHere", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " is an example of how you can do it:\n\n```\nimport", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " pandas as pd\nimport matplotlib.pyplot as plt\nimport requests\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "# Download the csv file\nurl = \"https://example.com", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "/your_file.csv\"\nresponse = requests.get(url)\n\n# Load", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the csv file into a pandas dataframe\ndf = pd.read_csv", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "(response.content)\n\n# Convert 'Year' column to datetime\ndf", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "['Year'] = pd.to_datetime(df['Year'])\n\n# Group", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " by year and calculate average inflation\naverage_inflation = df.groupby", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "('Year')['Inflation'].mean().reset_index()\n\n# Plot", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " average yearly inflation as a time series\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "plt.figure(figsize=(10,6))\nplt.plot(average_in", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "flation['Year'], average_inflation['Inflation'], marker='", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "o')\nplt.title('Average Yearly Inflation')\nplt.xlabel", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "('Year')\nplt.ylabel('Inflation Rate')\nplt.grid(True", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ")\nplt.show()\n```\n\nPlease replace the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " `url` variable with the actual URL of", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " your csv file. \n\nIf you", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " are using a local file, you can", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " simply use the `pd.read_csv()` function with the file", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " path:\n\n```\nimport pandas as pd\nimport matplotlib.pyplot as", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " plt\n\n# Load the csv file into a pandas dataframe\ndf", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " = pd.read_csv('your_file.csv')\n\n# Convert 'Year", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "' column to datetime\ndf['Year'] = pd.to_datetime", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "(df['Year'])\n\n# Group by", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " year and calculate average inflation\naverage_inflation = df.groupby('", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "Year')['Inflation'].mean().reset_index()\n\n# Plot average", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " yearly inflation as a time series\nplt.figure", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "(figsize=(10,6))\nplt.plot(average_inflation", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "['Year'], average_inflation['Inflation'], marker='o", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "')\nplt.title('Average Yearly Inflation')\nplt.xlabel('", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "Year')\nplt.ylabel('Inflation Rate')\nplt.grid(True)\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "plt.show()\n```\n\nPlease replace `'", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "your_file.csv'` with the actual", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " path to your csv file.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv, can you describe it?', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\n# Load data\\ndf = pd.read_csv(\"\")\\n# Rows\\nprint(\"Number of rows and columns in the data:\", df.shape)\\n# Columns\\nprint(\"Columns of the data are:\", len(df.columns))\\n# Column names\\nprint(\"Columns of the data are:\", df.columns)\\n# Column dtypes\\nprint(\"Datatype of the columns are:\", df.dtypes)'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\"), CompletionMessage(role='assistant', content='It seems that the file \"\" does not exist. \\n\\nTo describe the csv file, you need to provide the actual file path or the file itself. If you are using a remote server, you can use the `requests` library to download the file and then load it into a pandas dataframe. \\n\\nHere is an example of how you can do it:\\n\\n```\\nimport pandas as pd\\nimport requests\\n\\n# Download the csv file\\nurl = \"https://example.com/your_file.csv\"\\nresponse = requests.get(url)\\n\\n# Load the csv file into a pandas dataframe\\ndf = pd.read_csv(response.content)\\n\\n# Print the description of the dataframe\\nprint(df.describe())\\n```\\n\\nPlease replace the `url` variable with the actual URL of your csv file. \\n\\nIf you are using a local file, you can simply use the `pd.read_csv()` function with the file path:\\n\\n```\\nimport pandas as pd\\n\\n# Load the csv file into a pandas dataframe\\ndf = pd.read_csv(\\'your_file.csv\\')\\n\\n# Print the description of the dataframe\\nprint(df.describe())\\n```\\n\\nPlease replace `\\'your_file.csv\\'` with the actual path to your csv file.', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Plot average yearly inflation as a time series', context=None)])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "started" + }, + "tool_call": "", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "import pandas as pd\nimport matplotlib.pyplot as plt\n\n# Load", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " data\ndf = pd.read_csv(\"/var/folders/cz", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "/vyh7y1d11x", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "g881lsxsshnc5c0000gn/T/tmpc", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "_ozqkdv/EzGUQEnJinflation", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": ".csv\")\n\n# Convert 'Year' column", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " to datetime\ndf['Year'] = pd.to_datetime(df['", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "Year'])\n\n# Group by year and calculate average inflation\naverage_in", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "flation = df.groupby('Year')['Inflation'].mean().reset", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "_index()\n\n# Plot average yearly inflation as a time series\nplt", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": ".figure(figsize=(10,6))\nplt", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": ".plot(average_inflation['Year'], average_inflation['In", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "flation'], marker='o')\nplt.title('Average Yearly Inflation')\n", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "plt.xlabel('Year')\nplt.ylabel('Inflation Rate')\nplt.grid(True", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": ")\nplt.show()", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "succeeded" + }, + "tool_call": { + "arguments": { + "code": "import pandas as pd\nimport matplotlib.pyplot as plt\n\n# Load data\ndf = pd.read_csv(\"/var/folders/cz/vyh7y1d11xg881lsxsshnc5c0000gn/T/tmpc_ozqkdv/EzGUQEnJinflation.csv\")\n\n# Convert 'Year' column to datetime\ndf['Year'] = pd.to_datetime(df['Year'])\n\n# Group by year and calculate average inflation\naverage_inflation = df.groupby('Year')['Inflation'].mean().reset_index()\n\n# Plot average yearly inflation as a time series\nplt.figure(figsize=(10,6))\nplt.plot(average_inflation['Year'], average_inflation['Inflation'], marker='o')\nplt.title('Average Yearly Inflation')\nplt.xlabel('Year')\nplt.ylabel('Inflation Rate')\nplt.grid(True)\nplt.show()" + }, + "call_id": "7e62f796-c5cd-4021-a651-b0048b75a083", + "tool_name": { + "__enum__": "BuiltinTool", + "value": "code_interpreter" + } + }, + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Here is a csv, can you describe it?', context=None), ToolResponseMessage(role='tool', call_id='', tool_name=, content=[TextContentItem(type='text', text='# User provided a file accessible to you at \"\"\\nYou can use code_interpreter to load and inspect it.')]), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'code': 'import pandas as pd\\n# Load data\\ndf = pd.read_csv(\"\")\\n# Rows\\nprint(\"Number of rows and columns in the data:\", df.shape)\\n# Columns\\nprint(\"Columns of the data are:\", len(df.columns))\\n# Column names\\nprint(\"Columns of the data are:\", df.columns)\\n# Column dtypes\\nprint(\"Datatype of the columns are:\", df.dtypes)'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content=\"completed\\n[stderr]\\nTraceback (most recent call last):\\n line 5, in \\n from bwrap.core import main\\nModuleNotFoundError: No module named 'bwrap.core'\\n[/stderr]\")])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Execute code', parameters={'code': ToolParamDefinition(param_type='string', description='The code to execute', required=True, default=None)})])]": { "chunks": [ { @@ -3748,7 +5356,7 @@ { "event": { "delta": { - "text": "olders/cz/vyh7y1", + "text": "olders/cz/vyh7y1d11x", "type": "text" }, "event_type": { @@ -3763,7 +5371,7 @@ { "event": { "delta": { - "text": "d11xg881lsxsshnc5c0000", + "text": "g881lsxsshnc5c000", "type": "text" }, "event_type": { @@ -3778,7 +5386,7 @@ { "event": { "delta": { - "text": "gn/T/tmpkbnyoruj/lbnHmUP", + "text": "0gn/T/tmpc", "type": "text" }, "event_type": { @@ -3793,7 +5401,7 @@ { "event": { "delta": { - "text": "2inflation.csv\" does not exist. \n\nTo describe", + "text": "_ozqkdv/EzGUQEnJinflation", "type": "text" }, "event_type": { @@ -3808,7 +5416,7 @@ { "event": { "delta": { - "text": " the csv file, you need to provide the actual file", + "text": ".csv\" does not exist. \n\nTo", "type": "text" }, "event_type": { @@ -3823,7 +5431,7 @@ { "event": { "delta": { - "text": " path or the file itself. If you are using a local file", + "text": " describe the csv file, you need to provide the actual file", "type": "text" }, "event_type": { @@ -3838,7 +5446,7 @@ { "event": { "delta": { - "text": ", you can use the `load_data` function from the `", + "text": " path or the file itself. If you", "type": "text" }, "event_type": { @@ -3853,7 +5461,7 @@ { "event": { "delta": { - "text": "code_interpreter` library to load the file. \n\nHere is", + "text": " are using a remote server, you can use the `requests` library", "type": "text" }, "event_type": { @@ -3868,7 +5476,7 @@ { "event": { "delta": { - "text": " an example of how you can do it:\n\n```\nimport pandas", + "text": " to download the file and then load it into a pandas dataframe. \n\nHere", "type": "text" }, "event_type": { @@ -3883,7 +5491,7 @@ { "event": { "delta": { - "text": " as pd\nfrom code_interpreter import load_data\n\n# Load", + "text": " is an example of how you can do it:\n\n```\nimport pandas as", "type": "text" }, "event_type": { @@ -3898,7 +5506,7 @@ { "event": { "delta": { - "text": " data\ndf = load_data('inflation.csv')\n\n# Print", + "text": " pd\nimport requests\n\n# Download the csv file\nurl = \"https", "type": "text" }, "event_type": { @@ -3913,7 +5521,7 @@ { "event": { "delta": { - "text": " summary of the data\nprint(df.head())\nprint(df.info())\n", + "text": "://example.com/your_file.csv\"\nresponse = requests.get(url)\n\n#", "type": "text" }, "event_type": { @@ -3928,7 +5536,7 @@ { "event": { "delta": { - "text": "print(df.describe())\n```\n\nThis will load the csv file and print", + "text": " Load the csv file into a pandas dataframe\ndf", "type": "text" }, "event_type": { @@ -3943,7 +5551,7 @@ { "event": { "delta": { - "text": " the first few rows, a summary of the data, and some descriptive statistics", + "text": " = pd.read_csv(response.content)\n\n# Print", "type": "text" }, "event_type": { @@ -3958,7 +5566,7 @@ { "event": { "delta": { - "text": ". \n\nPlease replace 'inflation.csv' with the actual path to your", + "text": " the description of the dataframe\nprint", "type": "text" }, "event_type": { @@ -3973,7 +5581,7 @@ { "event": { "delta": { - "text": " csv file. \n\nIf you are using a", + "text": "(df.describe())\n```\n\nPlease replace the `url`", "type": "text" }, "event_type": { @@ -3988,7 +5596,7 @@ { "event": { "delta": { - "text": " remote file, you need to provide the actual file path or", + "text": " variable with the actual URL of your csv file. \n\nIf", "type": "text" }, "event_type": { @@ -4003,7 +5611,7 @@ { "event": { "delta": { - "text": " the file itself. \n\nPlease provide the actual file path or the", + "text": " you are using a", "type": "text" }, "event_type": { @@ -4018,7 +5626,7 @@ { "event": { "delta": { - "text": " file itself, and I will be happy to help you describe it", + "text": " local file, you can simply use the `pd.read_csv", "type": "text" }, "event_type": { @@ -4033,7 +5641,112 @@ { "event": { "delta": { - "text": ".", + "text": "()` function with the file path:\n\n```\nimport pandas as", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " pd\n\n#", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " Load the csv file into a pandas", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " dataframe\ndf = pd.read_csv('your", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_file.csv')\n\n# Print the description of", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the dataframe\nprint(df.describe())\n``", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "`\n\nPlease replace `'your_file.csv'` with the actual path", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " to your csv file.", "type": "text" }, "event_type": { @@ -4109,7 +5822,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "import pandas as pd\n# Load", + "tool_call": "import pandas as pd\n# Load data\ndf = pd", "type": "tool_call" }, "event_type": { @@ -4128,7 +5841,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " data\ndf = pd.read_csv(\"/", + "tool_call": ".read_csv(\"/var", "type": "tool_call" }, "event_type": { @@ -4147,7 +5860,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "var/f", + "tool_call": "/folders/cz/vyh7y1d11xg881", "type": "tool_call" }, "event_type": { @@ -4166,7 +5879,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "olders/cz/vyh7y1d11x", + "tool_call": "lsxsshnc5c0000gn/T/tmpc_oz", "type": "tool_call" }, "event_type": { @@ -4185,7 +5898,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "g881lsxsshnc5c000", + "tool_call": "qkdv/EzGUQEnJinflation.csv\")\n", "type": "tool_call" }, "event_type": { @@ -4204,7 +5917,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "0gn/T/tmpkbnyoruj/l", + "tool_call": "# Rows\nprint(\"Number of rows and columns in the data", "type": "tool_call" }, "event_type": { @@ -4223,7 +5936,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "bnHmUP2inflation", + "tool_call": ":\", df.shape)\n# Columns\nprint(\"Columns of the data", "type": "tool_call" }, "event_type": { @@ -4242,7 +5955,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": ".csv\")\n# Rows\nprint(\"", + "tool_call": " are:\", len(df.columns))\n# Column names\n", "type": "tool_call" }, "event_type": { @@ -4261,7 +5974,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "Number of rows and columns in the data", + "tool_call": "print(\"Columns of the data are:\", df.columns)\n", "type": "tool_call" }, "event_type": { @@ -4280,7 +5993,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": ":\", df.shape)\n# Columns\n", + "tool_call": "# Column dtypes\nprint(\"Datatype of", "type": "tool_call" }, "event_type": { @@ -4299,83 +6012,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "print(\"Columns of the data are:\", len", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": "(df.columns))\n# Column names\nprint(\"", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": "Columns of the data are:\", df.columns)\n# Column dt", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": "ypes\nprint(\"Datatype of the columns are:\", df", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": ".dtypes)", + "tool_call": " the columns are:\", df.dtypes)", "type": "tool_call" }, "event_type": { @@ -4396,9 +6033,9 @@ }, "tool_call": { "arguments": { - "code": "import pandas as pd\n# Load data\ndf = pd.read_csv(\"/var/folders/cz/vyh7y1d11xg881lsxsshnc5c0000gn/T/tmpkbnyoruj/lbnHmUP2inflation.csv\")\n# Rows\nprint(\"Number of rows and columns in the data:\", df.shape)\n# Columns\nprint(\"Columns of the data are:\", len(df.columns))\n# Column names\nprint(\"Columns of the data are:\", df.columns)\n# Column dtypes\nprint(\"Datatype of the columns are:\", df.dtypes)" + "code": "import pandas as pd\n# Load data\ndf = pd.read_csv(\"/var/folders/cz/vyh7y1d11xg881lsxsshnc5c0000gn/T/tmpc_ozqkdv/EzGUQEnJinflation.csv\")\n# Rows\nprint(\"Number of rows and columns in the data:\", df.shape)\n# Columns\nprint(\"Columns of the data are:\", len(df.columns))\n# Column names\nprint(\"Columns of the data are:\", df.columns)\n# Column dtypes\nprint(\"Datatype of the columns are:\", df.dtypes)" }, - "call_id": "c2d44218-eea1-408d-b332-cd82574e2b4e", + "call_id": "e57ec9d1-68d8-4493-b3d3-0fb683a4663a", "tool_name": { "__enum__": "BuiltinTool", "value": "code_interpreter" @@ -4439,6 +6076,1745 @@ ], "type": "generator" }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:71183\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:84988\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')]), CompletionMessage(role='assistant', content='You can ask your question now. I will help you answer it using the knowledge_search tool results.', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Tell me how to use LoRA', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'How to use LoRA'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text=\"Result 1:\\nDocument_id:98cad\\nContent: .. _lora_finetune_label:\\n\\n============================\\nFine-Tuning Llama2 with LoRA\\n============================\\n\\nThis guide will teach you about `LoRA `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 3:\\nDocument_id:84988\\nContent: with training with LoRA quickly,\\njust specify any config with ``_lora`` in its name, e.g:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\\n\\n\\nThere are two sets of parameters to customize LoRA to suit your needs. Firstly, the parameters which control\\nwhich linear layers LoRA should be applied to in the model:\\n\\n* ``lora_attn_modules: List[str]`` accepts a list of strings specifying which layers of the model to apply\\n LoRA to:\\n\\n * ``q_proj`` applies LoRA to the query projection layer.\\n * ``k_proj`` applies LoRA to the key projection layer.\\n * ``v_proj`` applies LoRA to the value projection layer.\\n * ``output_proj`` applies LoRA to the attention output projection layer.\\n\\n Whilst adding more layers to be fine-tuned may improve model accuracy,\\n this will come at the cost of increased memory usage and reduced training speed.\\n\\n* ``apply_lora_to_mlp: Bool`` applies LoRA to the MLP in each transformer layer.\\n* ``apply_lora_to_output: Bool`` applies LoRA to the model\\'s final output projection.\\n This is usually a projection to vocabulary space (e.g. in language models), but\\n other modelling tasks may have different projections - classifier models will project\\n to the number of classes, for example\\n\\n.. note::\\n\\n Models which use tied embeddings (such as Gemma and Qwen2 1.5B and 0.5B) for the\\n final output projection do not support ``apply_lora_to_output``.\\n\\nThese are all specified under the ``model`` flag or config entry, i.e:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\",\"output_proj\"]\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.llama3.lora_llama3_8b\\n apply_lora_to_mlp: True\\n model.lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\",\"output_proj\"]\\n\\nSecondly, parameters which control the scale of the impact of LoRA on the model:\\n\\n* ``lora_rank: int`` affects the scale of\\n'), TextContentItem(type='text', text='Result 4:\\nDocument_id:98cad\\nContent: LoRA to Llama2 models\\n------------------------------\\n\\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\\nLet\\'s take a look at how to construct Llama2 models in torchtune with and without LoRA.\\n\\n.. code-block:: python\\n\\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\\n\\n # Build Llama2 without any LoRA layers\\n base_model = llama2_7b()\\n\\n # The default settings for lora_llama2_7b will match those for llama2_7b\\n # We just need to define which layers we want LoRA applied to.\\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\\n # layers outside of the self-attention.\\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\\n\\n.. note::\\n\\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\\n See :ref:`below` for how to do this.\\n\\nLet\\'s inspect each of these models a bit more closely.\\n\\n.. code-block:: bash\\n\\n # Print the first layer\\'s self-attention in the usual Llama2 model\\n >>> print(base_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (pos_embeddings): RotaryPositionalEmbeddings()\\n )\\n\\n # Print the same for Llama2 with LoRA weights\\n >>> print(lora_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): LoRALinear(\\n (dropout): Dropout(p=0.0, inplace=False)\\n \\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:9c730\\nContent: ora_finetune_label>`.\\nFor more on QLoRA in torchtune, see our :ref:`QLoRA Tutorial `.\\n\\nLet\\'s take a look at how we can fine-tune Llama3-8B-Instruct with LoRA on a single device using torchtune. In this example, we will fine-tune\\nfor one epoch on a common instruct dataset for illustrative purposes. The basic command for a single-device LoRA fine-tune is\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\\n\\n.. note::\\n To see a full list of recipes and their corresponding configs, simply run ``tune ls`` from the command line.\\n\\nWe can also add :ref:`command-line overrides ` as needed, e.g.\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n checkpointer.checkpoint_dir= \\\\\\n tokenizer.path=/tokenizer.model \\\\\\n checkpointer.output_dir=\\n\\nThis will load the Llama3-8B-Instruct checkpoint and tokenizer from ```` used in the :ref:`tune download ` command above,\\nthen save a final checkpoint in the same directory following the original format. For more details on the\\ncheckpoint formats supported in torchtune, see our :ref:`checkpointing deep-dive `.\\n\\n.. note::\\n To see the full set of configurable parameters for this (and other) configs we can use :ref:`tune cp ` to copy (and modify)\\n the default config. :ref:`tune cp ` can be used with recipe scripts too, in case you want to make more custom changes\\n that cannot be achieved by directly modifying existing configurable parameters. For more on :ref:`tune cp ` see the section on\\n :ref:`modifying configs ` in our \":ref:`finetune_llama_label`\" tutorial.\\n\\nOnce training is complete, the model checkpoints will be saved and their locations will be logged. For\\nLoRA fine-tuning, the final checkpoint will contain the merged weights, and a copy of just the (much smaller) LoRA weights\\nwill\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')])])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "To", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " use LoRA, you can follow these steps", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ":\n\n1. Install the necessary packages", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ", including torchtune and the Llama2 model.\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "2. Load the Llama2 model and specify which", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " layers to apply LoRA to.\n3.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " Define the LoRA parameters, such as the rank and", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " alpha values.\n4. Train the model using", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the LoRA fine-tuning recipe in torchtune", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ".\n5. Use the trained model for inference or further fine", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "-tuning.\n\nHere is an example of how to apply Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA to Llama2-7B:\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "```python\nfrom torchtune.models.llama2 import", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " llama2_7b, lora_llama2", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_7b\n\n# Build Llama2 without any Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA layers\nbase_model = llama2_7b()\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "# The default settings for lora_llama", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "2_7b will match those for", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " llama2_7b\n# We just need to define", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " which layers we want LoRA applied to.\n# Within each", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " self-attention, we can choose from [\"q_proj\",", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " \"k_proj\", \"v_proj\", and \"output_proj\"]", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ".\n# We can also set apply_lora_to_mlp=True", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " or apply_lora_to_output=True to apply LoRA to other", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " linear\n# layers outside of the self-", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "attention.\nlora_model = lora_llama2_7", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "```\n\nYou can also customize the LoRA parameters", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " by specifying the rank and alpha values:\n\n```python", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "\nlora_model = lora_llama2_7b", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "(lora_attn_modules=[\"q_proj\", \"v_proj\"],", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " lora_rank=8, lora_alpha=16)\n``", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "`\n\nTo train the model using the LoRA", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " fine-tuning recipe in torchtune, you can use", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the following command:\n\n```bash\ntune run lora_f", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "inetune_single_device --config llama3/8B_l", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "ora_single_device\n```\n\nThis will", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " load the Llama3-8B-Instruct checkpoint and", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " tokenizer from the specified directory, then save a final checkpoint in the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " same directory following the original format.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:71183\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:84988\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')]), CompletionMessage(role='assistant', content='You can ask your question now. I will help you answer it using the knowledge_search tool results.', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Tell me how to use LoRA', context=None)])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "{\"", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "type\": \"function\", \"name\": \"knowledge_search", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "\", \"parameters\": {\"query\": \"How to use Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA\"}}", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "succeeded" + }, + "tool_call": { + "arguments": { + "query": "How to use LoRA" + }, + "call_id": "ee82ce77-7143-4b2f-8eb8-de5f31517b84", + "tool_name": "knowledge_search" + }, + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:71183\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:84988\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')])])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "You", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " can ask your question now. I will help you answer it using", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the knowledge_search tool results.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:7bdfa\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:0c95c\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')]), CompletionMessage(role='assistant', content='You can use the following function call to answer the user\\'s question:\\n\\n{\"type\": \"function\", \"name\": \"knowledge_search\", \"parameters\": {\"query\": \"How to fine-tune a Llama2 model with LoRA in torchtune\"}}', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Tell me how to use LoRA', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'How to use LoRA'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text=\"Result 1:\\nDocument_id:64211\\nContent: .. _lora_finetune_label:\\n\\n============================\\nFine-Tuning Llama2 with LoRA\\n============================\\n\\nThis guide will teach you about `LoRA `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 3:\\nDocument_id:0c95c\\nContent: with training with LoRA quickly,\\njust specify any config with ``_lora`` in its name, e.g:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\\n\\n\\nThere are two sets of parameters to customize LoRA to suit your needs. Firstly, the parameters which control\\nwhich linear layers LoRA should be applied to in the model:\\n\\n* ``lora_attn_modules: List[str]`` accepts a list of strings specifying which layers of the model to apply\\n LoRA to:\\n\\n * ``q_proj`` applies LoRA to the query projection layer.\\n * ``k_proj`` applies LoRA to the key projection layer.\\n * ``v_proj`` applies LoRA to the value projection layer.\\n * ``output_proj`` applies LoRA to the attention output projection layer.\\n\\n Whilst adding more layers to be fine-tuned may improve model accuracy,\\n this will come at the cost of increased memory usage and reduced training speed.\\n\\n* ``apply_lora_to_mlp: Bool`` applies LoRA to the MLP in each transformer layer.\\n* ``apply_lora_to_output: Bool`` applies LoRA to the model\\'s final output projection.\\n This is usually a projection to vocabulary space (e.g. in language models), but\\n other modelling tasks may have different projections - classifier models will project\\n to the number of classes, for example\\n\\n.. note::\\n\\n Models which use tied embeddings (such as Gemma and Qwen2 1.5B and 0.5B) for the\\n final output projection do not support ``apply_lora_to_output``.\\n\\nThese are all specified under the ``model`` flag or config entry, i.e:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\",\"output_proj\"]\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.llama3.lora_llama3_8b\\n apply_lora_to_mlp: True\\n model.lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\",\"output_proj\"]\\n\\nSecondly, parameters which control the scale of the impact of LoRA on the model:\\n\\n* ``lora_rank: int`` affects the scale of\\n'), TextContentItem(type='text', text='Result 4:\\nDocument_id:64211\\nContent: LoRA to Llama2 models\\n------------------------------\\n\\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\\nLet\\'s take a look at how to construct Llama2 models in torchtune with and without LoRA.\\n\\n.. code-block:: python\\n\\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\\n\\n # Build Llama2 without any LoRA layers\\n base_model = llama2_7b()\\n\\n # The default settings for lora_llama2_7b will match those for llama2_7b\\n # We just need to define which layers we want LoRA applied to.\\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\\n # layers outside of the self-attention.\\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\\n\\n.. note::\\n\\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\\n See :ref:`below` for how to do this.\\n\\nLet\\'s inspect each of these models a bit more closely.\\n\\n.. code-block:: bash\\n\\n # Print the first layer\\'s self-attention in the usual Llama2 model\\n >>> print(base_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (pos_embeddings): RotaryPositionalEmbeddings()\\n )\\n\\n # Print the same for Llama2 with LoRA weights\\n >>> print(lora_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): LoRALinear(\\n (dropout): Dropout(p=0.0, inplace=False)\\n \\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:1d70c\\nContent: ora_finetune_label>`.\\nFor more on QLoRA in torchtune, see our :ref:`QLoRA Tutorial `.\\n\\nLet\\'s take a look at how we can fine-tune Llama3-8B-Instruct with LoRA on a single device using torchtune. In this example, we will fine-tune\\nfor one epoch on a common instruct dataset for illustrative purposes. The basic command for a single-device LoRA fine-tune is\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\\n\\n.. note::\\n To see a full list of recipes and their corresponding configs, simply run ``tune ls`` from the command line.\\n\\nWe can also add :ref:`command-line overrides ` as needed, e.g.\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n checkpointer.checkpoint_dir= \\\\\\n tokenizer.path=/tokenizer.model \\\\\\n checkpointer.output_dir=\\n\\nThis will load the Llama3-8B-Instruct checkpoint and tokenizer from ```` used in the :ref:`tune download ` command above,\\nthen save a final checkpoint in the same directory following the original format. For more details on the\\ncheckpoint formats supported in torchtune, see our :ref:`checkpointing deep-dive `.\\n\\n.. note::\\n To see the full set of configurable parameters for this (and other) configs we can use :ref:`tune cp ` to copy (and modify)\\n the default config. :ref:`tune cp ` can be used with recipe scripts too, in case you want to make more custom changes\\n that cannot be achieved by directly modifying existing configurable parameters. For more on :ref:`tune cp ` see the section on\\n :ref:`modifying configs ` in our \":ref:`finetune_llama_label`\" tutorial.\\n\\nOnce training is complete, the model checkpoints will be saved and their locations will be logged. For\\nLoRA fine-tuning, the final checkpoint will contain the merged weights, and a copy of just the (much smaller) LoRA weights\\nwill\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')])])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "To", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " use LoRA, you can follow these steps:\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "1. Install the necessary packages", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ", including torchtune and the Llama", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "2 model.\n2. Load the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " Llama2 model and specify which layers", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " to apply LoRA to.\n3. Define the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " LoRA parameters, such as the rank", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " and alpha values.\n4. Train the model using", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the LoRA fine-tuning recipe in torchtune.\n\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "Here is an example of how to use Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA with the Llama2 model:\n\n```python\nfrom", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " torchtune.models.llama2 import", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " llama2_7b, lora_llama2_7", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "b\n\n# Build Llama2 without any LoRA layers\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "base_model = llama2_7b()\n\n# The default settings", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " for lora_llama2_7b will match those", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " for llama2_7b\n#", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " We just need to define which layers we", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " want LoRA applied to.\n# Within each self-attention", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ", we can choose from [\"q_proj\", \"k_proj", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "\", \"v_proj\", and \"output_proj\"].\n#", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " We can also set apply_lora_to_mlp=True or", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " apply_lora_to_output=True to apply LoRA to other", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " linear\n# layers outside of the self-attention.\nl", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "ora_model = lora_llama", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "2_7b(lora_attn", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "_modules=[\"q_proj\", \"v_proj\"])\n\n# Print the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " first layer's self-attention in the usual Llama2", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " model\nprint(base_model.layers[0", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "].attn)\n# Print the same for Llama2 with", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " LoRA weights\nprint(lora_model.layers[0].", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "attn)\n```\n\nThis code will load the Llama", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "2 model and apply LoRA to the", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " specified layers. You can then train the model using the Lo", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "RA fine-tuning recipe in torchtune", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": ".\n\nNote that you will need to modify the code to suit", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " your specific use case and requirements. Additionally,", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " you may need to adjust the LoRA parameters and the training", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " settings to achieve the desired results.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:7bdfa\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:0c95c\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')]), CompletionMessage(role='assistant', content='You can use the following function call to answer the user\\'s question:\\n\\n{\"type\": \"function\", \"name\": \"knowledge_search\", \"parameters\": {\"query\": \"How to fine-tune a Llama2 model with LoRA in torchtune\"}}', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Tell me how to use LoRA', context=None)])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "{\"", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "type\": \"function\", \"name\": \"knowledge_search\", \"", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "parameters\": {\"query\": \"How to use LoRA\"}}", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "succeeded" + }, + "tool_call": { + "arguments": { + "query": "How to use LoRA" + }, + "call_id": "ce86a63d-964a-49a0-8488-29c28ecb2f80", + "tool_name": "knowledge_search" + }, + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:7bdfa\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:0c95c\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')])])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "You", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " can use the following function call to answer", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " the user's question:\n\n{\"type\": \"function\", \"", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "name\": \"knowledge_search\", \"parameters\": {\"query\":", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " \"How to fine-tune a L", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "lama2 model with LoRA in torch", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "tune\"}}", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='I am attaching some documentation for Torchtune. Help me answer questions I will ask next.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'Torchtune documentation'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text='Result 1:\\nDocument_id:c4b2d\\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\\nlook like so:\\n\\n.. code-block:: python\\n\\n from torchtune.datasets import chat_dataset\\n from torchtune.models.llama3 import llama3_tokenizer\\n\\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\\n ds = chat_dataset(\\n tokenizer=tokenizer,\\n source=\"json\",\\n data_files=\"data/my_data.json\",\\n split=\"train\",\\n conversation_column=\"dialogue\",\\n conversation_style=\"sharegpt\",\\n )\\n\\n.. code-block:: yaml\\n\\n # In config\\n tokenizer:\\n _component_: torchtune.models.llama3.llama3_tokenizer\\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\\n\\n dataset:\\n _component_: torchtune.datasets.chat_dataset\\n source: json\\n data_files: data/my_data.json\\n split: train\\n conversation_column: dialogue\\n conversation_style: sharegpt\\n\\n.. note::\\n You can pass in any keyword argument for `load_dataset `_ into all our\\n Dataset classes and they will honor them. This is useful for common parameters\\n such as specifying the data split with :code:`split` or configuration with\\n :code:`name`\\n\\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\\nSince we\\'re fine-tuning Llama3, the tokenizer will handle all formatting for\\nus and prompt templates are optional. Other models such as Mistral\\'s :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:e37c3\\nContent: etune\\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.use_dora=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n use_dora: True\\n\\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\\neven more memory savings!\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\\\\n model.lora_rank=16 \\\\\\n model.lora_alpha=32 \\\\\\n model.use_dora=True \\\\\\n model.quantize_base=True\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.lora_llama3_8b\\n apply_lora_to_mlp: True\\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\\n lora_rank: 16\\n lora_alpha: 32\\n use_dora: True\\n quantize_base: True\\n\\n\\n.. note::\\n\\n Under the hood, we\\'ve enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\\n\\n.. _glossary_distrib:\\n\\n\\n.. TODO\\n\\n.. Distributed\\n.. -----------\\n\\n.. .. _glossary_fsdp:\\n\\n.. Fully Sharded Data Parallel (FSDP)\\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\\n.. All our ``_distributed`` recipes use `FSDP `.\\n.. .. _glossary_fsdp2:\\n\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')]), CompletionMessage(role='assistant', content='You can use the following function call to answer the user\\'s question:\\n\\n{\"type\": \"function\", \"name\": \"knowledge_search\", \"parameters\": {\"query\": \"How to fine-tune a Llama2 model with LoRA in torchtune\"}}', stop_reason=, tool_calls=[]), UserMessage(role='user', content='Tell me how to use LoRA', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name='knowledge_search', arguments={'query': 'How to use LoRA'})]), ToolResponseMessage(role='tool', call_id='', tool_name='knowledge_search', content=[TextContentItem(type='text', text='knowledge_search tool found 5 chunks:\\nBEGIN of knowledge_search tool results.\\n'), TextContentItem(type='text', text=\"Result 1:\\nDocument_id:606ad\\nContent: .. _lora_finetune_label:\\n\\n============================\\nFine-Tuning Llama2 with LoRA\\n============================\\n\\nThis guide will teach you about `LoRA `_, a parameter-efficient finetuning technique,\\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\\nIf you already know what LoRA is and want to get straight to running\\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\\n\\n.. grid:: 2\\n\\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\\n\\n * What LoRA is and how it saves memory during finetuning\\n * An overview of LoRA components in torchtune\\n * How to run a LoRA finetune using torchtune\\n * How to experiment with different LoRA configurations\\n\\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\\n\\n * Be familiar with :ref:`torchtune`\\n * Make sure to :ref:`install torchtune`\\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\\n\\nWhat is LoRA?\\n-------------\\n\\n`LoRA `_ is an adapter-based method for\\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\\ntransformer models, in which case it is common to add the low-rank matrices\\nto some of the linear projections in each transformer layer's self-attention.\\n\\n.. note::\\n\\n If you're unfamiliar, check out these references for the `definition of rank `_\\n and discussion of `low-rank approximations `_.\\n\\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\\nyou can expect to see memory savings due to a substantial reduction in the\\nnumber of parameters with gradients. When using an optimizer with momentum,\\nlike `AdamW `_.\\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\\n\\n.. code-block:: bash\\n\\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\\n\\n.. note::\\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\\n for more details on how you can easily clone and modify torchtune configs.\\n\\n.. note::\\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\\n and (b) the memory constraints of your hardware.\\n\\nThe preceding command will run a LoRA finetune with torchtune\\'s factory settings, but we may want to experiment a bit.\\nLet\\'s take a closer look at some of the :code:`lora_finetune_distributed` config.\\n\\n.. code-block:: yaml\\n\\n # Model Arguments\\n model:\\n _component_: lora_llama2_7b\\n lora_attn_modules: [\\'q_proj\\', \\'v_proj\\']\\n lora_rank: 8\\n lora_alpha: 16\\n ...\\n\\nWe see that the\\n'), TextContentItem(type='text', text='Result 3:\\nDocument_id:e37c3\\nContent: with training with LoRA quickly,\\njust specify any config with ``_lora`` in its name, e.g:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\\n\\n\\nThere are two sets of parameters to customize LoRA to suit your needs. Firstly, the parameters which control\\nwhich linear layers LoRA should be applied to in the model:\\n\\n* ``lora_attn_modules: List[str]`` accepts a list of strings specifying which layers of the model to apply\\n LoRA to:\\n\\n * ``q_proj`` applies LoRA to the query projection layer.\\n * ``k_proj`` applies LoRA to the key projection layer.\\n * ``v_proj`` applies LoRA to the value projection layer.\\n * ``output_proj`` applies LoRA to the attention output projection layer.\\n\\n Whilst adding more layers to be fine-tuned may improve model accuracy,\\n this will come at the cost of increased memory usage and reduced training speed.\\n\\n* ``apply_lora_to_mlp: Bool`` applies LoRA to the MLP in each transformer layer.\\n* ``apply_lora_to_output: Bool`` applies LoRA to the model\\'s final output projection.\\n This is usually a projection to vocabulary space (e.g. in language models), but\\n other modelling tasks may have different projections - classifier models will project\\n to the number of classes, for example\\n\\n.. note::\\n\\n Models which use tied embeddings (such as Gemma and Qwen2 1.5B and 0.5B) for the\\n final output projection do not support ``apply_lora_to_output``.\\n\\nThese are all specified under the ``model`` flag or config entry, i.e:\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n model.apply_lora_to_mlp=True \\\\\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\",\"output_proj\"]\\n\\n.. code-block:: yaml\\n\\n model:\\n _component_: torchtune.models.llama3.lora_llama3_8b\\n apply_lora_to_mlp: True\\n model.lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\",\"output_proj\"]\\n\\nSecondly, parameters which control the scale of the impact of LoRA on the model:\\n\\n* ``lora_rank: int`` affects the scale of\\n'), TextContentItem(type='text', text='Result 4:\\nDocument_id:606ad\\nContent: LoRA to Llama2 models\\n------------------------------\\n\\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\\nLet\\'s take a look at how to construct Llama2 models in torchtune with and without LoRA.\\n\\n.. code-block:: python\\n\\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\\n\\n # Build Llama2 without any LoRA layers\\n base_model = llama2_7b()\\n\\n # The default settings for lora_llama2_7b will match those for llama2_7b\\n # We just need to define which layers we want LoRA applied to.\\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\\n # layers outside of the self-attention.\\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\\n\\n.. note::\\n\\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\\n See :ref:`below` for how to do this.\\n\\nLet\\'s inspect each of these models a bit more closely.\\n\\n.. code-block:: bash\\n\\n # Print the first layer\\'s self-attention in the usual Llama2 model\\n >>> print(base_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\\n (pos_embeddings): RotaryPositionalEmbeddings()\\n )\\n\\n # Print the same for Llama2 with LoRA weights\\n >>> print(lora_model.layers[0].attn)\\n MultiHeadAttention(\\n (q_proj): LoRALinear(\\n (dropout): Dropout(p=0.0, inplace=False)\\n \\n'), TextContentItem(type='text', text='Result 5:\\nDocument_id:0b7ba\\nContent: ora_finetune_label>`.\\nFor more on QLoRA in torchtune, see our :ref:`QLoRA Tutorial `.\\n\\nLet\\'s take a look at how we can fine-tune Llama3-8B-Instruct with LoRA on a single device using torchtune. In this example, we will fine-tune\\nfor one epoch on a common instruct dataset for illustrative purposes. The basic command for a single-device LoRA fine-tune is\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\\n\\n.. note::\\n To see a full list of recipes and their corresponding configs, simply run ``tune ls`` from the command line.\\n\\nWe can also add :ref:`command-line overrides ` as needed, e.g.\\n\\n.. code-block:: bash\\n\\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\\\\n checkpointer.checkpoint_dir= \\\\\\n tokenizer.path=/tokenizer.model \\\\\\n checkpointer.output_dir=\\n\\nThis will load the Llama3-8B-Instruct checkpoint and tokenizer from ```` used in the :ref:`tune download ` command above,\\nthen save a final checkpoint in the same directory following the original format. For more details on the\\ncheckpoint formats supported in torchtune, see our :ref:`checkpointing deep-dive `.\\n\\n.. note::\\n To see the full set of configurable parameters for this (and other) configs we can use :ref:`tune cp ` to copy (and modify)\\n the default config. :ref:`tune cp ` can be used with recipe scripts too, in case you want to make more custom changes\\n that cannot be achieved by directly modifying existing configurable parameters. For more on :ref:`tune cp ` see the section on\\n :ref:`modifying configs ` in our \":ref:`finetune_llama_label`\" tutorial.\\n\\nOnce training is complete, the model checkpoints will be saved and their locations will be logged. For\\nLoRA fine-tuning, the final checkpoint will contain the merged weights, and a copy of just the (much smaller) LoRA weights\\nwill\\n'), TextContentItem(type='text', text='END of knowledge_search tool results.\\n')])])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name='knowledge_search', description='Search for information in a database.', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for. Can be a natural language sentence or keywords.', required=True, default=None)})])]": { "chunks": [ { @@ -6446,7 +9822,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "{\"type\": \"function\", \"name", + "tool_call": "{\"type\": \"function\", \"name\": \"knowledge_search", "type": "tool_call" }, "event_type": { @@ -6465,7 +9841,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\": \"knowledge_search\", \"parameters\": {\"query\": \"Tor", + "tool_call": "\", \"parameters\": {\"query\": \"", "type": "tool_call" }, "event_type": { @@ -6484,7 +9860,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "chtune documentation\"}}", + "tool_call": "Torchtune documentation\"}}", "type": "tool_call" }, "event_type": { @@ -6507,7 +9883,7 @@ "arguments": { "query": "Torchtune documentation" }, - "call_id": "96e0974a-8831-4440-af01-9d42c2a46306", + "call_id": "6ec2bf0f-42f3-453d-ad5f-52bc6e0267b7", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -6580,7 +9956,7 @@ { "event": { "delta": { - "text": "lama3-8B uses grouped-query attention", + "text": "lama3-8B uses grouped-query attention instead of the standard multi-head", "type": "text" }, "event_type": { @@ -6595,22 +9971,7 @@ { "event": { "delta": { - "text": " instead of the standard multi-head attention from Llama2-7", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": "B.", + "text": " attention from Llama2-7B.", "type": "text" }, "event_type": { @@ -6678,22 +10039,7 @@ { "event": { "delta": { - "text": " attention type used by Llama3-8B is grouped-query", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " attention.", + "text": " attention type used by Llama3-8B is grouped-query attention.", "type": "text" }, "event_type": { @@ -6761,7 +10107,7 @@ { "event": { "delta": { - "text": " \"type\": \"function\",\n \"name\": \"knowledge", + "text": " \"type\": \"function\",\n ", "type": "text" }, "event_type": { @@ -6776,7 +10122,7 @@ { "event": { "delta": { - "text": "_search\",\n \"parameters\": {\n \"query\": \"L", + "text": " \"name\": \"knowledge_search\",\n \"parameters\": {\n \"", "type": "text" }, "event_type": { @@ -6791,7 +10137,37 @@ { "event": { "delta": { - "text": "lama3-8B attention type\"\n }\n}", + "text": "query\": \"Llama3", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "-8B attention type\"\n }\n", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "}", "type": "text" }, "event_type": { @@ -6814,7 +10190,7 @@ "arguments": { "query": "Llama3-8B attention type" }, - "call_id": "8c86f3e4-1312-4857-8baa-91e23bfd33a4", + "call_id": "95471ab3-196c-45ba-a7f1-7585026662c2", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -6895,7 +10271,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "{\"type\": \"function\", \"name\": \"knowledge_search\",", + "tool_call": "{\"type\": \"function\", \"name\": \"knowledge_search\", \"", "type": "tool_call" }, "event_type": { @@ -6914,26 +10290,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " \"parameters\": {\"query\": \"Llama3-8B", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": " attention type\"}}", + "tool_call": "parameters\": {\"query\": \"Llama3-8B attention type\"}}", "type": "tool_call" }, "event_type": { @@ -6956,7 +10313,7 @@ "arguments": { "query": "Llama3-8B attention type" }, - "call_id": "652117f8-9427-4090-a0c7-c7d03f94ea74", + "call_id": "f026154f-72fb-47aa-828c-065bd5a16267", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -6994,6 +10351,74 @@ ], "type": "generator" }, + "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Search the web and tell me who the current CEO of Meta is.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'query': 'current CEO of Meta'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content='{\"query\": \"current CEO of Meta\", \"top_k\": [{\"title\": \"Executives - Meta\", \"url\": \"https://about.meta.com/media-gallery/executives/\", \"content\": \"Mark Zuckerberg, Founder, Chairman and Chief Executive Officer Joel Kaplan, Chief Global Affairs Officer Susan Li, Chief Financial Officer Javier Olivan, Chief Operating Officer Chris Cox, Chief Product Officer Andrew \\\\u2018Boz\\\\u2019 Bosworth, Chief Technology Officer Jennifer Newstead, Chief Legal Officer Dave Wehner, Chief Strategy Officer Will Cathcart, Head of WhatsApp Naomi Gleit, Head of Product John Hegeman, Chief Revenue Officer Adam Mosseri, Head of Instagram Erin Egan, Chief Privacy Officer, Policy Michel Protti, Chief Privacy Officer, Product Alex Schultz, Chief Marketing Officer and VP of Analytics Tom Alison, Head of Facebook Nicola Mendelsohn, Head of Global Business Group Ahmad Al-Dahle, VP and Head of GenAI at Meta Joelle Pineau, Vice President of AI Research and Head of FAIR at Meta\", \"score\": 0.8190992, \"raw_content\": null}, {\"title\": \"Mark Zuckerberg, Founder, Chairman and Chief Executive Officer - Meta\", \"url\": \"https://about.meta.com/media-gallery/executives/mark-zuckerberg/\", \"content\": \"Mark Zuckerberg, Founder, Chairman and Chief Executive Officer | Meta Meta Quest Ray-Ban Meta Meta Horizon Meta AI Meta Verified Meta Pay Meta Horizon Workrooms Meta and you Learn about our community Shop Meta Meta Quest Meta Portal Meta Horizon Mark Zuckerberg is the founder, chairman and CEO of Meta, which he originally founded as Facebook in 2004. In October 2021, Facebook rebranded to Meta to reflect all of its products and services across its family of apps and a focus on developing social experiences for the metaverse \\\\u2014 moving beyond 2D screens toward immersive experiences like augmented and virtual reality to help build the next evolution in social technology. Shop Ray-Ban Meta glassesRay-Ban StoriesPrivacy informationSupported countries \\\\u00a9 2025 Meta\", \"score\": 0.79099923, \"raw_content\": null}, {\"title\": \"Meet the Executive CSuite Team of Meta (Facebook) [2025]\", \"url\": \"https://digitaldefynd.com/IQ/meet-the-executive-csuite-team-of-meta-facebook/\", \"content\": \"Harvard University Executive Programs Free Harvard University Courses As a chief financial officer of Meta, Susan Li oversees the firm\\\\u2019s finance and facilities team to keep track of the company\\\\u2019s overall financial health. The chief operating officer of Meta, Javier Olivan, oversees the firm\\\\u2019s business team, infrastructure, and other products. Andrew Bosworth, called Boz, serves as chief technology officer at Meta and is responsible for leading the firm\\\\u2019s AR/VR organization, Reality Labs. Andrew has also served as engineering director to oversee events, mobile monetization, and feed ads and as VP of ads and business platforms to lead engineering, design, analytics, and product teams. Meta\\\\u2019s c-suite team comprises experienced and diverse executives, having extensive experience in technology, finance, legal, and all major industries.\", \"score\": 0.7602419, \"raw_content\": null}, {\"title\": \"Meta to spend up to $65 billion this year to power AI goals, Zuckerberg ...\", \"url\": \"https://www.reuters.com/technology/meta-invest-up-65-bln-capital-expenditure-this-year-2025-01-24/\", \"content\": \"Meta Platforms plans to spend as much as $65 billion this year to expand its AI infrastructure, CEO Mark Zuckerberg said on Friday, aiming to bolster the company\\'s position against rivals OpenAI\", \"score\": 0.73914057, \"raw_content\": null}, {\"title\": \"Mark Zuckerberg - Forbes\", \"url\": \"https://www.forbes.com/profile/mark-zuckerberg/\", \"content\": \"Meta CEO Mark Zuckerberg \\\\u201cloved\\\\u201d an image on Facebook known as \\\\\"Challah Horse\\\\\" that happens to be AI-generated, highlighting the amount of AI spam on the platform. ### Meta Donates $1 Million To Trump\\\\u2019s Inaugural Fund Weeks After Mark Zuckerberg Met President Elect Meta has donated $1 million to President-elect Donald Trump\\\\u2019s inaugural fund, the company confirmed to various news outlets on Wednesday, a move that comes just weeks after its CEO Mark Zuckerberg met with Trump at his Mar-a-Lago residence in an apparent bid to mend years of strained ties. ### Meta Donates $1 Million To Trump\\\\u2019s Inaugural Fund Weeks After Mark Zuckerberg Met President-Elect Read the full profile on Forbes: https://www.forbes.com/sites/kerryadolan/2023/09/26/mark-gets-meta-zuckerberg-talks-ai-and-that-musk-mma-fight-thats-never-going-to-happen/?sh=671046e73037\", \"score\": 0.6410185, \"raw_content\": null}]}')])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Search the web for information', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for', required=True, default=None)})])]": { + "chunks": [ + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "start" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "The", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " current CEO of Meta is Mark Zuckerberg.", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "complete" + }, + "logprobs": null, + "stop_reason": { + "__enum__": "StopReason", + "value": "end_of_turn" + } + }, + "metrics": null + } + ], + "type": "generator" + }, "('meta-llama/Llama-3.1-8B-Instruct', [SystemMessage(role='system', content='You are a helpful assistant'), UserMessage(role='user', content='Search the web and tell me who the current CEO of Meta is.', context=None), CompletionMessage(role='assistant', content='', stop_reason=, tool_calls=[ToolCall(call_id='', tool_name=, arguments={'query': 'current CEO of Meta'})]), ToolResponseMessage(role='tool', call_id='', tool_name=, content='{\"query\": \"current CEO of Meta\", \"top_k\": [{\"title\": \"Executives - Meta\", \"url\": \"https://about.meta.com/media-gallery/executives/\", \"content\": \"Mark Zuckerberg, Founder, Chairman and Chief Executive Officer Joel Kaplan, Chief Global Affairs Officer Susan Li, Chief Financial Officer Javier Olivan, Chief Operating Officer Chris Cox, Chief Product Officer Andrew \\\\u2018Boz\\\\u2019 Bosworth, Chief Technology Officer Jennifer Newstead, Chief Legal Officer Dave Wehner, Chief Strategy Officer Will Cathcart, Head of WhatsApp Naomi Gleit, Head of Product John Hegeman, Chief Revenue Officer Adam Mosseri, Head of Instagram Erin Egan, Chief Privacy Officer, Policy Michel Protti, Chief Privacy Officer, Product Alex Schultz, Chief Marketing Officer and VP of Analytics Tom Alison, Head of Facebook Nicola Mendelsohn, Head of Global Business Group Ahmad Al-Dahle, VP and Head of GenAI at Meta Joelle Pineau, Vice President of AI Research and Head of FAIR at Meta\", \"score\": 0.8190992, \"raw_content\": null}, {\"title\": \"Mark Zuckerberg, Founder, Chairman and Chief Executive Officer - Meta\", \"url\": \"https://about.meta.com/media-gallery/executives/mark-zuckerberg/\", \"content\": \"Mark Zuckerberg, Founder, Chairman and Chief Executive Officer | Meta Meta Quest Ray-Ban Meta Meta Horizon Meta AI Meta Verified Meta Pay Meta Horizon Workrooms Meta and you Learn about our community Shop Meta Meta Quest Meta Portal Meta Horizon Mark Zuckerberg is the founder, chairman and CEO of Meta, which he originally founded as Facebook in 2004. In October 2021, Facebook rebranded to Meta to reflect all of its products and services across its family of apps and a focus on developing social experiences for the metaverse \\\\u2014 moving beyond 2D screens toward immersive experiences like augmented and virtual reality to help build the next evolution in social technology. Shop Ray-Ban Meta glassesRay-Ban StoriesPrivacy informationSupported countries \\\\u00a9 2025 Meta\", \"score\": 0.79099923, \"raw_content\": null}, {\"title\": \"Meet the Executive CSuite Team of Meta (Facebook) [2025]\", \"url\": \"https://digitaldefynd.com/IQ/meet-the-executive-csuite-team-of-meta-facebook/\", \"content\": \"Harvard University Executive Programs Free Harvard University Courses As a chief financial officer of Meta, Susan Li oversees the firm\\\\u2019s finance and facilities team to keep track of the company\\\\u2019s overall financial health. The chief operating officer of Meta, Javier Olivan, oversees the firm\\\\u2019s business team, infrastructure, and other products. Andrew Bosworth, called Boz, serves as chief technology officer at Meta and is responsible for leading the firm\\\\u2019s AR/VR organization, Reality Labs. Andrew has also served as engineering director to oversee events, mobile monetization, and feed ads and as VP of ads and business platforms to lead engineering, design, analytics, and product teams. Meta\\\\u2019s c-suite team comprises experienced and diverse executives, having extensive experience in technology, finance, legal, and all major industries.\", \"score\": 0.7602419, \"raw_content\": null}, {\"title\": \"Meta to spend up to $65 billion this year to power AI goals, Zuckerberg ...\", \"url\": \"https://www.reuters.com/technology/meta-invest-up-65-bln-capital-expenditure-this-year-2025-01-24/\", \"content\": \"Meta Platforms plans to spend as much as $65 billion this year to expand its AI infrastructure, CEO Mark Zuckerberg said on Friday, aiming to bolster the company\\'s position against rivals OpenAI\", \"score\": 0.73914057, \"raw_content\": null}, {\"title\": \"Meta - Leadership & Governance\", \"url\": \"https://investor.atmeta.com/leadership-and-governance/\", \"content\": \"Mr. Andreessen was a co-founder of Netscape Communications Corporation, a software company, serving in various positions, including Chief Technology Officer and Executive Vice President of Products. Ms. Killefer also served as Assistant Secretary for Management, Chief Financial Officer, and Chief Operating Officer of the U.S. Department of the Treasury from 1997 to 2000 and as a member of the IRS Oversight Board from 2000 to 2005, including as Chair of the IRS Oversight Board from 2002 to 2004. Ms. Travis has served as Executive Vice President and Chief Financial Officer of The Estee Lauder Companies Inc., a global manufacturer and marketer of skin care, makeup, fragrance and hair care products, since August 2012.\", \"score\": 0.6175132, \"raw_content\": null}]}')])_[('response_format', None), ('sampling_params', SamplingParams(strategy=TopPSamplingStrategy(type='top_p', temperature=0.0001, top_p=0.9), max_tokens=0, repetition_penalty=1.0)), ('stream', True), ('tool_config', ToolConfig(tool_choice=, tool_prompt_format=None, system_message_behavior=)), ('tool_prompt_format', None), ('tools', [ToolDefinition(tool_name=, description='Search the web for information', parameters={'query': ToolParamDefinition(param_type='string', description='The query to search for', required=True, default=None)})])]": { "chunks": [ { @@ -7188,7 +10613,26 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "brave_search.call(query=\"current CEO of Meta\")", + "tool_call": "brave_search.call(query=\"current CEO of", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " Meta\")", "type": "tool_call" }, "event_type": { @@ -7211,7 +10655,7 @@ "arguments": { "query": "current CEO of Meta" }, - "call_id": "b5a3c852-c152-4397-b01d-cf0b55da1460", + "call_id": "b9ee4732-1663-429c-ae7d-186578174556", "tool_name": { "__enum__": "BuiltinTool", "value": "brave_search" @@ -7385,7 +10829,7 @@ { "event": { "delta": { - "text": " function `get_boiling_point` is not able to find the boiling point", + "text": " function `get_boiling_point` is not able to find", "type": "text" }, "event_type": { @@ -7400,7 +10844,7 @@ { "event": { "delta": { - "text": " of polyjuice as it is a fictional liquid from the Harry Potter series", + "text": " the boiling point of polyjuice as it is a fictional", "type": "text" }, "event_type": { @@ -7415,7 +10859,22 @@ { "event": { "delta": { - "text": ".", + "text": " liquid from the Harry Potter series. The", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": " function only works with real-world liquids.", "type": "text" }, "event_type": { @@ -7626,7 +11085,7 @@ { "event": { "delta": { - "text": " able to find the boiling", + "text": " able to find the boiling point of polyjuice as it is", "type": "text" }, "event_type": { @@ -7641,7 +11100,7 @@ { "event": { "delta": { - "text": " point of polyjuice as it is not a", + "text": " not a real liquid. Polyjuice is a magical potion from", "type": "text" }, "event_type": { @@ -7656,22 +11115,7 @@ { "event": { "delta": { - "text": " real liquid. Polyjuice is a magical potion from the", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " Harry Potter series.", + "text": " the Harry Potter series.", "type": "text" }, "event_type": { @@ -7867,7 +11311,7 @@ { "event": { "delta": { - "text": " not able to find the boiling point of polyjuice as", + "text": " not able to find the boiling point of polyjuice as it", "type": "text" }, "event_type": { @@ -7882,7 +11326,7 @@ { "event": { "delta": { - "text": " it is not a real liquid. Polyjuice is a magical potion", + "text": " is not a real liquid. Polyjuice is", "type": "text" }, "event_type": { @@ -7897,7 +11341,7 @@ { "event": { "delta": { - "text": " from the Harry Potter series.", + "text": " a magical potion from the Harry Potter series.", "type": "text" }, "event_type": { @@ -8115,7 +11559,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "{\"type\": \"function\", \"name\": \"get", + "tool_call": "{\"type\": \"function\", \"name\":", "type": "tool_call" }, "event_type": { @@ -8134,7 +11578,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "_boiling_point\", \"parameters\": {\"liquid_name\": \"poly", + "tool_call": " \"get_boiling_point\", \"parameters\":", "type": "tool_call" }, "event_type": { @@ -8153,7 +11597,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "juice\"}}", + "tool_call": " {\"liquid_name\": \"polyjuice\"}}", "type": "tool_call" }, "event_type": { @@ -8176,7 +11620,7 @@ "arguments": { "liquid_name": "polyjuice" }, - "call_id": "c6384f37-a43d-4ead-a7d5-a9705c32551f", + "call_id": "a994859b-38d2-45d5-913e-359409ee8ae2", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -8399,7 +11843,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "{\"type\": \"function\", \"name\": \"get_bo", + "tool_call": "{\"type\": \"function\", \"name\": \"get_boiling", "type": "tool_call" }, "event_type": { @@ -8418,7 +11862,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "iling_point\", \"parameters\": {\"liquid_name\": \"polyju", + "tool_call": "_point\", \"parameters\": {\"liquid_name\": \"polyjuice", "type": "tool_call" }, "event_type": { @@ -8437,7 +11881,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "ice\"}}", + "tool_call": "\"}}", "type": "tool_call" }, "event_type": { @@ -8460,7 +11904,7 @@ "arguments": { "liquid_name": "polyjuice" }, - "call_id": "386d264e-6a42-45dd-8b74-669dbb086014", + "call_id": "e48d4312-1a88-4759-9b9c-bc573c23fee6", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -8676,7 +12120,7 @@ { "event": { "delta": { - "text": " couldn't find any information on the boiling", + "text": " couldn't find any information on the boiling point of Poly", "type": "text" }, "event_type": { @@ -8691,7 +12135,7 @@ { "event": { "delta": { - "text": " point of Polyjuice. Polyjuice is a magical", + "text": "juice. Polyjuice is a magical potion in", "type": "text" }, "event_type": { @@ -8706,7 +12150,7 @@ { "event": { "delta": { - "text": " potion in the Harry Potter series that allows the drinker to", + "text": " the Harry Potter series that allows the drinker", "type": "text" }, "event_type": { @@ -8721,7 +12165,7 @@ { "event": { "delta": { - "text": " transform into someone else. It's not a physical substance with a", + "text": " to transform into someone else. It's not a physical substance", "type": "text" }, "event_type": { @@ -8736,7 +12180,7 @@ { "event": { "delta": { - "text": " boiling point. If you have any other questions, I'd be", + "text": " with a boiling point. If you have any other questions, I'd", "type": "text" }, "event_type": { @@ -8751,7 +12195,7 @@ { "event": { "delta": { - "text": " happy to help.", + "text": " be happy to help.", "type": "text" }, "event_type": { @@ -8969,7 +12413,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "{\"type\": \"function\", \"name\": \"get", + "tool_call": "{\"type\": \"function\", \"name\": \"get_boiling_point\",", "type": "tool_call" }, "event_type": { @@ -8988,26 +12432,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "_boiling_point\", \"parameters\": {\"liquid_name", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": "\": \"polyjuice\"}}", + "tool_call": " \"parameters\": {\"liquid_name\": \"polyjuice\"}}", "type": "tool_call" }, "event_type": { @@ -9030,7 +12455,7 @@ "arguments": { "liquid_name": "polyjuice" }, - "call_id": "71d947ad-d4d6-4a15-8ec5-d9bf890ed45c", + "call_id": "cd0e926b-b1c8-468b-8c55-b3e42e7ae89d", "tool_name": "get_boiling_point" }, "type": "tool_call" @@ -9103,7 +12528,7 @@ { "event": { "delta": { - "text": " 100th prime number is", + "text": " 100th prime number is ", "type": "text" }, "event_type": { @@ -9118,7 +12543,7 @@ { "event": { "delta": { - "text": " 541.", + "text": "541.", "type": "text" }, "event_type": { @@ -9232,7 +12657,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\n if n % 2 == 0 or n % 3", + "tool_call": "\n if n % 2 ==", "type": "tool_call" }, "event_type": { @@ -9251,7 +12676,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " == 0:\n return False\n i = 5\n while", + "tool_call": " 0 or n % 3 == 0:\n ", "type": "tool_call" }, "event_type": { @@ -9270,7 +12695,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " i * i <= n:\n if n %", + "tool_call": " return False\n i = 5\n", "type": "tool_call" }, "event_type": { @@ -9289,7 +12714,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " i == 0 or n % (i", + "tool_call": " while i * i <= n:\n if n % i", "type": "tool_call" }, "event_type": { @@ -9308,7 +12733,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " + 2) == 0:\n return False\n ", + "tool_call": " == 0 or n % (i + 2) ==", "type": "tool_call" }, "event_type": { @@ -9327,7 +12752,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " i += 6\n return True\n\ndef get_nth_prime", + "tool_call": " 0:\n return False\n i += 6\n", "type": "tool_call" }, "event_type": { @@ -9346,7 +12771,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "(n):\n count = 0\n num = 2", + "tool_call": " return True\n\ndef get_nth_prime(n):\n count =", "type": "tool_call" }, "event_type": { @@ -9365,7 +12790,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "\n while True:\n if is_prime(num):\n count += ", + "tool_call": " 0\n num = 2\n while True:\n", "type": "tool_call" }, "event_type": { @@ -9384,7 +12809,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "1\n if count == n:\n return num\n num +=", + "tool_call": " if is_prime(num):\n count += 1\n ", "type": "tool_call" }, "event_type": { @@ -9403,7 +12828,45 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": " 1\n\nprint(get_nth_prime(100))", + "tool_call": " if count == n:\n return num\n num +=", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": " 1\n\nprint(get_nth_prime(", + "type": "tool_call" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "parse_status": { + "__enum__": "ToolCallParseStatus", + "value": "in_progress" + }, + "tool_call": "100))", "type": "tool_call" }, "event_type": { @@ -9426,7 +12889,7 @@ "arguments": { "code": "def is_prime(n):\n if n <= 1:\n return False\n if n <= 3:\n return True\n if n % 2 == 0 or n % 3 == 0:\n return False\n i = 5\n while i * i <= n:\n if n % i == 0 or n % (i + 2) == 0:\n return False\n i += 6\n return True\n\ndef get_nth_prime(n):\n count = 0\n num = 2\n while True:\n if is_prime(num):\n count += 1\n if count == n:\n return num\n num += 1\n\nprint(get_nth_prime(100))" }, - "call_id": "ee20e420-1f28-44be-b6e1-4672dec916d8", + "call_id": "a184cbe8-b941-472d-9254-fda5ed8d770f", "tool_name": { "__enum__": "BuiltinTool", "value": "code_interpreter" @@ -9638,7 +13101,22 @@ { "event": { "delta": { - "text": "type\": \"function\", \"name\": \"knowledge_search\", \"parameters\":", + "text": "type\": \"function\", \"name\": \"", + "type": "text" + }, + "event_type": { + "__enum__": "ChatCompletionResponseEventType", + "value": "progress" + }, + "logprobs": null, + "stop_reason": null + }, + "metrics": null + }, + { + "event": { + "delta": { + "text": "knowledge_search\", \"parameters\":", "type": "text" }, "event_type": { @@ -9676,7 +13154,7 @@ "arguments": { "query": "Perplexity company founding date" }, - "call_id": "ad2b7b43-e9b7-41ff-91f8-150f9ae8b213", + "call_id": "9ad1f31d-4fb3-40e6-8037-0cc50794d6ce", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -9925,7 +13403,7 @@ "arguments": { "query": "Perplexity company founding date" }, - "call_id": "d3ccf807-0bd6-47c4-98c0-d3c603b8b3ca", + "call_id": "11c1dca5-6754-4ba6-8337-1bb8a538342f", "tool_name": "knowledge_search" }, "type": "tool_call" @@ -10140,7 +13618,7 @@ { "event": { "delta": { - "text": " NBA was created on August ", + "text": " NBA was created on August 3, ", "type": "text" }, "event_type": { @@ -10155,7 +13633,7 @@ { "event": { "delta": { - "text": "3, 1949, with", + "text": "1949, with the merger of the Basketball Association of America", "type": "text" }, "event_type": { @@ -10170,37 +13648,7 @@ { "event": { "delta": { - "text": " the merger of the Basketball Association of", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " America (BAA) and the National Basketball League", - "type": "text" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "text": " (NBL).", + "text": " (BAA) and the National Basketball League (NBL).", "type": "text" }, "event_type": { @@ -10389,7 +13837,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "{\"type\": \"function\", \"", + "tool_call": "{\"type\": \"function\", \"name\": \"knowledge_search\", \"parameters\":", "type": "tool_call" }, "event_type": { @@ -10408,45 +13856,7 @@ "__enum__": "ToolCallParseStatus", "value": "in_progress" }, - "tool_call": "name\": \"knowledge_search\", \"parameters", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": "\": {\"query\": \"NBA", - "type": "tool_call" - }, - "event_type": { - "__enum__": "ChatCompletionResponseEventType", - "value": "progress" - }, - "logprobs": null, - "stop_reason": null - }, - "metrics": null - }, - { - "event": { - "delta": { - "parse_status": { - "__enum__": "ToolCallParseStatus", - "value": "in_progress" - }, - "tool_call": " creation date\"}}", + "tool_call": " {\"query\": \"NBA creation date\"}}", "type": "tool_call" }, "event_type": { @@ -10469,7 +13879,7 @@ "arguments": { "query": "NBA creation date" }, - "call_id": "34cb848d-3c9f-4f70-9b1c-8fd4f8455f00", + "call_id": "9ffcb7be-c9ba-478a-af1c-8f68d4033c4f", "tool_name": "knowledge_search" }, "type": "tool_call" diff --git a/tests/integration/fixtures/recorded_responses/chat_completion.pickle b/tests/integration/fixtures/recorded_responses/chat_completion.pickle index aef1aa45db1fbad744a507b0f021e2d2009e06f8..4abc0c17e7d9e44535052c241befdb72a42fa952 100644 GIT binary patch literal 684331 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 z%0D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�}}1PA{YaVz&)Dke)3aI%${N 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 literal 541735 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

{laH?jS14_XzicpEOgYdJyjNZ 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

0$SY z>m=4N`zi*cWB1t-10)*&zByF*iYQGjbR*`MZ{6iv8JU`T3y_yw#0fJl0xjGFR*ilu zM@XJ~l<2KG%+lk=2Yxz2cCy@vGh*7eACG{S=OWk>m@dS?!&wHQA0IOl=219woUr`l zDxw)L#x~<+XvWz_<})+B9mnSP8g~6S!Q{J`j{7&ZWj2WaMZ_bF(e|jr`YJ1n7QhoX zFj-O|2lw`!A)t#)=ug){K*pgWiY<2Vn)!s-navqFxPfjA~mn?QY8FGEH4#)8sLyxy75u zoQ@g?u{M5xiYESfq5J$EREta)TxY@i6sLI=rzk&PX1DN8cHP30dQ;E+!1=Do zgbR~uU~I+Q51eOWWMo&o41VArjd@^-Oqeb-A&$zJ8iZ_3IPkko!+(a`HN(pZ`I2{io;Y5|`d#I>ENNcXZr4 z`bBXZY3J{GUcB7-n>&A#AQhTz#@(qIb^hkw(cC*aL=AOnqbg&L$1$k1K=AEU%6V=F y7V?bz$ykLq>K(t&wUzdZHi@y&MqO-AmF%Ksm!r6AA% diff --git a/tests/integration/fixtures/recorded_responses/invoke_tool.json b/tests/integration/fixtures/recorded_responses/invoke_tool.json index 2dde8c83c..7d56a829a 100644 --- a/tests/integration/fixtures/recorded_responses/invoke_tool.json +++ b/tests/integration/fixtures/recorded_responses/invoke_tool.json @@ -71,6 +71,15 @@ "metadata": null } }, + "()_[('kwargs', {'session_id': '', 'code': 'import pandas as pd\\nimport matplotlib.pyplot as plt\\n\\n# Load data\\ndf = pd.read_csv(\"\")\\n\\n# Convert \\'Year\\' column to datetime\\ndf[\\'Year\\'] = pd.to_datetime(df[\\'Year\\'])\\n\\n# Group by year and calculate average inflation\\naverage_inflation = df.groupby(\\'Year\\')[\\'Inflation\\'].mean().reset_index()\\n\\n# Plot average yearly inflation as a time series\\nplt.figure(figsize=(10,6))\\nplt.plot(average_inflation[\\'Year\\'], average_inflation[\\'Inflation\\'], marker=\\'o\\')\\nplt.title(\\'Average Yearly Inflation\\')\\nplt.xlabel(\\'Year\\')\\nplt.ylabel(\\'Inflation Rate\\')\\nplt.grid(True)\\nplt.show()'}), ('tool_name', 'code_interpreter')]": { + "type": "value", + "value": { + "content": "completed\n[stderr]\nTraceback (most recent call last):\n line 5, in \n from bwrap.core import main\nModuleNotFoundError: No module named 'bwrap.core'\n[/stderr]", + "error_code": null, + "error_message": null, + "metadata": null + } + }, "()_[('kwargs', {'session_id': '', 'code': 'import pandas as pd\\nimport matplotlib.pyplot as plt\\n\\n# Load the CSV file\\ndf = pd.read_csv(\"\")\\n\\n# Convert the \\'Year\\' column to datetime\\ndf[\\'Year\\'] = pd.to_datetime(df[\\'Year\\'], format=\\'%Y\\')\\n\\n# Group by \\'Year\\' and calculate the average inflation\\ndf_avg_inflation = df.groupby(\\'Year\\')[\\'Inflation\\'].mean().reset_index()\\n\\n# Plot the average inflation as a time series\\nplt.figure(figsize=(10,6))\\nplt.plot(df_avg_inflation[\\'Year\\'], df_avg_inflation[\\'Inflation\\'], marker=\\'o\\')\\nplt.title(\\'Average Yearly Inflation\\')\\nplt.xlabel(\\'Year\\')\\nplt.ylabel(\\'Inflation\\')\\nplt.grid(True)\\nplt.show()'}), ('tool_name', 'code_interpreter')]": { "type": "value", "value": { @@ -98,23 +107,23 @@ "type": "text" }, { - "text": "Result 1:\nDocument_id:cbc88\nContent: .. _lora_finetune_label:\n\n============================\nFine-Tuning Llama2 with LoRA\n============================\n\nThis guide will teach you about `LoRA `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", + "text": "Result 2:\nDocument_id:64211\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", "type": "text" }, { - "text": "Result 3:\nDocument_id:8892b\nContent: with training with LoRA quickly,\njust specify any config with ``_lora`` in its name, e.g:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n\nThere are two sets of parameters to customize LoRA to suit your needs. Firstly, the parameters which control\nwhich linear layers LoRA should be applied to in the model:\n\n* ``lora_attn_modules: List[str]`` accepts a list of strings specifying which layers of the model to apply\n LoRA to:\n\n * ``q_proj`` applies LoRA to the query projection layer.\n * ``k_proj`` applies LoRA to the key projection layer.\n * ``v_proj`` applies LoRA to the value projection layer.\n * ``output_proj`` applies LoRA to the attention output projection layer.\n\n Whilst adding more layers to be fine-tuned may improve model accuracy,\n this will come at the cost of increased memory usage and reduced training speed.\n\n* ``apply_lora_to_mlp: Bool`` applies LoRA to the MLP in each transformer layer.\n* ``apply_lora_to_output: Bool`` applies LoRA to the model's final output projection.\n This is usually a projection to vocabulary space (e.g. in language models), but\n other modelling tasks may have different projections - classifier models will project\n to the number of classes, for example\n\n.. note::\n\n Models which use tied embeddings (such as Gemma and Qwen2 1.5B and 0.5B) for the\n final output projection do not support ``apply_lora_to_output``.\n\nThese are all specified under the ``model`` flag or config entry, i.e:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\",\"output_proj\"]\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.llama3.lora_llama3_8b\n apply_lora_to_mlp: True\n model.lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\",\"output_proj\"]\n\nSecondly, parameters which control the scale of the impact of LoRA on the model:\n\n* ``lora_rank: int`` affects the scale of\n", + "text": "Result 3:\nDocument_id:0c95c\nContent: with training with LoRA quickly,\njust specify any config with ``_lora`` in its name, e.g:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n\nThere are two sets of parameters to customize LoRA to suit your needs. Firstly, the parameters which control\nwhich linear layers LoRA should be applied to in the model:\n\n* ``lora_attn_modules: List[str]`` accepts a list of strings specifying which layers of the model to apply\n LoRA to:\n\n * ``q_proj`` applies LoRA to the query projection layer.\n * ``k_proj`` applies LoRA to the key projection layer.\n * ``v_proj`` applies LoRA to the value projection layer.\n * ``output_proj`` applies LoRA to the attention output projection layer.\n\n Whilst adding more layers to be fine-tuned may improve model accuracy,\n this will come at the cost of increased memory usage and reduced training speed.\n\n* ``apply_lora_to_mlp: Bool`` applies LoRA to the MLP in each transformer layer.\n* ``apply_lora_to_output: Bool`` applies LoRA to the model's final output projection.\n This is usually a projection to vocabulary space (e.g. in language models), but\n other modelling tasks may have different projections - classifier models will project\n to the number of classes, for example\n\n.. note::\n\n Models which use tied embeddings (such as Gemma and Qwen2 1.5B and 0.5B) for the\n final output projection do not support ``apply_lora_to_output``.\n\nThese are all specified under the ``model`` flag or config entry, i.e:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\",\"output_proj\"]\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.llama3.lora_llama3_8b\n apply_lora_to_mlp: True\n model.lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\",\"output_proj\"]\n\nSecondly, parameters which control the scale of the impact of LoRA on the model:\n\n* ``lora_rank: int`` affects the scale of\n", "type": "text" }, { - "text": "Result 4:\nDocument_id:cbc88\nContent: LoRA to Llama2 models\n------------------------------\n\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\nLet's take a look at how to construct Llama2 models in torchtune with and without LoRA.\n\n.. code-block:: python\n\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\n\n # Build Llama2 without any LoRA layers\n base_model = llama2_7b()\n\n # The default settings for lora_llama2_7b will match those for llama2_7b\n # We just need to define which layers we want LoRA applied to.\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\n # layers outside of the self-attention.\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\n\n.. note::\n\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\n See :ref:`below` for how to do this.\n\nLet's inspect each of these models a bit more closely.\n\n.. code-block:: bash\n\n # Print the first layer's self-attention in the usual Llama2 model\n >>> print(base_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (pos_embeddings): RotaryPositionalEmbeddings()\n )\n\n # Print the same for Llama2 with LoRA weights\n >>> print(lora_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): LoRALinear(\n (dropout): Dropout(p=0.0, inplace=False)\n \n", + "text": "Result 4:\nDocument_id:64211\nContent: LoRA to Llama2 models\n------------------------------\n\nWith torchtune, we can easily apply LoRA to Llama2 with a variety of different configurations.\nLet's take a look at how to construct Llama2 models in torchtune with and without LoRA.\n\n.. code-block:: python\n\n from torchtune.models.llama2 import llama2_7b, lora_llama2_7b\n\n # Build Llama2 without any LoRA layers\n base_model = llama2_7b()\n\n # The default settings for lora_llama2_7b will match those for llama2_7b\n # We just need to define which layers we want LoRA applied to.\n # Within each self-attention, we can choose from [\"q_proj\", \"k_proj\", \"v_proj\", and \"output_proj\"].\n # We can also set apply_lora_to_mlp=True or apply_lora_to_output=True to apply LoRA to other linear\n # layers outside of the self-attention.\n lora_model = lora_llama2_7b(lora_attn_modules=[\"q_proj\", \"v_proj\"])\n\n.. note::\n\n Calling :func:`lora_llama_2_7b ` alone will not handle the definition of which parameters are trainable.\n See :ref:`below` for how to do this.\n\nLet's inspect each of these models a bit more closely.\n\n.. code-block:: bash\n\n # Print the first layer's self-attention in the usual Llama2 model\n >>> print(base_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (k_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (v_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (output_proj): Linear(in_features=4096, out_features=4096, bias=False)\n (pos_embeddings): RotaryPositionalEmbeddings()\n )\n\n # Print the same for Llama2 with LoRA weights\n >>> print(lora_model.layers[0].attn)\n MultiHeadAttention(\n (q_proj): LoRALinear(\n (dropout): Dropout(p=0.0, inplace=False)\n \n", "type": "text" }, { - "text": "Result 5:\nDocument_id:9dcb7\nContent: ora_finetune_label>`.\nFor more on QLoRA in torchtune, see our :ref:`QLoRA Tutorial `.\n\nLet's take a look at how we can fine-tune Llama3-8B-Instruct with LoRA on a single device using torchtune. In this example, we will fine-tune\nfor one epoch on a common instruct dataset for illustrative purposes. The basic command for a single-device LoRA fine-tune is\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n.. note::\n To see a full list of recipes and their corresponding configs, simply run ``tune ls`` from the command line.\n\nWe can also add :ref:`command-line overrides ` as needed, e.g.\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n checkpointer.checkpoint_dir= \\\n tokenizer.path=/tokenizer.model \\\n checkpointer.output_dir=\n\nThis will load the Llama3-8B-Instruct checkpoint and tokenizer from ```` used in the :ref:`tune download ` command above,\nthen save a final checkpoint in the same directory following the original format. For more details on the\ncheckpoint formats supported in torchtune, see our :ref:`checkpointing deep-dive `.\n\n.. note::\n To see the full set of configurable parameters for this (and other) configs we can use :ref:`tune cp ` to copy (and modify)\n the default config. :ref:`tune cp ` can be used with recipe scripts too, in case you want to make more custom changes\n that cannot be achieved by directly modifying existing configurable parameters. For more on :ref:`tune cp ` see the section on\n :ref:`modifying configs ` in our \":ref:`finetune_llama_label`\" tutorial.\n\nOnce training is complete, the model checkpoints will be saved and their locations will be logged. For\nLoRA fine-tuning, the final checkpoint will contain the merged weights, and a copy of just the (much smaller) LoRA weights\nwill\n", + "text": "Result 5:\nDocument_id:1d70c\nContent: ora_finetune_label>`.\nFor more on QLoRA in torchtune, see our :ref:`QLoRA Tutorial `.\n\nLet's take a look at how we can fine-tune Llama3-8B-Instruct with LoRA on a single device using torchtune. In this example, we will fine-tune\nfor one epoch on a common instruct dataset for illustrative purposes. The basic command for a single-device LoRA fine-tune is\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device\n\n.. note::\n To see a full list of recipes and their corresponding configs, simply run ``tune ls`` from the command line.\n\nWe can also add :ref:`command-line overrides ` as needed, e.g.\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n checkpointer.checkpoint_dir= \\\n tokenizer.path=/tokenizer.model \\\n checkpointer.output_dir=\n\nThis will load the Llama3-8B-Instruct checkpoint and tokenizer from ```` used in the :ref:`tune download ` command above,\nthen save a final checkpoint in the same directory following the original format. For more details on the\ncheckpoint formats supported in torchtune, see our :ref:`checkpointing deep-dive `.\n\n.. note::\n To see the full set of configurable parameters for this (and other) configs we can use :ref:`tune cp ` to copy (and modify)\n the default config. :ref:`tune cp ` can be used with recipe scripts too, in case you want to make more custom changes\n that cannot be achieved by directly modifying existing configurable parameters. For more on :ref:`tune cp ` see the section on\n :ref:`modifying configs ` in our \":ref:`finetune_llama_label`\" tutorial.\n\nOnce training is complete, the model checkpoints will be saved and their locations will be logged. For\nLoRA fine-tuning, the final checkpoint will contain the merged weights, and a copy of just the (much smaller) LoRA weights\nwill\n", "type": "text" }, { @@ -126,11 +135,11 @@ "error_message": null, "metadata": { "document_ids": [ - "cbc884b1-9d88-4d5c-aff4-7a4b3a56618c", - "cbc884b1-9d88-4d5c-aff4-7a4b3a56618c", - "8892b092-6394-471e-b143-a23c6cc374f8", - "cbc884b1-9d88-4d5c-aff4-7a4b3a56618c", - "9dcb747d-0627-40cc-a23c-0bee2b6b05af" + "6421150d-d334-4163-a058-3818b2b742e9", + "6421150d-d334-4163-a058-3818b2b742e9", + "0c95cff3-5612-40cf-a73d-77644a2462d0", + "6421150d-d334-4163-a058-3818b2b742e9", + "1d70c86d-4cdf-4be9-a1f2-8a271b15ce2c" ] } } @@ -298,23 +307,23 @@ "type": "text" }, { - "text": "Result 1:\nDocument_id:3e3a0\nContent: conversational data, :func:`~torchtune.datasets.chat_dataset` seems to be a good fit. For any\ncustom local dataset we always need to specify ``source``, ``data_files``, and ``split`` for any dataset\nbuilder in torchtune. For :func:`~torchtune.datasets.chat_dataset`, we additionally need to specify\n``conversation_column`` and ``conversation_style``. Our data follows the ``\"sharegpt\"`` format, so\nwe can specify that here. Altogether, our :func:`~torchtune.datasets.chat_dataset` call should\nlook like so:\n\n.. code-block:: python\n\n from torchtune.datasets import chat_dataset\n from torchtune.models.llama3 import llama3_tokenizer\n\n tokenizer = llama3_tokenizer(\"/tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\")\n ds = chat_dataset(\n tokenizer=tokenizer,\n source=\"json\",\n data_files=\"data/my_data.json\",\n split=\"train\",\n conversation_column=\"dialogue\",\n conversation_style=\"sharegpt\",\n )\n\n.. code-block:: yaml\n\n # In config\n tokenizer:\n _component_: torchtune.models.llama3.llama3_tokenizer\n path: /tmp/Meta-Llama-3-8B-Instruct/original/tokenizer.model\n\n dataset:\n _component_: torchtune.datasets.chat_dataset\n source: json\n data_files: data/my_data.json\n split: train\n conversation_column: dialogue\n conversation_style: sharegpt\n\n.. note::\n You can pass in any keyword argument for `load_dataset `_ into all our\n Dataset classes and they will honor them. This is useful for common parameters\n such as specifying the data split with :code:`split` or configuration with\n :code:`name`\n\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\nSince we're fine-tuning Llama3, the tokenizer will handle all formatting for\nus and prompt templates are optional. Other models such as Mistral's :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\nall messages according to their `recommendations `_ into all our\n Dataset classes and they will honor them. This is useful for common parameters\n such as specifying the data split with :code:`split` or configuration with\n :code:`name`\n\nIf you needed to add a prompt template, you would simply pass it into the tokenizer.\nSince we're fine-tuning Llama3, the tokenizer will handle all formatting for\nus and prompt templates are optional. Other models such as Mistral's :class:`~torchtune.models.mistral._tokenizer.MistralTokenizer`,\nuse a chat template by default (:class:`~torchtune.models.mistral.MistralChatTemplate`) to format\nall messages according to their `recommendations `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `_, a parameter-efficient finetuning technique,\nand show you how you can use torchtune to finetune a Llama2 model with LoRA.\nIf you already know what LoRA is and want to get straight to running\nyour own LoRA finetune in torchtune, you can jump to :ref:`LoRA finetuning recipe in torchtune`.\n\n.. grid:: 2\n\n .. grid-item-card:: :octicon:`mortar-board;1em;` What you will learn\n\n * What LoRA is and how it saves memory during finetuning\n * An overview of LoRA components in torchtune\n * How to run a LoRA finetune using torchtune\n * How to experiment with different LoRA configurations\n\n .. grid-item-card:: :octicon:`list-unordered;1em;` Prerequisites\n\n * Be familiar with :ref:`torchtune`\n * Make sure to :ref:`install torchtune`\n * Make sure you have downloaded the :ref:`Llama2-7B model weights`\n\nWhat is LoRA?\n-------------\n\n`LoRA `_ is an adapter-based method for\nparameter-efficient finetuning that adds trainable low-rank decomposition matrices to different layers of a neural network,\nthen freezes the network's remaining parameters. LoRA is most commonly applied to\ntransformer models, in which case it is common to add the low-rank matrices\nto some of the linear projections in each transformer layer's self-attention.\n\n.. note::\n\n If you're unfamiliar, check out these references for the `definition of rank `_\n and discussion of `low-rank approximations `_.\n\nBy finetuning with LoRA (as opposed to finetuning all model parameters),\nyou can expect to see memory savings due to a substantial reduction in the\nnumber of parameters with gradients. When using an optimizer with momentum,\nlike `AdamW `.\n.. .. _glossary_fsdp2:\n\n", + "text": "Result 3:\nDocument_id:0c95c\nContent: ` module, which we swap\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\n\n.. _glossary_distrib:\n\n\n.. TODO\n\n.. Distributed\n.. -----------\n\n.. .. _glossary_fsdp:\n\n.. Fully Sharded Data Parallel (FSDP)\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. All our ``_distributed`` recipes use `FSDP `.\n.. .. _glossary_fsdp2:\n\n", "type": "text" }, { - "text": "Result 4:\nDocument_id:7da0c\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", + "text": "Result 4:\nDocument_id:64211\nContent: 06% of all params are trainable.\n\n.. note::\n If you are directly using the LoRA recipe (as detailed :ref:`here`), you need only pass the\n relevant checkpoint path. Loading model weights and setting trainable parameters will be taken care\n of in the recipe.\n\n\n.. _lora_recipe_label:\n\nLoRA finetuning recipe in torchtune\n-----------------------------------\n\nFinally, we can put it all together and finetune a model using torchtune's `LoRA recipe `_.\nMake sure that you have first downloaded the Llama2 weights and tokenizer by following :ref:`these instructions`.\nYou can then run the following command to perform a LoRA finetune of Llama2-7B with two GPUs (each having VRAM of at least 16GB):\n\n.. code-block:: bash\n\n tune run --nnodes 1 --nproc_per_node 2 lora_finetune_distributed --config llama2/7B_lora\n\n.. note::\n Make sure to point to the location of your Llama2 weights and tokenizer. This can be done\n either by adding :code:`checkpointer.checkpoint_files=[my_model_checkpoint_path] tokenizer_checkpoint=my_tokenizer_checkpoint_path`\n or by directly modifying the :code:`7B_lora.yaml` file. See our \"\":ref:`config_tutorial_label`\" recipe\n for more details on how you can easily clone and modify torchtune configs.\n\n.. note::\n You can modify the value of :code:`nproc_per_node` depending on (a) the number of GPUs you have available,\n and (b) the memory constraints of your hardware.\n\nThe preceding command will run a LoRA finetune with torchtune's factory settings, but we may want to experiment a bit.\nLet's take a closer look at some of the :code:`lora_finetune_distributed` config.\n\n.. code-block:: yaml\n\n # Model Arguments\n model:\n _component_: lora_llama2_7b\n lora_attn_modules: ['q_proj', 'v_proj']\n lora_rank: 8\n lora_alpha: 16\n ...\n\nWe see that the\n", "type": "text" }, { - "text": "Result 5:\nDocument_id:fd0f6\nContent: etune\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.use_dora=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n use_dora: True\n\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\neven more memory savings!\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\n model.lora_rank=16 \\\n model.lora_alpha=32 \\\n model.use_dora=True \\\n model.quantize_base=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n apply_lora_to_mlp: True\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\n lora_rank: 16\n lora_alpha: 32\n use_dora: True\n quantize_base: True\n\n\n.. note::\n\n Under the hood, we've enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\n\n.. _glossary_distrib:\n\n\n.. TODO\n\n.. Distributed\n.. -----------\n\n.. .. _glossary_fsdp:\n\n.. Fully Sharded Data Parallel (FSDP)\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. All our ``_distributed`` recipes use `FSDP `.\n.. .. _glossary_fsdp2:\n\n", + "text": "Result 5:\nDocument_id:0c95c\nContent: etune\n:func:`torchtune.models.llama3.llama3_8b` with DoRA, you would use :func:`torchtune.models.llama3.lora_llama3_8b` with ``use_dora=True``:\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.use_dora=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n use_dora: True\n\nSince DoRA extends LoRA, the parameters for :ref:`customizing LoRA ` are identical. You can also quantize the base model weights like in :ref:`glossary_qlora` by using ``quantize=True`` to reap\neven more memory savings!\n\n.. code-block:: bash\n\n tune run lora_finetune_single_device --config llama3/8B_lora_single_device \\\n model.apply_lora_to_mlp=True \\\n model.lora_attn_modules=[\"q_proj\",\"k_proj\",\"v_proj\"] \\\n model.lora_rank=16 \\\n model.lora_alpha=32 \\\n model.use_dora=True \\\n model.quantize_base=True\n\n.. code-block:: yaml\n\n model:\n _component_: torchtune.models.lora_llama3_8b\n apply_lora_to_mlp: True\n lora_attn_modules: [\"q_proj\", \"k_proj\", \"v_proj\"]\n lora_rank: 16\n lora_alpha: 32\n use_dora: True\n quantize_base: True\n\n\n.. note::\n\n Under the hood, we've enabled DoRA by adding the :class:`~torchtune.modules.peft.DoRALinear` module, which we swap\n out for :class:`~torchtune.modules.peft.LoRALinear` when ``use_dora=True``.\n\n.. _glossary_distrib:\n\n\n.. TODO\n\n.. Distributed\n.. -----------\n\n.. .. _glossary_fsdp:\n\n.. Fully Sharded Data Parallel (FSDP)\n.. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. All our ``_distributed`` recipes use `FSDP `.\n.. .. _glossary_fsdp2:\n\n", "type": "text" }, { @@ -326,11 +335,11 @@ "error_message": null, "metadata": { "document_ids": [ - "3e3a05a7-23d4-461e-a304-8aa7cb35a4f5", - "7da0c755-7ffa-4c1a-9ab0-cfdda7cce00f", - "fd0f6ee9-15d2-43b3-8500-25bc5bdfd365", - "7da0c755-7ffa-4c1a-9ab0-cfdda7cce00f", - "fd0f6ee9-15d2-43b3-8500-25bc5bdfd365" + "7bdfad34-d546-4e98-9757-a0289696cd97", + "6421150d-d334-4163-a058-3818b2b742e9", + "0c95cff3-5612-40cf-a73d-77644a2462d0", + "6421150d-d334-4163-a058-3818b2b742e9", + "0c95cff3-5612-40cf-a73d-77644a2462d0" ] } } diff --git a/tests/integration/fixtures/recorded_responses/invoke_tool.pickle b/tests/integration/fixtures/recorded_responses/invoke_tool.pickle index a642db721a05d52dd9fa0a70de106191bfa3f158..bb7fb29d7a063a3a11c0530fec9637d0ca59c07b 100644 GIT binary patch delta 1647 zcmb_dZ)h839PTAOlg+TC&62Fw#KZgZkd3U9u}W5x@NM z-uwLWyuasp-bxS!|X1Gj>z$t zj6dG>3AKuz+4i`2Np#>JS(CL_EQ7vh4f#6_dnZc)b~ z3adm(FXDtK>4-^eRN|x*pAr$T#z~uXTsj?PV*O+(#on4jpp zmyAUQ(@Mp53y=hbMY57+QA&-oNiNN^Qj!|KUN+VgtOn^k&s3vjgf-CihJL zVCIR8p)JG0c*sfY!k>${G6oWDVK5+dv<^hps#& z$Nk<4sR>$pcyTo3sKO04xHtj}ZNb%iGSxmi4NQ+M{sTHt;KSB&6^-gTE8tuq5L_3y ze!$eQFdp>lW)PPBt1cy$fb}EXTP{2Pr(EI8>|ED>v)qzau{b-ozv_eC%>;r1YC32Q_EzsZT#RunacU3#>p5yro-_*b@cA^n?^%nv5c82lQOPQL3*U|M} z4%filHafkJBv5@5%nS5)VIDE`M+i)ACmiV8#_J_ByBkZ*OS?YWi)OUYTfProYzmzU z`QW3n2Ro?6e)1C6 z)?~+9E=?aA8q*jxNd3rMV(~IY(cq)b`m!;d8#7z7S3YUAu%Z)3@nH1sYir$}FqLg*QChKNM6iL8rbrT!6~j~v%dxPk zc(g*R_U`HSf+FGj_fDl}Yi~!;zBY449d2aE9vE~TPb%QP}k4Cq5EoIZUbE2wr0ey(zaaDuxUf#eV)6(`ot`L zY!40%J^F*&6Ba3DWu)S4pi3su z#Yhv3bQznfY2plVv@kHNi)4_6BvsBJBAG$TAP7l@ZOevgNQ&-wGZhi(Qn*>Z_)L$A zvv{=LT+y9^`{fc$9enqh?AaU+PY$uw&u4&|!vAUC+mN;{9((hMz&EK`IC^}hGu*52 z4oyP)*trI8U8oWLcG`_kt3?aPYb*3;r!5^fl_{F-lKoQz<4r3gJH3^k1dI& z-T0uP*RiLgKWgV%T4v6;b~X2Y@c|EWg(U1ha};h0V#Eo8g86M^$rC+X6Y>jRM_~QW ztJsJ)%yTQ@arIYjHM@86uj$YSheSB})g&7|yf@Mvo>^boW;uOi{I}`TYs6lR;ls0e zc!W>G-`f^9zZB)deE4Qrf+Z$N4DOahKDb7?;909ZCw~7=F}Ca4i8!2+Q~dUq;Ez%# ZTR+9eVRQMdu1av>EB|Y~;g;f>e*r