1. 为什么 Agent 需要 Elasticsearch 做上下文引擎
在 Azure AI Foundry Agent Service 里搭一个能用的 Agent 不难,难的是让它回答得靠谱。模型本身只有通用训练知识,你问它「我们公司上季度的库存周转率是多少」,它要么编一个数字,要么礼貌地告诉你不知道。要让它答得准,就得把企业私有数据喂进编排链路,这就是 grounding(有根有据)要解决的问题。
Elasticsearch 在这里扮演的角色是上下文引擎:它不只是个向量库,而是把关键词检索、向量检索、过滤条件、聚合分析统一在一套 DSL 里,让 Agent 每次调用都能拿到「经过验证、最新、可追溯」的上下文片段。相比把文档一股脑塞进 prompt,检索式注入能显著降低幻觉,也更容易做权限和版本控制。
Azure AI Foundry Agent Service 的编排模型里有三个关键构件:知识库(可信数据集合)、工具(通过 MCP 暴露的能力)、A2A 协议(Agent 之间的协作)。Elasticsearch 的接入点正好卡在「知识库 + 工具」这一层——通过远程 MCP 端点把检索能力注册成工具,Agent 在需要时主动调用,而不是被动接收一堆无关文本。
这篇面向的是已经在用 Azure AI Foundry 做 Agent、但检索链路还没跑通的开发者。我会给出一套可复制的连接配置骨架,包含用 TaoToken 统一 Key/API 通道管理凭据的 settings.json 片段,然后带你走一遍「检索—编排」联调验证,目标是你能照着复现一次可靠的上下文注入。
2. 前置准备:TaoToken 通道与 Elasticsearch 侧配置
在动 Azure 那边的配置之前,先把两边的凭据和端点理清楚。很多接入失败不是代码问题,而是 Key 散落在多个文件里、环境变量没对齐。
TaoToken 在这里的作用是统一 API 通道:你不需要在 Azure 项目、本地脚本、CI 里各维护一套 Key,而是通过一个兼容 OpenAI 协议的中转层统一管理模型调用和凭据。它的 API 地址是https://taotoken.net/api,控制台在https://taotoken.net/console,Key 在https://taotoken.net/api-keys生成。注意 API 地址不带 UTM 参数,直接写就行。
Elasticsearch 侧你需要准备三样东西:
第一,一个可访问的 Kibana 地址,形如https://your-kibana.example.com,后面拼 MCP 端点要用。
第二,一个具备read权限的 API Key,用于 MCP 连接鉴权。在 Kibana 的 Stack Management → API Keys 里创建,权限范围限定到你要检索的索引,别给all。
第三,一个已经建好的索引和 Search Template。Search Template 是关键——它把检索逻辑(比如混合搜索的权重、过滤条件)固化在 Elasticsearch 侧,Agent 调用时只传参数,不传完整 DSL。这样你能完全控制注入的上下文质量。
注意:MCP 端点走的是 Kibana 的
/api/agent_builder/mcp路径,需要 Elastic 8.x 以上且开启 Agent Builder 功能。如果你的 Kibana 版本较低,先在 Stack Management 里确认该功能可用。
3. 可复制的连接配置骨架
这一节是核心。我把配置拆成三块:TaoToken 的 settings.json、Elasticsearch 的 Search Template、Azure AI Foundry 的 MCP 连接定义。你可以直接复制改参数。
3.1 TaoToken settings.json 片段
如果你用支持 OpenAI 兼容配置的客户端或脚本,settings.json 大致长这样:
{ "api_base": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "default_model": "gpt-4o", "timeout_seconds": 60, "retry": { "max_attempts": 3, "backoff_seconds": 2 } }api_key_env指向环境变量,不要把 Key 硬编码进文件。在 shell 里设置:
export TAOTOKEN_API_KEY="sk-your-key-here"这样 Azure 侧的 Agent 和本地调试脚本共用同一个 Key 来源,轮换时只改一处。
3.2 Elasticsearch Search Template
在 Kibana Dev Tools 里创建模板,把混合检索逻辑下推:
PUT _scripts/agent-context-template { "script": { "lang": "mustache", "source": { "query": { "bool": { "must": [ { "multi_match": { "query": "{{query_string}}", "fields": ["title^2", "content", "tags"] } } ], "filter": [ { "term": { "tenant_id": "{{tenant_id}}" } }, { "range": { "updated_at": { "gte": "now-90d" } } } ] } }, "size": "{{top_k}}", "_source": ["title", "content", "updated_at", "doc_url"] } } }参数说明:query_string是 Agent 传来的用户问题,tenant_id做租户隔离,top_k控制注入条数。updated_at过滤保证只拿近 90 天的数据,避免过期信息污染上下文。
3.3 Azure AI Foundry MCP 连接定义
在 Azure AI Foundry 项目的 Connections 里新建一个自定义连接,指向 Elastic 的 MCP 端点:
{ "name": "elastic-context-engine", "type": "mcp", "endpoint": "https://your-kibana.example.com/api/agent_builder/mcp", "auth": { "type": "api_key", "header": "Authorization", "value": "ApiKey YOUR_ELASTIC_API_KEY" }, "tools": [ { "name": "search_context", "description": "检索企业知识库,返回与问题最相关的文档片段", "parameters": { "query_string": { "type": "string", "required": true }, "tenant_id": { "type": "string", "required": true }, "top_k": { "type": "integer", "default": 5 } } } ] }endpoint里的 Kibana 地址换成你自己的。auth.value用 Elastic API Key,格式是ApiKey加空格再加 Key 值。tools里声明的参数要和 Search Template 里的占位符一一对应,否则调用时会报参数缺失。
4. 验证请求与成功结果
配置写完,先别急着在 Agent 里跑,用 curl 单独验证 MCP 端点通不通。
curl -X POST "https://your-kibana.example.com/api/agent_builder/mcp" \ -H "Authorization: ApiKey YOUR_ELASTIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "search_context", "arguments": { "query_string": "库存周转率", "tenant_id": "acme", "top_k": 3 } }, "id": 1 }'成功的返回里会有result.content数组,每个元素包含title、content、updated_at。如果返回result.content为空数组,说明检索条件太严,先把updated_at过滤去掉再试。
MCP 通了之后,在 Azure AI Foundry 的 Agent Playground 里发一条测试消息:「根据知识库回答,我们上季度的库存周转率是多少?」观察 Agent 的调用轨迹——它应该先调用search_context工具,拿到片段后再生成回答。如果 Agent 直接回答而没调工具,检查工具的description是否足够明确,Agent 靠这段描述判断何时该调用。
实测下来,把description写成「当用户询问企业内部数据、政策、指标时调用此工具」比写「检索知识库」的触发率高很多。
5. 本篇常见错排查
报错一:401 Unauthorizedfrom MCP endpoint。九成是 API Key 格式问题。Elastic 的 Key 要写成ApiKey加空格再加值,少了空格或写成Bearer都会 401。另外确认 Key 的权限包含目标索引的read和view_index_metadata。
报错二:template not found: agent-context-template。Search Template 没创建成功,或者创建在了错误的集群。在 Dev Tools 里跑GET _scripts/agent-context-template确认存在。如果用了别名索引,模板里的索引名要写别名而不是具体索引。
报错三:Agent 调用工具后回答「未找到相关信息」。先看 MCP 返回的content是否为空。如果为空,把top_k调大到 10,或者放宽updated_at范围。如果content有数据但 Agent 说没找到,是 prompt 里没告诉它「优先使用工具返回的内容」,在 Agent 的 system prompt 里加一句「回答企业数据问题时必须基于 search_context 的返回结果」。
报错四:TaoToken 侧429 Too Many Requests。并发高了触发限流。settings.json 里的retry.backoff_seconds调到 5,max_attempts保持 3。如果持续 429,去https://taotoken.net/api-keys看当前 Key 的配额,必要时换一个 Key 或联系调整限额。
报错五:A2A 协作时上下文丢失。如果你用了 Elastic Agent 通过 A2A 和 Microsoft Agent 通信,确认 A2A 消息里带了context_id,否则每次调用都是新会话,检索结果无法关联。这个字段在 Elastic Agent Builder 的 A2A 配置里设置。
6. 把检索链路固化下来
跑通一次不难,难的是让它稳定。我的做法是把上面三块配置都纳入版本控制:Search Template 用PUT _scripts脚本化部署,MCP 连接定义导出成 JSON 存进仓库,TaoToken 的 settings.json 只留环境变量引用。这样换环境时改三个参数就能复现。
另外建议在 Agent 的编排链路里加一层日志,记录每次search_context的入参和返回条数。当回答质量下降时,先看检索层是不是返回了空结果或过期数据,而不是急着调模型参数。上下文引擎的可靠性,最终取决于你对检索结果的可观测性。
如果你还在选长期编码和 Agent 编排的方案,可以看看 TaoToken 的 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite),它把模型调用和通道管理打包在一起,省去自己维护多套 Key 的麻烦。接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite,里面有完整的 API 参数说明。想先验证模型效果的话,模型对话入口在https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite,可以直接试。