背景
なんか適当なテキストデータ食わせたものをインデックスするサービス考える
データ量
LLMが出力するのでそのLLMの出力の最大を検討すればいいのでは?
- 1 token ~= 4 chars in English
- 4K tokens are limit for GPT-4 Turbo
- LLama は 2kぽい?
現状多く見積もっても10Kぐらいが最大。input はもちろんもっと多い
1万くらいの文書だと 10k * 10 K だから大体 100M ぐらいなので余裕感ある。 全部メモリに乗せられそう
検索手段
- 全文検索:
- 文書内の単語ごとに出現頻度や位置を記録したインデックスに対して検索
- 完全一致に強い。コンテキスト把握は困難
- ElasticSearch / Lucene / etc
- Vector検索
- 文書/単語単位でベクトル化(座標化)して保存。検索クエリもベクトル化(座標化)し、ベクトル空間上の2点距離を比較
- PineCone / Qdrant / 既存のサービスの追加機能(pgVector/ElasticSearch)
性能関係
https://www.elastic.co/jp/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster
平均シャードサイズは最小で数GB、最大で数十GBに保つようにしましょう。時間ベースのデータを使用するケースでは、シャードサイズを20GBから40GBにするのが一般的です。
1GB以下だと多分余裕
料金
https://aws.amazon.com/jp/kendra/pricing/
- 月額料金 810 USD →高杉 https://aws.amazon.com/jp/opensearch-service/pricing/
- t3.small.search USD 0.056/hour → 40.32 USD * 3 → 120 USD →高い
これなら Qdrant とかを ECS にホスト→S3からロードが一番良さそう? S3に置いといて、Batch Task で入れるのが強そう。 でも永続ストレージいるからコンテナとは相性そこまでよくなさそうなんだよな。
フロント
WEBサービスとして使うなら認証が欲しい 認可も必要ならアプリと直結だけど、認証だけならアプリと分離した方が良さげ
https://github.com/aws-samples/bedrock-claude-chat/tree/main/frontend Vite 使ってるな
うーーーん、フロントはよくわからんな Amplify 使っちゃうかも
テキトーに作ってみる
Qdrant 導入
Docker image 確認 https://github.com/qdrant/qdrant/blob/master/Dockerfile
wget https://raw.githubusercontent.com/qdrant/qdrant/master/Dockerfile
code Dockerfile
ストレージだけは最低限変えたい https://qdrant.tech/documentation/concepts/storage/
- in-memory (on RAM)
- mmap storage (on Storage)
中身確認
ARG APP=/qdrant
RUN if [ "$USER_ID" != 0 ]; then \
groupadd --gid "$USER_ID" qdrant; \
useradd --uid "$USER_ID" --gid "$USER_ID" -m qdrant; \
mkdir -p "$APP"/storage "$APP"/snapshots; \
chown -R "$USER_ID:$USER_ID" "$APP"; \
fi
EXPOSE 6333
EXPOSE 6334
なるほどね〜 データ量少ないなら、起動時に毎回pullしてくる感じでもいいのかも? とりあえず一旦そのままにしとく
推奨フローはやっぱり ローカルpython での操作っぽい https://qdrant.tech/documentation/
finch vm start
cd server
finch build .
OSX上だとビルドエラー。イメージ持ってくる
finch pull qdrant/qdrant
finch run -p 6333:6333 qdrant/qdrant
finch ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c7113488132 docker.io/qdrant/qdrant:latest "./entrypoint.sh" 32 seconds ago Up 0.0.0.0:6333->6333/tcp qdrant-8c711
touch test.py
pip install qdrant-client
python test.py
レスポンス返ってきた
from qdrant_client import QdrantClient
client = QdrantClient(url="http://localhost:6333")
# # Prepare your documents, metadata, and IDs
# docs = ["Qdrant has Langchain integrations", "Qdrant also has Llama Index integrations"]
# metadata = [
# {"source": "Langchain-docs"},
# {"source": "Linkedin-docs"},
# ]
# ids = [42, 2]
# # Use the new add method
# client.add(
# collection_name="demo_collection",
# documents=docs,
# metadata=metadata,
# ids=ids
# )
search_result = client.query(
collection_name="demo_collection",
query_text="This is a query document"
)
print(search_result)
streamlint で フロント作ってみるか
# main.py
from qdrant_client import QdrantClient
client = QdrantClient(url="http://localhost:6333")
# main.py
import streamlit as st
def search():
name = st.session_state["text_keyword"]
st.title("Search Result!")
st.write(name)
search_result = client.query(
collection_name="demo_collection",
query_text=name
)
st.write(search_result)
def main():
st.title("Qdrant Example Search page")
st.button("Search", on_click=search)
st.text_input("Keyword", key="text_keyword")
if __name__ == "__main__":
main()
streamlit run test.py
これ両方デプロイすれば概ねOKそう?
- 8501
- 6333
ECSの場合どうするんやっけ? タスク定義作って、ポート開ければ良さげか
フロントのイメージ
1.DockerでStreamlitのwebアプリを動かす https://zenn.dev/kthrlab_blog/articles/2250b74ec16206 https://docs.streamlit.io/knowledge-base/tutorials/deploy/docker
test.py を main.py に変えとく
touch Dockerfile
code Dockerfile
以下だけ変える
# RUN git clone https://github.com/streamlit/streamlit-example.git .
ADD ./main.py /app/main.py
finch build -t streamlint .
一回起動した後、app url を環境変数にしとく requirements.txt 確認 https://github.com/streamlit/streamlit-example
touch requirements.txt
code requirements.txt
altair
pandas
streamlit
qdrant-client
fastembed
finch build -t streamlint .
finch images
REPOSITORY TAG IMAGE ID CREATED PLATFORM SIZE BLOB SIZE
streamlint latest 66792fbf0c7e 6 minutes ago linux/amd64 1.1 GiB 434.9 MiB
qdrant/qdrant latest 5bd665cb6e9b 4 weeks ago linux/amd64 161.3 MiB 56.0 MiB
finch run -p 80:8501 streamlint
finch exec -it 76c42b0609c0 /bin/bash
curl localhost:8501
http://localhost/ 見えたOK fastembedもいるっぽい…! 導入してやりなおし-> OK
finch kill $(finch ps -a)
ローカルで行けたので、ECSにデプロイ
finch run -p 6333:6333 qdrant/qdrant
finch run -p 80:8501 streamlint
OK? あ〜〜当たり前だけどdocker compose使わんとコンテナ間通信無理ですわ
ECRに push する https://ap-northeast-1.console.aws.amazon.com/ecr/get-started?region=ap-northeast-1
AWS_REGION=ap-northeast-1
REPOSITORY_NAME=docsearch
ACCOUNTID=hoge
aws ecr create-repository --repository-name ${REPOSITORY_NAME} --region ${AWS_REGION}
REGISTRY_ID=hoge
aws ecr get-login-password --region ${AWS_REGION} | finch login --username AWS --password-stdin ${ACCOUNTID}.dkr.ecr.${AWS_REGION}.amazonaws.com
タグ付け
finch tag qdrant/qdrant:latest ${ACCOUNTID}.dkr.ecr.${AWS_REGION}.amazonaws.com/docsearch:qdrant
finch tag streamlint:latest ${ACCOUNTID}.dkr.ecr.${AWS_REGION}.amazonaws.com/docsearch:streamlint
finch push ${ACCOUNTID}.dkr.ecr.${AWS_REGION}.amazonaws.com/docsearch:qdrant
finch push ${ACCOUNTID}.dkr.ecr.${AWS_REGION}.amazonaws.com/docsearch:streamlint
アップロード完了
Task definition 作成
JSONじゃなくて YAML にして欲しいな
{
"memory":"2048",
"networkMode":"awsvpc",
"cpu":"1024",
"family":"docsearch",
"requiresCompatibilities": [
"FARGATE"
],
"executionRoleArn": "arn:aws:iam::xxx:role/ECSTaskExecutionRole",
"containerDefinitions":[
{
"portMappings":[
{
"hostPort":6333,
"containerPort":6333,
"protocol":"tcp"
}
],
"essential":true,
"name":"qdrant",
"environment":[],
"cpu": 512,
"memory": 1536,
"image":"xxx.dkr.ecr.ap-northeast-1.amazonaws.com/docsearch:qdrant",
"logConfiguration":{
"logDriver":"awslogs",
"options":{
"awslogs-group":"/ecs/qdrant",
"awslogs-region":"ap-northeast-1",
"awslogs-stream-prefix":"ecs"
}
}
},
{
"portMappings":[
{
"hostPort":8501,
"containerPort":8501,
"protocol":"tcp"
}
],
"essential":true,
"name":"streamlint",
"environment":[
{
"name": "APPURL",
"value": "http://localhost:6333"
}
],
"cpu": 512,
"memory": 512,
"image":"xxx.dkr.ecr.ap-northeast-1.amazonaws.com/docsearch:streamlint",
"logConfiguration":{
"logDriver":"awslogs",
"options":{
"awslogs-group":"/ecs/streamlint",
"awslogs-region":"ap-northeast-1",
"awslogs-stream-prefix":"ecs"
}
}
}
]
}
ECRコンソールから定義作成 https://ap-northeast-1.console.aws.amazon.com/ecr/get-started?region=ap-northeast-1
CreateService
ECS でデプロイしているけど、ロールやCWL周りで色々トラシュー
デプロイ完了
ecs exec
nodeIPに接続→いけた
http://x.x.x.x:6333/
データ挿入 一応レスポンス返ってきた いけた