想象一下,我们如何搜索如下的一个问题:
`Find a home within 10 miles of Miami, Florida that has 2 bedrooms, 2 bathrooms, central air, and tile floors, with a budget up to $300,000.`AI写代码
为了能够实现智能搜索,我们有几种方法来实现:
- 使用 Python 代码实现工具,并让 LLM 来进行调用。我们需要调用 LLM 来提取我们搜索的参数。为了精准搜索,我们可以使用 template 来下继续搜索。详细的情况,可以参考文章 “统一 Elastic 向量数据库与 LLM 功能,实现智能查询”
- 我们可以为这个搜索用 Python 创建一个定制的 MCP 服务器,然后在客户端里进行调用。我们可以参考文章 “Elasticsearch:智能搜索的 MCP”
上面的这两种方案,我们都需要使用编程的技能来完成。我们有没有一种不需要编程就能完成的方法呢。答案是肯定的。我们可以为它创建一个 AI Agent。
步骤一:写入数据
我们需要按照文章 “Elasticsearch:智能搜索的 MCP” 写入文档到 Elasticsearch 中。
步骤一:创建 workflow
我们创建一个如下的 workflow:
`
1. name: real_estate_esql_workflow
2. enabled: true
3. description: Advanced ES|QL search with Geocoding, WKT construction, and clean console output
5. consts:
6. geocoding_api_url: https://maps.googleapis.com/maps/api/geocode/json?key=<Your API key>&
8. triggers:
9. - type: manual
11. inputs:
12. - name: user_query
13. type: string
14. required: true
15. description: Natural language real estate search request
17. steps:
18. # Step 1: Extract structured parameters from user query
19. - name: extract_parameters
20. type: ai.prompt
21. with:
22. temperature: 0.2
23. outputSchema:
24. type: object
25. properties:
26. query: { type: string }
27. bathrooms: { type: integer }
28. bedrooms: { type: integer }
29. home_price_max: { type: number, minimum: 0 }
30. property_features: { type: string }
31. location: { type: string }
32. distance: { type: string }
33. additionalProperties: false
34. prompt: |
35. Extract structured real estate parameters from: {{ inputs.user_query }}
37. # Step 2: Geocode the location (Restored)
38. - name: get_coordinate
39. type: http
40. with:
41. url: "{{ consts.geocoding_api_url }}address={{ steps.extract_parameters.output.content.location | url_encode }}"
42. method: GET
44. # Step 3: Combine parameters and normalize fields
45. - name: combine_with_coordinates
46. type: console
47. with:
48. message: |-
49. {%- assign lat = steps.get_coordinate.output.data.results[0].geometry.location.lat | default: 0 -%}
50. {%- assign lon = steps.get_coordinate.output.data.results[0].geometry.location.lng | default: 0 -%}
51. {%- assign dist_raw = steps.extract_parameters.output.content.distance | default: "0" | replace: ' miles', '' | plus: 0 -%}
53. {
54. "query": "{{ steps.extract_parameters.output.content.query | replace: '"', '\"' | strip }}",
55. "bathrooms": "{{ steps.extract_parameters.output.content.bathrooms }}",
56. "bedrooms": "{{ steps.extract_parameters.output.content.bedrooms }}",
57. "home_price_max": "{{ steps.extract_parameters.output.content.home_price_max }}",
58. "property_features": "{{ steps.extract_parameters.output.content.property_features | replace: '"', '\"' | strip }}",
59. "longitude": {{ lon }},
60. "latitude": {{ lat }},
61. "distance_meters": {{ dist_raw | times: 1609.34 }}
62. }
64. # Step 4: Build Dynamic ES|QL Query
65. - name: build_esql_query
66. type: console
67. with:
68. message: |-
69. {%- assign v = steps.combine_with_coordinates.output | json_parse -%}
70. {%- assign q = 'FROM properties METADATA _score | EVAL pt = TO_GEOPOINT(CONCAT("POINT(", "' | append: v.longitude | append: '", " ", "' | append: v.latitude | append: '", ")")) | EVAL distance = ST_DISTANCE(location, pt)' -%}
72. {%- if v.bathrooms != "" -%}{%- assign q = q | append: " | WHERE bathrooms >= " | append: v.bathrooms -%}{%- endif -%}
73. {%- if v.bedrooms != "" -%}{%- assign q = q | append: " | WHERE bedrooms >= " | append: v.bedrooms -%}{%- endif -%}
74. {%- if v.home_price_max != "" -%}{%- assign q = q | append: " | WHERE home_price <= " | append: v.home_price_max -%}{%- endif -%}
76. {%- if v.property_features != "" -%}
77. {%- assign q = q | append: ' | WHERE MATCH(property_features, "' | append: v.property_features | append: '")' -%}
78. {%- endif -%}
80. {%- if v.distance_meters > 0 -%}
81. {%- assign q = q | append: " | WHERE distance <= " | append: v.distance_meters -%}{%- endif -%}
83. {%- if v.query != "" -%}
84. {%- assign q = q | append: ' | WHERE MATCH(body_content_semantic_text, "' | append: v.query | append: '")' -%}{%- endif -%}
86. {%- assign q = q | append: " | SORT _score DESC, distance ASC | LIMIT 10 | KEEP title, bedrooms, bathrooms, home_price, property_features, distance" -%}
88. {{ q | strip }}
90. # Step 5: Run Query
91. - name: esql_run
92. type: elasticsearch.esql.query
93. with:
94. format: json
95. query: "{{ steps.build_esql_query.output | strip }}"
97. # Step 6: Display Top 3 Results Nicely
98. - name: display_top_results
99. type: console
100. with:
101. message: |-
102. {%- assign results = steps.esql_run.output.values -%}
103. {%- if results.size == 0 -%}
104. No properties found matching your criteria.
105. {%- else -%}
106. {%- for row in results limit:3 -%}
107. Title: {{ row[0] }}
108. Bathrooms: {{ row[2] }}
109. Bedrooms: {{ row[1] }}
110. Price: ${{ row[3] }}
111. Features: {{ row[4] }}
112. Distance: {{ row[5] | divided_by: 1609.34 | round: 2 }} miles
114. {% endfor -%}
115. {%- endif -%}
`AI写代码收起代码块
在上面,你需要填入自己的 google API key。测试文档如下:
`Find a home within 10 miles of Miami, Florida that has 2 bedrooms, 2 bathrooms, central air, and tile floors, with a budget up to $300,000.`AI写代码
我们运行的结果如下:
从上面的测试中,我们可以看到我们的查询是成功的。
步骤三:创建一个 tool
步骤四:创建一个 agent
我们需要加入上面创建的工具:
步骤五:测试
`Find a home within 10 miles of Miami, Florida that has 2 bedrooms, 2 bathrooms, central air, and tile floors, with a budget up to $300,000.`AI写代码
`Find a home within 10 miles of DeBary, Florida with 5 bedrooms, at least 2 bathrooms, central air, and a garage, with a budget up to $600,000.`AI写代码
我们完美地避开了 Python 代码的创建。
Hooray!