<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[David Pilato - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[David Pilato - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/cn/search-labs/author/david-pilato</link>
    </image>
    <link>https://www.elastic.co/cn/search-labs/author/david-pilato</link>
    <atom:link href="https://www.elastic.co/cn/search-labs/rss/author/david-pilato.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[cn]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 12:46:21 GMT</lastBuildDate>
  <item>
    <title><![CDATA[LangChain4j 使用 Elasticsearch 作为嵌入存储]]></title>
    <description><![CDATA[LangChain4j（Java 版 LangChain）将 Elasticsearch 作为嵌入式存储。了解如何使用它在普通 Java 中构建 RAG 应用程序。]]></description>
    <content:encoded><![CDATA[<p>
在<a href="https://www.elastic.co/search-labs/blog/langchain4j-llm-integration-introduction">上一篇文章</a>中，我们了解了什么是 LangChain4j 以及如何使用：</p><ul><li><p>与法律硕士进行讨论，实施<code>ChatLanguageModel</code> 和 <code>ChatMemory</code></p></li><li><p>在记忆中保留聊天记录，以便回忆起之前与一位法律硕士讨论的背景情况</p></li></ul><p>本博文将介绍如何</p><ul><li><p>根据文本示例创建向量嵌入</p></li><li><p>将向量嵌入存储在 Elasticsearch 嵌入存储中 </p></li><li><p>搜索类似载体</p></li></ul><h2>创建嵌入</h2><p>要创建嵌入式，我们需要定义一个<code>EmbeddingModel</code> 。例如，我们可以使用<a href="https://www.elastic.co/search-labs/blog/langchain4j-llm-integration-introduction">上一篇文章</a>中使用过的相同的 mistral 模型。它和奥拉马一起跑：</p>EmbeddingModel model = OllamaEmbeddingModel.builder()
  .baseUrl(ollama.getEndpoint())
  .modelName(MODEL_NAME)
  .build();<p>模型能够从文本中生成向量。在这里，我们可以检查模型生成的维数：</p>Logger.info("Embedding model has {} dimensions.", model.dimension());
// This gives: Embedding model has 4096 dimensions.<p>要从文本中生成向量，我们可以使用</p>Response&lt;Embedding&gt; response = model.embed("A text here");<p>或者，如果我们还想提供元数据，以便对文本、价格、发布日期等内容进行筛选，我们可以使用<code>Metadata.from()</code>.NET。例如，我们在这里添加游戏名称作为元数据字段：</p>TextSegment game1 = TextSegment.from("""
    The game starts off with the main character Guybrush Threepwood stating "I want to be a pirate!"
    To do so, he must prove himself to three old pirate captains. During the perilous pirate trials, 
    he meets the beautiful governor Elaine Marley, with whom he falls in love, unaware that the ghost pirate 
    LeChuck also has his eyes on her. When Elaine is kidnapped, Guybrush procures crew and ship to track 
    LeChuck down, defeat him and rescue his love.
""", Metadata.from("gameName", "The Secret of Monkey Island"));
Response&lt;Embedding&gt; response1 = model.embed(game1);
TextSegment game2 = TextSegment.from("""
    Out Run is a pseudo-3D driving video game in which the player controls a Ferrari Testarossa 
    convertible from a third-person rear perspective. The camera is placed near the ground, simulating 
    a Ferrari driver's position and limiting the player's view into the distance. The road curves, 
    crests, and dips, which increases the challenge by obscuring upcoming obstacles such as traffic 
    that the player must avoid. The object of the game is to reach the finish line against a timer.
    The game world is divided into multiple stages that each end in a checkpoint, and reaching the end 
    of a stage provides more time. Near the end of each stage, the track forks to give the player a 
    choice of routes leading to five final destinations. The destinations represent different 
    difficulty levels and each conclude with their own ending scene, among them the Ferrari breaking 
    down or being presented a trophy.
""", Metadata.from("gameName", "Out Run"));
Response&lt;Embedding&gt; response2 = model.embed(game2);<p>如果您想运行这段代码，请查看<a href="https://github.com/dadoonet/langchain4j-demo/blob/main/src/test/java/fr/pilato/demo/Step5EmbedddingsTest.java">Step5EmbedddingsTest.java</a>类。</p><h2>添加 Elasticsearch 来存储向量</h2><p>LangChain4j 提供内存嵌入存储。这对运行简单测试非常有用：</p>EmbeddingStore&lt;TextSegment&gt; embeddingStore = new InMemoryEmbeddingStore&lt;&gt;();
embeddingStore.add(response1.content(), game1);
embeddingStore.add(response2.content(), game2);<p>但是，这显然不能用于更大的数据集，因为该数据存储将所有内容都存储在内存中，而我们的服务器上没有无限的内存。因此，我们可以将嵌入式数据存储到 Elasticsearch 中，根据定义，Elasticsearch 是"elastic" ，可以随着数据的扩展而扩展。为此，让我们在项目中添加 Elasticsearch：</p>&lt;dependency&gt;
  &lt;groupId&gt;dev.langchain4j&lt;/groupId&gt;
  &lt;artifactId&gt;langchain4j-elasticsearch&lt;/artifactId&gt;
  &lt;version&gt;${langchain4j.version}&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;org.testcontainers&lt;/groupId&gt;
  &lt;artifactId&gt;elasticsearch&lt;/artifactId&gt;
  &lt;version&gt;1.20.1&lt;/version&gt;
  &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;<p>正如你所注意到的，我们还在项目中添加了 Elasticsearch TestContainers 模块，这样我们就可以从测试中启动 Elasticsearch 实例：</p>// Create the elasticsearch container
ElasticsearchContainer container =
  new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:8.15.0")
    .withPassword("changeme");

// Start the container. This step might take some time...
container.start();

// As we don't want to make our TestContainers code more complex than
// needed, we will use login / password for authentication.
// But note that you can also use API keys which is preferred.
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "changeme"));

// Create a low level Rest client which connects to the elasticsearch container.
client = RestClient.builder(HttpHost.create("https://" + container.getHttpHostAddress()))
  .setHttpClientConfigCallback(httpClientBuilder -&gt; {
    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
    httpClientBuilder.setSSLContext(container.createSslContextFromCa());
    return httpClientBuilder;
  })
  .build();

// Check the cluster is running
client.performRequest(new Request("GET", "/"));<p>要将 Elasticsearch 用作嵌入式存储，"，" ，就必须从 LangChain4j 内存数据存储切换到 Elasticsearch 数据存储：</p>EmbeddingStore&lt;TextSegment&gt; embeddingStore =
  ElasticsearchEmbeddingStore.builder()
    .restClient(client)
    .build();
embeddingStore.add(response1.content(), game1);
embeddingStore.add(response2.content(), game2);<p>这将在 Elasticsearch 中以<code>default</code> 索引的形式存储向量。您还可以将索引名称改为更有意义的名称：</p>EmbeddingStore&lt;TextSegment&gt; embeddingStore =
  ElasticsearchEmbeddingStore.builder()
    .indexName("games")
    .restClient(client)
    .build();
embeddingStore.add(response1.content(), game1);
embeddingStore.add(response2.content(), game2);<p>如果您想运行此代码，请查看<a href="https://github.com/dadoonet/langchain4j-demo/blob/main/src/test/java/fr/pilato/demo/Step6ElasticsearchEmbedddingsTest.java">Step6ElasticsearchEmbedddingsTest.java</a>类。</p><h2>搜索类似载体</h2><p>要搜索相似向量，我们首先需要使用之前使用过的相同模型，将问题转换为向量表示。我们已经做到了，所以再做一次并不难。请注意，在这种情况下我们不需要元数据：</p>String question = "I want to pilot a car";
Embedding questionAsVector = model.embed(question).content();<p>我们可以用问题的这种表示法建立一个搜索请求，并要求嵌入式存储空间找出最前面的向量：</p>EmbeddingSearchResult&lt;TextSegment&gt; result = embeddingStore.search(
  EmbeddingSearchRequest.builder()
    .queryEmbedding(questionAsVector)
    .build());<p>现在，我们可以遍历结果并打印一些信息，如来自元数据的游戏名称和得分：</p>result.matches().forEach(m -&gt; Logger.info("{} - score [{}]",
  m.embedded().metadata().getString("gameName"), m.score()));<p>正如我们所预料的那样，"Out Run" 作为第一击：</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7ca0dcfdb1a9c94f/6a170291cf4f256938b2d017/140b6a962e5edbb4870419250e30bfb815b0d73e-640x480.gif" alt="跑出" />Out Run - score [0.86672974]
The Secret of Monkey Island - score [0.85569763]<p>如果您想运行这段代码，请查看<a href="https://github.com/dadoonet/langchain4j-demo/blob/9ec4b1d4c7c69821f143ddf272bbfed273c67b14/src/test/java/fr/pilato/demo/Step7SearchForVectorsTest.java#L110-L129">Step7SearchForVectorsTest.java</a>类。 </p><h2>幕后花絮</h2><p>Elasticsearch 嵌入存储的默认配置是在后台使用<a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.15/query-dsl-knn-query.html">近似 kNN 查询</a>。</p>POST games/_search
{
  "query" : {
    "knn": {
      "field": "vector",
      "query_vector": [-0.019137882, /* ... */, -0.0148779955]
    }
  }
}<p>但这可以通过向嵌入存储区提供默认配置 (<code>ElasticsearchConfigurationKnn</code>) 以外的另一种配置 (<code>ElasticsearchConfigurationScript</code>) 来改变：</p>EmbeddingStore&lt;TextSegment&gt; embeddingStore =
  ElasticsearchEmbeddingStore.builder()
    .configuration(ElasticsearchConfigurationScript.builder().build())
    .indexName("games")
    .restClient(client)
    .build();<p><code>ElasticsearchConfigurationScript</code><a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.15/query-dsl-script-score-query.html"><code>script_score</code></a><a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.15/query-dsl-script-score-query.html"></a>执行程序使用<a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.15/query-dsl-script-score-query.html#vector-functions-cosine"><code>cosineSimilarity</code></a><a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.15/query-dsl-script-score-query.html#vector-functions-cosine"> 函数 在后台运行</a> 查询 。</p><p>基本上，打电话时</p>EmbeddingSearchResult&lt;TextSegment&gt; result = embeddingStore.search(
  EmbeddingSearchRequest.builder()
    .queryEmbedding(questionAsVector)
    .build());<p>现在呼叫</p>POST games/_search
{
  "query": {
    "script_score": {
      "script": {
        "source": "(cosineSimilarity(params.query_vector, 'vector') + 1.0) / 2",
        "params": {
          "queryVector": [-0.019137882, /* ... */, -0.0148779955]
        }
      }
    }
  }
}<p>在这种情况下，结果并不会因为"order" 而发生变化，只是分数会有所调整，因为<code>cosineSimilarity</code> 调用并不使用任何近似值，而是计算每个匹配向量的余弦值：</p>Out Run - score [0.871952]
The Secret of Monkey Island - score [0.86380446]<p>如果您想运行这段代码，请查看<a href="https://github.com/dadoonet/langchain4j-demo/blob/9ec4b1d4c7c69821f143ddf272bbfed273c67b14/src/test/java/fr/pilato/demo/Step7SearchForVectorsTest.java#L132-L155">Step7SearchForVectorsTest.java</a>类。</p><h2>结论</h2><p>我们已经介绍了如何从文本中轻松生成嵌入，以及如何使用两种不同的方法在 Elasticsearch 中存储和搜索近邻：</p><ul><li><p>使用<code>ElasticsearchConfigurationKnn</code> 默认选项进行近似和快速<code>knn</code> 查询</p></li><li><p>使用<code>ElasticsearchConfigurationScript</code> 选项进行精确但较慢的<code>script_score</code> 查询</p></li></ul><p>下一步将根据我们在这里学到的知识，构建一个完整的 RAG 应用程序。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/langchain4j-elasticsearch-embedding-store</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/langchain4j-elasticsearch-embedding-store</guid>
    <category><![CDATA[Java]]></category>
    <category><![CDATA[AI]]></category>
    <category><![CDATA[向量数据库]]></category>
    <dc:creator><![CDATA[David Pilato]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc873b86c76d1798/6a170293acf088f666be99b3/abd8a4a809064101c037af66b87f28e5ecde03b0-1474x645.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 08 Oct 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[引入 LangChain4j 以简化 LLM 与 Java 应用程序的集成]]></title>
    <description><![CDATA[LangChain4j（LangChain for Java）是一个功能强大的工具集，可用于在纯 Java 中构建 RAG 应用程序。]]></description>
    <content:encoded><![CDATA[<p><a href="https://docs.langchain4j.dev/">LangChain4j 框架</a>正是<a href="https://github.com/langchain4j/langchain4j/blob/main/README.md#introduction">以此为目标</a>于 2023 年创建的：</p>LangChain4j 的目标是简化将 LLM 集成到 Java 应用程序中的过程。<p>LangChain4j 提供了一种标准的方法：</p><ul><li><p>根据给定内容（例如文本）创建嵌入向量</p></li><li><p>将嵌入式存储在嵌入式存储库中</p></li><li><p>在嵌入存储中搜索相似向量</p></li><li><p>与法律硕士讨论</p></li><li><p>使用聊天记忆功能，记住与法律硕士讨论的来龙去脉</p></li></ul><p>此列表并不详尽，LangChain4j 社区一直在实施新功能。</p><p>本帖将介绍该框架的第一个主要部分。</p><h2>将 LangChain4j OpenAI 添加到我们的项目中</h2><p>与所有 Java 项目一样，这只是一个依赖关系问题。这里我们将使用 Maven，但任何其他依赖管理器也可以实现同样的功能。</p><p>作为构建项目的第一步，我们将使用 OpenAI，因此只需添加<code>langchain4j-open-ai</code> 工具：</p>&lt;properties&gt;
  &lt;langchain4j.version&gt;0.34.0&lt;/langchain4j.version&gt;
&lt;/properties&gt;

&lt;dependencies&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;dev.langchain4j&lt;/groupId&gt;
    &lt;artifactId&gt;langchain4j-open-ai&lt;/artifactId&gt;
    &lt;version&gt;${langchain4j.version}&lt;/version&gt;
  &lt;/dependency&gt;
&lt;/dependencies&gt;
<p>在其余代码中，我们将使用自己的 API 密钥（可通过注册<a href="https://platform.openai.com/signup/">OpenAI</a> 账户获得），或者 LangChain4j 项目提供的 API 密钥（仅供演示使用）：</p>static String getOpenAiApiKey() {
  String apiKey = System.getenv(API_KEY_ENV_NAME);
  if (apiKey == null || apiKey.isEmpty()) {
    Logger.warn("Please provide your own key instead using [{}] env variable", API_KEY_ENV_NAME);
    return "demo";
  }
  return apiKey;
}
<p>现在我们可以创建 ChatLanguageModel 的实例：</p>ChatLanguageModel model = OpenAiChatModel.withApiKey(getOpenAiApiKey());
<p>最后，我们可以问一个简单的问题，并得到答案：</p>String answer = model.generate("Who is Thomas Pesquet?");
Logger.info("Answer is: {}", answer);
<p>给出的答案可能是这样的</p>Thomas Pesquet is a French aerospace engineer, pilot, and European Space Agency astronaut.
He was selected as a member of the European Astronaut Corps in 2009 and has since completed 
two space missions to the International Space Station, including serving as a flight engineer 
for Expedition 50/51 in 2016-2017. Pesquet is known for his contributions to scientific 
research and outreach activities during his time in space.
<p>如果您想运行这段代码，请查看<a href="https://github.com/dadoonet/langchain4j-demo/blob/main/src/test/java/fr/pilato/demo/Step1AiChatTest.java">Step1AiChatTest.java</a>类。</p><h2>使用 langchain4j 提供更多语境</h2><p>让我们添加<code>langchain4j</code> 手工艺品：</p>&lt;dependency&gt;
  &lt;groupId&gt;dev.langchain4j&lt;/groupId&gt;
  &lt;artifactId&gt;langchain4j&lt;/artifactId&gt;
  &lt;version&gt;${langchain4j.version}&lt;/version&gt;
&lt;/dependency&gt;
<p>它提供了一个工具集，可以帮助我们建立更高级的 LLM 集成，以构建我们的助手。在这里，我们只需创建一个<code>Assistant</code> 接口，该接口提供的<code>chat</code> 方法将自动调用我们之前定义的<code>ChatLanguageModel</code> ：</p>interface Assistant {
  String chat(String userMessage);
}
<p>我们只需请求 LangChain4j<code>AiServices</code> 类为我们构建一个实例：</p>Assistant assistant = AiServices.create(Assistant.class, model);
<p>然后调用<code>chat(String)</code> 方法：</p>String answer = assistant.chat("Who is Thomas Pesquet?");
Logger.info("Answer is: {}", answer);
<p>这与之前的行为相同。那么，我们为什么要修改代码呢？首先，它更优雅，但更重要的是，你现在可以使用简单的注释向 LLM 发出一些指示：</p>interface Assistant {
  @SystemMessage("Please answer in a funny way.")
  String chat(String userMessage);
}
<p>这就是现在的奉献：</p>Ah, Thomas Pesquet is actually a super secret spy disguised as an astronaut! 
He's out there in space fighting aliens and saving the world one spacewalk at a time. 
Or maybe he's just a really cool French astronaut who has been to the International 
Space Station. But my spy theory is much more exciting, don't you think?
<p>如果您想运行这段代码，请查看<a href="https://github.com/dadoonet/langchain4j-demo/blob/main/src/test/java/fr/pilato/demo/Step2AssistantTest.java">Step2AssistantTest.java</a>类。</p><h2>转到另一个 LLM：langchain4j-ollama</h2><p>我们可以利用伟大的<a href="https://ollama.com/">奥拉马项目</a>。在本地计算机上运行 LLM 会有帮助。</p><p>让我们添加<code>langchain4j-ollama</code> 手工艺品：</p>&lt;dependency&gt;
  &lt;groupId&gt;dev.langchain4j&lt;/groupId&gt;
  &lt;artifactId&gt;langchain4j-ollama&lt;/artifactId&gt;
  &lt;version&gt;${langchain4j.version}&lt;/version&gt;
&lt;/dependency&gt;
<p>由于我们要使用测试来运行示例代码，因此让我们在项目中添加<a href="https://java.testcontainers.org/">Testcontainers</a>：</p>&lt;dependency&gt;
  &lt;groupId&gt;org.testcontainers&lt;/groupId&gt;
  &lt;artifactId&gt;ollama&lt;/artifactId&gt;
  &lt;version&gt;1.20.1&lt;/version&gt;
  &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
<p>现在我们可以启动/停止 Docker 容器了：</p>static String MODEL_NAME = "mistral";
static String DOCKER_IMAGE_NAME = "langchain4j/ollama-" + MODEL_NAME + ":latest";

static OllamaContainer ollama = new OllamaContainer(
  DockerImageName.parse(DOCKER_IMAGE_NAME).asCompatibleSubstituteFor("ollama/ollama"));

@BeforeAll
public static void setup() {
  ollama.start();
}

@AfterAll
public static void teardown() {
  ollama.stop();
}
<p>我们只需"，" ，将<code>model</code> 对象改为<code>OllamaChatModel</code> ，而不是之前使用的<code>OpenAiChatModel</code> ：</p>OllamaChatModel model = OllamaChatModel.builder()
  .baseUrl(ollama.getEndpoint())
  .modelName(MODEL_NAME)
  .build();
<p>请注意，提取图像及其模型可能需要一些时间，但一段时间后，您就可以得到答案了：</p>Oh, Thomas Pesquet, the man who single-handedly keeps the French space program running 
while sipping on his crisp rosé and munching on a baguette! He's our beloved astronaut 
with an irresistible accent that makes us all want to learn French just so we can 
understand him better. When he's not floating in space, he's probably practicing his 
best "je ne sais quoi" face for the next family photo. Vive le Thomas Pesquet! 
🚀🌍🇫🇷 #FrenchSpaceHero
<h2>记忆力更好</h2><p>如果我们提出多个问题，系统默认情况下不会记住之前的问题和答案。因此，如果我们在第一个问题之后提问"他是什么时候出生的？" 、我们的应用程序会回答：</p>Oh, you're asking about this legendary figure from history, huh? Well, let me tell 
you a hilarious tale! He was actually born on Leap Year's Day, but only every 400 
years! So, do the math... if we count backwards from 2020 (which is also a leap year), 
then he was born in... *drumroll please* ...1600! Isn't that a hoot? But remember 
folks, this is just a joke, and historical records may vary.
<p>这是无稽之谈。相反，我们应该使用<a href="https://docs.langchain4j.dev/tutorials/chat-memory">聊天记忆</a>：</p>ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
Assistant assistant = AiServices.builder(Assistant.class)
  .chatLanguageModel(model)
  .chatMemory(chatMemory)
  .build();
<p>现在运行同样的问题就能得到有意义的答案：</p>Oh, Thomas Pesquet, the man who was probably born before sliced bread but after dinosaurs! 
You know, around the time when people started putting wheels on suitcases and calling it 
a revolution. So, roughly speaking, he came into this world somewhere in the late 70s or 
early 80s, give or take a year or two - just enough time for him to grow up, become an 
astronaut, and make us all laugh with his space-aged antics! Isn't that a hoot? 
*laughs maniacally*
<h2>结论</h2><p>在<a href="https://www.elastic.co/search-labs/blog/langchain4j-elasticsearch-embedding-store">下一篇文章</a>中，我们将了解如何使用 Elasticsearch 作为嵌入存储，向我们的私有数据集提问。这将为我们提供一种方法，使我们的应用程序搜索工作更上一层楼。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/langchain4j-llm-integration-introduction</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/langchain4j-llm-integration-introduction</guid>
    <category><![CDATA[Java]]></category>
    <category><![CDATA[AI]]></category>
    <dc:creator><![CDATA[David Pilato]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0435ed6d14579089/6a17e79ae8fbce7e433a192f/cf129b8b25fbe7204e2adca8fca5fec04207f096-720x720.png" length="0" type="image/png"/>
    <pubDate>Mon, 23 Sep 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>