你的 AI 助手是不是也有"金鱼脑"?
聊了半小时业务背景,一刷新全忘。公司文档?它读不懂,还会一本正经地瞎编。
我被这事折腾了好几个月。直到发现亚马逊云科技新出的 S3 Vectors ,感觉终于有解了。今天分享一下我用 OpenClaw + S3 Vectors 搭个人知识库的全过程。代码都能跑,别光收藏不看啊。
S3 Vectors:在 S3 上直接存向量
先解释一下。你可能听过"向量数据库"------把文本转成数字(向量),用数学找语义相近的内容。
传统方案要单独搞个向量数据库集群。运维成本?别提了。
S3 Vectors 思路不同:在 S3 上直接加向量能力。不用额外服务,存储成本跟 S3 走。
三个概念就够了:
- Vector Bucket:向量桶,顶层容器
- Vector Index:向量索引,定义维度
- Vector:具体数据,带 key、向量值、元数据
RAG:让 AI 学会"开卷考试"
RAG(检索增强生成)的逻辑特简单:
用户提问 → 先从知识库搜相关内容 → 搜到的内容 + 问题一起喂给模型 → 模型看着"参考资料"回答
不用让 AI 背下所有知识,能"翻书"就行。
动手搭建
Step 1:建桶建索引
python
import boto3
s3vectors = boto3.client('s3vectors')
s3vectors.create_vector_bucket(
vectorBucketName='my-knowledge-base'
)
s3vectors.create_vector_index(
vectorBucketName='my-knowledge-base',
vectorIndexName='docs-index',
dimension=1024,
distanceMetric='cosine'
)
print('搞定!')
dimension=1024 跟 Titan Embed Text v2 的输出对齐。cosine 余弦相似度,文本场景标配。
Step 2:文档切分 + 向量化
文档不能整篇丢进去,得切成小块。我踩过这个坑------整篇转向量,搜出来的结果跟问题八竿子打不着。
python
import boto3
import json
def get_embedding(text):
bedrock = boto3.client('bedrock-runtime')
response = bedrock.invoke_model(
modelId='amazon.titan-embed-text-v2:0',
body=json.dumps({'inputText': text})
)
return json.loads(response['body'].read())['embedding']
def split_text(text, chunk_size=500, overlap=50):
chunks = []
start = 0
while start < len(text):
end = start + chunk_size
chunk = text[start:end]
if chunk.strip():
chunks.append(chunk.strip())
start = end - overlap
return chunks
500 字一块、50 字重叠,实测效果不错。
Step 3:写入向量
python
import boto3
import json
def get_embedding(text):
bedrock = boto3.client('bedrock-runtime')
response = bedrock.invoke_model(
modelId='amazon.titan-embed-text-v2:0',
body=json.dumps({'inputText': text})
)
return json.loads(response['body'].read())['embedding']
def split_text(text, chunk_size=500, overlap=50):
chunks = []
start = 0
while start < len(text):
end = start + chunk_size
chunk = text[start:end]
if chunk.strip():
chunks.append(chunk.strip())
start = end - overlap
return chunks
def ingest(documents):
s3vectors = boto3.client('s3vectors')
total = 0
for doc in documents:
chunks = split_text(doc['content'])
vectors = []
for i, chunk in enumerate(chunks):
vectors.append({
'key': f"{doc['id']}-{i:03d}",
'data': {'float32': get_embedding(chunk)},
'metadata': {
'title': doc['title'],
'source': doc.get('source', ''),
'content': chunk
}
})
for j in range(0, len(vectors), 20):
batch = vectors[j:j + 20]
s3vectors.put_vectors(
vectorBucketName='my-knowledge-base',
vectorIndexName='docs-index',
vectors=batch
)
total += len(batch)
print(f'写入 {total} 条向量')
# 试试
ingest([
{
'id': 'deploy',
'title': '部署指南',
'content': '服务用 Docker 部署,拉镜像后 docker-compose up -d,'
'健康检查 /health 返回 200 即正常。',
'source': 'wiki'
}
])
每 20 条一批,稳得很。
Step 4:语义搜索
python
import boto3
import json
def get_embedding(text):
bedrock = boto3.client('bedrock-runtime')
response = bedrock.invoke_model(
modelId='amazon.titan-embed-text-v2:0',
body=json.dumps({'inputText': text})
)
return json.loads(response['body'].read())['embedding']
def search(query, top_k=5):
s3vectors = boto3.client('s3vectors')
results = s3vectors.query_vectors(
vectorBucketName='my-knowledge-base',
vectorIndexName='docs-index',
queryVector={'float32': get_embedding(query)},
topK=top_k
)
for vec in results.get('vectors', []):
meta = vec.get('metadata', {})
print(f"[{vec.get('score', 0):.4f}] {meta.get('title', '')}")
print(f" {meta.get('content', '')[:100]}")
search('怎么部署')
搜"怎么部署"能匹配到"部署指南",语义搜索就是这么神奇。
Step 5:接入 OpenClaw
OpenClaw 用 Skill 扩展能力。建个 knowledge-base/scripts/search.py:
python
#!/usr/bin/env python3
import sys
import json
import boto3
def get_embedding(text):
bedrock = boto3.client('bedrock-runtime')
response = bedrock.invoke_model(
modelId='amazon.titan-embed-text-v2:0',
body=json.dumps({'inputText': text})
)
return json.loads(response['body'].read())['embedding']
def search(query, top_k=5):
s3vectors = boto3.client('s3vectors')
results = s3vectors.query_vectors(
vectorBucketName='my-knowledge-base',
vectorIndexName='docs-index',
queryVector={'float32': get_embedding(query)},
topK=top_k
)
return [
{
'title': v.get('metadata', {}).get('title', ''),
'content': v.get('metadata', {}).get('content', ''),
'score': v.get('score', 0)
}
for v in results.get('vectors', [])
]
if __name__ == '__main__':
q = sys.argv[1] if len(sys.argv) > 1 else ''
if not q:
print('用法: python search.py "关键词"')
sys.exit(1)
print(json.dumps(search(q), ensure_ascii=False, indent=2))
再配个 SKILL.md 告诉 OpenClaw 什么时候该搜知识库,整个 RAG 就通了。
S3 Vectors 和 Bedrock Knowledge Base 咋选?
亚马逊云科技的 Bedrock Knowledge Base 也能做 RAG。
- Bedrock Knowledge Base:全家桶,自动切分、自动向量化、自动检索。省事,适合快速验证
- S3 Vectors:乐高积木,每一步自己控制。灵活,适合需要定制的场景
我选 S3 Vectors,因为切分策略、搜索逻辑全在我手里。出了 bug 好查,想调优有空间。
成本呢?
存储跟 S3 标准走,查询按次计费,Embedding 按 token 计费。几百篇文档的知识库,月成本个位数美金。比单独跑数据库服务便宜太多。
实战体验
我把公司 30 多篇技术文档和会议纪要都灌进去了,大概花了 5 分钟。搜索延迟在 200ms 以内,体感非常丝滑。
实际使用中,我发现几个优化点:
- 元数据要丰富 :
metadata里多存点信息(来源、日期、作者),方便后续过滤 - chunk_size 要调:技术文档 500 字合适,会议纪要可以放到 800 字
- 定期更新:文档变了记得重新导入对应的向量
最后
整套方案:S3 Vectors 存向量,Bedrock 出 Embedding,OpenClaw 做调度。代码不到 200 行,一个下午搞定。
AI 助手的"失忆症",这次算是彻底治好了。
觉得有用的话,点个赞呗 👍