Harness Academy
Tài liệu gốc 25 9 phútTiếng Việt + English
docs/conversation-search.mdXem bản gốc
Ngôn ngữ bài đọc
Bản dịch tiếng Việt

Bản dịch đầy đủ theo đúng cấu trúc tài liệu; code, liên kết và định danh kỹ thuật được giữ nguyên.

Tìm kiếm cuộc hội thoại

ConversationSearch mang lại cho mô hình một search_conversation_history công cụ BM25 xếp hạng lịch sử a StepPersistence khả năng vẫn tồn tại -- các lượt nén trước đó bị loại bỏ khỏi ngữ cảnh trực tiếp và các lần chạy trước đây trong cùng một cuộc trò chuyện theo mặc định.

Nguồn

Mặc dù Pydantic AI Harness có trên các bản phát hành 0.x nhưng API có thể thay đổi giữa các bản phát hành nhỏ; khi đó, cảnh báo ngừng sử dụng và hướng dẫn di chuyển ghi chú phát hành sẽ cho bạn (hoặc người đại diện của bạn) biết chính xác cách nâng cấp. Xem chính sách phiên bản.

vấn đề

Khả năng nén (SlidingWindowCompaction, SummarizingCompaction, ...) thu hẹp lịch sử trực tiếp để phù hợp với cửa sổ ngữ cảnh. SummarizingCompaction vẫn duy trì các chỉnh sửa của nó: khi tiền tố được thay thế bằng một bản tóm tắt, bản gốc sẽ biến mất khỏi lần chạy message_history ở lượt tiếp theo. Mô hình không còn có thể nhớ lại đường dẫn tệp chính xác, quyết định hoặc giá trị đã nêu trước đó -- chỉ có thể diễn giải tóm tắt về nó. Và không có gì từ các lần chạy trước có thể truy cập được, tuy nhiên vẫn tồn tại tốt.

Giải pháp

ConversationSearch bản thân nó không tồn tại gì cả. Nó đọc bất cứ thứ gì mà khả năng lưu giữ lâu dài đã lưu trữ, thông qua một HistorySourcevà hiển thị một công cụ, search_conversation_history, BM25 xếp hạng lịch sử đó để mô hình có thể đưa các chi tiết chính xác trở lại bối cảnh theo yêu cầu.

Nguồn vận chuyển, SnapshotHistorySource, đọc ảnh chụp nhanh StepPersistence ghi: ghép nối hai khả năng trên một phiên bản cửa hàng dùng chung và tính năng thu hồi hoạt động mà không cần đường dẫn ghi bổ sung, không có ràng buộc về thứ tự và không cần phối hợp hook. Theo mặc định, tìm kiếm nằm trong phạm vi cuộc hội thoại, vì vậy hãy chuyển tương tự conversation_id trên mỗi lần chạy nên chia sẻ một kho văn bản:

from pydantic_ai import Agent
from pydantic_ai_harness import ConversationSearch, SlidingWindowCompaction, StepPersistence
from pydantic_ai_harness.conversation_search import SnapshotHistorySource
from pydantic_ai_harness.step_persistence import SqliteStepStore

store = SqliteStepStore(database='sessions.db')
agent = Agent(
    'openai:gpt-5',
    capabilities=[
        StepPersistence(store=store),
        ConversationSearch(SnapshotHistorySource(store), scope='conversation'),
        SlidingWindowCompaction(max_messages=40),
    ],
)


async def ask(question: str, conversation_id: str) -> str:
    result = await agent.run(question, conversation_id=conversation_id)
    return result.output
  • Xếp hạng là BM25 (thuật toán đằng sau Lucene/Elasticsearch), được triển khai bằng Python thuần túy -- không có phần phụ thuộc mới. Các thuật ngữ hiếm và các kết quả trùng khớp chính xác có điểm cao hơn; truy vấn nhiều từ cho điểm từng từ một cách độc lập.
  • Để đạt được lượt chạy trước đây yêu cầu cả hai lượt chạy phải chia sẻ điểm conversation_id. pydantic-ai giải quyết một lần mỗi lần chạy: một cách rõ ràng conversation_id= thắng, nếu không thì gần đây nhất conversation_id trên message_history được kế thừa, nếu không thì một cái mới sẽ được tạo ra. Luồng message_history do đó thông qua các lần theo dõi sẽ giữ họ trong một cuộc trò chuyện; các lần chạy chia sẻ không có id rõ ràng cũng như chuỗi lịch sử riêng biệt.
  • Kết quả mang xuất xứ (run: ... | conversation: ...) và công cụ này là tùy chọn run_id đối số xác định phạm vi tìm kiếm trong một lần chạy -- do đó, một lần chạy được tham chiếu ở nơi khác (ví dụ: bằng phần xử lý bản ghi của biên nhận nén) có thể được phân giải trực tiếp.
  • Tìm kiếm đọc cửa hàng một cách lười biếng vào thời điểm gọi, vì vậy nó luôn thấy mọi thứ vẫn tồn tại cho đến nay, bao gồm cả các bước trước đó của lần chạy hiện tại.

Cách phục hồi hoạt động

StepPersistence lưu ảnh chụp nhanh toàn bộ lịch sử ở mọi ranh giới bước. Một chiến lược nén vẫn duy trì các chỉnh sửa của nó (như SummarizingCompaction) chuyển những chỉnh sửa đó thành ảnh chụp nhanh sau -- nhưng các ảnh chụp nhanh trước đó của cùng một lần chạy đã được chụp trong khi ảnh gốc vẫn còn tồn tại. SnapshotHistorySource kết hợp các ảnh chụp nhanh của mỗi lần chạy theo thứ tự ghi, bỏ qua các tạo phẩm tóm tắt dẫn xuất và loại bỏ sự chồng chéo giữa hậu tố của lịch sử tích lũy và tiền tố của mỗi ảnh chụp nhanh. Điều này khôi phục bản gốc cộng với mọi thứ nén chưa bao giờ được chạm tới trong khi vẫn lưu giữ các thông báo lặp lại ở các vị trí trình tự riêng biệt -- cho đến khi cửa hàng vẫn giữ lại các ảnh chụp nhanh trước khi nén đó (xem Hạn chế). Chỉ complete ảnh chụp nhanh đóng góp: interrupted các lần chụp (công cụ chưa được xử lý, trả về công cụ tổng hợp) bị loại trừ bởi cổng đọc mặc định của cửa hàng.

Các khóa khớp chồng chéo khỏi hàm băm nội dung của từng thông báo được tuần tự hóa chứ không phải nhận dạng đối tượng: các ảnh chụp nhanh liên tiếp sẽ tuần tự hóa lại cùng một lịch sử đang phát triển và các trình thực thi lâu bền (Tạm thời, DBOS) sẽ khởi tạo lại các thông báo giữa các bước.

HistorySource có chủ ý là trung tính về chất nền ("liệt kê các lần chạy, mang lại bản ghi thông báo lâu dài của mỗi lần chạy"): chất nền bền vững giữ nhật ký mục nhập chỉ bổ sung có thể triển khai trực tiếp bằng cách phát lại, thay thế bộ điều hợp ảnh chụp nhanh mà không cần chạm vào lớp tìm kiếm.

Phạm vi

scope='conversation' hạn chế kho văn bản chạy mà conversation_id phù hợp với việc chạy cuộc gọi. Chuyển một giá trị được xác thực, trong phạm vi đối tượng thuê dưới dạng conversation_id khi chạy agent:

agent = Agent(
    'openai:gpt-5',
    capabilities=[
        StepPersistence(store=store),
        ConversationSearch(SnapshotHistorySource(store), scope='conversation'),
    ],
)


async def ask(question: str, user_id: str) -> str:
    result = await agent.run(question, conversation_id=user_id)
    return result.output

Sau đó, kho dữ liệu bị hạn chế chạy mà conversation_id khớp với lệnh gọi, mô tả riêng của công cụ sẽ cho mô hình biết hạn chế được áp dụng và mô tả của công cụ run_id đối số không thể vượt qua nó - một lần chạy ngoài phạm vi báo cáo cùng một câu trả lời "không có lịch sử tồn tại" như một lần chạy không tồn tại.

pydantic-ai giải quyết lệnh gọi conversation_id theo một thứ tự cố định: rõ ràng conversation_id= tranh luận với Agent.run(...), sau đó là gần đây nhất conversation_id tiếp tục message_history, sau đó là UUID7 mới. Vượt qua conversation_id='new' buộc một cuộc trò chuyện mới, tạo ra một cuộc trò chuyện ngoài lịch sử được cung cấp.

Lệnh đó có hai hậu quả đối với phạm vi này. Một lần chạy tiếp theo chủ đề đó message_history kế thừa id của lần chạy trước, vì vậy nó có thể tìm kiếm các lần chạy phía sau nó mà không cần truyền đối số. Một lần chạy không vượt qua id rõ ràng cũng như chuỗi lịch sử không nhận được id của riêng nó và chỉ đạt đến chính nó -- một đối số bị bỏ qua không phải là lỗi ở đây, chỉ là một kho văn bản hẹp hơn. Cả hai hành vi đều không phải là ranh giới cô lập để dựa vào để phân tách nhiều đối tượng thuê: vượt qua một đối tượng thuê được xác thực, có phạm vi conversation_id= một cách rõ ràng (đó là giá trị StepPersistence hồ sơ đang chạy).

A RunContext của ai conversation_id không được đặt, không tìm kiếm gì trong phạm vi này và công cụ sẽ cho biết lý do. Việc khớp "id cuộc hội thoại chưa được đặt" sẽ gộp mọi lần chạy không được gắn nhãn trong cửa hàng vào một kho dữ liệu, đây là mức độ phơi nhiễm mà phạm vi tồn tại để ngăn chặn, do đó, thay vào đó, nó không thể đóng được.

Phạm vi được áp dụng cho RunRecords a HistorySource trả về, vì vậy một nguồn tùy chỉnh phải được điền conversation_id trên chúng để có phạm vi mặc định phù hợp với mọi thứ. Đặt scope='all' chỉ khi cửa hàng đã được cách ly với một hiệu trưởng. Chế độ chọn tham gia này tìm kiếm mỗi lần chạy bảng liệt kê nguồn và có thể trả về các đoạn trích nguyên văn từ bất kỳ đoạn trích nào trong số chúng.

Di cư từ scope='all' mặc định

Mặc định này đã thay đổi. Các bản phát hành trước đó được mặc định là scope='all', do đó, một tìm kiếm được xếp hạng mỗi lần chạy trong cửa hàng; bây giờ nó mặc định là conversation. Không có gì tăng lên khi nâng cấp -- người gọi dựa vào chế độ mặc định cũ vẫn tiếp tục hoạt động và chỉ dừng xem các cuộc trò chuyện khác -- vì vậy hãy rời đi scope bỏ đặt phát ra một HarnessDeprecationWarning một lần cho mỗi phiên bản khả năng đặt tên cho thay đổi.

Đặt tùy chọn rõ ràng để giải quyết nó. Cả hai giá trị đều được hỗ trợ và không bị phản đối:

  • scope='all' khôi phục hành vi toàn cửa hàng trước đó. Đúng khi cửa hàng lưu giữ lịch sử của một hiệu trưởng.
  • scope='conversation' giữ hành vi mới và tắt cảnh báo.

Tắt tiếng mọi hoạt động ngừng sử dụng khai thác cùng một lúc, nếu bạn muốn di chuyển sau:

import warnings

from pydantic_ai_harness import HarnessDeprecationWarning

warnings.filterwarnings('ignore', category=HarnessDeprecationWarning)

Tùy chọn chính

Tùy chọnMặc địnhMục đích
source(bắt buộc)Xác chết đến từ đâu. sử dụng SnapshotHistorySource(store) qua cửa hàng StepPersistence viết vào.
scope'conversation' (bỏ đặt cảnh báo)Hạn chế tìm kiếm trong lần chạy cuộc gọi conversation_id. sử dụng 'all' chỉ dành cho một cửa hàng bị cô lập với một hiệu trưởng. Để nó không được đặt sẽ cảnh báo một lần; xem Phạm vi.
max_matches10Trích đoạn phù hợp tối đa mà công cụ tìm kiếm trả về.
context_lines5Các dòng hiển thị xung quanh mỗi trận đấu (trong thời gian diễn ra trận đấu).
bm25_k11.5Độ bão hòa tần số thuật ngữ BM25. Mặc định của khả năng này; của Lucene BM25Similarity công dụng 1.2.
bm25_b0.75Chuẩn hóa độ dài BM25 (mặc định Lucene).
add_instructionsTruePhát ra một ghi chú ngắn cho mô hình biết công cụ thu hồi tồn tại.
tool_idconversation-searchId bộ công cụ cho công cụ tìm kiếm.

Hạn chế

  • Tìm kiếm chỉ đạt được những gì đã tồn tại: lịch sử được kế thừa từ các lần chạy không bao giờ chạy cùng StepPersistence (ví dụ như một thời gian dài message_history được truyền vào từ một phiên không được duy trì) không thể được phục hồi nếu việc nén bỏ nó trước ảnh chụp nhanh đầu tiên.
  • Việc khôi phục các bản gốc bị nén lại phụ thuộc vào các ảnh chụp nhanh trước khi nén vẫn được giữ lại. Một cửa hàng có khả năng lưu giữ ảnh chụp nhanh có giới hạn (ví dụ: giới hạn ảnh chụp nhanh mỗi lần chạy) có thể cắt bớt các ảnh chụp nhanh sớm chứa các ảnh gốc đó; sau đó tìm kiếm chỉ trả về những gì mà ảnh chụp nhanh còn sót lại vẫn mang theo, chuyển thành kết quả một phần thay vì có lỗi. Giữ lại toàn bộ lịch sử ảnh chụp nhanh trong quá trình chạy nếu quá trình khôi phục hoàn toàn quan trọng.
  • Kho dữ liệu được xây dựng lại trên mỗi lệnh gọi công cụ bằng cách đọc ảnh chụp nhanh của mọi lần chạy trong phạm vi. Dung lượng lưu trữ ảnh chụp nhanh được tích lũy (mỗi ảnh chụp nhanh sẽ tuần tự hóa lại lịch sử ngày càng tăng), do đó, lịch sử lớn trong phạm vi sẽ khiến mỗi tìm kiếm trở nên đắt hơn tương ứng. Một chỉ mục liên tục (SQLite FTS5, được theo dõi trong #124) là đường dẫn tỷ lệ.
  • Đọc ảnh chụp nhanh khôi phục phương tiện bên ngoài (tải trọng nhị phân lớn) ngay cả khi chỉ mục văn bản không bao giờ sử dụng nó; các cửa hàng có chương trình phụ trợ phương tiện từ xa sẽ trả chi phí tìm nạp đó cho mỗi lần tìm kiếm.

Đọc thêm

Tham chiếu API

::: pydantic_ai_harness.conversation_search.ConversationSearch

Mục lục nguồn