> ## Documentation Index
> Fetch the complete documentation index at: https://cndoc-langchain.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 优化分类器

本教程将指导你如何基于用户反馈来优化一个分类器。分类器非常适合优化，因为收集期望输出通常相当简单，这使得基于用户反馈创建少量示例变得容易。这正是我们在这个示例中要做的事情。

## 目标

在这个示例中，我们将构建一个机器人，根据 GitHub issue 的标题对其进行分类。它将接收一个标题并将其分类到多个不同类别中的一个。然后，我们将开始收集用户反馈，并利用这些反馈来塑造这个分类器的表现。

## 开始

首先，我们将进行设置，以便将所有跟踪发送到特定项目。我们可以通过设置一个环境变量来实现：

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import os
os.environ["LANGSMITH_PROJECT"] = "classifier"
```

然后，我们可以创建初始应用程序。这将是一个非常简单的函数，它只接收一个 GitHub issue 标题并尝试为其打标签。

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import openai
from langsmith import traceable, Client
import uuid

client = openai.Client()

available_topics = [
    "bug",
    "improvement",
    "new_feature",
    "documentation",
    "integration",
]

prompt_template = """Classify the type of the issue as one of {topics}.
Issue: {text}"""

@traceable(
    run_type="chain",
    name="Classifier",
)
def topic_classifier(
    topic: str):
    return client.chat.completions.create(
        model="gpt-5.4-mini",
        temperature=0,
        messages=[
            {
                "role": "user",
                "content": prompt_template.format(
                    topics=','.join(available_topics),
                    text=topic,
                )
            }
        ],
    ).choices[0].message.content
```

然后，我们可以开始与它交互。在交互时，我们将提前生成 LangSmith 运行 ID 并将其传递给这个函数。这样做是为了我们以后可以附加反馈。

以下是我们如何调用应用程序：

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
from langsmith import uuid7

run_id = uuid7()
topic_classifier(
    "fix bug in LCEL",
    langsmith_extra={"run_id": run_id})
```

以下是我们之后如何附加反馈。我们可以收集两种形式的反馈。

首先，我们可以收集“正面”反馈——这是针对模型判断正确的示例。

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
ls_client = Client()
run_id = uuid7()
topic_classifier(
    "fix bug in LCEL",
    langsmith_extra={"run_id": run_id})
ls_client.create_feedback(
    run_id,
    key="user-score",
    score=1.0,
)
```

接下来，我们可以专注于收集对应于对生成结果进行“纠正”的反馈。在这个示例中，模型会将其分类为 bug，而我实际上希望它被分类为 documentation。

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
ls_client = Client()
run_id = uuid7()
topic_classifier(
    "fix bug in documentation",
    langsmith_extra={"run_id": run_id})
ls_client.create_feedback(
    run_id,
    key="correction",
    correction="documentation")
```

## 设置自动化

我们现在可以设置自动化，将带有某种形式反馈的示例移动到数据集中。我们将设置两个自动化，一个用于正面反馈，另一个用于负面反馈。

第一个将获取所有带有正面反馈的运行，并自动将它们添加到数据集。背后的逻辑是，任何带有正面反馈的运行我们都可以在未来的迭代中用作好的示例。让我们创建一个名为 `classifier-github-issues` 的数据集来添加这些数据。

<img src="https://mintcdn.com/other-405835d4/U_V3brHb6y_62TSF/langsmith/images/class-optimization-neg.png?fit=max&auto=format&n=U_V3brHb6y_62TSF&q=85&s=90512043e06ce7257570d2da53717977" alt="优化负面" width="1033" height="558" data-path="langsmith/images/class-optimization-neg.png" />

第二个将获取所有带有纠正的运行，并使用 webhook 将它们添加到数据集。创建此 webhook 时，我们将选择“使用纠正”选项。此选项将使得在从运行创建数据集时，不是使用运行的输出作为数据点的真实输出，而是使用纠正内容。

<img src="https://mintcdn.com/other-405835d4/U_V3brHb6y_62TSF/langsmith/images/class-optimization-pos.png?fit=max&auto=format&n=U_V3brHb6y_62TSF&q=85&s=c13ce4565cf525b9200e994f37ac5e34" alt="优化正面" width="1038" height="506" data-path="langsmith/images/class-optimization-pos.png" />

## 更新应用程序

我们现在可以更新代码，以拉取我们正在发送运行的数据集。一旦拉取下来，我们就可以创建一个包含示例的字符串。然后，我们可以将此字符串作为提示的一部分！

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
### 新代码 ###
# 初始化 LangSmith 客户端，以便我们可以使用它来获取数据集
ls_client = Client()

# 创建一个函数，该函数接收一个示例列表并将其格式化为字符串
def create_example_string(examples):
    final_strings = []
    for e in examples:
        final_strings.append(f"Input: {e.inputs['topic']}\n> {e.outputs['output']}")
    return "\n\n".join(final_strings)
### 新代码 ###

client = openai.Client()

available_topics = [
    "bug",
    "improvement",
    "new_feature",
    "documentation",
    "integration",
]

prompt_template = """Classify the type of the issue as one of {topics}.

Here are some examples:
{examples}

Begin!
Issue: {text}
>"""

@traceable(
    run_type="chain",
    name="Classifier",
)
def topic_classifier(
    topic: str):
    # 我们现在可以从数据集中拉取示例
    # 我们在函数内部执行此操作，以便始终获取最新的示例，
    # 但如果需要，也可以在外部执行并缓存以提高速度
    examples = list(ls_client.list_examples(dataset_name="classifier-github-issues"))  # <- 新代码
    example_string = create_example_string(examples)
    return client.chat.completions.create(
        model="gpt-5.4-mini",
        temperature=0,
        messages=[
            {
                "role": "user",
                "content": prompt_template.format(
                    topics=','.join(available_topics),
                    text=topic,
                    examples=example_string,
                )
            }
        ],
    ).choices[0].message.content
```

如果现在使用与之前类似的输入运行应用程序，我们可以看到它正确地学会了任何与文档相关的内容（即使是 bug）都应该被分类为 `documentation`

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
ls_client = Client()
run_id = uuid7()
topic_classifier(
    "address bug in documentation",
    langsmith_extra={"reset_id": run_id})
```

## 对示例进行语义搜索

我们可以做的另一件事是只使用语义上最相似的示例。当你开始积累大量示例时，这很有用。

为了做到这一点，我们可以首先定义一个函数来查找 `k` 个最相似的示例：

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import numpy as np

def find_similar(examples, topic, k=5):
    inputs = [e.inputs['topic'] for e in examples] + [topic]
    vectors = client.embeddings.create(input=inputs, model="text-embedding-3-small")
    vectors = [e.embedding for e in vectors.data]
    vectors = np.array(vectors)
    args = np.argsort(-vectors.dot(vectors[-1])[:-1])[:5]
    examples = [examples[i] for i in args]
    return examples
```

然后我们可以在应用程序中使用它

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
ls_client = Client()

def create_example_string(examples):
    final_strings = []
    for e in examples:
        final_strings.append(f"Input: {e.inputs['topic']}\n> {e.outputs['output']}")
    return "\n\n".join(final_strings)

client = openai.Client()

available_topics = [
    "bug",
    "improvement",
    "new_feature",
    "documentation",
    "integration",
]

prompt_template = """Classify the type of the issue as one of {topics}.

Here are some examples:
{examples}

Begin!
Issue: {text}
>"""

@traceable(
    run_type="chain",
    name="Classifier",
)
def topic_classifier(
    topic: str):
    examples = list(ls_client.list_examples(dataset_name="classifier-github-issues"))
    examples = find_similar(examples, topic)
    example_string = create_example_string(examples)
    return client.chat.completions.create(
        model="gpt-5.4-mini",
        temperature=0,
        messages=[
            {
                "role": "user",
                "content": prompt_template.format(
                    topics=','.join(available_topics),
                    text=topic,
                    examples=example_string,
                )
            }
        ],
    ).choices[0].message.content
```

***

<div className="source-links">
  <Callout icon="terminal-2">
    [连接这些文档](/use-these-docs) 到 Claude、VSCode 等，通过 MCP 获取实时答案。
  </Callout>

  <Callout icon="edit">
    [在 GitHub 上编辑此页面](https://github.com/langchain-ai/docs/edit/main/src/langsmith/optimize-classifier.mdx) 或 [提交问题](https://github.com/langchain-ai/docs/issues/new/choose)。
  </Callout>
</div>
