构建基于Serverless架构的向量检索MCP Server:TaoToken统一Key接入与AWS Lambda部署实战
2026/9/23 3:08:04 网站建设 项目流程

1. 为什么要在 Lambda 上跑向量检索 MCP Server

如果你正在给 AI Agent 接一套语义检索能力,大概率会遇到三个绕不开的问题:向量库要常驻、检索服务要扩容、模型调用要管 Key。传统做法是买一台 EC2 常驻跑 FastAPI,前面挂 Nginx,后面连 OpenSearch,再自己写一套鉴权。流量低谷时机器空转烧钱,流量高峰时又要手动扩容,运维成本比业务代码还高。

MCP Server 的出现让这件事有了新解法。它把「工具」以标准协议暴露给 Claude、Cursor、Strands Agent 这类客户端,Agent 不需要知道你的检索后端是 OpenSearch 还是别的,只要按 MCP 协议调用工具即可。而 Serverless 架构(AWS Lambda + API Gateway)恰好补上了弹性这一环:没有请求时不产生计算费用,有请求时自动并发,配合 OpenSearch 的 k-NN 向量字段,就能搭出一个零运维、按量计费的语义检索服务端。

这篇要交付的东西很具体:一份可复制的serverless.yml(SAM 模板)、MCP Server 的工具注册骨架、TaoToken 统一 Key 接入的settings.json片段,以及本地调用和云端验证的完整动作。适合已经了解 MCP 基本概念、想把它落到 AWS 上的后端或 AI 应用开发者。整个链路里,模型调用统一走 TaoToken 的 API 通道,省去在多个厂商之间切换 Key 的麻烦。

2. TaoToken 前置:统一 Key 与接入通道

在动手写 Lambda 之前,先把模型调用这一层理顺。向量检索 MCP Server 需要两类模型能力:一是把文本转成向量的 embedding 模型,二是 Agent 侧对话用的对话模型。如果每个都单独申请 Key、单独配环境变量,Lambda 的环境变量会越堆越多,轮换时也容易漏。

TaoToken 在这里的角色是统一入口。你只需要在控制台创建一个 API Key,之后 embedding 请求和对话请求都走同一个 base URL 和同一个 Key。对 Lambda 来说,环境变量从「N 个厂商 Key」收敛成「一个TAOTOKEN_API_KEY」,代码里也不用为不同厂商写不同的请求适配。

具体操作路径:打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册后进入控制台,在 API Keys 页面新建一个 Key。建议按用途命名,比如mcp-vector-lambda,方便后续在 CloudWatch 日志里定位调用来源。创建完成后复制 Key,它只会完整显示一次。

拿到 Key 之后,接入文档在 https://taotoken.net/api 可以查到完整的请求格式。embedding 接口兼容 OpenAI 的/v1/embeddings规范,所以你在 Lambda 里可以直接用requestshttpx发 POST,不需要额外 SDK。base URL 填https://taotoken.net/api,鉴权头是Authorization: Bearer <你的Key>

有一点要提醒:Lambda 的环境变量里不要明文写 Key。用 SAM 的--parameter-overrides传入,或者接 AWS Systems Manager Parameter Store,模板里用{{resolve:ssm:...}}引用。下面第 3 节的配置会体现这一点。

3. 可复制配置:serverless.yml 与 MCP 工具骨架

3.1 SAM 模板 serverless.yml

这份模板定义了 Lambda 函数、API Gateway、DynamoDB 会话表和必要的 IAM 权限。OpenSearch 的 endpoint 和 TaoToken 的 Key 都通过参数传入,不写死在文件里。

AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Vector Search MCP Server on Lambda with OpenSearch Parameters: McpAuthToken: Type: String NoEcho: true OpenSearchHost: Type: String OpenSearchUsername: Type: String OpenSearchPassword: Type: String NoEcho: true TaoTokenApiKey: Type: String NoEcho: true Globals: Function: Timeout: 30 MemorySize: 512 Runtime: python3.11 Environment: Variables: OPENSEARCH_HOST: !Ref OpenSearchHost OPENSEARCH_USERNAME: !Ref OpenSearchUsername OPENSEARCH_PASSWORD: !Ref OpenSearchPassword TAOTOKEN_API_KEY: !Ref TaoTokenApiKey TAOTOKEN_BASE_URL: https://taotoken.net/api MCP_AUTH_TOKEN: !Ref McpAuthToken SESSION_TABLE: !Ref SessionTable Resources: McpFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: app.lambda_handler Events: McpApi: Type: Api Properties: Path: /mcp Method: post RestApiId: !Ref McpApiGateway Policies: - DynamoDBCrudPolicy: TableName: !Ref SessionTable McpApiGateway: Type: AWS::Serverless::Api Properties: StageName: prod Auth: DefaultAuthorizer: McpTokenAuthorizer Authorizers: McpTokenAuthorizer: FunctionArn: !GetAtt AuthFunction.Arn Identity: Header: authorizationToken AuthFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: auth.lambda_handler Runtime: python3.11 SessionTable: Type: AWS::DynamoDB::Table Properties: TableName: mcp-session-table BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: session_id AttributeType: S KeySchema: - AttributeName: session_id KeyType: HASH TimeToLiveSpecification: AttributeName: ttl Enabled: true Outputs: McpEndpoint: Description: API Gateway endpoint for MCP Server Value: !Sub "https://${McpApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod/mcp"

几个关键点:NoEcho: true保证敏感参数不会在 CloudFormation 控制台回显;DynamoDB 开了 TTL,会话过期自动清理,不用写定时任务;API Gateway 挂了自定义授权器,所有请求先过AuthFunction校验 token。

3.2 MCP 工具注册骨架

Lambda 里的 MCP Server 核心是一个装饰器注册机制。下面这份骨架把「文本索引」和「相似度检索」两个工具注册进去,embedding 调用统一走 TaoToken。

import json import os import requests from typing import Dict TAOTOKEN_BASE_URL = os.environ["TAOTOKEN_BASE_URL"] TAOTOKEN_API_KEY = os.environ["TAOTOKEN_API_KEY"] EMBEDDING_MODEL = "BAAI/bge-m3" def generate_embedding(text: str) -> Dict: """通过 TaoToken 统一通道生成文本向量""" url = f"{TAOTOKEN_BASE_URL}/v1/embeddings" headers = { "Authorization": f"Bearer {TAOTOKEN_API_KEY}", "Content-Type": "application/json", } payload = { "model": EMBEDDING_MODEL, "input": text, "encoding_format": "float", } try: resp = requests.post(url, json=payload, headers=headers, timeout=15) resp.raise_for_status() data = resp.json() return { "status": "success", "embedding": data["data"][0]["embedding"], "model": EMBEDDING_MODEL, } except Exception as e: return {"status": "error", "message": str(e)} class LambdaMCPServer: def __init__(self): self.tools = {} def tool(self): def decorator(func): self.tools[func.__name__] = func return func return decorator mcp_server = LambdaMCPServer() @mcp_server.tool() def index_text_with_embedding(text: str, document_id: str = None, metadata: str = "{}") -> Dict: """将文本转换为向量并索引到 OpenSearch 知识库""" emb = generate_embedding(text) if emb["status"] != "success": return emb # 此处调用 OpenSearchClient.write_document 写入 knn_vector 字段 return {"status": "success", "document_id": document_id} @mcp_server.tool() def text_similarity_search(text: str, k: int = 10, score: float = 0.0) -> Dict: """基于向量相似度检索相关文档""" emb = generate_embedding(text) if emb["status"] != "success": return emb # 此处调用 OpenSearchClient.search_documents 执行 k-NN 查询 return {"status": "success", "query_vector_dim": len(emb["embedding"])}

generate_embedding里只认TAOTOKEN_BASE_URLTAOTOKEN_API_KEY两个环境变量,换模型只改EMBEDDING_MODEL常量,不用动请求逻辑。这就是统一 Key 通道带来的直接好处。

3.3 TaoToken 接入 settings.json 片段

如果你在本地用 Claude Code 或 Cursor 这类支持 MCP 的客户端调试,需要在settings.json里声明 MCP Server 和模型通道。下面这段同时配了 TaoToken 的对话通道和本地 MCP Server。

{ "mcpServers": { "vector-search": { "url": "https://your-api-id.execute-api.cn-north-1.amazonaws.com/prod/mcp", "headers": { "authorizationToken": "your-mcp-auth-token" } } }, "modelProviders": { "taotoken": { "baseUrl": "https://taotoken.net/api", "apiKey": "sk-your-taotoken-key", "models": { "chat": "claude-sonnet-4-5", "embedding": "BAAI/bge-m3" } } } }

mcpServers里的url填第 3.1 节 SAM 部署后输出的McpEndpointauthorizationToken填你传给McpAuthToken参数的值。modelProviders里的 Key 就是第 2 节在控制台创建的那个。这样本地客户端既能调云端 MCP 工具,又能通过 TaoToken 走对话模型,两边共用一个 Key。

4. 验证请求与成功结果

4.1 本地先验证 embedding 通道

在部署 Lambda 之前,先用 curl 确认 TaoToken 的 embedding 接口通。这一步能排除掉 90% 的鉴权问题。

curl -X POST https://taotoken.net/api/v1/embeddings \ -H "Authorization: Bearer sk-your-taotoken-key" \ -H "Content-Type: application/json" \ -d '{ "model": "BAAI/bge-m3", "input": "厄尔尼诺监测系统", "encoding_format": "float" }'

返回体里data[0].embedding是一个长度 1024 的浮点数组。如果返回 401,检查 Key 是否复制完整;如果返回 404,检查 base URL 有没有多写或少写/v1

4.2 部署并验证 MCP 工具列表

用 SAM 部署,参数通过命令行传入,不落盘:

sam build sam deploy --guided \ --parameter-overrides \ "McpAuthToken=your-mcp-token" \ "OpenSearchHost=your-opensearch-endpoint" \ "OpenSearchUsername=admin" \ "OpenSearchPassword=your-password" \ "TaoTokenApiKey=sk-your-taotoken-key"

部署完成后,用 MCP 客户端连接McpEndpoint。连接成功后点「List Tools」,应该能看到index_text_with_embeddingtext_similarity_search两个工具。选中text_similarity_search,传入{"text": "厄尔尼诺监测系统", "k": 5, "score": 0.5},正常返回里会带query_vector_dim: 1024,说明 embedding 通道和工具注册都通了。

4.3 用 Strands Agent 调用

如果你用 Strands Agent 做编排,工具定义和调用可以这样写:

import os from strands import Agent agent = Agent(tools=["similarity_search.py"]) API_ENDPOINT = os.getenv("MCP_ENDPOINT") AUTH_TOKEN = os.getenv("MCP_AUTH_TOKEN") results = agent.tool.similarity_search( text="厄尔尼诺监测系统", k=5, score=0.5, api_endpoint=API_ENDPOINT, auth_token=AUTH_TOKEN, ) print(results)

similarity_search.py里按 Strands 的 Tool 规范声明名称、描述、输入输出,内部用requests发 POST 到 MCP endpoint,带上authorizationToken头。返回的results就是 OpenSearch 的 k-NN 检索结果。

5. 本篇常见错排查

Lambda 超时 30 秒:embedding 请求默认超时 15 秒,如果 OpenSearch 写入慢,两个加起来容易顶到 Lambda 上限。把Timeout调到 60,或者把 embedding 和写入拆成两个异步步骤。

API Gateway 返回 403:自定义授权器里event.get('authorizationToken')取的是请求头,注意大小写。API Gateway 会把头名转成小写,所以客户端传authorizationToken时,授权器里要用event['headers']['authorizationtoken']取。

OpenSearch k-NN 查询报维度不匹配:索引创建时knn_vectordimension必须和 embedding 输出维度一致。BGE-M3 是 1024 维,如果你换了模型,索引要重建。

DynamoDB 会话读不到:检查 Lambda 执行角色的 IAM 策略有没有dynamodb:GetItemdynamodb:PutItem。SAM 模板里用的DynamoDBCrudPolicy已经覆盖,但如果你手动改了策略,容易漏。

TaoToken 返回 429:并发高了触发限流。Lambda 的预留并发调低一点,或者在generate_embedding里加指数退避重试。

6. 下一步:把 Key 和通道固定下来

整套链路跑通之后,你会发现最值得固定下来的不是 Lambda 代码,而是模型调用通道。Lambda 可以随时重新部署,OpenSearch 索引可以重建,但 Key 一旦散落在多个环境变量里,轮换和审计就会变成负担。

我的做法是把 TaoToken 的 Key 统一放在一个环境变量里,embedding 和对话共用。本地调试用settings.json里的modelProviders,云端 Lambda 用 SAM 参数注入,两边指向同一个 base URL。这样无论你后面加多少个 MCP 工具、换多少个模型,接入层都不用动。

如果你还没建 Key,可以从控制台开始:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。建完之后把 Key 填进上面的serverless.yml参数和settings.json,重新sam deploy一次,整条 Serverless 向量检索链路就活了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询