.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "build_tutorial/structured_output.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_build_tutorial_structured_output.py: .. _structured-output: Structured Output ========================== In this tutorial, we will be building a simple agent that outputs structured data in JSON dictionary format using the `agentscope.parsers` module. .. GENERATED FROM PYTHON SOURCE LINES 11-13 .. code-block:: Python from agentscope.models import ModelResponse .. GENERATED FROM PYTHON SOURCE LINES 14-16 Defining the Parser ------------------- .. GENERATED FROM PYTHON SOURCE LINES 16-26 .. code-block:: Python from agentscope.parsers import MarkdownJsonDictParser parser = MarkdownJsonDictParser( content_hint='{"thought": "What you thought", "speak": "What you speak to the user"}', required_keys=["thought", "speak"], ) .. GENERATED FROM PYTHON SOURCE LINES 27-30 The parser will generate a format instruction according to your input. You can use the `format_instruction` property to in your prompt to guide LLM to generate the desired output. .. GENERATED FROM PYTHON SOURCE LINES 30-33 .. code-block:: Python print(parser.format_instruction) .. rst-class:: sphx-glr-script-out .. code-block:: none Respond a JSON dictionary in a markdown's fenced code block as follows: ```json {"thought": "What you thought", "speak": "What you speak to the user"} ``` .. GENERATED FROM PYTHON SOURCE LINES 34-41 Parsing the Output ------------------- When receiving output from LLM, use `parse` method to extract the structured data. It takes an object of `agentscope.models.ModelResponse` as input, parses the value of the `text` field, and returns a parsed dictionary in the `parsed` field. .. GENERATED FROM PYTHON SOURCE LINES 41-58 .. code-block:: Python dummy_response = ModelResponse( text="""```json { "thought": "I should greet the user", "speak": "Hi! How can I help you?" } ```""", ) print(f"parsed field before parsing: {dummy_response.parsed}") parsed_response = parser.parse(dummy_response) print(f"parsed field after parsing: {parsed_response.parsed}") print(type(parsed_response.parsed)) .. rst-class:: sphx-glr-script-out .. code-block:: none parsed field before parsing: None parsed field after parsing: {'thought': 'I should greet the user', 'speak': 'Hi! How can I help you?'} .. GENERATED FROM PYTHON SOURCE LINES 59-65 Error Handling ------------------- If the LLM output does not match the expected format, the parser will raise an error with a detailed message. So developers can present the error message to LLM to guide it to correct the output. .. GENERATED FROM PYTHON SOURCE LINES 65-79 .. code-block:: Python error_response = ModelResponse( text="""```json { "thought": "I should greet the user" } ```""", ) try: parsed_response = parser.parse(error_response) except Exception as e: print(e) .. rst-class:: sphx-glr-script-out .. code-block:: none RequiredFieldNotFoundError: Missing required field speak in the JSON dictionary object. .. GENERATED FROM PYTHON SOURCE LINES 80-90 Advanced Usage ------------------- More Complex Content ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Asking LLM to directly generate a JSON dictionary can be challenging, especially when the JSON content is complex (e.g. code snippets, nested structures). In this case, you can use more advanced parsers to guide LLM to generate the desired output. Here is an example of a more complex parser that handle code snippets. .. GENERATED FROM PYTHON SOURCE LINES 90-109 .. code-block:: Python from agentscope.parsers import RegexTaggedContentParser parser = RegexTaggedContentParser( format_instruction="""Response in the following format: what you thought A random number here your python code here """, try_parse_json=True, # Try to parse the each value as a JSON object required_keys=[ "thought", "number", "code", ], # Required keys in the parsed dictionary ) print(parser.format_instruction) .. rst-class:: sphx-glr-script-out .. code-block:: none Response in the following format: what you thought A random number here your python code here .. GENERATED FROM PYTHON SOURCE LINES 110-115 The `RegexTaggedContentParser` uses regular expressions to match the tagged content in the text and return the parsed dictionary. .. note:: The parsed output of `RegexTaggedContentParser` is a dictionary, which means the required keys should be unique. You can also change the regular expression pattern by settings the `tagged_content_pattern` parameter when initializing the parser. .. GENERATED FROM PYTHON SOURCE LINES 115-133 .. code-block:: Python import json dummy_response = ModelResponse( text="""Print the current date 42 import datetime print(datetime.datetime.now()) """, ) parsed_response = parser.parse(dummy_response) print("The type of parsed response: ", type(parsed_response.parsed)) print("The type of the number: ", type(parsed_response.parsed["number"])) print(json.dumps(parsed_response.parsed, indent=4)) .. rst-class:: sphx-glr-script-out .. code-block:: none The type of parsed response: The type of the number: { "thought": "Print the current date", "number": 42, "code": "import datetime\nprint(datetime.datetime.now())\n" } .. GENERATED FROM PYTHON SOURCE LINES 134-163 Auto Post-Processing ^^^^^^^^^^^^^^^^^^^^ Within the parsed dictionary, different keys may require different post-processing steps. For example, in a werewolf game, the LLM is playing the role of a seer, and the output should contain the following keys: - `thought`: The seer's thoughts - `speak`: The seer's speech - `use_ability`: A boolean value indicating whether the seer should use its ability In this case, the `thought` and `speak` contents should be stored in the agent's memory to ensure the consistency of the agent's behavior. The `speak` content should be spoken out to the user. The `use_ability` key should be accessed outside the agent easily to determine the game flow. AgentScope supports automatic post-processing of the parsed dictionary by providing the following parameters when initializing the parser. - `keys_to_memory`: key(s) that should be stored in the agent's memory - `keys_to_content`: key(s) that should be spoken out - `keys_to_metadata`: key(s) that should be stored in the metadata field of the agent's response message .. note:: If a string is provided, the parser will extract the value of the given key from the parsed dictionary. If a list of strings is provided, a sub-dictionary will be created with the given keys. Here is an example of using the `MarkdownJsonDictParser` to automatically post-process the parsed dictionary. .. GENERATED FROM PYTHON SOURCE LINES 163-188 .. code-block:: Python parser = MarkdownJsonDictParser( content_hint='{"thought": "what you thought", "speak": "what you speak", "use_ability": "whether to use the ability"}', keys_to_memory=["thought", "speak"], keys_to_content="speak", keys_to_metadata="use_ability", ) dummy_response = ModelResponse( text="""```json { "thought": "I should ...", "speak": "I will not use my ability", "use_ability": false }``` """, ) parsed_response = parser.parse(dummy_response) print("The parsed response: ", parsed_response.parsed) print("To memory", parser.to_memory(parsed_response.parsed)) print("To message content: ", parser.to_content(parsed_response.parsed)) print("To message metadata: ", parser.to_metadata(parsed_response.parsed)) .. rst-class:: sphx-glr-script-out .. code-block:: none The parsed response: {'thought': 'I should ...', 'speak': 'I will not use my ability', 'use_ability': False} To memory {'thought': 'I should ...', 'speak': 'I will not use my ability'} To message content: I will not use my ability To message metadata: False .. GENERATED FROM PYTHON SOURCE LINES 189-197 Here we show how to create an agent that can automatically post-process the parsed dictionary by the following core steps in the `reply` method. 1. Put the format instruction in prompt to guide LLM to generate the desired output 2. Parse the LLM response 3. Post-process the parsed dictionary by using the `to_memory`, `to_content`, and `to_metadata` methods .. tip:: By changing different parsers, the agent can adapt to different scenarios and generate structured output in various formats. .. GENERATED FROM PYTHON SOURCE LINES 197-251 .. code-block:: Python from agentscope.models import DashScopeChatWrapper from agentscope.agents import AgentBase from agentscope.message import Msg class Agent(AgentBase): def __init__(self): self.name = "Alice" super().__init__(name=self.name) self.sys_prompt = f"You're a helpful assistant named {self.name}." self.model = DashScopeChatWrapper( config_name="_", model_name="qwen-max", ) self.parser = MarkdownJsonDictParser( content_hint='{"thought": "what you thought", "speak": "what you speak", "use_ability": "whether to use the ability"}', keys_to_memory=["thought", "speak"], keys_to_content="speak", keys_to_metadata="use_ability", ) self.memory.add(Msg("system", self.sys_prompt, "system")) def reply(self, msg): self.memory.add(msg) prompt = self.model.format( self.memory.get_memory(), # Instruct the model to respond in the required format Msg("system", self.parser.format_instruction, "system"), ) response = self.model(prompt) parsed_response = self.parser.parse(response) self.memory.add( Msg( name=self.name, content=self.parser.to_memory(parsed_response.parsed), role="assistant", ), ) return Msg( name=self.name, content=self.parser.to_content(parsed_response.parsed), role="assistant", metadata=self.parser.to_metadata(parsed_response.parsed), ) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.004 seconds) .. _sphx_glr_download_build_tutorial_structured_output.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: structured_output.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: structured_output.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: structured_output.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_