[Python] How to store Gemini 2.5 Flash + MCP multi-turn conversation data (including tool...

Discussão em 'Python' iniciado por Stack, Agosto 12, 2025.

  1. Stack

    Stack Membro Participativo

    I’m building a multi-turn conversation system using Gemini 2.5 Flash with thinking and Model Context Protocol (MCP) tool calls. With OpenAI models, I usually store conversation history as an array of messages (role, content) and that’s enough for replaying the chat.

    With Gemini + MCP, I’m getting much richer responses — including function_call, function_response, and thought_signature — and I’m unsure what should be stored to faithfully reconstruct the conversation later.

    Example (trimmed for brevity):

    {
    "sdk_http_response": {
    "headers": {
    "Content-Type": "application/json; charset=UTF-8",
    "Vary": "Origin, X-Origin, Referer",
    "Content-Encoding": "gzip",
    "Date": "Wed, 13 Aug 2025 01:35:21 GMT",
    "Server": "scaffolding on HTTPServer2",
    "X-XSS-Protection": "0",
    "X-Frame-Options": "SAMEORIGIN",
    "X-Content-Type-Options": "nosniff",
    "Server-Timing": "gfet4t7; dur=4209",
    "Alt-Svc": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000",
    "Transfer-Encoding": "chunked"
    },
    "body": null
    },
    "candidates": [
    {
    "content": {
    "parts": [
    {
    "video_metadata": null,
    "thought": null,
    "inline_data": null,
    "file_data": null,
    "thought_signature": "b'\\n\\xa9\\x0c\\x01T\\xa8\\\\\\xee\\xd4\\xb6\\xf6%\\xd5\\...''",
    "code_execution_result": null,
    "executable_code": null,
    "function_call": null,
    "function_response": null,
    "text": "INSIGHTS\n- Current total: **290 employees**\n- Status mix: All employees are currently active.\n- Top segments by job title:..."
    }
    ],
    "role": "model"
    },
    "citation_metadata": null,
    "finish_message": null,
    "token_count": null,
    "finish_reason": {
    "_value_": "STOP",
    "_name_": "STOP",
    "__objclass__": "{'_generate_next_value_': <function Enum._generate_next_value_ at 0x0000015CD5637BA0>, '__module__': 'google.genai.types', '__doc__': 'Output only. The reason why the model stopped generating tokens.\\n\\n If empty, the model has not stopped generating the tokens.\\n ', '_new_member_': <built-in method __new__ of type object at 0x00007FF8DCD1B980>, '_use_args_': True, '_member_names_': ['FINISH_REASON_UNSPECIFIED', 'STOP', 'MAX_TOKENS', 'SAFETY', 'RECITATION', 'LANGUAGE', 'OTHER', 'BLOCKLIST', 'PROHIBITED_CONTENT', 'SPII', 'MALFORMED_FUNCTION_CALL', 'IMAGE_SAFETY', 'UNEXPECTED_TOOL_CALL'], '_member_map_': {'FINISH_REASON_UNSPECIFIED': <FinishReason.FINISH_REASON_UNSPECIFIED: 'FINISH_REASON_UNSPECIFIED'>, 'STOP': <FinishReason.STOP: 'STOP'>, 'MAX_TOKENS': <FinishReason.MAX_TOKENS: 'MAX_TOKENS'>, 'SAFETY': <FinishReason.SAFETY: 'SAFETY'>, 'RECITATION': <FinishReason.RECITATION: 'RECITATION'>, 'LANGUAGE': <FinishReason.LANGUAGE: 'LANGUAGE'>, 'OTHER': <FinishReason.OTHER: 'OTHER'>, 'BLOCKLIST': <FinishReason.BLOCKLIST: 'BLOCKLIST'>, 'PROHIBITED_CONTENT': <FinishReason.PROHIBITED_CONTENT: 'PROHIBITED_CONTENT'>, 'SPII': <FinishReason.SPII: 'SPII'>, 'MALFORMED_FUNCTION_CALL': <FinishReason.MALFORMED_FUNCTION_CALL: 'MALFORMED_FUNCTION_CALL'>, 'IMAGE_SAFETY': <FinishReason.IMAGE_SAFETY: 'IMAGE_SAFETY'>, 'UNEXPECTED_TOOL_CALL': <FinishReason.UNEXPECTED_TOOL_CALL: 'UNEXPECTED_TOOL_CALL'>}, '_value2member_map_': {'FINISH_REASON_UNSPECIFIED': <FinishReason.FINISH_REASON_UNSPECIFIED: 'FINISH_REASON_UNSPECIFIED'>, 'STOP': <FinishReason.STOP: 'STOP'>, 'MAX_TOKENS': <FinishReason.MAX_TOKENS: 'MAX_TOKENS'>, 'SAFETY': <FinishReason.SAFETY: 'SAFETY'>, 'RECITATION': <FinishReason.RECITATION: 'RECITATION'>, 'LANGUAGE': <FinishReason.LANGUAGE: 'LANGUAGE'>, 'OTHER': <FinishReason.OTHER: 'OTHER'>, 'BLOCKLIST': <FinishReason.BLOCKLIST: 'BLOCKLIST'>, 'PROHIBITED_CONTENT': <FinishReason.PROHIBITED_CONTENT: 'PROHIBITED_CONTENT'>, 'SPII': <FinishReason.SPII: 'SPII'>, 'MALFORMED_FUNCTION_CALL': <FinishReason.MALFORMED_FUNCTION_CALL: 'MALFORMED_FUNCTION_CALL'>, 'IMAGE_SAFETY': <FinishReason.IMAGE_SAFETY: 'IMAGE_SAFETY'>, 'UNEXPECTED_TOOL_CALL': <FinishReason.UNEXPECTED_TOOL_CALL: 'UNEXPECTED_TOOL_CALL'>}, '_unhashable_values_': [], '_member_type_': <class 'str'>, '_value_repr_': <slot wrapper '__repr__' of 'str' objects>, 'FINISH_REASON_UNSPECIFIED': <FinishReason.FINISH_REASON_UNSPECIFIED: 'FINISH_REASON_UNSPECIFIED'>, 'STOP': <FinishReason.STOP: 'STOP'>, 'MAX_TOKENS': <FinishReason.MAX_TOKENS: 'MAX_TOKENS'>, 'SAFETY': <FinishReason.SAFETY: 'SAFETY'>, 'RECITATION': <FinishReason.RECITATION: 'RECITATION'>, 'LANGUAGE': <FinishReason.LANGUAGE: 'LANGUAGE'>, 'OTHER': <FinishReason.OTHER: 'OTHER'>, 'BLOCKLIST': <FinishReason.BLOCKLIST: 'BLOCKLIST'>, 'PROHIBITED_CONTENT': <FinishReason.PROHIBITED_CONTENT: 'PROHIBITED_CONTENT'>, 'SPII': <FinishReason.SPII: 'SPII'>, 'MALFORMED_FUNCTION_CALL': <FinishReason.MALFORMED_FUNCTION_CALL: 'MALFORMED_FUNCTION_CALL'>, 'IMAGE_SAFETY': <FinishReason.IMAGE_SAFETY: 'IMAGE_SAFETY'>, 'UNEXPECTED_TOOL_CALL': <FinishReason.UNEXPECTED_TOOL_CALL: 'UNEXPECTED_TOOL_CALL'>, '__new__': <function Enum.__new__ at 0x0000015CD5637A60>}",
    "_sort_order_": 1
    },
    "url_context_metadata": null,
    "avg_logprobs": null,
    "grounding_metadata": null,
    "index": 0,
    "logprobs_result": null,
    "safety_ratings": null
    }
    ],
    "create_time": null,
    "model_version": "gemini-2.5-flash",
    "prompt_feedback": null,
    "response_id": "2eubaISSKc7ZqtsPl_i46Qk",
    "usage_metadata": {
    "cache_tokens_details": null,
    "cached_content_token_count": null,
    "candidates_token_count": 218,
    "candidates_tokens_details": null,
    "prompt_token_count": 6409,
    "prompt_tokens_details": [
    {
    "modality": {
    "_value_": "TEXT",
    "_name_": "TEXT",
    "__objclass__": "{'_generate_next_value_': <function Enum._generate_next_value_ at 0x0000015CD5637BA0>, '__module__': 'google.genai.types', '__doc__': 'Server content modalities.', '_new_member_': <built-in method __new__ of type object at 0x00007FF8DCD1B980>, '_use_args_': True, '_member_names_': ['MODALITY_UNSPECIFIED', 'TEXT', 'IMAGE', 'VIDEO', 'AUDIO', 'DOCUMENT'], '_member_map_': {'MODALITY_UNSPECIFIED': <MediaModality.MODALITY_UNSPECIFIED: 'MODALITY_UNSPECIFIED'>, 'TEXT': <MediaModality.TEXT: 'TEXT'>, 'IMAGE': <MediaModality.IMAGE: 'IMAGE'>, 'VIDEO': <MediaModality.VIDEO: 'VIDEO'>, 'AUDIO': <MediaModality.AUDIO: 'AUDIO'>, 'DOCUMENT': <MediaModality.DOCUMENT: 'DOCUMENT'>}, '_value2member_map_': {'MODALITY_UNSPECIFIED': <MediaModality.MODALITY_UNSPECIFIED: 'MODALITY_UNSPECIFIED'>, 'TEXT': <MediaModality.TEXT: 'TEXT'>, 'IMAGE': <MediaModality.IMAGE: 'IMAGE'>, 'VIDEO': <MediaModality.VIDEO: 'VIDEO'>, 'AUDIO': <MediaModality.AUDIO: 'AUDIO'>, 'DOCUMENT': <MediaModality.DOCUMENT: 'DOCUMENT'>}, '_unhashable_values_': [], '_member_type_': <class 'str'>, '_value_repr_': <slot wrapper '__repr__' of 'str' objects>, 'MODALITY_UNSPECIFIED': <MediaModality.MODALITY_UNSPECIFIED: 'MODALITY_UNSPECIFIED'>, 'TEXT': <MediaModality.TEXT: 'TEXT'>, 'IMAGE': <MediaModality.IMAGE: 'IMAGE'>, 'VIDEO': <MediaModality.VIDEO: 'VIDEO'>, 'AUDIO': <MediaModality.AUDIO: 'AUDIO'>, 'DOCUMENT': <MediaModality.DOCUMENT: 'DOCUMENT'>, '__new__': <function Enum.__new__ at 0x0000015CD5637A60>}",
    "_sort_order_": 1
    },
    "token_count": 6409
    }
    ],
    "thoughts_token_count": 306,
    "tool_use_prompt_token_count": null,
    "tool_use_prompt_tokens_details": null,
    "total_token_count": 6933,
    "traffic_type": null
    },
    "automatic_function_calling_history": [
    {
    "parts": [
    {
    "video_metadata": null,
    "thought": null,
    "inline_data": null,
    "file_data": null,
    "thought_signature": null,
    "code_execution_result": null,
    "executable_code": null,
    "function_call": null,
    "function_response": null,
    "text": "how many emplyoees do we have?"
    }
    ],
    "role": "user"
    },
    {
    "parts": [
    {
    "video_metadata": null,
    "thought": null,
    "inline_data": null,
    "file_data": null,
    "thought_signature": "b'\\n\\xbf\\x03\\x01T\\xa8\\\\\\xee...'",
    "code_execution_result": null,
    "executable_code": null,
    "function_call": null,
    "function_response": null,
    "text": "Clarifying which data best answers your question so results are reliable."
    },
    {
    "video_metadata": null,
    "thought": null,
    "inline_data": null,
    "file_data": null,
    "thought_signature": null,
    "code_execution_result": null,
    "executable_code": null,
    "function_call": {
    "id": null,
    "args": {},
    "name": "list_tables"
    },
    "function_response": null,
    "text": null
    }
    ],
    "role": "model"
    },
    {
    "parts": [
    {
    "video_metadata": null,
    "thought": null,
    "inline_data": null,
    "file_data": null,
    "thought_signature": null,
    "code_execution_result": null,
    "executable_code": null,
    "function_call": null,
    "function_response": {
    "will_continue": null,
    "scheduling": null,
    "id": null,
    "name": "list_tables",
    "response": {
    "result": {
    "meta": null,
    "content": [
    {
    "type": "text",
    "text": "Available tables: ['Sales.SalesTaxRate', 'Sales.PersonCreditCard', ...",
    "annotations": null,
    "meta": null
    }
    ],
    "structuredContent": {
    "result": "Available tables: ['Sales.SalesTaxRate', 'Sales.PersonCreditCard', ..."
    },
    "isError": false
    }
    }
    },
    "text": null
    }
    ],
    "role": "user"
    }
    ],
    "parsed": null
    }


    My questions:


    1. What’s the best practice for storing messages from both the user and the model, including tool calls and tool responses, so I can later replay or analyze the conversation?


    2. Should I store all fields, including thought_signature, or is it safe to omit some parts for storage efficiency?


    3. Is there a recommended JSON schema for Gemini+MCP conversation history, similar to OpenAI’s messages format, but with support for function_call and function_response?

    I’m using the google.genai Python SDK (Gemini 2.5 Flash) with automatic function calling via an MCP tool.

    Continue reading...

Compartilhe esta Página