Галоўная / Артыкулы

Практычныя нататкі: як фотагалерэя ператварылася ў аўтаномнага AI-агента

Практычны разбор тэмы «як ператварыць фотагалерэю ў аўтаномнага AI-агента»: кантракты, праверкі і гатовыя фрагменты кода для каманд, якія ўкараняюць гэты падыход.

Выдавец: REACTAPP.TOP31 хв чытання7088 слоў

Крыніцы: How I turned my photo gallery into an autonomous AI Agent — The Complete Guide

У гэтым карыце парадоксальнае шлях ад сыр'ёў да рабочай сістэмы для: «Як я ператворыў сваю галерэю фота на автонамнага агента AI — Повная інструкцыя». Акцэнт ставіцца на практычныя крокі, чысткія перакананні і код, які можна проста дадаць у рэпазітарый без неабяснення меты. У стадзіі агульнага відгледу неабходна прадзефінаваць вхідныя даны, адпаведальную особу за крок і крытэрыя завершэння пры перамены коду. Аперацыйныя працавнікі должны магчымае перадзеўсці крок з вядомага пункта контролю, не намагаючыся з'ясавіць схованы стан. Валідзіце маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшоў, прычына нехацкага рэзультата должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцужок задач.

Введэнне

Калі працюеце над стадзіяй «Введэнне», спачатку запісайце контракт: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс пераконтроўкаў дапамагае заліцвачыць змяны ў кодзе пазнейша. Спрыймайце гэтую стадзію як контракт межа данымі і перакананымі выходамі. Дайце назву рэзультатам, задацьце крытэрыя успеху і не падтрымайце тых, хто выкананяе задачу часткова без паведамлення. Зробіце пераконтроўку пасля дорогіх крокаў. Програма не должна зноў выкарыстоўваць той самы вызов LLM, калі аператар прабуе зноў выканаць пазнейшы элемент.

Чаму традыцыйны пошук фота не працюе

Калі працюеце над стадзіяй «Чаму традыцыйны пошук фота», спачатку запісайце умовы: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс контроля дапамагае заліцварваць можлівыя змены ў кодзе.

Запісвайце час выканання і кост токенаў або запытаў разам з функцыйнальнымі рэзултатамі. Відразы костаў з самага пачатку запобегае неспакойным рахункам, калі праця пераходзіць з дэмавай версіі ў спяльныя асяроддзя.

Зробіце контрольную пазнаку пасля дорогіх крокаў. Програма не должна зноў нарачыць косты за той самы вызов LLM, калі аператар прабуе зноў выконаць пазнейшы элемент.

Падход з альбамамі не працуе ў рэальных умовах

Калі працуеце над стадзіяй «The album approach collapses», спачатку запісайце контракт: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс пераконвае ў тым, што пазнейшыя змены коду будуць чыстымі. Зберагаеце настройкі за межамі коду прыемлі. Файлы сераўнавання, храненні секрэтных даных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аўдыт без неабяжлівага чытання всей структуры. Ставяйце контрольныя пункты пасля дорогіх крокаў. Сістэма вярнення праблемы не должна занова ставіць плату за той самы вызыв LLM, калі аператар перапрыяўляе працу да наступнага элемента. Калі працуеце над стадзіяй «The album approach collapses», спачатку запісайце контракт: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс пераконвае ў тым, што пазнейшыя змены коду будуць чыстымі. Валіце маленькія, тэставаныя елементы працы над вялікімі скрыптамі. Калі якісь крок не выйшаў, прычына нявыпання должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаную схему працы.

Пошук за ключовымі словамі дапамага толькі часткова

Пошук за ключовымі словамі ў стадыі распрацоўкі працюе найэфектывней, калі яго розглядаць як меркаваны параметр. Запісайце адна ідэальная версія, адзін прыклад неудачы і прыметкі па поверненню да попярэдней версіі, перш чым расшырваць масштабы працы. Разглядайце гэтае стадыю як кантракт межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Дайце назвы всім элементам, задаць крытэрыя успеху і не падзеўляйцеся частым, непূরным вікананнем задач. Зберагаюце стан графа ў простаму і тыпаванаму фармаце. Вкладышы-блокі маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакойваюць працу пасля перэрываў.

Пошук у галерэі воблака: добра, але за певную цену

Пошук у галерэі Cloud gallery працюе наяўнейша, калі яго спрыяваць як мерыемую паверхню. Запісаце адна «золатая» транскрыпцыя, адын прыклад неудачы і прыметку па вярнэнню да пачатковага стану пры расшырэнні масштаба. Запісвайце часы выканання і кост токена або запіту праза функцыональныя рэзультаты. Відразлівасць коста з самага пачатку запобегае неспакоўным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спяльнаваныя сераўеры. Храніце стан графа як плоскі і з адначытаемымі данымі. Вярнутыя блокі маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакшваюць продажчыку працу пасля перарываў.

Асалодны прыем: абсэнцыя сэмантычнага разумеўння

Настоямы розныя стадзіі працуюць наўжоўды лепш, калі іх спрыяваць як меркаваную паверхню. Зберагуце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Хавайце настройкі за межамі коду прыемлівання. Файлы сераўнавальных сэрваў, хранілішча секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куда аператары можуць адбавляць контроль без неабяжнага чытання всіх дадзеных. Хавайце стан графа простым і з адзінаковым тыпам дадзеных. Вярсткаваныя блокі дадзеных маскуюць інфармацыю пра тое, канкрэтны вузол запісаў канкрэтнае поле, і спакшваюць возобнавленне працы пасля перарываў. Настоямы розныя стадзіі працуюць наўжоўды лепш, калі іх спрыяваць як меркаваную паверхню. Зберагуце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшаў, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцоўкі задач.

Канцэпцыя: Семантычны пошук, адказна паспяшна

Для этапы Semantic Search у праекце The Concept неабяжна ўзначыць вхідныя даны, адпаведальнага за этап і крэтыры завершэння пры змяне коду. Аперацыйныя працавнікі должны магчымае запускаць этап з вядомай точкі контролю, не падозрываючы прыхованы стан. Спрыяйце цій этапы як даговору межаў вхідных даных і перакананых выходных рэзультатаў. Даць назвы артыфактам, узначыць крэтыры успеху і адмовіцца ад тыхнага частковага завершэння без паведамлення. Заставіць людзкую апраўду для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даны для працы. Компіляцыйныя налашчэння не ўзначаюць павнае выпаненне бізнес-задач.

Якую ролю выпалоўвае мова?

Для этапа «Звядзе язык выходзіць?» неабяжна пазначыць вхідныя даны, адпаведальнага за шаг і крэтарыя выходу пры перадзеі коду. Аператары должны магчымаць перзапуск шагу з вядомай точкі контролю, не прабуючы спадарваць схованы стан. Запісвайце час выканання і кост токенаў або запытаў разам з функцыйнальнымі рэзултатамі. Відразы костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмавайнага рэжыма ў спакульнае сераўера. Заставіце людзкую апрацоўку для тых крокаў, якія выкарыстоўваюць грошы або зменяюць даны ў працэсе. Компіляцыйныя налаштаванні не ўзроўнаўцяюцься з пачатковай готовасцю сістэмы для працы.

Выбір правільных інструментаў (і чаму на гэта патрэбна была калькі зусенняў)

У стадыі Выбор правільных інструментаў неабходна з’явіць вхідныя даны, адпаведальнага за крок і крэтыяры завершэння пры перадзеіснаванні коду. Аператары должны магчымаць перзапуск кроку з вядомай точкі контролю, не спрабоўваючы здогадвацца пра схованы стан. Конфігурацыю трэба знаходзіць паза кодам прыкладнення. Файлы сераўіса, хранальнікі секрэтных даных і флагі функцый належаць у аднам месца, якое аператары можаць пераглядаць, не чытаяўшы весь ланцуг задач. Аўтэнтыфікацыя павінна выканацца на воратах, а пераправенне прав нальгавання — у роўні дадзэйнаў. Сам токен-носіцель не ёсць межай адпаведальнасці. У стадыі Выбор правільных інструментаў неабходна з’явіць вхідныя даны, адпаведальнага за крок і крэтыяры завершэння пры перадзеіснаванні коду. Аператары должны магчымаць перзапуск кроку з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Валіць крашчэ маленькія, тэставаныя елементы за велікія скрыпты. Калі крок не выйшаў, прычына нехаспекі павінна вказываць на адну адпаведальнасць, а не на заплутаны ланцуг задач.

CLIP ViT-B/32 праз FastEmbed — глыбы сістэмы

Калі працуеце з CLIP ViT-B 32 праз певны этап, спачатку запісайце умовы: неабяжлівыя вхідныя даны, сігнал успеху і тое, што выходзіць у разы ў частковай невялікай памяці. Такі спіс дапамагае залічыць пазнейшыя змены ў кодзе. Спрыймайце гэты этап як угоду між вхіднымі данымі і перакананымі выходамі. Дайце назву рэзультатам, задаць тэсты на успех і не падпішывайцеся на тыхое часткова завершэння. Замерьце рывень запам’ятовування на фіксаванай сэтцы запітаў прычым рэгулюванні прапазісаў. Частыя змены прапазісаў рэдка калі вялікі эфект на слабую сістэму пошуку.

from fastembed import ImageEmbeddingModel, TextEmbeddingModel

# Loaded once, reused forever
image_model = ImageEmbeddingModel.from_pretrained("Qdrant/clip-ViT-B-32-vision")
text_model = TextEmbeddingModel.from_pretrained("Qdrant/clip-ViT-B-32-text")
# After embedding:
image_vector = embed_image("sunset_photo.jpg") # shape: (512,)
query_vector = embed_text("beautiful sunset") # shape: (512,)
# Cosine similarity — just a dot product on normalised vectors
similarity = np.dot(image_vector, query_vector)
# If image is a sunset → similarity ≈ 0.85 (strong match)
# If image is food → similarity ≈ 0.15 (weak match)

Qdrant Edge — памяць

Калі працуеце з рэжымам мемарыяў Qdrant Edge, спачатку запісайце умовы вікорыстання: неабходныя даныя, сігнал пра успех і тое, што выходзіць на частыя неудачы. Такі спіс дапамагае заліцварваць можлівыя змены ў кодзе. Запісваюце час выканання і кост токенаў або запытаў разам з функцыйнальнымі рэзултатамі. Відразы костаў з самага пачатку запобегае неспакойным рахункам, калі праця пераходзіць з дэмаверсіі ў спакульнаныя сераўсы. Стварайце контрольныя пункты пасля дорогіх крокаў. Функцыя адновлення не должна зноў нараховваць косты той самай вызову LLM, калі аператар прабуюць зноў выконаць пазнейшы вузел.

from qdrant_edge import(
    Distance,
    EdgeConfig,
    EdgeShard,
    EdgeVectorParams,
)
config = EdgeConfig(
            vectors={
                VECTOR_NAME: EdgeVectorParams(
                    size=EMBED_DIM,
                    distance=Distance.Cosine
                )
            }
        )
        _shard = EdgeShard.create(path=str(SHARD_DIR), config=config)

Аднаўленне усяго разам

Калі працуеце на стадыі «Аб’еднанне усяго», спачатку запісайце контракт: неабяжлівыя даны, сігнал успеху і тое, што выканаецца у разе частковага нявыполнення. Такі спіс пераканальвае ў тым, каб пазнейшыя змены коду былі чыстымі. Зберагаеце настройкі паза кодам прыемлі. Файлы сераўіса, храненні секрэтных даных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аўдыт без неабяжлівага чытання всей структуры. Ставяйце контрольныя пункты пасля дорогіх крокаў. Функцыя вярнення до працы не должна занова ставіць плату за той самы вызыв LLM, калі аператар перапрыяўляе працу да наступнага элемента. Калі працуеце на стадыі «Аб’еднанне усяго», спачатку запісайце контракт: неабяжлівыя даны, сігнал успеху і тое, што выканаецца у разе частковага нявыполнення. Такі спіс пераканальвае ў тым, каб пазнейшыя змены коду былі чыстымі. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выканаецца, прычына нявыполнення должна вказываць на адну адпаведальнасць, а не на заплутаную лінію апрацоўкі.

OpenClaw — галавны мозг

Этап «OpenClaw – мозг» працюе найкрашча, калі яго расследжваць як вімерную паверхню. Запісаўце адна «золатая» транскрыпцыя, адзін прыклад неудачы і запіс пра вярненне да пачатковага стану перш чым расшырваць масштабы. Расследжвайце этап як кантракт межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаце крытэрыя успеху і адмовіцеся ад мовчанкавага частковага завершэння. Храніце стан графа ў простам і тыпаваным фармаце. Вкладзеныя блокі маскуюць, які вузел запісаў кожны поле, і спакоююць продажчыку пасля перарываў.

Настройка сяродавысці

Этап стварэння сяродавішча працуе наўжоўды лепш, калі яго спрыятаць як вімерную плошчу. Запісаўце адна «золатая» транскрыпцыю, адзін прыклад неудачы і прыметку па адвярненню змян перад расшырэнням масштаба. Запісвайце часы выканання і кост токена або запіту па боку ад функцыональных рэзультатаў. Візуабельнасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя сяродавішчы. Храніце стан графа як плоскі і з адзінаковым тыпам дадзеных. Вкладаныя блобы маскуюць, які вузол запісаў кожны поле, і спакшваюць продажчык працы пасля перарываў.

Шаг 1: Клонавайце рэпазітарый і створыце вяртуальнае сяродавішча

Этап 1: Клонаванне стэджа працуе наякраўсі, калі яго спрыягаць як мерымая паверхню. Зберагуце адна ідэальная транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Зберагуйце настройкі пазырочна ад коду прыемліка. Файлы сераўнавання сяродовысці, хранілішча секрэтных дадзеных і флагі функцый павінны знаходзіцца ў адном месцы, куда аператары можуць аўдытаваць іх без неабяжнага чытання всіх дадзеных. Зберагуйце стан графа ў простам і тыпаваным фармаце. Вярнутыя блокі маскуюць інфармацыю пра тое, які вузел запісаў які поле, і спакоююць продаж чытання пасля перэрываў. Этап 1: Клонаванне стэджа працуе наякраўсі, калі яго спрыягаць як мерымую паверхню. Зберагуце адна ідэальная транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісьць крока не выходзіць, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцоўкі задач.

# Clone the repo
git clone https://github.com/vatsala-singh/AI-Powered-Photo-Search-and-Tagging-Agent.git
cd AI-Powered-Photo-Search-and-Tagging-Agent

# Create and activate virtual environment
python -m venv .venv
source .venv/bin/activate        # Mac/Linux
# .venv\Scripts\activate         # Windows

Этап 2: Установка залежнасцяў

Для другога крока, практыкуя інсталляцыю, неабходна ўстановка этапы, а таксама ваказваўце вхідных дадзенняў, адпаведальнага за крок і крэтарыяў завершэння працы перад зменым коду. Аперацыйныя працавнікі павінны магчымае перапрацаваць крок пачаткуючы з вядомага контрольнага пункту, не прымусваныя здогадвацца пра схованы стан. Спрыяйце гэтай этапы як даговору межа вхіднымі дадзеннямі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, ваказваўце крэтарыяў успеху і адмовіцеся ад беззвучнага частковага завершэння. Забезпечыце людскія апраўданні для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даны праўай працы. Працэс складання коду не ёсць роўнозначным пачатковай цэласнасці бізнес-процэсу.

pip install -r requirements.txt

Крок 3: З’ясаваць структуру праекту

Для трэцьяго крока «Розумеўце стадыю» неабходна пазначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння пры зміне коду. Аператары должны магчыма ўвайсці крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Запісвайце час выканання і кост токенаў або запытаў па боку функцыйнаых рэзультатаў. Візуабельнасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмавайнтару ў спяльныя сераўры. Заставіце людзкую апрацоўку для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даны ў працэсе. Працэс складання коду не ўзроўнаважваецца з повнасцю бізнес-процэсаў.

AI-Powered-Photo-Search-and-Tagging-Agent/
│
├── main.py                  # FastAPI app + OpenClaw agent entry point
├── config.py                # All configurable parameters in one place
├── requirements.txt
│
├── pipeline/
│   ├── embedder.py          # CLIP embedding logic (image + text)
│   └── indexer.py           # Batch photo processing and indexing
│
├── store/
│   └── qdrant_client.py     # Qdrant Edge setup and collection management
│
├── tools/
│   ├── search.py            # Semantic search tool
│   ├── tag.py               # Zero-shot auto-tagging tool
│   ├── duplicates.py        # Near-duplicate detection tool
│   └── albums.py            # Smart album grouping tool
│
├── test/
│   ├── embedder_test.py
│   ├── indexer_test.py
│   ├── search_test.py
│   └── qdrant_edge_client_test.py
│
└── qdrant-edge-data/        # Auto-created at runtime
    ├── storage/             # Qdrant's internal shard data
    ├── models/              # Cached CLIP model weights
    └── photos/              # Collection data

Крок 4: Адзін раз пагляньце на config.py

У стадыі «Пагляд на крок 4» неабяжна прадзеўніць вхідныя даны, адпаведальную особу за крок і крэтыяры завершэння пры зміне коду. Аперацыйныя працавнікі павінны магчымае перзапускаць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Конфігурацыю трэба залічваць праза код аплікацыі. Файлы сераўіса, хранільнікі секрэтных дадзеных і флагі функцый павінны знаходзіцца ў адном месцы, якое працавнікі можуць пераглядаць, не чытаючы весь ланцуг задач. Прызначайце людскія апраўды для рэлей, якія вітрачаюць грошы або зменяюць даны у працоўнай сітцы. Падключэння праз час компілявання не ўзначае повнасці бізнес-процэсу. У стадыі «Пагляд на крок 4» неабяжна прадзеўніць вхідныя даны, адпаведальную особу за крок і крэтыяры завершэння пры зміне коду. Аперацыйныя працавнікі павінны магчымае перзапускаць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Валічыце маленькія, тэставальныя елементы пра велікія скрыпты. Калі крок не выйшоў, прычына нехарактэрыстыкі павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцуг задач.

# config.py

CLIP_IMAGE_MODEL = "Qdrant/clip-ViT-B-32-vision"
CLIP_TEXT_MODEL  = "Qdrant/clip-ViT-B-32-text"
EMBEDDING_DIM    = 512          # CLIP ViT-B/32 output dimension

COLLECTION_NAME  = "photos"
QDRANT_PATH      = "./qdrant-edge-data"

BATCH_SIZE             = 32     # Images per indexing batch
TOP_K                  = 10     # Default search results returned
TAG_THRESHOLD          = 0.20   # Min similarity score for a tag to apply
DUPLICATE_THRESHOLD    = 0.97   # Min similarity to flag as duplicate

Шаг 5: Запуск сервера

Калі вы працуеце над шагам 5 «Запуск», спачатку запісайце умовы кантракту: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі спіс контролю дапамагае заліцвачыць змяны ў кодзе. Спрэчвайце гэты этап як кантракт межа данымі і перакананымі выходамі. Дайце назвы элементам, задаць правіла пераканання успеху і не падзеўляйцеся частковым завершэнням без паведамлення. Зробіце контрольную точку пасля дорогіх крокаў. Програма для продакцыі не должна занова ставіць плату за той самы вызов LLM, калі аператар праказвае пазнейшы вузел.

uvicorn main:app --reload --port 8000

Шаг 6: Пераканацца ў налашоўкі

Калі вы працуеце над этапам 6 «Парацэнка», спачатку запісайце умовы контракту: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі спіс контроля дапамагае заліцвачыць змяны коду пасля таго.

# Quick sanity check - should return {"status": "ok"}
curl http://localhost:8000/health
curl http://localhost:8000/api/status

Стварэнне каналу імбеддынга зображэнняў

Калі працуеце над стадзіяй «Стварэнне імедж-ембеддынга», спачатку запісайце умовы вярбунка: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць пад частковыя аберанціі. Такі спіс дапамагае залічваць пазнейшыя змены ў кодзе чыста.

Інструмент для стварэння імедж-ембеддынга

Этап уявлення працюе належначы, калі яго розглядаць як вімерную паверхню. Зафіксавце адна ідэальная версія, адзін случай неудачы і прыметкі па поверненню да пачатковага стану пры расшырэнні масштаба. Разглядзайце этап як кантракт межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаце крытэрыя успеху і адмовіцеся ад тыхоўага частковага завершэння. Раздзеліце політыку часткавага абрабатвання дадзеных ад політыкі ўтрымання іх. Змена адной з яных не павінна вымагаць перапісвання другой, калі зменяюцца паказнікі якосці.

# pipeline/embedder.py

from fastembed import ImageEmbeddingModel, TextEmbeddingModel
from PIL import Image
import numpy as np
from config import CLIP_IMAGE_MODEL, CLIP_TEXT_MODEL

# Load once, reuse for the lifetime of the process
# Models are large (~150MB each) — we never want to reload them per request
_image_model = ImageEmbeddingModel.from_pretrained(CLIP_IMAGE_MODEL)
_text_model  = TextEmbeddingModel.from_pretrained(CLIP_TEXT_MODEL)

def embed_image(image_path: str) -> np.ndarray:
    """Convert an image file to a 512-d CLIP embedding."""
    image = Image.open(image_path).convert("RGB")
    embeddings = list(_image_model.embed([image]))
    return np.array(embeddings[0])   # shape: (512,)

def embed_text(query: str) -> np.ndarray:
    """Convert a text string to a 512-d CLIP embedding."""
    embeddings = list(_text_model.embed([query]))
    return np.array(embeddings[0])   # shape: (512,)

Індэксавальнік

Этап індэксавання працюе наяўнасты лепш, калі яго розглядаць як вімерную паверхню. Запісаце адна ідэальная транскрыпцыя, адзін прыклад неудачы і прыметку па абратанні стану раней, чым расшырваце дыячную сферу. Запісвайце часы выканання і косты токеноў або запытаў разам з функцыйнаімі рэзультатамі. Візуабельнасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спяльнаныя сераўы. Храніце стан графа ў простам і тыпаваным фармаце. Вкладзеныя блокі маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакшваюць продажчыку працу пасля перарываў.

# pipeline/indexer.py

import os
import uuid
from pathlib import Path
from datetime import datetime
from PIL import Image

from pipeline.embedder import embed_image
from store.qdrant_client import get_shard
from tools.tag import generate_tags
from config import BATCH_SIZE

SUPPORTED_FORMATS = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tiff"}

def index_folder(folder_path: str) -> dict:
    """
    Recursively index all images in a folder into Qdrant Edge.
    Returns a summary: total found, indexed, skipped.
    """
    folder   = Path(folder_path)
    shard    = get_shard()

    image_paths = [
        p for p in folder.rglob("*")
        if p.suffix.lower() in SUPPORTED_FORMATS
    ]

    total    = len(image_paths)
    indexed  = 0
    skipped  = 0
    batch    = []

    for i, path in enumerate(image_paths):
        try:
            vector   = embed_image(str(path))
            tags     = generate_tags(str(path))
            img      = Image.open(path)

            point = {
                "id":      str(uuid.uuid4()),
                "vector":  vector.tolist(),
                "payload": {
                    "filename":  path.name,
                    "filepath":  str(path.absolute()),
                    "tags":      tags,
                    "timestamp": int(path.stat().st_mtime),
                    "width":     img.width,
                    "height":    img.height,
                }
            }
            batch.append(point)
            indexed += 1

        except Exception as e:
            print(f"Skipping {path.name}: {e}")
            skipped += 1

        # Flush every BATCH_SIZE images
        if len(batch) >= BATCH_SIZE:
            shard.upsert(points=batch)
            batch = []
            print(f"  Progress: {i+1}/{total} images indexed...")

    # Flush remaining
    if batch:
        shard.upsert(points=batch)

    return {"total": total, "indexed": indexed, "skipped": skipped}

Індэксаванне аўтарысаў у Qdrant Edge

Этап індэксавання зображэнняў у Qdrant працуе наякша, калі яго розглядаюць як мерыябельную паверхню. Зафіксуйце адны ідэальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Зберагаюце настройкі пазначэнныя ад коду прыемлі. Файлы сераўнавання, храненні секрэтных даных і флагі функцый павінны знаходзіцца ў адном месцы, куда аператары можуць аўдытаваць іх без неабяжнага чытання всіх дадзеных. Зберагаюце стан графа ў простам і тыпаваным фармаце. Вкладныя блокі маскуюць інфармацыю пра тое, які вузел запісаў які поле, і спакоююць продовжэнне працы пасля перэрываў. Этап індэксавання зображэнняў у Qdrant працуе наякша, калі яго розглядаюць як мерыябельную паверхню. Зафіксуйце адны ідэальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Вядзеце прывялівае, тэставаныя елементы ў працу пад час працы з велікімі скрыптамі. Калі якась зэнта не выйшла, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцоўкі задач.

Як тут працуе Qdrant Edge

Для этапа «Як працюе Qdrant Edge» неабяжна прадзефінавацыя вхідных дадзеных, адпраўніка крока і крэтарыяў завершэння перад зменым коду. Аперацыяныя працавнікі павінны магчымае перапрацаваць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Спрыяйце гэтаму этапу як кантракту межа вхіднымі дадзенымі і паверанымі выходнымі. Даўце назвы артыфактам, прадзефінавацыя перакананняў у успеху і адмовіцеся ад беззвучнага частковага завершэння. Заставьце людзкую апраўду для крокаў, якія выкарыстоўваюць грошы або зміняюць даныя у працэсе віробніцтва. Працэс складання коду не ўзроўнаважваецца з пачытальнасцю бізнес-процэсаў.

Настройка шарда

Для налагоджэння этапа шардавання неабяцкова практычна вказаць інпуты, адміністратара шагу і крэтыяры завершэння пры перадзеіснаванні коду. Аператары должны магчымаць перзапуск шагу з вядомай точкі контролю, не падозрываючы прыхованы стан. Запісваць трэба час выканання і вартасць токена або запыту разам з функцыйнальнымі рэзултатамі. Відразувыя даныя пра вартасць запобегаюць неспакоўным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спакульную. Неабяцкова адзначыць людскія празгляды для тых крокав, якія вітрачаюць грошы або зменяюць даныя ў працэйной асяроддзі. Прыўязка на час компілявання не ўзначае повнайшага адпрацоўвання бізнес-праблем.

def get_shard() -> EdgeShard:
    """
    Return the singleton EdgeShard, creating it on first call.

    - If SHARD_DIR does not exist → create a brand-new shard.
    - If SHARD_DIR already contains data → reopen it (no config needed).

    EdgeShard runs entirely in-process. No binary, no port, no network.
    """
    global _shard
    if _shard is not None:
        return _shard

    SHARD_DIR.mkdir(parents=True, exist_ok=True)
    # Detect whether this is a fresh shard or an existing one.
    # EdgeShard.create() fails if data already exists on disk.
    shard_has_data = any(SHARD_DIR.iterdir())

    if shard_has_data:
        print(f"[qdrant_client] Reopening existing shard at '{SHARD_DIR}'")
        _shard = EdgeShard.load(path=SHARD_DIR)
    else:
        print(f"[qdrant_client] Creating new shard at '{SHARD_DIR}'")
        config = EdgeConfig(
            vectors={
                VECTOR_NAME: EdgeVectorParams(
                    size=EMBED_DIM,
                    distance=Distance.Cosine
                )
            }
        )
        _shard = EdgeShard.create(path=str(SHARD_DIR), config=config)
        print(f"[store] Shard ready — vector: '{VECTOR_NAME}', dim: {EMBED_DIM}")
    return _shard

Разлік між стварэнням і завантажэнням

Для этапы «Стварэнне» проты «Завантажэння» неабяжна практычна апранаванне вхідных дадзеных, адміністратара шагу і крэтэрыяў завершэння пры перадзеіснаванні коду. Аператары павінны магчымаецца перазапускаць шаг з вядомай точкі контролю, не падозрываючы прыхованы стан. Конфігурацыю трэба знаходзіць за межамі коду прыемленае. Файлы сераўнавання, хранільнікі секрэтных дадзеных і флагі функцыйяў павінны быць у адном месца, якое аператары можаць пераглядаць, не чытаяўшы весь ланцуг аперацый. Неабяжна ўстановіць людскую апраўду для рэлейнаў, якія вітрачаюць грошы або зменяюць даныя ў працэсе. Прыемленае пад час компілявання паўзы не ёсць адпаведнай ступенем завершанасці бізнес-процэса. Для этапы «Стварэнне» проты «Завантажэння» неабяжна практычна апранаванне вхідных дадзеных, адміністратара шагу і крэтэрыяў завершэння пры перадзеіснаванні коду. Аператары павінны магчымаецца перазапускаць шаг з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі шаг не выканаецца, прычына нехтаравання павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцуг аперацый.

Шаблон сінглтон

Калі вы працуеце над этапам шаблона сінглтон, спачатку запісайце умовы вікорыстоўвання: неабходныя даныя, сігнал успеху і тое, што выходзіць у разе частковай нявыплненасці. Такі спіс дапамагае заставіць пазнейшыя змены коду быць чыстымі. Спрыятлівае ставленне да гэтага этапу як да угоды межаў вхідных дадзеных і перакананых выходных рэзультатаў. Дайце назвы элементам, задаце крытэрыя успеху і не прабывайце прыймаць часткова завершаныя рэзультаты без паведамлення. Зробіце перапаконтаванне пасля дорогіх крокаў. Сістэма вярнення не павінна зноў ставіць плату за той самы вызов LLM, калі аператар прабуе зноў выконаць пазнейшы элемент.

@app.on_event("shutdown")
def on_shutdown():
  close_shard()

Схема пэйлоаду

Калі працуеце над стадзіяй «Схема пэйлоаду», спачатку запісайце умовы кантракту: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі спіс контроля дапамагае заліцвачыць змяны ў кодзе.

from dataclasses import dataclass, field
from typing import List, Optional

@dataclass
class PhotoPayload:
    filename:str
    path:str
    tags: list[str] = field(default_factory=list)
    timestamp: Optional[str] = None
    width: Optional[int] = None
    height: Optional[int] = None

    def to_dict(self) -> dict:
        return {
            "filename": self.filename,
            "path": self.path,
            "tags": self.tags,
            "timestamp": self.timestamp,
            "width": self.width,
            "height": self.height
        }

Запісваўце пункты ў шард

Калі працуеце над пунктамі напісання коду на данай стадыі, спачатку запішыце умовы кантракту: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс пераконтроўвае чыстасць пазнейшых змян у кодзе. Зберагаюце настройкі праза код аплікацыі. Файлы сераўіса, хранільнікі секрэтных даных і флагі функцый належаць у аднам месца, куды аператары можаць пераконтроўваць іх без неабяжлівага чытання всей структуры.

from qdrant_edge import PointStruct
from store.qdrant_client import get_shard
from schema import PhotoPayload

shard = get_shard()

payload = PhotoPayload(
    filename  = "beach_sunset.jpg",
    path      = "/Users/me/Pictures/2024/Goa/beach_sunset.jpg",
    tags      = ["sunset", "beach", "outdoor"],
    timestamp = "2024-05-01T18:42:00",
    width     = 4032,
    height    = 3024
)

point = PointStruct(
    id      = "3f7a2b1c-8e4d-4f9a-b2c1-7d8e9f0a1b2c",
    vector  = {"image": vector.tolist()},   # named vector matching VECTOR_NAME
    payload = payload.to_dict()
)

shard.upsert(points=[point])

Калі працуеце над пунктамі напісання коду на данай стадыі, спачатку запішыце умовы кантракту: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс пераконтроўвае чыстасць пазнейшых змян у кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшаў, прычына нявыпання должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаную структуру задач.

Аўтаматычная атрыбутацыя фота

Этап аўтаматычнай атрыбутацыі фота працюе наякша, калі яго спрыяваць як мерыемую структуру. Запісаўце адна ідэальная прыклад, адзін кейс неудачы і прыметкі па поверненню да пачатковага стану пры расшырэнні масштаба. Спрыяйце этапу як кантракту межа вхіднымі дадзеннямі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаце крытэрыя успеху і не прымайце часткова завершаныя рэзультаты без паведамлення. Храніце стан графа ў простым і тыпаванам фармаце. Вярнутыя структуры дадзення маскуюць інфармацыю пра тое, які вузел запісаў кожны поле, і спакшваюць продажчэнне працы пасля перарываў.

Ідэя: класыфікацыя без практычных прыкладаў

Ідэя этапы класыфікацыі без практычнага трэнінгу працюе наявнасцю, калі яе рассматрываць як вімерную паверхню. Запісайце адны ідэальны прыклад, адну справу з бягам і прыметку пра вярнэнне да пачатковага стану, перш чым расшырваць масштабы. Запісвайце часы выканання і косты токэнаў або запыткаў праза функцыйнае рэзультаты. Відкрытыя даныя пра косты з самага пачатку запобегаюць неспакоўным рашчыткам, калі працэс пераходзіць з дэмавай версіі ў спяльныя асяроддзя. Храніце стан графа ў простам і тыпаваным фармаце. Вярнутыя структуры маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакшваюць продажчыку працу пасля перарываў.

TAG_VOCABULARY = [
    "sunset", "sunrise", "beach", "ocean", "mountain", "forest", "city",
    "night", "snow", "rain", "fog", "sunny", "cloudy",
    "dog", "cat", "bird", "people", "crowd", "portrait", "selfie",
    "food", "coffee", "restaurant", "travel", "architecture",
    "car", "road", "nature", "flowers", "trees",
    "indoor", "outdoor", "party", "celebration", "sport",
    "screenshot", "document", "text", "map",
]
# tools/tag.py

from pipeline.embedder import embed_image, embed_text
from config import TAG_THRESHOLD
import numpy as np

TAG_LABELS = [...]  # full list as above

# Pre-compute label embeddings once at module load —
# no point re-embedding the same 50 words on every photo
_label_vectors = {
    label: embed_text(label)
    for label in TAG_LABELS
}

def generate_tags(image_path: str) -> list[str]:
    """
    Run zero-shot classification on an image.
    Returns a list of tags whose similarity to the image
    exceeds TAG_THRESHOLD (default: 0.20).
    """
    image_vector = embed_image(image_path)

    tags = []
    for label, label_vector in _label_vectors.items():
        similarity = np.dot(image_vector, label_vector)  # cosine sim on normalised vectors
        if similarity >= TAG_THRESHOLD:
            tags.append(label)

    return tags

Тэгі ў час адзначэння індэксу проты часа запытку

Тэгі на стадыі індэксавання працуюць найэфектывней, калі іх спрыяваць як меркаваную паверхню. Зберагачыце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Зберагачыце настройкі пазначэнныя окола коду прыемлі. Файлы серавэра, хранільнікі секрэтных даных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куда аператары можуць адрабоўваць аўдыт без неабходнасці чытання всей структуры. Стан графа павінен быць простым і з адзінаковым тыпам дадзеных. Вярсткаваныя блокі дадзеных маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакоююць продажчыку працы пасля перарываў. Тэгі на стадыі індэксавання працуюць найэфектывней, калі іх спрыяваць як меркаваную паверхню. Зберагачыце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Валідзіце маленькія, тэставаныя елементы замест большых скрыптов. Калі які-небудзь крок не выйшаў, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаную лінію выканання.

def generate_tags_from_vector(img_vec: np.ndarray, threshold: float = 0.20, max_tags: int = 6) -> list[str]:
    """
    Generate tags for an image vector using zero-shot CLIP classification.
    Tags with cosine similarity above threshold are included (up to max_tags).

    This is a utility function used for generating tags during indexing
    or when you already have an image vector.
    """
    tag_vecs = _get_tag_vectors()

    scores = {
        tag: float(np.dot(img_vec, vec))   # both normalized → cosine similarity
        for tag, vec in tag_vecs.items()
    }

    tags = sorted(
        [t for t, s in scores.items() if s >= threshold],
        key=lambda t: scores[t],
        reverse=True,
    )[:max_tags]

    return tags

Іспытанне тэгоў як фільтраў

У стадыі «Іспытанне тэгоў як фільтраў» неабходна пазначыць вхідныя даны, адпаведальнага за этап і крэтыры завершэння пры перадзеяванні коду. Аператары должны магчымае перазапускаць этап з вядомай точкі контролю, не прабуючы спадарожваць схованы стан. Спрыяйце цій этапы як даговору межаў вхідных і перакананых выходных даных. Даўце назвы артыфактам, пазначыце крэтыры успеху і не прымайце тыхчасова часткова завершаных задач. Заставьце людзкія падтверджэння для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даны для працы. Компіляцыйны падключэння не ўзроўнаўваецца з повнай завершанасцю бізнес-процэсу.

def search_photos(query: str, top_k: int = TOP_K, tags: list[str] = None) -> list[dict]:
    #search photo library with a Natural language query
    #takes in query, no of results to be displayed, and a list of tags
    # returns list of dicts with photo metadata and relevance score
    print(f"[search] Received query='{query}' with tags={tags} and top_k={top_k}")
    shard = get_shard()
    query_vector = embed_text(query)

    # Over-fetch when tag filtering is requested to have enough candidates
    # after post-filtering by tags
    over_fetch_multiplier = 5 if tags else 1
    fetch_limit = top_k * over_fetch_multiplier

    results = shard.query(
        QueryRequest(
            query=Query.Nearest(query_vector.tolist(), using=VECTOR_NAME),
            limit=fetch_limit,
            with_vector=False,
            with_payload=True,
        )
    )
    print(f"[search] Found {len(results)} initial hits for query='{query}' with tags={tags}")

    hits = []
    untagged_hits = []  # Fallback results for images without tags

    for point in results:
        payload = point.payload or {}
        point_tags = payload.get("tags", [])

        result_dict = {
            "path": payload.get("path"),
            "filename": payload.get("filename"),
            "tags": point_tags,
            "timestamp": payload.get("timestamp"),
            "score": round(point.score, 4)
        }

        # Post-filter by tags if specified
        # (EdgeShard doesn't support complex filters, so we filter in Python
        # after over-fetching more results than needed)
        if tags:
            if point_tags and any(t in point_tags for t in tags):
                # Has tags and matches the filter
                hits.append(result_dict)
            elif not point_tags:
                # No tags yet (images not auto-tagged), save as fallback
                untagged_hits.append(result_dict)
        else:
            # No tag filter specified, include all results
            hits.append(result_dict)

        # Stop if we have enough tagged results
        if len(hits) >= top_k:
            break

    # If we don't have enough tagged results, include untagged ones that match the query
    if tags and len(hits) < top_k:
        hits.extend(untagged_hits[:top_k - len(hits)])

    return hits[:top_k]

Стварэнне агента для пошуку

Для этапы стварэння агента пошуку неабяжна ўзначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння пры перадзеіснавленні коду. Аператары должны магчымаць перзапуск кроку з вядомай точкі контролю, не падозрываючы прыхованы стан. Запісваць час выканання і кост токена або запыту праза функцыйнальныя рэзултаты. Відразлівасць коста з самага пачатку запобегае неспакоўным рахункам, калі парадок пераходзіць з дэмаверсіі ў спяльныя асяроддзя. Заставіць людзкую апраўду для тых крокаў, якія вітрачаюць грошы або зменяюць даны ў працэсе. Працэс складання коду не ўзначае повнайшага адпаведання бізнес-трэбаванням.

curl --location 'http://localhost:8000/search' \
--header 'Content-Type: application/json' \
--data '{"query": "eiffel tower from rooftop","tags":[], "top_k": 1}'
{
    "query": "eiffel tower from rooftop",
    "results": [
        {
            "path": "/Users/vatsalasingh/Documents/Datasets/tag_phot/photo-1638051017225-0d9fcca18cf4.jpg",
            "filename": "photo-1638051017225-0d9fcca18cf4.jpg",
            "tags": [
                "cloudy",
                "city",
                "rain",
                "screenshot",
                "architecture",
                "travel"
            ],
            "timestamp": "2021-12-09T17:27:56",
            "score": 0.2864
        }
    ]
}

Адпаведнае рашэнне экстрэмальных сітуацыяў

Ёнколі трэба граматычна распрацаваць крайнія случаі, яшчэ перад зменым коду неабходна ўзначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння. Аператары павінны магчымаць перзапуск крока з вядомай точкі контролю, не падозрываючы прыхованы стан. Канфігурацыю трэба залічыць пазначкай ад коду прыемлівання. Файлы сераўнавальнага сэрвісу, хранення секрэтных дадзенаў і флагі функцыйяў павінны знаходзіцца ў адном месцы, якое аператары можаць пераглядаць, не чытаяўшы весь ланцуг. Даецца можлівасць апраўды чалавека для тых крокаў, якія выкорыстоўваюць грошы або зміняюць даны у працэсе. Прыўязка на час компілявання не ёсць падтверджэннем полныя адпаведнасці з бізнес-трэбованнямі. Ёнколі трэба граматычна распрацаваць крайнія случаі, яшчэ перад зменым коду неабходна ўзначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння. Аператары павінны магчымаць перзапуск крока з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшоў, прычына нехарактэрнага рэзультата павінна вказываць на адну конкрэтную адпаведальнасць, а не...

заплутаная сетка практык.

Організацыя всьго за дапамою OpenClaw

Калі працуеце над этапам разработкі, спачатку запісайце умовы: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі спіс контролю дапамагае заліцварыць пазнейшыя змены ў кодзе. Спрэцьвачайце гэты этап як угоду межаў між вхіднымі данымі і перакананымі выходамі. Дайце назвы элементам, задаце крытэрыя успеху і не прабывайце прыймаць часткова завершаныя рэзультаты без паведамлення. Стварайце контрольныя точкі пасля дорогіх крокаў. Програма для продакцыі не должна занова ставіць плату за той самы вызов LLM, калі аператар прабуе зноў запрацаваць з пазнейшым вузлам.

Як працюе OpenClaw

Калі працюеце над этапам «Як працюе OpenClaw», спачатку запісайце умовы вікорыстоўвання: неабходныя даны, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі спіс дапамагае заліцвачваць змяны ў кодзе пазнейшаю часам. Запісвайце час выканання і кост токеноў або запытаў разам з функцыйнальнымі рэзультатамі. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя сераўы. Стварайце контрольныя пункты пасля дорогіх крокаў. Функцыя вярнення не должна зноў нарахоўваць косты той самай вызову LLM, калі аператар перапрыямляе працу да наступнага вузла.

@app.post("/chat")
def chat(req: ChatRequest):
    """
    Conversational endpoint. Accepts user message and conversation history,
    returns agent's reply after processing with tools.
    """
    # Define tool functions that the agent can call
    def search_tool(query: str, top_k: int = 10, tag_filter: list = None):
        """Search photos by natural language query"""
        return search_photos(query=query, top_k=top_k, tags=tag_filter)

    def duplicates_tool(threshold: float = 0.97):
        """Find duplicate or near-duplicate photos"""
        return find_duplicates(threshold=threshold)

    def tag_tool(image_path: str):
        """Generate and update tags for a specific photo"""
        return generate_tags_from_vector(image_path=image_path)

    # Create the agent with tools
    agent = Agent(
        tools=[search_tool, duplicates_tool, tag_tool],
        system_prompt="""
        You are a personal photo assistant. You help users search, organize,
        and understand their local photo library. You have access to tools
        for semantic search, duplicate detection, and tagging.

        When helping users:
        - Use the search tool to find photos by describing their content
        - Use duplicates tool to find and clean up duplicate shots
        - Use tag tool to inspect or update tags for specific photos

        Always be concise and helpful. When returning photo results,
        format them clearly with filenames, similarity scores, and tags.
        Use emojis sparingly but helpfully.
        """
    )

    # Run the agent conversation
    response = agent.chat(
        message=req.message,
        history=req.history
    )
    return {"response": response}

Рэальныя прабегі взаімадзеяння

Калі працуеце над стадзіяй «Рэальныя праблемы ваходжання», спачатку запісайце умовы ваходжання: неабяжлівыя даны, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі спіс дапамагае заліцваліваць пазнейшыя змены ў кодзе. Зберагаюце настройкі за межамі коду прыемліка. Файлы сераўіса, хранілішча секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аўдыт без неабяжлівага чытання всей структуры. Ставяце контрольныя пункты пасля дорогіх крокаў. Сістэма вярнення не должна занова ставіць плату за той самы вызов LLM, калі аператар перапрыяўляе выконанне на пазнейшы вузел. Калі працуеце над стадзіяй «Рэальныя праблемы ваходжання», спачатку запісайце умовы ваходжання: неабяжлівыя даны, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі спіс дапамагае заліцваліваць пазнейшыя змены ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшаў, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаную структуру працы.

Чаму важнае роўэнь агента

Этап шара агента працюе найкрашча, калі яго розглядаць як вімерную паверхню. Зафіксавце адзін ідэальны прымер, адзін кейс неудачы і запіс працэўкі з вярненням да пачатковага стану пры перадзеяванні масштаба. Разглядайце гэты этап як кантракт межа вхіднымі данымі і паверынутымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаце крытэрыя успеху і не падзеўляйцеся частым, непূরным выкананнем задачы. Храніце стан графа ў простам і тыпаваным фармаце. Вкладзеныя блокі маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакшваюць продажчыку працу пасля перарываў.

Выкананне всьго локальна — і чаму гэта важна

Працэс Выканання всьго локальна і на стадыі працюе найэфектыўней, калі яго спрыяваць як мерыемую паверхню. Запісаце адна ідэальная транскрыпцыя, адзін прыклад неудачы і прыметку па адвярненню змян перш чым расшырваць масштаб. Запісвайце часы выканання і косты токеноў або запытаў разам з функцыйнальнымі рэзультатамі. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя асяроддзя. Храніце стан графаў у простам і тыпаваным фармаце. Вярнутыя структуры маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакшваюць продажчыку працу пасля перарываў.

Нічога не выходзіць з вашага прыстрою. Канец.

The Nothing leaves your device stage працюе наякша, калі яго спрыяваць як до мерымабельнай паверхні. Зберагучы адны ідэальны прыклад працы, адны прыклад неудачы і запіс пра вярнэнне да пачатковага стану, перш чым расшырваць сферу дзеяння. Храніце настройкі параду ў кодзе прыемленае. Файлы серавэра, сховішчы секрэтных даных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавляць контроль без неабяжнага чытання всіх дадзеных. Храніце стан графа ў простам і тыпаваным фармаце. Вярнутыя структуры дадзеных маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакоююць продовжэнне працы пасля перэрываў. The Nothing leaves your device stage працюе наякша, калі яго спрыяваць як до мерымабельнай паверхні. Зберагучы адны ідэальны прыклад працы, адны прыклад неудачы і запіс пра вярнэнне да пачатковага стану, перш чым расшырваць сферу дзеяння. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцоўкі дзеяння.

Што на самай працэ патрэбна, каб гэта запрацавало

Для этапа «Што на самай працо ўключана» неабходна пазначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння пры перадзеіснавленні коду. Аператары должны магчымаць перзапуск кроку з вядомай точкі контролю, не прабуючы спадарожваць схованы стан. Спрыяйце цэму этапу як даговору межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, пазначыце крытэрыя успеху і не прымайце тыхню частковую завершанасць. Заставіце людзкія апраўленні для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даны ў працэсе віробніцтва. Компіляцыйныя налашчэнні не ўзроўнаўцяюцься з пачатковай цэласнасцю бізнес-процэса.

Што далей — пашырэнне сістэмы

Для этапы расшырэння What s Next неабяжна прадзеўначыць вхідныя даны, адпаведальнага за крок і крэтыяры завершэння пры змены коду. Аперацыйныя працавнікі должны магчымае перадзеўжваць крок з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Запісвайце час выканання і кост токенаў або запытаў разам з функцыйнальнымі рэзультатамі. Відразлівая відавальнасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмавайнага рэжыма ў спяльныя асяроддзя. Заставіце людзкую апраўдку на тых кроках, якія вітрачаюць грошы або зменяюць даны ў працоўным рэжыме. Працэс складання коду не ўзроўнаважваецца з повнасцю бізнес-процэсаў.

Кластарызацыя эйкаў

Для этапы кластэрування аўтаматычных фота неабходна перад змянай коду адзначыць вхідныя даны, адпаведальнага за этап і крэтыры завершэння. Аператары должны магчымае перадзванаць гэты этап з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Конфігурацыю трэба заставіць праза код аплікацыі. Файлы сяродавішча, хранільнікі секрэтных дадзеных і флагі функцый должны знаходзіцца ў аднам месцы, якое аператары можаць пераглядаць, не чытаючы весь ланцуг аператацый. Прызначаць людскія празгляды для рэшэнняў, якія выкарыстоўваюць грошы або зміняюць даны для працы. Прыўязка на час компілявання не ёсць падтверджэннем полныя адпаведнасці да бізнес-трэбаў. Для этапы кластэрування аўтаматычных фота неабходна перад змянай коду адзначыць вхідныя даны, адпаведальнага за этап і крэтыры завершэння. Аператары должны магчымае перадзванаць гэты этап з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Валідзіць маленькія, тэставаныя елементы працы больш ніж велікія, складныя скрыпты. Калі этап не выконваецца, прычына нехарактэрнага роблення должна быць адзінай, а не ўскладненым ланцугам аператацый.

OCR для скрыншотаў і дакументаў

Калі працюеце над OCR для скрыншотаў і дакументаў, спачатку запісайце умовы контракту: неабходныя даны, сігнал успеху і тое, што вядзецься у разе частковай невыплнення. Такі спіс перэказваў дапамагае заліцвачыць змяны ў кодзе пазней. Спрыймайце гэты этап як контракт між вхіднымі данымі і перакананымі выходнымі рэзультатамі. Дайце назвы артыфактам, задаць правіла пераканання успеху і не падтрымайце тыхія частковыя завершэння. Зробіце пераказв пасля дорогіх крокаў. Сістэма вярнення не павінна знову ставіць плату за той самы вызов LLM, калі аператар перапрыяўляе працу да наступнага етапу.

Індэксаванне кадраў відэа

Калі працюеце над стадзіяй індэксавання кадраў відэа, спачатку запішыце умовы: неабяжныя даныя, сігнал успеху і тое, што выходзіць у разе частковага нэуспеху. Такі спіс контролю дапамагае заліцвачыць змяны ў кодзе пазнейшаю часам. Запісвайце часы выканання і косты токеноў або запытаў разам з функцыйнальнымі рэзультатамі. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмавай версіі ў спяльныя сераўры. Зробіце контрольную пазнаку пасля дорогіх крокаў. Функцыя адновлення не должна зноў нарахоўваць косты той самай вызову LLM, калі аператар прабуюць зноў выконаць пазнейшы вузел.

Гібрыдны пошук: вектары + ключавыя словы + метаданы

Калі працуеце з этапам гэтыя фазы гібранай пошуку, спачатку запісаце кантракт: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі спіс контроля дапамагае заліцвачыць пазнейшыя змены ў кодзе. Храніце настройкі параду ўнутры коду прыемлі. Файлы сераўіса, хранальнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавіць аўдыт без неабяжлівага чытання всей структуры. Стварайце контрольныя пункты пасля дорогіх крокаў. Функцыя вярнення працы не должна занова ставіць плату за той самы вызов LLM, калі аператар перапрыяўляе працу да наступнага элемента. Калі працуеце з этапам гэтыя фазы гібранай пошуку, спачатку запісаце кантракт: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі спіс контроля дапамагае заліцвачыць пазнейшыя змены ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшаў, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны працэс.

Адаптаванне працэса выкарыстоўвання па часе і месцазнаходзенні

Этап, які урахоўвае час і месцазнаходзення, працюе наяўнейша, калі яго спрыяваць як мерыемую структуру. Зберажыце адна ідэальная версія транскрыпцыі, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Спрыявайце этап як даговор межа вхіднымі дадзеннямі і перакананымі выходнымі рэзультатамі. Даць назвы артыфактам, задаць крытэрыя успеху і не падзеўляйцеся частым, непূরным выкарыстоўваннем. Раздзеліце правілы часткавага апрантавання дадзенняў і правілы ўзяць іх з памяці. Змена адных не должна прымусваць перапісванне іншых, калі змянююцца паказнікі якосці.

Заключныя меркі

Этап «Заключныя меркіі» працюе найэфектывней, калі яго розглядаць як вімерную паверхню. Запісацеце адна «золатая» транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Запісвайце часы выканання і кост токеноў або запытаў праза функцыйнае рэзультат. Відкрытыя даныя пра косцы з’являюцца рана, таму не будзе неспакою з расчыткамі, калі праця перайдзе з дэмаверсіі ў спакульнаныя сераўысы. Храніце стан графа як плоскі і з адначынным тыпам дадзеных. Вярнутыя блокі маскуюць, які вузел запісаў канкрэтны поле, і спакшваюць продажчыку працу пасля перарываў.

Справы і далейшая літэратура

Этап «Справакі і дадзеныя для падальшага чытання» працюе найэфектывней, калі яго спрыяваць як меравальную плошчу. Зберагачыце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць сферу дзеяння. Храніце настройкі парадульна ад коду прыемлі. Файлы сераўнавання, базы секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куда аператары можуць адбавляць контроль без неабяжнага чытання всіх дадзеных. Храніце стан графа ў простам і тыпаваным фармаце. Вярнутыя структуры дадзеных маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакшваюць продаж чытання пасля перэрываў. Этап «Справакі і дадзеныя для падальшага чытання» працюе найэфектывней, калі яго спрыяваць як меравальную плошчу. Зберагачыце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць сферу дзеяння. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцоўкі дзеяння.

Чэрніца аператывных дзеянняў

Этап стварэння чэк-ліста для аператыўных задач работае наякша, калі яго спрыяваць як мерыемую структуру. Запісайце адну ідэальную версію працы, адзін кейс неудачы і прыметкі па вярнэнню да пачатковага стану, прычым расшыруючы сферу дзеяння.

Документавайце як шлях успеху, так і шлях вярнэння да нормальнага стану разам. Практыкі перапрыбутку, людзкія контрольныя пункты і обработка некорэктных звесцей ўжо ёсць часткай продукту, а не елементамі пазнейшай доработкі.

Зберагаюце стан графа ў простам і тыпаваным фармаце. Вкладзеныя структуры маскуюць інфармацыю пра тое, які вузел запісаў кожнае поле, і спакошуюць працу пасля перарываў.

Калі бюджэт дазволяе, дадзіце тэст на першыя перакананні, які працюе з крытычным шляхам у сістэме CI за дапамою фіксатываў, а не з рэальнымі платнымі API.

Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына неудачы павінна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач.

Зберагаюце стан графа ў простам і тыпаваным фармаце. Вкладзеныя структуры маскуюць інфармацыю пра тое, які вузел запісаў кожнае поле, і спакошуюць працу пасля перарываў.

Перш чым запускаць стак, заморозьце версіі, зафіксавце «золаты» транскрыпты для крытычнага шляху і паказвце способы абяроны. У спільных срэдах неабходны ліміты частоты запытанняў, пераконтрольванне прав на выкарыстоўвання рэсурсаў і чысткі власнік для змены секрэтных даных. Лепш выбіраць простую надзею на надзейнасць, чым хітрыя експерыментальныя дэманстрацыі.

Прыметка для b7b9768f8acd: не кладзіце ключы прадаўцаў у рэпазітарый, задаце максімальны тэрмін дзейнасці токена на кожную сесію і зберагачыце транскрыпты разам з фіксатрамі для ацэнкі, каб пазнейшыя замены мадэляў заставаліся порównаннэй.