Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

⚡️ Speed up methodAgentRunResult._set_output_tool_return by 18798%#2196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Conversation

misrasaurabh1
Copy link
Contributor

📄 18,798% (187.98x) speedup forAgentRunResult._set_output_tool_return inpydantic_ai_slim/pydantic_ai/agent.py

⏱️ Runtime :8.31 milliseconds44.0 microseconds (best of21 runs)

📝 Explanation and details

Key optimization:

  • The deep copy of the whole message history (deepcopy(self._state.message_history)) was by far the slowest operation (99.3% of time).
  • The intent is to copy the list and its objects enough to mutate the last message's tool return part safely.
  • We optimize by.
    • Copying the message listshallowly, and only making a shallow copy of the last message and a shallow copy of its parts. This is much faster than recursively copying every nested attribute of every message.
    • We still keep copy-on-write semantics for the last message and the relevant parts subtree.
  • All other logic remains, but now is much faster due to a reduced amount of copying.

Notes:

  • We only deep-copy branches of the structure that will actually be mutated. This dramatically reduces overhead.
  • Defined behavior assumesModelMessage is a dataclass or otherwise supports__class__(**__dict__) for shallow copying. If this can't be guaranteed, substitute with a more explicit copy (e.g.,dataclasses.replace if it is a dataclass).
  • All output and error conditions remain identical.
  • The comments are preserved and extended for clarity where the code was changed.

Correctness verification report:

TestStatus
⚙️ Existing Unit Tests🔘None Found
🌀 Generated Regression Tests🔘None Found
⏪ Replay Tests2 Passed
🔎 Concolic Coverage Tests🔘None Found
📊 Tests Coverage88.9%
⏪ Replay Tests and Runtime
Test File::Test FunctionOriginal ⏱️Optimized ⏱️Speedup

Codeflash

codeflash-aibotand others added2 commitsJuly 12, 2025 09:37
Here's an optimized version of your code, focusing on the main bottleneck: `deepcopy(self._state.message_history)`.**Optimization explanation:**- `deepcopy` is extremely expensive (see profile: 99% of the time). Here, we only need to modify the last message's relevant tool part; the rest of `message_history` can be shared *unchanged*.- We replace `deepcopy` with a shallow copy for `messages`. Then we make a **copy of the last message** and only copy its `parts` list. This isolates mutation to the last message and its parts while *reusing* all previous messages unmodified.- This minimizes object allocations and recursive copying.**Functionality remains identical** (the changed code only avoids unnecessary copying).**Summary of improvements:**  - No deep copy unless necessary (minimal required copying).  - Lower memory churn and much faster.  - Identical results and error handling.  - Compatible with existing code and data class message structures.  This will provide a **dramatic speedup**, especially when `message_history` is long.
@KludexKludex requested a review fromCopilotJuly 15, 2025 08:31
Copy link

@CopilotCopilotAI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Pull Request Overview

A significant performance optimization for theAgentRunResult._set_output_tool_return method by replacing a full deep copy of the message history with a lazy copy that only deep copies the last message when needed.

  • Removed fulldeepcopy ofmessage_history
  • Introduced shallow copy of list and deep copy of only the last message
  • Maintained original error conditions and semantics
Comments suppressed due to low confidence (3)

pydantic_ai_slim/pydantic_ai/agent.py:2105

  • The new lazy-copy logic in this method introduces multiple code paths (no-op vs. deep-copy-and-modify). Consider adding unit tests that verify both branches—ensuring the originalmessage_history isn’t mutated when there’s no matching tool part and that only the last message is copied when a match is found.
        messages = self._state.message_history

pydantic_ai_slim/pydantic_ai/agent.py:2111

  • [nitpick] The variablecopied_last could be renamed tocopied_last_message for better clarity and readability.
                copied_last = deepcopy(last_message)

pydantic_ai_slim/pydantic_ai/agent.py:2105

  • [nitpick] The docstring still describes a full deep copy of the history but the implementation now uses a lazy-copy approach. Update the method’s docstring to reflect that only the last message is deep-copied when modified.
        messages = self._state.message_history

Copy link
Member

@samuelcolvinsamuelcolvin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

LGTM

misrasaurabh1 reacted with rocket emoji
@DouweMDouweM merged commite6396cc intopydantic:mainJul 17, 2025
18 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@dmontagudmontagudmontagu left review comments

Copilot code reviewCopilotCopilot left review comments

@samuelcolvinsamuelcolvinsamuelcolvin approved these changes

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

4 participants
@misrasaurabh1@samuelcolvin@dmontagu@DouweM

[8]ページ先頭

©2009-2025 Movatter.jp