概述

在智能体逐渐成为人工智能应用核心的今天,如何让它“聪明”且“高效”是开发者最关心的问题。本文将带你从设计思路、核心能力到工程实践,全面解析高效智能体的构建方法。无论是任务分解、知识获取,还是与外部工具的协同,都会结合实际案例,帮助你理解如何打造一个真正能落地、能进化的智能体。

2.内容

2.1 什么是智能体

智能体(Agent)是人工智能领域中的核心概念,可以理解为一种具备 感知、决策和执行能力的自主系统。它能够从环境中获取信息,结合自身的知识或模型进行推理和判断,并通过调用工具或执行操作来完成任务。与传统程序不同,智能体不仅仅是被动执行预设指令,而是具备一定程度的自主性和适应性,能够在复杂、多变的环境中不断优化行为。

在实际应用中,智能体的使用场景非常广泛:

对话交互:例如智能客服或AI助手,能够理解用户需求并给出合适的回应;

任务自动化:如自动化办公、数据分析、代码生成,帮助人类提高效率;

智能决策:在金融风控、供应链优化、推荐系统中,智能体可以快速处理复杂数据并做出判断;

虚拟与现实结合:从游戏NPC到智能机器人,智能体能够与真实世界或虚拟环境交互,带来更智能的体验。

简而言之,智能体的核心价值在于 替人类完成复杂任务、提升效率和创造力,它正逐渐成为AI应用的关键载体。

2.2 何时使用智能体以及智能体框架

并不是所有问题都需要引入智能体,有些场景用普通脚本或固定规则就能解决。但当任务具备 复杂性、动态性和不确定性 时,智能体和智能体框架就展现出独特优势。

适合使用智能体的典型场景:

1. 任务复杂、需要自主规划

例如在 数据分析 中,不仅要获取数据,还要清洗、建模、可视化。传统脚本需要逐步编写流程,而智能体可以根据目标自动分解任务,并灵活调用工具完成每个环节。

2. 环境动态、信息来源多样

在 金融风控 中,数据源包含市场行情、新闻资讯、历史交易记录,信息随时变化。智能体能持续监控并动态调整策略。

3. 需要多轮交互与记忆

在 智能客服 或 教育辅导 场景中,用户问题往往连续且上下文相关,智能体通过框架中的“记忆机制”保持连贯性,而不是每次都从零开始。

4. 需要调用多种外部工具或API

比如在 软件研发 中,智能体能先检索文档,再调用代码生成工具,最后利用测试框架验证结果,形成一个完整闭环。

智能体框架的价值 在于降低开发门槛。它提供了任务调度、插件管理、上下文记忆等通用能力,让开发者可以专注于业务逻辑。例如:

LangChain 适合构建多步推理与工具调用场景;

AutoGen 擅长多智能体协作;

LlamaIndex 在知识库问答中表现突出。

当你的问题是 一次性、结构化、固定逻辑 → 用传统脚本即可;

当你的问题是 多步骤、不确定性强、需要灵活应对 → 就是使用智能体和框架的好时机。

3.智能体模式

3.1 链式工作流智能体

Prompt Chaining 工作流模式 是在大型语言模型(LLM)应用开发中常见且高效的一种设计思路。其核心理念是:将复杂的任务 分解为一系列有机衔接的步骤,每个步骤由一次 LLM 调用完成,并且后续步骤会基于前一步的输出继续处理。

image

提示链(Prompt Chaining)模式 在以下几类场景中尤为适用:

任务复杂度高:当问题难以一次性解决时,可以将其拆解为一系列更简单、可控的步骤;

需要逐步验证:每个中间输出都可能需要检查、修正或转换,确保最终结果的准确性;

保持清晰链路:通过分步骤衔接,能够清楚追踪数据或逻辑的流转过程,避免“黑箱式”结果。

例如,下述案例展示了一个针对 文本中数值数据处理 的四步工作流:

提取数值和指标 —— 从原始文本中识别出数字及其对应的含义;

标准化格式 —— 将不同表示方式统一为百分比格式,确保结果一致;

排序处理 —— 按照数值大小进行降序排序,便于后续分析;

结果输出 —— 将整理好的数据转换为 Markdown 表格,便于展示与阅读。

通过这种链式调用方式,复杂的数据处理过程被拆分为结构清晰、可追踪的步骤,既提升了 准确性和可维护性,又让开发者能够灵活地对每一环节进行优化和扩展。

具体实现代码如下所示:

复制代码

import org.springframework.ai.chat.client.ChatClient;

public class ChainWorkflow {

/**

* Array of system prompts that define the transformation steps in the chain.

* Each prompt acts as a gate that validates and transforms the output before

* proceeding to the next step.

*/

private static final String[] DEFAULT_SYSTEM_PROMPTS = {

// Step 1

"""

Extract only the numerical values and their associated metrics from the text.

Format each as'value: metric' on a new line.

Example format:

92: customer satisfaction

45%: revenue growth""",

// Step 2

"""

Convert all numerical values to percentages where possible.

If not a percentage or points, convert to decimal (e.g., 92 points -> 92%).

Keep one number per line.

Example format:

92%: customer satisfaction

45%: revenue growth""",

// Step 3

"""

Sort all lines in descending order by numerical value.

Keep the format 'value: metric' on each line.

Example:

92%: customer satisfaction

87%: employee satisfaction""",

// Step 4

"""

Format the sorted data as a markdown table with columns:

| Metric | Value |

|:--|--:|

| Customer Satisfaction | 92% | """

};

private final ChatClient chatClient;

private final String[] systemPrompts;

public ChainWorkflow(ChatClient chatClient) {

this(chatClient, DEFAULT_SYSTEM_PROMPTS);

}

public ChainWorkflow(ChatClient chatClient, String[] systemPrompts) {

this.chatClient = chatClient;

this.systemPrompts = systemPrompts;

}

public String chain(String userInput) {

int step = 0;

String response = userInput;

System.out.println(String.format("\nSTEP %s:\n %s", step++, response));

for (String prompt : systemPrompts) {

// 1. Compose the input using the response from the previous step.

String input = String.format("{%s}\n {%s}", prompt, response);

// 2. Call the chat client with the new input and get the new response.

response = chatClient.prompt(input).call().content();

System.out.println(String.format("\nSTEP %s:\n %s", step++, response));

}

return response;

}

}

复制代码

主服务入口代码实现:

复制代码

import org.springframework.ai.chat.client.ChatClient;

import org.springframework.boot.CommandLineRunner;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.annotation.Bean;

// ------------------------------------------------------------

// PROPMT CHAINING WORKFLOW

// ------------------------------------------------------------

@SpringBootApplication

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

String report = """

Q3 Performance Summary:

Our customer satisfaction score rose to 92 points this quarter.

Revenue grew by 45% compared to last year.

Market share is now at 23% in our primary market.

Customer churn decreased to 5% from 8%.

New user acquisition cost is $43 per user.

Product adoption rate increased to 78%.

Employee satisfaction is at 87 points.

Operating margin improved to 34%.

""";

@Bean

public CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) {

return args -> {

new ChainWorkflow(chatClientBuilder.build()).chain(report);

};

}

}

复制代码

该示例通过一系列提示来处理第三季度的绩效报告。以下是示例输入:

复制代码

Q3 Performance Summary:

Our customer satisfaction score rose to 92 points this quarter.

Revenue grew by 45% compared to last year.

Market share is now at 23% in our primary market.

Customer churn decreased to 5% from 8%.

New user acquisition cost is $43 per user.

Product adoption rate increased to 78%.

Employee satisfaction is at 87 points.

Operating margin improved to 34%.

复制代码

工作流程通过四个步骤来处理此问题:

1.提取值:提取数值及其指标

复制代码

92: customer satisfaction

45%: revenue growth

23%: market share

5%: customer churn

43: user acquisition cost

78%: product adoption

87: employee satisfaction

34%: operating margin

复制代码

2.标准化格式:将适用的值转换为百分比

复制代码

92%: customer satisfaction

45%: revenue growth

23%: market share

5%: customer churn

78%: product adoption

87%: employee satisfaction

34%: operating margin

复制代码

3.排序:按降序排列值

复制代码

92%: customer satisfaction

87%: employee satisfaction

78%: product adoption

45%: revenue growth

34%: operating margin

23%: market share

5%: customer churn

复制代码

4.格式:创建 markdown 表

复制代码

| Metric | Value |

|:--|--:|

| Customer Satisfaction | 92% |

| Employee Satisfaction | 87% |

| Product Adoption | 78% |

| Revenue Growth | 45% |

| Operating Margin | 34% |

| Market Share | 23% |

| Customer Churn | 5% |

复制代码

3.2 评估器-优化器智能体

image

评估器–优化器模式(Evaluator–Optimizer Pattern) 是一种典型的 双 LLM 协作工作流。它模拟了人类作者“写—审—改”的迭代过程:一个模型负责生成候选答案,另一个模型则充当评估员,给出改进建议,二者循环迭代,直到得到令人满意的结果。

该模式包含两个核心组件:

生成器 LLM(Optimizer/Generator):负责为任务生成初始响应,并在收到反馈后进行改进;

评估员 LLM(Evaluator):根据预设的质量标准(如准确性、逻辑性、风格或完整性)对响应进行分析,并输出具体的改进意见。

工作机制如下:

初始生成 —— 生成器 LLM 根据任务需求给出初稿;

质量评估 —— 评估员 LLM 审查初稿,基于评估标准给出反馈;

改进迭代 —— 如果结果不符合要求,生成器根据反馈重新生成内容;

收敛输出 —— 当评估员确认结果达到满意水平时,最终答案被采纳。

这种模式的优势在于:

提升结果质量:避免“一次性生成”的粗糙输出,通过多轮改进获得更佳结果;

增强鲁棒性:减少模型幻觉或逻辑错误;

灵活性高:评估标准可以根据不同任务(如代码正确性、文本风格、数据完整性)进行定制。

应用场景示例:

内容创作:生成文章后由评估员检查逻辑流畅性和语言风格,再反复打磨;

代码生成:评估员负责检测语法错误和单元测试结果,生成器根据反馈修复代码;

问答系统:确保答案不仅正确,还要清晰、全面。

简而言之,评估器–优化器模式就像“作者与编辑”的协作,前者负责创作,后者负责把关,两者交替工作,最终产出高质量成果。

image

评估器–优化器模式 在以下场景中特别适用:

有明确的质量标准:当任务结果能够通过清晰的指标(如正确性、逻辑性、风格或一致性)进行评估时;

迭代能带来显著改进:输出质量在多轮反馈中能逐步优化,而不是“一次生成定型”;

任务需要深度审查:复杂问题往往需要多轮批评与修正,才能得到高质量的结果。

示例应用

文学翻译:在直译之外捕捉语境和风格的细微差别,通过多轮优化更贴近原文意境;

复杂搜索与分析:如学术研究或市场调研,需要多次筛选、比对和总结;

代码生成与调试:初始生成后经过系统性审查,逐步修复语法错误、逻辑漏洞或性能问题;

内容创作:写作往往需要多次草稿与润色,模型在迭代过程中可不断提升逻辑连贯性和表达质量。

简而言之,当任务 可以被客观评估 且 质量提升依赖迭代打磨 时,这种模式能显著提高最终成果的可靠性与可用性。

具体实现代码如下:

复制代码

import java.util.ArrayList;

import java.util.List;

import java.util.StringJoiner;

import org.springframework.ai.chat.client.ChatClient;

import org.springframework.util.Assert;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class EvaluatorOptimizer {

private static final Logger logger = LoggerFactory.getLogger(EvaluatorOptimizer.class);

public static final String DEFAULT_GENERATOR_PROMPT = """

Your goal is to complete the task based on the input. If there are feedback

from your previous generations, you should reflect on them to improve your solution.

CRITICAL: Your response must be a SINGLE LINE of valid JSON with NO LINE BREAKS except those explicitly escaped with \\n.

Here is the exact format to follow, including all quotes and braces:

{"thoughts":"Brief description here","response":"public class Example {\\n // Code here\\n}"}

Rules for the response field:

1. ALL line breaks must use \\n

2. ALL quotes must use \\"

3. ALL backslashes must be doubled: \\

4. NO actual line breaks or formatting - everything on one line

5. NO tabs or special characters

6. Java code must be complete and properly escaped

Example of properly formatted response:

{"thoughts":"Implementing counter","response":"public class Counter {\\n private int count;\\n public Counter() {\\n count = 0;\\n }\\n public void increment() {\\n count++;\\n }\\n}"}

Follow this format EXACTLY - your response must be valid JSON on a single line.

""";

public static final String DEFAULT_EVALUATOR_PROMPT = """

Evaluate this code implementation for correctness, time complexity, and best practices.

Ensure the code have proper javadoc documentation.

Respond with EXACTLY this JSON format on a single line:

{"evaluation":"PASS, NEEDS_IMPROVEMENT, or FAIL", "feedback":"Your feedback here"}

The evaluation field must be one of: "PASS", "NEEDS_IMPROVEMENT", "FAIL"

Use "PASS" only if all criteria are met with no improvements needed.

""";

public static final int MAX_ITERATIONS = 10;

public enum Evaluation {

PASS, NEEDS_IMPROVEMENT, FAIL

}

public record EvaluationResponse(Evaluation evaluation, String feedback) {}

public record RefinedResponse(String solution, List chainOfThought) {}

public record Generation(String thoughts, String response) {}

private final ChatClient chatClient;

private final String generatorPrompt;

private final String evaluatorPrompt;

private final int maxIterations;

public EvaluatorOptimizer(ChatClient chatClient) {

this(chatClient, DEFAULT_GENERATOR_PROMPT, DEFAULT_EVALUATOR_PROMPT, MAX_ITERATIONS);

}

public EvaluatorOptimizer(ChatClient chatClient, String generatorPrompt, String evaluatorPrompt) {

this(chatClient, generatorPrompt, evaluatorPrompt, MAX_ITERATIONS);

}

public EvaluatorOptimizer(ChatClient chatClient, String generatorPrompt,

String evaluatorPrompt, int maxIterations) {

Assert.notNull(chatClient, "ChatClient must not be null");

Assert.hasText(generatorPrompt, "Generator prompt must not be empty");

Assert.hasText(evaluatorPrompt, "Evaluator prompt must not be empty");

Assert.isTrue(maxIterations > 0, "Max iterations must be positive");

this.chatClient = chatClient;

this.generatorPrompt = generatorPrompt;

this.evaluatorPrompt = evaluatorPrompt;

this.maxIterations = maxIterations;

}

public RefinedResponse loop(String task) {

return loop(task, new ArrayList<>(), new ArrayList<>(), 0);

}

private RefinedResponse loop(String task, List memory,

List chainOfThought, int iteration) {

if (iteration >= maxIterations) {

logger.warn("Max iterations ({}) reached without finding a PASS solution", maxIterations);

return new RefinedResponse(getBestSolution(memory), chainOfThought);

}

String context = buildContext(memory, chainOfThought);

Generation generation = generate(task, context);

memory.add(generation.response());

chainOfThought.add(generation);

EvaluationResponse evaluation = evaluate(generation.response(), task);

if (evaluation.evaluation() == Evaluation.PASS) {

logger.info("Solution accepted after {} iterations", iteration + 1);

return new RefinedResponse(generation.response(), chainOfThought);

}

logger.debug("Iteration {}: Evaluation {}", iteration + 1, evaluation.evaluation());

return loop(task, memory, chainOfThought, iteration + 1);

}

private String buildContext(List memory, List chainOfThought) {

if (memory.isEmpty()) {

return "";

}

StringJoiner context = new StringJoiner("\n");

context.add("Previous attempts and feedback:");

for (int i = 0; i < memory.size(); i++) {

context.add(String.format("Attempt %d:", i + 1));

context.add("Code: " + memory.get(i));

if (i < chainOfThought.size()) {

context.add("Thoughts: " + chainOfThought.get(i).thoughts());

}

}

return context.toString();

}

private Generation generate(String task, String context) {

try {

Generation generation = chatClient.prompt()

.user(u -> u.text("{prompt}\n{context}\nTask: {task}")

.param("prompt", generatorPrompt)

.param("context", context)

.param("task", task))

.call()

.entity(Generation.class);

logGeneration(generation);

return generation;

} catch (Exception e) {

logger.error("Generation failed for task: {}", task, e);

throw new RuntimeException("Failed to generate solution", e);

}

}

private EvaluationResponse evaluate(String content, String task) {

try {

EvaluationResponse evaluation = chatClient.prompt()

.user(u -> u.text("{prompt}\nOriginal task: {task}\nContent to evaluate: {content}")

.param("prompt", evaluatorPrompt)

.param("task", task)

.param("content", content))

.call()

.entity(EvaluationResponse.class);

logEvaluation(evaluation);

return evaluation;

} catch (Exception e) {

logger.error("Evaluation failed for content: {}", content, e);

return new EvaluationResponse(Evaluation.NEEDS_IMPROVEMENT,

"Evaluation service unavailable. Please review the code manually.");

}

}

private void logGeneration(Generation generation) {

if (logger.isDebugEnabled()) {

logger.debug("\n=== GENERATOR OUTPUT ===\nTHOUGHTS: {}\n\nRESPONSE:\n{}\n",

generation.thoughts(), generation.response());

}

}

private void logEvaluation(EvaluationResponse evaluation) {

if (logger.isDebugEnabled()) {

logger.debug("\n=== EVALUATOR OUTPUT ===\nEVALUATION: {}\n\nFEEDBACK: {}\n",

evaluation.evaluation(), evaluation.feedback());

}

}

private String getBestSolution(List solutions) {

return solutions.isEmpty() ? "" : solutions.get(solutions.size() - 1);

}

}

复制代码

Logo

更多推荐